diff --git a/AUTHORS b/AUTHORS
index 7ad2718..b8dee18 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -258,6 +258,7 @@
 Huapeng Li <huapengl@amazon.com>
 Huayong Xu <huayong.xu@samsung.com>
 Hugo Holgersson <hugo.holgersson@sonymobile.com>
+Huiwon Jo <jhwon0415@gmail.com>
 Hwanseung Lee <hs1217.lee@gmail.com>
 Hwanseung Lee <hs1217.lee@samsung.com>
 Hyunjune Kim <hyunjune.kim@samsung.com>
@@ -755,6 +756,7 @@
 Cathie Chen <cathiechen@tencent.com>
 Kyle Plumadore <kyle.plumadore@amd.com>
 Sunchang Li <johnstonli@tencent.com>
+Yeol Park <peary2@gmail.com>
 
 BlackBerry Limited <*@blackberry.com>
 Code Aurora Forum <*@codeaurora.org>
diff --git a/BUILD.gn b/BUILD.gn
index 73c12e9..f5275fa 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -150,6 +150,7 @@
     ]
   }
 
+  # TODO(sebmarchand): Remove this once we stop supporting Syzygy (M54+).
   group("All_syzygy") {
     if (is_syzyasan || syzygy_optimize) {
       deps = [
@@ -158,6 +159,15 @@
       ]
     }
   }
+
+  if (is_syzyasan) {
+    group("chrome_official_syzyasan_builder") {
+      deps = [
+        ":All_syzygy",
+        ":chrome_official_builder_no_unittests",
+      ]
+    }
+  }
 }
 
 if (is_chromeos) {
@@ -907,7 +917,7 @@
         "//breakpad:minidump_dump",
         "//breakpad:minidump_stackwalk",
         "//breakpad:symupload",
-        "//tools/android/forwarder",
+        "//tools/android/forwarder2",
       ]
     }
 
diff --git a/DEPS b/DEPS
index 182078d..55ea2ad 100644
--- a/DEPS
+++ b/DEPS
@@ -39,11 +39,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': 'c4cbd74a38232a0e9f1cc1cc8fb826bb06c577a9',
+  'skia_revision': 'e4a17372a188f1dffc3f9c9bcdfbb9860728630b',
   # 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': 'a964163e6ac4f1124b22ea7e46b8afe26dec02e0',
+  'v8_revision': '99d3258cf7b6336bbd85b4a127a74ce118a8850a',
   # 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.
@@ -51,11 +51,11 @@
   # 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': '00ff11948e74abac78e2a125c7b85080d8877ada',
+  'angle_revision': '886de369c7f050e9622e0c41634feb1410d1b5cd',
   # 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.
-  'buildtools_revision': '86f7e41d9424b9d8faf66c601b129855217f9a08',
+  'buildtools_revision': '5fd66957f08bb752dca714a591c84587c9d70762',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -63,7 +63,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': '341422fe3beb1210b28727d08e1e6f9a6fa4b030',
+  'pdfium_revision': '4ba37c6f6964f6a24fc4b8b48bc82c02edb70370',
   # 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.
@@ -95,11 +95,11 @@
   # 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': 'f332dd6dd55d4754ecf770f5edc7cc606b13a161',
+  'catapult_revision': '7bb1742caa6b83fc583b84afa861a9d62ef6fce8',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
-  'libfuzzer_revision': 'eb9b8b0366f34b53cd2ffde6837f037728aa5e9c',
+  'libfuzzer_revision': '11256fd0aa00523e65b8c4ec507150041c4bab91',
 }
 
 # Only these hosts are allowed for dependencies in this DEPS file.
@@ -1018,6 +1018,8 @@
 ]
 
 recursedeps = [
+  # buildtools provides clang_format, libc++, and libc++abi
+  'src/buildtools',
   # android_tools manages the NDK.
   'src/third_party/android_tools',
   # ANGLE manages DEPS that it also owns the build files for, such as dEQP.
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index 3ef9827..fff88c7 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -54,61 +54,10 @@
 }
 
 locale_pak_resources("locale_paks") {
-  sources = [
-    "$root_out_dir/android_webview/locales/am.pak",
-    "$root_out_dir/android_webview/locales/ar.pak",
-    "$root_out_dir/android_webview/locales/bg.pak",
-    "$root_out_dir/android_webview/locales/bn.pak",
-    "$root_out_dir/android_webview/locales/ca.pak",
-    "$root_out_dir/android_webview/locales/cs.pak",
-    "$root_out_dir/android_webview/locales/da.pak",
-    "$root_out_dir/android_webview/locales/de.pak",
-    "$root_out_dir/android_webview/locales/el.pak",
-    "$root_out_dir/android_webview/locales/en-GB.pak",
-    "$root_out_dir/android_webview/locales/en-US.pak",
-    "$root_out_dir/android_webview/locales/es-419.pak",
-    "$root_out_dir/android_webview/locales/es.pak",
-    "$root_out_dir/android_webview/locales/et.pak",
-    "$root_out_dir/android_webview/locales/fa.pak",
-    "$root_out_dir/android_webview/locales/fi.pak",
-    "$root_out_dir/android_webview/locales/fil.pak",
-    "$root_out_dir/android_webview/locales/fr.pak",
-    "$root_out_dir/android_webview/locales/gu.pak",
-    "$root_out_dir/android_webview/locales/he.pak",
-    "$root_out_dir/android_webview/locales/hi.pak",
-    "$root_out_dir/android_webview/locales/hr.pak",
-    "$root_out_dir/android_webview/locales/hu.pak",
-    "$root_out_dir/android_webview/locales/id.pak",
-    "$root_out_dir/android_webview/locales/it.pak",
-    "$root_out_dir/android_webview/locales/ja.pak",
-    "$root_out_dir/android_webview/locales/kn.pak",
-    "$root_out_dir/android_webview/locales/ko.pak",
-    "$root_out_dir/android_webview/locales/lt.pak",
-    "$root_out_dir/android_webview/locales/lv.pak",
-    "$root_out_dir/android_webview/locales/ml.pak",
-    "$root_out_dir/android_webview/locales/mr.pak",
-    "$root_out_dir/android_webview/locales/ms.pak",
-    "$root_out_dir/android_webview/locales/nb.pak",
-    "$root_out_dir/android_webview/locales/nl.pak",
-    "$root_out_dir/android_webview/locales/pl.pak",
-    "$root_out_dir/android_webview/locales/pt-BR.pak",
-    "$root_out_dir/android_webview/locales/pt-PT.pak",
-    "$root_out_dir/android_webview/locales/ro.pak",
-    "$root_out_dir/android_webview/locales/ru.pak",
-    "$root_out_dir/android_webview/locales/sk.pak",
-    "$root_out_dir/android_webview/locales/sl.pak",
-    "$root_out_dir/android_webview/locales/sr.pak",
-    "$root_out_dir/android_webview/locales/sv.pak",
-    "$root_out_dir/android_webview/locales/sw.pak",
-    "$root_out_dir/android_webview/locales/ta.pak",
-    "$root_out_dir/android_webview/locales/te.pak",
-    "$root_out_dir/android_webview/locales/th.pak",
-    "$root_out_dir/android_webview/locales/tr.pak",
-    "$root_out_dir/android_webview/locales/uk.pak",
-    "$root_out_dir/android_webview/locales/vi.pak",
-    "$root_out_dir/android_webview/locales/zh-CN.pak",
-    "$root_out_dir/android_webview/locales/zh-TW.pak",
-  ]
+  sources = []
+  foreach(_locale, locales) {
+    sources += [ "$root_out_dir/android_webview/locales/$_locale.pak" ]
+  }
   deps = [
     ":repack_locales",
   ]
@@ -232,60 +181,10 @@
   source = "ui/aw_strings.grd"
   outputs = [
     "grit/aw_strings.h",
-    "aw_strings_am.pak",
-    "aw_strings_ar.pak",
-    "aw_strings_bg.pak",
-    "aw_strings_bn.pak",
-    "aw_strings_ca.pak",
-    "aw_strings_cs.pak",
-    "aw_strings_da.pak",
-    "aw_strings_de.pak",
-    "aw_strings_el.pak",
-    "aw_strings_en-US.pak",
-    "aw_strings_en-GB.pak",
-    "aw_strings_es.pak",
-    "aw_strings_es-419.pak",
-    "aw_strings_et.pak",
-    "aw_strings_fa.pak",
-    "aw_strings_fi.pak",
-    "aw_strings_fil.pak",
-    "aw_strings_fr.pak",
-    "aw_strings_gu.pak",
-    "aw_strings_he.pak",
-    "aw_strings_hi.pak",
-    "aw_strings_hr.pak",
-    "aw_strings_hu.pak",
-    "aw_strings_id.pak",
-    "aw_strings_it.pak",
-    "aw_strings_ja.pak",
-    "aw_strings_kn.pak",
-    "aw_strings_ko.pak",
-    "aw_strings_lt.pak",
-    "aw_strings_lv.pak",
-    "aw_strings_ml.pak",
-    "aw_strings_mr.pak",
-    "aw_strings_ms.pak",
-    "aw_strings_nl.pak",
-    "aw_strings_nb.pak",
-    "aw_strings_pl.pak",
-    "aw_strings_pt-BR.pak",
-    "aw_strings_pt-PT.pak",
-    "aw_strings_ro.pak",
-    "aw_strings_ru.pak",
-    "aw_strings_sk.pak",
-    "aw_strings_sl.pak",
-    "aw_strings_sr.pak",
-    "aw_strings_sv.pak",
-    "aw_strings_sw.pak",
-    "aw_strings_ta.pak",
-    "aw_strings_te.pak",
-    "aw_strings_th.pak",
-    "aw_strings_tr.pak",
-    "aw_strings_uk.pak",
-    "aw_strings_vi.pak",
-    "aw_strings_zh-CN.pak",
-    "aw_strings_zh-TW.pak",
   ]
+  foreach(_locale, locales) {
+    outputs += [ "aw_strings_${_locale}.pak" ]
+  }
 }
 
 grit("generate_components_strings") {
@@ -305,60 +204,6 @@
   ]
   outputs = [
     "grit/components_strings.h",
-    "components_strings_am.pak",
-    "components_strings_ar.pak",
-    "components_strings_bg.pak",
-    "components_strings_bn.pak",
-    "components_strings_ca.pak",
-    "components_strings_cs.pak",
-    "components_strings_da.pak",
-    "components_strings_de.pak",
-    "components_strings_el.pak",
-    "components_strings_en-GB.pak",
-    "components_strings_en-US.pak",
-    "components_strings_es.pak",
-    "components_strings_es-419.pak",
-    "components_strings_et.pak",
-    "components_strings_fa.pak",
-    "components_strings_fake-bidi.pak",
-    "components_strings_fi.pak",
-    "components_strings_fil.pak",
-    "components_strings_fr.pak",
-    "components_strings_gu.pak",
-    "components_strings_he.pak",
-    "components_strings_hi.pak",
-    "components_strings_hr.pak",
-    "components_strings_hu.pak",
-    "components_strings_id.pak",
-    "components_strings_it.pak",
-    "components_strings_ja.pak",
-    "components_strings_kn.pak",
-    "components_strings_ko.pak",
-    "components_strings_lt.pak",
-    "components_strings_lv.pak",
-    "components_strings_ml.pak",
-    "components_strings_mr.pak",
-    "components_strings_ms.pak",
-    "components_strings_nl.pak",
-    "components_strings_nb.pak",
-    "components_strings_pl.pak",
-    "components_strings_pt-BR.pak",
-    "components_strings_pt-PT.pak",
-    "components_strings_ro.pak",
-    "components_strings_ru.pak",
-    "components_strings_sk.pak",
-    "components_strings_sl.pak",
-    "components_strings_sr.pak",
-    "components_strings_sv.pak",
-    "components_strings_sw.pak",
-    "components_strings_ta.pak",
-    "components_strings_te.pak",
-    "components_strings_th.pak",
-    "components_strings_tr.pak",
-    "components_strings_uk.pak",
-    "components_strings_vi.pak",
-    "components_strings_zh-CN.pak",
-    "components_strings_zh-TW.pak",
     "java/res/values-am/components_strings.xml",
     "java/res/values-ar/components_strings.xml",
     "java/res/values-bg/components_strings.xml",
@@ -404,6 +249,9 @@
     "java/res/values-zh-rTW/components_strings.xml",
     "java/res/values/components_strings.xml",
   ]
+  foreach(_locale, locales_with_fake_bidi) {
+    outputs += [ "components_strings_${_locale}.pak" ]
+  }
 }
 
 source_set("webview_entry_point") {
@@ -698,6 +546,7 @@
     "java/src/org/chromium/android_webview/AwAutofillClient.java",
     "java/src/org/chromium/android_webview/AwBrowserContext.java",
     "java/src/org/chromium/android_webview/AwBrowserProcess.java",
+    "java/src/org/chromium/android_webview/AwContentVideoViewEmbedder.java",
     "java/src/org/chromium/android_webview/AwContentViewClient.java",
     "java/src/org/chromium/android_webview/AwContents.java",
     "java/src/org/chromium/android_webview/AwContentsBackgroundThreadClient.java",
diff --git a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc
index 55a309a..fa0dc88 100644
--- a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc
+++ b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc
@@ -269,6 +269,7 @@
     content::ResourceContext* resource_context,
     bool is_content_initiated,
     bool must_download,
+    bool is_new_request,
     ScopedVector<content::ResourceThrottle>* throttles) {
   GURL url(request->url());
   std::string user_agent;
diff --git a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h
index 7bfc6ef..4731573 100644
--- a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h
+++ b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h
@@ -39,6 +39,7 @@
       content::ResourceContext* resource_context,
       bool is_content_initiated,
       bool must_download,
+      bool is_new_request,
       ScopedVector<content::ResourceThrottle>* throttles) override;
   content::ResourceDispatcherHostLoginDelegate* CreateLoginDelegate(
       net::AuthChallengeInfo* auth_info,
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentVideoViewEmbedder.java b/android_webview/java/src/org/chromium/android_webview/AwContentVideoViewEmbedder.java
new file mode 100644
index 0000000..9f06e16
--- /dev/null
+++ b/android_webview/java/src/org/chromium/android_webview/AwContentVideoViewEmbedder.java
@@ -0,0 +1,102 @@
+// 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.
+
+package org.chromium.android_webview;
+
+import android.content.Context;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import org.chromium.base.annotations.JNINamespace;
+import org.chromium.content.browser.ContentVideoViewEmbedder;
+
+/**
+ * Implementation of {@link ContentViewViewEmbedder} for webview.
+ */
+@JNINamespace("android_webview")
+public class AwContentVideoViewEmbedder implements ContentVideoViewEmbedder {
+    private final Context mContext;
+    private final AwContentsClient mAwContentsClient;
+
+    private FrameLayout mCustomView;
+    private View mProgressView;
+
+    public AwContentVideoViewEmbedder(Context context, AwContentsClient contentsClient,
+            FrameLayout customView) {
+        mContext = context;
+        mAwContentsClient = contentsClient;
+        mCustomView = customView;
+    }
+
+    public void setCustomView(FrameLayout customView) {
+        mCustomView = customView;
+    }
+
+    @Override
+    public void enterFullscreenVideo(View videoView, boolean isVideoLoaded) {
+        if (mCustomView == null) {
+            // enterFullscreenVideo will only be called after enterFullscreen, but
+            // in this case exitFullscreen has been invoked in between them.
+            // TODO(igsolla): Fix http://crbug/425926 and replace with assert.
+            return;
+        }
+
+        mCustomView.addView(videoView, 0);
+
+        if (isVideoLoaded) return;
+
+        mProgressView = mAwContentsClient.getVideoLoadingProgressView();
+        if (mProgressView == null) {
+            mProgressView = new ProgressView(mContext);
+        }
+        mCustomView.addView(
+                mProgressView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+                                       ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER));
+    }
+
+    @Override
+    public void fullscreenVideoLoaded() {
+        if (mCustomView == null) return;
+
+        if (mProgressView != null) {
+            mCustomView.removeView(mProgressView);
+            mProgressView = null;
+        }
+    }
+
+    @Override
+    public void exitFullscreenVideo() {
+        // Intentional no-op
+    }
+
+    @Override
+    public void setSystemUiVisibility(boolean enterFullscreen) {
+    }
+
+    private static class ProgressView extends LinearLayout {
+        private final ProgressBar mProgressBar;
+        private final TextView mTextView;
+
+        public ProgressView(Context context) {
+            super(context);
+            setOrientation(LinearLayout.VERTICAL);
+            setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
+                    LinearLayout.LayoutParams.WRAP_CONTENT));
+            mProgressBar = new ProgressBar(context, null, android.R.attr.progressBarStyleLarge);
+            mTextView = new TextView(context);
+
+            String videoLoadingText = context.getString(
+                    org.chromium.android_webview.R.string.media_player_loading_video);
+
+            mTextView.setText(videoLoadingText);
+            addView(mProgressBar);
+            addView(mTextView);
+        }
+    }
+}
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentViewClient.java b/android_webview/java/src/org/chromium/android_webview/AwContentViewClient.java
index b06de5e..0192b2b 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContentViewClient.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContentViewClient.java
@@ -6,30 +6,18 @@
 
 import android.content.Context;
 import android.content.Intent;
-import android.view.Gravity;
 import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.webkit.URLUtil;
-import android.webkit.WebChromeClient;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-import android.widget.ProgressBar;
-import android.widget.TextView;
 
-import org.chromium.content.browser.ContentVideoViewEmbedder;
 import org.chromium.content.browser.ContentViewClient;
 
 /**
  * ContentViewClient implementation for WebView
  */
-public class AwContentViewClient extends ContentViewClient implements ContentVideoViewEmbedder {
+public class AwContentViewClient extends ContentViewClient {
     private final AwContentsClient mAwContentsClient;
     private final AwSettings mAwSettings;
     private final AwContents mAwContents;
     private final Context mContext;
-    private FrameLayout mCustomView;
-    private View mProgressView;
 
     public AwContentViewClient(AwContentsClient awContentsClient, AwSettings awSettings,
             AwContents awContents, Context context) {
@@ -69,58 +57,6 @@
     }
 
     @Override
-    public final ContentVideoViewEmbedder getContentVideoViewEmbedder() {
-        return this;
-    }
-
-    @Override
-    public boolean shouldBlockMediaRequest(String url) {
-        return mAwSettings != null
-                ? mAwSettings.getBlockNetworkLoads() && URLUtil.isNetworkUrl(url) : true;
-    }
-
-    @Override
-    public void enterFullscreenVideo(View videoView, boolean isVideoLoaded) {
-        if (mCustomView == null) {
-            // enterFullscreenVideo will only be called after enterFullscreen, but
-            // in this case exitFullscreen has been invoked in between them.
-            // TODO(igsolla): Fix http://crbug/425926 and replace with assert.
-            return;
-        }
-
-        mCustomView.addView(videoView, 0);
-
-        if (isVideoLoaded) return;
-
-        mProgressView = mAwContentsClient.getVideoLoadingProgressView();
-        if (mProgressView == null) {
-            mProgressView = new ProgressView(mContext);
-        }
-        mCustomView.addView(
-                mProgressView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
-                                       ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER));
-    }
-
-    @Override
-    public void fullscreenVideoLoaded() {
-        if (mCustomView == null) return;
-
-        if (mProgressView != null) {
-            mCustomView.removeView(mProgressView);
-            mProgressView = null;
-        }
-    }
-
-    @Override
-    public void exitFullscreenVideo() {
-        // Intentional no-op
-    }
-
-    @Override
-    public void setSystemUiVisibility(boolean enterFullscreen) {
-    }
-
-    @Override
     public boolean doesPerformProcessText() {
         return true;
     }
@@ -134,71 +70,4 @@
     public boolean isSelectActionModeAllowed(int actionModeItem) {
         return mAwContents.isSelectActionModeAllowed(actionModeItem);
     }
-
-    /**
-     * Called to show the web contents in fullscreen mode.
-     *
-     * <p>If entering fullscreen on a video element the web contents will contain just
-     * the html5 video controls. {@link #enterFullscreenVideo(View)} will be called later
-     * once the ContentVideoView, which contains the hardware accelerated fullscreen video,
-     * is ready to be shown.
-     */
-    public void enterFullscreen() {
-        if (mAwContents.isFullScreen()) {
-            return;
-        }
-        View fullscreenView = mAwContents.enterFullScreen();
-        if (fullscreenView == null) {
-            return;
-        }
-        WebChromeClient.CustomViewCallback cb = new WebChromeClient.CustomViewCallback() {
-            @Override
-            public void onCustomViewHidden() {
-                if (mCustomView != null) {
-                    mAwContents.requestExitFullscreen();
-                }
-            }
-        };
-        mCustomView = new FrameLayout(mContext);
-        mCustomView.addView(fullscreenView);
-        mAwContentsClient.onShowCustomView(mCustomView, cb);
-    }
-
-    /**
-     * Called to show the web contents in embedded mode.
-     */
-    public void exitFullscreen() {
-        if (mCustomView != null) {
-            mCustomView = null;
-            mProgressView = null;
-            mAwContents.exitFullScreen();
-            mAwContentsClient.onHideCustomView();
-        }
-    }
-
-    @Override
-    public String getProductVersion() {
-        return AwContentsStatics.getProductVersion();
-    }
-
-    private static class ProgressView extends LinearLayout {
-        private final ProgressBar mProgressBar;
-        private final TextView mTextView;
-
-        public ProgressView(Context context) {
-            super(context);
-            setOrientation(LinearLayout.VERTICAL);
-            setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
-                    LinearLayout.LayoutParams.WRAP_CONTENT));
-            mProgressBar = new ProgressBar(context, null, android.R.attr.progressBarStyleLarge);
-            mTextView = new TextView(context);
-
-            String videoLoadingText = context.getString(
-                    org.chromium.android_webview.R.string.media_player_loading_video);
-
-            mTextView.setText(videoLoadingText);
-            addView(mProgressBar);
-            addView(mTextView);
-        }
-    }
 }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java
index e80d8c3..6735b004 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -102,6 +102,7 @@
     private static final boolean TRACE = false;
     private static final int NO_WARN = 0;
     private static final int WARN = 1;
+    private static final String PRODUCT_VERSION = AwContentsStatics.getProductVersion();
 
     private static final String WEB_ARCHIVE_EXTENSION = ".mht";
     // The request code should be unique per WebView/AwContents object.
@@ -771,7 +772,7 @@
         mSettings = settings;
         mLayoutSizer.setDelegate(new AwLayoutSizerDelegate());
         mWebContentsDelegate = new AwWebContentsDelegateAdapter(
-                this, contentsClient, mContentViewClient, mContext, mContainerView);
+                this, contentsClient, settings, mContext, mContainerView);
         mContentsClientBridge = new AwContentsClientBridge(mContext, contentsClient,
                 AwContentsStatics.getClientCertLookupTable());
         mZoomControls = new AwZoomControls(this);
@@ -1048,7 +1049,7 @@
         WebContents webContents = nativeGetWebContents(mNativeAwContents);
 
         mWindowAndroid = getWindowAndroid(mContext);
-        mContentViewCore = new ContentViewCore(mContext);
+        mContentViewCore = new ContentViewCore(mContext, PRODUCT_VERSION);
         mViewAndroidDelegate = new AwViewAndroidDelegate(mContainerView,
                 mContentViewCore.getRenderCoordinates());
         initializeContentViewCore(mContentViewCore, mContext, mViewAndroidDelegate,
diff --git a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java
index cb372ae..6274f0a0 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java
@@ -19,10 +19,14 @@
 import android.view.KeyEvent;
 import android.view.View;
 import android.webkit.ConsoleMessage;
+import android.webkit.URLUtil;
 import android.webkit.ValueCallback;
+import android.webkit.WebChromeClient;
+import android.widget.FrameLayout;
 
 import org.chromium.base.ContentUriUtils;
 import org.chromium.base.ThreadUtils;
+import org.chromium.content.browser.ContentVideoViewEmbedder;
 import org.chromium.content_public.browser.InvalidateTypes;
 import org.chromium.content_public.common.ResourceRequestBody;
 
@@ -37,15 +41,17 @@
 
     private final AwContents mAwContents;
     private final AwContentsClient mContentsClient;
-    private final AwContentViewClient mContentViewClient;
+    private final AwSettings mAwSettings;
     private final Context mContext;
     private View mContainerView;
+    private FrameLayout mCustomView;
+    private AwContentVideoViewEmbedder mVideoViewEmbedder;
 
     public AwWebContentsDelegateAdapter(AwContents awContents, AwContentsClient contentsClient,
-            AwContentViewClient contentViewClient, Context context, View containerView) {
+            AwSettings settings, Context context, View containerView) {
         mAwContents = awContents;
         mContentsClient = contentsClient;
-        mContentViewClient = contentViewClient;
+        mAwSettings = settings;
         mContext = context;
         setContainerView(containerView);
     }
@@ -264,9 +270,9 @@
     @Override
     public void toggleFullscreenModeForTab(boolean enterFullscreen) {
         if (enterFullscreen) {
-            mContentViewClient.enterFullscreen();
+            enterFullscreen();
         } else {
-            mContentViewClient.exitFullscreen();
+            exitFullscreen();
         }
     }
 
@@ -275,6 +281,59 @@
         mContentsClient.updateTitle(mAwContents.getTitle(), false);
     }
 
+    /**
+     * Called to show the web contents in fullscreen mode.
+     *
+     * <p>If entering fullscreen on a video element the web contents will contain just
+     * the html5 video controls. {@link #enterFullscreenVideo(View)} will be called later
+     * once the ContentVideoView, which contains the hardware accelerated fullscreen video,
+     * is ready to be shown.
+     */
+    private void enterFullscreen() {
+        if (mAwContents.isFullScreen()) {
+            return;
+        }
+        View fullscreenView = mAwContents.enterFullScreen();
+        if (fullscreenView == null) {
+            return;
+        }
+        WebChromeClient.CustomViewCallback cb = new WebChromeClient.CustomViewCallback() {
+            @Override
+            public void onCustomViewHidden() {
+                if (mCustomView != null) {
+                    mAwContents.requestExitFullscreen();
+                }
+            }
+        };
+        mCustomView = new FrameLayout(mContext);
+        mCustomView.addView(fullscreenView);
+        mContentsClient.onShowCustomView(mCustomView, cb);
+    }
+
+    /**
+     * Called to show the web contents in embedded mode.
+     */
+    private void exitFullscreen() {
+        if (mCustomView != null) {
+            mCustomView = null;
+            if (mVideoViewEmbedder != null) mVideoViewEmbedder.setCustomView(null);
+            mAwContents.exitFullScreen();
+            mContentsClient.onHideCustomView();
+        }
+    }
+
+    @Override
+    public ContentVideoViewEmbedder getContentVideoViewEmbedder() {
+        mVideoViewEmbedder = new AwContentVideoViewEmbedder(mContext, mContentsClient, mCustomView);
+        return mVideoViewEmbedder;
+    }
+
+    @Override
+    public boolean shouldBlockMediaRequest(String url) {
+        return mAwSettings != null
+                ? mAwSettings.getBlockNetworkLoads() && URLUtil.isNetworkUrl(url) : true;
+    }
+
     private static class GetDisplayNameTask extends AsyncTask<Void, Void, String[]> {
         final int mProcessId;
         final int mRenderId;
diff --git a/android_webview/tools/apk_merger.py b/android_webview/tools/apk_merger.py
index ff1966eb..4ccd895 100755
--- a/android_webview/tools/apk_merger.py
+++ b/android_webview/tools/apk_merger.py
@@ -5,6 +5,18 @@
 
 """ Merges a 64-bit and a 32-bit APK into a single APK
 
+This script is used to merge two APKs which have only 32-bit or 64-bit
+binaries respectively into a APK that has both 32-bit and 64-bit binaries
+for 64-bit Android platform.
+
+You normally don't need this script because GN 64-bit build generates
+such APK for you.
+
+To use this script, you need to
+1. Build 32-bit APK as usual.
+2. Build 64-bit APK with GN variable build_apk_secondary_abi=false.
+3. Use this script to merge 2 APKs.
+
 """
 
 import argparse
@@ -202,6 +214,9 @@
   ignores = ['META-INF', 'AndroidManifest.xml']
   if args.ignore_classes_dex:
     ignores += ['classes.dex', 'classes2.dex']
+  if args.debug:
+    # see http://crbug.com/648720
+    ignores += ['webview_licenses.notice']
 
   dcmp = filecmp.dircmp(
       tmp_dir_64,
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 7a5f529..4b2bef3 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -1004,6 +1004,22 @@
   ]
 }
 
+# Used to test ash with an aura backend.
+source_set("ash_with_aura_test_support") {
+  testonly = true
+  sources = [
+    "test/ash_test_impl_aura.cc",
+    "test/ash_test_impl_aura.h",
+  ]
+  deps = [
+    ":ash",
+    ":test_support_common",
+    "//base",
+    "//skia",
+    "//ui/display",
+  ]
+}
+
 # Internal target consumed by |test_support_with_content| and
 # |test_support_without_content|. This target contains all the test support
 # files, with the exception of an implementation of AshTestEnvironment.
@@ -1013,6 +1029,9 @@
   testonly = true
   visibility = [ ":*" ]
   sources = [
+    "common/test/ash_test.cc",
+    "common/test/ash_test.h",
+    "common/test/ash_test_impl.h",
     "common/test/material_design_controller_test_api.cc",
     "common/test/material_design_controller_test_api.h",
     "common/test/test_palette_delegate.cc",
@@ -1317,6 +1336,7 @@
 
   deps = [
     ":ash",
+    ":ash_with_aura_test_support",
     ":ash_with_content",
     ":test_support_with_content",
     "//base",
@@ -1409,6 +1429,7 @@
     "common/wm/overview/cleanup_animation_observer_unittest.cc",
     "common/wm/workspace/workspace_event_handler_test_helper.cc",
     "common/wm/workspace/workspace_event_handler_test_helper.h",
+    "common/wm_window_unittest.cc",
     "common/wm_window_user_data_unittest.cc",
     "dip_unittest.cc",
     "display/cursor_window_controller_unittest.cc",
@@ -1517,6 +1538,7 @@
 
   deps = [
     ":ash",
+    ":ash_with_aura_test_support",
     ":test_support_without_content",
     "//ash/autoclick/common:autoclick",
     "//ash/common/strings",
diff --git a/ash/aura/wm_window_aura.cc b/ash/aura/wm_window_aura.cc
index 9715a7c..0c7184d4 100644
--- a/ash/aura/wm_window_aura.cc
+++ b/ash/aura/wm_window_aura.cc
@@ -45,16 +45,16 @@
 #include "ui/wm/core/visibility_controller.h"
 #include "ui/wm/core/window_util.h"
 
-DECLARE_WINDOW_PROPERTY_TYPE(ash::ShelfItemDetails*);
 DECLARE_WINDOW_PROPERTY_TYPE(ash::WmWindowAura*);
 
 namespace ash {
 
 DEFINE_WINDOW_PROPERTY_KEY(ShelfID, kShelfIDKey, kInvalidShelfID);
+DEFINE_WINDOW_PROPERTY_KEY(int, kShelfItemTypeKey, TYPE_UNDEFINED);
+DEFINE_WINDOW_PROPERTY_KEY(int,
+                           kShelfIconResourceIdKey,
+                           kInvalidImageResourceID);
 
-DEFINE_OWNED_WINDOW_PROPERTY_KEY(ShelfItemDetails,
-                                 kShelfItemDetailsKey,
-                                 nullptr);
 DEFINE_OWNED_WINDOW_PROPERTY_KEY(WmWindowAura, kWmWindowKey, nullptr);
 
 static_assert(aura::Window::kInitialId == kShellWindowId_Invalid,
@@ -168,6 +168,10 @@
   return window_->name();
 }
 
+void WmWindowAura::SetTitle(const base::string16& title) {
+  window_->SetTitle(title);
+}
+
 base::string16 WmWindowAura::GetTitle() const {
   return window_->title();
 }
@@ -316,9 +320,15 @@
   if (key == WmWindowProperty::MODAL_TYPE)
     return window_->GetProperty(aura::client::kModalKey);
 
+  if (key == WmWindowProperty::SHELF_ICON_RESOURCE_ID)
+    return window_->GetProperty(kShelfIconResourceIdKey);
+
   if (key == WmWindowProperty::SHELF_ID)
     return window_->GetProperty(kShelfIDKey);
 
+  if (key == WmWindowProperty::SHELF_ITEM_TYPE)
+    return window_->GetProperty(kShelfItemTypeKey);
+
   if (key == WmWindowProperty::TOP_VIEW_INSET)
     return window_->GetProperty(aura::client::kTopViewInset);
 
@@ -327,10 +337,18 @@
 }
 
 void WmWindowAura::SetIntProperty(WmWindowProperty key, int value) {
+  if (key == WmWindowProperty::SHELF_ICON_RESOURCE_ID) {
+    window_->SetProperty(kShelfIconResourceIdKey, value);
+    return;
+  }
   if (key == WmWindowProperty::SHELF_ID) {
     window_->SetProperty(kShelfIDKey, value);
     return;
   }
+  if (key == WmWindowProperty::SHELF_ITEM_TYPE) {
+    window_->SetProperty(kShelfItemTypeKey, value);
+    return;
+  }
   if (key == WmWindowProperty::TOP_VIEW_INSET) {
     window_->SetProperty(aura::client::kTopViewInset, value);
     return;
@@ -339,20 +357,6 @@
   NOTREACHED();
 }
 
-ShelfItemDetails* WmWindowAura::GetShelfItemDetails() {
-  return window_->GetProperty(kShelfItemDetailsKey);
-}
-
-void WmWindowAura::SetShelfItemDetails(const ShelfItemDetails& details) {
-  // |item_details| is owned by |window_|.
-  ShelfItemDetails* item_details = new ShelfItemDetails(details);
-  window_->SetProperty(kShelfItemDetailsKey, item_details);
-}
-
-void WmWindowAura::ClearShelfItemDetails() {
-  window_->ClearProperty(kShelfItemDetailsKey);
-}
-
 const wm::WindowState* WmWindowAura::GetWindowState() const {
   return ash::wm::GetWindowState(window_);
 }
@@ -825,10 +829,12 @@
     wm_property = WmWindowProperty::EXCLUDE_FROM_MRU;
   } else if (key == aura::client::kModalKey) {
     wm_property = WmWindowProperty::MODAL_TYPE;
+  } else if (key == kShelfIconResourceIdKey) {
+    wm_property = WmWindowProperty::SHELF_ICON_RESOURCE_ID;
   } else if (key == kShelfIDKey) {
     wm_property = WmWindowProperty::SHELF_ID;
-  } else if (key == kShelfItemDetailsKey) {
-    wm_property = WmWindowProperty::SHELF_ITEM_DETAILS;
+  } else if (key == kShelfItemTypeKey) {
+    wm_property = WmWindowProperty::SHELF_ITEM_TYPE;
   } else if (key == kSnapChildrenToPixelBoundary) {
     wm_property = WmWindowProperty::SNAP_CHILDREN_TO_PIXEL_BOUNDARY;
   } else if (key == aura::client::kTopViewInset) {
diff --git a/ash/aura/wm_window_aura.h b/ash/aura/wm_window_aura.h
index a13d2bdd..1bf4da0 100644
--- a/ash/aura/wm_window_aura.h
+++ b/ash/aura/wm_window_aura.h
@@ -52,6 +52,7 @@
   WmShell* GetShell() const override;
   void SetName(const char* name) override;
   std::string GetName() const override;
+  void SetTitle(const base::string16& title) override;
   base::string16 GetTitle() const override;
   void SetShellWindowId(int id) override;
   int GetShellWindowId() const override;
@@ -83,9 +84,6 @@
   void SetColorProperty(WmWindowProperty key, SkColor value) override;
   int GetIntProperty(WmWindowProperty key) override;
   void SetIntProperty(WmWindowProperty key, int value) override;
-  ShelfItemDetails* GetShelfItemDetails() override;
-  void SetShelfItemDetails(const ShelfItemDetails& details) override;
-  void ClearShelfItemDetails() override;
   const wm::WindowState* GetWindowState() const override;
   WmWindow* GetToplevelWindow() override;
   WmWindow* GetToplevelWindowForFocus() override;
diff --git a/ash/common/shelf/shelf_constants.h b/ash/common/shelf/shelf_constants.h
index 9f00840..bd80e6b 100644
--- a/ash/common/shelf/shelf_constants.h
+++ b/ash/common/shelf/shelf_constants.h
@@ -28,7 +28,7 @@
   SHELF_INSETS_FOR_AUTO_HIDE
 };
 
-// Invalid image resource id used for ShelfItemDetails.
+// Invalid image resource id used for shelf items.
 const int kInvalidImageResourceID = -1;
 
 // We reserve a small area on the edge of the workspace area to ensure that
diff --git a/ash/common/shelf/shelf_item_types.cc b/ash/common/shelf/shelf_item_types.cc
index ec86132..74fce98b 100644
--- a/ash/common/shelf/shelf_item_types.cc
+++ b/ash/common/shelf/shelf_item_types.cc
@@ -9,7 +9,4 @@
 ShelfItem::ShelfItem() {}
 ShelfItem::~ShelfItem() {}
 
-ShelfItemDetails::ShelfItemDetails() {}
-ShelfItemDetails::~ShelfItemDetails() {}
-
 }  // namespace ash
diff --git a/ash/common/shelf/shelf_item_types.h b/ash/common/shelf/shelf_item_types.h
index 68fd849c..02a8a5a8 100644
--- a/ash/common/shelf/shelf_item_types.h
+++ b/ash/common/shelf/shelf_item_types.h
@@ -9,7 +9,6 @@
 
 #include "ash/ash_export.h"
 #include "ash/common/shelf/shelf_constants.h"
-#include "base/strings/string16.h"
 #include "ui/gfx/image/image_skia.h"
 
 namespace ash {
@@ -76,21 +75,6 @@
 
 typedef std::vector<ShelfItem> ShelfItems;
 
-// Windows with ShelfItemDetails appear in the shelf.
-// See ShelfWindowWatcher for details.
-struct ASH_EXPORT ShelfItemDetails {
-  ShelfItemDetails();
-  ~ShelfItemDetails();
-
-  ShelfItemType type = TYPE_UNDEFINED;
-
-  // Resource id of the image to display on the shelf.
-  int image_resource_id = kInvalidImageResourceID;
-
-  // Title of the item.
-  base::string16 title;
-};
-
 }  // namespace ash
 
 #endif  // ASH_COMMON_SHELF_SHELF_ITEM_TYPES_H_
diff --git a/ash/common/shelf/shelf_view.cc b/ash/common/shelf/shelf_view.cc
index 05076cc..e9c16d4a 100644
--- a/ash/common/shelf/shelf_view.cc
+++ b/ash/common/shelf/shelf_view.cc
@@ -1709,6 +1709,8 @@
     new_view->SetBoundsRect(old_view->bounds());
     if (overflow_button_ && overflow_button_->visible())
       AnimateToIdealBounds();
+    else
+      bounds_animator_->AnimateViewTo(new_view, old_ideal_bounds);
     return;
   }
 
diff --git a/ash/common/shelf/shelf_window_watcher.cc b/ash/common/shelf/shelf_window_watcher.cc
index 3288f95..7bf4873 100644
--- a/ash/common/shelf/shelf_window_watcher.cc
+++ b/ash/common/shelf/shelf_window_watcher.cc
@@ -23,19 +23,20 @@
 namespace ash {
 namespace {
 
-// Sets ShelfItem property by using the value of |details|.
-void SetShelfItemDetailsForShelfItem(ash::ShelfItem* item,
-                                     const ash::ShelfItemDetails& details) {
-  item->type = details.type;
-  if (details.image_resource_id != ash::kInvalidImageResourceID) {
-    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-    item->image = *rb.GetImageSkiaNamed(details.image_resource_id);
-  }
+// Update the ShelfItem from relevant window properties.
+void UpdateShelfItemForWindow(ShelfItem* item, WmWindow* window) {
+  item->type = static_cast<ShelfItemType>(
+      window->GetIntProperty(WmWindowProperty::SHELF_ITEM_TYPE));
+  const int icon =
+      window->GetIntProperty(WmWindowProperty::SHELF_ICON_RESOURCE_ID);
+  if (icon != kInvalidImageResourceID)
+    item->image = *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(icon);
 }
 
 // Returns true if |window| has a ShelfItem added by ShelfWindowWatcher.
 bool HasShelfItemForWindow(WmWindow* window) {
-  return window->GetShelfItemDetails() &&
+  return window->GetIntProperty(WmWindowProperty::SHELF_ITEM_TYPE) !=
+             TYPE_UNDEFINED &&
          window->GetIntProperty(WmWindowProperty::SHELF_ID) != kInvalidShelfID;
 }
 
@@ -74,8 +75,10 @@
 void ShelfWindowWatcher::UserWindowObserver::OnWindowPropertyChanged(
     WmWindow* window,
     WmWindowProperty property) {
-  if (property == WmWindowProperty::SHELF_ITEM_DETAILS)
-    window_watcher_->OnUserWindowShelfItemDetailsChanged(window);
+  if (property == WmWindowProperty::SHELF_ITEM_TYPE ||
+      property == WmWindowProperty::SHELF_ICON_RESOURCE_ID) {
+    window_watcher_->OnUserWindowPropertyChanged(window);
+  }
 }
 
 void ShelfWindowWatcher::UserWindowObserver::OnWindowDestroying(
@@ -106,11 +109,10 @@
 }
 
 void ShelfWindowWatcher::AddShelfItem(WmWindow* window) {
-  const ShelfItemDetails* item_details = window->GetShelfItemDetails();
   ShelfItem item;
   ShelfID id = model_->next_id();
   item.status = window->IsActive() ? STATUS_ACTIVE : STATUS_RUNNING;
-  SetShelfItemDetailsForShelfItem(&item, *item_details);
+  UpdateShelfItemForWindow(&item, window);
   window->SetIntProperty(WmWindowProperty::SHELF_ID, id);
   std::unique_ptr<ShelfItemDelegate> item_delegate(
       new ShelfWindowWatcherItemDelegate(window));
@@ -148,15 +150,15 @@
 
 void ShelfWindowWatcher::OnUserWindowAdded(WmWindow* window) {
   // The window may already be tracked from when it was added to a different
-  // display or because an existing window added ShelfItemDetails to itself.
+  // display or because an existing window added its shelf item properties.
   if (observed_user_windows_.IsObserving(window))
     return;
 
   observed_user_windows_.Add(window);
 
-  // Add ShelfItem if |window| already has a ShelfItemDetails when it is
-  // created.
-  if (window->GetShelfItemDetails() &&
+  // Add a ShelfItem if |window| has a valid ShelfItemType on creation.
+  if (window->GetIntProperty(WmWindowProperty::SHELF_ITEM_TYPE) !=
+          TYPE_UNDEFINED &&
       window->GetIntProperty(WmWindowProperty::SHELF_ID) == kInvalidShelfID) {
     AddShelfItem(window);
   }
@@ -170,21 +172,21 @@
     RemoveShelfItem(window);
 }
 
-void ShelfWindowWatcher::OnUserWindowShelfItemDetailsChanged(WmWindow* window) {
-  if (!window->GetShelfItemDetails()) {
+void ShelfWindowWatcher::OnUserWindowPropertyChanged(WmWindow* window) {
+  if (window->GetIntProperty(WmWindowProperty::SHELF_ITEM_TYPE) ==
+      TYPE_UNDEFINED) {
     // Removes ShelfItem for |window| when it has a ShelfItem.
     if (window->GetIntProperty(WmWindowProperty::SHELF_ID) != kInvalidShelfID)
       RemoveShelfItem(window);
     return;
   }
 
-  // When ShelfItemDetails is changed, update ShelfItem.
+  // Update an existing ShelfItem for |window| when a property has changed.
   if (HasShelfItemForWindow(window)) {
     int index = GetShelfItemIndexForWindow(window);
     DCHECK_GE(index, 0);
     ShelfItem item = model_->items()[index];
-    const ShelfItemDetails* details = window->GetShelfItemDetails();
-    SetShelfItemDetailsForShelfItem(&item, *details);
+    UpdateShelfItemForWindow(&item, window);
     model_->Set(index, item);
     return;
   }
diff --git a/ash/common/shelf/shelf_window_watcher.h b/ash/common/shelf/shelf_window_watcher.h
index 1fa1128..45565e8 100644
--- a/ash/common/shelf/shelf_window_watcher.h
+++ b/ash/common/shelf/shelf_window_watcher.h
@@ -17,7 +17,7 @@
 class WmWindow;
 
 // ShelfWindowWatcher creates and handles a ShelfItem for windows in the default
-// container that have a ShelfItemDetails property (e.g. the task manager
+// container that have a valid ShelfItemType property (e.g. the task manager
 // dialog or the OS settings window). It adds the ShelfItem when the window is
 // added to the default container and maintains it until the window is closed,
 // even if the window is transiently reparented (e.g. during a drag).
@@ -46,7 +46,7 @@
   };
 
   // Observes individual user windows to detect when they are closed or when
-  // they have ShelfItemDetails changed.
+  // their shelf item properties have changed.
   class UserWindowObserver : public WmWindowObserver {
    public:
     explicit UserWindowObserver(ShelfWindowWatcher* window_watcher);
@@ -63,7 +63,7 @@
     DISALLOW_COPY_AND_ASSIGN(UserWindowObserver);
   };
 
-  // Creates a ShelfItem for |window| that has ShelfItemDetails.
+  // Creates a ShelfItem for |window|.
   void AddShelfItem(WmWindow* window);
 
   // Removes a ShelfItem for |window|.
@@ -79,11 +79,11 @@
   void OnContainerWindowDestroying(WmWindow* container);
 
   // Adds a shelf item for new windows added to the default container that have
-  // a ShelfItemDetails property.
+  // a valid ShelfItemType property value.
   void OnUserWindowAdded(WmWindow* window);
 
   // Adds, updates or removes the shelf item based on a property change.
-  void OnUserWindowShelfItemDetailsChanged(WmWindow* window);
+  void OnUserWindowPropertyChanged(WmWindow* window);
 
   // Removes the shelf item when a window closes.
   void OnUserWindowDestroying(WmWindow* window);
diff --git a/ash/common/shelf/shelf_window_watcher_item_delegate.cc b/ash/common/shelf/shelf_window_watcher_item_delegate.cc
index 91a12e3..a1450e1 100644
--- a/ash/common/shelf/shelf_window_watcher_item_delegate.cc
+++ b/ash/common/shelf/shelf_window_watcher_item_delegate.cc
@@ -4,8 +4,6 @@
 
 #include "ash/common/shelf/shelf_window_watcher_item_delegate.h"
 
-#include "ash/common/shelf/shelf_item_types.h"
-#include "ash/common/wm/window_state.h"
 #include "ash/common/wm_window.h"
 #include "ui/events/event.h"
 
@@ -18,23 +16,20 @@
 
 ShelfItemDelegate::PerformedAction ShelfWindowWatcherItemDelegate::ItemSelected(
     const ui::Event& event) {
-  wm::WindowState* window_state = window_->GetWindowState();
-  if (window_state->IsActive()) {
+  if (window_->IsActive()) {
     if (event.type() & ui::ET_KEY_RELEASED) {
       window_->Animate(::wm::WINDOW_ANIMATION_TYPE_BOUNCE);
       return kNoAction;
-    } else {
-      window_state->Minimize();
-      return kExistingWindowMinimized;
     }
-  } else {
-    window_state->Activate();
-    return kExistingWindowActivated;
+    window_->Minimize();
+    return kExistingWindowMinimized;
   }
+  window_->Activate();
+  return kExistingWindowActivated;
 }
 
 base::string16 ShelfWindowWatcherItemDelegate::GetTitle() {
-  return window_->GetShelfItemDetails()->title;
+  return window_->GetTitle();
 }
 
 ShelfMenuModel* ShelfWindowWatcherItemDelegate::CreateApplicationMenu(
diff --git a/ash/common/shelf/shelf_window_watcher_unittest.cc b/ash/common/shelf/shelf_window_watcher_unittest.cc
index 08413b65..fdbeb52 100644
--- a/ash/common/shelf/shelf_window_watcher_unittest.cc
+++ b/ash/common/shelf/shelf_window_watcher_unittest.cc
@@ -12,6 +12,7 @@
 #include "ash/common/wm_lookup.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
+#include "ash/common/wm_window_property.h"
 #include "ash/test/ash_test_base.h"
 #include "ui/base/hit_test.h"
 #include "ui/views/widget/widget.h"
@@ -35,9 +36,7 @@
 
   ShelfID CreateShelfItem(WmWindow* window) {
     ShelfID id = model_->next_id();
-    ShelfItemDetails item_details;
-    item_details.type = TYPE_PLATFORM_APP;
-    window->SetShelfItemDetails(item_details);
+    window->SetIntProperty(WmWindowProperty::SHELF_ITEM_TYPE, TYPE_DIALOG);
     return id;
   }
 
@@ -53,7 +52,7 @@
   // ShelfModel only has an APP_LIST item.
   EXPECT_EQ(1, model_->item_count());
 
-  // Adding windows with ShelfItemDetails properties adds shelf items.
+  // Adding windows with valid ShelfItemType properties adds shelf items.
   std::unique_ptr<views::Widget> widget1 =
       CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect());
   CreateShelfItem(WmLookup::Get()->GetWindowForWidget(widget1.get()));
@@ -70,11 +69,11 @@
   EXPECT_EQ(1, model_->item_count());
 }
 
-TEST_F(ShelfWindowWatcherTest, CreateAndRemoveShelfItemDetails) {
+TEST_F(ShelfWindowWatcherTest, CreateAndRemoveShelfItemProperties) {
   // ShelfModel only has an APP_LIST item.
   EXPECT_EQ(1, model_->item_count());
 
-  // Creating windows without ShelfItemDetails does not add items.
+  // Creating windows without a valid ShelfItemType does not add items.
   std::unique_ptr<views::Widget> widget1 =
       CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect());
   WmWindow* window1 = WmLookup::Get()->GetWindowForWidget(widget1.get());
@@ -97,13 +96,17 @@
   int index_w2 = model_->ItemIndexByID(id_w2);
   EXPECT_EQ(STATUS_ACTIVE, model_->items()[index_w2].status);
 
-  // ShelfItem is removed when its window property is cleared.
-  window1->ClearShelfItemDetails();
+  // ShelfItem is removed when the item type window property is cleared.
+  window1->SetIntProperty(WmWindowProperty::SHELF_ITEM_TYPE, TYPE_UNDEFINED);
   EXPECT_EQ(2, model_->item_count());
-  window2->ClearShelfItemDetails();
+  window2->SetIntProperty(WmWindowProperty::SHELF_ITEM_TYPE, TYPE_UNDEFINED);
   EXPECT_EQ(1, model_->item_count());
   // Clearing twice doesn't do anything.
-  window2->ClearShelfItemDetails();
+  window2->SetIntProperty(WmWindowProperty::SHELF_ITEM_TYPE, TYPE_UNDEFINED);
+  EXPECT_EQ(1, model_->item_count());
+
+  // Setting an icon id (without a valid item type) does not add a shelf item.
+  window2->SetIntProperty(WmWindowProperty::SHELF_ICON_RESOURCE_ID, 1234);
   EXPECT_EQ(1, model_->item_count());
 }
 
@@ -156,11 +159,8 @@
   int index = model_->ItemIndexByID(id);
   EXPECT_EQ(STATUS_ACTIVE, model_->items()[index].status);
 
-  // Update ShelfItem for |window|.
-  ShelfItemDetails details;
-  details.type = TYPE_PLATFORM_APP;
-
-  window->SetShelfItemDetails(details);
+  // Update the ShelfItemType for |window|.
+  window->SetIntProperty(WmWindowProperty::SHELF_ITEM_TYPE, TYPE_PLATFORM_APP);
   // No new item is created after updating a launcher item.
   EXPECT_EQ(2, model_->item_count());
   // index and id are not changed after updating a launcher item.
diff --git a/ash/common/system/tray/tray_background_view.cc b/ash/common/system/tray/tray_background_view.cc
index 91234c6..df868045 100644
--- a/ash/common/system/tray/tray_background_view.cc
+++ b/ash/common/system/tray/tray_background_view.cc
@@ -196,8 +196,10 @@
   UpdateLayout();
 }
 
-void TrayBackgroundView::TrayContainer::SetMargin(const gfx::Insets& margin) {
-  margin_ = margin;
+void TrayBackgroundView::TrayContainer::SetMargin(int main_axis_margin,
+                                                  int cross_axis_margin) {
+  main_axis_margin_ = main_axis_margin;
+  cross_axis_margin_ = cross_axis_margin;
   UpdateLayout();
 }
 
@@ -223,24 +225,30 @@
 }
 
 void TrayBackgroundView::TrayContainer::UpdateLayout() {
+  bool is_horizontal = IsHorizontalAlignment(alignment_);
+
   // Adjust the size of status tray dark background by adding additional
   // empty border.
   views::BoxLayout::Orientation orientation =
-      IsHorizontalAlignment(alignment_) ? views::BoxLayout::kHorizontal
-                                        : views::BoxLayout::kVertical;
+      is_horizontal ? views::BoxLayout::kHorizontal
+                    : views::BoxLayout::kVertical;
   const gfx::Insets insets(
       ash::MaterialDesignController::IsShelfMaterial()
-          ? gfx::Insets(IsHorizontalAlignment(alignment_)
-                            ? gfx::Insets(0, kHitRegionPadding, 0,
-                                          kHitRegionPadding + kSeparatorWidth)
-                            : gfx::Insets(kHitRegionPadding, 0,
-                                          kHitRegionPadding + kSeparatorWidth,
-                                          0))
+          ? is_horizontal ? gfx::Insets(0, kHitRegionPadding, 0,
+                                        kHitRegionPadding + kSeparatorWidth)
+                          : gfx::Insets(kHitRegionPadding, 0,
+                                        kHitRegionPadding + kSeparatorWidth, 0)
           : gfx::Insets(kBackgroundAdjustPadding));
-  SetBorder(views::Border::CreateEmptyBorder(insets + margin_));
+  const gfx::Insets margin(
+      is_horizontal ? gfx::Insets(cross_axis_margin_, main_axis_margin_)
+                    : gfx::Insets(main_axis_margin_, cross_axis_margin_));
+  SetBorder(views::Border::CreateEmptyBorder(insets + margin));
+
   views::BoxLayout* layout = new views::BoxLayout(orientation, 0, 0, 0);
   layout->SetDefaultFlex(1);
+  layout->set_minimum_cross_axis_size(kTrayItemSize);
   views::View::SetLayoutManager(layout);
+
   PreferredSizeChanged();
 }
 
diff --git a/ash/common/system/tray/tray_background_view.h b/ash/common/system/tray/tray_background_view.h
index fc3821709..41d5dbbe 100644
--- a/ash/common/system/tray/tray_background_view.h
+++ b/ash/common/system/tray/tray_background_view.h
@@ -43,7 +43,7 @@
 
     void set_size(const gfx::Size& size) { size_ = size; }
 
-    void SetMargin(const gfx::Insets& margin);
+    void SetMargin(int main_axis_margin, int cross_axis_margin);
 
     // views::View:
     gfx::Size GetPreferredSize() const override;
@@ -60,7 +60,8 @@
 
     ShelfAlignment alignment_;
     gfx::Size size_;
-    gfx::Insets margin_;
+    int main_axis_margin_ = 0;
+    int cross_axis_margin_ = 0;
 
     DISALLOW_COPY_AND_ASSIGN(TrayContainer);
   };
diff --git a/ash/common/system/web_notification/web_notification_tray.cc b/ash/common/system/web_notification/web_notification_tray.cc
index 078c811f..145e35f 100644
--- a/ash/common/system/web_notification/web_notification_tray.cc
+++ b/ash/common/system/web_notification/web_notification_tray.cc
@@ -70,7 +70,8 @@
 constexpr gfx::Size kTrayItemInnerIconSize(16, 16);
 constexpr gfx::Size kTrayItemInnerBellIconSizeNonMd(18, 18);
 constexpr gfx::Size kTrayItemOuterSize(26, 26);
-constexpr gfx::Insets kTrayItemInsets(3, 3);
+constexpr int kTrayMainAxisInset = 3;
+constexpr int kTrayCrossAxisInset = 0;
 
 constexpr int kTrayItemAnimationDurationMS = 200;
 
@@ -334,7 +335,7 @@
                                             display);
   OnMessageCenterTrayChanged();
 
-  tray_container()->SetMargin(kTrayItemInsets);
+  tray_container()->SetMargin(kTrayMainAxisInset, kTrayCrossAxisInset);
 }
 
 WebNotificationTray::~WebNotificationTray() {
diff --git a/ash/common/test/ash_test.cc b/ash/common/test/ash_test.cc
new file mode 100644
index 0000000..8803096
--- /dev/null
+++ b/ash/common/test/ash_test.cc
@@ -0,0 +1,70 @@
+// 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.
+
+#include "ash/common/test/ash_test.h"
+
+#include "ash/common/test/ash_test_impl.h"
+#include "ash/common/wm_shell.h"
+#include "ash/common/wm_window.h"
+#include "ui/compositor/layer_type.h"
+#include "ui/display/display.h"
+
+namespace ash {
+
+WindowOwner::WindowOwner(WmWindow* window) : window_(window) {}
+
+WindowOwner::~WindowOwner() {
+  window_->Destroy();
+}
+
+AshTest::AshTest() : test_impl_(AshTestImpl::Create()) {}
+
+AshTest::~AshTest() {}
+
+bool AshTest::SupportsMultipleDisplays() const {
+  return test_impl_->SupportsMultipleDisplays();
+}
+
+void AshTest::UpdateDisplay(const std::string& display_spec) {
+  return test_impl_->UpdateDisplay(display_spec);
+}
+
+std::unique_ptr<WindowOwner> AshTest::CreateTestWindow(const gfx::Rect& bounds,
+                                                       ui::wm::WindowType type,
+                                                       int shell_window_id) {
+  return test_impl_->CreateTestWindow(bounds, type, shell_window_id);
+}
+
+std::unique_ptr<WindowOwner> AshTest::CreateChildWindow(WmWindow* parent,
+                                                        const gfx::Rect& bounds,
+                                                        int shell_window_id) {
+  std::unique_ptr<WindowOwner> window_owner =
+      base::MakeUnique<WindowOwner>(WmShell::Get()->NewWindow(
+          ui::wm::WINDOW_TYPE_NORMAL, ui::LAYER_NOT_DRAWN));
+  window_owner->window()->SetBounds(bounds);
+  window_owner->window()->SetShellWindowId(shell_window_id);
+  parent->AddChild(window_owner->window());
+  window_owner->window()->Show();
+  return window_owner;
+}
+
+display::Display AshTest::GetSecondaryDisplay() {
+  return test_impl_->GetSecondaryDisplay();
+}
+
+bool AshTest::SetSecondaryDisplayPlacement(
+    display::DisplayPlacement::Position position,
+    int offset) {
+  return test_impl_->SetSecondaryDisplayPlacement(position, offset);
+}
+
+void AshTest::SetUp() {
+  test_impl_->SetUp();
+}
+
+void AshTest::TearDown() {
+  test_impl_->TearDown();
+}
+
+}  // namespace ash
diff --git a/ash/common/test/ash_test.h b/ash/common/test/ash_test.h
new file mode 100644
index 0000000..161732a5
--- /dev/null
+++ b/ash/common/test/ash_test.h
@@ -0,0 +1,103 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_COMMON_TEST_ASH_TEST_H_
+#define ASH_COMMON_TEST_ASH_TEST_H_
+
+#include <memory>
+#include <string>
+
+#include "ash/common/shell_window_ids.h"
+#include "base/macros.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/display/manager/display_layout.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/wm/public/window_types.h"
+
+namespace display {
+class Display;
+}
+
+namespace ash {
+
+class AshTestImpl;
+class WmWindow;
+
+// Wraps a WmWindow calling WmWindow::Destroy() from the destructor. WmWindow is
+// owned by the corresponding window implementation. The only way to delete
+// WmWindow is to call WmWindow::Destroy(), which deletes the corresponding
+// window, then the WmWindow. This class calls WmWindow::Destroy() from its
+// destructor.
+class WindowOwner {
+ public:
+  explicit WindowOwner(WmWindow* window);
+  ~WindowOwner();
+
+  WmWindow* window() { return window_; }
+
+ private:
+  WmWindow* window_;
+
+  DISALLOW_COPY_AND_ASSIGN(WindowOwner);
+};
+
+// Base class for ash tests. This class calls through to AshTestImpl for the
+// real implementation. This class exists so that tests can be written to
+// ash/common and run in both mus and aura.
+//
+// The implementation of AshTestImpl that is used depends upon gn targets. To
+// use the aura backend depend on "//ash:ash_with_aura_test_support." The mus
+// backend is not provided as a separate link target.
+class AshTest : public testing::Test {
+ public:
+  AshTest();
+  ~AshTest() override;
+
+  bool SupportsMultipleDisplays() const;
+
+  // Update the display configuration as given in |display_spec|.
+  // See test::DisplayManagerTestApi::UpdateDisplay for more details.
+  void UpdateDisplay(const std::string& display_spec);
+
+  // Creates a top level visible window in the appropriate container. If
+  // |bounds_in_screen| is empty the window is added to the primary root window,
+  // otherwise the window is added to the display matching |bounds_in_screen|.
+  // |shell_window_id| is the shell window id to give to the new window.
+  std::unique_ptr<WindowOwner> CreateTestWindow(
+      const gfx::Rect& bounds_in_screen = gfx::Rect(),
+      ui::wm::WindowType type = ui::wm::WINDOW_TYPE_NORMAL,
+      int shell_window_id = kShellWindowId_Invalid);
+
+  // Creates a visible window parented to |parent| with the specified bounds and
+  // id.
+  std::unique_ptr<WindowOwner> CreateChildWindow(
+      WmWindow* parent,
+      const gfx::Rect& bounds = gfx::Rect(),
+      int shell_window_id = kShellWindowId_Invalid);
+
+  // Returns the Display for the secondary display. It's assumed there are two
+  // displays.
+  display::Display GetSecondaryDisplay();
+
+  // Sets the placement of the secondary display. Returns true if the secondary
+  // display can be moved, false otherwise. The false return value is temporary
+  // until mus fully supports this.
+  bool SetSecondaryDisplayPlacement(
+      display::DisplayPlacement::Position position,
+      int offset);
+
+ protected:
+  // testing::Test:
+  void SetUp() override;
+  void TearDown() override;
+
+ private:
+  std::unique_ptr<AshTestImpl> test_impl_;
+
+  DISALLOW_COPY_AND_ASSIGN(AshTest);
+};
+
+}  // namespace ash
+
+#endif  // ASH_COMMON_TEST_ASH_TEST_H_
diff --git a/ash/common/test/ash_test_impl.h b/ash/common/test/ash_test_impl.h
new file mode 100644
index 0000000..0b5cf69
--- /dev/null
+++ b/ash/common/test/ash_test_impl.h
@@ -0,0 +1,54 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_COMMON_TEST_ASH_TEST_IMPL_H_
+#define ASH_COMMON_TEST_ASH_TEST_IMPL_H_
+
+#include <memory>
+#include <string>
+
+#include "ui/display/manager/display_layout.h"
+#include "ui/views/widget/widget.h"
+#include "ui/wm/public/window_types.h"
+
+namespace display {
+class Display;
+}
+
+namespace gfx {
+class Rect;
+}
+
+namespace ash {
+
+class WindowOwner;
+class WmWindow;
+
+// Provides the real implementation of AshTest, see it for details.
+class AshTestImpl {
+ public:
+  virtual ~AshTestImpl() {}
+
+  // Factory function for creating AshTestImpl. Implemention that is used
+  // depends upon build dependencies.
+  static std::unique_ptr<AshTestImpl> Create();
+
+  // These functions mirror that of AshTest, see it for details.
+  virtual void SetUp() = 0;
+  virtual void TearDown() = 0;
+  virtual bool SupportsMultipleDisplays() const = 0;
+  virtual void UpdateDisplay(const std::string& display_spec) = 0;
+  virtual std::unique_ptr<WindowOwner> CreateTestWindow(
+      const gfx::Rect& bounds_in_screen,
+      ui::wm::WindowType type,
+      int shell_window_id) = 0;
+  virtual display::Display GetSecondaryDisplay() = 0;
+  virtual bool SetSecondaryDisplayPlacement(
+      display::DisplayPlacement::Position position,
+      int offset) = 0;
+};
+
+}  // namespace ash
+
+#endif  // ASH_COMMON_TEST_ASH_TEST_IMPL_H_
diff --git a/ash/common/wm/system_modal_container_layout_manager.cc b/ash/common/wm/system_modal_container_layout_manager.cc
index 4185abf..1a895ab 100644
--- a/ash/common/wm/system_modal_container_layout_manager.cc
+++ b/ash/common/wm/system_modal_container_layout_manager.cc
@@ -52,6 +52,21 @@
 ////////////////////////////////////////////////////////////////////////////////
 // SystemModalContainerLayoutManager, WmLayoutManager implementation:
 
+void SystemModalContainerLayoutManager::OnChildWindowVisibilityChanged(
+    WmWindow* window,
+    bool visible) {
+  if (GetModalType(window) != ui::MODAL_TYPE_SYSTEM)
+    return;
+
+  if (window->IsVisible()) {
+    DCHECK(!base::ContainsValue(modal_windows_, window));
+    AddModalWindow(window);
+  } else {
+    if (RemoveModalWindow(window))
+      WmShell::Get()->OnModalWindowRemoved(window);
+  }
+}
+
 void SystemModalContainerLayoutManager::OnWindowResized() {
   PositionDialogsAfterWorkAreaResize();
 }
@@ -110,20 +125,6 @@
   }
 }
 
-void SystemModalContainerLayoutManager::OnWindowVisibilityChanged(
-    WmWindow* window,
-    bool visible) {
-  if (GetModalType(window) != ui::MODAL_TYPE_SYSTEM)
-    return;
-
-  if (window->IsVisible()) {
-    AddModalWindow(window);
-  } else {
-    RemoveModalWindow(window);
-    WmShell::Get()->OnModalWindowRemoved(window);
-  }
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // SystemModalContainerLayoutManager, Keyboard::KeybaordControllerObserver
 // implementation:
diff --git a/ash/common/wm/system_modal_container_layout_manager.h b/ash/common/wm/system_modal_container_layout_manager.h
index 18fe75d..7bf81c8 100644
--- a/ash/common/wm/system_modal_container_layout_manager.h
+++ b/ash/common/wm/system_modal_container_layout_manager.h
@@ -36,6 +36,7 @@
   bool has_window_dimmer() const { return window_dimmer_ != nullptr; }
 
   // Overridden from WmSnapToPixelLayoutManager:
+  void OnChildWindowVisibilityChanged(WmWindow* child, bool visible) override;
   void OnWindowResized() override;
   void OnWindowAddedToLayout(WmWindow* child) override;
   void OnWillRemoveWindowFromLayout(WmWindow* child) override;
@@ -45,7 +46,6 @@
   // Overridden from WmWindowObserver:
   void OnWindowPropertyChanged(WmWindow* window,
                                WmWindowProperty property) override;
-  void OnWindowVisibilityChanged(WmWindow* window, bool visible) override;
 
   // Overridden from keyboard::KeyboardControllerObserver:
   void OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) override;
diff --git a/ash/common/wm_window.h b/ash/common/wm_window.h
index 30a0a3c..7f496414 100644
--- a/ash/common/wm_window.h
+++ b/ash/common/wm_window.h
@@ -41,7 +41,6 @@
 namespace ash {
 
 class ImmersiveFullscreenController;
-struct ShelfItemDetails;
 class WmLayoutManager;
 class WmRootWindowController;
 class WmShell;
@@ -81,6 +80,7 @@
   virtual void SetName(const char* name) = 0;
   virtual std::string GetName() const = 0;
 
+  virtual void SetTitle(const base::string16& title) = 0;
   virtual base::string16 GetTitle() const = 0;
 
   // See shell_window_ids.h for list of known ids.
@@ -133,11 +133,6 @@
   virtual int GetIntProperty(WmWindowProperty key) = 0;
   virtual void SetIntProperty(WmWindowProperty key, int value) = 0;
 
-  // Returns null if there are no details.
-  virtual ShelfItemDetails* GetShelfItemDetails() = 0;
-  virtual void SetShelfItemDetails(const ShelfItemDetails& details) = 0;
-  virtual void ClearShelfItemDetails() = 0;
-
   wm::WindowState* GetWindowState() {
     return const_cast<wm::WindowState*>(
         const_cast<const WmWindow*>(this)->GetWindowState());
diff --git a/ash/common/wm_window_observer.h b/ash/common/wm_window_observer.h
index a50b00e..544fa3b 100644
--- a/ash/common/wm_window_observer.h
+++ b/ash/common/wm_window_observer.h
@@ -46,6 +46,9 @@
                                      const gfx::Rect& new_bounds) {}
 
   virtual void OnWindowVisibilityChanging(WmWindow* window, bool visible) {}
+
+  // Behavior of this function matches that of
+  // aura::WindowObserver::OnWindowVisibilityChanged(), see it for details.
   virtual void OnWindowVisibilityChanged(WmWindow* window, bool visible) {}
 
   virtual void OnWindowTitleChanged(WmWindow* window) {}
diff --git a/ash/common/wm_window_property.h b/ash/common/wm_window_property.h
index 57506bea8..2c15da1d 100644
--- a/ash/common/wm_window_property.h
+++ b/ash/common/wm_window_property.h
@@ -18,10 +18,13 @@
   MODAL_TYPE,
 
   // Type int.
+  SHELF_ICON_RESOURCE_ID,
+
+  // Type int.
   SHELF_ID,
 
-  // Type ShelfItemDetails.
-  SHELF_ITEM_DETAILS,
+  // Type int, but cast to ShelfItemType.
+  SHELF_ITEM_TYPE,
 
   // Type bool.
   SNAP_CHILDREN_TO_PIXEL_BOUNDARY,
diff --git a/ash/common/wm_window_unittest.cc b/ash/common/wm_window_unittest.cc
new file mode 100644
index 0000000..58dd29d6
--- /dev/null
+++ b/ash/common/wm_window_unittest.cc
@@ -0,0 +1,81 @@
+// 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.
+
+#include "ash/common/wm_window.h"
+
+#include <memory>
+
+#include "ash/common/test/ash_test.h"
+#include "ash/common/wm_window_observer.h"
+
+namespace ash {
+
+using WmWindowTest = AshTest;
+
+namespace {
+
+// Tracks calls to OnWindowVisibilityChanged().
+class VisibilityObserver : public WmWindowObserver {
+ public:
+  // Attaches a WmWindowObserver to |window_to_add_observer_to| and sets
+  // |last_observed_window_| and |last_observed_visible_value_| to the values
+  // of the last call to OnWindowVisibilityChanged().
+  explicit VisibilityObserver(WmWindow* window_to_add_observer_to)
+      : window_to_add_observer_to_(window_to_add_observer_to) {
+    window_to_add_observer_to_->AddObserver(this);
+  }
+  ~VisibilityObserver() override {
+    window_to_add_observer_to_->RemoveObserver(this);
+  }
+
+  // The values last supplied to OnWindowVisibilityChanged().
+  WmWindow* last_observed_window() { return last_observed_window_; }
+  bool last_observed_visible_value() const {
+    return last_observed_visible_value_;
+  }
+
+  // WmWindowObserver:
+  void OnWindowVisibilityChanged(WmWindow* window, bool visible) override {
+    last_observed_window_ = window;
+    last_observed_visible_value_ = visible;
+  }
+
+ private:
+  WmWindow* window_to_add_observer_to_;
+  WmWindow* last_observed_window_ = nullptr;
+  bool last_observed_visible_value_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(VisibilityObserver);
+};
+
+}  // namespace
+
+// Verifies OnWindowVisibilityChanged() is called on a WmWindowObserver attached
+// to the parent when the child window's visibility changes.
+TEST_F(WmWindowTest, OnWindowVisibilityChangedCalledOnAncestor) {
+  std::unique_ptr<WindowOwner> window_owner = CreateTestWindow();
+  WmWindow* window = window_owner->window();
+  std::unique_ptr<WindowOwner> child_owner =
+      CreateChildWindow(window_owner->window());
+  WmWindow* child_window = child_owner->window();
+  VisibilityObserver observer(window);
+  child_window->Hide();
+  EXPECT_EQ(child_window, observer.last_observed_window());
+  EXPECT_FALSE(observer.last_observed_visible_value());
+}
+
+// Verifies OnWindowVisibilityChanged() is called on a WmWindowObserver attached
+// to a child when the parent window's visibility changes.
+TEST_F(WmWindowTest, OnWindowVisibilityChangedCalledOnChild) {
+  std::unique_ptr<WindowOwner> parent_window_owner = CreateTestWindow();
+  WmWindow* parent_window = parent_window_owner->window();
+  std::unique_ptr<WindowOwner> child_owner = CreateChildWindow(parent_window);
+  WmWindow* child_window = child_owner->window();
+  VisibilityObserver observer(child_window);
+  parent_window->Hide();
+  EXPECT_EQ(parent_window, observer.last_observed_window());
+  EXPECT_FALSE(observer.last_observed_visible_value());
+}
+
+}  // namespace ash
diff --git a/ash/mus/BUILD.gn b/ash/mus/BUILD.gn
index 01b9f210..ecc4cee 100644
--- a/ash/mus/BUILD.gn
+++ b/ash/mus/BUILD.gn
@@ -212,6 +212,7 @@
   testonly = true
 
   sources = [
+    "../common/wm_window_unittest.cc",
     "accelerators/accelerator_controller_registrar_test_api.cc",
     "accelerators/accelerator_controller_registrar_test_api.h",
     "accelerators/accelerator_controller_unittest.cc",
@@ -221,6 +222,8 @@
     "bridge/wm_window_mus_test_api.h",
     "layout_manager_unittest.cc",
     "root_window_controller_unittest.cc",
+    "test/ash_test_impl_mus.cc",
+    "test/ash_test_impl_mus.h",
     "test/wm_test_base.cc",
     "test/wm_test_base.h",
     "test/wm_test_helper.cc",
diff --git a/ash/mus/bridge/wm_window_mus.cc b/ash/mus/bridge/wm_window_mus.cc
index d0234c6..553dca55 100644
--- a/ash/mus/bridge/wm_window_mus.cc
+++ b/ash/mus/bridge/wm_window_mus.cc
@@ -4,6 +4,7 @@
 
 #include "ash/mus/bridge/wm_window_mus.h"
 
+#include "ash/common/shelf/shelf_item_types.h"
 #include "ash/common/wm/container_finder.h"
 #include "ash/common/wm/window_positioning_utils.h"
 #include "ash/common/wm/window_state.h"
@@ -24,6 +25,7 @@
 #include "ui/aura/window.h"
 #include "ui/base/hit_test.h"
 #include "ui/display/display.h"
+#include "ui/resources/grit/ui_resources.h"
 #include "ui/views/view.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_delegate.h"
@@ -43,9 +45,8 @@
 
 namespace {
 
-// This classes is used so that the WindowState constructor can be made
-// protected. GetWindowState() is the only place that should be creating
-// WindowState.
+// This class is used so that the WindowState constructor can be made protected.
+// GetWindowState() is the only place that should be creating WindowState.
 class WindowStateMus : public wm::WindowState {
  public:
   explicit WindowStateMus(WmWindow* window) : wm::WindowState(window) {}
@@ -195,6 +196,10 @@
              : std::string();
 }
 
+void WmWindowMus::SetTitle(const base::string16& title) {
+  SetWindowTitle(window_, title);
+}
+
 base::string16 WmWindowMus::GetTitle() const {
   return GetWindowTitle(window_);
 }
@@ -373,17 +378,6 @@
 }
 
 int WmWindowMus::GetIntProperty(WmWindowProperty key) {
-  if (key == WmWindowProperty::SHELF_ID) {
-    NOTIMPLEMENTED();
-    return 0;
-  }
-
-  if (key == WmWindowProperty::TOP_VIEW_INSET) {
-    // TODO: need support for TOP_VIEW_INSET: http://crbug.com/615100.
-    NOTIMPLEMENTED();
-    return 0;
-  }
-
   if (key == WmWindowProperty::MODAL_TYPE) {
     // TODO: WindowTree::SetModalWindow() needs to route through WindowManager
     // so wm can position. http://crbug.com/645996.
@@ -391,16 +385,62 @@
     return static_cast<int>(ui::MODAL_TYPE_NONE);
   }
 
+  if (key == WmWindowProperty::SHELF_ICON_RESOURCE_ID) {
+    if (window_->HasSharedProperty(
+            ui::mojom::WindowManager::kShelfIconResourceId_Property)) {
+      return window_->GetSharedProperty<int>(
+          ui::mojom::WindowManager::kShelfIconResourceId_Property);
+    }
+    // Mash provides a default shelf icon image.
+    // TODO(msw): Support icon resource ids and bitmaps:
+    // mojo::Array<uint8_t> app_icon = GetWindowAppIcon(window_);
+    return IDR_DEFAULT_FAVICON;
+  }
+
+  if (key == WmWindowProperty::SHELF_ID) {
+    NOTIMPLEMENTED();
+    return kInvalidShelfID;
+  }
+
+  if (key == WmWindowProperty::SHELF_ITEM_TYPE) {
+    if (window_->HasSharedProperty(
+            ui::mojom::WindowManager::kShelfItemType_Property)) {
+      return window_->GetSharedProperty<int>(
+          ui::mojom::WindowManager::kShelfItemType_Property);
+    }
+    // Mash provides a default shelf item type for non-ignored windows.
+    return GetWindowIgnoredByShelf(window_) ? TYPE_UNDEFINED
+                                            : TYPE_PLATFORM_APP;
+  }
+
+  if (key == WmWindowProperty::TOP_VIEW_INSET) {
+    // TODO: need support for TOP_VIEW_INSET: http://crbug.com/615100.
+    NOTIMPLEMENTED();
+    return 0;
+  }
+
   NOTREACHED();
   return 0;
 }
 
 void WmWindowMus::SetIntProperty(WmWindowProperty key, int value) {
+  if (key == WmWindowProperty::SHELF_ICON_RESOURCE_ID) {
+    window_->SetSharedProperty<int>(
+        ui::mojom::WindowManager::kShelfIconResourceId_Property, value);
+    return;
+  }
+
   if (key == WmWindowProperty::SHELF_ID) {
     NOTIMPLEMENTED();
     return;
   }
 
+  if (key == WmWindowProperty::SHELF_ITEM_TYPE) {
+    window_->SetSharedProperty<int>(
+        ui::mojom::WindowManager::kShelfItemType_Property, value);
+    return;
+  }
+
   if (key == WmWindowProperty::TOP_VIEW_INSET) {
     // TODO: need support for TOP_VIEW_INSET: http://crbug.com/615100.
     NOTIMPLEMENTED();
@@ -410,19 +450,6 @@
   NOTREACHED();
 }
 
-ShelfItemDetails* WmWindowMus::GetShelfItemDetails() {
-  NOTIMPLEMENTED();  // TODO: Add support; see crbug.com/634150
-  return nullptr;
-}
-
-void WmWindowMus::SetShelfItemDetails(const ShelfItemDetails& details) {
-  NOTIMPLEMENTED();  // TODO: Add support; see crbug.com/634150
-}
-
-void WmWindowMus::ClearShelfItemDetails() {
-  NOTIMPLEMENTED();  // TODO: Add support; see crbug.com/634150
-}
-
 const wm::WindowState* WmWindowMus::GetWindowState() const {
   return window_state_.get();
 }
@@ -922,6 +949,17 @@
   FOR_EACH_OBSERVER(WmWindowObserver, observers_, OnWindowDestroyed(this));
 }
 
+void WmWindowMus::OnWindowVisibilityChanging(ui::Window* window) {
+  DCHECK_EQ(window_, window);
+  FOR_EACH_OBSERVER(WmWindowObserver, observers_,
+                    OnWindowVisibilityChanging(this, !window->visible()));
+}
+
+void WmWindowMus::OnWindowVisibilityChanged(ui::Window* window) {
+  FOR_EACH_OBSERVER(WmWindowObserver, observers_,
+                    OnWindowVisibilityChanged(Get(window), window->visible()));
+}
+
 void WmWindowMus::OnTransientChildAdded(ui::Window* window,
                                         ui::Window* transient) {
   FOR_EACH_OBSERVER(WmTransientWindowObserver, transient_observers_,
diff --git a/ash/mus/bridge/wm_window_mus.h b/ash/mus/bridge/wm_window_mus.h
index 0f0a2b95..6fe223e 100644
--- a/ash/mus/bridge/wm_window_mus.h
+++ b/ash/mus/bridge/wm_window_mus.h
@@ -116,6 +116,7 @@
   WmShell* GetShell() const override;
   void SetName(const char* name) override;
   std::string GetName() const override;
+  void SetTitle(const base::string16& title) override;
   base::string16 GetTitle() const override;
   void SetShellWindowId(int id) override;
   int GetShellWindowId() const override;
@@ -147,9 +148,6 @@
   void SetColorProperty(WmWindowProperty key, SkColor value) override;
   int GetIntProperty(WmWindowProperty key) override;
   void SetIntProperty(WmWindowProperty key, int value) override;
-  ShelfItemDetails* GetShelfItemDetails() override;
-  void SetShelfItemDetails(const ShelfItemDetails& details) override;
-  void ClearShelfItemDetails() override;
   const wm::WindowState* GetWindowState() const override;
   WmWindow* GetToplevelWindow() override;
   WmWindow* GetToplevelWindowForFocus() override;
@@ -262,6 +260,8 @@
                              const gfx::Rect& new_bounds) override;
   void OnWindowDestroying(ui::Window* window) override;
   void OnWindowDestroyed(ui::Window* window) override;
+  void OnWindowVisibilityChanging(ui::Window* window) override;
+  void OnWindowVisibilityChanged(ui::Window* window) override;
   void OnTransientChildAdded(ui::Window* window,
                              ui::Window* transient) override;
   void OnTransientChildRemoved(ui::Window* window,
diff --git a/ash/mus/property_util.cc b/ash/mus/property_util.cc
index 13c3359..4d199df 100644
--- a/ash/mus/property_util.cc
+++ b/ash/mus/property_util.cc
@@ -175,6 +175,11 @@
       window->GetSharedProperty<int32_t>(mojom::kAshWindowType_Property));
 }
 
+void SetWindowTitle(ui::Window* window, base::string16 title) {
+  window->SetSharedProperty<base::string16>(
+      ui::mojom::WindowManager::kWindowTitle_Property, title);
+}
+
 base::string16 GetWindowTitle(const ui::Window* window) {
   if (!window->HasSharedProperty(
           ui::mojom::WindowManager::kWindowTitle_Property)) {
@@ -253,5 +258,12 @@
              ui::mojom::WindowManager::kRendererParentTitleArea_Property);
 }
 
+int64_t GetInitialDisplayId(const ui::Window::SharedProperties& properties) {
+  auto iter =
+      properties.find(ui::mojom::WindowManager::kInitialDisplayId_Property);
+  return iter == properties.end() ? display::Display::kInvalidDisplayID
+                                  : mojo::ConvertTo<int64_t>(iter->second);
+}
+
 }  // namespace mus
 }  // namespace ash
diff --git a/ash/mus/property_util.h b/ash/mus/property_util.h
index 58795bf43..a0ede01 100644
--- a/ash/mus/property_util.h
+++ b/ash/mus/property_util.h
@@ -62,6 +62,7 @@
 
 mojom::AshWindowType GetAshWindowType(const ui::Window* window);
 
+void SetWindowTitle(ui::Window* window, base::string16 title);
 base::string16 GetWindowTitle(const ui::Window* window);
 
 mojo::Array<uint8_t> GetWindowAppIcon(const ui::Window* window);
@@ -83,6 +84,10 @@
 // See description of |WindowManager::kRendererParentTitleArea_Property|.
 bool ShouldRenderParentTitleArea(ui::Window* window);
 
+// Returns the kInitialDisplayId_Property if present, otherwise
+// kInvalidDisplayID.
+int64_t GetInitialDisplayId(const ui::Window::SharedProperties& properties);
+
 }  // namespace mus
 }  // namespace ash
 
diff --git a/ash/mus/test/ash_test_impl_mus.cc b/ash/mus/test/ash_test_impl_mus.cc
new file mode 100644
index 0000000..e530ebe
--- /dev/null
+++ b/ash/mus/test/ash_test_impl_mus.cc
@@ -0,0 +1,86 @@
+// 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.
+
+#include "ash/mus/test/ash_test_impl_mus.h"
+
+#include "ash/common/test/ash_test.h"
+#include "ash/mus/bridge/wm_window_mus.h"
+#include "base/memory/ptr_util.h"
+#include "services/ui/public/cpp/property_type_converters.h"
+#include "services/ui/public/cpp/window.h"
+#include "services/ui/public/cpp/window_property.h"
+#include "services/ui/public/interfaces/window_manager.mojom.h"
+
+namespace ash {
+namespace mus {
+namespace {
+
+// WmTestBase is abstract as TestBody() is pure virtual (the various TEST
+// macros have the implementation). In order to create WmTestBase we have to
+// subclass with an empty implementation of TestBody(). That's ok as the class
+// isn't used as a normal test here.
+class WmTestBaseImpl : public WmTestBase {
+ public:
+  WmTestBaseImpl() {}
+  ~WmTestBaseImpl() override {}
+
+  // WmTestBase:
+  void TestBody() override {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WmTestBaseImpl);
+};
+
+}  // namespace
+
+AshTestImplMus::AshTestImplMus()
+    : wm_test_base_(base::MakeUnique<WmTestBaseImpl>()) {}
+
+AshTestImplMus::~AshTestImplMus() {}
+
+void AshTestImplMus::SetUp() {
+  wm_test_base_->SetUp();
+}
+
+void AshTestImplMus::TearDown() {
+  wm_test_base_->TearDown();
+}
+
+bool AshTestImplMus::SupportsMultipleDisplays() const {
+  return wm_test_base_->SupportsMultipleDisplays();
+}
+
+void AshTestImplMus::UpdateDisplay(const std::string& display_spec) {
+  wm_test_base_->UpdateDisplay(display_spec);
+}
+
+std::unique_ptr<WindowOwner> AshTestImplMus::CreateTestWindow(
+    const gfx::Rect& bounds_in_screen,
+    ui::wm::WindowType type,
+    int shell_window_id) {
+  WmWindowMus* window =
+      WmWindowMus::Get(wm_test_base_->CreateTestWindow(bounds_in_screen, type));
+  window->SetShellWindowId(shell_window_id);
+  return base::MakeUnique<WindowOwner>(window);
+}
+
+display::Display AshTestImplMus::GetSecondaryDisplay() {
+  return wm_test_base_->GetSecondaryDisplay();
+}
+
+bool AshTestImplMus::SetSecondaryDisplayPlacement(
+    display::DisplayPlacement::Position position,
+    int offset) {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+}  // namespace mus
+
+// static
+std::unique_ptr<AshTestImpl> AshTestImpl::Create() {
+  return base::MakeUnique<mus::AshTestImplMus>();
+}
+
+}  // namespace ash
diff --git a/ash/mus/test/ash_test_impl_mus.h b/ash/mus/test/ash_test_impl_mus.h
new file mode 100644
index 0000000..7aa2944
--- /dev/null
+++ b/ash/mus/test/ash_test_impl_mus.h
@@ -0,0 +1,48 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_MUS_TEST_ASH_TEST_IMPL_MUS_H_
+#define ASH_MUS_TEST_ASH_TEST_IMPL_MUS_H_
+
+#include "ash/common/test/ash_test_impl.h"
+#include "ash/mus/test/wm_test_base.h"
+#include "base/macros.h"
+
+namespace ash {
+namespace mus {
+
+class WmTestBase;
+
+// Implementation of AshTestImpl for mus.
+class AshTestImplMus : public AshTestImpl {
+ public:
+  AshTestImplMus();
+  ~AshTestImplMus() override;
+
+  // AshTestImpl:
+  void SetUp() override;
+  void TearDown() override;
+  bool SupportsMultipleDisplays() const override;
+  void UpdateDisplay(const std::string& display_spec) override;
+  std::unique_ptr<WindowOwner> CreateTestWindow(
+      const gfx::Rect& bounds_in_screen,
+      ui::wm::WindowType type,
+      int shell_window_id) override;
+  display::Display GetSecondaryDisplay() override;
+  bool SetSecondaryDisplayPlacement(
+      display::DisplayPlacement::Position position,
+      int offset) override;
+
+ private:
+  // TODO(sky): fold WmTestBase directly into this class when no more subclasses
+  // of WmTestBase.
+  std::unique_ptr<WmTestBase> wm_test_base_;
+
+  DISALLOW_COPY_AND_ASSIGN(AshTestImplMus);
+};
+
+}  // namespace mus
+}  // namespace ash
+
+#endif  // ASH_MUS_TEST_ASH_TEST_IMPL_MUS_H_
diff --git a/ash/mus/test/wm_test_base.h b/ash/mus/test/wm_test_base.h
index 913bf5f..8c17d39 100644
--- a/ash/mus/test/wm_test_base.h
+++ b/ash/mus/test/wm_test_base.h
@@ -27,6 +27,7 @@
 namespace ash {
 namespace mus {
 
+class AshTestImplMus;
 class RootWindowController;
 class WmTestHelper;
 
@@ -69,6 +70,8 @@
   void TearDown() override;
 
  private:
+  friend class AshTestImplMus;
+
   bool setup_called_ = false;
   bool teardown_called_ = false;
   std::unique_ptr<WmTestHelper> test_helper_;
diff --git a/ash/mus/window_manager.cc b/ash/mus/window_manager.cc
index 43124a9..c6de102 100644
--- a/ash/mus/window_manager.cc
+++ b/ash/mus/window_manager.cc
@@ -93,9 +93,8 @@
 
 ui::Window* WindowManager::NewTopLevelWindow(
     std::map<std::string, std::vector<uint8_t>>* properties) {
-  // TODO(sky): need to maintain active as well as allowing specifying display.
   RootWindowController* root_window_controller =
-      root_window_controllers_.begin()->get();
+      GetRootWindowControllerForNewTopLevelWindow(properties);
   return root_window_controller->NewTopLevelWindow(properties);
 }
 
@@ -228,6 +227,23 @@
       ->root_window_controller();
 }
 
+RootWindowController*
+WindowManager::GetRootWindowControllerForNewTopLevelWindow(
+    std::map<std::string, std::vector<uint8_t>>* properties) {
+  // If a specific display was requested, use it.
+  const int64_t display_id = GetInitialDisplayId(*properties);
+  for (auto& root_window_controller_ptr : root_window_controllers_) {
+    if (root_window_controller_ptr->display().id() == display_id)
+      return root_window_controller_ptr.get();
+  }
+
+  return static_cast<WmRootWindowControllerMus*>(
+             WmShellMus::Get()
+                 ->GetRootWindowForNewWindows()
+                 ->GetRootWindowController())
+      ->root_window_controller();
+}
+
 void WindowManager::OnEmbed(ui::Window* root) {
   // WindowManager should never see this, instead OnWmNewDisplay() is called.
   NOTREACHED();
diff --git a/ash/mus/window_manager.h b/ash/mus/window_manager.h
index c24cc52..b7ce20f6 100644
--- a/ash/mus/window_manager.h
+++ b/ash/mus/window_manager.h
@@ -113,6 +113,11 @@
 
   RootWindowController* GetPrimaryRootWindowController();
 
+  // Returns the RootWindowController where new top levels are created.
+  // |properties| is the properties supplied during window creation.
+  RootWindowController* GetRootWindowControllerForNewTopLevelWindow(
+      std::map<std::string, std::vector<uint8_t>>* properties);
+
   // WindowTreeClientDelegate:
   void OnEmbed(ui::Window* root) override;
   void OnEmbedRootDestroyed(ui::Window* root) override;
diff --git a/ash/shelf/shelf_layout_manager_unittest.cc b/ash/shelf/shelf_layout_manager_unittest.cc
index d3e5f95b..67a2161 100644
--- a/ash/shelf/shelf_layout_manager_unittest.cc
+++ b/ash/shelf/shelf_layout_manager_unittest.cc
@@ -1891,11 +1891,8 @@
   GetPrimaryShelf()->SetAlignment(SHELF_ALIGNMENT_BOTTOM);
   generator.MoveMouseTo(inset_display_bounds.bottom_right());
   EXPECT_FALSE(status_area_widget->IsMessageBubbleShown());
-#if !defined(OS_WIN)
   generator.ClickLeftButton();
-  // The bottom right pixel doesn't work on Windows; see crbug.com/633434
   EXPECT_TRUE(status_area_widget->IsMessageBubbleShown());
-#endif
   generator.ClickLeftButton();
   EXPECT_FALSE(status_area_widget->IsMessageBubbleShown());
 
@@ -1903,11 +1900,8 @@
   GetPrimaryShelf()->SetAlignment(SHELF_ALIGNMENT_RIGHT);
   generator.MoveMouseTo(inset_display_bounds.bottom_right());
   EXPECT_FALSE(status_area_widget->IsMessageBubbleShown());
-#if !defined(OS_WIN)
   generator.ClickLeftButton();
-  // The bottom right pixel doesn't work on Windows; see crbug.com/633434
   EXPECT_TRUE(status_area_widget->IsMessageBubbleShown());
-#endif
   generator.ClickLeftButton();
   EXPECT_FALSE(status_area_widget->IsMessageBubbleShown());
 
diff --git a/ash/test/ash_test_base.h b/ash/test/ash_test_base.h
index 01e05f2..c93451ee 100644
--- a/ash/test/ash_test_base.h
+++ b/ash/test/ash_test_base.h
@@ -46,6 +46,7 @@
 }
 
 namespace ash {
+class AshTestImplAura;
 class DisplayManager;
 class SystemTray;
 class WmShelf;
@@ -168,6 +169,8 @@
   void DisableIME();
 
  private:
+  friend class ash::AshTestImplAura;
+
   bool setup_called_;
   bool teardown_called_;
   // |SetUp()| doesn't activate session if this is set to false.
diff --git a/ash/test/ash_test_impl_aura.cc b/ash/test/ash_test_impl_aura.cc
new file mode 100644
index 0000000..cf32bc44
--- /dev/null
+++ b/ash/test/ash_test_impl_aura.cc
@@ -0,0 +1,86 @@
+// 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.
+
+#include "ash/test/ash_test_impl_aura.h"
+
+#include "ash/aura/wm_window_aura.h"
+#include "ash/common/test/ash_test.h"
+#include "ash/display/display_manager.h"
+#include "ash/screen_util.h"
+#include "ash/shell.h"
+#include "ash/test/ash_test_base.h"
+#include "ash/test/display_manager_test_api.h"
+#include "base/memory/ptr_util.h"
+#include "ui/display/manager/display_layout.h"
+#include "ui/display/screen.h"
+
+namespace ash {
+namespace {
+
+// AshTestBase is abstract as TestBody() is pure virtual (the various TEST
+// macros have the implementation). In order to create AshTestBase we have to
+// subclass with an empty implementation of TestBody(). That's ok as the class
+// isn't used as a normal test here.
+class AshTestBaseImpl : public test::AshTestBase {
+ public:
+  AshTestBaseImpl() {}
+  ~AshTestBaseImpl() override {}
+
+  // AshTestBase:
+  void TestBody() override {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AshTestBaseImpl);
+};
+
+}  // namespace
+
+AshTestImplAura::AshTestImplAura()
+    : ash_test_base_(base::MakeUnique<AshTestBaseImpl>()) {}
+
+AshTestImplAura::~AshTestImplAura() {}
+
+void AshTestImplAura::SetUp() {
+  ash_test_base_->SetUp();
+}
+
+void AshTestImplAura::TearDown() {
+  ash_test_base_->TearDown();
+}
+
+bool AshTestImplAura::SupportsMultipleDisplays() const {
+  return ash_test_base_->SupportsMultipleDisplays();
+}
+
+void AshTestImplAura::UpdateDisplay(const std::string& display_spec) {
+  ash_test_base_->UpdateDisplay(display_spec);
+}
+
+std::unique_ptr<WindowOwner> AshTestImplAura::CreateTestWindow(
+    const gfx::Rect& bounds_in_screen,
+    ui::wm::WindowType type,
+    int shell_window_id) {
+  return base::MakeUnique<WindowOwner>(WmWindowAura::Get(
+      ash_test_base_->CreateTestWindowInShellWithDelegateAndType(
+          nullptr, type, shell_window_id, bounds_in_screen)));
+}
+
+display::Display AshTestImplAura::GetSecondaryDisplay() {
+  return ScreenUtil::GetSecondaryDisplay();
+}
+
+bool AshTestImplAura::SetSecondaryDisplayPlacement(
+    display::DisplayPlacement::Position position,
+    int offset) {
+  Shell::GetInstance()->display_manager()->SetLayoutForCurrentDisplays(
+      test::CreateDisplayLayout(position, 0));
+  return true;
+}
+
+// static
+std::unique_ptr<AshTestImpl> AshTestImpl::Create() {
+  return base::MakeUnique<AshTestImplAura>();
+}
+
+}  // namespace ash
diff --git a/ash/test/ash_test_impl_aura.h b/ash/test/ash_test_impl_aura.h
new file mode 100644
index 0000000..c395899c
--- /dev/null
+++ b/ash/test/ash_test_impl_aura.h
@@ -0,0 +1,44 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_MUS_TEST_ASH_TEST_IMPL_AURA_H_
+#define ASH_MUS_TEST_ASH_TEST_IMPL_AURA_H_
+
+#include "ash/common/test/ash_test_impl.h"
+
+namespace ash {
+namespace test {
+class AshTestBase;
+}
+
+// Implementation of AshTestImpl on top of aura. Implementation of AshTestImpl
+// calls through to AshTestBase.
+class AshTestImplAura : public AshTestImpl {
+ public:
+  AshTestImplAura();
+  ~AshTestImplAura() override;
+
+  // AshTestImpl:
+  void SetUp() override;
+  void TearDown() override;
+  bool SupportsMultipleDisplays() const override;
+  void UpdateDisplay(const std::string& display_spec) override;
+  std::unique_ptr<WindowOwner> CreateTestWindow(
+      const gfx::Rect& bounds_in_screen,
+      ui::wm::WindowType type,
+      int shell_window_id) override;
+  display::Display GetSecondaryDisplay() override;
+  bool SetSecondaryDisplayPlacement(
+      display::DisplayPlacement::Position position,
+      int offset) override;
+
+ private:
+  std::unique_ptr<test::AshTestBase> ash_test_base_;
+
+  DISALLOW_COPY_AND_ASSIGN(AshTestImplAura);
+};
+
+}  // namespace ash
+
+#endif  // ASH_MUS_TEST_ASH_TEST_IMPL_AURA_H_
diff --git a/ash/wm/system_modal_container_layout_manager_unittest.cc b/ash/wm/system_modal_container_layout_manager_unittest.cc
index 9ba6dfa..dc95fbd 100644
--- a/ash/wm/system_modal_container_layout_manager_unittest.cc
+++ b/ash/wm/system_modal_container_layout_manager_unittest.cc
@@ -784,6 +784,16 @@
   EXPECT_TRUE(WmShell::Get()->IsSystemModalWindowOpen());
   EXPECT_TRUE(layout_manager->has_window_dimmer());
 
+  // Make sure that a child visibility change should not cause
+  // inconsistent state.
+  std::unique_ptr<aura::Window> child = base::MakeUnique<aura::Window>(nullptr);
+  child->SetType(ui::wm::WINDOW_TYPE_CONTROL);
+  child->Init(ui::LAYER_TEXTURED);
+  modal_window->AddChild(child.get());
+  child->Show();
+  EXPECT_TRUE(WmShell::Get()->IsSystemModalWindowOpen());
+  EXPECT_TRUE(layout_manager->has_window_dimmer());
+
   modal_window->Hide();
   EXPECT_FALSE(WmShell::Get()->IsSystemModalWindowOpen());
   EXPECT_FALSE(layout_manager->has_window_dimmer());
diff --git a/base/files/file_path_watcher.cc b/base/files/file_path_watcher.cc
index a4624ab..e370fcb1 100644
--- a/base/files/file_path_watcher.cc
+++ b/base/files/file_path_watcher.cc
@@ -18,12 +18,6 @@
 }
 
 // static
-void FilePathWatcher::CancelWatch(
-    const scoped_refptr<PlatformDelegate>& delegate) {
-  delegate->CancelOnMessageLoopThread();
-}
-
-// static
 bool FilePathWatcher::RecursiveWatchAvailable() {
 #if (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN) || \
     defined(OS_LINUX) || defined(OS_ANDROID)
diff --git a/base/files/file_path_watcher.h b/base/files/file_path_watcher.h
index d5c6db1ac..7b1483a 100644
--- a/base/files/file_path_watcher.h
+++ b/base/files/file_path_watcher.h
@@ -53,11 +53,6 @@
 
     virtual ~PlatformDelegate();
 
-    // Stop watching. This is only called on the thread of the appropriate
-    // message loop. Since it can also be called more than once, it should
-    // check |is_cancelled()| to avoid duplicate work.
-    virtual void CancelOnMessageLoopThread() = 0;
-
     scoped_refptr<base::SingleThreadTaskRunner> task_runner() const {
       return task_runner_;
     }
diff --git a/base/files/file_path_watcher_fsevents.h b/base/files/file_path_watcher_fsevents.h
index cfbe020b..fbcca1f8 100644
--- a/base/files/file_path_watcher_fsevents.h
+++ b/base/files/file_path_watcher_fsevents.h
@@ -54,7 +54,7 @@
                       const FilePath& resolved_target);
 
   // Cleans up and stops the event stream.
-  void CancelOnMessageLoopThread() override;
+  void CancelOnMessageLoopThread();
 
   // (Re-)Initialize the event stream to start reporting events from
   // |start_event|.
diff --git a/base/files/file_path_watcher_kqueue.h b/base/files/file_path_watcher_kqueue.h
index d9db8c2..365cac53 100644
--- a/base/files/file_path_watcher_kqueue.h
+++ b/base/files/file_path_watcher_kqueue.h
@@ -61,7 +61,7 @@
   typedef std::vector<struct kevent> EventVector;
 
   // Can only be called on |io_task_runner_|'s thread.
-  void CancelOnMessageLoopThread() override;
+  void CancelOnMessageLoopThread();
 
   // Returns true if the kevent values are error free.
   bool AreKeventValuesValid(struct kevent* kevents, int count);
diff --git a/base/files/file_path_watcher_linux.cc b/base/files/file_path_watcher_linux.cc
index 9d50169..958e60c 100644
--- a/base/files/file_path_watcher_linux.cc
+++ b/base/files/file_path_watcher_linux.cc
@@ -120,7 +120,6 @@
 
   // Cancel the watch. This unregisters the instance with InotifyReader.
   void Cancel() override;
-  void CancelOnMessageLoopThread() override;
   void CancelOnMessageLoopThreadOrInDestructor();
 
   // Inotify watches are installed for all directory components of |target_|.
@@ -329,8 +328,8 @@
     return;
   }
 
-  // Check to see if CancelOnMessageLoopThread() has already been called.
-  // May happen when code flow reaches here from the PostTask() above.
+  // Check to see if CancelOnMessageLoopThreadOrInDestructor() has already been
+  // called. May happen when code flow reaches here from the PostTask() above.
   if (watches_.empty()) {
     DCHECK(target_.empty());
     return;
@@ -445,19 +444,17 @@
     return;
   }
 
-  // Switch to the message_loop() if necessary so we can access |watches_|.
+  // Switch to the task_runner() if necessary so we can access |watches_|.
   if (!task_runner()->BelongsToCurrentThread()) {
-    task_runner()->PostTask(FROM_HERE, Bind(&FilePathWatcher::CancelWatch,
-                                            make_scoped_refptr(this)));
+    task_runner()->PostTask(
+        FROM_HERE,
+        Bind(&FilePathWatcherImpl::CancelOnMessageLoopThreadOrInDestructor,
+             this));
   } else {
-    CancelOnMessageLoopThread();
+    CancelOnMessageLoopThreadOrInDestructor();
   }
 }
 
-void FilePathWatcherImpl::CancelOnMessageLoopThread() {
-  CancelOnMessageLoopThreadOrInDestructor();
-}
-
 void FilePathWatcherImpl::CancelOnMessageLoopThreadOrInDestructor() {
   DCHECK(in_destructor_ || task_runner()->BelongsToCurrentThread());
 
@@ -479,7 +476,7 @@
 }
 
 void FilePathWatcherImpl::UpdateWatches() {
-  // Ensure this runs on the message_loop() exclusively in order to avoid
+  // Ensure this runs on the task_runner() exclusively in order to avoid
   // concurrency issues.
   DCHECK(task_runner()->BelongsToCurrentThread());
   DCHECK(HasValidWatchVector());
diff --git a/base/files/file_path_watcher_mac.cc b/base/files/file_path_watcher_mac.cc
index 7338eaf..b65591a2 100644
--- a/base/files/file_path_watcher_mac.cc
+++ b/base/files/file_path_watcher_mac.cc
@@ -40,12 +40,6 @@
     set_cancelled();
   }
 
-  void CancelOnMessageLoopThread() override {
-    if (impl_.get())
-      impl_->Cancel();
-    set_cancelled();
-  }
-
  protected:
   ~FilePathWatcherImpl() override {}
 
diff --git a/base/files/file_path_watcher_stub.cc b/base/files/file_path_watcher_stub.cc
index 8138692e..c637e3c 100644
--- a/base/files/file_path_watcher_stub.cc
+++ b/base/files/file_path_watcher_stub.cc
@@ -21,8 +21,6 @@
 
   void Cancel() override {}
 
-  void CancelOnMessageLoopThread() override {}
-
  protected:
   ~FilePathWatcherImpl() override {}
 };
diff --git a/base/files/file_path_watcher_win.cc b/base/files/file_path_watcher_win.cc
index 9121fa9..3bbf2fb 100644
--- a/base/files/file_path_watcher_win.cc
+++ b/base/files/file_path_watcher_win.cc
@@ -60,7 +60,7 @@
   void DestroyWatch();
 
   // Cleans up and stops observing the |task_runner_| thread.
-  void CancelOnMessageLoopThread() override;
+  void CancelOnMessageLoopThread();
 
   // Callback to notify upon changes.
   FilePathWatcher::Callback callback_;
@@ -122,8 +122,8 @@
 
   // Switch to the file thread if necessary so we can stop |watcher_|.
   if (!task_runner()->BelongsToCurrentThread()) {
-    task_runner()->PostTask(FROM_HERE, Bind(&FilePathWatcher::CancelWatch,
-                                            make_scoped_refptr(this)));
+    task_runner()->PostTask(
+        FROM_HERE, Bind(&FilePathWatcherImpl::CancelOnMessageLoopThread, this));
   } else {
     CancelOnMessageLoopThread();
   }
diff --git a/base/files/important_file_writer.cc b/base/files/important_file_writer.cc
index 0099cda..cc0a616 100644
--- a/base/files/important_file_writer.cc
+++ b/base/files/important_file_writer.cc
@@ -57,13 +57,18 @@
 
 // Helper function to call WriteFileAtomically() with a
 // std::unique_ptr<std::string>.
-void WriteScopedStringToFileAtomically(const FilePath& path,
-                                       std::unique_ptr<std::string> data,
-                                       Callback<void(bool success)> callback) {
+void WriteScopedStringToFileAtomically(
+    const FilePath& path,
+    std::unique_ptr<std::string> data,
+    Closure before_write_callback,
+    Callback<void(bool success)> after_write_callback) {
+  if (!before_write_callback.is_null())
+    before_write_callback.Run();
+
   bool result = ImportantFileWriter::WriteFileAtomically(path, *data);
 
-  if (!callback.is_null())
-    callback.Run(result);
+  if (!after_write_callback.is_null())
+    after_write_callback.Run(result);
 }
 
 }  // namespace
@@ -173,7 +178,8 @@
     timer_.Stop();
 
   Closure task = Bind(&WriteScopedStringToFileAtomically, path_, Passed(&data),
-                      Passed(&on_next_write_callback_));
+                      Passed(&before_next_write_callback_),
+                      Passed(&after_next_write_callback_));
 
   if (!task_runner_->PostTask(FROM_HERE, MakeCriticalClosure(task))) {
     // Posting the task to background message loop is not expected
@@ -209,9 +215,11 @@
   serializer_ = nullptr;
 }
 
-void ImportantFileWriter::RegisterOnNextWriteCallback(
-    const Callback<void(bool success)>& on_next_write_callback) {
-  on_next_write_callback_ = on_next_write_callback;
+void ImportantFileWriter::RegisterOnNextWriteCallbacks(
+    const Closure& before_next_write_callback,
+    const Callback<void(bool success)>& after_next_write_callback) {
+  before_next_write_callback_ = before_next_write_callback;
+  after_next_write_callback_ = after_next_write_callback;
 }
 
 }  // namespace base
diff --git a/base/files/important_file_writer.h b/base/files/important_file_writer.h
index cd724e3..8823a9c 100644
--- a/base/files/important_file_writer.h
+++ b/base/files/important_file_writer.h
@@ -94,15 +94,17 @@
   // Serialize data pending to be saved and execute write on backend thread.
   void DoScheduledWrite();
 
-  // Registers |on_next_write_callback| to be synchronously invoked from
-  // WriteFileAtomically() on its next write (i.e. from |task_runner_|), with
-  // |success| indicating whether it succeeded or not.
-  // |on_next_write_callback| must be thread safe, as it will be called on
-  // |task_runner_| and may be called during Chrome shutdown.
+  // Registers |before_next_write_callback| and |after_next_write_callback| to
+  // be synchronously invoked from WriteFileAtomically() before its next write
+  // and after its next write, respectively. The boolean passed to
+  // |after_next_write_callback| indicates whether the write was successful.
+  // Both callbacks must be thread safe as they will be called on |task_runner_|
+  // and may be called during Chrome shutdown.
   // If called more than once before a write is scheduled on |task_runner|, the
-  // latest callback clobbers the others.
-  void RegisterOnNextWriteCallback(
-      const Callback<void(bool success)>& on_next_write_callback);
+  // latest callbacks clobber the others.
+  void RegisterOnNextWriteCallbacks(
+      const Closure& before_next_write_callback,
+      const Callback<void(bool success)>& after_next_write_callback);
 
   TimeDelta commit_interval() const {
     return commit_interval_;
@@ -110,7 +112,8 @@
 
  private:
   // Invoked synchronously on the next write event.
-  Callback<void(bool success)> on_next_write_callback_;
+  Closure before_next_write_callback_;
+  Callback<void(bool success)> after_next_write_callback_;
 
   // Path being written to.
   const FilePath path_;
diff --git a/base/files/important_file_writer_unittest.cc b/base/files/important_file_writer_unittest.cc
index b8920a07..9b8dcfd 100644
--- a/base/files/important_file_writer_unittest.cc
+++ b/base/files/important_file_writer_unittest.cc
@@ -52,38 +52,54 @@
   CALLED_WITH_SUCCESS,
 };
 
-class WriteCallbackObserver {
+class WriteCallbacksObserver {
  public:
-  WriteCallbackObserver() : observation_state_(NOT_CALLED) {}
+  WriteCallbacksObserver() = default;
 
-  // Register OnWrite() to be called on the next write of |writer|.
-  void ObserveNextWriteCallback(ImportantFileWriter* writer);
+  // Register OnBeforeWrite() and OnAfterWrite() to be called on the next write
+  // of |writer|.
+  void ObserveNextWriteCallbacks(ImportantFileWriter* writer);
 
-  // Returns true if a write was observed via OnWrite()
-  // and resets the observation state to false regardless.
+  // Returns the |WriteCallbackObservationState| which was observed, then resets
+  // it to |NOT_CALLED|.
   WriteCallbackObservationState GetAndResetObservationState();
 
  private:
-  void OnWrite(bool success) {
-    EXPECT_EQ(NOT_CALLED, observation_state_);
-    observation_state_ = success ? CALLED_WITH_SUCCESS : CALLED_WITH_ERROR;
+  void OnBeforeWrite() {
+    EXPECT_FALSE(before_write_called_);
+    before_write_called_ = true;
   }
 
-  WriteCallbackObservationState observation_state_;
+  void OnAfterWrite(bool success) {
+    EXPECT_EQ(NOT_CALLED, after_write_observation_state_);
+    after_write_observation_state_ =
+        success ? CALLED_WITH_SUCCESS : CALLED_WITH_ERROR;
+  }
 
-  DISALLOW_COPY_AND_ASSIGN(WriteCallbackObserver);
+  bool before_write_called_ = false;
+  WriteCallbackObservationState after_write_observation_state_ = NOT_CALLED;
+
+  DISALLOW_COPY_AND_ASSIGN(WriteCallbacksObserver);
 };
 
-void WriteCallbackObserver::ObserveNextWriteCallback(
+void WriteCallbacksObserver::ObserveNextWriteCallbacks(
     ImportantFileWriter* writer) {
-  writer->RegisterOnNextWriteCallback(
-      base::Bind(&WriteCallbackObserver::OnWrite, base::Unretained(this)));
+  writer->RegisterOnNextWriteCallbacks(
+      base::Bind(&WriteCallbacksObserver::OnBeforeWrite,
+                 base::Unretained(this)),
+      base::Bind(&WriteCallbacksObserver::OnAfterWrite,
+                 base::Unretained(this)));
 }
 
 WriteCallbackObservationState
-WriteCallbackObserver::GetAndResetObservationState() {
-  WriteCallbackObservationState state = observation_state_;
-  observation_state_ = NOT_CALLED;
+WriteCallbacksObserver::GetAndResetObservationState() {
+  EXPECT_EQ(after_write_observation_state_ != NOT_CALLED, before_write_called_)
+      << "The before-write callback should always be called before the "
+         "after-write callback";
+
+  WriteCallbackObservationState state = after_write_observation_state_;
+  before_write_called_ = false;
+  after_write_observation_state_ = NOT_CALLED;
   return state;
 }
 
@@ -98,7 +114,7 @@
   }
 
  protected:
-  WriteCallbackObserver write_callback_observer_;
+  WriteCallbacksObserver write_callback_observer_;
   FilePath file_;
   MessageLoop loop_;
 
@@ -124,7 +140,7 @@
   EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState());
 
   // Confirm that the observer is invoked.
-  write_callback_observer_.ObserveNextWriteCallback(&writer);
+  write_callback_observer_.ObserveNextWriteCallbacks(&writer);
   writer.WriteNow(MakeUnique<std::string>("foo"));
   RunLoop().RunUntilIdle();
 
@@ -135,7 +151,7 @@
 
   // Confirm that re-installing the observer works for another write.
   EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState());
-  write_callback_observer_.ObserveNextWriteCallback(&writer);
+  write_callback_observer_.ObserveNextWriteCallbacks(&writer);
   writer.WriteNow(MakeUnique<std::string>("bar"));
   RunLoop().RunUntilIdle();
 
@@ -162,7 +178,7 @@
                              ThreadTaskRunnerHandle::Get());
   EXPECT_FALSE(PathExists(writer.path()));
   EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState());
-  write_callback_observer_.ObserveNextWriteCallback(&writer);
+  write_callback_observer_.ObserveNextWriteCallbacks(&writer);
   writer.WriteNow(MakeUnique<std::string>("foo"));
   RunLoop().RunUntilIdle();
 
@@ -179,15 +195,26 @@
   ImportantFileWriter writer(file_, file_writer_thread.task_runner());
   EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState());
 
-  write_callback_observer_.ObserveNextWriteCallback(&writer);
+  // Block execution on |file_writer_thread| to verify that callbacks are
+  // executed on it.
+  base::WaitableEvent wait_helper(
+      base::WaitableEvent::ResetPolicy::MANUAL,
+      base::WaitableEvent::InitialState::NOT_SIGNALED);
+  file_writer_thread.task_runner()->PostTask(
+      FROM_HERE,
+      base::Bind(&base::WaitableEvent::Wait, base::Unretained(&wait_helper)));
+
+  write_callback_observer_.ObserveNextWriteCallbacks(&writer);
   writer.WriteNow(MakeUnique<std::string>("foo"));
   RunLoop().RunUntilIdle();
 
-  // Expect the callback to not have been executed before the write.
+  // Expect the callback to not have been executed before the
+  // |file_writer_thread| is unblocked.
   EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState());
 
-  // Make sure tasks posted by WriteNow() have ran before continuing.
+  wait_helper.Signal();
   file_writer_thread.FlushForTesting();
+
   EXPECT_EQ(CALLED_WITH_SUCCESS,
             write_callback_observer_.GetAndResetObservationState());
   ASSERT_TRUE(PathExists(writer.path()));
diff --git a/base/memory/memory_coordinator_client.h b/base/memory/memory_coordinator_client.h
index 6e0ce630..d63b17c 100644
--- a/base/memory/memory_coordinator_client.h
+++ b/base/memory/memory_coordinator_client.h
@@ -43,8 +43,6 @@
 // threading guarantees and ownership management.
 class BASE_EXPORT MemoryCoordinatorClient {
  public:
-  virtual ~MemoryCoordinatorClient() {}
-
   // Called when memory state has changed. Any transition can occur except for
   // UNKNOWN. General guidelines are:
   //  * NORMAL:    Restore the default settings for memory allocation/usage if
@@ -52,6 +50,9 @@
   //  * THROTTLED: Use smaller limits for memory allocations and caches.
   //  * SUSPENDED: Purge memory.
   virtual void OnMemoryStateChange(MemoryState state) = 0;
+
+protected:
+  virtual ~MemoryCoordinatorClient() {}
 };
 
 }  // namespace base
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
index 200f11e..74287b1 100644
--- a/base/message_loop/message_loop.cc
+++ b/base/message_loop/message_loop.cc
@@ -13,8 +13,6 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_pump_default.h"
-#include "base/metrics/histogram.h"
-#include "base/metrics/statistics_recorder.h"
 #include "base/run_loop.h"
 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
 #include "base/threading/thread_id_name_manager.h"
@@ -44,47 +42,6 @@
 LazyInstance<base::ThreadLocalPointer<MessageLoop> >::Leaky lazy_tls_ptr =
     LAZY_INSTANCE_INITIALIZER;
 
-// Logical events for Histogram profiling. Run with --message-loop-histogrammer
-// to get an accounting of messages and actions taken on each thread.
-const int kTaskRunEvent = 0x1;
-#if !defined(OS_NACL)
-const int kTimerEvent = 0x2;
-
-// Provide range of message IDs for use in histogramming and debug display.
-const int kLeastNonZeroMessageId = 1;
-const int kMaxMessageId = 1099;
-const int kNumberOfDistinctMessagesDisplayed = 1100;
-
-// Provide a macro that takes an expression (such as a constant, or macro
-// constant) and creates a pair to initialize an array of pairs.  In this case,
-// our pair consists of the expressions value, and the "stringized" version
-// of the expression (i.e., the expression put in quotes).  For example, if
-// we have:
-//    #define FOO 2
-//    #define BAR 5
-// then the following:
-//    VALUE_TO_NUMBER_AND_NAME(FOO + BAR)
-// will expand to:
-//   {7, "FOO + BAR"}
-// We use the resulting array as an argument to our histogram, which reads the
-// number as a bucket identifier, and proceeds to use the corresponding name
-// in the pair (i.e., the quoted string) when printing out a histogram.
-#define VALUE_TO_NUMBER_AND_NAME(name) {name, #name},
-
-const LinearHistogram::DescriptionPair event_descriptions_[] = {
-  // Provide some pretty print capability in our histogram for our internal
-  // messages.
-
-  // A few events we handle (kindred to messages), and used to profile actions.
-  VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent)
-  VALUE_TO_NUMBER_AND_NAME(kTimerEvent)
-
-  {-1, NULL}  // The list must be null-terminated, per API to histogram.
-};
-#endif  // !defined(OS_NACL)
-
-bool enable_histogrammer_ = false;
-
 MessageLoop::MessagePumpFactory* message_pump_for_ui_factory_ = NULL;
 
 #if defined(OS_IOS)
@@ -192,11 +149,6 @@
 }
 
 // static
-void MessageLoop::EnableHistogrammer(bool enable) {
-  enable_histogrammer_ = enable;
-}
-
-// static
 bool MessageLoop::InitMessagePumpForUIFactory(MessagePumpFactory* factory) {
   if (message_pump_for_ui_factory_)
     return false;
@@ -362,7 +314,6 @@
 #endif
       nestable_tasks_allowed_(true),
       pump_factory_(pump_factory),
-      message_histogram_(NULL),
       run_loop_(NULL),
       incoming_task_queue_(new internal::IncomingTaskQueue(this)),
       unbound_task_runner_(
@@ -416,7 +367,6 @@
 
 void MessageLoop::RunHandler() {
   DCHECK_EQ(this, current());
-  StartHistogrammer();
   pump_->Run(this);
 }
 
@@ -448,8 +398,6 @@
   // Execute the task and assume the worst: It is probably not reentrant.
   nestable_tasks_allowed_ = false;
 
-  HistogramEvent(kTaskRunEvent);
-
   TRACE_TASK_EXECUTION("MessageLoop::RunTask", pending_task);
 
   FOR_EACH_OBSERVER(TaskObserver, task_observers_,
@@ -534,31 +482,6 @@
 }
 #endif
 
-//------------------------------------------------------------------------------
-// Method and data for histogramming events and actions taken by each instance
-// on each thread.
-
-void MessageLoop::StartHistogrammer() {
-#if !defined(OS_NACL)  // NaCl build has no metrics code.
-  if (enable_histogrammer_ && !message_histogram_
-      && StatisticsRecorder::IsActive()) {
-    std::string thread_name = GetThreadName();
-    DCHECK(!thread_name.empty());
-    message_histogram_ = LinearHistogram::FactoryGetWithRangeDescription(
-        "MsgLoop:" + thread_name, kLeastNonZeroMessageId, kMaxMessageId,
-        kNumberOfDistinctMessagesDisplayed,
-        HistogramBase::kHexRangePrintingFlag, event_descriptions_);
-  }
-#endif
-}
-
-void MessageLoop::HistogramEvent(int event) {
-#if !defined(OS_NACL)
-  if (message_histogram_)
-    message_histogram_->Add(event);
-#endif
-}
-
 void MessageLoop::NotifyBeginNestedLoop() {
   FOR_EACH_OBSERVER(NestingObserver, nesting_observers_,
                     OnBeginNestedMessageLoop());
diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h
index 107e442..5b1728e4 100644
--- a/base/message_loop/message_loop.h
+++ b/base/message_loop/message_loop.h
@@ -46,7 +46,6 @@
 
 namespace base {
 
-class HistogramBase;
 class RunLoop;
 class ThreadTaskRunnerHandle;
 class WaitableEvent;
@@ -129,8 +128,6 @@
   // Returns the MessageLoop object for the current thread, or null if none.
   static MessageLoop* current();
 
-  static void EnableHistogrammer(bool enable_histogrammer);
-
   typedef std::unique_ptr<MessagePump>(MessagePumpFactory)();
   // Uses the given base::MessagePumpForUIFactory to override the default
   // MessagePump implementation for 'TYPE_UI'. Returns true if the factory
@@ -397,15 +394,6 @@
   // responsible for synchronizing ScheduleWork() calls.
   void ScheduleWork();
 
-  // Start recording histogram info about events and action IF it was enabled
-  // and IF the statistics recorder can accept a registration of our histogram.
-  void StartHistogrammer();
-
-  // Add occurrence of event to our histogram, so that we can see what is being
-  // done in a specific MessageLoop instance (i.e., specific thread).
-  // If message_histogram_ is NULL, this is a no-op.
-  void HistogramEvent(int event);
-
   // Notify observers that a nested message loop is starting.
   void NotifyBeginNestedLoop();
 
@@ -453,9 +441,6 @@
   // if type_ is TYPE_CUSTOM and pump_ is null.
   MessagePumpFactoryCallback pump_factory_;
 
-  // A profiling histogram showing the counts of various messages and events.
-  HistogramBase* message_histogram_;
-
   RunLoop* run_loop_;
 
   ObserverList<TaskObserver> task_observers_;
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
index ab6cdd0..a75abd6 100644
--- a/base/metrics/histogram.cc
+++ b/base/metrics/histogram.cc
@@ -673,15 +673,14 @@
                 "Histogram: %s recorded %d samples",
                 histogram_name().c_str(),
                 sample_count);
-  if (0 == sample_count) {
+  if (sample_count == 0) {
     DCHECK_EQ(samples.sum(), 0);
   } else {
-    double average = static_cast<float>(samples.sum()) / sample_count;
-
-    StringAppendF(output, ", average = %.1f", average);
+    double mean = static_cast<float>(samples.sum()) / sample_count;
+    StringAppendF(output, ", mean = %.1f", mean);
   }
-  if (flags() & ~kHexRangePrintingFlag)
-    StringAppendF(output, " (flags = 0x%x)", flags() & ~kHexRangePrintingFlag);
+  if (flags())
+    StringAppendF(output, " (flags = 0x%x)", flags());
 }
 
 void Histogram::WriteAsciiBucketContext(const int64_t past,
diff --git a/base/metrics/histogram_base.cc b/base/metrics/histogram_base.cc
index c2daf3cc..6dd91b2 100644
--- a/base/metrics/histogram_base.cc
+++ b/base/metrics/histogram_base.cc
@@ -173,12 +173,7 @@
 
 const std::string HistogramBase::GetSimpleAsciiBucketRange(
     Sample sample) const {
-  std::string result;
-  if (kHexRangePrintingFlag & flags())
-    StringAppendF(&result, "%#x", sample);
-  else
-    StringAppendF(&result, "%d", sample);
-  return result;
+  return StringPrintf("%d", sample);
 }
 
 void HistogramBase::WriteAsciiBucketValue(Count current,
diff --git a/base/metrics/histogram_base.h b/base/metrics/histogram_base.h
index c699b68b..9f836073 100644
--- a/base/metrics/histogram_base.h
+++ b/base/metrics/histogram_base.h
@@ -121,11 +121,6 @@
     // MemoryAllocator, and that loaded into the Histogram module before this
     // histogram is created.
     kIsPersistent = 0x40,
-
-    // TODO(rkaplow): Look into this, but looks like this is unused and can
-    // be removed.
-    // Only for Histogram and its sub classes: fancy bucket-naming support.
-    kHexRangePrintingFlag = 0x8000,
   };
 
   // Histogram data inconsistency types.
diff --git a/base/metrics/sparse_histogram.cc b/base/metrics/sparse_histogram.cc
index deba570..a8dfbeb7 100644
--- a/base/metrics/sparse_histogram.cc
+++ b/base/metrics/sparse_histogram.cc
@@ -282,8 +282,8 @@
                 "Histogram: %s recorded %d samples",
                 histogram_name().c_str(),
                 total_count);
-  if (flags() & ~kHexRangePrintingFlag)
-    StringAppendF(output, " (flags = 0x%x)", flags() & ~kHexRangePrintingFlag);
+  if (flags())
+    StringAppendF(output, " (flags = 0x%x)", flags());
 }
 
 }  // namespace base
diff --git a/base/trace_event/common/trace_event_common.h b/base/trace_event/common/trace_event_common.h
index 87588f5..5acacc3a 100644
--- a/base/trace_event/common/trace_event_common.h
+++ b/base/trace_event/common/trace_event_common.h
@@ -297,8 +297,8 @@
 
 #define TRACE_EVENT_INSTANT_WITH_TIMESTAMP0(category_group, name, scope, \
                                             timestamp)                   \
-  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                    \
-      TRACE_EVENT_PHASE_INSTANT, category_group, name, 0, 0, timestamp,  \
+  INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(                               \
+      TRACE_EVENT_PHASE_INSTANT, category_group, name, timestamp,        \
       TRACE_EVENT_FLAG_NONE | scope)
 
 // Syntactic sugars for the sampling tracing in the main thread.
@@ -396,14 +396,14 @@
                            arg2_name, arg2_val)
 
 #define TRACE_EVENT_MARK_WITH_TIMESTAMP0(category_group, name, timestamp) \
-  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                     \
-      TRACE_EVENT_PHASE_MARK, category_group, name, 0, 0, timestamp,      \
+  INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(                                \
+      TRACE_EVENT_PHASE_MARK, category_group, name, timestamp,            \
       TRACE_EVENT_FLAG_NONE)
 
 #define TRACE_EVENT_MARK_WITH_TIMESTAMP1(category_group, name, timestamp, \
                                          arg1_name, arg1_val)             \
-  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                     \
-      TRACE_EVENT_PHASE_MARK, category_group, name, 0, 0, timestamp,      \
+  INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(                                \
+      TRACE_EVENT_PHASE_MARK, category_group, name, timestamp,            \
       TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
 
 #define TRACE_EVENT_COPY_MARK(category_group, name)                      \
@@ -411,8 +411,8 @@
                            TRACE_EVENT_FLAG_COPY)
 
 #define TRACE_EVENT_COPY_MARK_WITH_TIMESTAMP(category_group, name, timestamp) \
-  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                         \
-      TRACE_EVENT_PHASE_MARK, category_group, name, 0, 0, timestamp,          \
+  INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(                                    \
+      TRACE_EVENT_PHASE_MARK, category_group, name, timestamp,                \
       TRACE_EVENT_FLAG_COPY)
 
 // Similar to TRACE_EVENT_ENDx but with a custom |at| timestamp provided.
diff --git a/blimp/client/BUILD.gn b/blimp/client/BUILD.gn
index c5b437a..3f01979 100644
--- a/blimp/client/BUILD.gn
+++ b/blimp/client/BUILD.gn
@@ -117,10 +117,12 @@
 if (is_linux && !is_chromeos && use_x11) {
   executable("blimp_shell") {
     sources = [
-      "app/linux/blimp_client_session_linux.cc",
-      "app/linux/blimp_client_session_linux.h",
+      "app/linux/blimp_client_context_delegate_linux.cc",
+      "app/linux/blimp_client_context_delegate_linux.h",
       "app/linux/blimp_display_manager.cc",
       "app/linux/blimp_display_manager.h",
+      "app/linux/blimp_display_manager_delegate_main.cc",
+      "app/linux/blimp_display_manager_delegate_main.h",
       "app/linux/blimp_main.cc",
     ]
 
diff --git a/blimp/client/app/linux/blimp_client_context_delegate_linux.cc b/blimp/client/app/linux/blimp_client_context_delegate_linux.cc
new file mode 100644
index 0000000..db7f2ff
--- /dev/null
+++ b/blimp/client/app/linux/blimp_client_context_delegate_linux.cc
@@ -0,0 +1,86 @@
+// 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.
+
+#include "base/memory/ptr_util.h"
+#include "blimp/client/app/linux/blimp_client_context_delegate_linux.h"
+#include "blimp/client/support/session/blimp_default_identity_provider.h"
+
+namespace blimp {
+namespace client {
+
+BlimpClientContextDelegateLinux::BlimpClientContextDelegateLinux() = default;
+
+BlimpClientContextDelegateLinux::~BlimpClientContextDelegateLinux() = default;
+
+void BlimpClientContextDelegateLinux::AttachBlimpContentsHelpers(
+    BlimpContents* blimp_contents) {}
+
+void BlimpClientContextDelegateLinux::OnAssignmentConnectionAttempted(
+    AssignmentRequestResult result,
+    const Assignment& assignment) {
+  // TODO(xingliu): Update this to use the new error strings and logging helper
+  // methods.
+  switch (result) {
+    case AssignmentRequestResult::ASSIGNMENT_REQUEST_RESULT_OK:
+      VLOG(0) << "Assignment request success";
+      break;
+    case AssignmentRequestResult::ASSIGNMENT_REQUEST_RESULT_UNKNOWN:
+      LOG(WARNING) << "Assignment request result unknown";
+      break;
+    case AssignmentRequestResult::ASSIGNMENT_REQUEST_RESULT_BAD_REQUEST:
+      LOG(WARNING) << "Assignment request error: Bad request";
+      break;
+    case AssignmentRequestResult::ASSIGNMENT_REQUEST_RESULT_BAD_RESPONSE:
+      LOG(WARNING) << "Assignment request error: Bad response";
+      break;
+    case AssignmentRequestResult::
+        ASSIGNMENT_REQUEST_RESULT_INVALID_PROTOCOL_VERSION:
+      LOG(WARNING) << "Assignment request error: Invalid protocol version";
+      break;
+    case AssignmentRequestResult::
+        ASSIGNMENT_REQUEST_RESULT_EXPIRED_ACCESS_TOKEN:
+      LOG(WARNING) << "Assignment request error: Expired access token";
+      break;
+    case AssignmentRequestResult::ASSIGNMENT_REQUEST_RESULT_USER_INVALID:
+      LOG(WARNING) << "Assignment request error: User invalid";
+      break;
+    case AssignmentRequestResult::ASSIGNMENT_REQUEST_RESULT_OUT_OF_VMS:
+      LOG(WARNING) << "Assignment request error: Out of VMs";
+      break;
+    case AssignmentRequestResult::ASSIGNMENT_REQUEST_RESULT_SERVER_ERROR:
+      LOG(WARNING) << "Assignment request error: Server error";
+      break;
+    case AssignmentRequestResult::ASSIGNMENT_REQUEST_RESULT_SERVER_INTERRUPTED:
+      LOG(WARNING) << "Assignment request error: Server interrupted";
+      break;
+    case AssignmentRequestResult::ASSIGNMENT_REQUEST_RESULT_NETWORK_FAILURE:
+      LOG(WARNING) << "Assignment request error: Network failure";
+      break;
+    case AssignmentRequestResult::ASSIGNMENT_REQUEST_RESULT_INVALID_CERT:
+      LOG(WARNING) << "Assignment request error: Invalid cert";
+      break;
+  }
+}
+
+std::unique_ptr<IdentityProvider>
+BlimpClientContextDelegateLinux::CreateIdentityProvider() {
+  return base::MakeUnique<BlimpDefaultIdentityProvider>();
+}
+
+void BlimpClientContextDelegateLinux::OnAuthenticationError(
+    BlimpClientContextDelegate::AuthError error) {
+  // TODO(xingliu): Update this to use the new error strings and logging helper
+  // methods.
+  switch (error) {
+    case BlimpClientContextDelegate::AuthError::NOT_SIGNED_IN:
+      LOG(WARNING) << "Error: Not signed in";
+      break;
+    case BlimpClientContextDelegate::AuthError::OAUTH_TOKEN_FAIL:
+      LOG(WARNING) << "Error: OAuth token failure";
+      break;
+  }
+}
+
+}  // namespace client
+}  // namespace blimp
diff --git a/blimp/client/app/linux/blimp_client_context_delegate_linux.h b/blimp/client/app/linux/blimp_client_context_delegate_linux.h
new file mode 100644
index 0000000..dda453a7
--- /dev/null
+++ b/blimp/client/app/linux/blimp_client_context_delegate_linux.h
@@ -0,0 +1,36 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BLIMP_CLIENT_APP_LINUX_BLIMP_CLIENT_CONTEXT_DELEGATE_LINUX_H_
+#define BLIMP_CLIENT_APP_LINUX_BLIMP_CLIENT_CONTEXT_DELEGATE_LINUX_H_
+
+#include "blimp/client/public/blimp_client_context_delegate.h"
+#include "google_apis/gaia/identity_provider.h"
+
+namespace blimp {
+namespace client {
+
+class BlimpContents;
+
+class BlimpClientContextDelegateLinux : public BlimpClientContextDelegate {
+ public:
+  BlimpClientContextDelegateLinux();
+  ~BlimpClientContextDelegateLinux() override;
+
+  // BlimpClientContextDelegate implementation.
+  void AttachBlimpContentsHelpers(BlimpContents* blimp_contents) override;
+  void OnAssignmentConnectionAttempted(AssignmentRequestResult result,
+                                       const Assignment& assignment) override;
+  std::unique_ptr<IdentityProvider> CreateIdentityProvider() override;
+  void OnAuthenticationError(
+      BlimpClientContextDelegate::AuthError error) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BlimpClientContextDelegateLinux);
+};
+
+}  // namespace client
+}  // namespace blimp
+
+#endif  // BLIMP_CLIENT_APP_LINUX_BLIMP_CLIENT_CONTEXT_DELEGATE_LINUX_H_
diff --git a/blimp/client/app/linux/blimp_display_manager.cc b/blimp/client/app/linux/blimp_display_manager.cc
index 5997c4d9..1f1f109 100644
--- a/blimp/client/app/linux/blimp_display_manager.cc
+++ b/blimp/client/app/linux/blimp_display_manager.cc
@@ -4,22 +4,22 @@
 
 #include "blimp/client/app/linux/blimp_display_manager.h"
 
+#include "base/memory/ptr_util.h"
 #include "blimp/client/app/compositor/browser_compositor.h"
-#include "blimp/client/core/compositor/blimp_compositor_dependencies.h"
-#include "blimp/client/core/compositor/blimp_compositor_manager.h"
-#include "blimp/client/core/contents/tab_control_feature.h"
-#include "blimp/client/core/render_widget/render_widget_feature.h"
-#include "blimp/client/support/compositor/compositor_dependencies_impl.h"
+#include "blimp/client/public/compositor/compositor_dependencies.h"
+#include "blimp/client/public/contents/blimp_contents.h"
+#include "blimp/client/public/contents/blimp_contents_view.h"
+#include "blimp/client/public/contents/blimp_navigation_controller.h"
 #include "ui/events/event.h"
 #include "ui/events/gesture_detection/motion_event_generic.h"
 #include "ui/events/gestures/motion_event_aura.h"
+#include "ui/events/platform/platform_event_source.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/platform_window/platform_window.h"
 #include "ui/platform_window/x11/x11_window.h"
 
 namespace blimp {
 namespace {
-constexpr int kDummyBlimpContentsId = 0;
 constexpr int kPointer1Id = 0;
 constexpr int kPointer2Id = 1;
 constexpr int kZoomOffsetMultiplier = 4;
@@ -28,40 +28,34 @@
 namespace client {
 
 BlimpDisplayManager::BlimpDisplayManager(
-    const gfx::Size& window_size,
     BlimpDisplayManagerDelegate* delegate,
-    RenderWidgetFeature* render_widget_feature,
-    TabControlFeature* tab_control_feature)
+    CompositorDependencies* compositor_dependencies)
     : device_pixel_ratio_(1.f),
       delegate_(delegate),
-      tab_control_feature_(tab_control_feature),
+      platform_event_source_(ui::PlatformEventSource::CreateDefault()),
       platform_window_(new ui::X11Window(this)) {
-  platform_window_->SetBounds(gfx::Rect(window_size));
-
-  compositor_dependencies_ = base::MakeUnique<BlimpCompositorDependencies>(
-      base::MakeUnique<CompositorDependenciesImpl>());
-
-  compositor_ = base::MakeUnique<BrowserCompositor>(
-      compositor_dependencies_->GetEmbedderDependencies());
-  compositor_->SetSize(platform_window_->GetBounds().size());
-
-  compositor_manager_ = base::MakeUnique<BlimpCompositorManager>(
-      kDummyBlimpContentsId, render_widget_feature,
-      compositor_dependencies_.get());
-
-  compositor_->SetContentLayer(compositor_manager_->layer());
-
-  platform_window_->Show();
-
-  tab_control_feature_->SetSizeAndScale(platform_window_->GetBounds().size(),
-                                        device_pixel_ratio_);
+  compositor_ = base::MakeUnique<BrowserCompositor>(compositor_dependencies);
 }
 
-BlimpDisplayManager::~BlimpDisplayManager() {}
+BlimpDisplayManager::~BlimpDisplayManager() = default;
+
+void BlimpDisplayManager::SetWindowSize(const gfx::Size& window_size) {
+  platform_window_->SetBounds(gfx::Rect(window_size));
+}
+
+void BlimpDisplayManager::SetBlimpContents(
+    std::unique_ptr<BlimpContents> contents) {
+  contents_ = std::move(contents);
+  compositor_->SetContentLayer(contents_->GetView()->GetLayer());
+  platform_window_->Show();
+}
 
 void BlimpDisplayManager::OnBoundsChanged(const gfx::Rect& new_bounds) {
   compositor_->SetSize(new_bounds.size());
-  tab_control_feature_->SetSizeAndScale(new_bounds.size(), device_pixel_ratio_);
+  if (contents_) {
+    contents_->GetView()->SetSizeAndScale(new_bounds.size(),
+                                          device_pixel_ratio_);
+  }
 }
 
 void BlimpDisplayManager::DispatchEvent(ui::Event* event) {
@@ -78,10 +72,12 @@
     int pointer_id,
     int pointer_x,
     int pointer_y) {
+  DCHECK(contents_);
+
   touch_event_stream->OnTouch(
       ui::TouchEvent(event_type, gfx::Point(pointer_x, pointer_y), pointer_id,
                      base::TimeTicks::Now()));
-  compositor_manager_->OnTouchEvent(*touch_event_stream);
+  contents_->GetView()->OnTouchEvent(*touch_event_stream);
 }
 
 void BlimpDisplayManager::DispatchMouseWheelEvent(
@@ -144,16 +140,20 @@
 
   if (action != ui::MotionEvent::ACTION_NONE &&
       mouse_event->IsOnlyLeftMouseButton()) {
+    DCHECK(contents_);
+
     ui::PointerProperties mouse_properties(mouse_event->x(), mouse_event->y(),
                                            0);
     ui::MotionEventGeneric motion_event(action, mouse_event->time_stamp(),
                                         mouse_properties);
-    compositor_manager_->OnTouchEvent(motion_event);
+    contents_->GetView()->OnTouchEvent(motion_event);
   }
 }
 
 void BlimpDisplayManager::OnCloseRequest() {
-  compositor_manager_->SetVisible(false);
+  DCHECK(contents_);
+
+  contents_->Hide();
   compositor_->SetAcceleratedWidget(gfx::kNullAcceleratedWidget);
   platform_window_->Close();
 }
@@ -166,18 +166,21 @@
 void BlimpDisplayManager::OnAcceleratedWidgetAvailable(
     gfx::AcceleratedWidget widget,
     float device_pixel_ratio) {
+  DCHECK(contents_);
+
   device_pixel_ratio_ = device_pixel_ratio;
-  tab_control_feature_->SetSizeAndScale(platform_window_->GetBounds().size(),
+  contents_->GetView()->SetSizeAndScale(platform_window_->GetBounds().size(),
                                         device_pixel_ratio_);
 
   if (widget != gfx::kNullAcceleratedWidget) {
-    compositor_manager_->SetVisible(true);
+    contents_->Show();
     compositor_->SetAcceleratedWidget(widget);
   }
 }
 
 void BlimpDisplayManager::OnAcceleratedWidgetDestroyed() {
-  compositor_manager_->SetVisible(false);
+  DCHECK(contents_);
+  contents_->Hide();
   compositor_->SetAcceleratedWidget(gfx::kNullAcceleratedWidget);
 }
 
diff --git a/blimp/client/app/linux/blimp_display_manager.h b/blimp/client/app/linux/blimp_display_manager.h
index 426ae44..450656b 100644
--- a/blimp/client/app/linux/blimp_display_manager.h
+++ b/blimp/client/app/linux/blimp_display_manager.h
@@ -17,32 +17,37 @@
 }
 
 namespace ui {
+class PlatformEventSource;
 class PlatformWindow;
 }
 
 namespace blimp {
 namespace client {
 
-class BlimpCompositorDependencies;
-class BlimpCompositorManager;
 class BrowserCompositor;
-class RenderWidgetFeature;
-class TabControlFeature;
+class BlimpContents;
+class CompositorDependencies;
 
 class BlimpDisplayManagerDelegate {
  public:
   virtual void OnClosed() = 0;
 };
 
+// Manages an X11 window that interacts with a Compositor by listening to the
+// window's event handlers
 class BlimpDisplayManager : public ui::PlatformWindowDelegate {
  public:
-  BlimpDisplayManager(const gfx::Size& window_size,
-                      BlimpDisplayManagerDelegate* delegate,
-                      RenderWidgetFeature* render_widget_feature,
-                      TabControlFeature* tab_control_feature);
+  // |delegate|: The delegate to receive the OnClosed call.
+  // |compositor_dependencies|: Set of compositor dependencies provided by the
+  // embedder.
+  BlimpDisplayManager(BlimpDisplayManagerDelegate* delegate,
+                      CompositorDependencies* compositor_dependencies);
   ~BlimpDisplayManager() override;
 
-  // ui::PlatformWindowDelegate:
+  void SetWindowSize(const gfx::Size& window_size);
+  void SetBlimpContents(std::unique_ptr<BlimpContents> contents);
+
+  // ui::PlatformWindowDelegate implementation.
   void OnBoundsChanged(const gfx::Rect& new_bounds) override;
   void OnDamageRect(const gfx::Rect& damaged_region) override {}
   void DispatchEvent(ui::Event* event) override;
@@ -75,11 +80,10 @@
   float device_pixel_ratio_;
 
   BlimpDisplayManagerDelegate* delegate_;
-  TabControlFeature* tab_control_feature_;
 
-  std::unique_ptr<BlimpCompositorDependencies> compositor_dependencies_;
-  std::unique_ptr<BlimpCompositorManager> compositor_manager_;
   std::unique_ptr<BrowserCompositor> compositor_;
+  std::unique_ptr<BlimpContents> contents_;
+  std::unique_ptr<ui::PlatformEventSource> platform_event_source_;
   std::unique_ptr<ui::PlatformWindow> platform_window_;
 
   DISALLOW_COPY_AND_ASSIGN(BlimpDisplayManager);
diff --git a/blimp/client/app/linux/blimp_display_manager_delegate_main.cc b/blimp/client/app/linux/blimp_display_manager_delegate_main.cc
new file mode 100644
index 0000000..ba4c51f
--- /dev/null
+++ b/blimp/client/app/linux/blimp_display_manager_delegate_main.cc
@@ -0,0 +1,17 @@
+// 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 "blimp/client/app/linux/blimp_display_manager_delegate_main.h"
+
+#include "base/run_loop.h"
+
+namespace blimp {
+namespace client {
+
+void BlimpDisplayManagerDelegateMain::OnClosed() {
+  base::MessageLoop::current()->QuitNow();
+}
+
+}  // namespace client
+}  // namespace blimp
diff --git a/blimp/client/app/linux/blimp_display_manager_delegate_main.h b/blimp/client/app/linux/blimp_display_manager_delegate_main.h
new file mode 100644
index 0000000..6d23be0d
--- /dev/null
+++ b/blimp/client/app/linux/blimp_display_manager_delegate_main.h
@@ -0,0 +1,21 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BLIMP_CLIENT_APP_LINUX_BLIMP_DISPLAY_MANAGER_DELEGATE_MAIN_H_
+#define BLIMP_CLIENT_APP_LINUX_BLIMP_DISPLAY_MANAGER_DELEGATE_MAIN_H_
+
+#include "blimp/client/app/linux/blimp_display_manager.h"
+
+namespace blimp {
+namespace client {
+
+class BlimpDisplayManagerDelegateMain : public BlimpDisplayManagerDelegate {
+ public:
+  void OnClosed() override;
+};
+
+}  // namespace client
+}  // namespace blimp
+
+#endif  // BLIMP_CLIENT_APP_LINUX_BLIMP_DISPLAY_MANAGER_DELEGATE_MAIN_H_
diff --git a/blimp/client/app/linux/blimp_main.cc b/blimp/client/app/linux/blimp_main.cc
index 37c7c95..2f06d93 100644
--- a/blimp/client/app/linux/blimp_main.cc
+++ b/blimp/client/app/linux/blimp_main.cc
@@ -1,4 +1,4 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// 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.
 
@@ -10,16 +10,18 @@
 #include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "blimp/client/app/blimp_startup.h"
-#include "blimp/client/app/linux/blimp_client_session_linux.h"
-#include "blimp/client/core/contents/navigation_feature.h"
-#include "blimp/client/core/contents/tab_control_feature.h"
-#include "blimp/client/core/session/assignment_source.h"
+#include "blimp/client/app/linux/blimp_client_context_delegate_linux.h"
+#include "blimp/client/app/linux/blimp_display_manager.h"
+#include "blimp/client/app/linux/blimp_display_manager_delegate_main.h"
+#include "blimp/client/public/blimp_client_context.h"
+#include "blimp/client/public/contents/blimp_navigation_controller.h"
+#include "blimp/client/support/compositor/compositor_dependencies_impl.h"
 #include "ui/gfx/x/x11_connection.h"
 
 namespace {
-const char kDummyLoginToken[] = "";
 const char kDefaultUrl[] = "https://www.google.com";
-const int kDummyTabId = 0;
+constexpr int kWindowWidth = 800;
+constexpr int kWindowHeight = 600;
 }
 
 int main(int argc, const char**argv) {
@@ -31,15 +33,44 @@
   blimp::client::InitializeLogging();
   blimp::client::InitializeMainMessageLoop();
 
-  blimp::client::BlimpClientSessionLinux session;
-  session.GetTabControlFeature()->CreateTab(kDummyTabId);
-  session.Connect(kDummyLoginToken);
+  base::Thread io_thread("BlimpIOThread");
+  base::Thread::Options options;
+  options.message_loop_type = base::MessageLoop::TYPE_IO;
+  io_thread.StartWithOptions(options);
+
+  // Creating this using "new" and passing to context using "WrapUnique" as
+  // opposed to "MakeUnique" because we'll need to pass the compositor
+  // dependencies to the display manager as well.
+  blimp::client::CompositorDependencies* compositor_dependencies =
+      new blimp::client::CompositorDependenciesImpl();
+  // Creating the context delegate before the context so that the context is
+  // destroyed before the delegate.
+  std::unique_ptr<blimp::client::BlimpClientContextDelegate> context_delegate =
+      base::MakeUnique<blimp::client::BlimpClientContextDelegateLinux>();
+  std::unique_ptr<blimp::client::BlimpClientContext> context =
+      base::WrapUnique<blimp::client::BlimpClientContext>(
+          blimp::client::BlimpClientContext::Create(
+              io_thread.task_runner(), io_thread.task_runner(),
+              base::WrapUnique(compositor_dependencies)));
+  context->SetDelegate(context_delegate.get());
+
+  context->Connect();
 
   // If there is a non-switch argument to the command line, load that url.
   base::CommandLine::StringVector args =
       base::CommandLine::ForCurrentProcess()->GetArgs();
   std::string url = args.size() > 0 ? args[0] : kDefaultUrl;
-  session.GetNavigationFeature()->NavigateToUrlText(kDummyTabId, url);
+  std::unique_ptr<blimp::client::BlimpContents> contents =
+      context->CreateBlimpContents(nullptr);
+  contents->GetNavigationController().LoadURL(GURL(url));
+
+  std::unique_ptr<blimp::client::BlimpDisplayManagerDelegate>
+      display_manager_delegate =
+          base::MakeUnique<blimp::client::BlimpDisplayManagerDelegateMain>();
+  blimp::client::BlimpDisplayManager display_manager(
+      display_manager_delegate.get(), compositor_dependencies);
+  display_manager.SetWindowSize(gfx::Size(kWindowWidth, kWindowHeight));
+  display_manager.SetBlimpContents(std::move(contents));
 
   base::RunLoop().Run();
 }
diff --git a/blimp/client/core/contents/blimp_navigation_controller_impl.h b/blimp/client/core/contents/blimp_navigation_controller_impl.h
index c8ec751..d3bd56237 100644
--- a/blimp/client/core/contents/blimp_navigation_controller_impl.h
+++ b/blimp/client/core/contents/blimp_navigation_controller_impl.h
@@ -36,7 +36,7 @@
   void GoBack() override;
   void GoForward() override;
   const GURL& GetURL() override;
-  const std::string& GetTitle();
+  const std::string& GetTitle() override;
 
  private:
   // NavigationFeatureDelegate implementation.
diff --git a/blimp/client/public/contents/blimp_navigation_controller.h b/blimp/client/public/contents/blimp_navigation_controller.h
index f2d38ee..0c8a4297 100644
--- a/blimp/client/public/contents/blimp_navigation_controller.h
+++ b/blimp/client/public/contents/blimp_navigation_controller.h
@@ -38,6 +38,9 @@
   // Retrieves the URL of the currently selected item in the navigation list.
   virtual const GURL& GetURL() = 0;
 
+  // Gets the current page title.
+  virtual const std::string& GetTitle() = 0;
+
  protected:
   BlimpNavigationController() {}
 
diff --git a/blimp/client/support/BUILD.gn b/blimp/client/support/BUILD.gn
index a80f1ed..946008aa3 100644
--- a/blimp/client/support/BUILD.gn
+++ b/blimp/client/support/BUILD.gn
@@ -5,5 +5,6 @@
 group("support") {
   public_deps = [
     "//blimp/client/support/compositor",
+    "//blimp/client/support/session",
   ]
 }
diff --git a/blimp/client/support/session/BUILD.gn b/blimp/client/support/session/BUILD.gn
new file mode 100644
index 0000000..ba6b59a
--- /dev/null
+++ b/blimp/client/support/session/BUILD.gn
@@ -0,0 +1,24 @@
+# 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.
+
+if (is_android) {
+  import("//build/config/android/config.gni")
+  import("//build/config/android/rules.gni")
+}
+
+source_set("session") {
+  sources = [
+    "blimp_default_identity_provider.cc",
+    "blimp_default_identity_provider.h",
+  ]
+
+  public_deps = [
+    "//base",
+    "//google_apis:google_apis",
+  ]
+
+  deps = [
+    "//blimp/client/public:public_headers",
+  ]
+}
diff --git a/blimp/client/support/session/blimp_default_identity_provider.cc b/blimp/client/support/session/blimp_default_identity_provider.cc
new file mode 100644
index 0000000..f66b3df
--- /dev/null
+++ b/blimp/client/support/session/blimp_default_identity_provider.cc
@@ -0,0 +1,36 @@
+// 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.
+
+#include "blimp/client/support/session/blimp_default_identity_provider.h"
+
+#include "google_apis/gaia/oauth2_token_service.h"
+
+namespace blimp {
+namespace client {
+namespace {
+constexpr char kDummyAccountId[] = "DummyAccountId";
+}  // namespace
+
+BlimpDefaultIdentityProvider::BlimpDefaultIdentityProvider() = default;
+
+BlimpDefaultIdentityProvider::~BlimpDefaultIdentityProvider() = default;
+
+std::string BlimpDefaultIdentityProvider::GetActiveUsername() {
+  return kDummyAccountId;
+}
+
+std::string BlimpDefaultIdentityProvider::GetActiveAccountId() {
+  return kDummyAccountId;
+}
+
+OAuth2TokenService* BlimpDefaultIdentityProvider::GetTokenService() {
+  return nullptr;
+}
+
+bool BlimpDefaultIdentityProvider::RequestLogin() {
+  return false;
+}
+
+}  // namespace client
+}  // namespace blimp
diff --git a/blimp/client/support/session/blimp_default_identity_provider.h b/blimp/client/support/session/blimp_default_identity_provider.h
new file mode 100644
index 0000000..7d82cf028
--- /dev/null
+++ b/blimp/client/support/session/blimp_default_identity_provider.h
@@ -0,0 +1,38 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BLIMP_CLIENT_SUPPORT_SESSION_BLIMP_DEFAULT_IDENTITY_PROVIDER_H_
+#define BLIMP_CLIENT_SUPPORT_SESSION_BLIMP_DEFAULT_IDENTITY_PROVIDER_H_
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "google_apis/gaia/identity_provider.h"
+
+namespace blimp {
+namespace client {
+
+// Provides a dummy identity provider with a null token service that doesn't
+// actually log in. Useful when using command-line switches to get the
+// assignment.
+class BlimpDefaultIdentityProvider : public IdentityProvider {
+ public:
+  BlimpDefaultIdentityProvider();
+  ~BlimpDefaultIdentityProvider() override;
+
+  // IdentityProvider implementation.
+  std::string GetActiveUsername() override;
+  std::string GetActiveAccountId() override;
+  OAuth2TokenService* GetTokenService() override;
+  bool RequestLogin() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BlimpDefaultIdentityProvider);
+};
+
+}  // namespace client
+}  // namespace blimp
+
+#endif  // BLIMP_CLIENT_SUPPORT_SESSION_BLIMP_DEFAULT_IDENTITY_PROVIDER_H_
diff --git a/blimp/client/test/BUILD.gn b/blimp/client/test/BUILD.gn
index b9eb194..986052d5 100644
--- a/blimp/client/test/BUILD.gn
+++ b/blimp/client/test/BUILD.gn
@@ -6,6 +6,8 @@
   testonly = true
 
   sources = [
+    "contents/mock_blimp_contents_observer.cc",
+    "contents/mock_blimp_contents_observer.h",
     "test_blimp_client_context_delegate.cc",
     "test_blimp_client_context_delegate.h",
   ]
diff --git a/blimp/client/test/contents/mock_blimp_contents_observer.cc b/blimp/client/test/contents/mock_blimp_contents_observer.cc
new file mode 100644
index 0000000..9a8d0c3
--- /dev/null
+++ b/blimp/client/test/contents/mock_blimp_contents_observer.cc
@@ -0,0 +1,16 @@
+// 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.
+
+#include "blimp/client/test/contents/mock_blimp_contents_observer.h"
+
+namespace blimp {
+namespace client {
+
+MockBlimpContentsObserver::MockBlimpContentsObserver(BlimpContents* contents)
+    : BlimpContentsObserver(contents) {}
+
+MockBlimpContentsObserver::~MockBlimpContentsObserver() = default;
+
+}  // namespace client
+}  // namespace blimp
diff --git a/blimp/client/test/contents/mock_blimp_contents_observer.h b/blimp/client/test/contents/mock_blimp_contents_observer.h
new file mode 100644
index 0000000..8bbfc9fc
--- /dev/null
+++ b/blimp/client/test/contents/mock_blimp_contents_observer.h
@@ -0,0 +1,28 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BLIMP_CLIENT_TEST_CONTENTS_MOCK_BLIMP_CONTENTS_OBSERVER_H_
+#define BLIMP_CLIENT_TEST_CONTENTS_MOCK_BLIMP_CONTENTS_OBSERVER_H_
+
+#include "blimp/client/public/contents/blimp_contents_observer.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace blimp {
+namespace client {
+
+class MockBlimpContentsObserver : public BlimpContentsObserver {
+ public:
+  explicit MockBlimpContentsObserver(BlimpContents* contents);
+  ~MockBlimpContentsObserver() override;
+
+  MOCK_METHOD0(OnNavigationStateChanged, void());
+  MOCK_METHOD1(OnLoadingStateChanged, void(bool loading));
+  MOCK_METHOD1(OnPageLoadingStateChanged, void(bool loading));
+  MOCK_METHOD0(OnContentsDestroyed, void());
+};
+
+}  // namespace client
+}  // namespace blimp
+
+#endif  // BLIMP_CLIENT_TEST_CONTENTS_MOCK_BLIMP_CONTENTS_OBSERVER_H_
diff --git a/blimp/engine/BUILD.gn b/blimp/engine/BUILD.gn
index a5b6e32d..9f0ee89 100644
--- a/blimp/engine/BUILD.gn
+++ b/blimp/engine/BUILD.gn
@@ -690,8 +690,9 @@
     "browser_tests/blimp_contents_view_readback_helper.cc",
     "browser_tests/blimp_contents_view_readback_helper.h",
     "browser_tests/blimp_test_launcher.cc",
-    "browser_tests/engine_browsertest.cc",
+    "browser_tests/input_browsertest.cc",
     "browser_tests/integration_test.cc",
+    "browser_tests/navigation_browsertest.cc",
     "browser_tests/waitable_content_pump.cc",
     "browser_tests/waitable_content_pump.h",
   ]
@@ -702,6 +703,7 @@
     "//base",
     "//blimp/client:session",
     "//blimp/client:test_support",
+    "//blimp/client/core:context",
     "//blimp/client/core:switches",
     "//blimp/client/core/contents:test_support",
     "//blimp/client/core/render_widget:test_support",
diff --git a/blimp/engine/browser_tests/engine_browsertest.cc b/blimp/engine/browser_tests/input_browsertest.cc
similarity index 64%
rename from blimp/engine/browser_tests/engine_browsertest.cc
rename to blimp/engine/browser_tests/input_browsertest.cc
index f85f4af8..03f890b 100644
--- a/blimp/engine/browser_tests/engine_browsertest.cc
+++ b/blimp/engine/browser_tests/input_browsertest.cc
@@ -8,7 +8,6 @@
 #include "blimp/client/core/contents/mock_navigation_feature_delegate.h"
 #include "blimp/client/core/contents/navigation_feature.h"
 #include "blimp/client/core/contents/tab_control_feature.h"
-#include "blimp/client/core/render_widget/mock_render_widget_feature_delegate.h"
 #include "blimp/client/core/render_widget/render_widget_feature.h"
 #include "blimp/client/core/session/assignment_source.h"
 #include "blimp/client/public/session/assignment.h"
@@ -33,16 +32,12 @@
 namespace {
 
 const int kDummyTabId = 0;
-const char kPage1Path[] = "/page1.html";
-const char kPage2Path[] = "/page2.html";
 const char kInputPagePath[] = "/input.html";
-const char kPage1Title[] = "page1";
-const char kPage2Title[] = "page2";
 
-// Uses a headless client session to test a full engine.
-class EngineBrowserTest : public BlimpBrowserTest {
+// TODO(bgoldman): Convert to v0.6 as in the rendering and navigation tests.
+class InputBrowserTest : public BlimpBrowserTest {
  public:
-  EngineBrowserTest() {}
+  InputBrowserTest() {}
 
  protected:
   void SetUpOnMainThread() override {
@@ -54,8 +49,6 @@
     // Set feature delegates.
     client_session_->GetNavigationFeature()->SetDelegate(
         kDummyTabId, &client_nav_feature_delegate_);
-    client_session_->GetRenderWidgetFeature()->SetDelegate(
-        kDummyTabId, &client_rw_feature_delegate_);
     client_session_->GetImeFeature()->set_delegate(
         &client_ime_feature_delegate_);
 
@@ -96,13 +89,11 @@
         .Times(AtLeast(1));
     EXPECT_CALL(client_nav_feature_delegate_,
                 OnLoadingChanged(kDummyTabId, false))
-        .WillOnce(
-            InvokeWithoutArgs(this, &EngineBrowserTest::SignalCompletion));
+        .WillOnce(InvokeWithoutArgs(this, &InputBrowserTest::SignalCompletion));
   }
 
   void RunAndVerify() {
     RunUntilCompletion();
-    testing::Mock::VerifyAndClearExpectations(&client_rw_feature_delegate_);
     testing::Mock::VerifyAndClearExpectations(&client_nav_feature_delegate_);
     testing::Mock::VerifyAndClearExpectations(&client_ime_feature_delegate_);
   }
@@ -116,77 +107,15 @@
   }
 
   client::MockNavigationFeatureDelegate client_nav_feature_delegate_;
-  client::MockRenderWidgetFeatureDelegate client_rw_feature_delegate_;
   client::MockImeFeatureDelegate client_ime_feature_delegate_;
   std::unique_ptr<client::TestClientSession> client_session_;
   std::string last_page_title_;
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(EngineBrowserTest);
+  DISALLOW_COPY_AND_ASSIGN(InputBrowserTest);
 };
 
-IN_PROC_BROWSER_TEST_F(EngineBrowserTest, LoadUrl) {
-  EXPECT_CALL(client_rw_feature_delegate_, OnRenderWidgetCreated(1));
-  ExpectPageLoad();
-  NavigateToLocalUrl(kPage1Path);
-  RunAndVerify();
-  EXPECT_EQ(kPage1Title, last_page_title_);
-}
-
-IN_PROC_BROWSER_TEST_F(EngineBrowserTest, Reload) {
-  LoadPage(kPage1Path);
-  EXPECT_EQ(kPage1Title, last_page_title_);
-
-  ExpectPageLoad();
-  client_session_->GetNavigationFeature()->Reload(kDummyTabId);
-  RunAndVerify();
-  EXPECT_EQ(kPage1Title, last_page_title_);
-}
-
-IN_PROC_BROWSER_TEST_F(EngineBrowserTest, GoBackAndGoForward) {
-  LoadPage(kPage1Path);
-  EXPECT_EQ(kPage1Title, last_page_title_);
-
-  ExpectPageLoad();
-  NavigateToLocalUrl(kPage2Path);
-  RunAndVerify();
-  EXPECT_EQ(kPage2Title, last_page_title_);
-
-  ExpectPageLoad();
-  client_session_->GetNavigationFeature()->GoBack(kDummyTabId);
-  RunAndVerify();
-  EXPECT_EQ(kPage1Title, last_page_title_);
-
-  ExpectPageLoad();
-  client_session_->GetNavigationFeature()->GoForward(kDummyTabId);
-  RunAndVerify();
-  EXPECT_EQ(kPage2Title, last_page_title_);
-}
-
-IN_PROC_BROWSER_TEST_F(EngineBrowserTest, InvalidGoBack) {
-  // Try an invalid GoBack before loading a page, and assert that the page still
-  // loads correctly.
-  ExpectPageLoad();
-  client_session_->GetNavigationFeature()->GoBack(kDummyTabId);
-  NavigateToLocalUrl(kPage1Path);
-  RunAndVerify();
-  EXPECT_EQ(kPage1Title, last_page_title_);
-}
-
-IN_PROC_BROWSER_TEST_F(EngineBrowserTest, InvalidGoForward) {
-  LoadPage(kPage1Path);
-  EXPECT_EQ(kPage1Title, last_page_title_);
-
-  // Try an invalid GoForward before loading a different page, and
-  // assert that the page still loads correctly.
-  ExpectPageLoad();
-  client_session_->GetNavigationFeature()->GoForward(kDummyTabId);
-  NavigateToLocalUrl(kPage2Path);
-  RunAndVerify();
-  EXPECT_EQ(kPage2Title, last_page_title_);
-}
-
-IN_PROC_BROWSER_TEST_F(EngineBrowserTest, InputText) {
+IN_PROC_BROWSER_TEST_F(InputBrowserTest, InputText) {
   LoadPage(kInputPagePath);
 
   blink::WebGestureEvent event;
@@ -197,7 +126,7 @@
   EXPECT_CALL(client_ime_feature_delegate_, OnShowImeRequested(_, "", _))
       .Times(AtLeast(1))
       .WillOnce(
-          DoAll(InvokeWithoutArgs(this, &EngineBrowserTest::SignalCompletion),
+          DoAll(InvokeWithoutArgs(this, &InputBrowserTest::SignalCompletion),
                 SaveArg<2>(&callback)));
   client_session_->GetRenderWidgetFeature()->SendWebGestureEvent(kDummyTabId, 1,
                                                                  event);
@@ -206,7 +135,7 @@
   // Enter text from the client and expect the input.html JavaScript to update
   // the page title.
   EXPECT_CALL(client_nav_feature_delegate_, OnTitleChanged(kDummyTabId, "test"))
-      .WillOnce(InvokeWithoutArgs(this, &EngineBrowserTest::SignalCompletion));
+      .WillOnce(InvokeWithoutArgs(this, &InputBrowserTest::SignalCompletion));
   callback.Run("test");
   RunAndVerify();
 }
diff --git a/blimp/engine/browser_tests/navigation_browsertest.cc b/blimp/engine/browser_tests/navigation_browsertest.cc
new file mode 100644
index 0000000..4e84672
--- /dev/null
+++ b/blimp/engine/browser_tests/navigation_browsertest.cc
@@ -0,0 +1,184 @@
+// 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.
+
+#include "base/memory/ptr_util.h"
+#include "blimp/client/core/blimp_client_context_impl.h"
+#include "blimp/client/core/contents/blimp_navigation_controller_impl.h"
+#include "blimp/client/session/test_client_session.h"
+#include "blimp/client/test/compositor/mock_compositor_dependencies.h"
+#include "blimp/client/test/contents/mock_blimp_contents_observer.h"
+#include "blimp/client/test/test_blimp_client_context_delegate.h"
+#include "blimp/engine/browser_tests/blimp_browser_test.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/test/browser_test.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+using ::testing::_;
+using ::testing::AtLeast;
+using ::testing::InvokeWithoutArgs;
+
+namespace blimp {
+namespace {
+
+const char kPage1Path[] = "/page1.html";
+const char kPage2Path[] = "/page2.html";
+const char kPage1Title[] = "page1";
+const char kPage2Title[] = "page2";
+
+// Tests for Blimp navigation features, with a full engine and a headless
+// client. These tests cover Blimp engine interaction with WebContents and
+// NavigationController, as well as network interaction between client and
+// engine.
+class NavigationBrowserTest : public BlimpBrowserTest {
+ public:
+  NavigationBrowserTest() {}
+
+ protected:
+  void SetUpOnMainThread() override {
+    BlimpBrowserTest::SetUpOnMainThread();
+
+    context_ = base::WrapUnique<client::BlimpClientContext>(
+        client::BlimpClientContext::Create(
+            content::BrowserThread::GetTaskRunnerForThread(
+                content::BrowserThread::IO),
+            content::BrowserThread::GetTaskRunnerForThread(
+                content::BrowserThread::FILE),
+            base::MakeUnique<client::MockCompositorDependencies>()));
+
+    delegate_ = base::MakeUnique<client::TestBlimpClientContextDelegate>();
+    context_->SetDelegate(delegate_.get());
+    context_->ConnectWithAssignment(GetAssignment());
+    contents_ = context_->CreateBlimpContents(nullptr);
+
+    EXPECT_TRUE(embedded_test_server()->Start());
+  }
+
+  void TearDownOnMainThread() override {
+    contents_.reset();
+    context_.reset();
+    delegate_.reset();
+    BlimpBrowserTest::TearDownOnMainThread();
+  }
+
+  // Given a path on the embedded local server, tell the client to navigate
+  // that page by URL.
+  //
+  // This method does not block; it simply triggers the intended action from the
+  // client side. See: RunUntilCompletion, SignalCompletion, and ExpectPageLoad.
+  void NavigateToLocalUrl(const std::string& path) {
+    GURL url = embedded_test_server()->GetURL(path);
+    contents_->GetNavigationController().LoadURL(url);
+  }
+
+  // Expect a page load on a mock observer, indicated by the loading state
+  // changing to true and then to false.
+  //
+  // When the page load has completed, the mock will call SignalCompletion,
+  // which will cause RunUntilCompletion to return on the test thread.
+  void ExpectPageLoad(client::MockBlimpContentsObserver* observer) {
+    // There may be redundant events indicating the page load status is true,
+    // so allow more than one.
+    EXPECT_CALL(*observer, OnLoadingStateChanged(true)).Times(AtLeast(1));
+    EXPECT_CALL(*observer, OnLoadingStateChanged(false))
+        .WillOnce(
+            InvokeWithoutArgs(this, &NavigationBrowserTest::SignalCompletion));
+  }
+
+  // Tell the client to navigate to a URL on the local server, and then wait
+  // for the page to load.
+  void LoadPage(const std::string& path) {
+    client::MockBlimpContentsObserver observer(contents_.get());
+    ExpectPageLoad(&observer);
+    NavigateToLocalUrl(path);
+    RunUntilCompletion();
+  }
+
+  // Gets the current page title from the client.
+  const std::string& GetTitle() {
+    return contents_->GetNavigationController().GetTitle();
+  }
+
+  std::unique_ptr<client::BlimpClientContextDelegate> delegate_;
+  std::unique_ptr<client::BlimpClientContext> context_;
+  std::unique_ptr<client::BlimpContents> contents_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NavigationBrowserTest);
+};
+
+IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, LoadUrl) {
+  LoadPage(kPage1Path);
+  EXPECT_EQ(kPage1Title, GetTitle());
+}
+
+IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, Reload) {
+  LoadPage(kPage1Path);
+  EXPECT_EQ(kPage1Title, GetTitle());
+
+  {
+    client::MockBlimpContentsObserver observer(contents_.get());
+    ExpectPageLoad(&observer);
+    contents_->GetNavigationController().Reload();
+    RunUntilCompletion();
+  }
+  EXPECT_EQ(kPage1Title, GetTitle());
+}
+
+IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, GoBackAndGoForward) {
+  LoadPage(kPage1Path);
+  EXPECT_EQ(kPage1Title, GetTitle());
+
+  LoadPage(kPage2Path);
+  EXPECT_EQ(kPage2Title, GetTitle());
+
+  {
+    client::MockBlimpContentsObserver observer(contents_.get());
+    ExpectPageLoad(&observer);
+    contents_->GetNavigationController().GoBack();
+    RunUntilCompletion();
+  }
+  EXPECT_EQ(kPage1Title, GetTitle());
+
+  {
+    client::MockBlimpContentsObserver observer(contents_.get());
+    ExpectPageLoad(&observer);
+    contents_->GetNavigationController().GoForward();
+    RunUntilCompletion();
+  }
+  EXPECT_EQ(kPage2Title, GetTitle());
+}
+
+IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, NavigateAfterInvalidGoBack) {
+  // Try an invalid GoBack before loading a page, and assert that the page still
+  // loads correctly.
+  {
+    client::MockBlimpContentsObserver observer(contents_.get());
+    ExpectPageLoad(&observer);
+    contents_->GetNavigationController().GoBack();
+    NavigateToLocalUrl(kPage1Path);
+    RunUntilCompletion();
+  }
+  EXPECT_EQ(kPage1Title, GetTitle());
+}
+
+IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, NavigateAfterInvalidGoForward) {
+  LoadPage(kPage1Path);
+  EXPECT_EQ(kPage1Title, GetTitle());
+
+  // Try an invalid GoForward before loading a different page, and
+  // assert that the page still loads correctly.
+  {
+    client::MockBlimpContentsObserver observer(contents_.get());
+    ExpectPageLoad(&observer);
+    contents_->GetNavigationController().GoForward();
+    NavigateToLocalUrl(kPage2Path);
+    RunUntilCompletion();
+  }
+  EXPECT_EQ(kPage2Title, GetTitle());
+}
+
+}  // namespace
+}  // namespace blimp
diff --git a/blimp/net/BUILD.gn b/blimp/net/BUILD.gn
index 9c348825..c8bf52b 100644
--- a/blimp/net/BUILD.gn
+++ b/blimp/net/BUILD.gn
@@ -21,7 +21,6 @@
     "blimp_message_pump.h",
     "blimp_message_thread_pipe.cc",
     "blimp_message_thread_pipe.h",
-    "blimp_net_export.h",
     "blimp_stats.cc",
     "blimp_stats.h",
     "blimp_transport.h",
@@ -77,6 +76,8 @@
   defines = [ "BLIMP_NET_IMPLEMENTATION=1" ]
 
   deps = [
+    ":helium",
+    ":net_export",
     "//base",
     "//blimp/common",
     "//net",
@@ -90,6 +91,28 @@
   ]
 }
 
+source_set("helium") {
+  sources = [
+    "helium/vector_clock.cc",
+    "helium/vector_clock.h",
+  ]
+  deps = [
+    ":net_export",
+    "//base",
+    "//blimp/common",
+  ]
+
+  public_deps = [
+    "//blimp/common/proto",
+  ]
+}
+
+source_set("net_export") {
+  sources = [
+      "blimp_net_export.h",
+  ]
+}
+
 source_set("test_support") {
   testonly = true
 
@@ -134,6 +157,7 @@
     "compressed_packet_unittest.cc",
     "engine_authentication_handler_unittest.cc",
     "engine_connection_manager_unittest.cc",
+    "helium/vector_clock_unittest.cc",
     "input_message_unittest.cc",
     "ssl_client_transport_unittest.cc",
     "stream_packet_reader_unittest.cc",
@@ -143,6 +167,7 @@
   ]
 
   deps = [
+    ":helium",
     ":net",
     ":test_support",
     "//base",
diff --git a/blimp/net/helium/vector_clock.cc b/blimp/net/helium/vector_clock.cc
new file mode 100644
index 0000000..6b13d28
--- /dev/null
+++ b/blimp/net/helium/vector_clock.cc
@@ -0,0 +1,57 @@
+// 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.
+
+#include "blimp/net/helium/vector_clock.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+
+namespace blimp {
+
+VectorClock::VectorClock() {}
+
+VectorClock::VectorClock(Revision local_revision, Revision remote_revision)
+    : local_revision_(local_revision), remote_revision_(remote_revision) {}
+
+VectorClock::Comparison VectorClock::CompareTo(const VectorClock& other) const {
+  DCHECK(local_revision_ >= other.local_revision());
+
+  if (local_revision_ == other.local_revision()) {
+    if (remote_revision_ == other.remote_revision()) {
+      return VectorClock::Comparison::EqualTo;
+    } else if (remote_revision_ < other.remote_revision()) {
+      return VectorClock::Comparison::LessThan;
+    } else {
+      return VectorClock::Comparison::GreaterThan;
+    }
+  } else {
+    if (local_revision_ > other.local_revision()) {
+      if (remote_revision_ == other.remote_revision()) {
+        return VectorClock::Comparison::GreaterThan;
+      } else {
+        return VectorClock::Comparison::Conflict;
+      }
+    } else {  // We know its not equal or greater, so its smaller
+      if (remote_revision_ == other.remote_revision()) {
+        return VectorClock::Comparison::LessThan;
+      } else {
+        LOG(FATAL) << "Local revision should always be greater or equal.";
+        return VectorClock::Comparison::Conflict;
+      }
+    }
+  }
+}
+
+VectorClock VectorClock::MergeWith(const VectorClock& other) const {
+  VectorClock result(std::max(local_revision_, other.local_revision()),
+                     std::max(remote_revision_, other.remote_revision()));
+  return result;
+}
+
+void VectorClock::IncrementLocal() {
+  local_revision_++;
+}
+
+}  // namespace blimp
diff --git a/blimp/net/helium/vector_clock.h b/blimp/net/helium/vector_clock.h
new file mode 100644
index 0000000..8028c02
--- /dev/null
+++ b/blimp/net/helium/vector_clock.h
@@ -0,0 +1,68 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BLIMP_NET_HELIUM_VECTOR_CLOCK_H_
+#define BLIMP_NET_HELIUM_VECTOR_CLOCK_H_
+
+#include <stdint.h>
+
+#include "blimp/net/blimp_net_export.h"
+
+namespace blimp {
+
+// From wikipedia:
+// A vector clock is an algorithm for generating a partial ordering of events
+// in a distributed system and detecting causality violations. This is used
+// in Blimp to allow client and server modify a local copy of an object and
+// later be able to detect ordering or conflicts if any.
+//
+// For more info see:
+// https://en.wikipedia.org/wiki/Vector_clock
+
+typedef uint32_t Revision;
+
+class BLIMP_NET_EXPORT VectorClock {
+ public:
+  enum class Comparison { LessThan, EqualTo, GreaterThan, Conflict };
+
+  VectorClock(Revision local_revision, Revision remote_revision);
+  VectorClock();
+
+  // Compares two vector clocks. There are 4 possibilities for the result:
+  // * LessThan: One revision is equal and for the other is smaller.
+  // (1,0).CompareTo((2, 0));
+  // * EqualTo: Both revisions are the same.
+  // * GreaterThan: One revision is equal and for the other is greater.
+  // (2,0).CompareTo((1, 0));
+  // * Conflict: Both revisions are different. (1,0).CompareTo(0,1)
+  Comparison CompareTo(const VectorClock& other) const;
+
+  // Merges two vector clocks. This function should be used at synchronization
+  // points. i.e. when client receives data from the server or vice versa.
+  VectorClock MergeWith(const VectorClock& other) const;
+
+  // Increments local_revision_ by one. This is used when something changes
+  // in the local state like setting a property or applying a change set.
+  void IncrementLocal();
+
+  Revision local_revision() const { return local_revision_; }
+
+  void set_local_revision(Revision local_revision) {
+    local_revision_ = local_revision;
+  }
+
+  Revision remote_revision() const { return remote_revision_; }
+
+  void set_remote_revision(Revision remote_revision) {
+    remote_revision_ = remote_revision;
+  }
+
+ private:
+  Revision local_revision_ = 0;
+  Revision remote_revision_ = 0;
+};
+
+}  // namespace blimp
+
+#endif  // BLIMP_NET_HELIUM_VECTOR_CLOCK_H_
diff --git a/blimp/net/helium/vector_clock_unittest.cc b/blimp/net/helium/vector_clock_unittest.cc
new file mode 100644
index 0000000..2bd258e
--- /dev/null
+++ b/blimp/net/helium/vector_clock_unittest.cc
@@ -0,0 +1,140 @@
+// 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.
+
+#include "blimp/net/helium/vector_clock.h"
+
+#include "base/macros.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blimp {
+namespace {
+
+class VectorClockComparisonTest
+    : public ::testing::TestWithParam<
+          std::tuple<VectorClock, VectorClock, VectorClock::Comparison>> {
+ public:
+  VectorClockComparisonTest() {}
+  ~VectorClockComparisonTest() override {}
+};
+
+TEST_P(VectorClockComparisonTest, CompareTo) {
+  auto param = GetParam();
+  VectorClock v1 = std::get<0>(param);
+  VectorClock v2 = std::get<1>(param);
+  VectorClock::Comparison expected = std::get<2>(param);
+  EXPECT_EQ(expected, v1.CompareTo(v2));
+}
+
+INSTANTIATE_TEST_CASE_P(
+    LessThan,
+    VectorClockComparisonTest,
+    ::testing::Values(std::make_tuple(VectorClock(1, 2),
+                                      VectorClock(1, 3),
+                                      VectorClock::Comparison::LessThan)));
+
+INSTANTIATE_TEST_CASE_P(
+    GreaterThan,
+    VectorClockComparisonTest,
+    ::testing::Values(std::make_tuple(VectorClock(1, 3),
+                                      VectorClock(1, 2),
+                                      VectorClock::Comparison::GreaterThan),
+                      std::make_tuple(VectorClock(2, 2),
+                                      VectorClock(1, 2),
+                                      VectorClock::Comparison::GreaterThan)));
+
+INSTANTIATE_TEST_CASE_P(
+    Conflict,
+    VectorClockComparisonTest,
+    ::testing::Values(std::make_tuple(VectorClock(1, 2),
+                                      VectorClock(0, 1),
+                                      VectorClock::Comparison::Conflict),
+                      std::make_tuple(VectorClock(1, 2),
+                                      VectorClock(0, 3),
+                                      VectorClock::Comparison::Conflict)));
+
+INSTANTIATE_TEST_CASE_P(
+    EqualTo,
+    VectorClockComparisonTest,
+    ::testing::Values(std::make_tuple(VectorClock(1, 1),
+                                      VectorClock(1, 1),
+                                      VectorClock::Comparison::EqualTo),
+                      std::make_tuple(VectorClock(2, 3),
+                                      VectorClock(2, 3),
+                                      VectorClock::Comparison::EqualTo),
+                      std::make_tuple(VectorClock(3, 2),
+                                      VectorClock(3, 2),
+                                      VectorClock::Comparison::EqualTo)));
+
+class VectorClockTest : public testing::Test {
+ public:
+  VectorClockTest() {}
+  ~VectorClockTest() override {}
+
+ protected:
+  void CheckCumulativeMerge(const VectorClock& v1,
+                            const VectorClock& v2,
+                            const VectorClock& expected) {
+    // Compute the merge of v1 and v2
+    VectorClock r1 = v1.MergeWith(v2);
+    EXPECT_EQ(expected.local_revision(), r1.local_revision());
+    EXPECT_EQ(expected.remote_revision(), r1.remote_revision());
+
+    // Compute the merge of v2 and v1
+    VectorClock r2 = v2.MergeWith(v1);
+    EXPECT_EQ(expected.local_revision(), r2.local_revision());
+    EXPECT_EQ(expected.remote_revision(), r2.remote_revision());
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(VectorClockTest);
+};
+
+TEST_F(VectorClockTest, IncrementLocal1) {
+  VectorClock v(0, 0);
+  v.IncrementLocal();
+  EXPECT_EQ(1U, v.local_revision());
+  EXPECT_EQ(0U, v.remote_revision());
+}
+
+TEST_F(VectorClockTest, IncrementLocal2) {
+  VectorClock v(4, 5);
+  v.IncrementLocal();
+  EXPECT_EQ(5U, v.local_revision());
+  EXPECT_EQ(5U, v.remote_revision());
+}
+
+TEST_F(VectorClockTest, MergeLocalEqualRemoteSmaller) {
+  VectorClock v1(1, 2);
+  VectorClock v2(1, 4);
+
+  VectorClock expected(1, 4);
+  CheckCumulativeMerge(v1, v2, expected);
+}
+
+TEST_F(VectorClockTest, MergeLocalSmallerRemoteEqual) {
+  VectorClock v1(1, 4);
+  VectorClock v2(2, 4);
+
+  VectorClock expected(2, 4);
+  CheckCumulativeMerge(v1, v2, expected);
+}
+
+TEST_F(VectorClockTest, MergeLocalSmallerRemoteSmaller) {
+  VectorClock v1(1, 2);
+  VectorClock v2(3, 4);
+
+  VectorClock expected(3, 4);
+  CheckCumulativeMerge(v1, v2, expected);
+}
+
+TEST_F(VectorClockTest, MergeLocalSmallerRemoteGreater) {
+  VectorClock v1(1, 4);
+  VectorClock v2(3, 2);
+
+  VectorClock expected(3, 4);
+  CheckCumulativeMerge(v1, v2, expected);
+}
+
+}  // namespace
+}  // namespace blimp
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
index 071b544..594a89c4 100644
--- a/build/config/BUILDCONFIG.gn
+++ b/build/config/BUILDCONFIG.gn
@@ -481,6 +481,7 @@
 ]
 if (is_win) {
   default_compiler_configs += [
+    "//build/config/win:default_crt",
     "//build/config/win:lean_and_mean",
     "//build/config/win:nominmax",
     "//build/config/win:unicode",
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 4bbc34f4..5fcc050 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -1084,9 +1084,7 @@
       defines += [ "_FORTIFY_SOURCE=2" ]
     }
 
-    if (is_mac) {
-      # Warn if automatic synthesis is triggered. This triggers numerous
-      # warnings for internal iOS directories.
+    if (is_mac || is_ios) {
       cflags_objc = [ "-Wobjc-missing-property-synthesis" ]
       cflags_objcc = [ "-Wobjc-missing-property-synthesis" ]
     }
diff --git a/build/config/compiler/compiler.gni b/build/config/compiler/compiler.gni
index 5b51faf..cc8f5a1 100644
--- a/build/config/compiler/compiler.gni
+++ b/build/config/compiler/compiler.gni
@@ -102,3 +102,9 @@
     symbol_level = 0
   }
 }
+
+# Assert that the configuration isn't going to hit https://crbug.com/648948.
+assert(!is_android || android_64bit_target_cpu || is_component_build ||
+           symbol_level < 2,
+       "Android 32-bit non-component builds cannot have symbol_level=2 " +
+           "due to 4GiB file size limit, see https://crbug.com/648948")
diff --git a/build/config/ios/codesign.py b/build/config/ios/codesign.py
index 3d66b24..5b55318 100644
--- a/build/config/ios/codesign.py
+++ b/build/config/ios/codesign.py
@@ -232,7 +232,6 @@
 
 
 class Action(object):
-
   """Class implementing one action supported by the script."""
 
   @classmethod
@@ -243,7 +242,6 @@
 
 
 class CodeSignBundleAction(Action):
-
   """Class implementing the code-sign-bundle action."""
 
   name = 'code-sign-bundle'
@@ -321,8 +319,49 @@
     CodeSignBundle(bundle.path, args.identity, codesign_extra_args)
 
 
-class GenerateEntitlementsAction(Action):
+class CodeSignFileAction(Action):
+  """Class implementing code signature for a single file."""
 
+  name = 'code-sign-file'
+  help = 'code-sign a single file'
+
+  @staticmethod
+  def _Register(parser):
+    parser.add_argument(
+        'path', help='path to the file to codesign')
+    parser.add_argument(
+        '--identity', '-i', required=True,
+        help='identity to use to codesign')
+    parser.add_argument(
+        '--output', '-o',
+        help='if specified copy the file to that location before signing it')
+    parser.set_defaults(sign=True)
+
+  @staticmethod
+  def _Execute(args):
+    if not args.identity:
+      args.identity = '-'
+
+    install_path = args.path
+    if args.output:
+
+      if os.path.isfile(args.output):
+        os.unlink(args.output)
+      elif os.path.isdir(args.output):
+        shutil.rmtree(args.output)
+
+      if os.path.isfile(args.path):
+        shutil.copy(args.path, args.output)
+      elif os.path.isdir(args.path):
+        shutil.copytree(args.path, args.output)
+
+      install_path = args.output
+
+    CodeSignBundle(install_path, args.identity,
+      ['--deep', '--preserve-metadata=identifier,entitlements'])
+
+
+class GenerateEntitlementsAction(Action):
   """Class implementing the generate-entitlements action."""
 
   name = 'generate-entitlements'
@@ -353,7 +392,13 @@
   parser = argparse.ArgumentParser('codesign iOS bundles')
   subparsers = parser.add_subparsers()
 
-  for action in [ CodeSignBundleAction, GenerateEntitlementsAction ]:
+  actions = [
+      CodeSignBundleAction,
+      CodeSignFileAction,
+      GenerateEntitlementsAction,
+  ]
+
+  for action in actions:
     action.Register(subparsers)
 
   args = parser.parse_args()
diff --git a/build/config/ios/rules.gni b/build/config/ios/rules.gni
index 8d1c162..93565f0 100644
--- a/build/config/ios/rules.gni
+++ b/build/config/ios/rules.gni
@@ -223,7 +223,7 @@
       code_signing_outputs +=
           [ "$_bundle_root_dir/_CodeSignature/CodeResources" ]
     }
-    if (ios_code_signing_identity != "" && ios_sdk_name != "iphonesimulator") {
+    if (ios_code_signing_identity != "" && !use_ios_simulator) {
       code_signing_outputs += [ "$_bundle_root_dir/embedded.mobileprovision" ]
     }
 
diff --git a/build/config/locales.gni b/build/config/locales.gni
index 5886132..2b608b7 100644
--- a/build/config/locales.gni
+++ b/build/config/locales.gni
@@ -2,6 +2,22 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+# Android doesn't ship all locales in order to save space (but webview does).
+# http://crbug.com/369218
+if (is_android) {
+  android_chrome_omitted_locales = [
+    "bn",
+    "et",
+    "gu",
+    "kn",
+    "ml",
+    "mr",
+    "ms",
+    "ta",
+    "te",
+  ]
+}
+
 # Chrome on iOS only ships with a subset of the locales supported by other
 # version of Chrome as the corresponding locales are not supported by the
 # operating system (but for simplicity, the corresponding .pak files are
diff --git a/build/config/sanitizers/BUILD.gn b/build/config/sanitizers/BUILD.gn
index 9dc878e..5040189e 100644
--- a/build/config/sanitizers/BUILD.gn
+++ b/build/config/sanitizers/BUILD.gn
@@ -9,6 +9,10 @@
 import("//build/config/sanitizers/sanitizers.gni")
 import("//build/toolchain/toolchain.gni")
 
+if (is_ios) {
+  import("//build/config/ios/ios_sdk.gni")
+}
+
 # Contains the dependencies needed for sanitizers to link into executables and
 # shared_libraries. Unconditionally depend upon this target as it is empty if
 # |is_asan|, |is_lsan|, |is_tsan|, |is_msan| and |use_custom_libcxx| are false.
@@ -67,35 +71,65 @@
       public_deps += [ "//buildtools/third_party/libc++:libcxx_proxy" ]
       data += [ "$root_out_dir/libc++.so" ]
     }
-    if (is_mac || is_win) {
+
+    # ASAN is supported on iOS but the runtime library depends on the compiler
+    # used (Chromium version of clang versus Xcode version of clang). Only copy
+    # the ASAN runtime on iOS if building with Chromium clang.
+    if (is_win || is_mac || (is_ios && !use_xcode_clang)) {
       data_deps = [
         ":copy_asan_runtime",
       ]
     }
-    if (is_mac) {
+    if (is_mac || (is_ios && !use_xcode_clang)) {
       public_deps += [ ":asan_runtime_bundle_data" ]
     }
   }
 }
 
-if ((is_mac || is_win) && using_sanitizer) {
-  copy("copy_asan_runtime") {
-    if (is_mac) {
-      clang_rt_dso_path = "darwin/libclang_rt.asan_osx_dynamic.dylib"
-    } else if (is_win && target_cpu == "x86") {
-      clang_rt_dso_path = "windows/clang_rt.asan_dynamic-i386.dll"
-    } else if (is_win && target_cpu == "x64") {
-      clang_rt_dso_path = "windows/clang_rt.asan_dynamic-x86_64.dll"
-    }
-    sources = [
-      "$clang_base_path/lib/clang/$clang_version/lib/$clang_rt_dso_path",
-    ]
-    outputs = [
-      "$root_out_dir/{{source_file_part}}",
-    ]
+if ((is_mac || is_win || (is_ios && !use_xcode_clang)) && using_sanitizer) {
+  if (is_mac) {
+    _clang_rt_dso_path = "darwin/libclang_rt.asan_osx_dynamic.dylib"
+  } else if (is_ios) {
+    _clang_rt_dso_path = "darwin/libclang_rt.asan_iossim_dynamic.dylib"
+  } else if (is_win && target_cpu == "x86") {
+    _clang_rt_dso_path = "windows/clang_rt.asan_dynamic-i386.dll"
+  } else if (is_win && target_cpu == "x64") {
+    _clang_rt_dso_path = "windows/clang_rt.asan_dynamic-x86_64.dll"
   }
 
-  if (is_mac) {
+  _clang_rt_dso_full_path =
+      "$clang_base_path/lib/clang/$clang_version/lib/$_clang_rt_dso_path"
+
+  if (!is_ios) {
+    copy("copy_asan_runtime") {
+      sources = [
+        _clang_rt_dso_full_path,
+      ]
+      outputs = [
+        "$root_out_dir/{{source_file_part}}",
+      ]
+    }
+  } else {
+    # On iOS, the runtime library need to be code signed (adhoc signature)
+    # starting with Xcode 8, so use an action instead of a copy on iOS.
+    action("copy_asan_runtime") {
+      script = "//build/config/ios/codesign.py"
+      sources = [
+        _clang_rt_dso_full_path,
+      ]
+      outputs = [
+        "$root_out_dir/" + get_path_info(sources[0], "file"),
+      ]
+      args = [
+        "code-sign-file",
+        "--identity=" + ios_code_signing_identity,
+        "--output=" + rebase_path(outputs[0], root_build_dir),
+        rebase_path(sources[0], root_build_dir),
+      ]
+    }
+  }
+
+  if (is_mac || is_ios) {
     bundle_data("asan_runtime_bundle_data") {
       sources = get_target_outputs(":copy_asan_runtime")
       outputs = [
diff --git a/build/config/win/BUILD.gn b/build/config/win/BUILD.gn
index b437516..9b6ac7423 100644
--- a/build/config/win/BUILD.gn
+++ b/build/config/win/BUILD.gn
@@ -193,33 +193,6 @@
     # However it is prohibited when using /analyze
     defines += [ "_USING_V110_SDK71_" ]
   }
-
-  if (is_component_build) {
-    # Component mode: dynamic CRT. Since the library is shared, it requires
-    # exceptions or will give errors about things not matching, so keep
-    # exceptions on.
-    if (is_debug) {
-      cflags += [ "/MDd" ]
-    } else {
-      cflags += [ "/MD" ]
-    }
-  } else {
-    if (current_os != "win") {
-      # WindowsRT: use the dynamic CRT.
-      if (is_debug) {
-        cflags += [ "/MDd" ]
-      } else {
-        cflags += [ "/MD" ]
-      }
-    } else {
-      # Desktop Windows: static CRT.
-      if (is_debug) {
-        cflags += [ "/MTd" ]
-      } else {
-        cflags += [ "/MT" ]
-      }
-    }
-  }
 }
 
 # Sets the default Windows build version. This is separated because some
@@ -291,6 +264,44 @@
   }
 }
 
+# CRT --------------------------------------------------------------------------
+
+# Configures how the runtime library (CRT) is going to be used.
+# See https://msdn.microsoft.com/en-us/library/2kzt1wy3.aspx for a reference of
+# what each value does.
+config("default_crt") {
+  if (is_component_build) {
+    # Component mode: dynamic CRT. Since the library is shared, it requires
+    # exceptions or will give errors about things not matching, so keep
+    # exceptions on.
+    configs = [ ":dynamic_crt" ]
+  } else {
+    if (current_os != "win") {
+      # WindowsRT: use the dynamic CRT.
+      configs = [ ":dynamic_crt" ]
+    } else {
+      # Desktop Windows: static CRT.
+      configs = [ ":static_crt" ]
+    }
+  }
+}
+
+config("dynamic_crt") {
+  if (is_debug) {
+    cflags = [ "/MDd" ]
+  } else {
+    cflags = [ "/MD" ]
+  }
+}
+
+config("static_crt") {
+  if (is_debug) {
+    cflags = [ "/MTd" ]
+  } else {
+    cflags = [ "/MT" ]
+  }
+}
+
 # Subsystem --------------------------------------------------------------------
 
 # This is appended to the subsystem to specify a minimum version.
diff --git a/build/linux/sysroot_scripts/packagelist.jessie.amd64 b/build/linux/sysroot_scripts/packagelist.jessie.amd64
index f54fc2ee..8a6c613 100644
--- a/build/linux/sysroot_scripts/packagelist.jessie.amd64
+++ b/build/linux/sysroot_scripts/packagelist.jessie.amd64
@@ -18,14 +18,14 @@
 main/d/dbus-glib/libdbus-glib-1-2_0.102-1_amd64.deb
 main/d/dbus/libdbus-1-3_1.8.20-0+deb8u1_amd64.deb
 main/d/dbus/libdbus-1-dev_1.8.20-0+deb8u1_amd64.deb
-main/e/e2fsprogs/comerr-dev_2.1-1.42.12-1.1_amd64.deb
-main/e/e2fsprogs/libcomerr2_1.42.12-1.1_amd64.deb
+main/e/e2fsprogs/comerr-dev_2.1-1.42.12-2_amd64.deb
+main/e/e2fsprogs/libcomerr2_1.42.12-2_amd64.deb
 main/e/elfutils/libelf1_0.159-4.2_amd64.deb
 main/e/elfutils/libelf-dev_0.159-4.2_amd64.deb
-main/e/expat/libexpat1_2.1.0-6+deb8u2_amd64.deb
-main/e/expat/libexpat1-dev_2.1.0-6+deb8u2_amd64.deb
-main/f/fontconfig/libfontconfig1_2.11.0-6.3_amd64.deb
-main/f/fontconfig/libfontconfig1-dev_2.11.0-6.3_amd64.deb
+main/e/expat/libexpat1_2.1.0-6+deb8u3_amd64.deb
+main/e/expat/libexpat1-dev_2.1.0-6+deb8u3_amd64.deb
+main/f/fontconfig/libfontconfig1_2.11.0-6.3+deb8u1_amd64.deb
+main/f/fontconfig/libfontconfig1-dev_2.11.0-6.3+deb8u1_amd64.deb
 main/f/freetype/libfreetype6_2.5.2-3+deb8u1_amd64.deb
 main/f/freetype/libfreetype6-dev_2.5.2-3+deb8u1_amd64.deb
 main/g/gcc-4.8/libasan0_4.8.4-1_amd64.deb
@@ -44,12 +44,12 @@
 main/g/gconf/libgconf2-4_3.2.6-3_amd64.deb
 main/g/gconf/libgconf-2-4_3.2.6-3_amd64.deb
 main/g/gconf/libgconf2-dev_3.2.6-3_amd64.deb
-main/g/gdk-pixbuf/libgdk-pixbuf2.0-0_2.31.1-2+deb8u4_amd64.deb
-main/g/gdk-pixbuf/libgdk-pixbuf2.0-dev_2.31.1-2+deb8u4_amd64.deb
+main/g/gdk-pixbuf/libgdk-pixbuf2.0-0_2.31.1-2+deb8u5_amd64.deb
+main/g/gdk-pixbuf/libgdk-pixbuf2.0-dev_2.31.1-2+deb8u5_amd64.deb
 main/g/glib2.0/libglib2.0-0_2.42.1-1+b1_amd64.deb
 main/g/glib2.0/libglib2.0-dev_2.42.1-1+b1_amd64.deb
-main/g/glibc/libc6_2.19-18+deb8u4_amd64.deb
-main/g/glibc/libc6-dev_2.19-18+deb8u4_amd64.deb
+main/g/glibc/libc6_2.19-18+deb8u6_amd64.deb
+main/g/glibc/libc6-dev_2.19-18+deb8u6_amd64.deb
 main/g/gnutls28/libgnutls28-dev_3.3.8-6+deb8u3_amd64.deb
 main/g/gnutls28/libgnutls-deb0-28_3.3.8-6+deb8u3_amd64.deb
 main/g/gnutls28/libgnutls-openssl27_3.3.8-6+deb8u3_amd64.deb
@@ -80,8 +80,8 @@
 main/libd/libdrm/libdrm-radeon1_2.4.58-2_amd64.deb
 main/libf/libffi/libffi6_3.1-2+b2_amd64.deb
 main/libf/libffi/libffi-dev_3.1-2+b2_amd64.deb
-main/libg/libgcrypt20/libgcrypt20_1.6.3-2+deb8u1_amd64.deb
-main/libg/libgcrypt20/libgcrypt20-dev_1.6.3-2+deb8u1_amd64.deb
+main/libg/libgcrypt20/libgcrypt20_1.6.3-2+deb8u2_amd64.deb
+main/libg/libgcrypt20/libgcrypt20-dev_1.6.3-2+deb8u2_amd64.deb
 main/libg/libgnome-keyring/libgnome-keyring0_3.12.0-1+b1_amd64.deb
 main/libg/libgnome-keyring/libgnome-keyring-dev_3.12.0-1+b1_amd64.deb
 main/libg/libgpg-error/libgpg-error0_1.17-3_amd64.deb
@@ -133,7 +133,7 @@
 main/libx/libxtst/libxtst6_1.2.2-1+b1_amd64.deb
 main/libx/libxtst/libxtst-dev_1.2.2-1+b1_amd64.deb
 main/libx/libxxf86vm/libxxf86vm1_1.1.3-1+b1_amd64.deb
-main/l/linux/linux-libc-dev_3.16.7-ckt25-2_amd64.deb
+main/l/linux/linux-libc-dev_3.16.36-1+deb8u1_amd64.deb
 main/m/mesa/libgl1-mesa-dev_10.3.2-1+deb8u1_amd64.deb
 main/m/mesa/libgl1-mesa-glx_10.3.2-1+deb8u1_amd64.deb
 main/m/mesa/libglapi-mesa_10.3.2-1+deb8u1_amd64.deb
@@ -142,8 +142,8 @@
 main/n/nspr/libnspr4-dev_4.10.7-1+deb8u1_amd64.deb
 main/n/nss/libnss3_3.17.2-1.1+deb8u2_amd64.deb
 main/n/nss/libnss3-dev_3.17.2-1.1+deb8u2_amd64.deb
-main/o/openssl/libssl1.0.0_1.0.1t-1+deb8u2_amd64.deb
-main/o/openssl/libssl-dev_1.0.1t-1+deb8u2_amd64.deb
+main/o/openssl/libssl1.0.0_1.0.1t-1+deb8u3_amd64.deb
+main/o/openssl/libssl-dev_1.0.1t-1+deb8u3_amd64.deb
 main/o/orbit2/liborbit2_2.14.19-0.3_amd64.deb
 main/p/p11-kit/libp11-kit0_0.20.7-1_amd64.deb
 main/p/pam/libpam0g_1.1.8-3.1+deb8u1+b1_amd64.deb
@@ -167,8 +167,8 @@
 main/s/speech-dispatcher/libspeechd2_0.8-7_amd64.deb
 main/s/speech-dispatcher/libspeechd-dev_0.8-7_amd64.deb
 main/s/speech-dispatcher/speech-dispatcher_0.8-7_amd64.deb
-main/s/systemd/libudev1_215-17+deb8u4_amd64.deb
-main/s/systemd/libudev-dev_215-17+deb8u4_amd64.deb
+main/s/systemd/libudev1_215-17+deb8u5_amd64.deb
+main/s/systemd/libudev-dev_215-17+deb8u5_amd64.deb
 main/x/x11proto-composite/x11proto-composite-dev_0.4.2-2_all.deb
 main/x/x11proto-core/x11proto-core-dev_7.0.26-1_all.deb
 main/x/x11proto-damage/x11proto-damage-dev_1.2.1-2_all.deb
diff --git a/build/linux/sysroot_scripts/packagelist.jessie.arm b/build/linux/sysroot_scripts/packagelist.jessie.arm
index cc88fe4e..6455073 100644
--- a/build/linux/sysroot_scripts/packagelist.jessie.arm
+++ b/build/linux/sysroot_scripts/packagelist.jessie.arm
@@ -18,14 +18,14 @@
 main/d/dbus-glib/libdbus-glib-1-2_0.102-1_armhf.deb
 main/d/dbus/libdbus-1-3_1.8.20-0+deb8u1_armhf.deb
 main/d/dbus/libdbus-1-dev_1.8.20-0+deb8u1_armhf.deb
-main/e/e2fsprogs/comerr-dev_2.1-1.42.12-1.1_armhf.deb
-main/e/e2fsprogs/libcomerr2_1.42.12-1.1_armhf.deb
+main/e/e2fsprogs/comerr-dev_2.1-1.42.12-2_armhf.deb
+main/e/e2fsprogs/libcomerr2_1.42.12-2_armhf.deb
 main/e/elfutils/libelf1_0.159-4.2_armhf.deb
 main/e/elfutils/libelf-dev_0.159-4.2_armhf.deb
-main/e/expat/libexpat1_2.1.0-6+deb8u2_armhf.deb
-main/e/expat/libexpat1-dev_2.1.0-6+deb8u2_armhf.deb
-main/f/fontconfig/libfontconfig1_2.11.0-6.3_armhf.deb
-main/f/fontconfig/libfontconfig1-dev_2.11.0-6.3_armhf.deb
+main/e/expat/libexpat1_2.1.0-6+deb8u3_armhf.deb
+main/e/expat/libexpat1-dev_2.1.0-6+deb8u3_armhf.deb
+main/f/fontconfig/libfontconfig1_2.11.0-6.3+deb8u1_armhf.deb
+main/f/fontconfig/libfontconfig1-dev_2.11.0-6.3+deb8u1_armhf.deb
 main/f/freetype/libfreetype6_2.5.2-3+deb8u1_armhf.deb
 main/f/freetype/libfreetype6-dev_2.5.2-3+deb8u1_armhf.deb
 main/g/gcc-4.8/libasan0_4.8.4-1_armhf.deb
@@ -39,12 +39,12 @@
 main/g/gconf/libgconf2-4_3.2.6-3_armhf.deb
 main/g/gconf/libgconf-2-4_3.2.6-3_armhf.deb
 main/g/gconf/libgconf2-dev_3.2.6-3_armhf.deb
-main/g/gdk-pixbuf/libgdk-pixbuf2.0-0_2.31.1-2+deb8u4_armhf.deb
-main/g/gdk-pixbuf/libgdk-pixbuf2.0-dev_2.31.1-2+deb8u4_armhf.deb
+main/g/gdk-pixbuf/libgdk-pixbuf2.0-0_2.31.1-2+deb8u5_armhf.deb
+main/g/gdk-pixbuf/libgdk-pixbuf2.0-dev_2.31.1-2+deb8u5_armhf.deb
 main/g/glib2.0/libglib2.0-0_2.42.1-1+b1_armhf.deb
 main/g/glib2.0/libglib2.0-dev_2.42.1-1+b1_armhf.deb
-main/g/glibc/libc6_2.19-18+deb8u4_armhf.deb
-main/g/glibc/libc6-dev_2.19-18+deb8u4_armhf.deb
+main/g/glibc/libc6_2.19-18+deb8u6_armhf.deb
+main/g/glibc/libc6-dev_2.19-18+deb8u6_armhf.deb
 main/g/gnutls28/libgnutls28-dev_3.3.8-6+deb8u3_armhf.deb
 main/g/gnutls28/libgnutls-deb0-28_3.3.8-6+deb8u3_armhf.deb
 main/g/gnutls28/libgnutls-openssl27_3.3.8-6+deb8u3_armhf.deb
@@ -77,8 +77,8 @@
 main/libd/libdrm/libdrm-radeon1_2.4.58-2_armhf.deb
 main/libf/libffi/libffi6_3.1-2+b2_armhf.deb
 main/libf/libffi/libffi-dev_3.1-2+b2_armhf.deb
-main/libg/libgcrypt20/libgcrypt20_1.6.3-2+deb8u1_armhf.deb
-main/libg/libgcrypt20/libgcrypt20-dev_1.6.3-2+deb8u1_armhf.deb
+main/libg/libgcrypt20/libgcrypt20_1.6.3-2+deb8u2_armhf.deb
+main/libg/libgcrypt20/libgcrypt20-dev_1.6.3-2+deb8u2_armhf.deb
 main/libg/libgnome-keyring/libgnome-keyring0_3.12.0-1+b1_armhf.deb
 main/libg/libgnome-keyring/libgnome-keyring-dev_3.12.0-1+b1_armhf.deb
 main/libg/libgpg-error/libgpg-error0_1.17-3_armhf.deb
@@ -130,7 +130,7 @@
 main/libx/libxtst/libxtst6_1.2.2-1+b1_armhf.deb
 main/libx/libxtst/libxtst-dev_1.2.2-1+b1_armhf.deb
 main/libx/libxxf86vm/libxxf86vm1_1.1.3-1+b1_armhf.deb
-main/l/linux/linux-libc-dev_3.16.7-ckt25-2_armhf.deb
+main/l/linux/linux-libc-dev_3.16.36-1+deb8u1_armhf.deb
 main/m/mesa/libgl1-mesa-dev_10.3.2-1+deb8u1_armhf.deb
 main/m/mesa/libgl1-mesa-glx_10.3.2-1+deb8u1_armhf.deb
 main/m/mesa/libglapi-mesa_10.3.2-1+deb8u1_armhf.deb
@@ -139,8 +139,8 @@
 main/n/nspr/libnspr4-dev_4.10.7-1+deb8u1_armhf.deb
 main/n/nss/libnss3_3.17.2-1.1+deb8u2_armhf.deb
 main/n/nss/libnss3-dev_3.17.2-1.1+deb8u2_armhf.deb
-main/o/openssl/libssl1.0.0_1.0.1t-1+deb8u2_armhf.deb
-main/o/openssl/libssl-dev_1.0.1t-1+deb8u2_armhf.deb
+main/o/openssl/libssl1.0.0_1.0.1t-1+deb8u3_armhf.deb
+main/o/openssl/libssl-dev_1.0.1t-1+deb8u3_armhf.deb
 main/o/orbit2/liborbit2_2.14.19-0.3_armhf.deb
 main/p/p11-kit/libp11-kit0_0.20.7-1_armhf.deb
 main/p/pam/libpam0g_1.1.8-3.1+deb8u1+b1_armhf.deb
@@ -164,8 +164,8 @@
 main/s/speech-dispatcher/libspeechd2_0.8-7_armhf.deb
 main/s/speech-dispatcher/libspeechd-dev_0.8-7_armhf.deb
 main/s/speech-dispatcher/speech-dispatcher_0.8-7_armhf.deb
-main/s/systemd/libudev1_215-17+deb8u4_armhf.deb
-main/s/systemd/libudev-dev_215-17+deb8u4_armhf.deb
+main/s/systemd/libudev1_215-17+deb8u5_armhf.deb
+main/s/systemd/libudev-dev_215-17+deb8u5_armhf.deb
 main/x/x11proto-composite/x11proto-composite-dev_0.4.2-2_all.deb
 main/x/x11proto-core/x11proto-core-dev_7.0.26-1_all.deb
 main/x/x11proto-damage/x11proto-damage-dev_1.2.1-2_all.deb
diff --git a/build/linux/sysroot_scripts/packagelist.jessie.arm64 b/build/linux/sysroot_scripts/packagelist.jessie.arm64
index f13eb47..e7a0a7b 100644
--- a/build/linux/sysroot_scripts/packagelist.jessie.arm64
+++ b/build/linux/sysroot_scripts/packagelist.jessie.arm64
@@ -18,14 +18,14 @@
 main/d/dbus-glib/libdbus-glib-1-2_0.102-1_arm64.deb
 main/d/dbus/libdbus-1-3_1.8.20-0+deb8u1_arm64.deb
 main/d/dbus/libdbus-1-dev_1.8.20-0+deb8u1_arm64.deb
-main/e/e2fsprogs/comerr-dev_2.1-1.42.12-1.1_arm64.deb
-main/e/e2fsprogs/libcomerr2_1.42.12-1.1_arm64.deb
+main/e/e2fsprogs/comerr-dev_2.1-1.42.12-2_arm64.deb
+main/e/e2fsprogs/libcomerr2_1.42.12-2_arm64.deb
 main/e/elfutils/libelf1_0.159-4.2_arm64.deb
 main/e/elfutils/libelf-dev_0.159-4.2_arm64.deb
-main/e/expat/libexpat1_2.1.0-6+deb8u2_arm64.deb
-main/e/expat/libexpat1-dev_2.1.0-6+deb8u2_arm64.deb
-main/f/fontconfig/libfontconfig1_2.11.0-6.3_arm64.deb
-main/f/fontconfig/libfontconfig1-dev_2.11.0-6.3_arm64.deb
+main/e/expat/libexpat1_2.1.0-6+deb8u3_arm64.deb
+main/e/expat/libexpat1-dev_2.1.0-6+deb8u3_arm64.deb
+main/f/fontconfig/libfontconfig1_2.11.0-6.3+deb8u1_arm64.deb
+main/f/fontconfig/libfontconfig1-dev_2.11.0-6.3+deb8u1_arm64.deb
 main/f/freetype/libfreetype6_2.5.2-3+deb8u1_arm64.deb
 main/f/freetype/libfreetype6-dev_2.5.2-3+deb8u1_arm64.deb
 main/g/gcc-4.8/libgcc-4.8-dev_4.8.4-1_arm64.deb
@@ -38,12 +38,12 @@
 main/g/gconf/libgconf2-4_3.2.6-3_arm64.deb
 main/g/gconf/libgconf-2-4_3.2.6-3_arm64.deb
 main/g/gconf/libgconf2-dev_3.2.6-3_arm64.deb
-main/g/gdk-pixbuf/libgdk-pixbuf2.0-0_2.31.1-2+deb8u4_arm64.deb
-main/g/gdk-pixbuf/libgdk-pixbuf2.0-dev_2.31.1-2+deb8u4_arm64.deb
+main/g/gdk-pixbuf/libgdk-pixbuf2.0-0_2.31.1-2+deb8u5_arm64.deb
+main/g/gdk-pixbuf/libgdk-pixbuf2.0-dev_2.31.1-2+deb8u5_arm64.deb
 main/g/glib2.0/libglib2.0-0_2.42.1-1+b1_arm64.deb
 main/g/glib2.0/libglib2.0-dev_2.42.1-1+b1_arm64.deb
-main/g/glibc/libc6_2.19-18+deb8u4_arm64.deb
-main/g/glibc/libc6-dev_2.19-18+deb8u4_arm64.deb
+main/g/glibc/libc6_2.19-18+deb8u6_arm64.deb
+main/g/glibc/libc6-dev_2.19-18+deb8u6_arm64.deb
 main/g/gmp/libgmp10_6.0.0+dfsg-6_arm64.deb
 main/g/gnutls28/libgnutls28-dev_3.3.8-6+deb8u3_arm64.deb
 main/g/gnutls28/libgnutls-deb0-28_3.3.8-6+deb8u3_arm64.deb
@@ -76,8 +76,8 @@
 main/libd/libdrm/libdrm-radeon1_2.4.58-2_arm64.deb
 main/libf/libffi/libffi6_3.1-2+b2_arm64.deb
 main/libf/libffi/libffi-dev_3.1-2+b2_arm64.deb
-main/libg/libgcrypt20/libgcrypt20_1.6.3-2+deb8u1_arm64.deb
-main/libg/libgcrypt20/libgcrypt20-dev_1.6.3-2+deb8u1_arm64.deb
+main/libg/libgcrypt20/libgcrypt20_1.6.3-2+deb8u2_arm64.deb
+main/libg/libgcrypt20/libgcrypt20-dev_1.6.3-2+deb8u2_arm64.deb
 main/libg/libgnome-keyring/libgnome-keyring0_3.12.0-1+b1_arm64.deb
 main/libg/libgnome-keyring/libgnome-keyring-dev_3.12.0-1+b1_arm64.deb
 main/libg/libgpg-error/libgpg-error0_1.17-3_arm64.deb
@@ -130,7 +130,7 @@
 main/libx/libxtst/libxtst6_1.2.2-1+b1_arm64.deb
 main/libx/libxtst/libxtst-dev_1.2.2-1+b1_arm64.deb
 main/libx/libxxf86vm/libxxf86vm1_1.1.3-1+b1_arm64.deb
-main/l/linux/linux-libc-dev_3.16.7-ckt25-2_arm64.deb
+main/l/linux/linux-libc-dev_3.16.36-1+deb8u1_arm64.deb
 main/m/mesa/libgl1-mesa-dev_10.3.2-1+deb8u1_arm64.deb
 main/m/mesa/libgl1-mesa-glx_10.3.2-1+deb8u1_arm64.deb
 main/m/mesa/libglapi-mesa_10.3.2-1+deb8u1_arm64.deb
@@ -141,8 +141,8 @@
 main/n/nspr/libnspr4-dev_4.10.7-1+deb8u1_arm64.deb
 main/n/nss/libnss3_3.17.2-1.1+deb8u2_arm64.deb
 main/n/nss/libnss3-dev_3.17.2-1.1+deb8u2_arm64.deb
-main/o/openssl/libssl1.0.0_1.0.1t-1+deb8u2_arm64.deb
-main/o/openssl/libssl-dev_1.0.1t-1+deb8u2_arm64.deb
+main/o/openssl/libssl1.0.0_1.0.1t-1+deb8u3_arm64.deb
+main/o/openssl/libssl-dev_1.0.1t-1+deb8u3_arm64.deb
 main/o/orbit2/liborbit2_2.14.19-0.3_arm64.deb
 main/p/p11-kit/libp11-kit0_0.20.7-1_arm64.deb
 main/p/pam/libpam0g_1.1.8-3.1+deb8u1+b1_arm64.deb
@@ -166,8 +166,8 @@
 main/s/speech-dispatcher/libspeechd2_0.8-7_arm64.deb
 main/s/speech-dispatcher/libspeechd-dev_0.8-7_arm64.deb
 main/s/speech-dispatcher/speech-dispatcher_0.8-7_arm64.deb
-main/s/systemd/libudev1_215-17+deb8u4_arm64.deb
-main/s/systemd/libudev-dev_215-17+deb8u4_arm64.deb
+main/s/systemd/libudev1_215-17+deb8u5_arm64.deb
+main/s/systemd/libudev-dev_215-17+deb8u5_arm64.deb
 main/x/x11proto-composite/x11proto-composite-dev_0.4.2-2_all.deb
 main/x/x11proto-core/x11proto-core-dev_7.0.26-1_all.deb
 main/x/x11proto-damage/x11proto-damage-dev_1.2.1-2_all.deb
diff --git a/build/linux/sysroot_scripts/packagelist.jessie.i386 b/build/linux/sysroot_scripts/packagelist.jessie.i386
index a293f11..1e9bc34 100644
--- a/build/linux/sysroot_scripts/packagelist.jessie.i386
+++ b/build/linux/sysroot_scripts/packagelist.jessie.i386
@@ -18,14 +18,14 @@
 main/d/dbus-glib/libdbus-glib-1-2_0.102-1_i386.deb
 main/d/dbus/libdbus-1-3_1.8.20-0+deb8u1_i386.deb
 main/d/dbus/libdbus-1-dev_1.8.20-0+deb8u1_i386.deb
-main/e/e2fsprogs/comerr-dev_2.1-1.42.12-1.1_i386.deb
-main/e/e2fsprogs/libcomerr2_1.42.12-1.1_i386.deb
+main/e/e2fsprogs/comerr-dev_2.1-1.42.12-2_i386.deb
+main/e/e2fsprogs/libcomerr2_1.42.12-2_i386.deb
 main/e/elfutils/libelf1_0.159-4.2_i386.deb
 main/e/elfutils/libelf-dev_0.159-4.2_i386.deb
-main/e/expat/libexpat1_2.1.0-6+deb8u2_i386.deb
-main/e/expat/libexpat1-dev_2.1.0-6+deb8u2_i386.deb
-main/f/fontconfig/libfontconfig1_2.11.0-6.3_i386.deb
-main/f/fontconfig/libfontconfig1-dev_2.11.0-6.3_i386.deb
+main/e/expat/libexpat1_2.1.0-6+deb8u3_i386.deb
+main/e/expat/libexpat1-dev_2.1.0-6+deb8u3_i386.deb
+main/f/fontconfig/libfontconfig1_2.11.0-6.3+deb8u1_i386.deb
+main/f/fontconfig/libfontconfig1-dev_2.11.0-6.3+deb8u1_i386.deb
 main/f/freetype/libfreetype6_2.5.2-3+deb8u1_i386.deb
 main/f/freetype/libfreetype6-dev_2.5.2-3+deb8u1_i386.deb
 main/g/gcc-4.8/libasan0_4.8.4-1_i386.deb
@@ -42,12 +42,12 @@
 main/g/gconf/libgconf-2-4_3.2.6-3_i386.deb
 main/g/gconf/libgconf2-4_3.2.6-3_i386.deb
 main/g/gconf/libgconf2-dev_3.2.6-3_i386.deb
-main/g/gdk-pixbuf/libgdk-pixbuf2.0-0_2.31.1-2+deb8u4_i386.deb
-main/g/gdk-pixbuf/libgdk-pixbuf2.0-dev_2.31.1-2+deb8u4_i386.deb
+main/g/gdk-pixbuf/libgdk-pixbuf2.0-0_2.31.1-2+deb8u5_i386.deb
+main/g/gdk-pixbuf/libgdk-pixbuf2.0-dev_2.31.1-2+deb8u5_i386.deb
 main/g/glib2.0/libglib2.0-0_2.42.1-1+b1_i386.deb
 main/g/glib2.0/libglib2.0-dev_2.42.1-1+b1_i386.deb
-main/g/glibc/libc6_2.19-18+deb8u4_i386.deb
-main/g/glibc/libc6-dev_2.19-18+deb8u4_i386.deb
+main/g/glibc/libc6_2.19-18+deb8u6_i386.deb
+main/g/glibc/libc6-dev_2.19-18+deb8u6_i386.deb
 main/g/gnutls28/libgnutls28-dev_3.3.8-6+deb8u3_i386.deb
 main/g/gnutls28/libgnutls-deb0-28_3.3.8-6+deb8u3_i386.deb
 main/g/gnutls28/libgnutls-openssl27_3.3.8-6+deb8u3_i386.deb
@@ -78,8 +78,8 @@
 main/libd/libdrm/libdrm-radeon1_2.4.58-2_i386.deb
 main/libf/libffi/libffi6_3.1-2+b2_i386.deb
 main/libf/libffi/libffi-dev_3.1-2+b2_i386.deb
-main/libg/libgcrypt20/libgcrypt20_1.6.3-2+deb8u1_i386.deb
-main/libg/libgcrypt20/libgcrypt20-dev_1.6.3-2+deb8u1_i386.deb
+main/libg/libgcrypt20/libgcrypt20_1.6.3-2+deb8u2_i386.deb
+main/libg/libgcrypt20/libgcrypt20-dev_1.6.3-2+deb8u2_i386.deb
 main/libg/libgnome-keyring/libgnome-keyring0_3.12.0-1+b1_i386.deb
 main/libg/libgnome-keyring/libgnome-keyring-dev_3.12.0-1+b1_i386.deb
 main/libg/libgpg-error/libgpg-error0_1.17-3_i386.deb
@@ -131,7 +131,7 @@
 main/libx/libxtst/libxtst6_1.2.2-1+b1_i386.deb
 main/libx/libxtst/libxtst-dev_1.2.2-1+b1_i386.deb
 main/libx/libxxf86vm/libxxf86vm1_1.1.3-1+b1_i386.deb
-main/l/linux/linux-libc-dev_3.16.7-ckt25-2_i386.deb
+main/l/linux/linux-libc-dev_3.16.36-1+deb8u1_i386.deb
 main/m/mesa/libgl1-mesa-dev_10.3.2-1+deb8u1_i386.deb
 main/m/mesa/libgl1-mesa-glx_10.3.2-1+deb8u1_i386.deb
 main/m/mesa/libglapi-mesa_10.3.2-1+deb8u1_i386.deb
@@ -140,8 +140,8 @@
 main/n/nspr/libnspr4-dev_4.10.7-1+deb8u1_i386.deb
 main/n/nss/libnss3_3.17.2-1.1+deb8u2_i386.deb
 main/n/nss/libnss3-dev_3.17.2-1.1+deb8u2_i386.deb
-main/o/openssl/libssl1.0.0_1.0.1t-1+deb8u2_i386.deb
-main/o/openssl/libssl-dev_1.0.1t-1+deb8u2_i386.deb
+main/o/openssl/libssl1.0.0_1.0.1t-1+deb8u3_i386.deb
+main/o/openssl/libssl-dev_1.0.1t-1+deb8u3_i386.deb
 main/o/orbit2/liborbit2_2.14.19-0.3_i386.deb
 main/p/p11-kit/libp11-kit0_0.20.7-1_i386.deb
 main/p/pam/libpam0g_1.1.8-3.1+deb8u1+b1_i386.deb
@@ -165,8 +165,8 @@
 main/s/speech-dispatcher/libspeechd2_0.8-7_i386.deb
 main/s/speech-dispatcher/libspeechd-dev_0.8-7_i386.deb
 main/s/speech-dispatcher/speech-dispatcher_0.8-7_i386.deb
-main/s/systemd/libudev1_215-17+deb8u4_i386.deb
-main/s/systemd/libudev-dev_215-17+deb8u4_i386.deb
+main/s/systemd/libudev1_215-17+deb8u5_i386.deb
+main/s/systemd/libudev-dev_215-17+deb8u5_i386.deb
 main/x/x11proto-composite/x11proto-composite-dev_0.4.2-2_all.deb
 main/x/x11proto-core/x11proto-core-dev_7.0.26-1_all.deb
 main/x/x11proto-damage/x11proto-damage-dev_1.2.1-2_all.deb
diff --git a/build/linux/sysroot_scripts/packagelist.jessie.mipsel b/build/linux/sysroot_scripts/packagelist.jessie.mipsel
index 95032de..220618c4 100644
--- a/build/linux/sysroot_scripts/packagelist.jessie.mipsel
+++ b/build/linux/sysroot_scripts/packagelist.jessie.mipsel
@@ -18,14 +18,14 @@
 main/d/dbus-glib/libdbus-glib-1-2_0.102-1_mipsel.deb
 main/d/dbus/libdbus-1-3_1.8.20-0+deb8u1_mipsel.deb
 main/d/dbus/libdbus-1-dev_1.8.20-0+deb8u1_mipsel.deb
-main/e/e2fsprogs/comerr-dev_2.1-1.42.12-1.1_mipsel.deb
-main/e/e2fsprogs/libcomerr2_1.42.12-1.1_mipsel.deb
+main/e/e2fsprogs/comerr-dev_2.1-1.42.12-2_mipsel.deb
+main/e/e2fsprogs/libcomerr2_1.42.12-2_mipsel.deb
 main/e/elfutils/libelf1_0.159-4.2_mipsel.deb
 main/e/elfutils/libelf-dev_0.159-4.2_mipsel.deb
-main/e/expat/libexpat1_2.1.0-6+deb8u2_mipsel.deb
-main/e/expat/libexpat1-dev_2.1.0-6+deb8u2_mipsel.deb
-main/f/fontconfig/libfontconfig1_2.11.0-6.3_mipsel.deb
-main/f/fontconfig/libfontconfig1-dev_2.11.0-6.3_mipsel.deb
+main/e/expat/libexpat1_2.1.0-6+deb8u3_mipsel.deb
+main/e/expat/libexpat1-dev_2.1.0-6+deb8u3_mipsel.deb
+main/f/fontconfig/libfontconfig1_2.11.0-6.3+deb8u1_mipsel.deb
+main/f/fontconfig/libfontconfig1-dev_2.11.0-6.3+deb8u1_mipsel.deb
 main/f/freetype/libfreetype6_2.5.2-3+deb8u1_mipsel.deb
 main/f/freetype/libfreetype6-dev_2.5.2-3+deb8u1_mipsel.deb
 main/g/gcc-4.8/libgcc-4.8-dev_4.8.4-1_mipsel.deb
@@ -37,12 +37,12 @@
 main/g/gconf/libgconf2-4_3.2.6-3_mipsel.deb
 main/g/gconf/libgconf-2-4_3.2.6-3_mipsel.deb
 main/g/gconf/libgconf2-dev_3.2.6-3_mipsel.deb
-main/g/gdk-pixbuf/libgdk-pixbuf2.0-0_2.31.1-2+deb8u4_mipsel.deb
-main/g/gdk-pixbuf/libgdk-pixbuf2.0-dev_2.31.1-2+deb8u4_mipsel.deb
+main/g/gdk-pixbuf/libgdk-pixbuf2.0-0_2.31.1-2+deb8u5_mipsel.deb
+main/g/gdk-pixbuf/libgdk-pixbuf2.0-dev_2.31.1-2+deb8u5_mipsel.deb
 main/g/glib2.0/libglib2.0-0_2.42.1-1+b1_mipsel.deb
 main/g/glib2.0/libglib2.0-dev_2.42.1-1+b1_mipsel.deb
-main/g/glibc/libc6_2.19-18+deb8u4_mipsel.deb
-main/g/glibc/libc6-dev_2.19-18+deb8u4_mipsel.deb
+main/g/glibc/libc6_2.19-18+deb8u6_mipsel.deb
+main/g/glibc/libc6-dev_2.19-18+deb8u6_mipsel.deb
 main/g/gnutls28/libgnutls28-dev_3.3.8-6+deb8u3_mipsel.deb
 main/g/gnutls28/libgnutls-deb0-28_3.3.8-6+deb8u3_mipsel.deb
 main/g/gnutls28/libgnutls-openssl27_3.3.8-6+deb8u3_mipsel.deb
@@ -72,8 +72,8 @@
 main/libd/libdrm/libdrm-radeon1_2.4.58-2_mipsel.deb
 main/libf/libffi/libffi6_3.1-2+b2_mipsel.deb
 main/libf/libffi/libffi-dev_3.1-2+b2_mipsel.deb
-main/libg/libgcrypt20/libgcrypt20_1.6.3-2+deb8u1_mipsel.deb
-main/libg/libgcrypt20/libgcrypt20-dev_1.6.3-2+deb8u1_mipsel.deb
+main/libg/libgcrypt20/libgcrypt20_1.6.3-2+deb8u2_mipsel.deb
+main/libg/libgcrypt20/libgcrypt20-dev_1.6.3-2+deb8u2_mipsel.deb
 main/libg/libgnome-keyring/libgnome-keyring0_3.12.0-1+b1_mipsel.deb
 main/libg/libgnome-keyring/libgnome-keyring-dev_3.12.0-1+b1_mipsel.deb
 main/libg/libgpg-error/libgpg-error0_1.17-3_mipsel.deb
@@ -125,7 +125,7 @@
 main/libx/libxtst/libxtst6_1.2.2-1+b1_mipsel.deb
 main/libx/libxtst/libxtst-dev_1.2.2-1+b1_mipsel.deb
 main/libx/libxxf86vm/libxxf86vm1_1.1.3-1+b1_mipsel.deb
-main/l/linux/linux-libc-dev_3.16.7-ckt25-2_mipsel.deb
+main/l/linux/linux-libc-dev_3.16.36-1+deb8u1_mipsel.deb
 main/m/mesa/libgl1-mesa-dev_10.3.2-1+deb8u1_mipsel.deb
 main/m/mesa/libgl1-mesa-glx_10.3.2-1+deb8u1_mipsel.deb
 main/m/mesa/libglapi-mesa_10.3.2-1+deb8u1_mipsel.deb
@@ -134,8 +134,8 @@
 main/n/nspr/libnspr4-dev_4.10.7-1+deb8u1_mipsel.deb
 main/n/nss/libnss3_3.17.2-1.1+deb8u2_mipsel.deb
 main/n/nss/libnss3-dev_3.17.2-1.1+deb8u2_mipsel.deb
-main/o/openssl/libssl1.0.0_1.0.1t-1+deb8u2_mipsel.deb
-main/o/openssl/libssl-dev_1.0.1t-1+deb8u2_mipsel.deb
+main/o/openssl/libssl1.0.0_1.0.1t-1+deb8u3_mipsel.deb
+main/o/openssl/libssl-dev_1.0.1t-1+deb8u3_mipsel.deb
 main/o/orbit2/liborbit2_2.14.19-0.3_mipsel.deb
 main/p/p11-kit/libp11-kit0_0.20.7-1_mipsel.deb
 main/p/pam/libpam0g_1.1.8-3.1+deb8u1+b1_mipsel.deb
@@ -159,8 +159,8 @@
 main/s/speech-dispatcher/libspeechd2_0.8-7_mipsel.deb
 main/s/speech-dispatcher/libspeechd-dev_0.8-7_mipsel.deb
 main/s/speech-dispatcher/speech-dispatcher_0.8-7_mipsel.deb
-main/s/systemd/libudev1_215-17+deb8u4_mipsel.deb
-main/s/systemd/libudev-dev_215-17+deb8u4_mipsel.deb
+main/s/systemd/libudev1_215-17+deb8u5_mipsel.deb
+main/s/systemd/libudev-dev_215-17+deb8u5_mipsel.deb
 main/x/x11proto-composite/x11proto-composite-dev_0.4.2-2_all.deb
 main/x/x11proto-core/x11proto-core-dev_7.0.26-1_all.deb
 main/x/x11proto-damage/x11proto-damage-dev_1.2.1-2_all.deb
diff --git a/build/toolchain/concurrent_links.gni b/build/toolchain/concurrent_links.gni
index 89c2ce7d..163fc1b 100644
--- a/build/toolchain/concurrent_links.gni
+++ b/build/toolchain/concurrent_links.gni
@@ -22,8 +22,8 @@
 if (concurrent_links == -1) {
   if (allow_posix_link_time_opt || is_cfi) {
     _args = [
-      "--mem_per_link_gb=24",
-      "--reserve_mem_gb=10",
+      "--mem_per_link_gb=26",
+      "--reserve_mem_gb=20",
     ]
   } else if (is_win) {
     _args = [ "--mem_per_link_gb=5" ]
diff --git a/cc/layers/texture_layer_unittest.cc b/cc/layers/texture_layer_unittest.cc
index 072e464..9292aa4 100644
--- a/cc/layers/texture_layer_unittest.cc
+++ b/cc/layers/texture_layer_unittest.cc
@@ -844,8 +844,8 @@
   scoped_refptr<TextureLayer> layer_;
 };
 
-// Flaky on windows. https://crbug.com/641613
-#if !defined(OS_WIN)
+// Flaky on windows and linux. https://crbug.com/641613
+#if !defined(OS_WIN) && !defined(OS_LINUX)
 SINGLE_AND_MULTI_THREAD_TEST_F(TextureLayerMailboxIsActivatedDuringCommit);
 #endif
 
diff --git a/cc/playback/skip_image_canvas.cc b/cc/playback/skip_image_canvas.cc
index badaf107..27926be 100644
--- a/cc/playback/skip_image_canvas.cc
+++ b/cc/playback/skip_image_canvas.cc
@@ -17,7 +17,7 @@
     return false;
 
   SkShader* shader = (*paint) ? (*paint)->getShader() : nullptr;
-  return !shader || !shader->isABitmap();
+  return !shader || !shader->isAImage();
 }
 
 void SkipImageCanvas::onDrawPicture(const SkPicture* picture,
diff --git a/cc/resources/video_resource_updater.cc b/cc/resources/video_resource_updater.cc
index 2584e0b..e56c385 100644
--- a/cc/resources/video_resource_updater.cc
+++ b/cc/resources/video_resource_updater.cc
@@ -84,6 +84,11 @@
     case media::PIXEL_FORMAT_YUV420P10:
     case media::PIXEL_FORMAT_YUV422P10:
     case media::PIXEL_FORMAT_YUV444P10:
+    case media::PIXEL_FORMAT_YUV420P12:
+    case media::PIXEL_FORMAT_YUV422P12:
+    case media::PIXEL_FORMAT_YUV444P12:
+    case media::PIXEL_FORMAT_Y8:
+    case media::PIXEL_FORMAT_Y16:
     case media::PIXEL_FORMAT_UNKNOWN:
       break;
   }
@@ -289,6 +294,25 @@
   return gfx::Size(plane_width, plane_height);
 }
 
+void VideoResourceUpdater::MakeHalfFloats(const uint16_t* src,
+                                          int bits_per_channel,
+                                          size_t num,
+                                          uint16_t* dst) {
+  // TODO(hubbe): Make AVX and neon versions of this code.
+
+  // This magic constant is 2^-112. Multiplying by this
+  // is the same as subtracting 112 from the exponent, which
+  // is the difference in exponent bias between 32-bit and
+  // 16-bit floats. Once we've done this subtraction, we can
+  // simply extract the low bits of the exponent and the high
+  // bits of the mantissa from our float and we're done.
+  float mult = 1.9259299444e-34f / ((1 << bits_per_channel) - 1);
+  for (size_t i = 0; i < num; i++) {
+    float value = src[i] * mult;
+    dst[i] = (*(uint32_t*)&value) >> 13;
+  }
+}
+
 VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes(
     scoped_refptr<media::VideoFrame> video_frame) {
   TRACE_EVENT0("cc", "VideoResourceUpdater::CreateForSoftwarePlanes");
@@ -315,6 +339,7 @@
     case media::PIXEL_FORMAT_RGB32:
     case media::PIXEL_FORMAT_MJPEG:
     case media::PIXEL_FORMAT_MT21:
+    case media::PIXEL_FORMAT_Y8:
       bits_per_channel = 8;
       break;
     case media::PIXEL_FORMAT_YUV420P9:
@@ -327,8 +352,19 @@
     case media::PIXEL_FORMAT_YUV444P10:
       bits_per_channel = 10;
       break;
+    case media::PIXEL_FORMAT_YUV420P12:
+    case media::PIXEL_FORMAT_YUV422P12:
+    case media::PIXEL_FORMAT_YUV444P12:
+      bits_per_channel = 12;
+      break;
+    case media::PIXEL_FORMAT_Y16:
+      bits_per_channel = 16;
+      break;
   }
 
+  // TODO(dshwang): support PIXEL_FORMAT_Y16. crbug.com/624436
+  DCHECK_NE(bits_per_channel, 16);
+
   // Only YUV software video frames are supported.
   if (!media::IsYuvPlanar(input_frame_format)) {
     NOTREACHED() << media::VideoPixelFormatToString(input_frame_format);
@@ -482,9 +518,34 @@
       // LUMINANCE_F16 uses half-floats, so we always need a conversion step.
       if (plane_resource.resource_format() == LUMINANCE_F16) {
         needs_conversion = true;
-        // Note that the current method of converting integers to half-floats
-        // stops working if you have more than 10 bits of data.
-        DCHECK_LE(bits_per_channel, 10);
+
+        // If the input data was 9 or 10 bit, and we output to half-floats,
+        // then we used the OR path below, which means that we need to
+        // adjust the resource offset and multiplier accordingly. If the
+        // input data uses more than 10 bits, it will already be normalized
+        // to 0.0..1.0, so there is no need to do anything.
+        if (bits_per_channel <= 10) {
+          // By OR-ing with 0x3800, 10-bit numbers become half-floats in the
+          // range [0.5..1) and 9-bit numbers get the range [0.5..0.75).
+          //
+          // Half-floats are evaluated as:
+          // float value = pow(2.0, exponent - 25) * (0x400 + fraction);
+          //
+          // In our case the exponent is 14 (since we or with 0x3800) and
+          // pow(2.0, 14-25) * 0x400 evaluates to 0.5 (our offset) and
+          // pow(2.0, 14-25) * fraction is [0..0.49951171875] for 10-bit and
+          // [0..0.24951171875] for 9-bit.
+          //
+          // https://en.wikipedia.org/wiki/Half-precision_floating-point_format
+          //
+          // PLEASE NOTE:
+          // All planes are assumed to use the same multiplier/offset.
+          external_resources.offset = 0.5f;
+          // Max value from input data.
+          int max_input_value = (1 << bits_per_channel) - 1;
+          // 2 << 11 = 2048 would be 1.0 with our exponent.
+          external_resources.multiplier = 2048.0 / max_input_value;
+        }
       } else if (bits_per_channel > 8) {
         // If bits_per_channel > 8 and we can't use LUMINANCE_F16, we need to
         // shift the data down and create an 8-bit texture.
@@ -508,13 +569,17 @@
                 &upload_pixels_[upload_image_stride * row]);
             const uint16_t* src = reinterpret_cast<uint16_t*>(
                 video_frame->data(i) + (video_stride_bytes * row));
-            // Micro-benchmarking indicates that the compiler does
-            // a good enough job of optimizing this loop that trying
-            // to manually operate on one uint64 at a time is not
-            // actually helpful.
-            // Note to future optimizers: Benchmark your optimizations!
-            for (size_t i = 0; i < bytes_per_row / 2; i++)
-              dst[i] = src[i] | 0x3800;
+            if (bits_per_channel <= 10) {
+              // Micro-benchmarking indicates that the compiler does
+              // a good enough job of optimizing this loop that trying
+              // to manually operate on one uint64 at a time is not
+              // actually helpful.
+              // Note to future optimizers: Benchmark your optimizations!
+              for (size_t i = 0; i < bytes_per_row / 2; i++)
+                dst[i] = src[i] | 0x3800;
+            } else {
+              MakeHalfFloats(src, bits_per_channel, bytes_per_row / 2, dst);
+            }
           } else if (shift != 0) {
             // We have more-than-8-bit input which we need to shift
             // down to fit it into an 8-bit texture.
@@ -540,28 +605,6 @@
       plane_resource.SetUniqueId(video_frame->unique_id(), i);
     }
 
-    if (plane_resource.resource_format() == LUMINANCE_F16) {
-      // By OR-ing with 0x3800, 10-bit numbers become half-floats in the
-      // range [0.5..1) and 9-bit numbers get the range [0.5..0.75).
-      //
-      // Half-floats are evaluated as:
-      // float value = pow(2.0, exponent - 25) * (0x400 + fraction);
-      //
-      // In our case the exponent is 14 (since we or with 0x3800) and
-      // pow(2.0, 14-25) * 0x400 evaluates to 0.5 (our offset) and
-      // pow(2.0, 14-25) * fraction is [0..0.49951171875] for 10-bit and
-      // [0..0.24951171875] for 9-bit.
-      //
-      // (https://en.wikipedia.org/wiki/Half-precision_floating-point_format)
-      //
-      // PLEASE NOTE: This doesn't work if bits_per_channel is > 10.
-      // PLEASE NOTE: All planes are assumed to use the same multiplier/offset.
-      external_resources.offset = 0.5f;
-      // Max value from input data.
-      int max_input_value = (1 << bits_per_channel) - 1;
-      // 2 << 11 = 2048 would be 1.0 with our exponent.
-      external_resources.multiplier = 2048.0 / max_input_value;
-    }
 
     // VideoResourceUpdater shares a context with the compositor so a
     // sync token is not required.
diff --git a/cc/resources/video_resource_updater.h b/cc/resources/video_resource_updater.h
index a3a5011..a42784c9 100644
--- a/cc/resources/video_resource_updater.h
+++ b/cc/resources/video_resource_updater.h
@@ -80,6 +80,15 @@
   VideoFrameExternalResources CreateExternalResourcesFromVideoFrame(
       scoped_refptr<media::VideoFrame> video_frame);
 
+  // Convert an array of short integers into an array of half-floats.
+  // |src| is an array of integers in range 0 .. 2^{bits_per_channel} - 1
+  // |num| is number of entries in input and output array.
+  // The numbers stored in |dst| will be half floats in range 0.0..1.0
+  static void MakeHalfFloats(const uint16_t* src,
+                             int bits_per_channel,
+                             size_t num,
+                             uint16_t* dst);
+
  private:
   class PlaneResource {
    public:
diff --git a/cc/resources/video_resource_updater_unittest.cc b/cc/resources/video_resource_updater_unittest.cc
index 938c0fc..1c414fc 100644
--- a/cc/resources/video_resource_updater_unittest.cc
+++ b/cc/resources/video_resource_updater_unittest.cc
@@ -504,5 +504,54 @@
   EXPECT_FALSE(context3d_->WasImmutableTextureCreated());
 }
 
+namespace {
+
+// Convert an IEEE 754 half-float to a double value
+// that we can do math on.
+double FromHalfFloat(uint16_t half_float) {
+  if (!half_float)
+    return 0.0;
+  int sign = (half_float & 0x8000) ? -1 : 1;
+  int exponent = (half_float >> 10) & 0x1F;
+  int fraction = half_float & 0x3FF;
+  if (exponent == 0) {
+    return pow(2.0, -24.0) * fraction;
+  } else if (exponent == 0x1F) {
+    return sign * 1000000000000.0;
+  } else {
+    return pow(2.0, exponent - 25) * (0x400 + fraction);
+  }
+}
+
+}  // namespace
+
+TEST_F(VideoResourceUpdaterTest, MakeHalfFloatTest) {
+  unsigned short integers[1 << 12];
+  unsigned short half_floats[1 << 12];
+  for (int bits = 9; bits <= 12; bits++) {
+    int num_values = 1 << bits;
+    for (int i = 0; i < num_values; i++)
+      integers[i] = i;
+
+    VideoResourceUpdater::MakeHalfFloats(integers, bits, num_values,
+                                         half_floats);
+
+    // Multiplier to converting integers to 0.0..1.0 range.
+    double multiplier = 1.0 / (num_values - 1);
+
+    for (int i = 0; i < num_values; i++) {
+      // We expect the result to be within +/- one least-significant bit.
+      // Within the range we care about, half-floats values and
+      // their representation both sort in the same order, so we
+      // can just add one to get the next bigger half-float.
+      float expected_precision =
+          FromHalfFloat(half_floats[i] + 1) - FromHalfFloat(half_floats[i]);
+      EXPECT_NEAR(FromHalfFloat(half_floats[i]), integers[i] * multiplier,
+                  expected_precision)
+          << "i = " << i << " bits = " << bits;
+    }
+  }
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/chrome/VERSION b/chrome/VERSION
index afe9430..ccc7d51 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=55
 MINOR=0
-BUILD=2875
+BUILD=2876
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 8a22ed7..697030c8b 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -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("//android_webview/webview_repack_locales_list.gni")
 import("//build/config/android/config.gni")
 import("//build/config/android/rules.gni")
 import("//build/util/process_version.gni")
@@ -67,52 +68,10 @@
 }
 
 locale_pak_resources("chrome_locale_paks") {
-  sources = [
-    "$root_out_dir/locales/am.pak",
-    "$root_out_dir/locales/ar.pak",
-    "$root_out_dir/locales/bg.pak",
-    "$root_out_dir/locales/ca.pak",
-    "$root_out_dir/locales/cs.pak",
-    "$root_out_dir/locales/da.pak",
-    "$root_out_dir/locales/de.pak",
-    "$root_out_dir/locales/el.pak",
-    "$root_out_dir/locales/en-GB.pak",
-    "$root_out_dir/locales/en-US.pak",
-    "$root_out_dir/locales/es-419.pak",
-    "$root_out_dir/locales/es.pak",
-    "$root_out_dir/locales/fa.pak",
-    "$root_out_dir/locales/fi.pak",
-    "$root_out_dir/locales/fil.pak",
-    "$root_out_dir/locales/fr.pak",
-    "$root_out_dir/locales/he.pak",
-    "$root_out_dir/locales/hi.pak",
-    "$root_out_dir/locales/hr.pak",
-    "$root_out_dir/locales/hu.pak",
-    "$root_out_dir/locales/id.pak",
-    "$root_out_dir/locales/it.pak",
-    "$root_out_dir/locales/ja.pak",
-    "$root_out_dir/locales/ko.pak",
-    "$root_out_dir/locales/lt.pak",
-    "$root_out_dir/locales/lv.pak",
-    "$root_out_dir/locales/nb.pak",
-    "$root_out_dir/locales/nl.pak",
-    "$root_out_dir/locales/pl.pak",
-    "$root_out_dir/locales/pt-BR.pak",
-    "$root_out_dir/locales/pt-PT.pak",
-    "$root_out_dir/locales/ro.pak",
-    "$root_out_dir/locales/ru.pak",
-    "$root_out_dir/locales/sk.pak",
-    "$root_out_dir/locales/sl.pak",
-    "$root_out_dir/locales/sr.pak",
-    "$root_out_dir/locales/sv.pak",
-    "$root_out_dir/locales/sw.pak",
-    "$root_out_dir/locales/th.pak",
-    "$root_out_dir/locales/tr.pak",
-    "$root_out_dir/locales/uk.pak",
-    "$root_out_dir/locales/vi.pak",
-    "$root_out_dir/locales/zh-CN.pak",
-    "$root_out_dir/locales/zh-TW.pak",
-  ]
+  sources = []
+  foreach(_locale, locales - android_chrome_omitted_locales) {
+    sources += [ "$root_out_dir/locales/$_locale.pak" ]
+  }
 
   deps = [
     "//chrome:packed_resources",
@@ -596,19 +555,26 @@
       "//android_webview:generate_aw_resources",
     ]
 
+    additional_locale_source_patterns = webview_repack_locales_source_patterns
+    deps += webview_repack_locales_deps
+
     if (enable_resource_whitelist_generation) {
       repack_whitelist = monochrome_resource_whitelist
       deps += [ ":monochrome_resource_whitelist" ]
     }
   }
-}  # current_toolchain == host_toolchain
 
-java_group("monochrome_assets") {
-  deps = [
-    ":monochrome_pak_assets",
-    "//android_webview:monochrome_webview_assets",
-  ]
-}
+  locale_pak_resources("monochrome_locale_paks") {
+    sources = []
+    foreach(_locale, locales) {
+      sources += [ "$target_gen_dir/monochrome_paks/locales/$_locale.pak" ]
+    }
+
+    deps = [
+      ":monochrome_paks",
+    ]
+  }
+}  # current_toolchain == host_toolchain
 
 android_assets("monochrome_pak_assets") {
   sources = [
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni
index c107d629..8e9e9b9 100644
--- a/chrome/android/chrome_public_apk_tmpl.gni
+++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -77,3 +77,46 @@
     }
   }
 }
+
+template("monochrome_public_apk_tmpl") {
+  chrome_public_apk_tmpl(target_name) {
+    # Always build 64-bit //android_webview:monochrome because Chrome runs
+    # in 32-bit mode.
+    if (android_64bit_target_cpu) {
+      shared_libraries = [ "//android_webview:monochrome" ]
+    } else {
+      shared_libraries = [ "//chrome/android:monochrome" ]
+    }
+    if (android_64bit_target_cpu && build_apk_secondary_abi) {
+      secondary_abi_shared_libraries =
+          [ "//chrome/android:monochrome_secondary_abi_lib" ]
+    }
+
+    alternative_locale_resource_dep = "//chrome/android:monochrome_locale_paks"
+
+    alternative_android_sdk_jar = webview_framework_jar
+    app_as_shared_lib = true
+    use_chromium_linker = false
+    requires_sdk_api_level_23 = true
+    enable_relocation_packing = true
+    extensions_to_not_compress = ".lpak,.pak,.bin,.dat"
+
+    # Configrations to make android load shared library from APK.
+    uncompress_shared_libraries = true
+    page_align_shared_libraries = true
+
+    forward_variables_from(invoker, "*")
+
+    if (!defined(deps)) {
+      deps = []
+    }
+    deps += [ "//android_webview/glue" ]
+
+    if (!is_java_debug) {
+      if (!defined(proguard_configs)) {
+        proguard_configs = []
+      }
+      proguard_configs += [ "//android_webview/apk/java/proguard.flags" ]
+    }
+  }
+}
diff --git a/chrome/android/java/res/layout/account_signin_view.xml b/chrome/android/java/res/layout/account_signin_view.xml
index e1a536b9..646127e 100644
--- a/chrome/android/java/res/layout/account_signin_view.xml
+++ b/chrome/android/java/res/layout/account_signin_view.xml
@@ -236,30 +236,36 @@
             android:layout_weight="1"
             android:visibility="invisible"/>
 
-        <!--suppress ButtonStyle -->
-        <org.chromium.ui.widget.ButtonCompat
-            android:id="@+id/positive_button"
+        <FrameLayout
             android:layout_width="wrap_content"
-            android:layout_height="36dp"
-            android:text="@string/choose_account_sign_in"
-            android:textAllCaps="true"
-            android:textColor="@android:color/white"
-            android:textSize="14sp"
-            chrome:buttonColor="@color/light_active_color"
-            chrome:buttonRaised="false"/>
+            android:layout_height="wrap_content"
+            android:measureAllChildren="true">
 
-        <Button
-            android:id="@+id/more_button"
-            style="@style/ButtonCompatBorderless"
-            android:layout_width="wrap_content"
-            android:layout_height="36dp"
-            android:text="@string/more"
-            android:textAllCaps="true"
-            android:textColor="@color/light_active_color"
-            android:textSize="14sp"
-            android:drawableEnd="@drawable/down_arrow"
-            android:drawablePadding="8dp"
-            android:visibility="gone"/>
+            <!--suppress ButtonStyle -->
+            <org.chromium.ui.widget.ButtonCompat
+                android:id="@+id/positive_button"
+                android:layout_width="wrap_content"
+                android:layout_height="36dp"
+                android:text="@string/choose_account_sign_in"
+                android:textAllCaps="true"
+                android:textColor="@android:color/white"
+                android:textSize="14sp"
+                chrome:buttonColor="@color/light_active_color"
+                chrome:buttonRaised="false"/>
+
+            <Button
+                android:id="@+id/more_button"
+                style="@style/ButtonCompatBorderless"
+                android:layout_width="wrap_content"
+                android:layout_height="36dp"
+                android:text="@string/more"
+                android:textAllCaps="true"
+                android:textColor="@color/light_active_color"
+                android:textSize="14sp"
+                android:drawableEnd="@drawable/down_arrow"
+                android:drawablePadding="8dp"
+                android:visibility="gone"/>
+            </FrameLayout>
 
         <View
             android:id="@+id/positive_button_end_padding"
diff --git a/chrome/android/java/res/layout/toolbar.xml b/chrome/android/java/res/layout/toolbar.xml
index 83feb109..c610ab1 100644
--- a/chrome/android/java/res/layout/toolbar.xml
+++ b/chrome/android/java/res/layout/toolbar.xml
@@ -23,13 +23,6 @@
         android:background="?attr/selectableItemBackground"
         android:contentDescription="@string/accessibility_toolbar_btn_new_tab" />
 
-    <org.chromium.chrome.browser.widget.TintedImageButton
-        android:id="@+id/return_button"
-        style="@style/ToolbarButton"
-        android:src="@drawable/btn_close"
-        android:contentDescription="@string/close_tab_and_return"
-        android:visibility="gone" />
-
     <org.chromium.chrome.browser.toolbar.HomePageButton
         android:id="@+id/home_button"
         style="@style/ToolbarButton"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java
index a18e61a3..8904660 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java
@@ -179,20 +179,12 @@
      */
     public static final String HERB_FLAVOR_DISABLED_SWITCH =
             "tab-management-experiment-type-disabled";
-    public static final String HERB_FLAVOR_ANISE_SWITCH = "tab-management-experiment-type-anise";
-    public static final String HERB_FLAVOR_BASIL_SWITCH = "tab-management-experiment-type-basil";
-    public static final String HERB_FLAVOR_CHIVE_SWITCH = "tab-management-experiment-type-chive";
-    public static final String HERB_FLAVOR_DILL_SWITCH = "tab-management-experiment-type-dill";
     public static final String HERB_FLAVOR_ELDERBERRY_SWITCH =
             "tab-management-experiment-type-elderberry";
 
     public static final String HERB_FLAVOR_DEFAULT = "Default";
     public static final String HERB_FLAVOR_CONTROL = "Control";
     public static final String HERB_FLAVOR_DISABLED = "Disabled";
-    public static final String HERB_FLAVOR_ANISE = "Anise";
-    public static final String HERB_FLAVOR_BASIL = "Basil";
-    public static final String HERB_FLAVOR_CHIVE = "Chive";
-    public static final String HERB_FLAVOR_DILL = "Dill";
     public static final String HERB_FLAVOR_ELDERBERRY = "Elderberry";
 
     public static final String DISABLE_APP_LINK = "disable-app-link";
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 699cebf4..c498fdf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -10,11 +10,9 @@
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Color;
-import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.SystemClock;
-import android.provider.Browser;
 import android.support.annotation.IntDef;
 import android.support.annotation.Nullable;
 import android.text.TextUtils;
@@ -55,8 +53,6 @@
 import org.chromium.chrome.browser.compositor.layouts.eventfilter.EventFilter;
 import org.chromium.chrome.browser.compositor.layouts.phone.StackLayout;
 import org.chromium.chrome.browser.cookies.CookiesFetcher;
-import org.chromium.chrome.browser.customtabs.CustomTabActivity;
-import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider;
 import org.chromium.chrome.browser.device.DeviceClassManager;
 import org.chromium.chrome.browser.document.ChromeLauncherActivity;
 import org.chromium.chrome.browser.download.DownloadUtils;
@@ -119,7 +115,6 @@
 public class ChromeTabbedActivity extends ChromeActivity implements OverviewModeObserver {
 
     private static final int FIRST_RUN_EXPERIENCE_RESULT = 101;
-    private static final int CCT_RESULT = 102;
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({
@@ -538,16 +533,6 @@
             getToolbarManager().initializeWithNative(mTabModelSelectorImpl, getFullscreenManager(),
                     mFindToolbarManager, mLayoutManager, mLayoutManager,
                     tabSwitcherClickHandler, newTabClickHandler, bookmarkClickHandler, null);
-            getToolbarManager().getToolbar().setReturnButtonListener(new OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    if (getActivityTab() == null) return;
-                    mActivityStopMetrics.setStopReason(
-                            ActivityStopMetrics.STOP_REASON_RETURN_BUTTON);
-                    RecordUserAction.record("TaskManagement.ReturnButtonClicked");
-                    sendToBackground(getActivityTab());
-                }
-            });
 
             if (isTablet()) {
                 EmptyBackgroundViewWrapper bgViewWrapper = new EmptyBackgroundViewWrapper(
@@ -676,26 +661,6 @@
                 }
             }
             return true;
-        } else if (requestCode == CCT_RESULT) {
-            Log.d(TAG, "Custom Tab result: " + resultCode);
-            if (resultCode == CustomTabActivity.RESULT_STOPPED && data != null) {
-                // Open the last URL shown in the CustomTabActivity.  Unfortunately, there isn't a
-                // good TabLaunchType to use here (FROM_EXTERNAL_APP changes back behavior, e.g.),
-                // but this shouldn't be a problem once Tab reparenting lands.
-                //
-                // TODO(dfalcantara): Use real tab reparenting here when possible.  We should fall
-                //                    back to using the TabState file or URL, in that order.
-                getTabCreator(false).createNewTab(new LoadUrlParams(
-                        data.getDataString()), TabLaunchType.FROM_CHROME_UI, null);
-            } else if ((resultCode == CustomTabActivity.RESULT_BACK_PRESSED
-                    || resultCode == CustomTabActivity.RESULT_CLOSED) && data != null) {
-                // Herb UMA should have already been recorded by the CustomTabActivity.
-                Log.d(TAG, "Herb: Sending app to the background");
-                mActivityStopMetrics.setStopReason(
-                        ActivityStopMetrics.STOP_REASON_CUSTOM_TAB_STOPPED);
-                sendToBackground(null);
-            }
-            return true;
         }
         return false;
     }
@@ -857,35 +822,11 @@
             boolean isAllowedToReturnToExternalApp = IntentUtils.safeGetBooleanExtra(intent,
                     ChromeLauncherActivity.EXTRA_IS_ALLOWED_TO_RETURN_TO_PARENT, true);
 
-            String herbFlavor = FeatureUtilities.getHerbFlavor();
-            if (isAllowedToReturnToExternalApp
-                    && ChromeLauncherActivity.canBeHijackedByHerb(intent)
-                    && TextUtils.equals(ChromeSwitches.HERB_FLAVOR_DILL, herbFlavor)) {
-                Log.d(TAG, "Sending to CustomTabActivity");
-                mActivityStopMetrics.setStopReason(
-                        ActivityStopMetrics.STOP_REASON_CUSTOM_TAB_STARTED);
-
-                Intent newIntent = ChromeLauncherActivity.createCustomTabActivityIntent(
-                        ChromeTabbedActivity.this, intent, false);
-                newIntent.putExtra(Browser.EXTRA_APPLICATION_ID, getPackageName());
-                newIntent.putExtra(
-                        CustomTabIntentDataProvider.EXTRA_IS_OPENED_BY_CHROME, true);
-                ChromeLauncherActivity.updateHerbIntent(ChromeTabbedActivity.this,
-                        newIntent, Uri.parse(IntentHandler.getUrlFromIntent(newIntent)));
-
-                // Launch the Activity on top of this task.
-                int updatedFlags = newIntent.getFlags();
-                updatedFlags &= ~Intent.FLAG_ACTIVITY_NEW_TASK;
-                updatedFlags &= ~Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
-                newIntent.setFlags(updatedFlags);
-                startActivityForResult(newIntent, CCT_RESULT);
-            } else {
-                // Create a new tab.
-                Tab newTab =
-                        launchIntent(url, referer, headers, externalAppId, forceNewTab, intent);
-                newTab.setIsAllowedToReturnToExternalApp(isAllowedToReturnToExternalApp);
-                RecordUserAction.record("MobileReceivedExternalIntent");
-            }
+            // Create a new tab.
+            Tab newTab =
+                    launchIntent(url, referer, headers, externalAppId, forceNewTab, intent);
+            newTab.setIsAllowedToReturnToExternalApp(isAllowedToReturnToExternalApp);
+            RecordUserAction.record("MobileReceivedExternalIntent");
         }
     }
 
@@ -1217,22 +1158,13 @@
             return true;
         }
 
-        // The current spec says that tabs are closed only when there is NO "X" visible, i.e. when
-        // the tab is NOT allowed to return to the external app.
-        boolean isAllowedToCloseTab = true;
-        String herbFlavor = FeatureUtilities.getHerbFlavor();
-        if (TextUtils.equals(ChromeSwitches.HERB_FLAVOR_BASIL, herbFlavor)
-                || TextUtils.equals(ChromeSwitches.HERB_FLAVOR_CHIVE, herbFlavor)) {
-            isAllowedToCloseTab = !currentTab.isAllowedToReturnToExternalApp();
-        }
-
         // [true]: Reached the bottom of the back stack on a tab the user did not explicitly
         // create (i.e. it was created by an external app or opening a link in background, etc).
         // [false]: Reached the bottom of the back stack on a tab that the user explicitly
         // created (e.g. selecting "new tab" from menu).
         final int parentId = currentTab.getParentId();
         final boolean shouldCloseTab = type == TabLaunchType.FROM_LINK
-                || (type == TabLaunchType.FROM_EXTERNAL_APP && isAllowedToCloseTab)
+                || type == TabLaunchType.FROM_EXTERNAL_APP
                 || type == TabLaunchType.FROM_LONGPRESS_FOREGROUND
                 || type == TabLaunchType.FROM_LONGPRESS_BACKGROUND
                 || (type == TabLaunchType.FROM_RESTORE && parentId != Tab.INVALID_TAB_ID);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ItemChooserDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/ItemChooserDialog.java
index d93e107..ec0bfdf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ItemChooserDialog.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ItemChooserDialog.java
@@ -202,6 +202,17 @@
         public void remove(ItemChooserRow item) {
             ItemChooserRow oldItem = mKeyToItemMap.remove(item.mKey);
             if (oldItem == null) return;
+            int oldItemPosition = getPosition(oldItem);
+            // If the removed item is the item that is currently selected, deselect it
+            // and disable the confirm button. Otherwise if the removed item is before
+            // the currently selected item, the currently selected item's index needs
+            // to be adjusted by one.
+            if (oldItemPosition == mSelectedItem) {
+                mSelectedItem = ListView.INVALID_POSITION;
+                mConfirmButton.setEnabled(false);
+            } else if (oldItemPosition < mSelectedItem) {
+                --mSelectedItem;
+            }
             removeFromDescriptionsMap(oldItem.mDescription);
             super.remove(oldItem);
         }
@@ -221,6 +232,7 @@
          * selected.
          */
         public String getSelectedItemKey() {
+            if (mSelectedItem == ListView.INVALID_POSITION) return "";
             ItemChooserRow row = getItem(mSelectedItem);
             if (row == null) return "";
             return row.mKey;
@@ -241,7 +253,7 @@
         }
 
         /**
-         * Sets whether the itam is enabled. Disabled items are grayed out.
+         * Sets whether the item is enabled. Disabled items are grayed out.
          * @param id The id of the item to affect.
          * @param enabled Whether the item should be enabled or not.
          */
@@ -251,6 +263,14 @@
             } else {
                 mDisabledEntries.add(id);
             }
+
+            if (mSelectedItem != ListView.INVALID_POSITION) {
+                ItemChooserRow selectedRow = getItem(mSelectedItem);
+                if (id.equals(selectedRow.mKey)) {
+                    mConfirmButton.setEnabled(enabled);
+                }
+            }
+
             notifyDataSetChanged();
         }
 
@@ -399,6 +419,7 @@
         });
 
         mItemAdapter = new ItemAdapter(mActivity, R.layout.item_chooser_dialog_row);
+        mItemAdapter.setNotifyOnChange(true);
         mListView.setAdapter(mItemAdapter);
         mListView.setEmptyView(mEmptyMessage);
         mListView.setOnItemClickListener(mItemAdapter);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java
index 1382e512..655fa82 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java
@@ -12,7 +12,6 @@
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
-import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.ShortcutHelper;
 import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.bookmarks.BookmarkBridge;
@@ -110,7 +109,7 @@
 
                 MenuItem offlineMenuItem = menu.findItem(R.id.offline_page_id);
                 if (offlineMenuItem != null) {
-                    if (ChromeFeatureList.isEnabled("DownloadsUi")) {
+                    if (DownloadUtils.isDownloadHomeEnabled()) {
                         offlineMenuItem.setEnabled(
                                 DownloadUtils.isAllowedToDownloadPage(currentTab));
 
@@ -128,7 +127,7 @@
             }
 
             menu.findItem(R.id.downloads_menu_id)
-                    .setVisible(ChromeFeatureList.isEnabled("DownloadsUi"));
+                    .setVisible(DownloadUtils.isDownloadHomeEnabled());
 
             menu.findItem(R.id.update_menu_id).setVisible(
                     UpdateMenuItemHelper.getInstance().shouldShowMenuItem(mActivity));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java
index 36e994b..d202dbf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java
@@ -6,7 +6,6 @@
 
 import android.app.Activity;
 import android.content.Context;
-import android.view.View;
 import android.view.View.MeasureSpec;
 
 import org.chromium.base.ActivityState;
@@ -28,7 +27,6 @@
 import org.chromium.chrome.browser.compositor.scene_layer.SceneOverlayLayer;
 import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.content.browser.ContentVideoViewEmbedder;
 import org.chromium.content.browser.ContentViewClient;
 import org.chromium.content.browser.ContentViewCore;
 import org.chromium.content_public.common.TopControlsState;
@@ -405,27 +403,7 @@
                             MeasureSpec.EXACTLY);
                 }
             }
-
-            @Override
-            public ContentVideoViewEmbedder getContentVideoViewEmbedder() {
-                // TODO(mdjones): Possibly enable fullscreen video in overlay panels rather than
-                // passing an empty implementation.
-                return new ContentVideoViewEmbedder() {
-                    @Override
-                    public void enterFullscreenVideo(View view, boolean isVideoLoaded) {}
-
-                    @Override
-                    public void fullscreenVideoLoaded() {}
-
-                    @Override
-                    public void exitFullscreenVideo() {}
-
-                    @Override
-                    public void setSystemUiVisibility(boolean enterFullscreen) {}
-                };
-            }
         });
-
         return content;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java
index 63eb32c..a10f056 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java
@@ -11,6 +11,7 @@
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.WebContentsFactory;
 import org.chromium.chrome.browser.contextualsearch.ContextualSearchManager;
 import org.chromium.chrome.browser.externalnav.ExternalNavigationHandler;
@@ -18,6 +19,7 @@
 import org.chromium.components.navigation_interception.InterceptNavigationDelegate;
 import org.chromium.components.navigation_interception.NavigationParams;
 import org.chromium.components.web_contents_delegate_android.WebContentsDelegateAndroid;
+import org.chromium.content.browser.ContentVideoViewEmbedder;
 import org.chromium.content.browser.ContentView;
 import org.chromium.content.browser.ContentViewClient;
 import org.chromium.content.browser.ContentViewCore;
@@ -160,6 +162,11 @@
             public boolean isFullscreenForTabOrPending() {
                 return mIsFullscreen;
             }
+
+            @Override
+            public ContentVideoViewEmbedder getContentVideoViewEmbedder() {
+                return null;  // Have a no-op embedder be used.
+            }
         };
     }
 
@@ -204,7 +211,7 @@
      * @return The newly created ContentViewCore.
      */
     protected ContentViewCore createContentViewCore(ChromeActivity activity) {
-        return new ContentViewCore(activity);
+        return new ContentViewCore(activity, ChromeVersionInfo.getProductVersion());
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchCaptionControl.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchCaptionControl.java
index 91c62fc..6ebc32f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchCaptionControl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchCaptionControl.java
@@ -181,6 +181,8 @@
     // ============================================================================================
 
     private void animateTransitionIn() {
+        if (mAnimationPercentage == 0f) return;
+
         long duration = (long)
                 (OverlayPanelAnimation.MAXIMUM_ANIMATION_DURATION_MS * mAnimationPercentage);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java
index 7048c9b..a111ea5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java
@@ -460,6 +460,8 @@
         if (getPanelState() == PanelState.CLOSED || getPanelState() == PanelState.PEEKED) {
             mHasContentBeenTouched = false;
         }
+
+        if (getPanelState() == PanelState.CLOSED) mPanelMetrics.onPanelTriggered();
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelMetrics.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelMetrics.java
index 6991ad2..68e268e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelMetrics.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelMetrics.java
@@ -10,6 +10,8 @@
 import org.chromium.chrome.browser.contextualsearch.ContextualSearchHeuristics;
 import org.chromium.chrome.browser.contextualsearch.ContextualSearchUma;
 
+import java.util.Locale;
+
 /**
  * This class is responsible for all the logging related to Contextual Search.
  */
@@ -33,8 +35,13 @@
     private boolean mWasPanelOpenedBeyondPeek;
     private boolean mWasSelectionPartOfUrl;
     private boolean mWasContextualCardsDataShown;
+    private boolean mWasSelectionAllCaps;
+    private boolean mDidSelectionStartWithCapital;
     // Whether any Tap suppression heuristic was satisfied when the panel was shown.
     private boolean mWasAnyHeuristicSatisfiedOnPanelShow;
+    // Time when the panel was triggered (not reset by a chained search).
+    // Panel transitions are animated so mPanelTriggerTimeNs will be less than mFirstPeekTimeNs.
+    private long mPanelTriggerTimeNs;
     // Time when the panel peeks into view (not reset by a chained search).
     // Used to log total time the panel is showing (not closed).
     private long mFirstPeekTimeNs;
@@ -79,6 +86,14 @@
         // so a local copy is created before the reset.
         boolean isSearchPanelFullyPreloaded = mIsSearchPanelFullyPreloaded;
 
+        if (toState == PanelState.CLOSED && mPanelTriggerTimeNs != 0
+                && reason == StateChangeReason.BASE_PAGE_SCROLL) {
+            long durationMs =
+                    (System.nanoTime() - mPanelTriggerTimeNs) / MILLISECONDS_TO_NANOSECONDS;
+            ContextualSearchUma.logDurationBetweenTriggerAndScroll(
+                    durationMs, mWasSearchContentViewSeen);
+        }
+
         if (isEndingSearch) {
             long durationMs = (System.nanoTime() - mFirstPeekTimeNs) / MILLISECONDS_TO_NANOSECONDS;
             ContextualSearchUma.logPanelViewDurationAction(durationMs);
@@ -102,6 +117,12 @@
                 ContextualSearchUma.logContextualCardsResultsSeen(mWasSearchContentViewSeen);
             }
 
+            if (mWasSelectionAllCaps && mWasActivatedByTap) {
+                ContextualSearchUma.logAllCapsResultsSeen(mWasSearchContentViewSeen);
+            } else if (mDidSelectionStartWithCapital && mWasActivatedByTap) {
+                ContextualSearchUma.logStartedWithCapitalResultsSeen(mWasSearchContentViewSeen);
+            }
+
             ContextualSearchUma.logBlacklistSeen(mBlacklistReason, mWasSearchContentViewSeen);
 
             ContextualSearchUma.logIconSpriteAnimated(mWasIconSpriteAnimated,
@@ -114,9 +135,9 @@
             }
 
             if (mWasActivatedByTap) {
-                // TODO(twellington): consider blacklist in suppression heuristic satisfaction?
                 boolean wasAnySuppressionHeuristicSatisfied =
-                        mWasAnyHeuristicSatisfiedOnPanelShow || mWasSelectionPartOfUrl;
+                        mWasAnyHeuristicSatisfiedOnPanelShow || mWasSelectionPartOfUrl
+                        || mWasSelectionAllCaps;
                 ContextualSearchUma.logAnyTapSuppressionHeuristicSatisfied(
                         mWasSearchContentViewSeen, wasAnySuppressionHeuristicSatisfied);
             }
@@ -202,6 +223,9 @@
             mIsSerpNavigation = false;
             mWasSelectionPartOfUrl = false;
             mWasContextualCardsDataShown = false;
+            mWasSelectionAllCaps = false;
+            mDidSelectionStartWithCapital = false;
+            mPanelTriggerTimeNs = 0;
         }
     }
 
@@ -259,6 +283,27 @@
     }
 
     /**
+     * Should be called when the panel first starts showing.
+     */
+    public void onPanelTriggered() {
+        mPanelTriggerTimeNs = System.nanoTime();
+    }
+
+    /**
+     * @param selection The text that is selected when a selection is established.
+     */
+    public void onSelectionEstablished(String selection) {
+        // In some locales, there is no concept of an upper or lower case letter. Account for this
+        // by checking that the selected text is not equalivalet to selection#toLowerCase().
+        mWasSelectionAllCaps = selection.equals(selection.toUpperCase(Locale.getDefault()))
+                && !selection.equals(selection.toLowerCase(Locale.getDefault()));
+        String firstChar = String.valueOf(selection.charAt(0));
+        mDidSelectionStartWithCapital = firstChar.equals(
+                firstChar.toUpperCase(Locale.getDefault()))
+                && !firstChar.equals(firstChar.toLowerCase(Locale.getDefault()));
+    }
+
+    /**
      * Called to record the time when a search request started, for resolve and prefetch timing.
      */
     public void onSearchRequestStarted() {
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 a7c89ff7..7cf16f1 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
@@ -1285,6 +1285,7 @@
             ContextualSearchUma.logSelectionIsValid(selectionValid);
             if (selectionValid) {
                 mSearchPanel.updateBasePageSelectionYPx(y);
+                mSearchPanel.getPanelMetrics().onSelectionEstablished(selection);
                 showContextualSearch(stateChangeReason);
             } else {
                 hideContextualSearch(stateChangeReason);
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 8a21768e..cadaf08c 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
@@ -906,6 +906,28 @@
     }
 
     /**
+     * Logs whether results were seen when the selected text consisted of all capital letters.
+     * @param wasSearchContentViewSeen If the panel was opened.
+     */
+    public static void logAllCapsResultsSeen(boolean wasSearchContentViewSeen) {
+        RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchAllCapsResultsSeen",
+                wasSearchContentViewSeen ? RESULTS_SEEN : RESULTS_NOT_SEEN,
+                RESULTS_SEEN_BOUNDARY);
+    }
+
+    /**
+     * Logs whether results were seen when the selected text started with a capital letter but was
+     * not all capital letters.
+     * @param wasSearchContentViewSeen If the panel was opened.
+     */
+    public static void logStartedWithCapitalResultsSeen(boolean wasSearchContentViewSeen) {
+        RecordHistogram.recordEnumeratedHistogram(
+                "Search.ContextualSearchStartedWithCapitalResultsSeen",
+                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
@@ -1016,6 +1038,24 @@
     }
 
     /**
+     * Logs the duration between the panel being triggered due to a tap or long-press and the
+     * panel being dismissed due to a scroll.
+     * @param durationSincePanelTriggerMs The amount of time between the panel getting triggered and
+     *                                    the panel being dismissed due to a scroll.
+     * @param wasSearchContentViewSeen If the panel was opened.
+     */
+    public static void logDurationBetweenTriggerAndScroll(
+            long durationSincePanelTriggerMs, boolean wasSearchContentViewSeen) {
+        String histogram = wasSearchContentViewSeen
+                ? "Search.ContextualSearchDurationBetweenTriggerAndScrollSeen"
+                : "Search.ContextualSearchDurationBetweenTriggerAndScrollNotSeen";
+        if (durationSincePanelTriggerMs < 2000) {
+            RecordHistogram.recordCustomCountHistogram(
+                    histogram, (int) durationSincePanelTriggerMs, 1, 2000, 200);
+        }
+    }
+
+    /**
      * Logs whether a Quick Answer caption was activated, and whether it was an answer (as opposed
      * to just being informative), and whether the panel was opened anyway.
      * Logged only for Tap events.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
index 2c02d1a..c218120 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -35,8 +35,6 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.ChromeFeatureList;
-import org.chromium.chrome.browser.ChromeSwitches;
-import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.IntentHandler.ExternalAppId;
 import org.chromium.chrome.browser.KeyboardShortcuts;
@@ -62,7 +60,6 @@
 import org.chromium.chrome.browser.tabmodel.TabPersistencePolicy;
 import org.chromium.chrome.browser.toolbar.ToolbarControlContainer;
 import org.chromium.chrome.browser.util.ColorUtils;
-import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.browser.util.UrlUtilities;
 import org.chromium.chrome.browser.widget.findinpage.FindToolbarManager;
 import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils;
@@ -76,9 +73,6 @@
  * The activity for custom tabs. It will be launched on top of a client's task.
  */
 public class CustomTabActivity extends ChromeActivity {
-    public static final int RESULT_BACK_PRESSED = 1;
-    public static final int RESULT_STOPPED = 2;
-    public static final int RESULT_CLOSED = 3;
 
     private static final String TAG = "CustomTabActivity";
     private static final String LAST_URL_PREF = "pref_last_custom_tab_url";
@@ -246,15 +240,6 @@
 
     @Override
     public void onStop() {
-        // This happens before super.onStop() to maximize chances of getting the Tab while it's
-        // alive.
-        // TODO(dfalcantara): Once this is addressed on M50, consider transferring the Tab directly
-        //                    via Tab reparenting.
-        if (mIntentDataProvider.isOpenedByChrome() && isHerbResultNeeded()) {
-            createHerbResultIntent(RESULT_STOPPED);
-            finish();
-        }
-
         super.onStop();
         CustomTabsConnection.getInstance(getApplication())
                 .dontKeepAliveForSession(mIntentDataProvider.getSession());
@@ -372,9 +357,6 @@
                 new OnClickListener() {
                     @Override
                     public void onClick(View v) {
-                        if (mIntentDataProvider.isOpenedByChrome() && isHerbResultNeeded()) {
-                            createHerbResultIntent(RESULT_CLOSED);
-                        }
                         RecordUserAction.record("CustomTabs.CloseButtonClicked");
                         finishAndClose();
                     }
@@ -677,9 +659,6 @@
             if (getCurrentTabModel().getCount() > 1) {
                 getCurrentTabModel().closeTab(getActivityTab(), false, false, false);
             } else {
-                if (mIntentDataProvider.isOpenedByChrome() && isHerbResultNeeded()) {
-                    createHerbResultIntent(RESULT_BACK_PRESSED);
-                }
                 finishAndClose();
             }
         }
@@ -861,44 +840,6 @@
     }
 
     /**
-     * @return Whether {@link ChromeTabbedActivity} is waiting for a result from this Activity.
-     */
-    private boolean isHerbResultNeeded() {
-        if (!TextUtils.equals(FeatureUtilities.getHerbFlavor(), ChromeSwitches.HERB_FLAVOR_DILL)) {
-            return false;
-        }
-
-        String callingActivity =
-                getCallingActivity() == null ? null : getCallingActivity().getClassName();
-        return TextUtils.equals(callingActivity, ChromeTabbedActivity.class.getName());
-    }
-
-    /**
-     * Lets the original Activity know how this {@link CustomTabActivity} was finished.
-     */
-    private void createHerbResultIntent(int result) {
-        if (getActivityTab() == null) return;
-        Intent resultIntent = new Intent();
-
-        switch (result) {
-            case RESULT_STOPPED:
-                // Send the URL to the browser.  Should pass the Tab in the future.
-                resultIntent.setAction(Intent.ACTION_VIEW);
-                resultIntent.setData(Uri.parse(getActivityTab().getUrl()));
-                break;
-
-            case RESULT_BACK_PRESSED:
-            case RESULT_CLOSED:
-                break;
-
-            default:
-                assert false;
-        }
-
-        setResult(result, resultIntent);
-    }
-
-    /**
      * @return The URL that should be used from this intent. If it is a WebLite url, it may be
      *         overridden if the Data Reduction Proxy is using Lo-Fi previews.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
index 046bdfc..5ad0f71 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
@@ -333,21 +333,9 @@
         } else if (TextUtils.equals(flavor, ChromeSwitches.HERB_FLAVOR_ELDERBERRY)) {
             return IntentUtils.safeGetBooleanExtra(getIntent(),
                     ChromeLauncherActivity.EXTRA_IS_ALLOWED_TO_RETURN_TO_PARENT, true);
-        } else if (TextUtils.equals(flavor, ChromeSwitches.HERB_FLAVOR_ANISE)
-                || TextUtils.equals(flavor, ChromeSwitches.HERB_FLAVOR_BASIL)
-                || TextUtils.equals(flavor, ChromeSwitches.HERB_FLAVOR_DILL)) {
-            // Only Intents without NEW_TASK and NEW_DOCUMENT will trigger a Custom Tab.
-            boolean isSameTask = (getIntent().getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) == 0;
-            boolean isSameDocument =
-                    (getIntent().getFlags() & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) == 0;
-            Log.d(TAG, "Herb Intent proprties -- SAME TASK: "
-                    + isSameTask + ", SAME DOCUMENT: " + isSameDocument);
-            return isSameTask && isSameDocument;
-        } else if (TextUtils.equals(flavor, ChromeSwitches.HERB_FLAVOR_CHIVE)) {
-            // Send all View Intents to the main browser.
-            return false;
         } else {
-            assert false;
+            // Legacy Herb Flavors might hit this path before the caching logic corrects it, so
+            // treat this as disabled.
             return false;
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
index 99a7079a..d51ad82 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
@@ -4,7 +4,6 @@
 
 package org.chromium.chrome.browser.download;
 
-import android.app.Activity;
 import android.app.DownloadManager;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
@@ -22,8 +21,6 @@
 import android.util.LongSparseArray;
 import android.util.Pair;
 
-import org.chromium.base.ActivityState;
-import org.chromium.base.ApplicationStatus;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.ObserverList;
@@ -33,7 +30,6 @@
 import org.chromium.base.annotations.SuppressFBWarnings;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.download.ui.BackendProvider;
 import org.chromium.chrome.browser.download.ui.DownloadHistoryAdapter;
 import org.chromium.chrome.browser.externalnav.ExternalNavigationDelegateImpl;
@@ -1063,17 +1059,7 @@
      * @param context Application context
      */
     protected static void openDownloadsPage(Context context) {
-        // Try to open Download Home.
-        Activity lastActivity = ApplicationStatus.getLastTrackedFocusedActivity();
-        if (lastActivity instanceof ChromeActivity) {
-            int state = ApplicationStatus.getStateForActivity(lastActivity);
-            if (state >= ActivityState.CREATED && state <= ActivityState.RESUMED) {
-                ChromeActivity chromeActivity = (ChromeActivity) lastActivity;
-                DownloadUtils.showDownloadManager(
-                        lastActivity, chromeActivity.getActivityTab());
-                return;
-            }
-        }
+        if (DownloadUtils.showDownloadManager(null, null)) return;
 
         // Open the Android Download Manager.
         Intent pageView = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
index 2747451..088d003e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
@@ -7,17 +7,21 @@
 import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
+import android.content.SharedPreferences;
 import android.net.Uri;
 import android.os.StrictMode;
+import android.support.annotation.Nullable;
 import android.text.TextUtils;
 
+import org.chromium.base.ApplicationStatus;
 import org.chromium.base.ContentUriUtils;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeTabbedActivity;
+import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.download.ui.BackendProvider;
@@ -50,27 +54,72 @@
     private static final String EXTRA_IS_OFF_THE_RECORD =
             "org.chromium.chrome.browser.download.IS_OFF_THE_RECORD";
 
+    private static final String PREF_IS_DOWNLOAD_HOME_ENABLED =
+            "org.chromium.chrome.browser.download.IS_DOWNLOAD_HOME_ENABLED";
+
+    /**
+     * @return Whether or not the Download Home is enabled.
+     */
+    public static boolean isDownloadHomeEnabled() {
+        SharedPreferences preferences = ContextUtils.getAppSharedPreferences();
+        return preferences.getBoolean(PREF_IS_DOWNLOAD_HOME_ENABLED, false);
+    }
+
+    /**
+     * Caches the native flag that enables the Download Home in SharedPreferences.
+     * This is necessary because the DownloadActivity can be opened before native has been loaded.
+     */
+    public static void cacheIsDownloadHomeEnabled() {
+        boolean isEnabled = ChromeFeatureList.isEnabled("DownloadsUi");
+        SharedPreferences preferences = ContextUtils.getAppSharedPreferences();
+        preferences.edit().putBoolean(PREF_IS_DOWNLOAD_HOME_ENABLED, isEnabled).apply();
+    }
+
     /**
      * Displays the download manager UI. Note the UI is different on tablets and on phones.
+     * @return Whether the UI was shown.
      */
-    public static void showDownloadManager(Activity activity, Tab tab) {
-        if (DeviceFormFactor.isTablet(activity) && activity instanceof ChromeTabbedActivity) {
-            // Download Home shows up inside a tab in the browser.
+    public static boolean showDownloadManager(@Nullable Activity activity, @Nullable Tab tab) {
+        if (!isDownloadHomeEnabled()) return false;
+
+        // Figure out what tab was last being viewed by the user.
+        if (activity == null) activity = ApplicationStatus.getLastTrackedFocusedActivity();
+        if (tab == null && activity instanceof ChromeActivity) {
+            tab = ((ChromeActivity) activity).getActivityTab();
+        }
+
+        Context appContext = ContextUtils.getApplicationContext();
+        if (DeviceFormFactor.isTablet(appContext)) {
+            // Download Home shows up as a tab on tablets.
             LoadUrlParams params = new LoadUrlParams(UrlConstants.DOWNLOADS_URL);
             if (tab == null || !tab.isInitialized()) {
+                // Open a new tab, which pops Chrome into the foreground.
                 TabDelegate delegate = new TabDelegate(false);
                 delegate.createNewTab(params, TabLaunchType.FROM_CHROME_UI, null);
             } else {
+                // Download Home shows up inside an existing tab.  Manually foreground Chrome.
                 tab.loadUrl(params);
+                Intent intent = Tab.createBringTabToFrontIntent(tab.getId());
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                IntentUtils.safeStartActivity(appContext, intent);
             }
         } else {
-            // Download Home sits on top as a new Activity.
+            // Download Home shows up as a new Activity on phones.
             Intent intent = new Intent();
-            intent.setClass(activity, DownloadActivity.class);
-            intent.putExtra(IntentHandler.EXTRA_PARENT_COMPONENT, activity.getComponentName());
+            intent.setClass(appContext, DownloadActivity.class);
             if (tab != null) intent.putExtra(EXTRA_IS_OFF_THE_RECORD, tab.isIncognito());
-            activity.startActivity(intent);
+            if (activity == null) {
+                // Stands alone in its own task.
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                appContext.startActivity(intent);
+            } else {
+                // Sits on top of another Activity.
+                intent.putExtra(IntentHandler.EXTRA_PARENT_COMPONENT, activity.getComponentName());
+                activity.startActivity(intent);
+            }
         }
+
+        return true;
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryItemViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryItemViewHolder.java
index 0352799..4be5689 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryItemViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryItemViewHolder.java
@@ -66,8 +66,9 @@
 
         // Asynchronously grab a thumbnail for the file if it might have one.
         int fileType = item.getFilterType();
+        Bitmap thumbnail = null;
         if (fileType == DownloadFilter.FILTER_IMAGE) {
-            thumbnailProvider.getThumbnail(this);
+            thumbnail = thumbnailProvider.getThumbnail(this);
         } else {
             // TODO(dfalcantara): Get thumbnails for audio and video files when possible.
         }
@@ -94,7 +95,7 @@
         }
 
         // Initialize the DownloadItemView.
-        mItemView.initialize(item, iconResource);
+        mItemView.initialize(item, iconResource, thumbnail);
     }
 
     @VisibleForTesting
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java
index e2b1766..337a7e1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java
@@ -14,6 +14,8 @@
 import org.chromium.chrome.browser.widget.TintedImageView;
 import org.chromium.chrome.browser.widget.selection.SelectableItemView;
 
+import javax.annotation.Nullable;
+
 /**
  * The view for a downloaded item displayed in the Downloads list.
  */
@@ -50,13 +52,15 @@
      *
      * @param item      The item represented by this DownloadItemView.
      * @param iconResId The drawable resource ID to use for the icon ImageView.
+     * @param thumbnail The Bitmap to use for the thumbnail or null.
      */
-    public void initialize(DownloadHistoryItemWrapper item, int iconResId) {
+    public void initialize(DownloadHistoryItemWrapper item, int iconResId,
+            @Nullable Bitmap thumbnail) {
         mItem = item;
         setItem(item);
 
         mIconResId = iconResId;
-        mThumbnailBitmap = null;
+        mThumbnailBitmap = thumbnail;
         updateIconView();
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/ThumbnailProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/ThumbnailProvider.java
index 3ef3b466..032215e5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/ThumbnailProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/ThumbnailProvider.java
@@ -21,10 +21,11 @@
     void destroy();
 
     /**
-     * Asynchronously returns a thumbnail via {@link ThumbnailRequest#onThumbnailRetrieved}.
+     * Synchronously returns a thumbnail if it is cached. Otherwise, asynchronously returns a
+     * thumbnail via {@link ThumbnailRequest#onThumbnailRetrieved}.
      * @param request Parameters that describe the thumbnail being retrieved.
      */
-    void getThumbnail(ThumbnailRequest request);
+    Bitmap getThumbnail(ThumbnailRequest request);
 
     /** Removes a particular request from the pending queue. */
     void cancelRetrieval(ThumbnailRequest request);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/ThumbnailProviderImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/ThumbnailProviderImpl.java
index c32b4c02..73366c0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/ThumbnailProviderImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/ThumbnailProviderImpl.java
@@ -67,12 +67,16 @@
     }
 
     @Override
-    public void getThumbnail(ThumbnailRequest request) {
+    public Bitmap getThumbnail(ThumbnailRequest request) {
         String filePath = request.getFilePath();
-        if (TextUtils.isEmpty(filePath)) return;
+        if (TextUtils.isEmpty(filePath)) return null;
+
+        Bitmap cachedBitmap = getBitmapCache().get(filePath);
+        if (cachedBitmap != null) return cachedBitmap;
 
         mRequestQueue.offer(request);
         processQueue();
+        return null;
     }
 
     /** Removes a particular file from the pending queue. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/ActivityStopMetrics.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/ActivityStopMetrics.java
index cb6cdff..2c1b266b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/ActivityStopMetrics.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/ActivityStopMetrics.java
@@ -21,9 +21,6 @@
     @IntDef({
         STOP_REASON_UNKNOWN,
         STOP_REASON_BACK_BUTTON,
-        STOP_REASON_RETURN_BUTTON,
-        STOP_REASON_CUSTOM_TAB_STARTED,
-        STOP_REASON_CUSTOM_TAB_STOPPED,
         STOP_REASON_OTHER_CHROME_ACTIVITY_IN_FOREGROUND,
         STOP_REASON_COUNT
     })
@@ -35,14 +32,15 @@
     /** Activity stopped after the user hit the back button. */
     public static final int STOP_REASON_BACK_BUTTON = 1;
 
-    /** Activity stopped after the user hit the close/return UI button. */
-    public static final int STOP_REASON_RETURN_BUTTON = 2;
+    // Obsolete -- Activity stopped after the user hit the close/return UI button.
+    // public static final int STOP_REASON_RETURN_BUTTON = 2;
 
-    /** Activity stopped because it launched a {@link CustomTabActivity} on top of itself. */
-    public static final int STOP_REASON_CUSTOM_TAB_STARTED = 3;
+    // Obsolete --  Activity stopped because it launched a {@link CustomTabActivity} on top of
+    //              itself.
+    // public static final int STOP_REASON_CUSTOM_TAB_STARTED = 3;
 
-    /** Activity stopped because its child {@link CustomTabActivity} stopped itself. */
-    public static final int STOP_REASON_CUSTOM_TAB_STOPPED = 4;
+    // Obsolete -- Activity stopped because its child {@link CustomTabActivity} stopped itself.
+    // public static final int STOP_REASON_CUSTOM_TAB_STOPPED = 4;
 
     /** Activity stopped because another of Chrome Activities came into focus. */
     public static final int STOP_REASON_OTHER_CHROME_ACTIVITY_IN_FOREGROUND = 5;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
index 264d2e8..2b130a55 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
@@ -457,7 +457,7 @@
         @Override
         public void navigateToDownloadManager() {
             if (mIsDestroyed) return;
-            assert ChromeFeatureList.isEnabled("DownloadsUi");
+            assert DownloadUtils.isDownloadHomeEnabled();
             RecordUserAction.record("MobileNTPSwitchToDownloadManager");
             DownloadUtils.showDownloadManager(mActivity, mTab);
         }
@@ -644,6 +644,11 @@
         }
 
         @Override
+        public void closeContextMenu() {
+            mActivity.closeContextMenu();
+        }
+
+        @Override
         public SuggestionsSource getSuggestionsSource() {
             return mSnippetsBridge;
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
index 1a1ac8f7e..8a382e39 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
@@ -18,7 +18,9 @@
 import android.support.annotation.Nullable;
 import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
 import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
+import android.support.v7.widget.DefaultItemAnimator;
 import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.ViewHolder;
 import android.support.v7.widget.helper.ItemTouchHelper;
 import android.text.Editable;
 import android.text.TextUtils;
@@ -48,7 +50,6 @@
 import org.chromium.chrome.browser.ntp.MostVisitedItem.MostVisitedItemManager;
 import org.chromium.chrome.browser.ntp.NewTabPage.OnSearchBoxScrollListener;
 import org.chromium.chrome.browser.ntp.cards.NewTabPageAdapter;
-import org.chromium.chrome.browser.ntp.cards.NewTabPageItem;
 import org.chromium.chrome.browser.ntp.cards.NewTabPageRecyclerView;
 import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
 import org.chromium.chrome.browser.ntp.snippets.SnippetsConfig;
@@ -275,6 +276,11 @@
         void removeContextMenuCloseCallback(Callback<Menu> callback);
 
         /**
+         * Makes the {@link Activity} close any open context menu.
+         */
+        void closeContextMenu();
+
+        /**
          * Handles clicks on the "learn more" link in the footer.
          */
         void onLearnMoreClicked();
@@ -325,6 +331,17 @@
             // made for the ScrollView UI.
             ViewGroup.LayoutParams params = mNewTabPageLayout.getLayoutParams();
             params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+
+            mRecyclerView.setItemAnimator(new DefaultItemAnimator() {
+                @Override
+                public void onAnimationFinished(ViewHolder viewHolder) {
+                    super.onAnimationFinished(viewHolder);
+                    // When removing sections, because the animations are all translations, the
+                    // scroll events don't fire and we can get in the situation where the toolbar
+                    // buttons disappear.
+                    updateSearchBoxOnScroll();
+                }
+            });
         } else {
             stub.setLayoutResource(R.layout.new_tab_page_scroll_view);
             mScrollView = (NewTabPageScrollView) stub.inflate();
@@ -357,8 +374,7 @@
 
         // Set up snippets
         if (mUseCardsUi) {
-            mNewTabPageAdapter =
-                    new NewTabPageAdapter(mManager, mNewTabPageLayout, mUiConfig);
+            mNewTabPageAdapter = NewTabPageAdapter.create(mManager, mNewTabPageLayout, mUiConfig);
             mRecyclerView.setAdapter(mNewTabPageAdapter);
             mRecyclerView.scrollToPosition(scrollPosition);
 
@@ -513,21 +529,6 @@
     }
 
     /**
-     * Get the number of listed items (visible or not) for the given type.
-     * @param newTabPageItemViewType the item type to count.
-     */
-    public int getViewCountMatchingViewType(@NewTabPageItem.ViewType int newTabPageItemViewType) {
-        int viewCount = 0;
-        int adapterSize = mNewTabPageAdapter.getItemCount();
-        for (int i = 0; i < adapterSize; i++) {
-            if (mNewTabPageAdapter.getItemViewType(i) == newTabPageItemViewType) {
-                viewCount++;
-            }
-        }
-        return viewCount;
-    }
-
-    /**
      * Sets up scrolling when snippets are enabled. It adds scroll listeners and touch listeners to
      * the RecyclerView.
      */
@@ -881,6 +882,9 @@
         int oldHeight = oldBottom - oldTop;
         int newHeight = bottom - top;
 
+        // Close the Context Menu as it may have moved (https://crbug.com/642688).
+        mManager.closeContextMenu();
+
         if (oldHeight == newHeight && !mTileCountChanged) return;
         mTileCountChanged = false;
 
@@ -1192,6 +1196,7 @@
      * @return The adapter position the user has scrolled to.
      */
     public int getScrollPosition() {
-        return mRecyclerView.getScrollPosition();
+        if (mUseCardsUi) return mRecyclerView.getScrollPosition();
+        return RecyclerView.NO_POSITION;
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ItemGroup.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ItemGroup.java
index db393a7..5193a69 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ItemGroup.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ItemGroup.java
@@ -14,4 +14,19 @@
      * @return A list of items contained in this group. The list should not be modified.
      */
     List<NewTabPageItem> getItems();
+
+    /**
+     * Defines the actions an object can be notified about when there are changes inside of
+     * an {@link ItemGroup}.
+     */
+    interface Observer {
+        /** Non specific notification about changes inside of the group. */
+        void notifyGroupChanged(ItemGroup group, int itemCountBefore, int itemCountAfter);
+
+        /** Notification about an item having been added to the group. */
+        void notifyItemInserted(ItemGroup group, int itemPosition);
+
+        /** Notification about an item having been removed from the group. */
+        void notifyItemRemoved(ItemGroup group, int itemPosition);
+    }
 }
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 3701ed4..a9db205 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
@@ -42,7 +42,7 @@
  * elements will be the cards shown to the user
  */
 public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder>
-        implements SuggestionsSource.Observer {
+        implements SuggestionsSource.Observer, ItemGroup.Observer {
     private static final String TAG = "Ntp";
 
     private final NewTabPageManager mNewTabPageManager;
@@ -127,19 +127,38 @@
     }
 
     /**
-     * Constructor to create the manager for all the cards to display on the NTP
+     * Creates the adapter that will manage all the cards to display on the NTP.
      *
      * @param manager the NewTabPageManager to use to interact with the rest of the system.
      * @param aboveTheFoldView the layout encapsulating all the above-the-fold elements
      *                         (logo, search box, most visited tiles)
-     * @param suggestionsSource the bridge to interact with the content suggestions service.
      * @param uiConfig the NTP UI configuration, to be passed to created views.
      */
-    public NewTabPageAdapter(NewTabPageManager manager, View aboveTheFoldView, UiConfig uiConfig) {
+    public static NewTabPageAdapter create(
+            NewTabPageManager manager, View aboveTheFoldView, UiConfig uiConfig) {
+        NewTabPageAdapter adapter = new NewTabPageAdapter(manager, aboveTheFoldView, uiConfig);
+        adapter.initializeSections();
+        return adapter;
+    }
+
+    /**
+     * Constructor for {@link NewTabPageAdapter}. The object is not completely ready to be used
+     * until {@link #initializeSections()} is called. Usage reserved for testing, prefer calling
+     * {@link NewTabPageAdapter#create(NewTabPageManager, View, UiConfig)} in production code.
+     */
+    @VisibleForTesting
+    NewTabPageAdapter(NewTabPageManager manager, View aboveTheFoldView, UiConfig uiConfig) {
         mNewTabPageManager = manager;
         mAboveTheFoldView = aboveTheFoldView;
         mUiConfig = uiConfig;
+    }
 
+    /**
+     * Initialises the sections to be handled by this adapter. Events about categories for which
+     * a section has not been registered at this point will be ignored.
+     */
+    @VisibleForTesting
+    void initializeSections() {
         SuggestionsSource suggestionsSource = mNewTabPageManager.getSuggestionsSource();
 
         int[] categories = suggestionsSource.getCategories();
@@ -203,7 +222,6 @@
         if (suggestions.isEmpty()) return;
 
         setSuggestions(category, suggestions, status);
-        updateGroups();
 
         NewTabPageUma.recordSnippetAction(NewTabPageUma.SNIPPETS_ACTION_SHOWN);
     }
@@ -222,18 +240,16 @@
         if (status == CategoryStatus.CATEGORY_EXPLICITLY_DISABLED
                 || status == CategoryStatus.LOADING_ERROR) {
             // Need to remove the entire section from the UI immediately.
-            mSections.remove(category);
+            removeSection(mSections.get(category));
         } else {
             mSections.get(category).setStatus(status);
         }
-        updateGroups();
     }
 
     @Override
-    public void onSuggestionInvalidated(@CategoryInt int category, String suggestionId) {
+    public void onSuggestionInvalidated(@CategoryInt int category, String idWithinCategory) {
         if (!mSections.containsKey(category)) return;
-        mSections.get(category).removeSuggestionById(suggestionId);
-        updateGroups();
+        mSections.get(category).removeSuggestionById(idWithinCategory);
     }
 
     @Override
@@ -318,14 +334,11 @@
         return getGroupPositionOffset(mBottomSpacer);
     }
 
-    public int getSuggestionPosition(String suggestionId) {
+    public int getSuggestionPosition(SnippetArticle article) {
         List<NewTabPageItem> items = getItems();
         for (int i = 0; i < items.size(); i++) {
             NewTabPageItem item = items.get(i);
-            if (item instanceof SnippetArticle
-                    && ((SnippetArticle) item).mId.equals(suggestionId)) {
-                return i;
-            }
+            if (article.equals(item)) return i;
         }
         return RecyclerView.NO_POSITION;
     }
@@ -361,10 +374,60 @@
             mGroups.add(mBottomSpacer);
         }
 
-        // TODO(bauerb): Notify about a smaller range: https://crbug.com/627512
         notifyDataSetChanged();
     }
 
+    private void removeSection(SuggestionsSection section) {
+        mSections.remove(section.getCategory());
+        int startPos = getGroupPositionOffset(section);
+        mGroups.remove(section);
+        int removedItems = section.getItems().size();
+
+        notifyItemRangeRemoved(startPos, removedItems);
+
+        if (mSections.isEmpty()) {
+            mGroups.remove(mFooter);
+            mGroups.remove(mBottomSpacer);
+            notifyItemRangeRemoved(startPos + removedItems, 2);
+        } else {
+            notifyItemChanged(getItems().size() - 1); // Refresh the spacer too.
+        }
+    }
+
+    @Override
+    public void notifyGroupChanged(ItemGroup group, int itemCountBefore, int itemCountAfter) {
+        int startPos = getGroupPositionOffset(group);
+
+        if (group instanceof SuggestionsSection) {
+            // The header is stable in sections. Don't notify about it.
+            ++startPos;
+            --itemCountBefore;
+            --itemCountAfter;
+        }
+
+        if (itemCountBefore < itemCountAfter) {
+            notifyItemRangeChanged(startPos, itemCountBefore);
+            notifyItemRangeInserted(startPos + itemCountBefore, itemCountAfter - itemCountBefore);
+        } else {
+            notifyItemRangeChanged(startPos, itemCountAfter);
+            notifyItemRangeRemoved(startPos + itemCountAfter, itemCountBefore - itemCountAfter);
+        }
+
+        notifyItemChanged(getItems().size() - 1); // Refresh the spacer too.
+    }
+
+    @Override
+    public void notifyItemInserted(ItemGroup group, int itemPosition) {
+        notifyItemInserted(getGroupPositionOffset(group) + itemPosition);
+        notifyItemChanged(getItems().size() - 1); // Refresh the spacer too.
+    }
+
+    @Override
+    public void notifyItemRemoved(ItemGroup group, int itemPosition) {
+        notifyItemRemoved(getGroupPositionOffset(group) + itemPosition);
+        notifyItemChanged(getItems().size() - 1); // Refresh the spacer too.
+    }
+
     @Override
     public void onAttachedToRecyclerView(RecyclerView recyclerView) {
         super.onAttachedToRecyclerView(recyclerView);
@@ -395,9 +458,7 @@
 
     private void dismissSection(SuggestionsSection section) {
         mNewTabPageManager.getSuggestionsSource().dismissCategory(section.getCategory());
-
-        mSections.remove(section.getCategory());
-        updateGroups();
+        removeSection(section);
     }
 
     private void dismissSuggestion(int position) {
@@ -421,22 +482,11 @@
             }
         });
 
-        mRecyclerView.announceForAccessibility(mRecyclerView.getResources().getString(
-                R.string.ntp_accessibility_item_removed, suggestion.mTitle));
+        announceItemRemoved(suggestion.mTitle);
 
         suggestionsSource.dismissSuggestion(suggestion);
         SuggestionsSection section = (SuggestionsSection) getGroup(position);
         section.removeSuggestion(suggestion);
-
-        if (section.hasSuggestions()) {
-            // If one of many suggestions was dismissed, it's a simple item removal, which can be
-            // animated smoothly by the RecyclerView.
-            notifyItemRemoved(position);
-        } else {
-            // If the last suggestion was dismissed, multiple items will have changed, so mark
-            // everything as changed.
-            notifyDataSetChanged();
-        }
     }
 
     /**
@@ -473,6 +523,7 @@
             if (candidateGroup == group) return positionOffset;
             positionOffset += candidateGroup.getItems().size();
         }
+        Log.d(TAG, "Group not found: %s", group);
         return RecyclerView.NO_POSITION;
     }
 
@@ -480,4 +531,10 @@
     SnippetArticle getSuggestionAt(int position) {
         return (SnippetArticle) getItems().get(position);
     }
+
+    @VisibleForTesting
+    void announceItemRemoved(String suggestionTitle) {
+        mRecyclerView.announceForAccessibility(mRecyclerView.getResources().getString(
+                R.string.ntp_accessibility_item_removed, suggestionTitle));
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java
index 351e0d4..6fd73985 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java
@@ -274,8 +274,10 @@
      * @return The {@code ViewHolder} of the header, or null if it is not present.
      */
     private SectionHeaderViewHolder findFirstHeader() {
-        ViewHolder viewHolder =
-                findViewHolderForAdapterPosition(getNewTabPageAdapter().getFirstHeaderPosition());
+        int firstHeaderPosition = getNewTabPageAdapter().getFirstHeaderPosition();
+        if (firstHeaderPosition == RecyclerView.NO_POSITION) return null;
+
+        ViewHolder viewHolder = findViewHolderForAdapterPosition(firstHeaderPosition);
         if (!(viewHolder instanceof SectionHeaderViewHolder)) return null;
 
         return (SectionHeaderViewHolder) viewHolder;
@@ -286,8 +288,10 @@
      * @return The {@code ViewHolder} for the first card, or null if it is not present.
      */
     private CardViewHolder findFirstCard() {
-        ViewHolder viewHolder =
-                findViewHolderForAdapterPosition(getNewTabPageAdapter().getFirstCardPosition());
+        int firstCardPosition = getNewTabPageAdapter().getFirstCardPosition();
+        if (firstCardPosition == RecyclerView.NO_POSITION) return null;
+
+        ViewHolder viewHolder = findViewHolderForAdapterPosition(firstCardPosition);
         if (!(viewHolder instanceof CardViewHolder)) return null;
 
         return (CardViewHolder) viewHolder;
@@ -298,8 +302,10 @@
      * @return The {@code ViewHolder} of the last content item, or null if it is not present.
      */
     private ViewHolder findLastContentItem() {
-        ViewHolder viewHolder = findViewHolderForAdapterPosition(
-                getNewTabPageAdapter().getLastContentItemPosition());
+        int lastContentItemPosition = getNewTabPageAdapter().getLastContentItemPosition();
+        if (lastContentItemPosition == RecyclerView.NO_POSITION) return null;
+
+        ViewHolder viewHolder = findViewHolderForAdapterPosition(lastContentItemPosition);
         if (viewHolder instanceof Footer.ViewHolder) return viewHolder;
 
         return null;
@@ -310,7 +316,10 @@
      * @return The {@code ViewHolder} of the bottom spacer, or null if it is not present.
      */
     private ViewHolder findBottomSpacer() {
-        return findViewHolderForAdapterPosition(getNewTabPageAdapter().getBottomSpacerPosition());
+        int bottomSpacerPosition = getNewTabPageAdapter().getBottomSpacerPosition();
+        if (bottomSpacerPosition == RecyclerView.NO_POSITION) return null;
+
+        return findViewHolderForAdapterPosition(bottomSpacerPosition);
     }
 
     /**
@@ -318,8 +327,10 @@
      * @return The View for above the fold or null, if it is not present.
      */
     public NewTabPageLayout findAboveTheFoldView() {
-        ViewHolder viewHolder =
-                findViewHolderForAdapterPosition(getNewTabPageAdapter().getAboveTheFoldPosition());
+        int aboveTheFoldPosition = getNewTabPageAdapter().getAboveTheFoldPosition();
+        if (aboveTheFoldPosition == RecyclerView.NO_POSITION) return null;
+
+        ViewHolder viewHolder = findViewHolderForAdapterPosition(aboveTheFoldPosition);
         if (viewHolder == null) return null;
 
         View view = viewHolder.itemView;
@@ -429,7 +440,7 @@
      */
     public void dismissItemWithAnimation(SnippetArticle suggestion) {
         // We need to recompute the position, as it might have changed.
-        final int position = getNewTabPageAdapter().getSuggestionPosition(suggestion.mId);
+        final int position = getNewTabPageAdapter().getSuggestionPosition(suggestion);
         if (position == RecyclerView.NO_POSITION) {
             // The item does not exist anymore, so ignore.
             return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
index 6348250..31e695d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
@@ -28,11 +28,24 @@
     private final ActionItem mMoreButton;
     @CategoryInt
     private final int mCategory;
+    private final Observer mObserver;
 
     public SuggestionsSection(@CategoryInt int category, SuggestionsCategoryInfo info,
             final NewTabPageAdapter adapter) {
+        this(category, info, adapter, new ActionDelegate() {
+            @Override
+            public void onButtonTapped() {
+                adapter.reloadSnippets();
+            }
+        });
+    }
+
+    @VisibleForTesting
+    SuggestionsSection(@CategoryInt int category, SuggestionsCategoryInfo info, Observer observer,
+            ActionDelegate actionDelegate) {
         mHeader = new SectionHeader(info.getTitle());
         mCategory = category;
+        mObserver = observer;
 
         // TODO(dgn): Properly define strings, actions, etc. for each section and category type.
         if (info.hasMoreButton()) {
@@ -40,17 +53,13 @@
             mActionDelegate = null;
         } else {
             mMoreButton = null;
-            mActionDelegate = new ActionDelegate() {
-                @Override
-                public void onButtonTapped() {
-                    adapter.reloadSnippets();
-                }
-            };
+            mActionDelegate = actionDelegate;
         }
     }
 
     @Override
     public List<NewTabPageItem> getItems() {
+        // Note: Keep this coherent with the various notify** calls on ItemGroup.Observer
         List<NewTabPageItem> items = new ArrayList<>();
         items.add(mHeader);
         items.addAll(mSuggestions);
@@ -63,13 +72,27 @@
     }
 
     public void removeSuggestion(SnippetArticle suggestion) {
-        mSuggestions.remove(suggestion);
+        int removedIndex = mSuggestions.indexOf(suggestion);
+        if (removedIndex == -1) return;
+
+        mSuggestions.remove(removedIndex);
         if (mMoreButton != null) mMoreButton.setDismissable(!hasSuggestions());
+
+        // Note: Keep this coherent with getItems()
+        int globalRemovedIndex = removedIndex + 1; // Header has index 0 in the section.
+        mObserver.notifyItemRemoved(this, globalRemovedIndex);
+
+        if (!hasSuggestions()) {
+            // When the last suggestion is removed, we insert other items to display the status,
+            // notify about them too.
+            mObserver.notifyItemInserted(this, globalRemovedIndex);
+            mObserver.notifyItemInserted(this, globalRemovedIndex + (mMoreButton == null ? 1 : 2));
+        }
     }
 
-    public void removeSuggestionById(String suggestionId) {
+    public void removeSuggestionById(String idWithinCategory) {
         for (SnippetArticle suggestion : mSuggestions) {
-            if (suggestion.mId.equals(suggestionId)) {
+            if (suggestion.mIdWithinCategory.equals(idWithinCategory)) {
                 removeSuggestion(suggestion);
                 return;
             }
@@ -87,7 +110,8 @@
     public void setSuggestions(List<SnippetArticle> suggestions, @CategoryStatusEnum int status) {
         copyThumbnails(suggestions);
 
-        setStatus(status);
+        int itemCountBefore = getItems().size();
+        setStatusInternal(status);
 
         mSuggestions.clear();
         mSuggestions.addAll(suggestions);
@@ -95,10 +119,17 @@
         if (mMoreButton != null) {
             mMoreButton.setPosition(mSuggestions.size());
         }
+        mObserver.notifyGroupChanged(this, itemCountBefore, getItems().size());
     }
 
     /** Sets the status for the section. Some statuses can cause the suggestions to be cleared. */
     public void setStatus(@CategoryStatusEnum int status) {
+        int itemCountBefore = getItems().size();
+        setStatusInternal(status);
+        mObserver.notifyGroupChanged(this, itemCountBefore, getItems().size());
+    }
+
+    private void setStatusInternal(@CategoryStatusEnum int status) {
         mStatus = StatusItem.create(status, mActionDelegate);
 
         if (!SnippetsBridge.isCategoryStatusAvailable(status)) mSuggestions.clear();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/FakeSuggestionsSource.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/FakeSuggestionsSource.java
index bec2652..7a645d9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/FakeSuggestionsSource.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/FakeSuggestionsSource.java
@@ -70,14 +70,14 @@
      * Removes the given suggestion from the source and notifies any observer that it has been
      * invalidated.
      */
-    public void fireSuggestionInvalidated(@CategoryInt int category, String suggestionId) {
+    public void fireSuggestionInvalidated(@CategoryInt int category, String idWithinCategory) {
         for (SnippetArticle suggestion : mSuggestions.get(category)) {
-            if (suggestion.mId.equals(suggestionId)) {
+            if (suggestion.mIdWithinCategory.equals(idWithinCategory)) {
                 mSuggestions.get(category).remove(suggestion);
                 break;
             }
         }
-        mObserver.onSuggestionInvalidated(category, suggestionId);
+        mObserver.onSuggestionInvalidated(category, idWithinCategory);
     }
 
     /**
@@ -102,15 +102,15 @@
 
     @Override
     public void fetchSuggestionImage(SnippetArticle suggestion, Callback<Bitmap> callback) {
-        if (mThumbnails.containsKey(suggestion.mId)) {
-            callback.onResult(mThumbnails.get(suggestion.mId));
+        if (mThumbnails.containsKey(suggestion.mIdWithinCategory)) {
+            callback.onResult(mThumbnails.get(suggestion.mIdWithinCategory));
         }
     }
 
     @Override
     public void getSuggestionVisited(
             SnippetArticle suggestion, Callback<Boolean> callback) {
-        throw new UnsupportedOperationException();
+        callback.onResult(false);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticle.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticle.java
index 7fb0372..2387d61 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticle.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticle.java
@@ -18,8 +18,8 @@
     /** The category of this article. */
     public final int mCategory;
 
-    /** The unique identifier for this article. */
-    public final String mId;
+    /** The identifier for this article within the category - not necessarily unique globally. */
+    public final String mIdWithinCategory;
 
     /** The title of this article. */
     public final String mTitle;
@@ -64,11 +64,11 @@
     /**
      * Creates a SnippetArticleListItem object that will hold the data.
      */
-    public SnippetArticle(int category, String id, String title, String publisher,
+    public SnippetArticle(int category, String idWithinCategory, String title, String publisher,
             String previewText, String url, String ampUrl, long timestamp, float score,
             int position, @ContentSuggestionsCardLayoutEnum int cardLayout) {
         mCategory = category;
-        mId = id;
+        mIdWithinCategory = idWithinCategory;
         mTitle = title;
         mPublisher = publisher;
         mPreviewText = previewText;
@@ -83,12 +83,13 @@
     @Override
     public boolean equals(Object other) {
         if (!(other instanceof SnippetArticle)) return false;
-        return mId.equals(((SnippetArticle) other).mId);
+        SnippetArticle rhs = (SnippetArticle) other;
+        return mCategory == rhs.mCategory && mIdWithinCategory.equals(rhs.mIdWithinCategory);
     }
 
     @Override
     public int hashCode() {
-        return mId.hashCode();
+        return mCategory ^ mIdWithinCategory.hashCode();
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java
index e3850d1..e3cdbd3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java
@@ -107,13 +107,15 @@
     @Override
     public void fetchSuggestionImage(SnippetArticle suggestion, Callback<Bitmap> callback) {
         assert mNativeSnippetsBridge != 0;
-        nativeFetchSuggestionImage(mNativeSnippetsBridge, suggestion.mId, callback);
+        nativeFetchSuggestionImage(mNativeSnippetsBridge, suggestion.mCategory,
+                suggestion.mIdWithinCategory, callback);
     }
 
     @Override
     public void dismissSuggestion(SnippetArticle suggestion) {
         assert mNativeSnippetsBridge != 0;
-        nativeDismissSuggestion(mNativeSnippetsBridge, suggestion.mId);
+        nativeDismissSuggestion(
+                mNativeSnippetsBridge, suggestion.mCategory, suggestion.mIdWithinCategory);
     }
 
     @Override
@@ -219,8 +221,8 @@
     }
 
     @CalledByNative
-    private void onSuggestionInvalidated(@CategoryInt int category, String suggestionId) {
-        if (mObserver != null) mObserver.onSuggestionInvalidated(category, suggestionId);
+    private void onSuggestionInvalidated(@CategoryInt int category, String idWithinCategory) {
+        if (mObserver != null) mObserver.onSuggestionInvalidated(category, idWithinCategory);
     }
 
     private native long nativeInit(Profile profile);
@@ -233,9 +235,10 @@
             long nativeNTPSnippetsBridge, int category);
     private native List<SnippetArticle> nativeGetSuggestionsForCategory(
             long nativeNTPSnippetsBridge, int category);
-    private native void nativeFetchSuggestionImage(
-            long nativeNTPSnippetsBridge, String suggestionId, Callback<Bitmap> callback);
-    private native void nativeDismissSuggestion(long nativeNTPSnippetsBridge, String suggestionId);
+    private native void nativeFetchSuggestionImage(long nativeNTPSnippetsBridge, int category,
+            String idWithinCategory, Callback<Bitmap> callback);
+    private native void nativeDismissSuggestion(
+            long nativeNTPSnippetsBridge, int category, String idWithinCategory);
     private native void nativeDismissCategory(long nativeNTPSnippetsBridge, int category);
     private native void nativeGetURLVisited(
             long nativeNTPSnippetsBridge, Callback<Boolean> callback, String url);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SuggestionsSource.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SuggestionsSource.java
index 9bd37a8d..1f631587a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SuggestionsSource.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SuggestionsSource.java
@@ -31,7 +31,7 @@
          * immediately. This event may be fired for a category or suggestion that does not
          * currently exist or has never existed and should be ignored in that case.
          */
-        void onSuggestionInvalidated(@CategoryInt int category, String suggestionId);
+        void onSuggestionInvalidated(@CategoryInt int category, String idWithinCategory);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarTablet.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarTablet.java
index b16f040..f25b10a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarTablet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarTablet.java
@@ -18,7 +18,6 @@
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.download.DownloadUtils;
 import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.tab.Tab;
@@ -562,7 +561,7 @@
         if (tab == null) return false;
         // The save offline button should not be shown on native pages. Currently, trying to
         // save an offline page in incognito crashes, so don't show it on incognito either.
-        return ChromeFeatureList.isEnabled("DownloadsUi") && shouldShowPageActionButtons()
+        return DownloadUtils.isDownloadHomeEnabled() && shouldShowPageActionButtons()
                 && !tab.isIncognito();
     }
 
@@ -578,7 +577,7 @@
         // should be shown if the delete button isn't showing. If the download UI is enabled, there
         // are two actions, bookmark and save offline, and they should be shown if the omnibox isn't
         // focused.
-        return (!shouldShowDeleteButton() && !ChromeFeatureList.isEnabled("DownloadsUi"))
+        return (!shouldShowDeleteButton() && !DownloadUtils.isDownloadHomeEnabled())
                 || !(mUrlBar.hasFocus() || mUrlFocusChangeInProgress);
     }
 
@@ -586,7 +585,7 @@
         // If the download UI is enabled, the mic button should be only be shown when the url bar
         // is focused.
         return isVoiceSearchEnabled() && mNativeInitialized
-                && (!ChromeFeatureList.isEnabled("DownloadsUi")
+                && (!DownloadUtils.isDownloadHomeEnabled()
                         || (mUrlBar.hasFocus() || mUrlFocusChangeInProgress));
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebDiagnosticsPage.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebDiagnosticsPage.java
index 32a7d7a1..4ad7113 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebDiagnosticsPage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebDiagnosticsPage.java
@@ -47,7 +47,7 @@
     }
 
     @Override
-    protected void initialize(Activity activity, Tab tab) {
+    protected void initialize(final Activity activity, Tab tab) {
         Resources resources = activity.getResources();
         mSuccessColor = colorToHexValue(ApiCompatibilityUtils.getColor(resources,
                 R.color.physical_web_diags_success_color));
@@ -63,7 +63,7 @@
         mLaunchButton.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                ContextUtils.getApplicationContext().startActivity(createListUrlsIntent());
+                activity.startActivity(createListUrlsIntent());
             }
         });
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
index 401988d..68a4bb3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -90,9 +90,7 @@
 import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils;
 import org.chromium.components.navigation_interception.InterceptNavigationDelegate;
 import org.chromium.components.security_state.ConnectionSecurityLevel;
-import org.chromium.content.browser.ActivityContentVideoViewEmbedder;
 import org.chromium.content.browser.ChildProcessLauncher;
-import org.chromium.content.browser.ContentVideoViewEmbedder;
 import org.chromium.content.browser.ContentView;
 import org.chromium.content.browser.ContentViewClient;
 import org.chromium.content.browser.ContentViewCore;
@@ -156,6 +154,8 @@
     /** Used for logging. */
     private static final String TAG = "Tab";
 
+    private static final String PRODUCT_VERSION = ChromeVersionInfo.getProductVersion();
+
     private long mNativeTabAndroid;
 
     /** Unique id of this tab (within its container). */
@@ -485,42 +485,6 @@
             }
             return 0;
         }
-
-        @Override
-        public ContentVideoViewEmbedder getContentVideoViewEmbedder() {
-            return new ActivityContentVideoViewEmbedder(getActivity()) {
-                @Override
-                public void enterFullscreenVideo(View view, boolean isVideoLoaded) {
-                    super.enterFullscreenVideo(view, isVideoLoaded);
-                    FullscreenManager fullscreenManager = getFullscreenManager();
-                    if (fullscreenManager != null) {
-                        fullscreenManager.setOverlayVideoMode(true);
-                        // Disable double tap for video.
-                        if (getContentViewCore() != null) {
-                            getContentViewCore().updateDoubleTapSupport(false);
-                        }
-                    }
-                }
-
-                @Override
-                public void exitFullscreenVideo() {
-                    FullscreenManager fullscreenManager = getFullscreenManager();
-                    if (fullscreenManager != null) {
-                        fullscreenManager.setOverlayVideoMode(false);
-                        // Disable double tap for video.
-                        if (getContentViewCore() != null) {
-                            getContentViewCore().updateDoubleTapSupport(true);
-                        }
-                    }
-                    super.exitFullscreenVideo();
-                }
-            };
-        }
-
-        @Override
-        public String getProductVersion() {
-            return ChromeVersionInfo.getProductVersion();
-        }
     }
 
     private GestureStateListener createGestureStateListener() {
@@ -1855,7 +1819,7 @@
      *                    {@link ContentViewCore}.
      */
     protected void initContentViewCore(WebContents webContents) {
-        ContentViewCore cvc = new ContentViewCore(mThemedApplicationContext);
+        ContentViewCore cvc = new ContentViewCore(mThemedApplicationContext, PRODUCT_VERSION);
         ContentView cv = ContentView.createContentView(mThemedApplicationContext, cvc);
         cv.setContentDescription(mThemedApplicationContext.getResources().getString(
                 R.string.accessibility_content_view));
@@ -2535,7 +2499,7 @@
     @CalledByNative
     public void swapWebContents(
             WebContents webContents, boolean didStartLoad, boolean didFinishLoad) {
-        ContentViewCore cvc = new ContentViewCore(mThemedApplicationContext);
+        ContentViewCore cvc = new ContentViewCore(mThemedApplicationContext, PRODUCT_VERSION);
         ContentView cv = ContentView.createContentView(mThemedApplicationContext, cvc);
         cv.setContentDescription(mThemedApplicationContext.getResources().getString(
                 R.string.accessibility_content_view));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java
index 567641c..845d6cf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java
@@ -29,6 +29,7 @@
 import org.chromium.chrome.browser.document.DocumentWebContentsDelegate;
 import org.chromium.chrome.browser.findinpage.FindMatchRectsDetails;
 import org.chromium.chrome.browser.findinpage.FindNotificationDetails;
+import org.chromium.chrome.browser.fullscreen.FullscreenManager;
 import org.chromium.chrome.browser.media.MediaCaptureNotificationService;
 import org.chromium.chrome.browser.policy.PolicyAuditor;
 import org.chromium.chrome.browser.policy.PolicyAuditor.AuditEvent;
@@ -38,6 +39,9 @@
 import org.chromium.chrome.browser.tabmodel.TabModelUtils;
 import org.chromium.chrome.browser.tabmodel.TabWindowManager;
 import org.chromium.components.web_contents_delegate_android.WebContentsDelegateAndroid;
+import org.chromium.content.browser.ActivityContentVideoViewEmbedder;
+import org.chromium.content.browser.ContentVideoViewEmbedder;
+import org.chromium.content.browser.ContentViewCore;
 import org.chromium.content_public.browser.InvalidateTypes;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.common.ResourceRequestBody;
@@ -489,6 +493,39 @@
         if (tab != null) nativeNotifyStopped(tab.getWebContents());
     }
 
+    @Override
+    public ContentVideoViewEmbedder getContentVideoViewEmbedder() {
+        return new ActivityContentVideoViewEmbedder(mTab.getActivity()) {
+            @Override
+            public void enterFullscreenVideo(View view, boolean isVideoLoaded) {
+                super.enterFullscreenVideo(view, isVideoLoaded);
+                FullscreenManager fullscreenManager = mTab.getFullscreenManager();
+                if (fullscreenManager != null) {
+                    fullscreenManager.setOverlayVideoMode(true);
+                    // Disable double tap for video.
+                    ContentViewCore cvc = mTab.getContentViewCore();
+                    if (cvc != null) {
+                        cvc.updateDoubleTapSupport(false);
+                    }
+                }
+            }
+
+            @Override
+            public void exitFullscreenVideo() {
+                FullscreenManager fullscreenManager = mTab.getFullscreenManager();
+                if (fullscreenManager != null) {
+                    fullscreenManager.setOverlayVideoMode(false);
+                    // Disable double tap for video.
+                    ContentViewCore cvc = mTab.getContentViewCore();
+                    if (cvc != null) {
+                        cvc.updateDoubleTapSupport(true);
+                    }
+                }
+                super.exitFullscreenVideo();
+            }
+        };
+    }
+
     private static native void nativeOnRendererUnresponsive(WebContents webContents);
     private static native void nativeOnRendererResponsive(WebContents webContents);
     private static native boolean nativeIsCapturingAudio(WebContents webContents);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/Toolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/Toolbar.java
index 9cf3508..04e2577 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/Toolbar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/Toolbar.java
@@ -85,9 +85,4 @@
      * @param animate Whether the removal of the badge should be animated.
      */
     void removeAppMenuUpdateBadge(boolean animate);
-
-    /**
-     * Herb: Sets the listener that is told when the "return to previous app" button is clicked.
-     */
-    void setReturnButtonListener(View.OnClickListener listener);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java
index e09a640..e2c96c0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java
@@ -784,8 +784,4 @@
                     R.string.accessibility_toolbar_btn_menu));
         }
     }
-
-    @Override
-    public void setReturnButtonListener(View.OnClickListener listener) {
-    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
index c101414..a022d255 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
@@ -26,7 +26,6 @@
 import android.os.Build;
 import android.os.SystemClock;
 import android.support.v4.view.animation.FastOutSlowInInterpolator;
-import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Property;
 import android.view.Gravity;
@@ -49,7 +48,6 @@
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.compositor.Invalidator;
 import org.chromium.chrome.browser.compositor.layouts.LayoutUpdateHost;
 import org.chromium.chrome.browser.fullscreen.FullscreenManager;
@@ -59,7 +57,6 @@
 import org.chromium.chrome.browser.partnercustomizations.HomepageManager;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.util.ColorUtils;
-import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.browser.util.MathUtils;
 import org.chromium.chrome.browser.widget.TintedImageButton;
 import org.chromium.chrome.browser.widget.newtab.NewTabButton;
@@ -117,7 +114,6 @@
     private ViewGroup mToolbarButtonsContainer;
     private ImageView mToggleTabStackButton;
     private NewTabButton mNewTabButton;
-    private TintedImageButton mReturnButton;
     private TintedImageButton mHomeButton;
     private TextView mUrlBar;
     private View mUrlActionContainer;
@@ -230,7 +226,6 @@
     private ValueAnimator mBrandColorTransitionAnimation;
     private boolean mBrandColorTransitionActive;
 
-    private View.OnClickListener mReturnButtonListener;
     private boolean mIsHomeButtonEnabled;
 
     private LayoutUpdateHost mLayoutUpdateHost;
@@ -325,7 +320,6 @@
 
         mToolbarButtonsContainer = (ViewGroup) findViewById(R.id.toolbar_buttons);
 
-        mReturnButton = (TintedImageButton) findViewById(R.id.return_button);
         mHomeButton = (TintedImageButton) findViewById(R.id.home_button);
 
         mUrlBar = (TextView) findViewById(R.id.url_bar);
@@ -637,11 +631,7 @@
 
     private int getBoundsAfterAccountingForLeftButton() {
         int padding = mToolbarSidePadding;
-        if (mReturnButton.getVisibility() != GONE) {
-            padding = mReturnButton.getMeasuredWidth();
-        } else if (mHomeButton.getVisibility() != GONE) {
-            padding = mHomeButton.getMeasuredWidth();
-        }
+        if (mHomeButton.getVisibility() != GONE) padding = mHomeButton.getMeasuredWidth();
         return padding;
     }
 
@@ -873,9 +863,6 @@
         // accepting click events.
         int toolbarButtonVisibility = mUrlExpansionPercent == 1f ? INVISIBLE : VISIBLE;
         mToolbarButtonsContainer.setVisibility(toolbarButtonVisibility);
-        if (mReturnButton.getVisibility() != GONE) {
-            mReturnButton.setVisibility(toolbarButtonVisibility);
-        }
         if (mHomeButton.getVisibility() != GONE) {
             mHomeButton.setVisibility(toolbarButtonVisibility);
         }
@@ -896,7 +883,6 @@
         mLocationBar.setTranslationY(0);
         if (!mUrlFocusChangeInProgress) {
             mToolbarButtonsContainer.setTranslationY(0);
-            mReturnButton.setTranslationY(0);
             mHomeButton.setTranslationY(0);
         }
         mToolbarShadow.setAlpha(1f);
@@ -981,7 +967,6 @@
         int transY = mTabSwitcherState == STATIC_TAB ? Math.min(mNtpSearchBoxTranslation.y, 0) : 0;
 
         mToolbarButtonsContainer.setTranslationY(transY);
-        mReturnButton.setTranslationY(transY);
         mHomeButton.setTranslationY(transY);
     }
 
@@ -1021,12 +1006,6 @@
         canvas.clipRect(mBackgroundOverlayBounds);
 
         float previousAlpha = 0.f;
-        if (mReturnButton.getVisibility() != View.GONE) {
-            previousAlpha = mReturnButton.getAlpha();
-            mReturnButton.setAlpha(previousAlpha * floatAlpha);
-            drawChild(canvas, mReturnButton, SystemClock.uptimeMillis());
-            mReturnButton.setAlpha(previousAlpha);
-        }
         if (mHomeButton.getVisibility() != View.GONE) {
             // Draw the New Tab button used in the URL view.
             previousAlpha = mHomeButton.getAlpha();
@@ -1152,7 +1131,7 @@
                 // Hardware mode does not support unioned clip regions, so clip using the
                 // appropriate bounds based on whether the child is to the left or right of the
                 // location bar.
-                boolean isLeft = (child == mNewTabButton || child == mReturnButton
+                boolean isLeft = (child == mNewTabButton
                         || child == mHomeButton) ^ LocalizationUtils.isLayoutRtl();
 
                 int clipBottom = mLocationBarBackgroundBounds.bottom
@@ -1369,17 +1348,7 @@
 
     @Override
     public void updateButtonVisibility() {
-        if (isReturnButtonVisible()) {
-            mReturnButton.setVisibility(
-                    urlHasFocus() || isTabSwitcherAnimationRunning() ? INVISIBLE : VISIBLE);
-            mBrowsingModeViews.add(mReturnButton);
-        } else {
-            mReturnButton.setVisibility(GONE);
-            mBrowsingModeViews.remove(mReturnButton);
-        }
-
-        boolean isHomeButtonVisible = mIsHomeButtonEnabled && !isReturnButtonVisible();
-        if (isHomeButtonVisible) {
+        if (mIsHomeButtonEnabled) {
             mHomeButton.setVisibility(urlHasFocus() || isTabSwitcherAnimationRunning()
                     ? INVISIBLE : VISIBLE);
             mBrowsingModeViews.add(mHomeButton);
@@ -1840,7 +1809,6 @@
 
     @Override
     protected void updateTabCountVisuals(int numberOfTabs) {
-        if (mReturnButton != null) mReturnButton.setEnabled(true);
         if (mHomeButton != null) mHomeButton.setEnabled(true);
 
         if (mToggleTabStackButton == null) return;
@@ -2133,7 +2101,6 @@
             setAppMenuUpdateBadgeDrawable(mUseLightToolbarDrawables);
         }
         ColorStateList tint = mUseLightToolbarDrawables ? mLightModeTint : mDarkModeTint;
-        if (isReturnButtonVisible()) mReturnButton.setTint(tint);
         if (mIsHomeButtonEnabled) mHomeButton.setTint(tint);
 
         mLocationBar.updateVisualsForState();
@@ -2230,29 +2197,11 @@
     }
 
     @Override
-    public void setReturnButtonListener(View.OnClickListener listener) {
-        mReturnButtonListener = listener;
-        mReturnButton.setOnClickListener(listener);
-    }
-
-    @Override
     public void setFullscreenManager(FullscreenManager manager) {
         super.setFullscreenManager(manager);
         mFullscreenManager = manager;
     }
 
-    private boolean isReturnButtonVisible() {
-        String herbFlavor = FeatureUtilities.getHerbFlavor();
-        if (!TextUtils.equals(ChromeSwitches.HERB_FLAVOR_BASIL, herbFlavor)
-                && !TextUtils.equals(ChromeSwitches.HERB_FLAVOR_CHIVE, herbFlavor)) {
-            return false;
-        }
-
-        Tab currentTab = getToolbarDataProvider().getTab();
-        return mReturnButtonListener != null && currentTab != null
-                && currentTab.isAllowedToReturnToExternalApp();
-    }
-
     private void setUseLightDrawablesForTextureCapture() {
         int currentPrimaryColor = getToolbarDataProvider().getPrimaryColor();
         mUseLightDrawablesForTextureCapture =
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
index 3e1fe5f..30f20282 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
@@ -24,6 +24,7 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.browser.download.DownloadUtils;
 import org.chromium.chrome.browser.instantapps.InstantAppsHandler;
 import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
 import org.chromium.chrome.browser.tabmodel.DocumentModeAssassin;
@@ -153,8 +154,8 @@
     }
 
     /**
-     * @return Which flavor of Herb is being tested.  See {@link ChromeSwitches#HERB_FLAVOR_ANISE}
-     *         and its related switches.
+     * @return Which flavor of Herb is being tested.
+     *         See {@link ChromeSwitches#HERB_FLAVOR_ELDERBERRY} and its related switches.
      */
     public static String getHerbFlavor() {
         Context context = ContextUtils.getApplicationContext();
@@ -184,6 +185,7 @@
      */
     public static void cacheNativeFlags() {
         cacheHerbFlavor();
+        DownloadUtils.cacheIsDownloadHomeEnabled();
         InstantAppsHandler.getInstance().cacheInstantAppsEnabled();
         ChromeWebApkHost.cacheEnabledStateForNextLaunch();
     }
@@ -201,33 +203,16 @@
         // The first clause does the null checks so so we can freely use the startsWith() function.
         String newFlavor = FieldTrialList.findFullName(HERB_EXPERIMENT_NAME);
         Log.d(TAG, "Experiment flavor: " + newFlavor);
-        if (TextUtils.isEmpty(newFlavor)
-                || newFlavor.startsWith(ChromeSwitches.HERB_FLAVOR_CONTROL)
-                || newFlavor.startsWith(ChromeSwitches.HERB_FLAVOR_DEFAULT)) {
-            newFlavor = ChromeSwitches.HERB_FLAVOR_DISABLED;
-        } else if (newFlavor.startsWith(ChromeSwitches.HERB_FLAVOR_ANISE)) {
-            newFlavor = ChromeSwitches.HERB_FLAVOR_ANISE;
-        } else if (newFlavor.startsWith(ChromeSwitches.HERB_FLAVOR_BASIL)) {
-            newFlavor = ChromeSwitches.HERB_FLAVOR_BASIL;
-        } else if (newFlavor.startsWith(ChromeSwitches.HERB_FLAVOR_CHIVE)) {
-            newFlavor = ChromeSwitches.HERB_FLAVOR_CHIVE;
-        } else if (newFlavor.startsWith(ChromeSwitches.HERB_FLAVOR_DILL)) {
-            newFlavor = ChromeSwitches.HERB_FLAVOR_DILL;
-        } else if (newFlavor.startsWith(ChromeSwitches.HERB_FLAVOR_ELDERBERRY)) {
+        if (!TextUtils.isEmpty(newFlavor)
+                && newFlavor.startsWith(ChromeSwitches.HERB_FLAVOR_ELDERBERRY)) {
             newFlavor = ChromeSwitches.HERB_FLAVOR_ELDERBERRY;
+        } else {
+            newFlavor = ChromeSwitches.HERB_FLAVOR_DISABLED;
         }
 
         CommandLine instance = CommandLine.getInstance();
         if (instance.hasSwitch(ChromeSwitches.HERB_FLAVOR_DISABLED_SWITCH)) {
             newFlavor = ChromeSwitches.HERB_FLAVOR_DISABLED;
-        } else if (instance.hasSwitch(ChromeSwitches.HERB_FLAVOR_ANISE_SWITCH)) {
-            newFlavor = ChromeSwitches.HERB_FLAVOR_ANISE;
-        } else if (instance.hasSwitch(ChromeSwitches.HERB_FLAVOR_BASIL_SWITCH)) {
-            newFlavor = ChromeSwitches.HERB_FLAVOR_BASIL;
-        } else if (instance.hasSwitch(ChromeSwitches.HERB_FLAVOR_CHIVE_SWITCH)) {
-            newFlavor = ChromeSwitches.HERB_FLAVOR_CHIVE;
-        } else if (instance.hasSwitch(ChromeSwitches.HERB_FLAVOR_DILL_SWITCH)) {
-            newFlavor = ChromeSwitches.HERB_FLAVOR_DILL;
         } else if (instance.hasSwitch(ChromeSwitches.HERB_FLAVOR_ELDERBERRY_SWITCH)) {
             newFlavor = ChromeSwitches.HERB_FLAVOR_ELDERBERRY;
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/util/IntentUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/util/IntentUtils.java
index 4bc09d8..40952d5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/util/IntentUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/util/IntentUtils.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.util;
 
+import android.content.ActivityNotFoundException;
+import android.content.Context;
 import android.content.Intent;
 import android.os.Binder;
 import android.os.Bundle;
@@ -298,6 +300,21 @@
     }
 
     /**
+     * Catches any failures to start an Activity.
+     * @param context Context to use when starting the Activity.
+     * @param intent  Intent to fire.
+     * @return Whether or not Android accepted the Intent.
+     */
+    public static boolean safeStartActivity(Context context, Intent intent) {
+        try {
+            context.startActivity(intent);
+            return true;
+        } catch (ActivityNotFoundException e) {
+            return false;
+        }
+    }
+
+    /**
      * Returns how large the Intent will be in Parcel form, which is helpful for gauging whether
      * Android will deliver the Intent instead of throwing a TransactionTooLargeException.
      *
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShell.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShell.java
index f3710ee..93104b7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShell.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShell.java
@@ -29,6 +29,7 @@
 
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.annotations.JNINamespace;
+import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.WebContentsFactory;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.content.browser.ContentView;
@@ -121,7 +122,7 @@
 
         mUiVrWindowAndroid = new VrWindowAndroid(mActivity);
         mUiContents = WebContentsFactory.createWebContents(true, false);
-        mUiCVC = new ContentViewCore(mActivity);
+        mUiCVC = new ContentViewCore(mActivity, ChromeVersionInfo.getProductVersion());
         ContentView uiContentView = ContentView.createContentView(mActivity, mUiCVC);
         mUiCVC.initialize(ViewAndroidDelegate.createBasicDelegate(uiContentView),
                 uiContentView, mUiContents, mUiVrWindowAndroid);
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 415bb71..2531087 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -1304,9 +1304,6 @@
       <message name="IDS_TAB_LOADING_DEFAULT_TITLE" desc="The title of a tab when we are still waiting for either the URL or the real title. This generally shows when the page is first loading.">
         Loading…
       </message>
-      <message name="IDS_CLOSE_TAB_AND_RETURN" desc="Button to close the current tab and return to the calling app.">
-        Close the current tab and return to the previous app
-      </message>
 
       <!-- InfoBar -->
       <message name="IDS_INFOBAR_CLOSE" desc="Accessibility label for the dismiss infobar Button">
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 0ffc9e1..6b109e1 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -1417,7 +1417,9 @@
   "junit/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridgeUnitTest.java",
   "junit/src/org/chromium/chrome/browser/ntp/NativePageFactoryTest.java",
   "junit/src/org/chromium/chrome/browser/ntp/TitleUtilTest.java",
+  "junit/src/org/chromium/chrome/browser/ntp/cards/ContentSuggestionsTestUtils.java",
   "junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java",
+  "junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java",
   "junit/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerTest.java",
   "junit/src/org/chromium/chrome/browser/offlinepages/BackgroundOfflinerTaskTest.java",
   "junit/src/org/chromium/chrome/browser/offlinepages/ClientIdTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ItemChooserDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ItemChooserDialogTest.java
index cdbc4f35..3f1abe26 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ItemChooserDialogTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ItemChooserDialogTest.java
@@ -203,6 +203,117 @@
     }
 
     @LargeTest
+    public void testPairButtonDisabledOrEnabledAfterSelectedItemDisabledOrEnabled()
+            throws InterruptedException {
+        Dialog dialog = mChooserDialog.getDialogForTesting();
+        assertTrue(dialog.isShowing());
+
+        final Button button = (Button) dialog.findViewById(R.id.positive);
+
+        mChooserDialog.addOrUpdateItem(new ItemChooserDialog.ItemChooserRow("key1", "desc1"));
+        mChooserDialog.addOrUpdateItem(new ItemChooserDialog.ItemChooserRow("key2", "desc2"));
+
+        selectItem(dialog, 1, "key1", true);
+        assertTrue(button.isEnabled());
+
+        mChooserDialog.setEnabled("key1", false);
+        assertFalse(button.isEnabled());
+
+        mChooserDialog.setEnabled("key1", true);
+        assertTrue(button.isEnabled());
+
+        mChooserDialog.dismiss();
+    }
+
+    @LargeTest
+    public void testPairButtonDisabledAfterSelectedItemRemoved() throws InterruptedException {
+        Dialog dialog = mChooserDialog.getDialogForTesting();
+        assertTrue(dialog.isShowing());
+
+        final Button button = (Button) dialog.findViewById(R.id.positive);
+
+        ItemChooserDialog.ItemChooserRow item1 =
+                new ItemChooserDialog.ItemChooserRow("key1", "desc1");
+        ItemChooserDialog.ItemChooserRow item2 =
+                new ItemChooserDialog.ItemChooserRow("key2", "desc2");
+        mChooserDialog.addOrUpdateItem(item1);
+        mChooserDialog.addOrUpdateItem(item2);
+
+        selectItem(dialog, 1, "key1", true);
+        assertTrue(button.isEnabled());
+
+        mChooserDialog.removeItemFromList(item1);
+        assertFalse(button.isEnabled());
+
+        mChooserDialog.dismiss();
+    }
+
+    @LargeTest
+    public void testSelectAnItemAndRemoveAnotherItem() throws InterruptedException {
+        Dialog dialog = mChooserDialog.getDialogForTesting();
+        assertTrue(dialog.isShowing());
+
+        final Button button = (Button) dialog.findViewById(R.id.positive);
+        ItemChooserDialog.ItemAdapter itemAdapter = mChooserDialog.getItemAdapterForTesting();
+
+        ItemChooserDialog.ItemChooserRow item1 =
+                new ItemChooserDialog.ItemChooserRow("key1", "desc1");
+        ItemChooserDialog.ItemChooserRow item2 =
+                new ItemChooserDialog.ItemChooserRow("key2", "desc2");
+        ItemChooserDialog.ItemChooserRow item3 =
+                new ItemChooserDialog.ItemChooserRow("key3", "desc3");
+
+        mChooserDialog.addOrUpdateItem(item1);
+        mChooserDialog.addOrUpdateItem(item2);
+        mChooserDialog.addOrUpdateItem(item3);
+
+        selectItem(dialog, 2, "key2", true);
+        assertTrue(button.isEnabled());
+
+        // Remove the item before the currently selected item.
+        mChooserDialog.removeItemFromList(item1);
+        assertTrue(button.isEnabled());
+        assertEquals("key2", itemAdapter.getSelectedItemKey());
+
+        // Remove the item after the currently selected item.
+        mChooserDialog.removeItemFromList(item3);
+        assertTrue(button.isEnabled());
+        assertEquals("key2", itemAdapter.getSelectedItemKey());
+
+        mChooserDialog.dismiss();
+    }
+
+    @LargeTest
+    public void testSelectAnItemAndRemoveTheSelectedItem() throws InterruptedException {
+        Dialog dialog = mChooserDialog.getDialogForTesting();
+        assertTrue(dialog.isShowing());
+
+        final Button button = (Button) dialog.findViewById(R.id.positive);
+        ItemChooserDialog.ItemAdapter itemAdapter = mChooserDialog.getItemAdapterForTesting();
+
+        ItemChooserDialog.ItemChooserRow item1 =
+                new ItemChooserDialog.ItemChooserRow("key1", "desc1");
+        ItemChooserDialog.ItemChooserRow item2 =
+                new ItemChooserDialog.ItemChooserRow("key2", "desc2");
+        ItemChooserDialog.ItemChooserRow item3 =
+                new ItemChooserDialog.ItemChooserRow("key3", "desc3");
+
+        mChooserDialog.addOrUpdateItem(item1);
+        mChooserDialog.addOrUpdateItem(item2);
+        mChooserDialog.addOrUpdateItem(item3);
+
+        selectItem(dialog, 2, "key2", true);
+        assertTrue(button.isEnabled());
+
+        // Remove the selected item.
+        mChooserDialog.removeItemFromList(item2);
+        assertFalse(button.isEnabled());
+        assertEquals("", itemAdapter.getSelectedItemKey());
+
+        mChooserDialog.dismiss();
+    }
+
+    @LargeTest
     public void testAddOrUpdateItemAndRemoveItemFromList() throws InterruptedException {
         Dialog dialog = mChooserDialog.getDialogForTesting();
         assertTrue(dialog.isShowing());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelEventFilterTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelEventFilterTest.java
index 641e728..18077c1d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelEventFilterTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelEventFilterTest.java
@@ -95,7 +95,7 @@
 
     private final class StubbedContentViewCore extends ContentViewCore {
         public StubbedContentViewCore(Context context) {
-            super(context);
+            super(context, "");
         }
 
         @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java
index 234f051f..9f8e077 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java
@@ -375,7 +375,7 @@
         private boolean mIsVisible;
 
         ContentViewCoreWrapper(ChromeActivity activity) {
-            super(activity);
+            super(activity, "");
         }
 
         @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
index 36174331..5060dee3 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
@@ -463,7 +463,7 @@
         private boolean mIsFocusedNodeEditable;
 
         public StubbedContentViewCore(Context context) {
-            super(context);
+            super(context, "");
         }
 
         /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java
index ec1b85f..adb7c98 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java
@@ -172,7 +172,7 @@
         private String mCurrentText;
 
         public StubbedContentViewCore(Context context) {
-            super(context);
+            super(context, "");
         }
 
         @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/ui/StubbedProvider.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/ui/StubbedProvider.java
index 81c0f67..66b52405 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/ui/StubbedProvider.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/ui/StubbedProvider.java
@@ -8,6 +8,7 @@
 import static junit.framework.Assert.assertNull;
 
 import android.content.ComponentName;
+import android.graphics.Bitmap;
 import android.os.Handler;
 import android.os.Looper;
 import android.text.TextUtils;
@@ -145,8 +146,12 @@
     public static class StubbedThumbnailProvider implements ThumbnailProvider {
         @Override
         public void destroy() {}
+
         @Override
-        public void getThumbnail(ThumbnailRequest request) {}
+        public Bitmap getThumbnail(ThumbnailRequest request) {
+            return null;
+        }
+
         @Override
         public void cancelRetrieval(ThumbnailRequest request) {}
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java
index 50ae0fe9..dec61d0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java
@@ -88,7 +88,7 @@
                 WebContents webContents = WebContentsFactory.createWebContents(false, false);
                 WindowAndroid windowAndroid = new ActivityWindowAndroid(getActivity());
 
-                ContentViewCore contentViewCore = new ContentViewCore(getActivity());
+                ContentViewCore contentViewCore = new ContentViewCore(getActivity(), "");
                 ContentView cv = ContentView.createContentView(getActivity(), contentViewCore);
                 contentViewCore.initialize(ViewAndroidDelegate.createBasicDelegate(cv), cv,
                         webContents, windowAndroid);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
index 768a814..3df0d4d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
@@ -77,7 +77,7 @@
                 View aboveTheFold = new View(getActivity());
 
                 mRecyclerView.setAboveTheFoldView(aboveTheFold);
-                mAdapter = new NewTabPageAdapter(mNtpManager, aboveTheFold, mUiConfig);
+                mAdapter = NewTabPageAdapter.create(mNtpManager, aboveTheFold, mUiConfig);
                 mRecyclerView.setAdapter(mAdapter);
             }
         });
@@ -349,5 +349,10 @@
         public SuggestionsSource getSuggestionsSource() {
             return mSnippetsSource;
         }
+
+        @Override
+        public void closeContextMenu() {
+            throw new UnsupportedOperationException();
+        }
     }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/ContentSuggestionsTestUtils.java b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/ContentSuggestionsTestUtils.java
new file mode 100644
index 0000000..24e9d2eb
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/ContentSuggestionsTestUtils.java
@@ -0,0 +1,37 @@
+// 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.
+
+package org.chromium.chrome.browser.ntp.cards;
+
+import org.chromium.chrome.browser.ntp.snippets.ContentSuggestionsCardLayout;
+import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Utilities to make testing content suggestions code easier. */
+public final class ContentSuggestionsTestUtils {
+    private ContentSuggestionsTestUtils() {}
+
+    public static List<SnippetArticle> createDummySuggestions(int count) {
+        List<SnippetArticle> suggestions = new ArrayList<>();
+        for (int index = 0; index < count; index++) {
+            suggestions.add(new SnippetArticle(0, "https://site.com/url" + index, "title" + index,
+                    "pub" + index, "txt" + index, "https://site.com/url" + index,
+                    "https://amp.site.com/url" + index, 0, 0, 0,
+                    ContentSuggestionsCardLayout.FULL_CARD));
+        }
+        return suggestions;
+    }
+
+    public static SuggestionsCategoryInfo createInfo(boolean moreButton, boolean showIfEmpty) {
+        return new SuggestionsCategoryInfo(
+                "", ContentSuggestionsCardLayout.FULL_CARD, moreButton, showIfEmpty);
+    }
+
+    public static SuggestionsSection createSection(
+            boolean moreButton, boolean showIfEmpty, ItemGroup.Observer observer) {
+        return new SuggestionsSection(42, createInfo(moreButton, showIfEmpty), observer, null);
+    }
+}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
index 956e6f0..8bb9a13 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
@@ -5,13 +5,18 @@
 package org.chromium.chrome.browser.ntp.cards;
 
 import static org.chromium.base.test.util.Matchers.greaterThanOrEqualTo;
+import static org.chromium.chrome.browser.ntp.cards.ContentSuggestionsTestUtils.createDummySuggestions;
 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.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 
 import android.support.annotation.Nullable;
 import android.view.ContextMenu;
@@ -42,6 +47,7 @@
 import org.junit.runner.RunWith;
 import org.robolectric.annotation.Config;
 
+import java.nio.channels.UnsupportedAddressTypeException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -211,7 +217,7 @@
         mSource.setInfoForCategory(KnownCategories.ARTICLES,
                 new SuggestionsCategoryInfo("Articles for you",
                                            ContentSuggestionsCardLayout.FULL_CARD, false, true));
-        mAdapter = new NewTabPageAdapter(new MockNewTabPageManager(mSource), null, null);
+        mAdapter = NewTabPageAdapter.create(new MockNewTabPageManager(mSource), null, null);
     }
 
     /**
@@ -404,20 +410,20 @@
         assertItemsFor();
 
         // Same when loading a new NTP.
-        mAdapter = new NewTabPageAdapter(new MockNewTabPageManager(mSource), null, null);
+        mAdapter = NewTabPageAdapter.create(new MockNewTabPageManager(mSource), null, null);
         assertItemsFor();
 
         // Same for CATEGORY_EXPLICITLY_DISABLED.
         mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE);
         mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, snippets);
-        mAdapter = new NewTabPageAdapter(new MockNewTabPageManager(mSource), null, null);
+        mAdapter = NewTabPageAdapter.create(new MockNewTabPageManager(mSource), null, null);
         assertItemsFor(section(5));
         mSource.setStatusForCategory(
                 KnownCategories.ARTICLES, CategoryStatus.CATEGORY_EXPLICITLY_DISABLED);
         assertItemsFor();
 
         // Same when loading a new NTP.
-        mAdapter = new NewTabPageAdapter(new MockNewTabPageManager(mSource), null, null);
+        mAdapter = NewTabPageAdapter.create(new MockNewTabPageManager(mSource), null, null);
         assertItemsFor();
     }
 
@@ -438,7 +444,7 @@
         assertItemsFor(section(4));
 
         // But it disappears when loading a new NTP.
-        mAdapter = new NewTabPageAdapter(new MockNewTabPageManager(mSource), null, null);
+        mAdapter = NewTabPageAdapter.create(new MockNewTabPageManager(mSource), null, null);
         assertItemsFor();
     }
 
@@ -460,7 +466,8 @@
                                   "", ContentSuggestionsCardLayout.MINIMAL_CARD, false, true));
 
         // 1.1 - Initial state
-        mAdapter = new NewTabPageAdapter(new MockNewTabPageManager(suggestionsSource), null, null);
+        mAdapter =
+                NewTabPageAdapter.create(new MockNewTabPageManager(suggestionsSource), null, null);
         assertItemsFor(sectionWithStatusCard());
 
         // 1.2 - With suggestions
@@ -485,7 +492,8 @@
                                   "", ContentSuggestionsCardLayout.MINIMAL_CARD, false, false));
 
         // 2.1 - Initial state
-        mAdapter = new NewTabPageAdapter(new MockNewTabPageManager(suggestionsSource), null, null);
+        mAdapter =
+                NewTabPageAdapter.create(new MockNewTabPageManager(suggestionsSource), null, null);
         assertItemsFor();
 
         // 2.2 - With suggestions
@@ -517,7 +525,8 @@
                                   "", ContentSuggestionsCardLayout.MINIMAL_CARD, true, true));
 
         // 1.1 - Initial state.
-        mAdapter = new NewTabPageAdapter(new MockNewTabPageManager(suggestionsSource), null, null);
+        mAdapter =
+                NewTabPageAdapter.create(new MockNewTabPageManager(suggestionsSource), null, null);
         assertItemsFor(sectionWithStatusCardAndMoreButton());
 
         // 1.2 - With suggestions.
@@ -542,7 +551,8 @@
                                   "", ContentSuggestionsCardLayout.MINIMAL_CARD, false, true));
 
         // 2.1 - Initial state.
-        mAdapter = new NewTabPageAdapter(new MockNewTabPageManager(suggestionsSource), null, null);
+        mAdapter =
+                NewTabPageAdapter.create(new MockNewTabPageManager(suggestionsSource), null, null);
         assertItemsFor(sectionWithStatusCard());
 
         // 2.2 - With suggestions.
@@ -580,7 +590,7 @@
         assertArticlesEqual(articles, 2, 5);
 
         SnippetArticle removed = articles.remove(1);
-        mSource.fireSuggestionInvalidated(KnownCategories.ARTICLES, removed.mId);
+        mSource.fireSuggestionInvalidated(KnownCategories.ARTICLES, removed.mIdWithinCategory);
         assertArticlesEqual(articles, 2, 4);
     }
 
@@ -602,7 +612,8 @@
                                           ContentSuggestionsCardLayout.MINIMAL_CARD, true, false));
         mSource.setStatusForCategory(dynamicCategory1, CategoryStatus.AVAILABLE);
         mSource.setSuggestionsForCategory(dynamicCategory1, dynamics1);
-        mAdapter = new NewTabPageAdapter(new MockNewTabPageManager(mSource), null, null); // Reload
+        mAdapter =
+                NewTabPageAdapter.create(new MockNewTabPageManager(mSource), null, null); // Reload
         assertItemsFor(section(3), sectionWithMoreButton(5));
 
         int dynamicCategory2 = 1011;
@@ -612,7 +623,8 @@
                                           ContentSuggestionsCardLayout.MINIMAL_CARD, false, false));
         mSource.setStatusForCategory(dynamicCategory2, CategoryStatus.AVAILABLE);
         mSource.setSuggestionsForCategory(dynamicCategory2, dynamics2);
-        mAdapter = new NewTabPageAdapter(new MockNewTabPageManager(mSource), null, null); // Reload
+        mAdapter =
+                NewTabPageAdapter.create(new MockNewTabPageManager(mSource), null, null); // Reload
         assertItemsFor(section(3), sectionWithMoreButton(5), section(11));
     }
 
@@ -628,8 +640,8 @@
         registerCategory(suggestionsSource, KnownCategories.PHYSICAL_WEB_PAGES, 0);
         registerCategory(suggestionsSource, KnownCategories.DOWNLOADS, 0);
 
-        NewTabPageAdapter ntpAdapter = new NewTabPageAdapter(
-                new MockNewTabPageManager(suggestionsSource), null, null);
+        NewTabPageAdapter ntpAdapter =
+                NewTabPageAdapter.create(new MockNewTabPageManager(suggestionsSource), null, null);
         List<ItemGroup> groups = ntpAdapter.getGroups();
 
         assertEquals(7, groups.size());
@@ -650,8 +662,8 @@
         registerCategory(suggestionsSource, KnownCategories.DOWNLOADS, 0);
         registerCategory(suggestionsSource, KnownCategories.BOOKMARKS, 0);
 
-        ntpAdapter = new NewTabPageAdapter(
-                new MockNewTabPageManager(suggestionsSource), null, null);
+        ntpAdapter =
+                NewTabPageAdapter.create(new MockNewTabPageManager(suggestionsSource), null, null);
         groups = ntpAdapter.getGroups();
 
         assertEquals(7, groups.size());
@@ -671,8 +683,8 @@
         registerCategory(suggestionsSource, KnownCategories.PHYSICAL_WEB_PAGES, 0);
         registerCategory(suggestionsSource, KnownCategories.DOWNLOADS, 0);
 
-        ntpAdapter = new NewTabPageAdapter(
-                new MockNewTabPageManager(suggestionsSource), null, null);
+        ntpAdapter =
+                NewTabPageAdapter.create(new MockNewTabPageManager(suggestionsSource), null, null);
 
         // The adapter is already initialised, it will not accept new categories anymore.
         registerCategory(suggestionsSource, 42, 1);
@@ -692,53 +704,68 @@
 
     @Test
     @Feature({"Ntp"})
-    public void testDismissSibling() {
-        List<SnippetArticle> snippets = createDummySuggestions(3);
-        SuggestionsSection section;
+    public void testChangeNotifications() {
+        FakeSuggestionsSource suggestionsSource = spy(new FakeSuggestionsSource());
+        // Allow using dismissSuggestion() instead of throwing UnsupportedOperationException.
+        doNothing().when(suggestionsSource).dismissSuggestion(any(SnippetArticle.class));
 
-        // Part 1: ShowMoreButton = true
-        section = new SuggestionsSection(42,
-                new SuggestionsCategoryInfo("", ContentSuggestionsCardLayout.FULL_CARD, true, true),
-                null);
-        section.setStatus(CategoryStatus.AVAILABLE);
-        assertNotNull(section.getActionItem());
+        registerCategory(suggestionsSource, KnownCategories.ARTICLES, 3);
+        NewTabPageAdapter adapter = spy(
+                new NewTabPageAdapter(new MockNewTabPageManager(suggestionsSource), null, null));
+        adapter.initializeSections();
+        doNothing().when(adapter).announceItemRemoved(anyString());
 
-        // 1.1: Without snippets
-        assertEquals(-1, section.getDismissSiblingPosDelta(section.getActionItem()));
-        assertEquals(1, section.getDismissSiblingPosDelta(section.getStatusItem()));
+        // Adapter content:
+        // Idx | Item
+        // ----|----------------
+        // 0   | Above-the-fold
+        // 1   | Header
+        // 2-4 | Sugg*3
+        // 5   | Footer
+        // 6   | Spacer
 
-        // 1.2: With snippets
-        section.setSuggestions(snippets, CategoryStatus.AVAILABLE);
-        assertEquals(0, section.getDismissSiblingPosDelta(section.getActionItem()));
-        assertEquals(0, section.getDismissSiblingPosDelta(section.getStatusItem()));
-        assertEquals(0, section.getDismissSiblingPosDelta(snippets.get(0)));
+        adapter.dismissItem(3); // Dismiss the second suggestion of the second section.
+        verify(adapter).notifyItemRemoved(3);
 
-        // Part 2: ShowMoreButton = false
-        section = new SuggestionsSection(42,
-                new SuggestionsCategoryInfo("", ContentSuggestionsCardLayout.FULL_CARD, false,
-                                                 true),
-                null);
-        section.setStatus(CategoryStatus.AVAILABLE);
-        assertNull(section.getActionItem());
+        // Make sure the call with the updated position works properly.
+        adapter.dismissItem(3);
+        verify(adapter, times(2)).notifyItemRemoved(3);
 
-        // 2.1: Without snippets
-        assertEquals(0, section.getDismissSiblingPosDelta(section.getStatusItem()));
+        // Dismiss the last suggestion in the section. We should now show the status card.
+        adapter.dismissItem(2);
+        verify(adapter).notifyItemRemoved(2);
+        verify(adapter).notifyItemInserted(2);
+        verify(adapter).notifyItemInserted(3);
 
-        // 2.2: With snippets
-        section.setSuggestions(snippets, CategoryStatus.AVAILABLE);
-        assertEquals(0, section.getDismissSiblingPosDelta(section.getStatusItem()));
-        assertEquals(0, section.getDismissSiblingPosDelta(snippets.get(0)));
-    }
+        // Adapter content:
+        // Idx | Item
+        // ----|----------------
+        // 0   | Above-the-fold
+        // 1   | Header
+        // 2   | Status
+        // 3   | Progress Indicator
+        // 4   | Footer
+        // 5   | Spacer
 
-    private List<SnippetArticle> createDummySuggestions(int count) {
-        List<SnippetArticle> suggestions = new ArrayList<>();
-        for (int index = 0; index < count; index++) {
-            suggestions.add(new SnippetArticle(0, "https://site.com/url" + index, "title" + index,
-                    "pub" + index, "txt" + index, "https://site.com/url" + index,
-                    "https://amp.site.com/url" + index, 0, 0, 0,
-                    ContentSuggestionsCardLayout.FULL_CARD));
-        }
-        return suggestions;
+        final int newSuggestionCount = 7;
+        suggestionsSource.setSuggestionsForCategory(
+                KnownCategories.ARTICLES, createDummySuggestions(newSuggestionCount));
+        adapter.onNewSuggestions(KnownCategories.ARTICLES);
+        verify(adapter).notifyItemRangeChanged(2, 2); // status and progress replaced by articles.
+        verify(adapter).notifyItemRangeInserted(4, newSuggestionCount - 2);
+
+        // Adapter content:
+        // Idx | Item
+        // ----|----------------
+        // 0   | Above-the-fold
+        // 1   | Header
+        // 2-8 | Sugg*7
+        // 9   | Footer
+        // 10  | Spacer
+
+        adapter.onCategoryStatusChanged(KnownCategories.ARTICLES, CategoryStatus.SIGNED_OUT);
+        verify(adapter, times(2)).notifyItemRangeChanged(2, 2);
+        verify(adapter).notifyItemRangeRemoved(4, newSuggestionCount - 2);
     }
 
     /** Registers the category with hasMoreButton=false and showIfEmpty=true*/
@@ -915,5 +942,14 @@
         @Nullable public SuggestionsSource getSuggestionsSource() {
             return mSuggestionsSource;
         }
+
+        @Override
+        public void closeContextMenu() {
+            throw new UnsupportedAddressTypeException();
+        }
+
+        public void setSuggestionsSource(SuggestionsSource suggestionsSource) {
+            mSuggestionsSource = suggestionsSource;
+        }
     }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java
new file mode 100644
index 0000000..4539ac8
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java
@@ -0,0 +1,171 @@
+// 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.
+
+package org.chromium.chrome.browser.ntp.cards;
+
+import static org.chromium.chrome.browser.ntp.cards.ContentSuggestionsTestUtils.createDummySuggestions;
+import static org.chromium.chrome.browser.ntp.cards.ContentSuggestionsTestUtils.createInfo;
+import static org.chromium.chrome.browser.ntp.cards.ContentSuggestionsTestUtils.createSection;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.browser.ntp.snippets.CategoryStatus;
+import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
+import org.chromium.testing.local.LocalRobolectricTestRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+import java.util.List;
+
+/**
+ * Unit tests for {@link SuggestionsSection}.
+ */
+@RunWith(LocalRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class SuggestionsSectionTest {
+    /** Number of items in a section when there are no suggestions: header, status, progress. */
+    private static final int EMPTY_SECTION_COUNT = 3;
+
+    @Test
+    @Feature({"Ntp"})
+    public void testDismissSibling() {
+        ItemGroup.Observer observerMock = mock(ItemGroup.Observer.class);
+        List<SnippetArticle> snippets = createDummySuggestions(3);
+        SuggestionsSection section;
+
+        // Part 1: ShowMoreButton = true.
+        section = new SuggestionsSection(42, createInfo(true, true), observerMock, null);
+        section.setStatus(CategoryStatus.AVAILABLE);
+        assertNotNull(section.getActionItem());
+
+        // 1.1: Without snippets.
+        assertEquals(-1, section.getDismissSiblingPosDelta(section.getActionItem()));
+        assertEquals(1, section.getDismissSiblingPosDelta(section.getStatusItem()));
+
+        // 1.2: With snippets.
+        section.setSuggestions(snippets, CategoryStatus.AVAILABLE);
+        assertEquals(0, section.getDismissSiblingPosDelta(section.getActionItem()));
+        assertEquals(0, section.getDismissSiblingPosDelta(section.getStatusItem()));
+        assertEquals(0, section.getDismissSiblingPosDelta(snippets.get(0)));
+
+        // Part 2: ShowMoreButton = false.
+        section = new SuggestionsSection(42, createInfo(false, true), observerMock, null);
+        section.setStatus(CategoryStatus.AVAILABLE);
+        assertNull(section.getActionItem());
+
+        // 2.1: Without snippets.
+        assertEquals(0, section.getDismissSiblingPosDelta(section.getStatusItem()));
+
+        // 2.2: With snippets.
+        section.setSuggestions(snippets, CategoryStatus.AVAILABLE);
+        assertEquals(0, section.getDismissSiblingPosDelta(section.getStatusItem()));
+        assertEquals(0, section.getDismissSiblingPosDelta(snippets.get(0)));
+    }
+
+    @Test
+    @Feature({"Ntp"})
+    public void testSetSuggestionsNotification() {
+        ItemGroup.Observer observerMock = mock(ItemGroup.Observer.class);
+
+        final int suggestionCount = 5;
+        List<SnippetArticle> snippets = createDummySuggestions(suggestionCount);
+
+        SuggestionsSection section = createSection(false, true, observerMock);
+        // Note: when status is not initialised, we insert an item for the status card, but it's
+        // null!
+        assertEquals(EMPTY_SECTION_COUNT, section.getItems().size());
+
+        section.setSuggestions(snippets, CategoryStatus.AVAILABLE);
+        verify(observerMock)
+                .notifyGroupChanged(
+                        eq(section), eq(EMPTY_SECTION_COUNT), eq(suggestionCount + 1 /* header */));
+    }
+
+    @Test
+    @Feature({"Ntp"})
+    public void testSetStatusNotification() {
+        ItemGroup.Observer observerMock = mock(ItemGroup.Observer.class);
+        final int emptySectionCount = 3;
+        final int suggestionCount = 5;
+        List<SnippetArticle> snippets = createDummySuggestions(suggestionCount);
+
+        SuggestionsSection section = createSection(false, true, observerMock);
+
+        section.setStatus(CategoryStatus.AVAILABLE);
+        verify(observerMock)
+                .notifyGroupChanged(eq(section), eq(EMPTY_SECTION_COUNT), eq(EMPTY_SECTION_COUNT));
+
+        section.setSuggestions(snippets, CategoryStatus.AVAILABLE);
+
+        // We don't clear suggestions when the status is AVAILABLE.
+        section.setStatus(CategoryStatus.AVAILABLE);
+        verify(observerMock)
+                .notifyGroupChanged(eq(section), eq(suggestionCount + 1), eq(suggestionCount + 1));
+
+        // We clear existing suggestions when the status is not AVAILABLE.
+        section.setStatus(CategoryStatus.LOADING_ERROR);
+        verify(observerMock)
+                .notifyGroupChanged(eq(section), eq(suggestionCount + 1), eq(EMPTY_SECTION_COUNT));
+    }
+
+    @Test
+    @Feature({"Ntp"})
+    public void testRemoveSuggestionNotification() {
+        ItemGroup.Observer observerMock = mock(ItemGroup.Observer.class);
+
+        final int suggestionCount = 2;
+        List<SnippetArticle> snippets = createDummySuggestions(suggestionCount);
+
+        SuggestionsSection section = createSection(false, true, observerMock);
+
+        section.removeSuggestion(snippets.get(0));
+        verify(observerMock, never()).notifyGroupChanged(any(ItemGroup.class), anyInt(), anyInt());
+        verify(observerMock, never()).notifyItemRemoved(any(ItemGroup.class), anyInt());
+
+        section.setSuggestions(snippets, CategoryStatus.AVAILABLE);
+
+        section.removeSuggestion(snippets.get(1));
+        verify(observerMock).notifyItemRemoved(section, 2);
+
+        section.removeSuggestion(snippets.get(0));
+        verify(observerMock).notifyItemRemoved(section, 1);
+        verify(observerMock).notifyItemInserted(section, 1);
+        verify(observerMock).notifyItemInserted(section, 2);
+    }
+
+    @Test
+    @Feature({"Ntp"})
+    public void testRemoveSuggestionNotificationWithButton() {
+        ItemGroup.Observer observerMock = mock(ItemGroup.Observer.class);
+
+        final int suggestionCount = 2;
+        List<SnippetArticle> snippets = createDummySuggestions(suggestionCount);
+
+        SuggestionsSection section = createSection(true, true, observerMock);
+
+        section.removeSuggestion(snippets.get(0));
+        verify(observerMock, never()).notifyGroupChanged(any(ItemGroup.class), anyInt(), anyInt());
+        verify(observerMock, never()).notifyItemRemoved(any(ItemGroup.class), anyInt());
+
+        section.setSuggestions(snippets, CategoryStatus.AVAILABLE);
+
+        section.removeSuggestion(snippets.get(0));
+        verify(observerMock).notifyItemRemoved(section, 1);
+
+        section.removeSuggestion(snippets.get(1));
+        verify(observerMock, times(2)).notifyItemRemoved(section, 1);
+        verify(observerMock).notifyItemInserted(section, 1);
+        verify(observerMock).notifyItemInserted(section, 3);
+    }
+}
diff --git a/chrome/android/monochrome_repack_locales.gni b/chrome/android/monochrome_repack_locales.gni
index bdba7a5..dbaab3e 100644
--- a/chrome/android/monochrome_repack_locales.gni
+++ b/chrome/android/monochrome_repack_locales.gni
@@ -5,6 +5,7 @@
 import("//android_webview/webview_repack_locales_list.gni")
 import("//chrome/chrome_repack_locales.gni")
 
+#TODO(agrieve): Delete once unreferenced downstream.
 template("monochrome_repack_locales") {
   chrome_repack_locales(target_name) {
     forward_variables_from(invoker, "*")
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc
index 8ec78fb4..64319c6 100644
--- a/chrome/app/chrome_main_delegate.cc
+++ b/chrome/app/chrome_main_delegate.cc
@@ -764,10 +764,6 @@
                                           chrome::DIR_INTERNAL_PLUGINS,
                                           chrome::DIR_USER_DATA);
 
-  // Enable Message Loop related state asap.
-  if (command_line.HasSwitch(switches::kMessageLoopHistogrammer))
-    base::MessageLoop::EnableHistogrammer(true);
-
 #if !defined(OS_ANDROID) && !defined(OS_WIN)
   // Android does InitLogging when library is loaded. Skip here.
   // For windows we call InitLogging when the sandbox is initialized.
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 299b886..e8e2180 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -4660,6 +4660,9 @@
   <message name="IDS_KEYBOARD_OVERLAY_TOGGLE_CHROMEVOX_SPOKEN_FEEDBACK" desc="The text in the keyboard overlay to explain the shortcut (enable or disable spoken feedback).">
     ChromeVox (spoken feedback)
   </message>
+  <message name="IDS_KEYBOARD_OVERLAY_TOGGLE_HIGH_CONTRAST_MODE" desc="The text in the keyboard overlay to explain the shortcut (Toggle high contrast mode).">
+    Toggle High Contrast Mode
+  </message>
   <message name="IDS_KEYBOARD_OVERLAY_TOGGLE_PROJECTION_TOUCH_HUD" desc="The text in the keyboard overlay to explain the shortcut.">
     Projection touch HUD
   </message>
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 28c1112b..8d8eac98 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -1831,7 +1831,7 @@
       </message>
       <message name="IDS_MD_DOWNLOAD_SEARCH"
                desc="Placeholder text/label for the search input in the download page">
-        Search
+        Search downloads
       </message>
       <message name="IDS_DOWNLOAD_CLEAR_SEARCH"
                desc="Tooltip text for the button that clears the search term on the downloads page.">
@@ -1841,7 +1841,7 @@
         Search results for '<ph name="SEARCH_STRING">$1</ph>'
       </message>
       <message name="IDS_DOWNLOAD_NO_SEARCH_RESULTS" desc="A message shown for when a search yield no results (no matching downloads).">
-        No search results found.
+        No search results found
       </message>
       <message name="IDS_MD_DOWNLOAD_NO_DOWNLOADS" desc="A message shown when the user has no downloads to show on chrome://downloads.">
         Nothing to see here...
@@ -6050,6 +6050,12 @@
       <message name="IDS_FLAGS_ALLOW_NACL_SOCKET_API_DESCRIPTION" desc="Description for the NaCl Socket API feature.">
         Allows applications to use NaCl Socket API. Use only to test NaCl plugins.
       </message>
+      <message name="IDS_FLAGS_RUN_ALL_FLASH_IN_ALLOW_MODE_NAME" desc="Name for the Run all Flash in Allow mode feature.">
+        Run all Flash content when Flash setting is set to "allow"
+      </message>
+      <message name="IDS_FLAGS_RUN_ALL_FLASH_IN_ALLOW_MODE_DESCRIPTION" desc="Description for the Run all Flash in Allow mode feature.">
+        For sites that have been set to "allow" Flash content, run all content including any that has been deemed unimportant.
+      </message>
       <message name="IDS_FLAGS_PINCH_SCALE_NAME" desc="Name of the flag to turn on experiental pinch to scale.">
         Pinch scale
       </message>
@@ -7986,7 +7992,7 @@
         Some settings that may reflect browsing habits will not be cleared.
       </message>
       <message name="IDS_CLEAR_BROWSING_DATA_HISTORY_FOOTER" desc="A text shown at the bottom of the Clear Browsing Data dialog, informing the user that deleting Chrome browsing history will not delete other forms of history stored at Google My Activity.">
-        Your Google Account may have other forms of browsing history at <ph name="BEGIN_LINK">&lt;a target="_blank" href="$1"&gt;</ph>history.google.com<ph name="END_LINK">&lt;/a&gt;</ph>.
+        Your Google Account may have other forms of browsing history at <ph name="BEGIN_LINK">&lt;a target="_blank" href="$1"&gt;</ph>history.google.com<ph name="END_LINK">&lt;/a&gt;</ph>
       </message>
       <message name="IDS_CLEAR_BROWSING_DATA_HISTORY_NOTICE" desc="A dialog informing the user that their Chrome browsing history was deleted, but other forms of history can still be found on Google My Activity.">
         The selected data has been removed from Chrome and synced devices. Your Google Account may have other forms of browsing history like searches and activity from other Google services at <ph name="BEGIN_LINK">&lt;a target="_blank" href="$1"&gt;</ph>history.google.com<ph name="END_LINK">&lt;/a&gt;</ph>.
diff --git a/chrome/app/main_dll_loader_win.cc b/chrome/app/main_dll_loader_win.cc
index 35c43d2..f3a2b57 100644
--- a/chrome/app/main_dll_loader_win.cc
+++ b/chrome/app/main_dll_loader_win.cc
@@ -74,6 +74,10 @@
 
 typedef int (*InitMetro)();
 
+bool ProcessTypeUsesMainDll(const std::string& process_type) {
+  return process_type.empty() || process_type == switches::kServiceProcess;
+}
+
 }  // namespace
 
 //=============================================================================
@@ -87,7 +91,7 @@
 
 HMODULE MainDllLoader::Load(base::FilePath* module) {
   const base::char16* dll_name = nullptr;
-  if (process_type_ == switches::kServiceProcess || process_type_.empty()) {
+  if (ProcessTypeUsesMainDll(process_type_)) {
     dll_name = installer::kChromeDll;
   } else if (process_type_ == switches::kWatcherProcess) {
     dll_name = kChromeWatcherDll;
@@ -181,12 +185,12 @@
       reinterpret_cast<RelaunchChromeBrowserWithNewCommandLineIfNeededFunc>(
           ::GetProcAddress(dll_,
                            "RelaunchChromeBrowserWithNewCommandLineIfNeeded"));
-  if (!relaunch_function) {
-    LOG(ERROR) << "Could not find exported function "
-               << "RelaunchChromeBrowserWithNewCommandLineIfNeeded "
-               << "(" << process_type_ << " process)";
-  } else {
+  if (relaunch_function) {
     relaunch_function();
+  } else if (ProcessTypeUsesMainDll(process_type_)) {
+    LOG(DFATAL) << "Could not find exported function "
+                << "RelaunchChromeBrowserWithNewCommandLineIfNeeded "
+                << "(" << process_type_ << " process)";
   }
 }
 
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 39d023a3c..df9d210 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -216,10 +216,10 @@
     Search settings
   </message>
   <message name="IDS_SETTINGS_SEARCH_NO_RESULTS" desc="Text description of a search that has no results.">
-    No matches were found.
+    No match found
   </message>
   <message name="IDS_SETTINGS_SEARCH_NO_RESULTS_HELP" desc="Help text for a search that has no results.">
-    Go to <ph name="BEGIN_LINK_CHROMIUM">&lt;a target="_blank" href="$1"&gt;</ph>Google Chrome help<ph name="END_LINK_CHROMIUM">&lt;/a&gt;</ph> if you can't find what you're looking for.
+    Go to <ph name="BEGIN_LINK_CHROMIUM">&lt;a target="_blank" href="$1"&gt;</ph>Google Chrome help<ph name="END_LINK_CHROMIUM">&lt;/a&gt;</ph> if you can't find what you're looking for
   </message>
   <message name="IDS_SETTINGS_SETTINGS" desc="The settings page title.">
     Settings
@@ -1335,6 +1335,9 @@
   <message name="IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_ORDERING_INSTRUCTIONS" desc="Explanatory message about ordering the list of languages.">
     Order languages based on your preference.
   </message>
+  <message name="IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_MOVE_TO_TOP" desc="Label for the menu item that moves the language up to the top of the list of languages.">
+    Move to the top
+  </message>
   <message name="IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_MOVE_UP" desc="Label for the menu item that moves the language up in the list of languages.">
     Move up
   </message>
@@ -1354,6 +1357,9 @@
     <message name="IDS_SETTINGS_LANGUAGES_INPUT_METHODS_LIST_TITLE" desc="Title for the current input method in the header for the collapsible list of enabled input methods (keyboard layouts and input method editors).">
       Input method
     </message>
+    <message name="IDS_SETTINGS_LANGUAGES_INPUT_METHOD_ENABLED" desc="Label underneath the currently active input method in the list of enabled input methods.">
+      Enabled
+    </message>
     <message name="IDS_SETTINGS_LANGUAGES_INPUT_METHODS_EXPAND_ACCESSIBILITY_LABEL" desc="Label for the button that toggles showing the input options. Only visible by screen reader software.">
       Show input options
     </message>
diff --git a/chrome/app/theme/default_100_percent/common/infobar_alt_nav_url.png b/chrome/app/theme/default_100_percent/common/infobar_alt_nav_url.png
deleted file mode 100644
index 0e145743..0000000
--- a/chrome/app/theme/default_100_percent/common/infobar_alt_nav_url.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/infobar_theme.png b/chrome/app/theme/default_100_percent/common/infobar_theme.png
deleted file mode 100644
index 3711787..0000000
--- a/chrome/app/theme/default_100_percent/common/infobar_theme.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/infobar_alt_nav_url.png b/chrome/app/theme/default_200_percent/common/infobar_alt_nav_url.png
deleted file mode 100644
index 547e3a3..0000000
--- a/chrome/app/theme/default_200_percent/common/infobar_alt_nav_url.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/infobar_theme.png b/chrome/app/theme/default_200_percent/common/infobar_theme.png
deleted file mode 100644
index 8889ab75..0000000
--- a/chrome/app/theme/default_200_percent/common/infobar_theme.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd
index e60c433..0e57ada 100644
--- a/chrome/app/theme/theme_resources.grd
+++ b/chrome/app/theme/theme_resources.grd
@@ -259,7 +259,6 @@
       </if>
       <structure type="chrome_scaled_image" name="IDR_INFO" file="common/info_small.png" />
       <structure type="chrome_scaled_image" name="IDR_INFOBAR_3D_BLOCKED" file="common/infobar_3d_blocked.png" />
-      <structure type="chrome_scaled_image" name="IDR_INFOBAR_ALT_NAV_URL" file="common/infobar_alt_nav_url.png" />
       <structure type="chrome_scaled_image" name="IDR_INFOBAR_COOKIE" file="common/infobar_cookie.png" />
       <if expr="is_macosx">
         <structure type="chrome_scaled_image" name="IDR_INFOBAR_DESKTOP_NOTIFICATIONS" file="legacy/infobar_desktop_notifications.png" />
@@ -276,7 +275,6 @@
       <if expr="is_android">
         <structure type="chrome_scaled_image" name="IDR_INFOBAR_SAVE_PASSWORD" file="common/infobar_save_password.png" />
       </if>
-      <structure type="chrome_scaled_image" name="IDR_INFOBAR_THEME" file="common/infobar_theme.png" />
       <if expr="is_macosx or is_android">
         <structure type="chrome_scaled_image" name="IDR_INFOBAR_TRANSLATE" file="common/infobar_translate.png" />
       </if>
@@ -321,7 +319,7 @@
         <structure type="chrome_scaled_image" name="IDR_NETWORK_SHOW_PASSWORD" file="cros/network_show_password.png" />
         <structure type="chrome_scaled_image" name="IDR_NETWORK_SHOW_PASSWORD_HOVER" file="cros/network_show_password_hover.png" />
       </if>
-      <if expr="toolkit_views or is_macosx or is_ios">
+      <if expr="is_macosx or is_ios">
         <structure type="chrome_scaled_image" name="IDR_NEWTAB_BUTTON" file="common/newtab_normal.png" />
         <structure type="chrome_scaled_image" name="IDR_NEWTAB_BUTTON_H" file="common/newtab_hover.png" />
         <structure type="chrome_scaled_image" name="IDR_NEWTAB_BUTTON_MASK" file="common/newtab_button_mask.png" />
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index bb368cc..8a29ebc 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -969,6 +969,8 @@
     "renderer_context_menu/context_menu_content_type_factory.h",
     "renderer_context_menu/context_menu_content_type_panel.cc",
     "renderer_context_menu/context_menu_content_type_panel.h",
+    "renderer_host/chrome_navigation_ui_data.cc",
+    "renderer_host/chrome_navigation_ui_data.h",
     "renderer_host/chrome_render_message_filter.cc",
     "renderer_host/chrome_render_message_filter.h",
     "renderer_host/chrome_render_widget_host_view_mac_delegate.h",
@@ -3283,8 +3285,8 @@
       "password_manager/save_password_infobar_delegate_android.h",
       "password_manager/update_password_infobar_delegate_android.cc",
       "password_manager/update_password_infobar_delegate_android.h",
-      "permissions/grouped_permission_infobar_delegate.cc",
-      "permissions/grouped_permission_infobar_delegate.h",
+      "permissions/grouped_permission_infobar_delegate_android.cc",
+      "permissions/grouped_permission_infobar_delegate_android.h",
       "permissions/permission_queue_controller.cc",
       "permissions/permission_queue_controller.h",
       "permissions/permission_update_infobar_delegate_android.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 8c01371..7297067 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -904,6 +904,9 @@
     {"allow-nacl-socket-api", IDS_FLAGS_ALLOW_NACL_SOCKET_API_NAME,
      IDS_FLAGS_ALLOW_NACL_SOCKET_API_DESCRIPTION, kOsDesktop,
      SINGLE_VALUE_TYPE_AND_VALUE(switches::kAllowNaClSocketAPI, "*")},
+    {"run-all-flash-in-allow-mode", IDS_FLAGS_RUN_ALL_FLASH_IN_ALLOW_MODE_NAME,
+     IDS_FLAGS_RUN_ALL_FLASH_IN_ALLOW_MODE_DESCRIPTION, kOsDesktop,
+     FEATURE_VALUE_TYPE(features::kRunAllFlashInAllowMode)},
 #endif  // ENABLE_PLUGINS
 #if defined(OS_CHROMEOS)
     {"mash", IDS_FLAGS_USE_MASH_NAME, IDS_FLAGS_USE_MASH_DESCRIPTION, kOsCrOS,
diff --git a/chrome/browser/android/compositor/layer/contextual_search_layer.cc b/chrome/browser/android/compositor/layer/contextual_search_layer.cc
index bd1cf21..e9ab2ff 100644
--- a/chrome/browser/android/compositor/layer/contextual_search_layer.cc
+++ b/chrome/browser/android/compositor/layer/contextual_search_layer.cc
@@ -266,31 +266,38 @@
       AddBarTextLayer(search_caption_);
     }
     if (search_caption_resource) {
-        // Calculate position of the Caption, and the main bar text.
-        // Without a caption the bar text is not moved from it's default
-        // centered position. When there is a Caption interpolate its
-        // position between the default and adjusted (moved up by the
-        // size of the caption and margin).
-        float bar_text_height = bar_text_->bounds().height();
-        float search_caption_height = search_caption_resource->size.height();
-        float text_margin = floor(
-            (search_bar_height - bar_text_height - search_caption_height) / 5);
-        float search_caption_top =
-            search_bar_top + bar_text_height + text_margin * 2;
-        // Get the current centered position set up by the OverlayPanelLayer.
-        float bar_text_top_centered = bar_text_->position().y();
-        float bar_text_adjust = search_caption_height + text_margin;
-        float bar_text_top =
-            bar_text_top_centered -
-            bar_text_adjust * search_caption_animation_percentage / 2;
-        // Move the main bar text up.
-        bar_text_->SetPosition(gfx::PointF(0.f, bar_text_top));
-        // Add the caption
-        search_caption_->SetUIResourceId(
-            search_caption_resource->ui_resource->id());
-        search_caption_->SetBounds(search_caption_resource->size);
-        search_caption_->SetPosition(gfx::PointF(0.f, search_caption_top));
-        search_caption_->SetOpacity(search_caption_animation_percentage);
+      // Calculate position of the Caption and offset the main bar text and
+      // Search Context to allow for it.
+      // Without a caption they are not moved from their default centered
+      // positions. When there is a Caption interpolate their positions between
+      // the default and adjusted (moved up by the size of the caption and
+      // margin).
+      float bar_text_height = bar_text_->bounds().height();
+      float search_caption_height = search_caption_resource->size.height();
+      float text_margin = floor(
+          (search_bar_height - bar_text_height - search_caption_height) / 5);
+      float search_caption_top =
+          search_bar_top + bar_text_height + text_margin * 2;
+      // Get the current centered position set up by the OverlayPanelLayer.
+      float bar_text_top_centered = bar_text_->position().y();
+      float bar_text_adjust =
+          search_caption_animation_percentage *
+          (search_caption_height + text_margin) / 2;
+      float bar_text_top = bar_text_top_centered - bar_text_adjust;
+      // Move the main bar text up.
+      bar_text_->SetPosition(gfx::PointF(0.f, bar_text_top));
+      // Move the Search Context up.
+      if (search_context_resource) {
+        float search_context_top =
+            search_context_->position().y() - bar_text_adjust;
+        search_context_->SetPosition(gfx::PointF(0.f, search_context_top));
+      }
+      // Add the caption
+      search_caption_->SetUIResourceId(
+          search_caption_resource->ui_resource->id());
+      search_caption_->SetBounds(search_caption_resource->size);
+      search_caption_->SetPosition(gfx::PointF(0.f, search_caption_top));
+      search_caption_->SetOpacity(search_caption_animation_percentage);
     }
   } else if (search_caption_.get() && search_caption_->parent()) {
     search_caption_->RemoveFromParent();
diff --git a/chrome/browser/android/download/download_controller.cc b/chrome/browser/android/download/download_controller.cc
index 337b8ab62..024bef0 100644
--- a/chrome/browser/android/download/download_controller.cc
+++ b/chrome/browser/android/download/download_controller.cc
@@ -217,11 +217,6 @@
       RequestFileAccess(callback_id);
 }
 
-void DownloadController::SetDefaultDownloadFileName(
-    const std::string& file_name) {
-  default_file_name_ = file_name;
-}
-
 bool DownloadController::HasFileAccessPermission(
     ui::WindowAndroid* window_android) {
   ScopedJavaLocalRef<jobject> jwindow_android = window_android->GetJavaObject();
diff --git a/chrome/browser/android/download/download_controller.h b/chrome/browser/android/download/download_controller.h
index 163e815..737e380 100644
--- a/chrome/browser/android/download/download_controller.h
+++ b/chrome/browser/android/download/download_controller.h
@@ -48,7 +48,6 @@
   void AcquireFileAccessPermission(
       content::WebContents* web_contents,
       const AcquireFileAccessPermissionCallback& callback) override;
-  void SetDefaultDownloadFileName(const std::string& file_name) override;
 
   // UMA histogram enum for download cancellation reasons. Keep this
   // in sync with MobileDownloadCancelReason in histograms.xml. This should be
diff --git a/chrome/browser/android/download/download_controller_base.h b/chrome/browser/android/download/download_controller_base.h
index c317ed4..ec85098 100644
--- a/chrome/browser/android/download/download_controller_base.h
+++ b/chrome/browser/android/download/download_controller_base.h
@@ -88,10 +88,6 @@
   // Called by unit test to approve or disapprove file access request.
   virtual void SetApproveFileAccessRequestForTesting(bool approve) {}
 
-  // Called to set the default download file name if it cannot be resolved
-  // from url and content disposition
-  virtual void SetDefaultDownloadFileName(const std::string& file_name) {}
-
  protected:
   ~DownloadControllerBase() override {}
   static DownloadControllerBase* download_controller_;
diff --git a/chrome/browser/android/download/download_manager_service.cc b/chrome/browser/android/download/download_manager_service.cc
index 5630e66..9b4fa66b 100644
--- a/chrome/browser/android/download/download_manager_service.cc
+++ b/chrome/browser/android/download/download_manager_service.cc
@@ -111,8 +111,6 @@
     JNIEnv* env,
     jobject obj) {
   java_ref_.Reset(env, obj);
-  DownloadControllerBase::Get()->SetDefaultDownloadFileName(
-      l10n_util::GetStringUTF8(IDS_DEFAULT_DOWNLOAD_FILENAME));
 }
 
 void DownloadManagerService::ResumeDownload(
diff --git a/chrome/browser/android/ntp/ntp_snippets_bridge.cc b/chrome/browser/android/ntp/ntp_snippets_bridge.cc
index 6b0c9fe..88d9729 100644
--- a/chrome/browser/android/ntp/ntp_snippets_bridge.cc
+++ b/chrome/browser/android/ntp/ntp_snippets_bridge.cc
@@ -20,7 +20,7 @@
 #include "components/history/core/browser/history_service.h"
 #include "components/ntp_snippets/content_suggestion.h"
 #include "components/ntp_snippets/content_suggestions_metrics.h"
-#include "components/ntp_snippets/ntp_snippets_service.h"
+#include "components/ntp_snippets/remote/ntp_snippets_service.h"
 #include "jni/SnippetsBridge_jni.h"
 #include "ui/base/window_open_disposition.h"
 #include "ui/gfx/android/java_bitmap.h"
@@ -201,7 +201,8 @@
       Java_SnippetsBridge_createSuggestionList(env);
   for (const ContentSuggestion& suggestion : suggestions) {
     Java_SnippetsBridge_addSuggestion(
-        env, result, category, ConvertUTF8ToJavaString(env, suggestion.id()),
+        env, result, category,
+        ConvertUTF8ToJavaString(env, suggestion.id().id_within_category()),
         ConvertUTF16ToJavaString(env, suggestion.title()),
         ConvertUTF16ToJavaString(env, suggestion.publisher_name()),
         ConvertUTF16ToJavaString(env, suggestion.snippet_text()),
@@ -216,11 +217,13 @@
 void NTPSnippetsBridge::FetchSuggestionImage(
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
-    const JavaParamRef<jstring>& suggestion_id,
+    jint category,
+    const JavaParamRef<jstring>& id_within_category,
     const JavaParamRef<jobject>& j_callback) {
   base::android::ScopedJavaGlobalRef<jobject> callback(j_callback);
   content_suggestions_service_->FetchSuggestionImage(
-      ConvertJavaStringToUTF8(env, suggestion_id),
+      ContentSuggestion::ID(CategoryFromIDValue(category),
+                            ConvertJavaStringToUTF8(env, id_within_category)),
       base::Bind(&NTPSnippetsBridge::OnImageFetched,
                  weak_ptr_factory_.GetWeakPtr(), callback));
 }
@@ -228,9 +231,11 @@
 void NTPSnippetsBridge::DismissSuggestion(
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
-    const JavaParamRef<jstring>& suggestion_id) {
+    jint category,
+    const JavaParamRef<jstring>& id_within_category) {
   content_suggestions_service_->DismissSuggestion(
-      ConvertJavaStringToUTF8(env, suggestion_id));
+      ContentSuggestion::ID(CategoryFromIDValue(category),
+                            ConvertJavaStringToUTF8(env, id_within_category)));
 }
 
 void NTPSnippetsBridge::DismissCategory(JNIEnv* env,
@@ -357,15 +362,14 @@
 }
 
 void NTPSnippetsBridge::OnSuggestionInvalidated(
-    Category category,
-    const std::string& suggestion_id) {
+    const ContentSuggestion::ID& suggestion_id) {
   if (observer_.is_null())
     return;
 
   JNIEnv* env = base::android::AttachCurrentThread();
   Java_SnippetsBridge_onSuggestionInvalidated(
-      env, observer_.obj(), static_cast<int>(category.id()),
-      ConvertUTF8ToJavaString(env, suggestion_id).obj());
+      env, observer_.obj(), static_cast<int>(suggestion_id.category().id()),
+      ConvertUTF8ToJavaString(env, suggestion_id.id_within_category()).obj());
 }
 
 void NTPSnippetsBridge::ContentSuggestionsServiceShutdown() {
diff --git a/chrome/browser/android/ntp/ntp_snippets_bridge.h b/chrome/browser/android/ntp/ntp_snippets_bridge.h
index e5332b8..3f94cb4 100644
--- a/chrome/browser/android/ntp/ntp_snippets_bridge.h
+++ b/chrome/browser/android/ntp/ntp_snippets_bridge.h
@@ -54,13 +54,15 @@
   void FetchSuggestionImage(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
-      const base::android::JavaParamRef<jstring>& suggestion_id,
+      jint category,
+      const base::android::JavaParamRef<jstring>& id_within_category,
       const base::android::JavaParamRef<jobject>& j_callback);
 
   void DismissSuggestion(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
-      const base::android::JavaParamRef<jstring>& suggestion_id);
+      jint category,
+      const base::android::JavaParamRef<jstring>& id_within_category);
 
   void DismissCategory(JNIEnv* env,
                        const base::android::JavaParamRef<jobject>& obj,
@@ -124,8 +126,8 @@
   void OnCategoryStatusChanged(
       ntp_snippets::Category category,
       ntp_snippets::CategoryStatus new_status) override;
-  void OnSuggestionInvalidated(ntp_snippets::Category category,
-                               const std::string& suggestion_id) override;
+  void OnSuggestionInvalidated(
+      const ntp_snippets::ContentSuggestion::ID& suggestion_id) override;
   void ContentSuggestionsServiceShutdown() override;
 
   void OnImageFetched(base::android::ScopedJavaGlobalRef<jobject> callback,
diff --git a/chrome/browser/android/ntp/ntp_snippets_launcher.h b/chrome/browser/android/ntp/ntp_snippets_launcher.h
index fb90ba8..2dfbb4b 100644
--- a/chrome/browser/android/ntp/ntp_snippets_launcher.h
+++ b/chrome/browser/android/ntp/ntp_snippets_launcher.h
@@ -9,7 +9,7 @@
 #include "base/lazy_instance.h"
 #include "base/macros.h"
 #include "base/time/time.h"
-#include "components/ntp_snippets/ntp_snippets_scheduler.h"
+#include "components/ntp_snippets/remote/ntp_snippets_scheduler.h"
 
 // Android implementation of ntp_snippets::NTPSnippetsScheduler.
 // The NTPSnippetsLauncher singleton owns the Java SnippetsLauncher object, and
diff --git a/chrome/browser/android/vr_shell/BUILD.gn b/chrome/browser/android/vr_shell/BUILD.gn
index 53c203e..9211540c 100644
--- a/chrome/browser/android/vr_shell/BUILD.gn
+++ b/chrome/browser/android/vr_shell/BUILD.gn
@@ -39,8 +39,6 @@
     "//content/public/browser",
     "//content/public/common",
     "//device/vr",
-    "//third_party/gvr-android-sdk:gvr_base_java",
-    "//third_party/gvr-android-sdk:gvr_common_java",
     "//third_party/gvr-android-sdk:libgvr",
     "//ui/android",
     "//ui/base",
diff --git a/chrome/browser/android/webapk/webapk_web_manifest_checker_unittest.cc b/chrome/browser/android/webapk/webapk_web_manifest_checker_unittest.cc
index 404b35c6..6d6f1fe 100644
--- a/chrome/browser/android/webapk/webapk_web_manifest_checker_unittest.cc
+++ b/chrome/browser/android/webapk/webapk_web_manifest_checker_unittest.cc
@@ -24,7 +24,7 @@
   manifest.display = blink::WebDisplayModeStandalone;
 
   content::Manifest::Icon icon;
-  icon.type = ToNullableUTF16("image/png");
+  icon.type = base::ASCIIToUTF16("image/png");
   icon.sizes.push_back(gfx::Size(144, 144));
   manifest.icons.push_back(icon);
 
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 5f447423..3685359 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
+++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
@@ -114,8 +114,6 @@
   WebApplicationInfo web_app_info = received_web_app_info;
   web_app_info.title =
       web_app_info.title.substr(0, chrome::kMaxMetaTagAttributeLength);
-  web_app_info.description =
-      web_app_info.description.substr(0, chrome::kMaxMetaTagAttributeLength);
 
   // Simply set the user-editable title to be the page's title
   shortcut_info_.user_title = web_app_info.title.empty()
@@ -211,6 +209,11 @@
         (data.error_code == NO_ERROR_DETECTED &&
          AreWebManifestUrlsWebApkCompatible(data.manifest));
     weak_observer_->OnDidDetermineWebApkCompatibility(webapk_compatible);
+
+    // WebAPKs are wholly defined by the Web Manifest. Ignore the <meta> tag
+    // data received in OnDidGetWebApplicationInfo().
+    if (webapk_compatible)
+      shortcut_info_ = ShortcutInfo(GURL());
   }
 
   if (!data.manifest.IsEmpty()) {
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 4bde273..b9180b2 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
@@ -14,6 +14,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/nullable_string16.h"
+#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "chrome/common/web_application_info.h"
@@ -96,7 +97,11 @@
 // called.
 class ObserverWaiter : public AddToHomescreenDataFetcher::Observer {
  public:
-  ObserverWaiter() {}
+  ObserverWaiter()
+      : is_webapk_compatible_(false),
+        determined_webapk_compatibility_(false),
+        title_available_(false),
+        data_available_(false) {}
   ~ObserverWaiter() override {}
 
   // Waits till the OnDataAvailable() callback is called.
@@ -275,6 +280,59 @@
   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) {
+  WebApplicationInfo web_application_info;
+  web_application_info.title = base::UTF8ToUTF16("Meta Title");
+
+  content::Manifest manifest(BuildDefaultManifest());
+  manifest.name = base::NullableString16();
+
+  RegisterServiceWorker(GURL(kDefaultStartUrl));
+  SetManifest(GURL(kDefaultManifestUrl), manifest, 0);
+
+  ObserverWaiter waiter;
+  scoped_refptr<AddToHomescreenDataFetcher> fetcher(BuildFetcher(&waiter));
+  fetcher->OnDidGetWebApplicationInfo(web_application_info);
+  waiter.WaitForDataAvailable();
+
+  EXPECT_TRUE(base::EqualsASCII(fetcher->shortcut_info().name,
+                                kDefaultManifestShortName));
+
+  fetcher->set_weak_observer(nullptr);
+}
+
+// Test that when the manifest does not provide either Manifest::short_name nor
+// Manifest::name that:
+// - 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);
+
+    content::Manifest manifest(BuildDefaultManifest());
+    manifest.name = base::NullableString16();
+    manifest.short_name = base::NullableString16();
+
+    RegisterServiceWorker(GURL(kDefaultStartUrl));
+    SetManifest(GURL(kDefaultManifestUrl), manifest, 0);
+
+    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));
+
+    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, ManifestFetchTimesOut) {
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 3d002da..5a32e520 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -1067,6 +1067,13 @@
   CacheDefaultWebClientState();
 
   platform_part_->PreMainMessageLoopRun();
+
+  if (base::FeatureList::IsEnabled(network_time::kNetworkTimeServiceQuerying)) {
+    network_time_tracker_.reset(new network_time::NetworkTimeTracker(
+        base::WrapUnique(new base::DefaultClock()),
+        base::WrapUnique(new base::DefaultTickClock()), local_state(),
+        system_request_context()));
+  }
 }
 
 void BrowserProcessImpl::CreateIconManager() {
diff --git a/chrome/browser/chooser_controller/mock_chooser_controller.cc b/chrome/browser/chooser_controller/mock_chooser_controller.cc
index 34f21ff..3595585 100644
--- a/chrome/browser/chooser_controller/mock_chooser_controller.cc
+++ b/chrome/browser/chooser_controller/mock_chooser_controller.cc
@@ -154,6 +154,8 @@
 const int MockChooserController::kSignalStrengthLevel2Bar = 2;
 const int MockChooserController::kSignalStrengthLevel3Bar = 3;
 const int MockChooserController::kSignalStrengthLevel4Bar = 4;
+const int MockChooserController::kImageColorUnselected = 0;
+const int MockChooserController::kImageColorSelected = 1;
 
 void MockChooserController::ClearAllOptions() {
   options_.clear();
diff --git a/chrome/browser/chooser_controller/mock_chooser_controller.h b/chrome/browser/chooser_controller/mock_chooser_controller.h
index 5b486e3eb..06fac53e 100644
--- a/chrome/browser/chooser_controller/mock_chooser_controller.h
+++ b/chrome/browser/chooser_controller/mock_chooser_controller.h
@@ -58,6 +58,8 @@
   static const int kSignalStrengthLevel2Bar;
   static const int kSignalStrengthLevel3Bar;
   static const int kSignalStrengthLevel4Bar;
+  static const int kImageColorUnselected;
+  static const int kImageColorSelected;
 
  private:
   void ClearAllOptions();
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 0b6a59a..c10195bc 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -66,6 +66,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/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"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
@@ -1676,7 +1677,6 @@
       switches::kForcePNaClSubzero,
 #endif
       switches::kJavaScriptHarmony,
-      switches::kMessageLoopHistogrammer,
       switches::kOriginTrialDisabledFeatures,
       switches::kOriginTrialPublicKey,
       switches::kPpapiFlashArgs,
@@ -3164,6 +3164,12 @@
   return throttles;
 }
 
+std::unique_ptr<content::NavigationUIData>
+ChromeContentBrowserClient::GetNavigationUIData(
+    content::NavigationHandle* navigation_handle) {
+  return base::MakeUnique<ChromeNavigationUIData>(navigation_handle);
+}
+
 content::DevToolsManagerDelegate*
 ChromeContentBrowserClient::GetDevToolsManagerDelegate() {
 #if defined(OS_ANDROID)
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index 61a2f96..80a2eec 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -311,6 +311,8 @@
   void RecordURLMetric(const std::string& metric, const GURL& url) override;
   ScopedVector<content::NavigationThrottle> CreateThrottlesForNavigation(
       content::NavigationHandle* handle) override;
+  std::unique_ptr<content::NavigationUIData> GetNavigationUIData(
+      content::NavigationHandle* navigation_handle) override;
 
  private:
   friend class DisableWebRtcEncryptionFlagTest;
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 16650f0..b88b0e0 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -84,6 +84,7 @@
     "//dbus",
     "//device/bluetooth",
     "//device/hid",
+    "//extensions/browser/kiosk",
     "//mash/public/interfaces",
     "//media",
     "//media/mojo/interfaces",
diff --git a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc
index b43173d..f930fe5 100644
--- a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc
+++ b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc
@@ -370,45 +370,31 @@
 // [1] https://developer.chrome.com/apps/declare_permissions
 // [2] https://developer.chrome.com/apps/api_other
 const char* const kSafePermissionStrings[] = {
-    // Risky: Reading accessibility settings could allow to infer health
-    // information.
-    // "accessibilityFeatures.read",
-
     // Modifying accessibility settings seems safe (at most a user could be
     // confused by it).
     "accessibilityFeatures.modify",
 
+    // Originally blocked due to concerns about leaking user health information,
+    // but it seems this does more harm than good as it would likely prevent the
+    // extension from enabling assistive features. If the concerns prevail, we
+    // should probably not block, but adjust the API to pretend accessibility is
+    // off, so we don't punish apps that try to be helpful.
+    "accessibilityFeatures.read",
+
+    // Allows access to web contents in response to user gesture. Note that this
+    // doesn't trigger a permission warning on install though, so blocking is
+    // somewhat at odds with the spirit of the API - however I presume the API
+    // design assumes user-installed extensions, which we don't have here.
+    // "activeTab",
+
     // Schedule code to run at future times.
     "alarms",
 
-    // Risk of listening attack.
-    // "audio",
+    // Allow, but keep PS UX on top regardless.
+    // "app.window.alwaysOnTop",
 
-    // Risk of listening attack.
-    // "audioCapture",
-
-    // Just resource management, probably doesn't even apply to Chrome OS.
-    "background",
-
-    // Open a new tab with a given URL.
-    "browser",
-
-    // Risky: Reading from clipboard could expose private information.
-    // "clipboardRead",
-
-    // Writing to clipboard is safe.
-    "clipboardWrite",
-
-    // Potentially risky: Could be used to spoof system UI.
-    // "contextMenus",
-
-    // Placing a document on the scanner implies user consent.
-    "documentScan",
-
-    // Possibly risky due to its experimental nature: not vetted for security,
-    // potentially buggy, subject to change without notice.
-    // "experimental",
-
+    // TODO(isandrk): The following permissions need to be adjusted
+    // (crbug/651071).
     // Fullscreen is a no-op for Public Session.  Whitelisting nevertheless to
     // broaden the range of supported apps.  (The recommended permission names
     // are "app.window.*" but their unprefixed counterparts are still
@@ -418,88 +404,284 @@
     "fullscreen",
     "overrideEscFullscreen",
 
-    // TBD
-    // "fileSystemProvider",
+    "app.window.shape",
+
+    // The embedded app is subject to the restrictions as well obviously.
+    "appview",
+
+    // Risk of listening attack.
+    // "audio",
+
+    // Need to surface notification to the user. Check what existing UI we have
+    // and whether that's sufficient for PS.
+    // "audioCapture",
+
+    // Just resource management, probably doesn't even apply to Chrome OS.
+    "background",
+
+    // Access to URLs only, no content.
+    "bookmarks",
+
+    // Open a new tab with a given URL.
+    "browser",
+
+    // This allows to read the current browsing data removal dialog settings,
+    // but I don't see why this would be problematic.
+    "browsingData",
+
+    "certificateProvider",
+
+    // This is risky, but blocking extensions just because they declare
+    // clipboardRead is unfortunate. Options: (1) Make clipboardRead return
+    // empty string (2) confirmation dialog.
+    // "clipboardRead",
+
+    // Writing to clipboard is safe.
+    "clipboardWrite",
+
+    "contentSettings",
+
+    // Provides access to URLs.
+    "contextMenus",
+
+    // This would provie access to auth cookies, so needs to be blocked.
+    // "cookies",
+
+    // Provides access to the DOM, so block.
+    // "debugger",
+
+    // This is mostly fine, but has a RequestContentScript action that'd allow
+    // access to page content, which we can't allow.
+    // "declarativeContent",
+
+    // Allow, but either (1) ask user for confirmation or (2) return blank
+    // capture.
+    // "desktopCapture",
+
+    // Haven't checked in detail what this does, but messing with devtools
+    // usually comes with the ability to access page content.
+    // "devtools",
+
+    // I think it's fine to allow this as it should be obvious to users that
+    // scanning a document on the scanner will make it available to the
+    // organization (placing a document in the scanner implies user consent).
+    "documentScan",
+
+    // Doesn't allow access to file contents AFAICT, so should be fine.
+    "downloads",
+
+    // Triggers a file open for the download.
+    "downloads.open",
+
+    // Controls shelf visibility.
+    "downloads.shelf",
+
+    "enterprise.deviceAttributes",
+
+    "enterprise.platformKeys",
+
+    // Possibly risky due to its experimental nature: not vetted for security,
+    // potentially buggy, subject to change without notice (shouldn't
+    // blanket-allow experimental stuff).
+    // "experimental",
+
+    "fileBrowserHandler",
+
+    // Allow: (1) session state is ephemeral anyways, so no leaks across users.
+    // (2) a user that stores data on an org-owned machine won't be surprised if
+    // the org can see it.
+    "fileSystem",
+
+    "fileSystem.directory",
+
+    "fileSystem.requestFileSystem",
+
+    "fileSystem.retainEntries",
+
+    "fileSystem.write",
+
+    "fileSystemProvider",
+
+    "fontSettings",
 
     // Just another type of connectivity.  On the system side, no user data is
     // involved, implicitly or explicity.
     "gcm",
 
-    // Risky: Accessing location without explicit user consent.
-    // "geolocation",
+    // It's fair game for a kiosk device owner to locate their device. Could
+    // just as well do this via IP-geolocation mechanism, so little difference.
+    "geolocation",
 
-    // Risky: Potentially allows keylogging.
-    // "hid",
+    // Somewhat risky as this opens up the ability to intercept user input.
+    // However, keyboards and mice are apparently not surfaced via this API.
+    "hid",
+
+    // Just URLs and meta data.
+    "history",
+
+    // Not really useful as there's no signed-in user, so OK to allow.
+    "identity",
+
+    "identity.email",
 
     // Detection of idle state.
     "idle",
 
-    // Dev channel only.  Not evaluated.
-    // "location",
+    // IME extensions see keystrokes. This might be useful though, might rely on
+    // manual whitelisting (assuming the number of useful IME extensions is
+    // relatively limited).
+    // "input",
+
+    // Fair game - admin can manipulate extensions via policy anyways.
+    "management",
 
     // Just another type of connectivity.
     "mdns",
 
-    // Risky: The "allAutoDectected" option could allow access to user data
-    // without their consent.
-    // "mediaGalleries",
+    // Storage is ephemeral, so user needs to get their content onto the Kiosk
+    // device (download or plug in media), both of which seem sufficient consent
+    // actions.
+    "mediaGalleries",
 
-    // Potentially risky: Could be used to spoof system UI.
-    // "notifications",
+    "mediaGalleries.allAutoDetected",
 
-    // TBD.  Could allow UX spoofing.
-    // "pointerLock",
+    "mediaGalleries.copyTo",
+
+    "mediaGalleries.delete",
+
+    "mediaGalleries.read",
+
+    // Probably doesn't work on Chrome OS anyways.
+    "nativeMessaging",
+
+    // Admin controls network connectivity anyways.
+    "networking.config",
+
+    // Status quo considers this risky due to the ability to fake system UI -
+    // low risk IMHO however since notifications are already badged with app
+    // icon and won't extract any data.
+    "notifications",
+
+    // Captures page content, so block. Alternatively: Allow, but either (1)
+    // prompt user or (2) return blank content.
+    // "pageCapture",
+
+    // Allows to use machine crypto keys - these would be provisioned by the
+    // admin anyways.
+    "platformKeys",
+
+    // No plugins on Chrome OS anyways.
+    "plugin",
+
+    // Status quo notes concern about UX spoofing - not an issue IMHO.
+    "pointerLock",
 
     // Potentiall risky: chrome.power.requestKeepAwake can inhibit idle time
     // detection and prevent idle time logout and that way reduce isolation
     // between subsequent Public Session users.
+    // OK to allow as long as it doesn't affect PS idle time detection.
     // "power",
 
-    // Risky: Could be used to siphon printed documents.
-    // "printerProvider",
+    // Printing initiated by user anyways, which provides consent gesture.
+    "printerProvider",
+
+    // The settings exposed via the API are under admin policy control anyways.
+    "privacy",
+
+    // Admin controls network anyways.
+    "proxy",
+
+    "runtime",
+
+    // Looking at the code, this feature is declared but used nowhere.
+    // "screensaver",
 
     // Access serial port.  It's hard to conceive a case in which private data
     // is stored on a serial device and being read without the user's consent.
+    // Minor risk of intercepting input events from serial input devices - given
+    // that serial input devices are exceedingly rare, OK to allow.
     "serial",
 
+    // Access to URLs.
+    "sessions",
+
+    "socket",
+
     // Per-app sandbox.  User cannot log into Public Session, thus storage
     // cannot be sync'ed to the cloud.
     "storage",
 
-    // Access system parameters.
+    // Not very useful since no signed-in user.
+    "syncFileSystem",
+
+    // Returns CPU parameters.
     "system.cpu",
 
-    // Access system parameters.
+    // Display parameters query/manipulation.
     "system.display",
 
-    // Access system parameters.
+    // Memory parameters access.
     "system.memory",
 
-    // Access system parameters.
+    // Enumerates network interfaces.
     "system.network",
 
-    // Risky: Could leak the name of a user-supplied storage medium.
-    // "system.storage",
+    // Enumerates removable storage.
+    "system.storage",
 
-    // Just UX.
+    // Provides access to screen contents, so block. Alternatively, (1) prompt
+    // for user consent or (2) return blank capture.
+    // "tabCapture",
+
+    // URLs and page titles.
+    "tabs",
+
+    // URLs and page titles.
+    "topSites",
+
+    // Allows to generate TTS, but no content access. Just UX.
     "tts",
 
+    // Might need this, but has content access. Manual whitelisting?
+    // "ttsEngine",
+
     // Excessive resource usage is not a risk.
     "unlimitedStorage",
 
-    // Risky: Raw peripheral access could allow an app to read user data from
-    // USB storage devices that have been plugged in by the user.  Not sure if
-    // that can happen though, because the system might claim storage devices
-    // for itself.  Still, leaving disallowed for now to be on the safe side.
-    // "usb",
+    // Plugging the USB device is sufficient as consent gesture.
+    "usb",
 
-    // TBD: What if one user connects and the next one is unaware of that?
-    // "vpnProvider",
+    // Belongs to the USB API.
+    "usbDevices",
+
+    // Need to surface notification to the user. Check what existing UI we have
+    // and whether that's sufficient for PS.
+    // "videoCapture",
+
+    // Admin controls network config anyways.
+    "vpnProvider",
 
     // Just UX.
     "wallpaper",
 
-    // Web capabilities are safe.
+    // Access to URLs.
+    "webNavigation",
+
+    // Provides access to cookies and form upload data. Options: (1) block,
+    // (2) strip all content in events.
+    // "webRequest",
+
+    // Fine once webRequest is adjusted.
+    // "webRequestBlocking",
+
+    // This allows content scripts and capturing. However, the webview runs
+    // within a separate storage partition, i.e. doesn't share cookies and other
+    // storage with the browsing session. Furthermore, the embedding app could
+    // just as well proxy 3rd-party origin content through its own web origin
+    // server-side or via chrome.socket. Finally, web security doesn't make a
+    // lot of sense when there's no URL bar or HTTPS padlock providing trusted
+    // UI. Bottom line: Risks are mitigated, further restrictions don't make
+    // sense, so OK to allow.
     "webview",
 };
 
@@ -717,6 +899,7 @@
       return true;
     }
 
+    // TODO(isandrk): Remove when whitelisting work is done (crbug/651027).
     // Allow extension if its type is whitelisted for use in public sessions.
     if (extension->GetType() == extensions::Manifest::TYPE_HOSTED_APP) {
       return true;
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc
index cd0190a..f0afec2 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc
@@ -83,6 +83,7 @@
                                       EntryProperties* properties) {
   properties->shared_with_me.reset(new bool(shared_with_me));
   properties->shared.reset(new bool(entry_proto.shared()));
+  properties->starred.reset(new bool(entry_proto.starred()));
 
   const drive::PlatformFileInfoProto& file_info = entry_proto.file_info();
   properties->size.reset(new double(file_info.size()));
diff --git a/chrome/browser/content_settings/content_settings_browsertest.cc b/chrome/browser/content_settings/content_settings_browsertest.cc
index 1bebedb..a2b8610 100644
--- a/chrome/browser/content_settings/content_settings_browsertest.cc
+++ b/chrome/browser/content_settings/content_settings_browsertest.cc
@@ -53,7 +53,6 @@
 #endif
 
 #if defined(ENABLE_PEPPER_CDMS)
-#include "chrome/browser/media/pepper_cdm_test_constants.h"
 #include "chrome/browser/media/pepper_cdm_test_helper.h"
 #endif
 
@@ -356,14 +355,16 @@
 #endif
   }
 
-#if defined(ENABLE_PEPPER_CDMS)
+#if defined(ENABLE_PEPPER_CDMS) && defined(WIDEVINE_CDM_AVAILABLE)
+  // Since the CDM is bundled and registered through the component updater,
+  // we must re-enable the component updater.
   void SetUpDefaultCommandLine(base::CommandLine* command_line) override {
     base::CommandLine default_command_line(base::CommandLine::NO_PROGRAM);
     InProcessBrowserTest::SetUpDefaultCommandLine(&default_command_line);
     test_launcher_utils::RemoveCommandLineSwitch(
         default_command_line, switches::kDisableComponentUpdate, command_line);
   }
-#endif  // defined(ENABLE_PEPPER_CDMS)
+#endif  // defined(ENABLE_PEPPER_CDMS) && defined(WIDEVINE_CDM_AVAILABLE)
 
   void SetUpInProcessBrowserTestFixture() override {
     ContentSettingsTest::SetUpInProcessBrowserTestFixture();
diff --git a/chrome/browser/data_use_measurement/chrome_data_use_ascriber_service.cc b/chrome/browser/data_use_measurement/chrome_data_use_ascriber_service.cc
index 7e01b59..ebd021d6 100644
--- a/chrome/browser/data_use_measurement/chrome_data_use_ascriber_service.cc
+++ b/chrome/browser/data_use_measurement/chrome_data_use_ascriber_service.cc
@@ -30,14 +30,16 @@
 namespace data_use_measurement {
 
 ChromeDataUseAscriberService::ChromeDataUseAscriberService()
-    : ascriber_(nullptr) {
+    : ascriber_(nullptr), is_initialized_(false) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   // Skip IO thread initialization if there is no IO thread. This check is
   // required because unit tests that do no set up an IO thread can cause this
   // code to execute.
-  if (!g_browser_process->io_thread())
+  if (!g_browser_process->io_thread()) {
+    is_initialized_ = true;
     return;
+  }
 
   content::BrowserThread::PostTaskAndReplyWithResult(
       content::BrowserThread::IO, FROM_HERE,
@@ -54,6 +56,11 @@
     content::RenderFrameHost* render_frame_host) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
+  if (!is_initialized_) {
+    pending_frames_queue_.push_back(render_frame_host);
+    return;
+  }
+
   if (!ascriber_)
     return;
 
@@ -77,6 +84,14 @@
     content::RenderFrameHost* render_frame_host) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
+  if (!is_initialized_) {
+    // While remove() is a O(n) operation, the pending queue is not expected
+    // to have a significant number of elements.
+    DCHECK_GE(50u, pending_frames_queue_.size());
+    pending_frames_queue_.remove(render_frame_host);
+    return;
+  }
+
   if (!ascriber_)
     return;
 
@@ -101,7 +116,15 @@
     content::NavigationHandle* navigation_handle) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  if (!ascriber_ || !navigation_handle->IsInMainFrame())
+  if (!navigation_handle->IsInMainFrame())
+    return;
+
+  if (!is_initialized_) {
+    pending_navigations_queue_.push_back(navigation_handle);
+    return;
+  }
+
+  if (!ascriber_)
     return;
 
   content::WebContents* web_contents = navigation_handle->GetWebContents();
@@ -118,7 +141,18 @@
     content::NavigationHandle* navigation_handle) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  if (!ascriber_ || !navigation_handle->IsInMainFrame())
+  if (!navigation_handle->IsInMainFrame())
+    return;
+
+  if (!is_initialized_) {
+    // While remove() is a O(n) operation, the pending queue is not expected
+    // to have a significant number of elements.
+    DCHECK_GE(50u, pending_navigations_queue_.size());
+    pending_navigations_queue_.remove(navigation_handle);
+    return;
+  }
+
+  if (!ascriber_)
     return;
 
   content::WebContents* web_contents = navigation_handle->GetWebContents();
@@ -137,7 +171,10 @@
     content::NavigationHandle* navigation_handle) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  if (!ascriber_ || !navigation_handle->IsInMainFrame())
+  if (!is_initialized_ || !navigation_handle->IsInMainFrame())
+    return;
+
+  if (!ascriber_)
     return;
 
   content::WebContents* web_contents = navigation_handle->GetWebContents();
@@ -152,9 +189,21 @@
 
 void ChromeDataUseAscriberService::SetDataUseAscriber(
     ChromeDataUseAscriber* ascriber) {
+  DCHECK(!is_initialized_);
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   ascriber_ = ascriber;
+  is_initialized_ = true;
+
+  for (auto& it : pending_frames_queue_) {
+    RenderFrameCreated(it);
+  }
+  pending_frames_queue_.clear();
+
+  for (auto& it : pending_navigations_queue_) {
+    DidStartNavigation(it);
+  }
+  pending_navigations_queue_.clear();
 }
 
 }  // namespace data_use_measurement
diff --git a/chrome/browser/data_use_measurement/chrome_data_use_ascriber_service.h b/chrome/browser/data_use_measurement/chrome_data_use_ascriber_service.h
index 006e212..04c8c84 100644
--- a/chrome/browser/data_use_measurement/chrome_data_use_ascriber_service.h
+++ b/chrome/browser/data_use_measurement/chrome_data_use_ascriber_service.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_DATA_USE_MEASUREMENT_CHROME_DATA_USE_ASCRIBER_SERVICE_H_
 #define CHROME_BROWSER_DATA_USE_MEASUREMENT_CHROME_DATA_USE_ASCRIBER_SERVICE_H_
 
+#include <list>
+
 #include "base/macros.h"
 #include "components/keyed_service/core/keyed_service.h"
 
@@ -25,8 +27,7 @@
 // WebContentsObservers to propagate events to itself because each
 // WebContents instance requires its own WebContentsObserver instance.
 //
-// Created and destroyed on the UI thread. Public methods should only be called
-// on the UI thread.
+// Created, destroyed, and used only on the UI thread.
 class ChromeDataUseAscriberService : public KeyedService {
  public:
   ChromeDataUseAscriberService();
@@ -67,6 +68,19 @@
   // |ascriber_| outlives this instance.
   ChromeDataUseAscriber* ascriber_;
 
+  // Tracks whether |ascriber_| was set. This field is required because tests
+  // might set |ascriber_| to nullptr.
+  bool is_initialized_;
+
+  // Frame and navigation events might arrive from the UI thread before
+  // |ascriber_| is set. A queue of frame and navigation events that arrive
+  // before |ascriber_| is set are maintained in these fields so that they can
+  // be propagated immediately after |ascriber_| is set. The RenderFrameHost
+  // and NavigationHandle pointers in the queues are valid for the duration that
+  // they are in the queue.
+  std::list<content::RenderFrameHost*> pending_frames_queue_;
+  std::list<content::NavigationHandle*> pending_navigations_queue_;
+
   DISALLOW_COPY_AND_ASSIGN(ChromeDataUseAscriberService);
 };
 
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index fcc33f17..e967e92a 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -76,18 +76,6 @@
     "api/automation_internal/automation_internal_api.h",
     "api/autotest_private/autotest_private_api.cc",
     "api/autotest_private/autotest_private_api.h",
-    "api/bluetooth_low_energy/bluetooth_api_advertisement.cc",
-    "api/bluetooth_low_energy/bluetooth_api_advertisement.h",
-    "api/bluetooth_low_energy/bluetooth_low_energy_api.cc",
-    "api/bluetooth_low_energy/bluetooth_low_energy_api.h",
-    "api/bluetooth_low_energy/bluetooth_low_energy_connection.cc",
-    "api/bluetooth_low_energy/bluetooth_low_energy_connection.h",
-    "api/bluetooth_low_energy/bluetooth_low_energy_event_router.cc",
-    "api/bluetooth_low_energy/bluetooth_low_energy_event_router.h",
-    "api/bluetooth_low_energy/bluetooth_low_energy_notify_session.cc",
-    "api/bluetooth_low_energy/bluetooth_low_energy_notify_session.h",
-    "api/bluetooth_low_energy/utils.cc",
-    "api/bluetooth_low_energy/utils.h",
     "api/bookmark_manager_private/bookmark_manager_private_api.cc",
     "api/bookmark_manager_private/bookmark_manager_private_api.h",
     "api/bookmarks/bookmark_api_constants.cc",
@@ -503,6 +491,8 @@
     "chrome_extension_web_contents_observer.h",
     "chrome_extensions_browser_client.cc",
     "chrome_extensions_browser_client.h",
+    "chrome_kiosk_delegate.h",
+    "chrome_kiosk_delegate_chromeos.cc",
     "chrome_mojo_service_registration.cc",
     "chrome_mojo_service_registration.h",
     "chrome_process_manager_delegate.cc",
@@ -921,6 +911,10 @@
     "//url",
   ]
 
+  if (!is_chromeos) {
+    sources += [ "chrome_kiosk_delegate.cc" ]
+  }
+
   if (is_chromeos) {
     sources += [
       "api/cast_devices_private/cast_devices_private_api.cc",
diff --git a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_apitest.cc b/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_apitest.cc
index eadea51..7cb0a30 100644
--- a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_apitest.cc
+++ b/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_apitest.cc
@@ -7,8 +7,6 @@
 #include <memory>
 #include <utility>
 
-#include "chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_api.h"
-#include "chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
 #include "device/bluetooth/test/mock_bluetooth_device.h"
@@ -17,6 +15,8 @@
 #include "device/bluetooth/test/mock_bluetooth_gatt_descriptor.h"
 #include "device/bluetooth/test/mock_bluetooth_gatt_notify_session.h"
 #include "device/bluetooth/test/mock_bluetooth_gatt_service.h"
+#include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.h"
+#include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h"
 #include "extensions/common/test_util.h"
 #include "extensions/test/extension_test_message_listener.h"
 #include "extensions/test/result_catcher.h"
diff --git a/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc b/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
index a8f61c9..818ec95 100644
--- a/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
+++ b/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
@@ -24,10 +24,14 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "content/public/browser/browser_context.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/download_test_observer.h"
+#include "content/public/test/test_utils.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
 #include "extensions/browser/notification_types.h"
@@ -38,6 +42,7 @@
 #include "extensions/test/result_catcher.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
@@ -105,7 +110,7 @@
     return browser_action_test_util_.get();
   }
 
-  bool OpenPopup(int index) {
+  WebContents* OpenPopup(int index) {
     ResultCatcher catcher;
     content::WindowedNotificationObserver popup_observer(
         content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
@@ -113,7 +118,13 @@
     GetBrowserActionsBar()->Press(index);
     popup_observer.Wait();
     EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
-    return GetBrowserActionsBar()->HasPopup();
+
+    if (!GetBrowserActionsBar()->HasPopup())
+      return nullptr;
+
+    const auto& source = static_cast<const content::Source<WebContents>&>(
+        popup_observer.source());
+    return source.ptr();
   }
 
   ExtensionAction* GetBrowserAction(const Extension& extension) {
@@ -794,5 +805,193 @@
   EXPECT_TRUE(catcher.GetNextResult()) << message_;
 }
 
+class NavigatingExtensionPopupBrowserTest : public BrowserActionApiTest {
+ public:
+  const Extension& popup_extension() { return *popup_extension_; }
+  const Extension& other_extension() { return *other_extension_; }
+
+  void SetUpOnMainThread() override {
+    BrowserActionApiTest::SetUpOnMainThread();
+
+    host_resolver()->AddRule("*", "127.0.0.1");
+    ASSERT_TRUE(embedded_test_server()->Start());
+
+    // Load an extension with a pop-up.
+    ASSERT_TRUE(popup_extension_ = LoadExtension(test_data_dir_.AppendASCII(
+                    "browser_action/popup_with_form")));
+
+    // Load another extension (that we can try navigating to).
+    ASSERT_TRUE(other_extension_ = LoadExtension(test_data_dir_.AppendASCII(
+                    "browser_action/popup_with_iframe")));
+  }
+
+  enum ExpectedNavigationStatus {
+    EXPECTING_NAVIGATION_SUCCESS,
+    EXPECTING_NAVIGATION_FAILURE,
+  };
+
+  void TestPopupNavigationViaGet(
+      const GURL& target_url,
+      ExpectedNavigationStatus expected_navigation_status) {
+    std::string navigation_starting_script =
+        "window.location = '" + target_url.spec() + "';\n";
+    TestPopupNavigation(target_url, expected_navigation_status,
+                        navigation_starting_script);
+  }
+
+  void TestPopupNavigationViaPost(
+      const GURL& target_url,
+      ExpectedNavigationStatus expected_navigation_status) {
+    std::string navigation_starting_script =
+        "var form = document.getElementById('form');\n"
+        "form.action = '" + target_url.spec() + "';\n"
+        "form.submit();\n";
+    TestPopupNavigation(target_url, expected_navigation_status,
+                        navigation_starting_script);
+  }
+
+ private:
+  void TestPopupNavigation(const GURL& target_url,
+                           ExpectedNavigationStatus expected_navigation_status,
+                           std::string navigation_starting_script) {
+    // Were there any failures so far (e.g. in SetUpOnMainThread)?
+    ASSERT_FALSE(HasFailure());
+
+    // Simulate a click on the browser action to open the popup.
+    WebContents* popup = OpenPopup(0);
+    ASSERT_TRUE(popup);
+    GURL popup_url = popup_extension().GetResourceURL("popup.html");
+    EXPECT_EQ(popup_url, popup->GetLastCommittedURL());
+
+    // Note that the |setTimeout| call below is needed to make sure
+    // ExecuteScriptAndExtractBool returns *after* a scheduled navigation has
+    // already started.
+    std::string script_to_execute =
+        navigation_starting_script +
+        "setTimeout(\n"
+        "    function() { window.domAutomationController.send(true); },\n"
+        "    0);\n";
+
+    // Try to navigate the pop-up.
+    bool ignored_script_result = false;
+    content::WebContentsDestroyedWatcher popup_destruction_watcher(popup);
+    EXPECT_TRUE(ExecuteScriptAndExtractBool(popup, script_to_execute,
+                                            &ignored_script_result));
+    popup = popup_destruction_watcher.web_contents();
+
+    // Verify if the popup navigation succeeded or failed as expected.
+    if (!popup) {
+      // If navigation ends up in a tab, then the tab will be focused and
+      // therefore the popup will be closed, destroying associated WebContents -
+      // don't do any verification in this case.
+      ADD_FAILURE() << "Navigation should not close extension pop-up";
+    } else {
+      // If the extension popup is still opened, then wait until there is no
+      // load in progress, and verify whether the navigation succeeded or not.
+      WaitForLoadStop(popup);
+      if (expected_navigation_status == EXPECTING_NAVIGATION_SUCCESS) {
+        EXPECT_EQ(target_url, popup->GetLastCommittedURL())
+            << "Navigation to " << target_url
+            << " should succeed in an extension pop-up";
+      } else {
+        EXPECT_NE(target_url, popup->GetLastCommittedURL())
+            << "Navigation to " << target_url
+            << " should fail in an extension pop-up";
+        EXPECT_THAT(
+            popup->GetLastCommittedURL(),
+            ::testing::AnyOf(::testing::Eq(popup_url),
+                             ::testing::Eq(GURL("chrome-extension://invalid")),
+                             ::testing::Eq(GURL("about:blank"))));
+      }
+
+      // Close the pop-up.
+      EXPECT_TRUE(GetBrowserActionsBar()->HidePopup());
+      popup_destruction_watcher.Wait();
+    }
+
+    // Make sure that the web navigation did not succeed somewhere outside of
+    // the extension popup (as it might if ExtensionViewHost::OpenURLFromTab
+    // forwards the navigation to Browser::OpenURL [which doesn't specify a
+    // source WebContents]).
+    TabStripModel* tabs = browser()->tab_strip_model();
+    for (int i = 0; i < tabs->count(); i++) {
+      WebContents* tab_contents = tabs->GetWebContentsAt(i);
+      WaitForLoadStop(tab_contents);
+      EXPECT_NE(target_url, tab_contents->GetLastCommittedURL())
+          << "Navigating an extension pop-up should not affect tabs.";
+    }
+  }
+
+  const Extension* popup_extension_;
+  const Extension* other_extension_;
+};
+
+// Tests that an extension pop-up cannot be navigated to a web page.
+IN_PROC_BROWSER_TEST_F(NavigatingExtensionPopupBrowserTest, Webpage) {
+  GURL web_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
+  TestPopupNavigationViaGet(web_url, EXPECTING_NAVIGATION_FAILURE);
+  TestPopupNavigationViaPost(web_url, EXPECTING_NAVIGATION_FAILURE);
+}
+
+// Tests that an extension pop-up can be navigated to another page
+// in the same extension.
+IN_PROC_BROWSER_TEST_F(NavigatingExtensionPopupBrowserTest,
+                       PageInSameExtension) {
+  GURL other_page_in_same_extension =
+      popup_extension().GetResourceURL("other_page.html");
+  TestPopupNavigationViaGet(other_page_in_same_extension,
+                            EXPECTING_NAVIGATION_SUCCESS);
+  TestPopupNavigationViaPost(other_page_in_same_extension,
+                             EXPECTING_NAVIGATION_SUCCESS);
+}
+
+// Tests that an extension pop-up cannot be navigated to a page
+// in another extension.
+IN_PROC_BROWSER_TEST_F(NavigatingExtensionPopupBrowserTest,
+                       PageInOtherExtension) {
+  GURL other_extension_url = other_extension().GetResourceURL("other.html");
+  TestPopupNavigationViaGet(other_extension_url, EXPECTING_NAVIGATION_FAILURE);
+  TestPopupNavigationViaPost(other_extension_url, EXPECTING_NAVIGATION_FAILURE);
+}
+
+// Tests that navigating an extension pop-up to a http URI that returns
+// Content-Disposition: attachment; filename=...
+// works: No navigation, but download shelf visible + download goes through.
+//
+// Note - there is no "...ViaGet" flavour of this test, because we don't care
+// (yet) if GET succeeds with the download or not (it probably should succeed
+// for consistency with POST, but it always failed in M54 and before).  After
+// abandoing ShouldFork/OpenURL for all methods (not just for POST) [see comment
+// about https://crbug.com/646261 in ChromeContentRendererClient::ShouldFork]
+// GET should automagically start working for downloads.
+// TODO(lukasza): https://crbug.com/650694: Add a "Get" flavour of the test once
+// the download works both for GET and POST requests.
+IN_PROC_BROWSER_TEST_F(NavigatingExtensionPopupBrowserTest, DownloadViaPost) {
+  content::DownloadTestObserverTerminal downloads_observer(
+      content::BrowserContext::GetDownloadManager(browser()->profile()),
+      1,  // == wait_count (only waiting for "download-test3.gif").
+      content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
+
+  // Navigate to a URL that replies with
+  // Content-Disposition: attachment; filename=...
+  // header.
+  GURL download_url(
+      embedded_test_server()->GetURL("foo.com", "/download-test3.gif"));
+  TestPopupNavigationViaPost(download_url, EXPECTING_NAVIGATION_FAILURE);
+
+  // Verify that "download-test3.gif got downloaded.
+  downloads_observer.WaitForFinished();
+  EXPECT_EQ(0u, downloads_observer.NumDangerousDownloadsSeen());
+  EXPECT_EQ(1u, downloads_observer.NumDownloadsSeenInState(
+                    content::DownloadItem::COMPLETE));
+
+  // The test verification below is applicable only to scenarios where the
+  // download shelf is supported - on ChromeOS, instead of the download shelf,
+  // there is a download notification in the right-bottom corner of the screen.
+#if !defined(OS_CHROMEOS)
+  EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
+#endif
+}
+
 }  // namespace
 }  // namespace extensions
diff --git a/chrome/browser/extensions/browser_context_keyed_service_factories.cc b/chrome/browser/extensions/browser_context_keyed_service_factories.cc
index 9b39773..1205abec 100644
--- a/chrome/browser/extensions/browser_context_keyed_service_factories.cc
+++ b/chrome/browser/extensions/browser_context_keyed_service_factories.cc
@@ -8,7 +8,6 @@
 #include "chrome/browser/extensions/activity_log/activity_log.h"
 #include "chrome/browser/extensions/api/activity_log_private/activity_log_private_api.h"
 #include "chrome/browser/extensions/api/autofill_private/autofill_private_event_router_factory.h"
-#include "chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_api.h"
 #include "chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h"
 #include "chrome/browser/extensions/api/bookmarks/bookmarks_api.h"
 #include "chrome/browser/extensions/api/braille_display_private/braille_display_private_api.h"
@@ -55,6 +54,7 @@
 #include "chrome/browser/extensions/warning_badge_service_factory.h"
 #include "chrome/browser/speech/extension_api/tts_extension_api.h"
 #include "chrome/browser/ui/toolbar/toolbar_actions_model_factory.h"
+#include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.h"
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/extensions/file_manager/event_router_factory.h"
diff --git a/chrome/browser/extensions/chrome_content_verifier_delegate.cc b/chrome/browser/extensions/chrome_content_verifier_delegate.cc
index 5f5b3a6..f144a6f4 100644
--- a/chrome/browser/extensions/chrome_content_verifier_delegate.cc
+++ b/chrome/browser/extensions/chrome_content_verifier_delegate.cc
@@ -11,6 +11,7 @@
 
 #include "base/base_switches.h"
 #include "base/command_line.h"
+#include "base/syslog_logging.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_util.h"
@@ -179,8 +180,9 @@
           service->pending_extension_manager();
       if (pending_manager->IsPolicyReinstallForCorruptionExpected(extension_id))
         return;
-      LOG(WARNING) << "Corruption detected in policy extension " << extension_id
-                   << " installed at: " << extension->path().value();
+      SYSLOG(WARNING) << "Corruption detected in policy extension "
+                      << extension_id << " installed at: "
+                      << extension->path().value();
       pending_manager->ExpectPolicyReinstallForCorruption(extension_id);
       service->DisableExtension(extension_id, Extension::DISABLE_CORRUPTED);
       service->CheckForExternalUpdates();
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.cc b/chrome/browser/extensions/chrome_extensions_browser_client.cc
index 3b9fea6..49bb0a80c 100644
--- a/chrome/browser/extensions/chrome_extensions_browser_client.cc
+++ b/chrome/browser/extensions/chrome_extensions_browser_client.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/extensions/chrome_extension_api_frame_id_map_helper.h"
 #include "chrome/browser/extensions/chrome_extension_host_delegate.h"
 #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
+#include "chrome/browser/extensions/chrome_kiosk_delegate.h"
 #include "chrome/browser/extensions/chrome_mojo_service_registration.h"
 #include "chrome/browser/extensions/chrome_process_manager_delegate.h"
 #include "chrome/browser/extensions/chrome_url_request_util.h"
@@ -417,4 +418,10 @@
   return activity_log && activity_log->is_active();
 }
 
+KioskDelegate* ChromeExtensionsBrowserClient::GetKioskDelegate() {
+  if (!kiosk_delegate_)
+    kiosk_delegate_.reset(new ChromeKioskDelegate());
+  return kiosk_delegate_.get();
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.h b/chrome/browser/extensions/chrome_extensions_browser_client.h
index 100c78f50..89477b1 100644
--- a/chrome/browser/extensions/chrome_extensions_browser_client.h
+++ b/chrome/browser/extensions/chrome_extensions_browser_client.h
@@ -15,6 +15,7 @@
 #include "base/memory/ref_counted.h"
 #include "build/build_config.h"
 #include "extensions/browser/extensions_browser_client.h"
+#include "extensions/browser/kiosk/kiosk_delegate.h"
 
 namespace base {
 class CommandLine;
@@ -121,6 +122,7 @@
       content::RenderFrameHost* frame,
       const content::BluetoothChooser::EventHandler& event_handler) override;
   bool IsActivityLoggingEnabled(content::BrowserContext* context) override;
+  KioskDelegate* GetKioskDelegate() override;
 
  private:
   friend struct base::DefaultLazyInstanceTraits<ChromeExtensionsBrowserClient>;
@@ -135,6 +137,8 @@
 
   std::unique_ptr<ExtensionCache> extension_cache_;
 
+  std::unique_ptr<KioskDelegate> kiosk_delegate_;
+
   DISALLOW_COPY_AND_ASSIGN(ChromeExtensionsBrowserClient);
 };
 
diff --git a/chrome/browser/extensions/chrome_kiosk_delegate.cc b/chrome/browser/extensions/chrome_kiosk_delegate.cc
new file mode 100644
index 0000000..1ddbeaa
--- /dev/null
+++ b/chrome/browser/extensions/chrome_kiosk_delegate.cc
@@ -0,0 +1,17 @@
+// 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.
+
+#include "chrome/browser/extensions/chrome_kiosk_delegate.h"
+
+namespace extensions {
+
+ChromeKioskDelegate::ChromeKioskDelegate() {}
+
+ChromeKioskDelegate::~ChromeKioskDelegate() {}
+
+bool ChromeKioskDelegate::IsAutoLaunchedKioskApp(const ExtensionId& id) const {
+  return false;
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/chrome_kiosk_delegate.h b/chrome/browser/extensions/chrome_kiosk_delegate.h
new file mode 100644
index 0000000..fa7632de
--- /dev/null
+++ b/chrome/browser/extensions/chrome_kiosk_delegate.h
@@ -0,0 +1,26 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_CHROME_KIOSK_DELEGATE_H_
+#define CHROME_BROWSER_EXTENSIONS_CHROME_KIOSK_DELEGATE_H_
+
+#include "extensions/browser/kiosk/kiosk_delegate.h"
+#include "extensions/common/extension_id.h"
+
+namespace extensions {
+
+// Delegate in Chrome that provides an extension/app API with Kiosk mode
+// functionality.
+class ChromeKioskDelegate : public KioskDelegate {
+ public:
+  ChromeKioskDelegate();
+  ~ChromeKioskDelegate() override;
+
+  // KioskDelegate overrides:
+  bool IsAutoLaunchedKioskApp(const ExtensionId& id) const override;
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_CHROME_KIOSK_DELEGATE_H_
diff --git a/chrome/browser/extensions/chrome_kiosk_delegate_chromeos.cc b/chrome/browser/extensions/chrome_kiosk_delegate_chromeos.cc
new file mode 100644
index 0000000..c89b322
--- /dev/null
+++ b/chrome/browser/extensions/chrome_kiosk_delegate_chromeos.cc
@@ -0,0 +1,21 @@
+// 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.
+
+#include "chrome/browser/extensions/chrome_kiosk_delegate.h"
+
+#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
+
+namespace extensions {
+
+ChromeKioskDelegate::ChromeKioskDelegate() {}
+
+ChromeKioskDelegate::~ChromeKioskDelegate() {}
+
+bool ChromeKioskDelegate::IsAutoLaunchedKioskApp(const ExtensionId& id) const {
+  chromeos::KioskAppManager::App app_info;
+  return chromeos::KioskAppManager::Get()->GetApp(id, &app_info) &&
+         app_info.was_auto_launched_with_zero_delay;
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/crx_installer_browsertest.cc b/chrome/browser/extensions/crx_installer_browsertest.cc
index c2d79a41..207bda32 100644
--- a/chrome/browser/extensions/crx_installer_browsertest.cc
+++ b/chrome/browser/extensions/crx_installer_browsertest.cc
@@ -354,6 +354,32 @@
   EXPECT_FALSE(base::PathExists(extension->path().AppendASCII("test2.exe")));
 }
 
+IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, AllowedThemeFileTypes) {
+  const Extension* extension = InstallExtension(
+      test_data_dir_.AppendASCII("theme_with_extension.crx"), 1);
+  ASSERT_TRUE(extension);
+  const base::FilePath& path = extension->path();
+  EXPECT_TRUE(
+      base::PathExists(path.AppendASCII("images/theme_frame_camo.PNG")));
+  EXPECT_TRUE(
+      base::PathExists(path.AppendASCII("images/theme_ntp_background.png")));
+  EXPECT_TRUE(base::PathExists(
+      path.AppendASCII("images/theme_ntp_background_norepeat.png")));
+  EXPECT_TRUE(
+      base::PathExists(path.AppendASCII("images/theme_toolbar_camo.png")));
+  EXPECT_TRUE(base::PathExists(path.AppendASCII("images/redirect_target.GIF")));
+  EXPECT_TRUE(base::PathExists(path.AppendASCII("test.image.bmp")));
+  EXPECT_TRUE(
+      base::PathExists(path.AppendASCII("test_image_with_no_extension")));
+
+  EXPECT_FALSE(base::PathExists(path.AppendASCII("non_images/test.html")));
+  EXPECT_FALSE(base::PathExists(path.AppendASCII("non_images/test.nexe")));
+  EXPECT_FALSE(base::PathExists(path.AppendASCII("non_images/test1.EXE")));
+  EXPECT_FALSE(base::PathExists(path.AppendASCII("non_images/test2.exe")));
+  EXPECT_FALSE(base::PathExists(path.AppendASCII("non_images/test.txt")));
+  EXPECT_FALSE(base::PathExists(path.AppendASCII("non_images/test.css")));
+}
+
 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, PackAndInstallExtension) {
   if (!FeatureSwitch::easy_off_store_install()->IsEnabled())
     return;
diff --git a/chrome/browser/extensions/extension_view_host.cc b/chrome/browser/extensions/extension_view_host.cc
index 615e13c..ea544c71 100644
--- a/chrome/browser/extensions/extension_view_host.cc
+++ b/chrome/browser/extensions/extension_view_host.cc
@@ -165,6 +165,14 @@
   }
 }
 
+bool ExtensionViewHost::ShouldTransferNavigation(
+    bool is_main_frame_navigation) {
+  // Block navigations that cause main frame of an extension pop-up (or
+  // background page) to navigate to non-extension content (i.e. to web
+  // content).
+  return !is_main_frame_navigation;
+}
+
 bool ExtensionViewHost::PreHandleKeyboardEvent(
     WebContents* source,
     const NativeWebKeyboardEvent& event,
diff --git a/chrome/browser/extensions/extension_view_host.h b/chrome/browser/extensions/extension_view_host.h
index d61c96f..70263c8c 100644
--- a/chrome/browser/extensions/extension_view_host.h
+++ b/chrome/browser/extensions/extension_view_host.h
@@ -67,6 +67,7 @@
   content::WebContents* OpenURLFromTab(
       content::WebContents* source,
       const content::OpenURLParams& params) override;
+  bool ShouldTransferNavigation(bool is_main_frame_navigation) override;
   bool PreHandleKeyboardEvent(content::WebContents* source,
                               const content::NativeWebKeyboardEvent& event,
                               bool* is_keyboard_shortcut) override;
diff --git a/chrome/browser/extensions/process_management_browsertest.cc b/chrome/browser/extensions/process_management_browsertest.cc
index 5d4facc..759b2305 100644
--- a/chrome/browser/extensions/process_management_browsertest.cc
+++ b/chrome/browser/extensions/process_management_browsertest.cc
@@ -12,12 +12,16 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/extensions/extension_process_policy.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/test_navigation_observer.h"
 #include "extensions/browser/extension_host.h"
 #include "extensions/browser/process_manager.h"
 #include "extensions/common/switches.h"
@@ -248,3 +252,53 @@
   EXPECT_GE((size_t) 6, process_map->size());
   EXPECT_EQ((size_t) 2, process_ids.size());
 }
+
+IN_PROC_BROWSER_TEST_F(ProcessManagementTest,
+                       NavigateExtensionTabToWebViaPost) {
+  host_resolver()->AddRule("*", "127.0.0.1");
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  // Load an extension.
+  const extensions::Extension* extension = LoadExtension(
+      test_data_dir_.AppendASCII("api_test/browser_action/popup_with_form"));
+  ASSERT_TRUE(extension);
+
+  // Navigate a tab to an extension page.
+  GURL extension_url = extension->GetResourceURL("popup.html");
+  ui_test_utils::NavigateToURL(browser(), extension_url);
+  WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  EXPECT_EQ(extension_url, web_contents->GetLastCommittedURL());
+  content::RenderProcessHost* old_process_host =
+      web_contents->GetMainFrame()->GetProcess();
+
+  // Note that the |setTimeout| call below is needed to make sure
+  // ExecuteScriptAndExtractBool returns *after* a scheduled navigation has
+  // already started.
+  GURL web_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
+  std::string navigation_starting_script =
+      "var form = document.getElementById('form');\n"
+      "form.action = '" + web_url.spec() + "';\n"
+      "form.submit();\n"
+      "setTimeout(\n"
+      "    function() { window.domAutomationController.send(true); },\n"
+      "    0);\n";
+
+  // Try to trigger navigation to a webpage from within the tab.
+  bool ignored_script_result = false;
+  content::TestNavigationObserver nav_observer(web_contents, 1);
+  EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+      web_contents, navigation_starting_script, &ignored_script_result));
+
+  // Verify that the navigation succeeded.
+  nav_observer.Wait();
+  EXPECT_EQ(web_url, web_contents->GetLastCommittedURL());
+
+  // Verify that the navigation transferred the contents to another renderer
+  // process.
+  if (extensions::IsIsolateExtensionsEnabled()) {
+    content::RenderProcessHost* new_process_host =
+        web_contents->GetMainFrame()->GetProcess();
+    EXPECT_NE(old_process_host, new_process_host);
+  }
+}
diff --git a/chrome/browser/extensions/theme_installed_infobar_delegate.cc b/chrome/browser/extensions/theme_installed_infobar_delegate.cc
index cf19022..4038a71 100644
--- a/chrome/browser/extensions/theme_installed_infobar_delegate.cc
+++ b/chrome/browser/extensions/theme_installed_infobar_delegate.cc
@@ -116,16 +116,8 @@
   return THEME_INSTALLED_INFOBAR_DELEGATE;
 }
 
-int ThemeInstalledInfoBarDelegate::GetIconId() const {
-  return IDR_INFOBAR_THEME;
-}
-
 gfx::VectorIconId ThemeInstalledInfoBarDelegate::GetVectorIconId() const {
-#if defined(OS_MACOSX)
-  return gfx::VectorIconId::VECTOR_ICON_NONE;
-#else
   return gfx::VectorIconId::PAINTBRUSH;
-#endif
 }
 
 ThemeInstalledInfoBarDelegate*
diff --git a/chrome/browser/extensions/theme_installed_infobar_delegate.h b/chrome/browser/extensions/theme_installed_infobar_delegate.h
index d440aca..eefdadb 100644
--- a/chrome/browser/extensions/theme_installed_infobar_delegate.h
+++ b/chrome/browser/extensions/theme_installed_infobar_delegate.h
@@ -44,7 +44,6 @@
   // ConfirmInfoBarDelegate:
   Type GetInfoBarType() const override;
   infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
-  int GetIconId() const override;
   gfx::VectorIconId GetVectorIconId() const override;
   ThemeInstalledInfoBarDelegate* AsThemePreviewInfobarDelegate() override;
   base::string16 GetMessageText() const override;
diff --git a/chrome/browser/installable/installable_manager.cc b/chrome/browser/installable/installable_manager.cc
index 7b4362c..8991a342 100644
--- a/chrome/browser/installable/installable_manager.cc
+++ b/chrome/browser/installable/installable_manager.cc
@@ -31,10 +31,10 @@
   for (const auto& icon : manifest.icons) {
     // The type field is optional. If it isn't present, fall back on checking
     // the src extension, and allow the icon if the extension ends with png.
-    if (!base::EqualsASCII(icon.type.string(), "image/png") &&
-        !(icon.type.is_null() &&
-          base::EndsWith(icon.src.ExtractFileName(), kPngExtension,
-                         base::CompareCase::INSENSITIVE_ASCII)))
+    if (!base::EqualsASCII(icon.type, "image/png") &&
+        !(icon.type.empty() && base::EndsWith(
+            icon.src.ExtractFileName(), kPngExtension,
+            base::CompareCase::INSENSITIVE_ASCII)))
       continue;
 
     for (const auto& size : icon.sizes) {
diff --git a/chrome/browser/installable/installable_manager_unittest.cc b/chrome/browser/installable/installable_manager_unittest.cc
index 0913920fc..9002ddb 100644
--- a/chrome/browser/installable/installable_manager_unittest.cc
+++ b/chrome/browser/installable/installable_manager_unittest.cc
@@ -25,7 +25,7 @@
     manifest.display = blink::WebDisplayModeStandalone;
 
     content::Manifest::Icon icon;
-    icon.type = ToNullableUTF16("image/png");
+    icon.type = base::ASCIIToUTF16("image/png");
     icon.sizes.push_back(gfx::Size(144, 144));
     manifest.icons.push_back(icon);
 
@@ -107,11 +107,11 @@
 TEST_F(InstallableManagerUnitTest, ManifestRequiresImagePNG) {
   content::Manifest manifest = GetValidManifest();
 
-  manifest.icons[0].type = ToNullableUTF16("image/gif");
+  manifest.icons[0].type = base::ASCIIToUTF16("image/gif");
   EXPECT_FALSE(IsManifestValid(manifest));
   EXPECT_EQ(MANIFEST_MISSING_SUITABLE_ICON, GetErrorCode());
 
-  manifest.icons[0].type = base::NullableString16();
+  manifest.icons[0].type.clear();
   EXPECT_FALSE(IsManifestValid(manifest));
   EXPECT_EQ(MANIFEST_MISSING_SUITABLE_ICON, GetErrorCode());
 
diff --git a/chrome/browser/interstitials/chrome_controller_client.cc b/chrome/browser/interstitials/chrome_controller_client.cc
index 98d33838..6f6e30f 100644
--- a/chrome/browser/interstitials/chrome_controller_client.cc
+++ b/chrome/browser/interstitials/chrome_controller_client.cc
@@ -10,6 +10,7 @@
 #include "base/process/launch.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/interstitials/chrome_metrics_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_service.h"
@@ -126,8 +127,11 @@
 }  // namespace
 
 ChromeControllerClient::ChromeControllerClient(
-    content::WebContents* web_contents)
-    : web_contents_(web_contents), interstitial_page_(nullptr) {}
+    content::WebContents* web_contents,
+    std::unique_ptr<security_interstitials::MetricsHelper> metrics_helper)
+    : ControllerClient(std::move(metrics_helper)),
+      web_contents_(web_contents),
+      interstitial_page_(nullptr) {}
 
 ChromeControllerClient::~ChromeControllerClient() {}
 
diff --git a/chrome/browser/interstitials/chrome_controller_client.h b/chrome/browser/interstitials/chrome_controller_client.h
index 6ba8c13..4a0cb42 100644
--- a/chrome/browser/interstitials/chrome_controller_client.h
+++ b/chrome/browser/interstitials/chrome_controller_client.h
@@ -16,7 +16,9 @@
 // Provides embedder-specific logic for the security error page controller.
 class ChromeControllerClient : public security_interstitials::ControllerClient {
  public:
-  explicit ChromeControllerClient(content::WebContents* web_contents);
+  ChromeControllerClient(
+      content::WebContents* web_contents,
+      std::unique_ptr<security_interstitials::MetricsHelper> metrics_helper);
   ~ChromeControllerClient() override;
 
   void set_interstitial_page(content::InterstitialPage* interstitial_page);
diff --git a/chrome/browser/interstitials/security_interstitial_page.cc b/chrome/browser/interstitials/security_interstitial_page.cc
index 0d189476..5ba1e03 100644
--- a/chrome/browser/interstitials/security_interstitial_page.cc
+++ b/chrome/browser/interstitials/security_interstitial_page.cc
@@ -27,12 +27,14 @@
 
 SecurityInterstitialPage::SecurityInterstitialPage(
     content::WebContents* web_contents,
-    const GURL& request_url)
+    const GURL& request_url,
+    std::unique_ptr<security_interstitials::MetricsHelper> metrics_helper)
     : web_contents_(web_contents),
       request_url_(request_url),
       interstitial_page_(NULL),
       create_view_(true),
-      controller_(new ChromeControllerClient(web_contents)) {
+      controller_(
+          new ChromeControllerClient(web_contents, std::move(metrics_helper))) {
   // Creating interstitial_page_ without showing it leaks memory, so don't
   // create it here.
 }
@@ -74,6 +76,15 @@
   return profile->GetPrefs()->GetBoolean(pref);
 }
 
+ChromeControllerClient* SecurityInterstitialPage::controller() {
+  return controller_.get();
+}
+
+security_interstitials::MetricsHelper*
+SecurityInterstitialPage::metrics_helper() {
+  return controller_->metrics_helper();
+}
+
 base::string16 SecurityInterstitialPage::GetFormattedHostName() const {
   return security_interstitials::common_string_util::GetFormattedHostName(
       request_url_);
@@ -90,17 +101,3 @@
   webui::AppendWebUiCssTextDefaults(&html);
   return webui::GetI18nTemplateHtml(html, &load_time_data);
 }
-
-security_interstitials::MetricsHelper*
-SecurityInterstitialPage::metrics_helper() {
-  return controller_->metrics_helper();
-}
-
-void SecurityInterstitialPage::set_metrics_helper(
-    std::unique_ptr<security_interstitials::MetricsHelper> metrics_helper) {
-  controller_->set_metrics_helper(std::move(metrics_helper));
-}
-
-ChromeControllerClient* SecurityInterstitialPage::controller() {
-  return controller_.get();
-}
diff --git a/chrome/browser/interstitials/security_interstitial_page.h b/chrome/browser/interstitials/security_interstitial_page.h
index f013d964..802db9b 100644
--- a/chrome/browser/interstitials/security_interstitial_page.h
+++ b/chrome/browser/interstitials/security_interstitial_page.h
@@ -29,8 +29,10 @@
 
 class SecurityInterstitialPage : public content::InterstitialPageDelegate {
  public:
-  SecurityInterstitialPage(content::WebContents* web_contents,
-                           const GURL& url);
+  SecurityInterstitialPage(
+      content::WebContents* web_contents,
+      const GURL& url,
+      std::unique_ptr<security_interstitials::MetricsHelper> metrics_helper);
   ~SecurityInterstitialPage() override;
 
   // Creates an interstitial and shows it.
@@ -65,15 +67,10 @@
   // Profile associated with |web_contents_|.
   bool IsPrefEnabled(const char* pref);
 
-  // TODO(felt): Remove these. They are temporary methods, used to pass along
-  // calls to the |controller_| for subclasses that don't yet have their own
-  // ChromeControllerClients. crbug.com/488673
-  security_interstitials::MetricsHelper* metrics_helper();
-  void set_metrics_helper(
-      std::unique_ptr<security_interstitials::MetricsHelper> metrics_helper);
-
   ChromeControllerClient* controller();
 
+  security_interstitials::MetricsHelper* metrics_helper();
+
  private:
   // The WebContents with which this interstitial page is
   // associated. Not available in ~SecurityInterstitialPage, since it
@@ -88,6 +85,8 @@
   // For subclasses that don't have their own ChromeControllerClients yet.
   std::unique_ptr<ChromeControllerClient> controller_;
 
+  std::unique_ptr<security_interstitials::MetricsHelper> metrics_helper_;
+
   DISALLOW_COPY_AND_ASSIGN(SecurityInterstitialPage);
 };
 
diff --git a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
index da28470..97cb50e 100644
--- a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
+++ b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
@@ -501,6 +501,7 @@
     content::ResourceContext* resource_context,
     bool is_content_initiated,
     bool must_download,
+    bool is_new_request,
     ScopedVector<content::ResourceThrottle>* throttles) {
   const content::ResourceRequestInfo* info =
         content::ResourceRequestInfo::ForRequest(request);
@@ -516,9 +517,9 @@
         request->url(), request->method()));
   }
 
-  // If this isn't a new request, we've seen this before and added the standard
-  //  resource throttles already so no need to add it again.
-  if (!request->is_pending()) {
+  // If this isn't a new request, the standard resource throttles have already
+  // been added, so no need to add them again.
+  if (is_new_request) {
     AppendStandardResourceThrottles(request,
                                     resource_context,
                                     content::RESOURCE_TYPE_MAIN_FRAME,
diff --git a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.h b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.h
index 001be0ea..b730ddbb 100644
--- a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.h
+++ b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.h
@@ -58,6 +58,7 @@
       content::ResourceContext* resource_context,
       bool is_content_initiated,
       bool must_download,
+      bool is_new_request,
       ScopedVector<content::ResourceThrottle>* throttles) override;
   content::ResourceDispatcherHostLoginDelegate* CreateLoginDelegate(
       net::AuthChallengeInfo* auth_info,
@@ -103,6 +104,14 @@
   static void SetExternalProtocolHandlerDelegateForTesting(
       ExternalProtocolHandler::Delegate* delegate);
 
+ protected:
+  // Virtual for testing.
+  virtual void AppendStandardResourceThrottles(
+      net::URLRequest* request,
+      content::ResourceContext* resource_context,
+      content::ResourceType resource_type,
+      ScopedVector<content::ResourceThrottle>* throttles);
+
  private:
 #if defined(ENABLE_EXTENSIONS)
   struct StreamTargetInfo {
@@ -111,12 +120,6 @@
   };
 #endif
 
-  void AppendStandardResourceThrottles(
-      net::URLRequest* request,
-      content::ResourceContext* resource_context,
-      content::ResourceType resource_type,
-      ScopedVector<content::ResourceThrottle>* throttles);
-
   scoped_refptr<DownloadRequestLimiter> download_request_limiter_;
   scoped_refptr<safe_browsing::SafeBrowsingService> safe_browsing_;
 #if defined(ENABLE_EXTENSIONS)
diff --git a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate_browsertest.cc b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate_browsertest.cc
index cda953f8..ebf2a250 100644
--- a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate_browsertest.cc
+++ b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate_browsertest.cc
@@ -11,20 +11,25 @@
 #include <utility>
 #include <vector>
 
+#include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
+#include "base/files/scoped_temp_dir.h"
 #include "base/macros.h"
 #include "base/path_service.h"
+#include "base/run_loop.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/test/scoped_command_line.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/download/download_browsertest.h"
 #include "chrome/browser/loader/chrome_navigation_data.h"
 #include "chrome/browser/policy/cloud/policy_header_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_paths.h"
+#include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h"
@@ -36,6 +41,8 @@
 #include "components/signin/core/browser/signin_header_helper.h"
 #include "components/signin/core/common/signin_pref_names.h"
 #include "components/signin/core/common/signin_switches.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_data.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/resource_dispatcher_host.h"
@@ -56,6 +63,7 @@
 using testing::Not;
 
 namespace {
+
 static const char kTestPolicyHeader[] = "test_header";
 static const char kServerRedirectUrl[] = "/server-redirect";
 
@@ -87,6 +95,7 @@
   TestDispatcherHostDelegate() : should_add_data_reduction_proxy_data_(false) {}
   ~TestDispatcherHostDelegate() override {}
 
+  // ResourceDispatcherHostDelegate implementation:
   void RequestBeginning(
       net::URLRequest* request,
       content::ResourceContext* resource_context,
@@ -125,10 +134,40 @@
     return ChromeResourceDispatcherHostDelegate::GetNavigationData(request);
   }
 
+  // ChromeResourceDispatcherHost implementation:
+  void AppendStandardResourceThrottles(
+      net::URLRequest* request,
+      content::ResourceContext* resource_context,
+      content::ResourceType resource_type,
+      ScopedVector<content::ResourceThrottle>* throttles) override {
+    ++times_stardard_throttles_added_for_url_[request->url()];
+    ChromeResourceDispatcherHostDelegate::AppendStandardResourceThrottles(
+        request, resource_context, resource_type, throttles);
+  }
+
+  void set_should_add_data_reduction_proxy_data(
+      bool should_add_data_reduction_proxy_data) {
+    should_add_data_reduction_proxy_data_ =
+        should_add_data_reduction_proxy_data;
+  }
+
+  const net::HttpRequestHeaders& request_headers() const {
+    return request_headers_;
+  }
+
+  // Writes the number of times the standard set of throttles have been added
+  // for requests for the speficied URL to |count|.
+  void GetTimesStandardThrottlesAddedForURL(const GURL& url, int* count) {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+    *count = times_stardard_throttles_added_for_url_[url];
+  }
+
+ private:
   bool should_add_data_reduction_proxy_data_;
   net::HttpRequestHeaders request_headers_;
 
- private:
+  std::map<GURL, int> times_stardard_throttles_added_for_url_;
+
   DISALLOW_COPY_AND_ASSIGN(TestDispatcherHostDelegate);
 };
 
@@ -194,6 +233,11 @@
       (*it)->SetServerURLForTest(dm_url_.spec());
       (*it)->UpdateHeader(kTestPolicyHeader);
     }
+
+    // Set up temp directory for downloads.
+    ASSERT_TRUE(downloads_directory_.CreateUniqueTempDir());
+    browser()->profile()->GetPrefs()->SetFilePath(
+        prefs::kDownloadDefaultDirectory, downloads_directory_.GetPath());
   }
 
   void TearDownOnMainThread() override {
@@ -202,14 +246,32 @@
   }
 
   void SetShouldAddDataReductionProxyData(bool add_data) {
-    dispatcher_host_delegate_->should_add_data_reduction_proxy_data_ = add_data;
+    dispatcher_host_delegate_->set_should_add_data_reduction_proxy_data(
+        add_data);
+  }
+
+  int GetTimesStandardThrottlesAddedForURL(const GURL& url) {
+    int count;
+    base::RunLoop run_loop;
+    content::BrowserThread::PostTaskAndReply(
+        content::BrowserThread::IO, FROM_HERE,
+        base::Bind(
+            &TestDispatcherHostDelegate::GetTimesStandardThrottlesAddedForURL,
+            base::Unretained(dispatcher_host_delegate_.get()), url, &count),
+        run_loop.QuitClosure());
+    run_loop.Run();
+    return count;
   }
 
  protected:
   // The fake URL for DMServer we are using.
   GURL dm_url_;
   std::unique_ptr<TestDispatcherHostDelegate> dispatcher_host_delegate_;
+
  private:
+  // Location of the downloads directory for tests that use one.
+  base::ScopedTempDir downloads_directory_;
+
   DISALLOW_COPY_AND_ASSIGN(ChromeResourceDispatcherHostDelegateBrowserTest);
 };
 
@@ -220,7 +282,7 @@
   // request.
   DCHECK(!embedded_test_server()->base_url().spec().empty());
   ui_test_utils::NavigateToURL(browser(), embedded_test_server()->base_url());
-  ASSERT_FALSE(dispatcher_host_delegate_->request_headers_.HasHeader(
+  ASSERT_FALSE(dispatcher_host_delegate_->request_headers().HasHeader(
       policy::kChromePolicyHeader));
 }
 
@@ -230,7 +292,7 @@
   // request.
   ui_test_utils::NavigateToURL(browser(), dm_url_);
   std::string value;
-  ASSERT_TRUE(dispatcher_host_delegate_->request_headers_.GetHeader(
+  ASSERT_TRUE(dispatcher_host_delegate_->request_headers().GetHeader(
       policy::kChromePolicyHeader, &value));
   ASSERT_EQ(kTestPolicyHeader, value);
 }
@@ -247,7 +309,7 @@
   ui_test_utils::NavigateToURL(browser(), embedded_test_server()->GetURL(
       redirect_url));
   std::string value;
-  ASSERT_TRUE(dispatcher_host_delegate_->request_headers_.GetHeader(
+  ASSERT_TRUE(dispatcher_host_delegate_->request_headers().GetHeader(
       policy::kChromePolicyHeader, &value));
   ASSERT_EQ(kTestPolicyHeader, value);
 }
@@ -531,3 +593,46 @@
     }
   }
 }
+
+// Check that exactly one set of throttles is added to smaller downloads, which
+// have their mime type determined only after the response is completely
+// received.
+// See https://crbug.com/640545
+IN_PROC_BROWSER_TEST_F(ChromeResourceDispatcherHostDelegateBrowserTest,
+                       ThrottlesAddedExactlyOnceToTinySniffedDownloads) {
+  GURL url = embedded_test_server()->GetURL("/downloads/tiny_binary.bin");
+  DownloadTestObserverNotInProgress download_observer(
+      content::BrowserContext::GetDownloadManager(browser()->profile()), 1);
+  download_observer.StartObserving();
+  ui_test_utils::NavigateToURL(browser(), url);
+  download_observer.WaitForFinished();
+  EXPECT_EQ(1, GetTimesStandardThrottlesAddedForURL(url));
+}
+
+// Check that exactly one set of throttles is added to larger downloads, which
+// have their mime type determined before the end of the response is reported.
+IN_PROC_BROWSER_TEST_F(ChromeResourceDispatcherHostDelegateBrowserTest,
+                       ThrottlesAddedExactlyOnceToLargeSniffedDownloads) {
+  GURL url = embedded_test_server()->GetURL("/downloads/thisdayinhistory.xls");
+  DownloadTestObserverNotInProgress download_observer(
+      content::BrowserContext::GetDownloadManager(browser()->profile()), 1);
+  download_observer.StartObserving();
+  ui_test_utils::NavigateToURL(browser(), url);
+  download_observer.WaitForFinished();
+  EXPECT_EQ(1, GetTimesStandardThrottlesAddedForURL(url));
+}
+
+// Check that exactly one set of throttles is added to downloads started by an
+// <a download> click.
+IN_PROC_BROWSER_TEST_F(ChromeResourceDispatcherHostDelegateBrowserTest,
+                       ThrottlesAddedExactlyOnceToADownloads) {
+  DownloadTestObserverNotInProgress download_observer(
+      content::BrowserContext::GetDownloadManager(browser()->profile()), 1);
+  download_observer.StartObserving();
+  ui_test_utils::NavigateToURL(browser(), embedded_test_server()->GetURL(
+                                              "/download-anchor-attrib.html"));
+  download_observer.WaitForFinished();
+  EXPECT_EQ(1,
+            GetTimesStandardThrottlesAddedForURL(
+                embedded_test_server()->GetURL("/anchor_download_test.png")));
+}
diff --git a/chrome/browser/manifest/manifest_icon_selector.cc b/chrome/browser/manifest/manifest_icon_selector.cc
index eacebd2..faae55d 100644
--- a/chrome/browser/manifest/manifest_icon_selector.cc
+++ b/chrome/browser/manifest/manifest_icon_selector.cc
@@ -118,9 +118,8 @@
   std::vector<Manifest::Icon> result;
 
   for (size_t i = 0; i < icons.size(); ++i) {
-    if (icons[i].type.is_null() ||
-        mime_util::IsSupportedImageMimeType(
-            base::UTF16ToUTF8(icons[i].type.string()))) {
+    if (icons[i].type.empty() ||
+        mime_util::IsSupportedImageMimeType(base::UTF16ToUTF8(icons[i].type))) {
       result.push_back(icons[i]);
     }
   }
diff --git a/chrome/browser/manifest/manifest_icon_selector_unittest.cc b/chrome/browser/manifest/manifest_icon_selector_unittest.cc
index b6c11fc..7cf0e5cf 100644
--- a/chrome/browser/manifest/manifest_icon_selector_unittest.cc
+++ b/chrome/browser/manifest/manifest_icon_selector_unittest.cc
@@ -62,8 +62,7 @@
       const std::vector<gfx::Size> sizes) {
     content::Manifest::Icon icon;
     icon.src = GURL(url);
-    if (!type.empty())
-      icon.type = base::NullableString16(base::UTF8ToUTF16(type), false);
+    icon.type = base::UTF8ToUTF16(type);
     icon.sizes = sizes;
 
     return icon;
diff --git a/chrome/browser/metrics/metrics_memory_details.cc b/chrome/browser/metrics/metrics_memory_details.cc
index 3a798d8cd..f8ccb55 100644
--- a/chrome/browser/metrics/metrics_memory_details.cc
+++ b/chrome/browser/metrics/metrics_memory_details.cc
@@ -72,7 +72,6 @@
 
 void MetricsMemoryDetails::UpdateHistograms() {
   // Reports a set of memory metrics to UMA.
-  // Memory is measured in KB.
 
   const ProcessData& browser = *ChromeBrowser();
   size_t aggregate_memory = 0;
@@ -97,6 +96,9 @@
                                       committed / 1024);
         continue;
       case content::PROCESS_TYPE_RENDERER: {
+        UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.RendererAll", sample / 1024);
+        UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.RendererAll.Committed",
+                                      committed / 1024);
         ProcessMemoryInformation::RendererProcessType renderer_type =
             browser.processes[index].renderer_type;
         switch (renderer_type) {
@@ -200,9 +202,6 @@
   // TODO(viettrungluu): Do we want separate counts for the other
   // (platform-specific) process types?
 
-  // TODO(rkaplow): Remove once we've verified Memory.Total2 is ok.
-  int total_sample_old = static_cast<int>(aggregate_memory / 1000);
-  UMA_HISTOGRAM_MEMORY_MB("Memory.Total", total_sample_old);
   int total_sample = static_cast<int>(aggregate_memory / 1024);
   UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Total2", total_sample);
 
diff --git a/chrome/browser/net/chrome_extensions_network_delegate.cc b/chrome/browser/net/chrome_extensions_network_delegate.cc
index 502585c..3a4c50d 100644
--- a/chrome/browser/net/chrome_extensions_network_delegate.cc
+++ b/chrome/browser/net/chrome_extensions_network_delegate.cc
@@ -14,10 +14,12 @@
 #include "chrome/browser/extensions/api/proxy/proxy_api.h"
 #include "chrome/browser/extensions/event_router_forwarder.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/renderer_host/chrome_navigation_ui_data.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/resource_request_info.h"
 #include "extensions/browser/api/web_request/web_request_api.h"
+#include "extensions/browser/extension_navigation_ui_data.h"
 #include "extensions/browser/info_map.h"
 #include "extensions/browser/process_manager.h"
 #include "extensions/common/constants.h"
@@ -82,6 +84,19 @@
   }
 }
 
+extensions::ExtensionNavigationUIData* GetExtensionNavigationUIData(
+    net::URLRequest* request) {
+  const content::ResourceRequestInfo* info =
+      content::ResourceRequestInfo::ForRequest(request);
+  if (!info)
+    return nullptr;
+  ChromeNavigationUIData* navigation_data =
+      static_cast<ChromeNavigationUIData*>(info->GetNavigationUIData());
+  if (!navigation_data)
+    return nullptr;
+  return navigation_data->GetExtensionNavigationUIData();
+}
+
 class ChromeExtensionsNetworkDelegateImpl
     : public ChromeExtensionsNetworkDelegate {
  public:
@@ -176,7 +191,8 @@
   }
 
   return ExtensionWebRequestEventRouter::GetInstance()->OnBeforeRequest(
-      profile_, extension_info_map_.get(), request, callback, new_url);
+      profile_, extension_info_map_.get(),
+      GetExtensionNavigationUIData(request), request, callback, new_url);
 }
 
 int ChromeExtensionsNetworkDelegateImpl::OnBeforeStartTransaction(
@@ -184,14 +200,16 @@
     const net::CompletionCallback& callback,
     net::HttpRequestHeaders* headers) {
   return ExtensionWebRequestEventRouter::GetInstance()->OnBeforeSendHeaders(
-      profile_, extension_info_map_.get(), request, callback, headers);
+      profile_, extension_info_map_.get(),
+      GetExtensionNavigationUIData(request), request, callback, headers);
 }
 
 void ChromeExtensionsNetworkDelegateImpl::OnStartTransaction(
     net::URLRequest* request,
     const net::HttpRequestHeaders& headers) {
   ExtensionWebRequestEventRouter::GetInstance()->OnSendHeaders(
-      profile_, extension_info_map_.get(), request, headers);
+      profile_, extension_info_map_.get(),
+      GetExtensionNavigationUIData(request), request, headers);
 }
 
 int ChromeExtensionsNetworkDelegateImpl::OnHeadersReceived(
@@ -201,12 +219,9 @@
     scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
     GURL* allowed_unsafe_redirect_url) {
   return ExtensionWebRequestEventRouter::GetInstance()->OnHeadersReceived(
-      profile_,
-      extension_info_map_.get(),
-      request,
-      callback,
-      original_response_headers,
-      override_response_headers,
+      profile_, extension_info_map_.get(),
+      GetExtensionNavigationUIData(request), request, callback,
+      original_response_headers, override_response_headers,
       allowed_unsafe_redirect_url);
 }
 
@@ -214,14 +229,16 @@
     net::URLRequest* request,
     const GURL& new_location) {
   ExtensionWebRequestEventRouter::GetInstance()->OnBeforeRedirect(
-      profile_, extension_info_map_.get(), request, new_location);
+      profile_, extension_info_map_.get(),
+      GetExtensionNavigationUIData(request), request, new_location);
 }
 
 
 void ChromeExtensionsNetworkDelegateImpl::OnResponseStarted(
     net::URLRequest* request) {
   ExtensionWebRequestEventRouter::GetInstance()->OnResponseStarted(
-      profile_, extension_info_map_.get(), request);
+      profile_, extension_info_map_.get(),
+      GetExtensionNavigationUIData(request), request);
   ForwardProxyErrors(request);
 }
 
@@ -234,7 +251,8 @@
             request->response_headers()->response_code());
     if (!is_redirect) {
       ExtensionWebRequestEventRouter::GetInstance()->OnCompleted(
-          profile_, extension_info_map_.get(), request);
+          profile_, extension_info_map_.get(),
+          GetExtensionNavigationUIData(request), request);
     }
     return;
   }
@@ -242,7 +260,8 @@
   if (request->status().status() == net::URLRequestStatus::FAILED ||
       request->status().status() == net::URLRequestStatus::CANCELED) {
     ExtensionWebRequestEventRouter::GetInstance()->OnErrorOccurred(
-        profile_, extension_info_map_.get(), request, started);
+        profile_, extension_info_map_.get(),
+        GetExtensionNavigationUIData(request), request, started);
     return;
   }
 
@@ -269,7 +288,8 @@
     const AuthCallback& callback,
     net::AuthCredentials* credentials) {
   return ExtensionWebRequestEventRouter::GetInstance()->OnAuthRequired(
-      profile_, extension_info_map_.get(), request, auth_info, callback,
+      profile_, extension_info_map_.get(),
+      GetExtensionNavigationUIData(request), request, auth_info, callback,
       credentials);
 }
 
diff --git a/chrome/browser/notifications/platform_notification_service_impl.cc b/chrome/browser/notifications/platform_notification_service_impl.cc
index 048fe0a..8eca908 100644
--- a/chrome/browser/notifications/platform_notification_service_impl.cc
+++ b/chrome/browser/notifications/platform_notification_service_impl.cc
@@ -7,7 +7,6 @@
 #include <utility>
 #include <vector>
 
-#include "base/command_line.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics_action.h"
 #include "base/strings/utf_string_conversions.h"
@@ -23,19 +22,16 @@
 #include "chrome/browser/profiles/profile_io_data.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "components/prefs/pref_service.h"
-#include "components/url_formatter/url_formatter.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/desktop_notification_delegate.h"
 #include "content/public/browser/notification_event_dispatcher.h"
 #include "content/public/browser/permission_type.h"
-#include "content/public/browser/storage_partition.h"
 #include "content/public/browser/user_metrics.h"
 #include "content/public/common/notification_resources.h"
 #include "content/public/common/platform_notification_data.h"
@@ -46,6 +42,11 @@
 #include "ui/message_center/notifier_settings.h"
 #include "url/url_constants.h"
 
+#if BUILDFLAG(ENABLE_BACKGROUND)
+#include "chrome/browser/lifetime/keep_alive_types.h"
+#include "chrome/browser/lifetime/scoped_keep_alive.h"
+#endif
+
 #if defined(ENABLE_EXTENSIONS)
 #include "chrome/browser/notifications/notifier_state_tracker.h"
 #include "chrome/browser/notifications/notifier_state_tracker_factory.h"
@@ -56,17 +57,10 @@
 #include "extensions/common/permissions/permissions_data.h"
 #endif
 
-#if BUILDFLAG(ENABLE_BACKGROUND)
-#include "chrome/browser/lifetime/keep_alive_types.h"
-#include "chrome/browser/lifetime/scoped_keep_alive.h"
-#endif
-
 using content::BrowserContext;
 using content::BrowserThread;
 using message_center::NotifierId;
 
-class ProfileAttributesEntry;
-
 namespace {
 
 // Invalid id for a renderer process. Used in cases where we need to check for
@@ -445,8 +439,8 @@
 
   // Developer supplied action buttons.
   std::vector<message_center::ButtonInfo> buttons;
-  for (size_t i = 0; i < notification_data.actions.size(); i++) {
-    content::PlatformNotificationAction const& action =
+  for (size_t i = 0; i < notification_data.actions.size(); ++i) {
+    const content::PlatformNotificationAction& action =
         notification_data.actions[i];
     message_center::ButtonInfo button(action.title);
     // TODO(peter): Handle different screen densities instead of always using
@@ -481,9 +475,9 @@
 NotificationDisplayService*
 PlatformNotificationServiceImpl::GetNotificationDisplayService(
     Profile* profile) {
-  if (test_display_service_ != nullptr)
-    return test_display_service_;
-  return NotificationDisplayServiceFactory::GetForProfile(profile);
+  return test_display_service_
+             ? test_display_service_
+             : NotificationDisplayServiceFactory::GetForProfile(profile);
 }
 
 base::string16 PlatformNotificationServiceImpl::DisplayNameForContextMessage(
diff --git a/chrome/browser/notifications/platform_notification_service_unittest.cc b/chrome/browser/notifications/platform_notification_service_unittest.cc
index ac36b8c..5f39564 100644
--- a/chrome/browser/notifications/platform_notification_service_unittest.cc
+++ b/chrome/browser/notifications/platform_notification_service_unittest.cc
@@ -77,6 +77,8 @@
  private:
   bool displayed_;
   bool clicked_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockDesktopNotificationDelegate);
 };
 
 }  // namespace
@@ -84,14 +86,14 @@
 class PlatformNotificationServiceTest : public testing::Test {
  public:
   void SetUp() override {
-    profile_manager_.reset(
-        new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
+    profile_manager_ = base::MakeUnique<TestingProfileManager>(
+        TestingBrowserProcess::GetGlobal());
     ASSERT_TRUE(profile_manager_->SetUp());
     profile_ = profile_manager_->CreateTestingProfile("Miguel");
-    std::unique_ptr<NotificationUIManager> ui_manager(
-        new StubNotificationUIManager);
-    std::unique_ptr<NotificationPlatformBridge> notification_bridge(
-        new StubNotificationPlatformBridge());
+    std::unique_ptr<NotificationUIManager> ui_manager =
+        base::MakeUnique<StubNotificationUIManager>();
+    std::unique_ptr<NotificationPlatformBridge> notification_bridge =
+        base::MakeUnique<StubNotificationPlatformBridge>();
 
     TestingBrowserProcess::GetGlobal()->SetNotificationUIManager(
         std::move(ui_manager));
@@ -254,7 +256,11 @@
   notification_data.vibration_pattern = vibration_pattern;
   notification_data.silent = true;
   notification_data.actions.resize(2);
+  notification_data.actions[0].type =
+      content::PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON;
   notification_data.actions[0].title = base::ASCIIToUTF16("Button 1");
+  notification_data.actions[1].type =
+      content::PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON;
   notification_data.actions[1].title = base::ASCIIToUTF16("Button 2");
 
   NotificationResources notification_resources;
diff --git a/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc b/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
index 8e7e3d6..4d19b304 100644
--- a/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
+++ b/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
@@ -32,11 +32,11 @@
 #include "components/ntp_snippets/content_suggestions_service.h"
 #include "components/ntp_snippets/features.h"
 #include "components/ntp_snippets/ntp_snippets_constants.h"
-#include "components/ntp_snippets/ntp_snippets_database.h"
-#include "components/ntp_snippets/ntp_snippets_fetcher.h"
-#include "components/ntp_snippets/ntp_snippets_scheduler.h"
-#include "components/ntp_snippets/ntp_snippets_service.h"
-#include "components/ntp_snippets/ntp_snippets_status_service.h"
+#include "components/ntp_snippets/remote/ntp_snippets_database.h"
+#include "components/ntp_snippets/remote/ntp_snippets_fetcher.h"
+#include "components/ntp_snippets/remote/ntp_snippets_scheduler.h"
+#include "components/ntp_snippets/remote/ntp_snippets_service.h"
+#include "components/ntp_snippets/remote/ntp_snippets_status_service.h"
 #include "components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.h"
 #include "components/ntp_snippets/sessions/tab_delegate_sync_adapter.h"
 #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/permissions/grouped_permission_infobar_delegate.cc b/chrome/browser/permissions/grouped_permission_infobar_delegate.cc
deleted file mode 100644
index 6ea8084..0000000
--- a/chrome/browser/permissions/grouped_permission_infobar_delegate.cc
+++ /dev/null
@@ -1,100 +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.
-
-#include "chrome/browser/permissions/grouped_permission_infobar_delegate.h"
-#include "chrome/browser/permissions/permission_util.h"
-#include "chrome/grit/generated_resources.h"
-#include "chrome/grit/theme_resources.h"
-#include "components/url_formatter/elide_url.h"
-#include "ui/base/l10n/l10n_util.h"
-
-GroupedPermissionInfoBarDelegate::GroupedPermissionInfoBarDelegate(
-    const GURL& requesting_origin,
-    const std::vector<ContentSettingsType>& types)
-    : requesting_origin_(requesting_origin),
-      types_(types),
-      accept_states_(types_.size(), true),
-      persist_(true) {}
-
-GroupedPermissionInfoBarDelegate::~GroupedPermissionInfoBarDelegate() {}
-
-infobars::InfoBarDelegate::Type
-GroupedPermissionInfoBarDelegate::GetInfoBarType() const {
-  return PAGE_ACTION_TYPE;
-}
-
-bool GroupedPermissionInfoBarDelegate::ShouldShowPersistenceToggle() const {
-  return PermissionUtil::ShouldShowPersistenceToggle();
-}
-
-int GroupedPermissionInfoBarDelegate::GetButtons() const {
-  if (GetPermissionCount() >= 2)
-    return ConfirmInfoBarDelegate::InfoBarButton::BUTTON_OK;
-  else
-    return ConfirmInfoBarDelegate::GetButtons();
-}
-
-base::string16 GroupedPermissionInfoBarDelegate::GetButtonLabel(
-    InfoBarButton button) const {
-  if (GetPermissionCount() >= 2) {
-    return ConfirmInfoBarDelegate::GetButtonLabel(button);
-  } else {
-    return l10n_util::GetStringUTF16(
-        (button == BUTTON_OK) ? IDS_PERMISSION_ALLOW : IDS_PERMISSION_DENY);
-  }
-}
-
-base::string16 GroupedPermissionInfoBarDelegate::GetMessageText() const {
-  return l10n_util::GetStringFUTF16(
-      IDS_PERMISSIONS_BUBBLE_PROMPT,
-      url_formatter::FormatUrlForSecurityDisplay(requesting_origin_));
-}
-
-int GroupedPermissionInfoBarDelegate::GetPermissionCount() const {
-  return types_.size();
-}
-
-ContentSettingsType GroupedPermissionInfoBarDelegate::GetContentSettingType(
-    int index) const {
-  DCHECK(index >= 0 && index < static_cast<int>(types_.size()));
-  return types_[index];
-}
-
-int GroupedPermissionInfoBarDelegate::GetIconIdForPermission(int index) const {
-  DCHECK(index >= 0 && index < static_cast<int>(types_.size()));
-  ContentSettingsType type = types_[index];
-  if (type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC) {
-    return IDR_INFOBAR_MEDIA_STREAM_MIC;
-  } else if (type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA) {
-    return IDR_INFOBAR_MEDIA_STREAM_CAMERA;
-  }
-  return IDR_INFOBAR_WARNING;
-}
-
-base::string16 GroupedPermissionInfoBarDelegate::GetMessageTextFragment(
-    int index) const {
-  DCHECK(index >= 0 && index < static_cast<int>(types_.size()));
-  ContentSettingsType type = types_[index];
-  int message_id;
-  if (type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC) {
-    message_id = IDS_MEDIA_CAPTURE_AUDIO_ONLY_PERMISSION_FRAGMENT;
-  } else if (type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA) {
-    message_id = IDS_MEDIA_CAPTURE_VIDEO_ONLY_PERMISSION_FRAGMENT;
-  } else {
-    NOTREACHED();
-    return base::string16();
-  }
-  return l10n_util::GetStringUTF16(message_id);
-}
-
-void GroupedPermissionInfoBarDelegate::ToggleAccept(int position,
-                                                    bool new_value) {
-  DCHECK(position >= 0 && position < static_cast<int>(types_.size()));
-  accept_states_[position] = new_value;
-}
-
-bool GroupedPermissionInfoBarDelegate::GetAcceptState(int position) {
-  DCHECK(position >= 0 && position < static_cast<int>(types_.size()));
-  return accept_states_[position];
-}
diff --git a/chrome/browser/permissions/grouped_permission_infobar_delegate.h b/chrome/browser/permissions/grouped_permission_infobar_delegate.h
deleted file mode 100644
index 70dc48d..0000000
--- a/chrome/browser/permissions/grouped_permission_infobar_delegate.h
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_PERMISSIONS_GROUPED_PERMISSION_INFOBAR_DELEGATE_H_
-#define CHROME_BROWSER_PERMISSIONS_GROUPED_PERMISSION_INFOBAR_DELEGATE_H_
-
-#include <memory>
-
-#include "base/callback.h"
-#include "components/content_settings/core/common/content_settings_types.h"
-#include "components/infobars/core/confirm_infobar_delegate.h"
-
-class GURL;
-class InfoBarService;
-
-namespace infobars {
-class InfoBarManager;
-}
-
-// Configures an InfoBar to display a group of permission requests, each of
-// which can be allowed or blocked independently.
-// TODO(tsergeant): Expand this class so it can be used without subclassing.
-class GroupedPermissionInfoBarDelegate : public ConfirmInfoBarDelegate {
- public:
-  // Implementation is in platform-specific infobar file.
-  static std::unique_ptr<infobars::InfoBar> CreateInfoBar(
-      infobars::InfoBarManager* infobar_manager,
-      std::unique_ptr<GroupedPermissionInfoBarDelegate> delegate);
-
-  GroupedPermissionInfoBarDelegate(
-      const GURL& requesting_origin,
-      const std::vector<ContentSettingsType>& types);
-  ~GroupedPermissionInfoBarDelegate() override;
-
-  bool ShouldShowPersistenceToggle() const;
-  bool persist() const { return persist_; }
-  void set_persist(bool persist) { persist_ = persist; }
-
-  base::string16 GetMessageText() const override;
-
-  int GetPermissionCount() const;
-  ContentSettingsType GetContentSettingType(int index) const;
-  int GetIconIdForPermission(int index) const;
-  // Message text to display for an individual permission at |index|.
-  base::string16 GetMessageTextFragment(int index) const;
-
-  void ToggleAccept(int position, bool new_value);
-
- protected:
-  bool GetAcceptState(int position);
-
- private:
-  // ConfirmInfoBarDelegate:
-  base::string16 GetButtonLabel(InfoBarButton button) const override;
-  int GetButtons() const override;
-
-  // InfoBarDelegate:
-  Type GetInfoBarType() const override;
-
-  const GURL requesting_origin_;
-  const std::vector<ContentSettingsType> types_;
-  std::vector<bool> accept_states_;
-  bool persist_;
-
-  DISALLOW_COPY_AND_ASSIGN(GroupedPermissionInfoBarDelegate);
-};
-
-#endif  // CHROME_BROWSER_PERMISSIONS_GROUPED_PERMISSION_INFOBAR_DELEGATE_H_
diff --git a/chrome/browser/permissions/grouped_permission_infobar_delegate_android.cc b/chrome/browser/permissions/grouped_permission_infobar_delegate_android.cc
new file mode 100644
index 0000000..2cbb3b0
--- /dev/null
+++ b/chrome/browser/permissions/grouped_permission_infobar_delegate_android.cc
@@ -0,0 +1,116 @@
+// 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.
+
+#include "chrome/browser/permissions/grouped_permission_infobar_delegate_android.h"
+
+#include "base/memory/ptr_util.h"
+#include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/permissions/permission_util.h"
+#include "chrome/browser/ui/android/infobars/grouped_permission_infobar.h"
+#include "chrome/grit/generated_resources.h"
+#include "chrome/grit/theme_resources.h"
+#include "components/infobars/core/infobar.h"
+#include "components/url_formatter/elide_url.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/strings/grit/ui_strings.h"
+
+GroupedPermissionInfoBarDelegate::~GroupedPermissionInfoBarDelegate() {}
+
+// static
+infobars::InfoBar* GroupedPermissionInfoBarDelegate::Create(
+    InfoBarService* infobar_service,
+    const GURL& requesting_origin,
+    const std::vector<ContentSettingsType>& types) {
+  return infobar_service->AddInfoBar(
+      base::MakeUnique<GroupedPermissionInfoBar>(base::WrapUnique(
+          new GroupedPermissionInfoBarDelegate(requesting_origin, types))));
+}
+
+bool GroupedPermissionInfoBarDelegate::ShouldShowPersistenceToggle() const {
+  return PermissionUtil::ShouldShowPersistenceToggle();
+}
+
+ContentSettingsType GroupedPermissionInfoBarDelegate::GetContentSettingType(
+    size_t position) const {
+  DCHECK_LT(position, types_.size());
+  return types_[position];
+}
+
+int GroupedPermissionInfoBarDelegate::GetIconIdForPermission(
+    size_t position) const {
+  DCHECK_LT(position, types_.size());
+  ContentSettingsType type = types_[position];
+  if (type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC)
+    return IDR_INFOBAR_MEDIA_STREAM_MIC;
+  if (type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA)
+    return IDR_INFOBAR_MEDIA_STREAM_CAMERA;
+
+  return IDR_INFOBAR_WARNING;
+}
+
+base::string16 GroupedPermissionInfoBarDelegate::GetMessageTextFragment(
+    size_t position) const {
+  DCHECK_LT(position, types_.size());
+  ContentSettingsType type = types_[position];
+
+  const bool is_mic = (type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
+  DCHECK(is_mic || (type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA));
+  return l10n_util::GetStringUTF16(
+      is_mic ? IDS_MEDIA_CAPTURE_AUDIO_ONLY_PERMISSION_FRAGMENT
+             : IDS_MEDIA_CAPTURE_VIDEO_ONLY_PERMISSION_FRAGMENT);
+}
+
+void GroupedPermissionInfoBarDelegate::ToggleAccept(size_t position,
+                                                    bool new_value) {
+  DCHECK_LT(position, types_.size());
+  accept_states_[position] = new_value;
+}
+
+base::string16 GroupedPermissionInfoBarDelegate::GetMessageText() const {
+  return l10n_util::GetStringFUTF16(
+      IDS_PERMISSIONS_BUBBLE_PROMPT,
+      url_formatter::FormatUrlForSecurityDisplay(requesting_origin_));
+}
+
+bool GroupedPermissionInfoBarDelegate::GetAcceptState(size_t position) {
+  DCHECK_LT(position, types_.size());
+  return accept_states_[position];
+}
+
+GroupedPermissionInfoBarDelegate::GroupedPermissionInfoBarDelegate(
+    const GURL& requesting_origin,
+    const std::vector<ContentSettingsType>& types)
+    : requesting_origin_(requesting_origin),
+      types_(types),
+      accept_states_(types_.size(), true),
+      persist_(true) {}
+
+infobars::InfoBarDelegate::InfoBarIdentifier
+GroupedPermissionInfoBarDelegate::GetIdentifier() const {
+  return GROUPED_PERMISSION_INFOBAR_DELEGATE_ANDROID;
+}
+
+infobars::InfoBarDelegate::Type
+GroupedPermissionInfoBarDelegate::GetInfoBarType() const {
+  return PAGE_ACTION_TYPE;
+}
+
+int GroupedPermissionInfoBarDelegate::GetButtons() const {
+  // If there is only one permission in the infobar, we show both OK and CANCEL
+  // button to allow/deny it. If there are multiple, we only show OK button
+  // which means making decision for all permissions according to each accept
+  // toggle.
+  return (permission_count() > 1) ? BUTTON_OK : (BUTTON_OK | BUTTON_CANCEL);
+}
+
+base::string16 GroupedPermissionInfoBarDelegate::GetButtonLabel(
+    InfoBarButton button) const {
+  if (permission_count() > 1) {
+    return l10n_util::GetStringUTF16((button == BUTTON_OK) ? IDS_APP_OK
+                                                           : IDS_APP_CANCEL);
+  }
+
+  return l10n_util::GetStringUTF16((button == BUTTON_OK) ? IDS_PERMISSION_ALLOW
+                                                         : IDS_PERMISSION_DENY);
+}
diff --git a/chrome/browser/permissions/grouped_permission_infobar_delegate_android.h b/chrome/browser/permissions/grouped_permission_infobar_delegate_android.h
new file mode 100644
index 0000000..7e48c6c7
--- /dev/null
+++ b/chrome/browser/permissions/grouped_permission_infobar_delegate_android.h
@@ -0,0 +1,73 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_PERMISSIONS_GROUPED_PERMISSION_INFOBAR_DELEGATE_ANDROID_H_
+#define CHROME_BROWSER_PERMISSIONS_GROUPED_PERMISSION_INFOBAR_DELEGATE_ANDROID_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "components/content_settings/core/common/content_settings_types.h"
+#include "components/infobars/core/confirm_infobar_delegate.h"
+
+class GURL;
+class InfoBarService;
+
+// An InfoBar that displays a group of permission requests, each of which can be
+// allowed or blocked independently.
+// TODO(tsergeant): Expand this class so it can be used without subclassing.
+class GroupedPermissionInfoBarDelegate : public ConfirmInfoBarDelegate {
+ public:
+  // Public so we can have std::unique_ptr<GroupedPermissionInfoBarDelegate>.
+  ~GroupedPermissionInfoBarDelegate() override;
+
+  static infobars::InfoBar* Create(
+      InfoBarService* infobar_service,
+      const GURL& requesting_origin,
+      const std::vector<ContentSettingsType>& types);
+
+  bool persist() const { return persist_; }
+  void set_persist(bool persist) { persist_ = persist; }
+  size_t permission_count() const { return types_.size(); }
+
+  // Returns true if the infobar should display a toggle to allow users to
+  // opt-out of persisting their accept/deny decision.
+  bool ShouldShowPersistenceToggle() const;
+
+  ContentSettingsType GetContentSettingType(size_t position) const;
+  int GetIconIdForPermission(size_t position) const;
+
+  // Message text to display for an individual permission at |position|.
+  base::string16 GetMessageTextFragment(size_t position) const;
+
+  // Toggle accept value for an individual permission at |position|.
+  void ToggleAccept(size_t position, bool new_value);
+
+  // ConfirmInfoBarDelegate:
+  base::string16 GetMessageText() const override;
+
+ protected:
+  bool GetAcceptState(size_t position);
+
+ private:
+  GroupedPermissionInfoBarDelegate(
+      const GURL& requesting_origin,
+      const std::vector<ContentSettingsType>& types);
+
+  // ConfirmInfoBarDelegate:
+  InfoBarIdentifier GetIdentifier() const override;
+  Type GetInfoBarType() const override;
+  int GetButtons() const override;
+  base::string16 GetButtonLabel(InfoBarButton button) const override;
+
+  const GURL requesting_origin_;
+  const std::vector<ContentSettingsType> types_;
+  std::vector<bool> accept_states_;
+  // Whether the accept/deny decision is persisted.
+  bool persist_;
+
+  DISALLOW_COPY_AND_ASSIGN(GroupedPermissionInfoBarDelegate);
+};
+
+#endif  // CHROME_BROWSER_PERMISSIONS_GROUPED_PERMISSION_INFOBAR_DELEGATE_ANDROID_H_
diff --git a/chrome/browser/permissions/permission_context_base.cc b/chrome/browser/permissions/permission_context_base.cc
index 341e3f7..8e0e4ee 100644
--- a/chrome/browser/permissions/permission_context_base.cc
+++ b/chrome/browser/permissions/permission_context_base.cc
@@ -273,13 +273,9 @@
   UpdateTabContext(id, requesting_origin,
                    content_setting == CONTENT_SETTING_ALLOW);
 
-  if (content_setting == CONTENT_SETTING_DEFAULT) {
-    content_setting =
-        HostContentSettingsMapFactory::GetForProfile(profile_)
-            ->GetDefaultContentSetting(content_settings_type_, nullptr);
-  }
+  if (content_setting == CONTENT_SETTING_DEFAULT)
+    content_setting = CONTENT_SETTING_ASK;
 
-  DCHECK_NE(content_setting, CONTENT_SETTING_DEFAULT);
   callback.Run(content_setting);
 }
 
diff --git a/chrome/browser/plugins/plugin_info_message_filter.cc b/chrome/browser/plugins/plugin_info_message_filter.cc
index b1ea5b4..1d61fab 100644
--- a/chrome/browser/plugins/plugin_info_message_filter.cc
+++ b/chrome/browser/plugins/plugin_info_message_filter.cc
@@ -365,7 +365,10 @@
   }
 #endif  // defined(ENABLE_EXTENSIONS)
 
-  if (plugin_setting == CONTENT_SETTING_DETECT_IMPORTANT_CONTENT) {
+  if (plugin_setting == CONTENT_SETTING_DETECT_IMPORTANT_CONTENT ||
+      (plugin_setting == CONTENT_SETTING_ALLOW &&
+       base::FeatureList::IsEnabled(features::kPreferHtmlOverPlugins) &&
+       !base::FeatureList::IsEnabled(features::kRunAllFlashInAllowMode))) {
     *status = ChromeViewHostMsg_GetPluginInfo_Status::kPlayImportantContent;
   } else if (plugin_setting == CONTENT_SETTING_BLOCK) {
     // For managed users with the ASK policy, we allow manually running plugins
diff --git a/chrome/browser/plugins/plugin_power_saver_browsertest.cc b/chrome/browser/plugins/plugin_power_saver_browsertest.cc
index 6cb3bd6..63136c54 100644
--- a/chrome/browser/plugins/plugin_power_saver_browsertest.cc
+++ b/chrome/browser/plugins/plugin_power_saver_browsertest.cc
@@ -12,6 +12,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
+#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -20,6 +21,7 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/test_switches.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/zoom/zoom_controller.h"
 #include "content/public/browser/readback_types.h"
 #include "content/public/browser/render_frame_host.h"
@@ -312,6 +314,14 @@
         GetActiveWebContents()->GetMainFrame()));
   }
 
+  // Loads a peripheral plugin (small cross origin) named 'plugin'.
+  void LoadPeripheralPlugin() {
+    LoadHTML(
+        "<object id='plugin' data='http://otherorigin.com/fake.swf' "
+        "    type='application/x-shockwave-flash' width='400' height='100'>"
+        "</object>");
+  }
+
   // Returns the background WebContents.
   content::WebContents* LoadHTMLInBackgroundTab(const std::string& html) {
     embedded_test_server()->RegisterRequestHandler(
@@ -457,6 +467,23 @@
   SimulateClickAndAwaitMarkedEssential("plugin_poster", gfx::Point(50, 150));
 }
 
+IN_PROC_BROWSER_TEST_F(PluginPowerSaverBrowserTest, ContentSettings) {
+  HostContentSettingsMap* content_settings_map =
+      HostContentSettingsMapFactory::GetForProfile(browser()->profile());
+
+  // Throttle on DETECT.
+  content_settings_map->SetDefaultContentSetting(
+      CONTENT_SETTINGS_TYPE_PLUGINS, CONTENT_SETTING_DETECT_IMPORTANT_CONTENT);
+  LoadPeripheralPlugin();
+  VerifyPluginIsThrottled(GetActiveWebContents(), "plugin");
+
+  // Don't throttle on ALLOW.
+  content_settings_map->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS,
+                                                 CONTENT_SETTING_ALLOW);
+  LoadPeripheralPlugin();
+  VerifyPluginMarkedEssential(GetActiveWebContents(), "plugin");
+}
+
 IN_PROC_BROWSER_TEST_F(PluginPowerSaverBrowserTest, SmallerThanPlayIcon) {
   LoadHTML(
       "<object id='plugin_16' type='application/x-shockwave-flash' "
@@ -622,10 +649,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(PluginPowerSaverBrowserTest, ExpandingSmallPlugin) {
-  LoadHTML(
-      "<object id='plugin' data='http://otherorigin.com/fake.swf' "
-      "    type='application/x-shockwave-flash' width='400' height='80'>"
-      "</object>");
+  LoadPeripheralPlugin();
   VerifyPluginIsThrottled(GetActiveWebContents(), "plugin");
 
   std::string script = "window.document.getElementById('plugin').height = 400;";
@@ -738,3 +762,27 @@
   VerifyPluginMarkedEssential(GetActiveWebContents(), "tiny_cross_origin_1");
   VerifyPluginMarkedEssential(GetActiveWebContents(), "tiny_cross_origin_2");
 }
+
+// Separate test case with HTML By Default feature flag on.
+class PluginPowerSaverPreferHtmlBrowserTest
+    : public PluginPowerSaverBrowserTest {
+ public:
+  void SetUpInProcessBrowserTestFixture() override {
+    PluginPowerSaverBrowserTest::SetUpInProcessBrowserTestFixture();
+    feature_list.InitAndEnableFeature(features::kPreferHtmlOverPlugins);
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list;
+};
+
+IN_PROC_BROWSER_TEST_F(PluginPowerSaverPreferHtmlBrowserTest,
+                       ThrottlePluginsOnAllowContentSetting) {
+  HostContentSettingsMap* content_settings_map =
+      HostContentSettingsMapFactory::GetForProfile(browser()->profile());
+
+  content_settings_map->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS,
+                                                 CONTENT_SETTING_ALLOW);
+  LoadPeripheralPlugin();
+  VerifyPluginIsThrottled(GetActiveWebContents(), "plugin");
+}
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.cc b/chrome/browser/predictors/resource_prefetch_predictor.cc
index b34cd78..bc80138 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor.cc
+++ b/chrome/browser/predictors/resource_prefetch_predictor.cc
@@ -10,6 +10,7 @@
 
 #include "base/command_line.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/sparse_histogram.h"
 #include "base/strings/string_number_conversions.h"
@@ -23,7 +24,6 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/url_constants.h"
 #include "components/history/core/browser/history_database.h"
-#include "components/history/core/browser/history_db_task.h"
 #include "components/history/core/browser/history_service.h"
 #include "components/mime_util/mime_util.h"
 #include "content/public/browser/browser_thread.h"
@@ -66,52 +66,6 @@
 namespace predictors {
 
 ////////////////////////////////////////////////////////////////////////////////
-// History lookup task.
-
-// Used to fetch the visit count for a URL from the History database.
-class GetUrlVisitCountTask : public history::HistoryDBTask {
- public:
-  typedef ResourcePrefetchPredictor::URLRequestSummary URLRequestSummary;
-  typedef base::Callback<void(
-      size_t,   // Visit count.
-      const NavigationID&,
-      const std::vector<URLRequestSummary>&)> VisitInfoCallback;
-
-  GetUrlVisitCountTask(
-      const NavigationID& navigation_id,
-      std::vector<URLRequestSummary>* requests,
-      VisitInfoCallback callback)
-      : visit_count_(0),
-        navigation_id_(navigation_id),
-        requests_(requests),
-        callback_(callback) {
-    DCHECK(requests_.get());
-  }
-
-  bool RunOnDBThread(history::HistoryBackend* backend,
-                     history::HistoryDatabase* db) override {
-    history::URLRow url_row;
-    if (db->GetRowForURL(navigation_id_.main_frame_url, &url_row))
-      visit_count_ = url_row.visit_count();
-    return true;
-  }
-
-  void DoneRunOnMainThread() override {
-    callback_.Run(visit_count_, navigation_id_, *requests_);
-  }
-
- private:
-  ~GetUrlVisitCountTask() override {}
-
-  int visit_count_;
-  NavigationID navigation_id_;
-  std::unique_ptr<std::vector<URLRequestSummary>> requests_;
-  VisitInfoCallback callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(GetUrlVisitCountTask);
-};
-
-////////////////////////////////////////////////////////////////////////////////
 // ResourcePrefetchPredictor static functions.
 
 // static
@@ -257,7 +211,7 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// ResourcePrefetchPredictor structs.
+// ResourcePrefetchPredictor nested types.
 
 ResourcePrefetchPredictor::URLRequestSummary::URLRequestSummary()
     : resource_type(content::RESOURCE_TYPE_LAST_TYPE),
@@ -318,6 +272,38 @@
   return true;
 }
 
+ResourcePrefetchPredictor::GetUrlVisitCountTask::GetUrlVisitCountTask(
+    const NavigationID& navigation_id,
+    std::unique_ptr<PageRequestSummary> summary,
+    VisitInfoCallback callback)
+    : visit_count_(0),
+      navigation_id_(navigation_id),
+      summary_(std::move(summary)),
+      callback_(callback) {
+  DCHECK(summary_.get());
+}
+
+bool ResourcePrefetchPredictor::GetUrlVisitCountTask::RunOnDBThread(
+    history::HistoryBackend* backend,
+    history::HistoryDatabase* db) {
+  history::URLRow url_row;
+  if (db->GetRowForURL(navigation_id_.main_frame_url, &url_row))
+    visit_count_ = url_row.visit_count();
+  return true;
+}
+
+void ResourcePrefetchPredictor::GetUrlVisitCountTask::DoneRunOnMainThread() {
+  callback_.Run(visit_count_, navigation_id_, *summary_);
+}
+
+ResourcePrefetchPredictor::GetUrlVisitCountTask::~GetUrlVisitCountTask() {}
+
+ResourcePrefetchPredictor::PageRequestSummary::PageRequestSummary(
+    const GURL& i_initial_url)
+    : initial_url(i_initial_url) {}
+
+ResourcePrefetchPredictor::PageRequestSummary::~PageRequestSummary() {}
+
 ////////////////////////////////////////////////////////////////////////////////
 // ResourcePrefetchPredictor.
 
@@ -414,9 +400,10 @@
   CleanupAbandonedNavigations(request.navigation_id);
 
   // New empty navigation entry.
-  inflight_navigations_.insert(std::make_pair(
-      request.navigation_id,
-      make_linked_ptr(new std::vector<URLRequestSummary>())));
+  const GURL& initial_url = request.navigation_id.main_frame_url;
+  inflight_navigations_.insert(
+      std::make_pair(request.navigation_id,
+                     base::MakeUnique<PageRequestSummary>(initial_url)));
 }
 
 void ResourcePrefetchPredictor::OnMainFrameResponse(
@@ -432,27 +419,33 @@
     const URLRequestSummary& response) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  // TODO(shishir): There are significant gains to be had here if we can use the
-  // start URL in a redirect chain as the key to start prefetching. We can save
-  // of redirect times considerably assuming that the redirect chains do not
-  // change.
-
   // Stop any inflight prefetching. Remove the older navigation.
   StopPrefetching(response.navigation_id);
-  inflight_navigations_.erase(response.navigation_id);
 
-  // A redirect will not lead to another OnMainFrameRequest call, so record the
-  // redirect url as a new navigation.
+  std::unique_ptr<PageRequestSummary> summary;
+  NavigationMap::iterator nav_it =
+      inflight_navigations_.find(response.navigation_id);
+  if (nav_it != inflight_navigations_.end()) {
+    summary.reset(nav_it->second.release());
+    inflight_navigations_.erase(nav_it);
+  }
 
   // The redirect url may be empty if the URL was invalid.
   if (response.redirect_url.is_empty())
     return;
 
+  // If we lost the information about the first hop for some reason.
+  if (!summary) {
+    const GURL& initial_url = response.navigation_id.main_frame_url;
+    summary = base::MakeUnique<PageRequestSummary>(initial_url);
+  }
+
+  // A redirect will not lead to another OnMainFrameRequest call, so record the
+  // redirect url as a new navigation id and save the initial url.
   NavigationID navigation_id(response.navigation_id);
   navigation_id.main_frame_url = response.redirect_url;
-  inflight_navigations_.insert(std::make_pair(
-      navigation_id,
-      make_linked_ptr(new std::vector<URLRequestSummary>())));
+  inflight_navigations_.insert(
+      std::make_pair(navigation_id, std::move(summary)));
 }
 
 void ResourcePrefetchPredictor::OnSubresourceResponse(
@@ -465,7 +458,7 @@
     return;
   }
 
-  nav_it->second->push_back(response);
+  nav_it->second->subresource_requests.push_back(response);
 }
 
 void ResourcePrefetchPredictor::OnNavigationComplete(
@@ -480,7 +473,7 @@
   const NavigationID navigation_id(nav_it->first);
 
   // Remove the navigation from the inflight navigations.
-  std::vector<URLRequestSummary>* requests = (nav_it->second).release();
+  std::unique_ptr<PageRequestSummary> summary = std::move(nav_it->second);
   inflight_navigations_.erase(nav_it);
 
   // Kick off history lookup to determine if we should record the URL.
@@ -490,7 +483,7 @@
   DCHECK(history_service);
   history_service->ScheduleDBTask(
       std::unique_ptr<history::HistoryDBTask>(new GetUrlVisitCountTask(
-          navigation_id, requests,
+          navigation_id, std::move(summary),
           base::Bind(&ResourcePrefetchPredictor::OnVisitCountLookup,
                      AsWeakPtr()))),
       &history_lookup_consumer_);
@@ -586,31 +579,40 @@
   initialization_state_ = INITIALIZING;
 
   // Create local caches using the database as loaded.
-  std::unique_ptr<PrefetchDataMap> url_data_map(new PrefetchDataMap());
-  std::unique_ptr<PrefetchDataMap> host_data_map(new PrefetchDataMap());
-  PrefetchDataMap* url_data_ptr = url_data_map.get();
-  PrefetchDataMap* host_data_ptr = host_data_map.get();
+  auto url_data_map = base::MakeUnique<PrefetchDataMap>();
+  auto host_data_map = base::MakeUnique<PrefetchDataMap>();
+  auto url_redirect_data_map = base::MakeUnique<RedirectDataMap>();
+  auto host_redirect_data_map = base::MakeUnique<RedirectDataMap>();
 
   BrowserThread::PostTaskAndReply(
       BrowserThread::DB, FROM_HERE,
-      base::Bind(&ResourcePrefetchPredictorTables::GetAllData,
-                 tables_, url_data_ptr, host_data_ptr),
+      base::Bind(&ResourcePrefetchPredictorTables::GetAllData, tables_,
+                 url_data_map.get(), host_data_map.get(),
+                 url_redirect_data_map.get(), host_redirect_data_map.get()),
       base::Bind(&ResourcePrefetchPredictor::CreateCaches, AsWeakPtr(),
-                 base::Passed(&url_data_map), base::Passed(&host_data_map)));
+                 base::Passed(&url_data_map), base::Passed(&host_data_map),
+                 base::Passed(&url_redirect_data_map),
+                 base::Passed(&host_redirect_data_map)));
 }
 
 void ResourcePrefetchPredictor::CreateCaches(
     std::unique_ptr<PrefetchDataMap> url_data_map,
-    std::unique_ptr<PrefetchDataMap> host_data_map) {
+    std::unique_ptr<PrefetchDataMap> host_data_map,
+    std::unique_ptr<RedirectDataMap> url_redirect_data_map,
+    std::unique_ptr<RedirectDataMap> host_redirect_data_map) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   DCHECK_EQ(INITIALIZING, initialization_state_);
   DCHECK(!url_table_cache_);
   DCHECK(!host_table_cache_);
+  DCHECK(!url_redirect_table_cache_);
+  DCHECK(!host_redirect_table_cache_);
   DCHECK(inflight_navigations_.empty());
 
   url_table_cache_ = std::move(url_data_map);
   host_table_cache_ = std::move(host_data_map);
+  url_redirect_table_cache_ = std::move(url_redirect_data_map);
+  host_redirect_table_cache_ = std::move(host_redirect_data_map);
 
   UMA_HISTOGRAM_COUNTS("ResourcePrefetchPredictor.UrlTableMainFrameUrlCount",
                        url_table_cache_->size());
@@ -653,6 +655,8 @@
   inflight_navigations_.clear();
   url_table_cache_->clear();
   host_table_cache_->clear();
+  url_redirect_table_cache_->clear();
+  host_redirect_table_cache_->clear();
 
   BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
       base::Bind(&ResourcePrefetchPredictorTables::DeleteAllData, tables_));
@@ -662,6 +666,7 @@
   // Check all the urls in the database and pick out the ones that are present
   // in the cache.
   std::vector<std::string> urls_to_delete, hosts_to_delete;
+  std::vector<std::string> url_redirects_to_delete, host_redirects_to_delete;
 
   for (const auto& it : urls) {
     const std::string& url_spec = it.url().spec();
@@ -670,19 +675,37 @@
       url_table_cache_->erase(url_spec);
     }
 
+    if (url_redirect_table_cache_->find(url_spec) !=
+        url_redirect_table_cache_->end()) {
+      url_redirects_to_delete.push_back(url_spec);
+      url_redirect_table_cache_->erase(url_spec);
+    }
+
     const std::string& host = it.url().host();
     if (host_table_cache_->find(host) != host_table_cache_->end()) {
       hosts_to_delete.push_back(host);
       host_table_cache_->erase(host);
     }
+
+    if (host_redirect_table_cache_->find(host) !=
+        host_redirect_table_cache_->end()) {
+      host_redirects_to_delete.push_back(host);
+      host_redirect_table_cache_->erase(host);
+    }
   }
 
   if (!urls_to_delete.empty() || !hosts_to_delete.empty()) {
-    BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
-        base::Bind(&ResourcePrefetchPredictorTables::DeleteData,
-                   tables_,
-                   urls_to_delete,
-                   hosts_to_delete));
+    BrowserThread::PostTask(
+        BrowserThread::DB, FROM_HERE,
+        base::Bind(&ResourcePrefetchPredictorTables::DeleteResourceData,
+                   tables_, urls_to_delete, hosts_to_delete));
+  }
+
+  if (!url_redirects_to_delete.empty() || !host_redirects_to_delete.empty()) {
+    BrowserThread::PostTask(
+        BrowserThread::DB, FROM_HERE,
+        base::Bind(&ResourcePrefetchPredictorTables::DeleteRedirectData,
+                   tables_, url_redirects_to_delete, host_redirects_to_delete));
   }
 }
 
@@ -703,23 +726,49 @@
   }
 
   data_map->erase(key_to_delete);
-    BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
-        base::Bind(&ResourcePrefetchPredictorTables::DeleteSingleDataPoint,
-                   tables_,
-                   key_to_delete,
-                   key_type));
+  BrowserThread::PostTask(
+      BrowserThread::DB, FROM_HERE,
+      base::Bind(
+          &ResourcePrefetchPredictorTables::DeleteSingleResourceDataPoint,
+          tables_, key_to_delete, key_type));
+}
+
+void ResourcePrefetchPredictor::RemoveOldestEntryInRedirectDataMap(
+    PrefetchKeyType key_type,
+    RedirectDataMap* data_map) {
+  if (data_map->empty())
+    return;
+
+  uint64_t oldest_time = UINT64_MAX;
+  std::string key_to_delete;
+  for (const auto& kv : *data_map) {
+    const RedirectData& data = kv.second;
+    if (key_to_delete.empty() || data.last_visit_time() < oldest_time) {
+      key_to_delete = data.primary_key();
+      oldest_time = data.last_visit_time();
+    }
+  }
+
+  data_map->erase(key_to_delete);
+  BrowserThread::PostTask(
+      BrowserThread::DB, FROM_HERE,
+      base::Bind(
+          &ResourcePrefetchPredictorTables::DeleteSingleRedirectDataPoint,
+          tables_, key_to_delete, key_type));
 }
 
 void ResourcePrefetchPredictor::OnVisitCountLookup(
     size_t visit_count,
     const NavigationID& navigation_id,
-    const std::vector<URLRequestSummary>& requests) {
+    const PageRequestSummary& summary) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   UMA_HISTOGRAM_COUNTS("ResourcePrefetchPredictor.HistoryVisitCountForUrl",
                        visit_count);
 
-  // URL level data - merge only if we are already saving the data, or we it
+  // TODO(alexilin): make only one request to DB thread.
+
+  // URL level data - merge only if we already saved the data, or it
   // meets the cutoff requirement.
   const std::string url_spec = navigation_id.main_frame_url.spec();
   bool already_tracking = url_table_cache_->find(url_spec) !=
@@ -728,17 +777,19 @@
       (visit_count >= config_.min_url_visit_count);
 
   if (should_track_url && config_.IsURLLearningEnabled()) {
-    LearnNavigation(url_spec, PREFETCH_KEY_TYPE_URL, requests,
-                    config_.max_urls_to_track, url_table_cache_.get());
+    LearnNavigation(url_spec, PREFETCH_KEY_TYPE_URL,
+                    summary.subresource_requests, config_.max_urls_to_track,
+                    url_table_cache_.get(), summary.initial_url.spec(),
+                    url_redirect_table_cache_.get());
   }
 
   // Host level data - no cutoff, always learn the navigation if enabled.
   if (config_.IsHostLearningEnabled()) {
-    LearnNavigation(navigation_id.main_frame_url.host(),
-                    PREFETCH_KEY_TYPE_HOST,
-                    requests,
-                    config_.max_hosts_to_track,
-                    host_table_cache_.get());
+    const std::string host = navigation_id.main_frame_url.host();
+    LearnNavigation(host, PREFETCH_KEY_TYPE_HOST, summary.subresource_requests,
+                    config_.max_hosts_to_track, host_table_cache_.get(),
+                    summary.initial_url.host(),
+                    host_redirect_table_cache_.get());
   }
 }
 
@@ -747,7 +798,9 @@
     PrefetchKeyType key_type,
     const std::vector<URLRequestSummary>& new_resources,
     size_t max_data_map_size,
-    PrefetchDataMap* data_map) {
+    PrefetchDataMap* data_map,
+    const std::string& key_before_redirects,
+    RedirectDataMap* redirect_map) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   // If the primary key is too long reject it.
@@ -756,10 +809,9 @@
 
   PrefetchDataMap::iterator cache_entry = data_map->find(key);
   if (cache_entry == data_map->end()) {
-    if (data_map->size() >= max_data_map_size) {
-      // The table is full, delete an entry.
+    // If the table is full, delete an entry.
+    if (data_map->size() >= max_data_map_size)
       RemoveOldestEntryInPrefetchDataMap(key_type, data_map);
-    }
 
     cache_entry = data_map->insert(std::make_pair(
         key, PrefetchData(key_type, key))).first;
@@ -879,23 +931,111 @@
     data_map->erase(key);
     BrowserThread::PostTask(
         BrowserThread::DB, FROM_HERE,
-        base::Bind(&ResourcePrefetchPredictorTables::DeleteSingleDataPoint,
-                   tables_,
-                   key,
-                   key_type));
+        base::Bind(
+            &ResourcePrefetchPredictorTables::DeleteSingleResourceDataPoint,
+            tables_, key, key_type));
   } else {
     bool is_host = key_type == PREFETCH_KEY_TYPE_HOST;
     PrefetchData empty_data(
         !is_host ? PREFETCH_KEY_TYPE_HOST : PREFETCH_KEY_TYPE_URL,
         std::string());
+    RedirectData empty_redirect_data;
     const PrefetchData& host_data = is_host ? cache_entry->second : empty_data;
     const PrefetchData& url_data = is_host ? empty_data : cache_entry->second;
     BrowserThread::PostTask(
         BrowserThread::DB, FROM_HERE,
-        base::Bind(&ResourcePrefetchPredictorTables::UpdateData,
-                   tables_,
-                   url_data,
-                   host_data));
+        base::Bind(&ResourcePrefetchPredictorTables::UpdateData, tables_,
+                   url_data, host_data, empty_redirect_data,
+                   empty_redirect_data));
+  }
+
+  if (key != key_before_redirects) {
+    LearnRedirect(key_before_redirects, key_type, key, max_data_map_size,
+                  redirect_map);
+  }
+}
+
+void ResourcePrefetchPredictor::LearnRedirect(const std::string& key,
+                                              PrefetchKeyType key_type,
+                                              const std::string& final_redirect,
+                                              size_t max_redirect_map_size,
+                                              RedirectDataMap* redirect_map) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  RedirectDataMap::iterator cache_entry = redirect_map->find(key);
+  if (cache_entry == redirect_map->end()) {
+    if (redirect_map->size() >= max_redirect_map_size)
+      RemoveOldestEntryInRedirectDataMap(key_type, redirect_map);
+
+    RedirectData new_data;
+    new_data.set_primary_key(key);
+    cache_entry = redirect_map->insert(std::make_pair(key, new_data)).first;
+    cache_entry->second.set_last_visit_time(
+        base::Time::Now().ToInternalValue());
+    RedirectStat* redirect_to_add =
+        cache_entry->second.add_redirect_endpoints();
+    redirect_to_add->set_url(final_redirect);
+    redirect_to_add->set_number_of_hits(1);
+  } else {
+    bool need_to_add = true;
+    cache_entry->second.set_last_visit_time(
+        base::Time::Now().ToInternalValue());
+
+    for (RedirectStat& redirect :
+         *(cache_entry->second.mutable_redirect_endpoints())) {
+      if (redirect.url() == final_redirect) {
+        need_to_add = false;
+        redirect.set_number_of_hits(redirect.number_of_hits() + 1);
+        redirect.set_consecutive_misses(0);
+      } else {
+        redirect.set_number_of_misses(redirect.number_of_misses() + 1);
+        redirect.set_consecutive_misses(redirect.consecutive_misses() + 1);
+      }
+    }
+
+    if (need_to_add) {
+      RedirectStat* redirect_to_add =
+          cache_entry->second.add_redirect_endpoints();
+      redirect_to_add->set_url(final_redirect);
+      redirect_to_add->set_number_of_hits(1);
+    }
+  }
+
+  // Trim and sort redirects after update.
+  std::vector<RedirectStat> redirects;
+  redirects.reserve(cache_entry->second.redirect_endpoints_size());
+  for (const RedirectStat& redirect :
+       cache_entry->second.redirect_endpoints()) {
+    if (redirect.consecutive_misses() < config_.max_consecutive_misses)
+      redirects.push_back(redirect);
+  }
+  ResourcePrefetchPredictorTables::SortRedirects(&redirects);
+
+  cache_entry->second.clear_redirect_endpoints();
+  for (const RedirectStat& redirect : redirects)
+    cache_entry->second.add_redirect_endpoints()->CopyFrom(redirect);
+
+  if (redirects.empty()) {
+    redirect_map->erase(cache_entry);
+    BrowserThread::PostTask(
+        BrowserThread::DB, FROM_HERE,
+        base::Bind(
+            &ResourcePrefetchPredictorTables::DeleteSingleRedirectDataPoint,
+            tables_, key, key_type));
+  } else {
+    bool is_host = key_type == PREFETCH_KEY_TYPE_HOST;
+    RedirectData empty_redirect_data;
+    PrefetchData empty_url_data(PREFETCH_KEY_TYPE_URL, std::string());
+    PrefetchData empty_host_data(PREFETCH_KEY_TYPE_HOST, std::string());
+    const RedirectData& host_redirect_data =
+        is_host ? cache_entry->second : empty_redirect_data;
+    const RedirectData& url_redirect_data =
+        is_host ? empty_redirect_data : cache_entry->second;
+    BrowserThread::PostTask(
+        BrowserThread::DB, FROM_HERE,
+        base::Bind(&ResourcePrefetchPredictorTables::UpdateData, tables_,
+                   empty_url_data, empty_host_data, url_redirect_data,
+                   host_redirect_data));
   }
 }
 
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.h b/chrome/browser/predictors/resource_prefetch_predictor.h
index c3177cd..969cfb8 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor.h
+++ b/chrome/browser/predictors/resource_prefetch_predictor.h
@@ -9,12 +9,12 @@
 
 #include <map>
 #include <memory>
+#include <set>
 #include <string>
 #include <vector>
 
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
-#include "base/memory/linked_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observer.h"
 #include "base/task/cancelable_task_tracker.h"
@@ -22,6 +22,7 @@
 #include "chrome/browser/predictors/resource_prefetch_common.h"
 #include "chrome/browser/predictors/resource_prefetch_predictor_tables.h"
 #include "chrome/browser/predictors/resource_prefetcher.h"
+#include "components/history/core/browser/history_db_task.h"
 #include "components/history/core/browser/history_service_observer.h"
 #include "components/history/core/browser/history_types.h"
 #include "components/keyed_service/core/keyed_service.h"
@@ -146,6 +147,8 @@
   FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest, NavigationUrlNotInDB);
   FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest,
                            NavigationUrlNotInDBAndDBFull);
+  FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest, RedirectUrlNotInDB);
+  FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest, RedirectUrlInDB);
   FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest, OnMainFrameRequest);
   FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest, OnMainFrameRedirect);
   FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest,
@@ -159,9 +162,53 @@
     INITIALIZED = 2
   };
 
+  // Stores information about inflight navigations.
+  struct PageRequestSummary {
+    explicit PageRequestSummary(const GURL& initial_url);
+    ~PageRequestSummary();
+
+    GURL initial_url;
+
+    // Stores all subresources requests within a single navigation, from initial
+    // main frame request to navigation completion.
+    std::vector<URLRequestSummary> subresource_requests;
+  };
+
+  // Used to fetch the visit count for a URL from the History database.
+  class GetUrlVisitCountTask : public history::HistoryDBTask {
+   public:
+    typedef ResourcePrefetchPredictor::URLRequestSummary URLRequestSummary;
+    typedef ResourcePrefetchPredictor::PageRequestSummary PageRequestSummary;
+    typedef base::Callback<void(size_t,  // Visit count.
+                                const NavigationID&,
+                                const PageRequestSummary&)>
+        VisitInfoCallback;
+
+    GetUrlVisitCountTask(const NavigationID& navigation_id,
+                         std::unique_ptr<PageRequestSummary> summary,
+                         VisitInfoCallback callback);
+
+    bool RunOnDBThread(history::HistoryBackend* backend,
+                       history::HistoryDatabase* db) override;
+
+    void DoneRunOnMainThread() override;
+
+   private:
+    ~GetUrlVisitCountTask() override;
+
+    int visit_count_;
+    NavigationID navigation_id_;
+    std::unique_ptr<PageRequestSummary> summary_;
+    VisitInfoCallback callback_;
+
+    DISALLOW_COPY_AND_ASSIGN(GetUrlVisitCountTask);
+  };
+
   typedef ResourcePrefetchPredictorTables::PrefetchData PrefetchData;
   typedef ResourcePrefetchPredictorTables::PrefetchDataMap PrefetchDataMap;
-  typedef std::map<NavigationID, linked_ptr<std::vector<URLRequestSummary> > >
+  typedef ResourcePrefetchPredictorTables::RedirectDataMap RedirectDataMap;
+
+  typedef std::map<NavigationID, std::unique_ptr<PageRequestSummary>>
       NavigationMap;
 
   // Returns true if the main page request is supported for prediction.
@@ -216,9 +263,11 @@
   void StartInitialization();
 
   // Callback for task to read predictor database. Takes ownership of
-  // |url_data_map| and |host_data_map|.
+  // all arguments.
   void CreateCaches(std::unique_ptr<PrefetchDataMap> url_data_map,
-                    std::unique_ptr<PrefetchDataMap> host_data_map);
+                    std::unique_ptr<PrefetchDataMap> host_data_map,
+                    std::unique_ptr<RedirectDataMap> url_redirect_data_map,
+                    std::unique_ptr<RedirectDataMap> host_redirect_data_map);
 
   // Called during initialization when history is read and the predictor
   // database has been read.
@@ -239,25 +288,38 @@
   // Callback for GetUrlVisitCountTask.
   void OnVisitCountLookup(size_t visit_count,
                           const NavigationID& navigation_id,
-                          const std::vector<URLRequestSummary>& requests);
+                          const PageRequestSummary& summary);
 
   // Removes the oldest entry in the input |data_map|, also deleting it from the
   // predictor database.
   void RemoveOldestEntryInPrefetchDataMap(PrefetchKeyType key_type,
                                           PrefetchDataMap* data_map);
 
+  void RemoveOldestEntryInRedirectDataMap(PrefetchKeyType key_type,
+                                          RedirectDataMap* data_map);
+
   // Merges resources in |new_resources| into the |data_map| and correspondingly
-  // updates the predictor database.
+  // updates the predictor database. Also calls LearnRedirect if relevant.
   void LearnNavigation(const std::string& key,
                        PrefetchKeyType key_type,
                        const std::vector<URLRequestSummary>& new_resources,
                        size_t max_data_map_size,
-                       PrefetchDataMap* data_map);
+                       PrefetchDataMap* data_map,
+                       const std::string& key_before_redirects,
+                       RedirectDataMap* redirect_map);
+
+  // Updates information about final redirect destination for |key| in
+  // |redirect_map| and correspondingly updates the predictor database.
+  void LearnRedirect(const std::string& key,
+                     PrefetchKeyType key_type,
+                     const std::string& final_redirect,
+                     size_t max_redirect_map_size,
+                     RedirectDataMap* redirect_map);
 
   // Reports overall page load time.
   void ReportPageLoadTimeStats(base::TimeDelta plt) const;
 
-  // Reports page load time for prefetched and not prefetched pages
+  // Reports page load time for prefetched and not prefetched pages.
   void ReportPageLoadTimePrefetchStats(
       base::TimeDelta plt,
       bool prefetched,
@@ -289,12 +351,13 @@
   scoped_refptr<ResourcePrefetcherManager> prefetch_manager_;
   base::CancelableTaskTracker history_lookup_consumer_;
 
-  // Map of all the navigations in flight to their resource requests.
-  NavigationMap inflight_navigations_;
-
   // Copy of the data in the predictor tables.
   std::unique_ptr<PrefetchDataMap> url_table_cache_;
   std::unique_ptr<PrefetchDataMap> host_table_cache_;
+  std::unique_ptr<RedirectDataMap> url_redirect_table_cache_;
+  std::unique_ptr<RedirectDataMap> host_redirect_table_cache_;
+
+  NavigationMap inflight_navigations_;
 
   ScopedObserver<history::HistoryService, history::HistoryServiceObserver>
       history_service_observer_;
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.proto b/chrome/browser/predictors/resource_prefetch_predictor.proto
index 8616d5c..6d2a59b 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor.proto
+++ b/chrome/browser/predictors/resource_prefetch_predictor.proto
@@ -4,11 +4,11 @@
 
 // Protocol buffers used for storing in SQLite.
 // CAUTION: When any change is done here, bump kDatabaseVersion in
-//          resource_prefetch_predictor.h.
+//          resource_prefetch_predictor_tables.h.
 
 syntax = "proto2";
 
-package chrome_browser_predictors;
+package predictors;
 
 // Required in Chrome.
 option optimize_for = LITE_RUNTIME;
@@ -61,3 +61,20 @@
   optional bool has_validators = 8;
   optional bool always_revalidate = 9;
 }
+
+// Represents a mapping from URL or host to a list of redirect endpoints.
+message RedirectData {
+  // Represents a single redirect chain endpoint.
+  message RedirectStat {
+    // Represents the host for RedirectData in a host-based table.
+    optional string url = 1;
+    optional uint32 number_of_hits = 2;
+    optional uint32 number_of_misses = 3;
+    optional uint32 consecutive_misses = 4;
+  }
+
+  // Represents main frame URL or host.
+  optional string primary_key = 1;
+  optional uint64 last_visit_time = 2;
+  repeated RedirectStat redirect_endpoints = 3;
+}
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_tables.cc b/chrome/browser/predictors/resource_prefetch_predictor_tables.cc
index 982e197..a300d5b0 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor_tables.cc
+++ b/chrome/browser/predictors/resource_prefetch_predictor_tables.cc
@@ -24,13 +24,17 @@
 namespace {
 
 using ResourceData = predictors::ResourceData;
+using RedirectData = predictors::RedirectData;
 
 const char kMetadataTableName[] = "resource_prefetch_predictor_metadata";
 const char kUrlResourceTableName[] = "resource_prefetch_predictor_url";
 const char kUrlMetadataTableName[] = "resource_prefetch_predictor_url_metadata";
+const char kUrlRedirectTableName[] = "resource_prefetch_predictor_url_redirect";
 const char kHostResourceTableName[] = "resource_prefetch_predictor_host";
 const char kHostMetadataTableName[] =
     "resource_prefetch_predictor_host_metadata";
+const char kHostRedirectTableName[] =
+    "resource_prefetch_predictor_host_redirect";
 
 const char kCreateGlobalMetadataStatementTemplate[] =
     "CREATE TABLE %s ( "
@@ -47,9 +51,16 @@
     "main_page_url TEXT, "
     "last_visit_time INTEGER, "
     "PRIMARY KEY(main_page_url))";
+const char kCreateRedirectTableStatementTemplate[] =
+    "CREATE TABLE %s ( "
+    "main_page_url TEXT, "
+    "proto BLOB, "
+    "PRIMARY KEY(main_page_url))";
 
 const char kInsertResourceTableStatementTemplate[] =
     "INSERT INTO %s (main_page_url, resource_url, proto) VALUES (?,?,?)";
+const char kInsertRedirectTableStatementTemplate[] =
+    "INSERT INTO %s (main_page_url, proto) VALUES (?,?)";
 const char kInsertMetadataTableStatementTemplate[] =
     "INSERT INTO %s (main_page_url, last_visit_time) VALUES (?,?)";
 const char kDeleteStatementTemplate[] = "DELETE FROM %s WHERE main_page_url=?";
@@ -58,7 +69,7 @@
                                  const std::string& primary_key,
                                  Statement* statement) {
   int size = data.ByteSize();
-  DCHECK(size > 0);
+  DCHECK_GT(size, 0);
   std::vector<char> proto_buffer(size);
   data.SerializeToArray(&proto_buffer[0], size);
 
@@ -67,6 +78,17 @@
   statement->BindBlob(2, &proto_buffer[0], size);
 }
 
+void BindRedirectDataToStatement(const RedirectData& data,
+                                 Statement* statement) {
+  int size = data.ByteSize();
+  DCHECK_GT(size, 0);
+  std::vector<char> proto_buffer(size);
+  data.SerializeToArray(&proto_buffer[0], size);
+
+  statement->BindString(0, data.primary_key());
+  statement->BindBlob(1, &proto_buffer[0], size);
+}
+
 bool StepAndInitializeResourceData(Statement* statement,
                                    ResourceData* data,
                                    std::string* primary_key) {
@@ -74,7 +96,6 @@
     return false;
 
   *primary_key = statement->ColumnString(0);
-
   int size = statement->ColumnByteLength(2);
   const void* blob = statement->ColumnBlob(2);
   DCHECK(blob);
@@ -86,6 +107,24 @@
   return true;
 }
 
+bool StepAndInitializeRedirectData(Statement* statement,
+                                   RedirectData* data,
+                                   std::string* primary_key) {
+  if (!statement->Step())
+    return false;
+
+  *primary_key = statement->ColumnString(0);
+
+  int size = statement->ColumnByteLength(1);
+  const void* blob = statement->ColumnBlob(1);
+  DCHECK(blob);
+  data->ParseFromArray(blob, size);
+
+  DCHECK(data->primary_key() == *primary_key);
+
+  return true;
+}
+
 }  // namespace
 
 namespace predictors {
@@ -93,11 +132,18 @@
 // static
 void ResourcePrefetchPredictorTables::SortResources(
     std::vector<ResourceData>* resources) {
-  // Sort indices instead of ResourceData objects and then apply resulting
-  // permutation to the resources.
   std::sort(resources->begin(), resources->end(),
             [](const ResourceData& x, const ResourceData& y) {
-              return ComputeScore(x) > ComputeScore(y);
+              return ComputeResourceScore(x) > ComputeResourceScore(y);
+            });
+}
+
+// static
+void ResourcePrefetchPredictorTables::SortRedirects(
+    std::vector<RedirectStat>* redirects) {
+  std::sort(redirects->begin(), redirects->end(),
+            [](const RedirectStat& x, const RedirectStat& y) {
+              return ComputeRedirectScore(x) > ComputeRedirectScore(y);
             });
 }
 
@@ -121,45 +167,66 @@
 
 void ResourcePrefetchPredictorTables::GetAllData(
     PrefetchDataMap* url_data_map,
-    PrefetchDataMap* host_data_map) {
+    PrefetchDataMap* host_data_map,
+    RedirectDataMap* url_redirect_data_map,
+    RedirectDataMap* host_redirect_data_map) {
   DCHECK_CURRENTLY_ON(BrowserThread::DB);
   if (CantAccessDatabase())
     return;
 
   DCHECK(url_data_map);
   DCHECK(host_data_map);
+  DCHECK(url_redirect_data_map);
+  DCHECK(host_redirect_data_map);
   url_data_map->clear();
   host_data_map->clear();
+  url_redirect_data_map->clear();
+  host_redirect_data_map->clear();
 
   std::vector<std::string> urls_to_delete, hosts_to_delete;
-  GetAllDataHelper(PREFETCH_KEY_TYPE_URL, url_data_map, &urls_to_delete);
-  GetAllDataHelper(PREFETCH_KEY_TYPE_HOST, host_data_map, &hosts_to_delete);
+  GetAllResourceDataHelper(PREFETCH_KEY_TYPE_URL, url_data_map,
+                           &urls_to_delete);
+  GetAllResourceDataHelper(PREFETCH_KEY_TYPE_HOST, host_data_map,
+                           &hosts_to_delete);
+  GetAllRedirectDataHelper(PREFETCH_KEY_TYPE_URL, url_redirect_data_map);
+  GetAllRedirectDataHelper(PREFETCH_KEY_TYPE_HOST, host_redirect_data_map);
 
   if (!urls_to_delete.empty() || !hosts_to_delete.empty())
-    DeleteData(urls_to_delete, hosts_to_delete);
+    DeleteResourceData(urls_to_delete, hosts_to_delete);
 }
 
 void ResourcePrefetchPredictorTables::UpdateData(
     const PrefetchData& url_data,
-    const PrefetchData& host_data) {
+    const PrefetchData& host_data,
+    const RedirectData& url_redirect_data,
+    const RedirectData& host_redirect_data) {
   DCHECK_CURRENTLY_ON(BrowserThread::DB);
   if (CantAccessDatabase())
     return;
 
   DCHECK(!url_data.is_host() && host_data.is_host());
-  DCHECK(!url_data.primary_key.empty() || !host_data.primary_key.empty());
+  DCHECK(!url_data.primary_key.empty() || !host_data.primary_key.empty() ||
+         url_redirect_data.has_primary_key() ||
+         host_redirect_data.has_primary_key());
 
   DB()->BeginTransaction();
 
-  bool success = (url_data.primary_key.empty() || UpdateDataHelper(url_data)) &&
-      (host_data.primary_key.empty() || UpdateDataHelper(host_data));
+  bool success =
+      (url_data.primary_key.empty() ||
+       UpdateResourceDataHelper(PREFETCH_KEY_TYPE_URL, url_data)) &&
+      (host_data.primary_key.empty() ||
+       UpdateResourceDataHelper(PREFETCH_KEY_TYPE_HOST, host_data)) &&
+      (!url_redirect_data.has_primary_key() ||
+       UpdateRedirectDataHelper(PREFETCH_KEY_TYPE_URL, url_redirect_data)) &&
+      (!host_redirect_data.has_primary_key() ||
+       UpdateRedirectDataHelper(PREFETCH_KEY_TYPE_HOST, host_redirect_data));
   if (!success)
     DB()->RollbackTransaction();
-
-  DB()->CommitTransaction();
+  else
+    DB()->CommitTransaction();
 }
 
-void ResourcePrefetchPredictorTables::DeleteData(
+void ResourcePrefetchPredictorTables::DeleteResourceData(
     const std::vector<std::string>& urls,
     const std::vector<std::string>& hosts) {
   DCHECK_CURRENTLY_ON(BrowserThread::DB);
@@ -169,19 +236,44 @@
   DCHECK(!urls.empty() || !hosts.empty());
 
   if (!urls.empty())
-    DeleteDataHelper(PREFETCH_KEY_TYPE_URL, urls);
+    DeleteDataHelper(PREFETCH_KEY_TYPE_URL, PrefetchDataType::RESOURCE, urls);
   if (!hosts.empty())
-    DeleteDataHelper(PREFETCH_KEY_TYPE_HOST, hosts);
+    DeleteDataHelper(PREFETCH_KEY_TYPE_HOST, PrefetchDataType::RESOURCE, hosts);
 }
 
-void ResourcePrefetchPredictorTables::DeleteSingleDataPoint(
+void ResourcePrefetchPredictorTables::DeleteSingleResourceDataPoint(
     const std::string& key,
     PrefetchKeyType key_type) {
   DCHECK_CURRENTLY_ON(BrowserThread::DB);
   if (CantAccessDatabase())
     return;
 
-  DeleteDataHelper(key_type, std::vector<std::string>(1, key));
+  DeleteDataHelper(key_type, PrefetchDataType::RESOURCE, {key});
+}
+
+void ResourcePrefetchPredictorTables::DeleteRedirectData(
+    const std::vector<std::string>& urls,
+    const std::vector<std::string>& hosts) {
+  DCHECK_CURRENTLY_ON(BrowserThread::DB);
+  if (CantAccessDatabase())
+    return;
+
+  DCHECK(!urls.empty() || !hosts.empty());
+
+  if (!urls.empty())
+    DeleteDataHelper(PREFETCH_KEY_TYPE_URL, PrefetchDataType::REDIRECT, urls);
+  if (!hosts.empty())
+    DeleteDataHelper(PREFETCH_KEY_TYPE_HOST, PrefetchDataType::REDIRECT, hosts);
+}
+
+void ResourcePrefetchPredictorTables::DeleteSingleRedirectDataPoint(
+    const std::string& key,
+    PrefetchKeyType key_type) {
+  DCHECK_CURRENTLY_ON(BrowserThread::DB);
+  if (CantAccessDatabase())
+    return;
+
+  DeleteDataHelper(key_type, PrefetchDataType::REDIRECT, {key});
 }
 
 void ResourcePrefetchPredictorTables::DeleteAllData() {
@@ -190,8 +282,9 @@
 
   Statement deleter;
   for (const char* table_name :
-       {kUrlResourceTableName, kUrlMetadataTableName, kHostResourceTableName,
-        kHostMetadataTableName}) {
+       {kUrlResourceTableName, kUrlMetadataTableName, kUrlRedirectTableName,
+        kHostResourceTableName, kHostMetadataTableName,
+        kHostRedirectTableName}) {
     deleter.Assign(DB()->GetUniqueStatement(
         base::StringPrintf("DELETE FROM %s", table_name).c_str()));
     deleter.Run();
@@ -205,7 +298,7 @@
 ResourcePrefetchPredictorTables::~ResourcePrefetchPredictorTables() {
 }
 
-void ResourcePrefetchPredictorTables::GetAllDataHelper(
+void ResourcePrefetchPredictorTables::GetAllResourceDataHelper(
     PrefetchKeyType key_type,
     PrefetchDataMap* data_map,
     std::vector<std::string>* to_delete) {
@@ -235,8 +328,8 @@
 
   // Read the metadata and keep track of entries that have metadata, but no
   // resource entries, so they can be deleted.
-  const char* metadata_table_name = is_host ? kHostMetadataTableName :
-      kUrlMetadataTableName;
+  const char* metadata_table_name =
+      is_host ? kHostMetadataTableName : kUrlMetadataTableName;
   Statement metadata_reader(DB()->GetUniqueStatement(
       base::StringPrintf("SELECT * FROM %s", metadata_table_name).c_str()));
 
@@ -253,7 +346,26 @@
   }
 }
 
-bool ResourcePrefetchPredictorTables::UpdateDataHelper(
+void ResourcePrefetchPredictorTables::GetAllRedirectDataHelper(
+    PrefetchKeyType key_type,
+    RedirectDataMap* redirect_map) {
+  bool is_host = key_type == PREFETCH_KEY_TYPE_HOST;
+
+  const char* redirect_table_name =
+      is_host ? kHostRedirectTableName : kUrlRedirectTableName;
+  Statement redirect_reader(DB()->GetUniqueStatement(
+      base::StringPrintf("SELECT * FROM %s", redirect_table_name).c_str()));
+
+  RedirectData data;
+  std::string primary_key;
+  while (StepAndInitializeRedirectData(&redirect_reader, &data, &primary_key)) {
+    auto result = redirect_map->insert(std::make_pair(primary_key, data));
+    DCHECK(result.second);
+  }
+}
+
+bool ResourcePrefetchPredictorTables::UpdateResourceDataHelper(
+    PrefetchKeyType key_type,
     const PrefetchData& data) {
   DCHECK(!data.primary_key.empty());
 
@@ -263,57 +375,78 @@
   }
 
   // Delete the older data from both the tables.
-  std::unique_ptr<Statement> deleter(data.is_host()
-                                         ? GetHostResourceDeleteStatement()
-                                         : GetUrlResourceDeleteStatement());
+  std::unique_ptr<Statement> deleter(GetTableUpdateStatement(
+      key_type, PrefetchDataType::RESOURCE, TableOperationType::REMOVE));
   deleter->BindString(0, data.primary_key);
   if (!deleter->Run())
     return false;
 
-  deleter.reset(data.is_host() ? GetHostMetadataDeleteStatement() :
-      GetUrlMetadataDeleteStatement());
+  deleter = GetTableUpdateStatement(key_type, PrefetchDataType::METADATA,
+                                    TableOperationType::REMOVE);
   deleter->BindString(0, data.primary_key);
   if (!deleter->Run())
     return false;
 
   // Add the new data to the tables.
   for (const ResourceData& resource : data.resources) {
-    std::unique_ptr<Statement> resource_inserter(
-        data.is_host() ? GetHostResourceUpdateStatement()
-                       : GetUrlResourceUpdateStatement());
+    std::unique_ptr<Statement> resource_inserter(GetTableUpdateStatement(
+        key_type, PrefetchDataType::RESOURCE, TableOperationType::INSERT));
     BindResourceDataToStatement(resource, data.primary_key,
                                 resource_inserter.get());
     if (!resource_inserter->Run())
       return false;
   }
 
-  std::unique_ptr<Statement> metadata_inserter(
-      data.is_host() ? GetHostMetadataUpdateStatement()
-                     : GetUrlMetadataUpdateStatement());
+  std::unique_ptr<Statement> metadata_inserter(GetTableUpdateStatement(
+      key_type, PrefetchDataType::METADATA, TableOperationType::INSERT));
   metadata_inserter->BindString(0, data.primary_key);
   metadata_inserter->BindInt64(1, data.last_visit.ToInternalValue());
-  if (!metadata_inserter->Run())
+  return metadata_inserter->Run();
+}
+
+bool ResourcePrefetchPredictorTables::UpdateRedirectDataHelper(
+    PrefetchKeyType key_type,
+    const RedirectData& data) {
+  DCHECK(data.has_primary_key());
+
+  if (!StringsAreSmallerThanDBLimit(data)) {
+    UMA_HISTOGRAM_BOOLEAN("ResourcePrefetchPredictor.DbStringTooLong", true);
+    return false;
+  }
+
+  // Delete the older data from the table.
+  std::unique_ptr<Statement> deleter(GetTableUpdateStatement(
+      key_type, PrefetchDataType::REDIRECT, TableOperationType::REMOVE));
+  deleter->BindString(0, data.primary_key());
+  if (!deleter->Run())
     return false;
 
-  return true;
+  // Add the new data to the table.
+  std::unique_ptr<Statement> inserter(GetTableUpdateStatement(
+      key_type, PrefetchDataType::REDIRECT, TableOperationType::INSERT));
+  BindRedirectDataToStatement(data, inserter.get());
+  return inserter->Run();
 }
 
 void ResourcePrefetchPredictorTables::DeleteDataHelper(
     PrefetchKeyType key_type,
+    PrefetchDataType data_type,
     const std::vector<std::string>& keys) {
-  bool is_host = key_type == PREFETCH_KEY_TYPE_HOST;
+  bool is_resource = data_type == PrefetchDataType::RESOURCE;
 
   for (const std::string& key : keys) {
-    std::unique_ptr<Statement> deleter(is_host
-                                           ? GetHostResourceDeleteStatement()
-                                           : GetUrlResourceDeleteStatement());
+    std::unique_ptr<Statement> deleter(GetTableUpdateStatement(
+        key_type, data_type, TableOperationType::REMOVE));
     deleter->BindString(0, key);
     deleter->Run();
 
-    deleter.reset(is_host ? GetHostMetadataDeleteStatement() :
-        GetUrlMetadataDeleteStatement());
-    deleter->BindString(0, key);
-    deleter->Run();
+    if (is_resource) {
+      // Delete corresponding resource metadata as well.
+      deleter = GetTableUpdateStatement(key_type, PrefetchDataType::METADATA,
+                                        TableOperationType::REMOVE);
+      deleter->BindString(0, key);
+      deleter->Run();
+    }
   }
 }
 
@@ -330,8 +463,21 @@
   return true;
 }
 
+bool ResourcePrefetchPredictorTables::StringsAreSmallerThanDBLimit(
+    const RedirectData& data) {
+  if (data.primary_key().length() > kMaxStringLength)
+    return false;
+
+  for (const RedirectStat& redirect : data.redirect_endpoints()) {
+    if (redirect.url().length() > kMaxStringLength)
+      return false;
+  }
+  return true;
+}
+
 // static
-float ResourcePrefetchPredictorTables::ComputeScore(const ResourceData& data) {
+float ResourcePrefetchPredictorTables::ComputeResourceScore(
+    const ResourceData& data) {
   // The score is calculated so that when the rows are sorted, stylesheets,
   // scripts and fonts appear first, sorted by position(ascending) and then the
   // rest of the resources sorted by position (ascending).
@@ -350,6 +496,13 @@
 }
 
 // static
+float ResourcePrefetchPredictorTables::ComputeRedirectScore(
+    const RedirectStat& data) {
+  // TODO(alexilin): Invent some scoring.
+  return 0.0;
+}
+
+// static
 bool ResourcePrefetchPredictorTables::DropTablesIfOutdated(
     sql::Connection* db) {
   int version = GetDatabaseVersion(db);
@@ -360,7 +513,8 @@
   if (incompatible_version) {
     for (const char* table_name :
          {kMetadataTableName, kUrlResourceTableName, kHostResourceTableName,
-          kUrlMetadataTableName, kHostMetadataTableName}) {
+          kUrlRedirectTableName, kHostRedirectTableName, kUrlMetadataTableName,
+          kHostMetadataTableName}) {
       success =
           success &&
           db->Execute(base::StringPrintf("DROP TABLE IF EXISTS %s", table_name)
@@ -427,6 +581,10 @@
        db->Execute(base::StringPrintf(kCreateMetadataTableStatementTemplate,
                                       kUrlMetadataTableName)
                        .c_str())) &&
+      (db->DoesTableExist(kUrlRedirectTableName) ||
+       db->Execute(base::StringPrintf(kCreateRedirectTableStatementTemplate,
+                                      kUrlRedirectTableName)
+                       .c_str())) &&
       (db->DoesTableExist(kHostResourceTableName) ||
        db->Execute(base::StringPrintf(kCreateResourceTableStatementTemplate,
                                       kHostResourceTableName)
@@ -434,6 +592,10 @@
       (db->DoesTableExist(kHostMetadataTableName) ||
        db->Execute(base::StringPrintf(kCreateMetadataTableStatementTemplate,
                                       kHostMetadataTableName)
+                       .c_str())) &&
+      (db->DoesTableExist(kHostRedirectTableName) ||
+       db->Execute(base::StringPrintf(kCreateRedirectTableStatementTemplate,
+                                      kHostRedirectTableName)
                        .c_str()));
 
   if (success)
@@ -465,67 +627,61 @@
                          statement.ColumnInt(0));
 }
 
-Statement*
-    ResourcePrefetchPredictorTables::GetUrlResourceDeleteStatement() {
-  return new Statement(DB()->GetCachedStatement(
-      SQL_FROM_HERE,
-      base::StringPrintf(kDeleteStatementTemplate, kUrlResourceTableName)
-          .c_str()));
+std::unique_ptr<Statement>
+ResourcePrefetchPredictorTables::GetTableUpdateStatement(
+    PrefetchKeyType key_type,
+    PrefetchDataType data_type,
+    TableOperationType op_type) {
+  sql::StatementID id(__FILE__, key_type | (static_cast<int>(data_type) << 1) |
+                                    (static_cast<int>(op_type) << 3));
+  const char* statement_template =
+      GetTableUpdateStatementTemplate(op_type, data_type);
+  const char* table_name =
+      GetTableUpdateStatementTableName(key_type, data_type);
+  return base::MakeUnique<Statement>(DB()->GetCachedStatement(
+      id, base::StringPrintf(statement_template, table_name).c_str()));
 }
 
-Statement*
-    ResourcePrefetchPredictorTables::GetUrlResourceUpdateStatement() {
-  return new Statement(DB()->GetCachedStatement(
-      SQL_FROM_HERE, base::StringPrintf(kInsertResourceTableStatementTemplate,
-                                        kUrlResourceTableName)
-                         .c_str()));
+// static
+const char* ResourcePrefetchPredictorTables::GetTableUpdateStatementTemplate(
+    TableOperationType op_type,
+    PrefetchDataType data_type) {
+  switch (op_type) {
+    case TableOperationType::REMOVE:
+      return kDeleteStatementTemplate;
+    case TableOperationType::INSERT:
+      switch (data_type) {
+        case PrefetchDataType::RESOURCE:
+          return kInsertResourceTableStatementTemplate;
+        case PrefetchDataType::REDIRECT:
+          return kInsertRedirectTableStatementTemplate;
+        case PrefetchDataType::METADATA:
+          return kInsertMetadataTableStatementTemplate;
+      }
+  }
+
+  NOTREACHED();
+  return nullptr;
 }
 
-Statement*
-    ResourcePrefetchPredictorTables::GetUrlMetadataDeleteStatement() {
-  return new Statement(DB()->GetCachedStatement(
-      SQL_FROM_HERE,
-      base::StringPrintf(kDeleteStatementTemplate, kUrlMetadataTableName)
-          .c_str()));
-}
+// static
+const char* ResourcePrefetchPredictorTables::GetTableUpdateStatementTableName(
+    PrefetchKeyType key_type,
+    PrefetchDataType data_type) {
+  DCHECK(key_type == PREFETCH_KEY_TYPE_URL ||
+         key_type == PREFETCH_KEY_TYPE_HOST);
+  bool is_host = key_type == PREFETCH_KEY_TYPE_HOST;
+  switch (data_type) {
+    case PrefetchDataType::RESOURCE:
+      return is_host ? kHostResourceTableName : kUrlResourceTableName;
+    case PrefetchDataType::REDIRECT:
+      return is_host ? kHostRedirectTableName : kUrlRedirectTableName;
+    case PrefetchDataType::METADATA:
+      return is_host ? kHostMetadataTableName : kUrlMetadataTableName;
+  }
 
-Statement*
-    ResourcePrefetchPredictorTables::GetUrlMetadataUpdateStatement() {
-  return new Statement(DB()->GetCachedStatement(
-      SQL_FROM_HERE, base::StringPrintf(kInsertMetadataTableStatementTemplate,
-                                        kUrlMetadataTableName)
-                         .c_str()));
-}
-
-Statement*
-    ResourcePrefetchPredictorTables::GetHostResourceDeleteStatement() {
-  return new Statement(DB()->GetCachedStatement(
-      SQL_FROM_HERE,
-      base::StringPrintf(kDeleteStatementTemplate, kHostResourceTableName)
-          .c_str()));
-}
-
-Statement*
-    ResourcePrefetchPredictorTables::GetHostResourceUpdateStatement() {
-  return new Statement(DB()->GetCachedStatement(
-      SQL_FROM_HERE, base::StringPrintf(kInsertResourceTableStatementTemplate,
-                                        kHostResourceTableName)
-                         .c_str()));
-}
-
-Statement*
-    ResourcePrefetchPredictorTables::GetHostMetadataDeleteStatement() {
-  return new Statement(DB()->GetCachedStatement(
-      SQL_FROM_HERE,
-      base::StringPrintf(kDeleteStatementTemplate, kHostMetadataTableName)
-          .c_str()));
-}
-
-Statement* ResourcePrefetchPredictorTables::GetHostMetadataUpdateStatement() {
-  return new Statement(DB()->GetCachedStatement(
-      SQL_FROM_HERE, base::StringPrintf(kInsertMetadataTableStatementTemplate,
-                                        kHostMetadataTableName)
-                         .c_str()));
+  NOTREACHED();
+  return nullptr;
 }
 
 }  // namespace predictors
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_tables.h b/chrome/browser/predictors/resource_prefetch_predictor_tables.h
index b56ed4c..6588b546 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor_tables.h
+++ b/chrome/browser/predictors/resource_prefetch_predictor_tables.h
@@ -13,6 +13,7 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/time/time.h"
 #include "chrome/browser/predictors/predictor_table_base.h"
 #include "chrome/browser/predictors/resource_prefetch_common.h"
@@ -27,7 +28,8 @@
 
 namespace predictors {
 
-using chrome_browser_predictors::ResourceData;
+// From resource_prefetch_predictor.proto.
+using RedirectStat = RedirectData_RedirectStat;
 
 // Interface for database tables used by the ResourcePrefetchPredictor.
 // All methods except the constructor and destructor need to be called on the DB
@@ -36,13 +38,12 @@
 // Currently manages:
 //  - UrlResourceTable - resources per Urls.
 //  - UrlMetadataTable - misc data for Urls (like last visit time).
+//  - UrlRedirectTable - redirects per Urls.
 //  - HostResourceTable - resources per host.
 //  - HostMetadataTable - misc data for hosts.
+//  - HostRedirectTable - redirects per host.
 class ResourcePrefetchPredictorTables : public PredictorTableBase {
  public:
-  // Sorts the resources by score, decreasing.
-  static void SortResources(std::vector<ResourceData>* resources);
-
   // Aggregated data for a Url or Host. Although the data differs slightly, we
   // store them in the same structure, because most of the fields are common and
   // it allows us to use the same functions.
@@ -63,58 +64,95 @@
   // Map from primary key to PrefetchData for the key.
   typedef std::map<std::string, PrefetchData> PrefetchDataMap;
 
+  // Map from primary key to RedirectData for the key.
+  typedef std::map<std::string, RedirectData> RedirectDataMap;
+
   // Returns data for all Urls and Hosts.
   virtual void GetAllData(PrefetchDataMap* url_data_map,
-                          PrefetchDataMap* host_data_map);
+                          PrefetchDataMap* host_data_map,
+                          RedirectDataMap* url_redirect_data_map,
+                          RedirectDataMap* host_redirect_data_map);
 
   // Updates data for a Url and a host. If either of the |url_data| or
-  // |host_data| has an empty primary key, it will be ignored.
-  // Note that the Urls and primary key in |url_data| and |host_data| should be
-  // less than |kMaxStringLength| in length.
+  // |host_data| or |url_redirect_data| or |host_redirect_data| has an empty
+  // primary key, it will be ignored.
+  // Note that the Urls and primary key in |url_data|, |host_data|,
+  // |url_redirect_data| and |host_redirect_data| should be less than
+  // |kMaxStringLength| in length.
   virtual void UpdateData(const PrefetchData& url_data,
-                          const PrefetchData& host_data);
+                          const PrefetchData& host_data,
+                          const RedirectData& url_redirect_data,
+                          const RedirectData& host_redirect_data);
 
   // Delete data for the input |urls| and |hosts|.
-  virtual void DeleteData(const std::vector<std::string>& urls,
-                  const std::vector<std::string>& hosts);
+  virtual void DeleteResourceData(const std::vector<std::string>& urls,
+                                  const std::vector<std::string>& hosts);
 
-  // Wrapper over DeleteData for convenience.
-  virtual void DeleteSingleDataPoint(const std::string& key,
-                                     PrefetchKeyType key_type);
+  // Wrapper over DeleteResourceData for convenience.
+  virtual void DeleteSingleResourceDataPoint(const std::string& key,
+                                             PrefetchKeyType key_type);
+
+  // Delete data for the input |urls| and |hosts|.
+  virtual void DeleteRedirectData(const std::vector<std::string>& urls,
+                                  const std::vector<std::string>& hosts);
+
+  // Wrapper over DeleteRedirectData for convenience.
+  virtual void DeleteSingleRedirectDataPoint(const std::string& key,
+                                             PrefetchKeyType key_type);
 
   // Deletes all data in all the tables.
   virtual void DeleteAllData();
 
+  // Sorts the resources by score, decreasing.
+  static void SortResources(std::vector<ResourceData>* resources);
+
+  // Sorts the redirects by score, decreasing.
+  static void SortRedirects(std::vector<RedirectStat>* redirects);
+
   // The maximum length of the string that can be stored in the DB.
   static constexpr size_t kMaxStringLength = 1024;
 
  private:
+  // Represents the type of information that is stored in prefetch database.
+  enum class PrefetchDataType { RESOURCE, REDIRECT, METADATA };
+
+  enum class TableOperationType { INSERT, REMOVE };
+
   friend class PredictorDatabaseInternal;
   friend class MockResourcePrefetchPredictorTables;
   FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTablesTest,
                            DatabaseVersionIsSet);
   FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTablesTest,
                            DatabaseIsResetWhenIncompatible);
-  FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTablesTest, ComputeScore);
+  FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTablesTest,
+                           ComputeResourceScore);
 
   ResourcePrefetchPredictorTables();
   ~ResourcePrefetchPredictorTables() override;
 
   // Helper functions below help perform functions on the Url and host table
   // using the same code.
-  void GetAllDataHelper(PrefetchKeyType key_type,
-                        PrefetchDataMap* data_map,
-                        std::vector<std::string>* to_delete);
-  bool UpdateDataHelper(const PrefetchData& data);
+  void GetAllResourceDataHelper(PrefetchKeyType key_type,
+                                PrefetchDataMap* data_map,
+                                std::vector<std::string>* to_delete);
+  void GetAllRedirectDataHelper(PrefetchKeyType key_type,
+                                RedirectDataMap* redirect_map);
+  bool UpdateResourceDataHelper(PrefetchKeyType key_type,
+                                const PrefetchData& data);
+  bool UpdateRedirectDataHelper(PrefetchKeyType key_type,
+                                const RedirectData& data);
   void DeleteDataHelper(PrefetchKeyType key_type,
+                        PrefetchDataType data_type,
                         const std::vector<std::string>& keys);
 
   // Returns true if the strings in the |data| are less than |kMaxStringLength|
   // in length.
   static bool StringsAreSmallerThanDBLimit(const PrefetchData& data);
+  static bool StringsAreSmallerThanDBLimit(const RedirectData& data);
 
   // Computes score of |data|.
-  static float ComputeScore(const ResourceData& data);
+  static float ComputeResourceScore(const ResourceData& data);
+  static float ComputeRedirectScore(const RedirectStat& data);
 
   // PredictorTableBase methods.
   void CreateTableIfNonExistent() override;
@@ -122,23 +160,24 @@
 
   // Database version. Always increment it when any change is made to the data
   // schema (including the .proto).
-  static constexpr int kDatabaseVersion = 2;
+  static constexpr int kDatabaseVersion = 3;
 
   static bool DropTablesIfOutdated(sql::Connection* db);
   static int GetDatabaseVersion(sql::Connection* db);
   static bool SetDatabaseVersion(sql::Connection* db, int version);
 
-  // Helpers to return Statements for cached Statements. The caller must take
-  // ownership of the return Statements.
-  sql::Statement* GetUrlResourceDeleteStatement();
-  sql::Statement* GetUrlResourceUpdateStatement();
-  sql::Statement* GetUrlMetadataDeleteStatement();
-  sql::Statement* GetUrlMetadataUpdateStatement();
+  // Helper to return Statements for cached Statements.
+  std::unique_ptr<sql::Statement> GetTableUpdateStatement(
+      PrefetchKeyType key_type,
+      PrefetchDataType data_type,
+      TableOperationType op_type);
 
-  sql::Statement* GetHostResourceDeleteStatement();
-  sql::Statement* GetHostResourceUpdateStatement();
-  sql::Statement* GetHostMetadataDeleteStatement();
-  sql::Statement* GetHostMetadataUpdateStatement();
+  static const char* GetTableUpdateStatementTemplate(
+      TableOperationType op_type,
+      PrefetchDataType data_type);
+  static const char* GetTableUpdateStatementTableName(
+      PrefetchKeyType key_type,
+      PrefetchDataType data_type);
 
   DISALLOW_COPY_AND_ASSIGN(ResourcePrefetchPredictorTables);
 };
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_tables_unittest.cc b/chrome/browser/predictors/resource_prefetch_predictor_tables_unittest.cc
index e7835442..c969bdea 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor_tables_unittest.cc
+++ b/chrome/browser/predictors/resource_prefetch_predictor_tables_unittest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <memory>
 #include <set>
 #include <utility>
 #include <vector>
@@ -41,6 +42,7 @@
   scoped_refptr<ResourcePrefetchPredictorTables> tables_;
 
   using PrefetchDataMap = ResourcePrefetchPredictorTables::PrefetchDataMap;
+  using RedirectDataMap = ResourcePrefetchPredictorTables::RedirectDataMap;
 
  private:
   using PrefetchData = ResourcePrefetchPredictorTables::PrefetchData;
@@ -55,10 +57,20 @@
   void TestResourcesAreEqual(const std::vector<ResourceData>& lhs,
                              const std::vector<ResourceData>& rhs) const;
 
+  // Checks that the input RedirectData are the same, although the redirects
+  // can be in different order.
+  void TestRedirectDataAreEqual(const RedirectDataMap& lhs,
+                                const RedirectDataMap& rhs) const;
+  void TestRedirectsAreEqual(const std::vector<RedirectStat>& lhs,
+                             const std::vector<RedirectStat>& rhs) const;
+
   void AddKey(PrefetchDataMap* m, const std::string& key) const;
+  void AddKey(RedirectDataMap* m, const std::string& key) const;
 
   PrefetchDataMap test_url_data_;
   PrefetchDataMap test_host_data_;
+  RedirectDataMap test_url_redirect_data_;
+  RedirectDataMap test_host_redirect_data_;
 };
 
 class ResourcePrefetchPredictorTablesReopenTest
@@ -95,38 +107,57 @@
 
 void ResourcePrefetchPredictorTablesTest::TestGetAllData() {
   PrefetchDataMap actual_url_data, actual_host_data;
-  tables_->GetAllData(&actual_url_data, &actual_host_data);
+  RedirectDataMap actual_url_redirect_data, actual_host_redirect_data;
+  tables_->GetAllData(&actual_url_data, &actual_host_data,
+                      &actual_url_redirect_data, &actual_host_redirect_data);
 
   TestPrefetchDataAreEqual(test_url_data_, actual_url_data);
   TestPrefetchDataAreEqual(test_host_data_, actual_host_data);
+  TestRedirectDataAreEqual(test_url_redirect_data_, actual_url_redirect_data);
+  TestRedirectDataAreEqual(test_host_redirect_data_, actual_host_redirect_data);
 }
 
 void ResourcePrefetchPredictorTablesTest::TestDeleteData() {
-  std::vector<std::string> urls_to_delete, hosts_to_delete;
-  urls_to_delete.push_back("http://www.google.com");
-  urls_to_delete.push_back("http://www.yahoo.com");
-  hosts_to_delete.push_back("www.yahoo.com");
+  std::vector<std::string> urls_to_delete = {"http://www.google.com",
+                                             "http://www.yahoo.com"};
+  std::vector<std::string> hosts_to_delete = {"www.yahoo.com"};
 
-  tables_->DeleteData(urls_to_delete, hosts_to_delete);
+  tables_->DeleteResourceData(urls_to_delete, hosts_to_delete);
+
+  urls_to_delete = {"http://fb.com/google", "http://google.com"};
+  hosts_to_delete = {"microsoft.com"};
+
+  tables_->DeleteRedirectData(urls_to_delete, hosts_to_delete);
 
   PrefetchDataMap actual_url_data, actual_host_data;
-  tables_->GetAllData(&actual_url_data, &actual_host_data);
+  RedirectDataMap actual_url_redirect_data, actual_host_redirect_data;
+  tables_->GetAllData(&actual_url_data, &actual_host_data,
+                      &actual_url_redirect_data, &actual_host_redirect_data);
 
   PrefetchDataMap expected_url_data, expected_host_data;
+  RedirectDataMap expected_url_redirect_data, expected_host_redirect_data;
   AddKey(&expected_url_data, "http://www.reddit.com");
   AddKey(&expected_host_data, "www.facebook.com");
+  AddKey(&expected_url_redirect_data, "http://nyt.com");
+  AddKey(&expected_host_redirect_data, "bbc.com");
 
   TestPrefetchDataAreEqual(expected_url_data, actual_url_data);
   TestPrefetchDataAreEqual(expected_host_data, actual_host_data);
+  TestRedirectDataAreEqual(expected_url_redirect_data,
+                           actual_url_redirect_data);
+  TestRedirectDataAreEqual(expected_host_redirect_data,
+                           actual_host_redirect_data);
 }
 
 void ResourcePrefetchPredictorTablesTest::TestDeleteSingleDataPoint() {
   // Delete a URL.
-  tables_->DeleteSingleDataPoint("http://www.reddit.com",
-                                 PREFETCH_KEY_TYPE_URL);
+  tables_->DeleteSingleResourceDataPoint("http://www.reddit.com",
+                                         PREFETCH_KEY_TYPE_URL);
 
   PrefetchDataMap actual_url_data, actual_host_data;
-  tables_->GetAllData(&actual_url_data, &actual_host_data);
+  RedirectDataMap actual_url_redirect_data, actual_host_redirect_data;
+  tables_->GetAllData(&actual_url_data, &actual_host_data,
+                      &actual_url_redirect_data, &actual_host_redirect_data);
 
   PrefetchDataMap expected_url_data;
   AddKey(&expected_url_data, "http://www.google.com");
@@ -134,18 +165,65 @@
 
   TestPrefetchDataAreEqual(expected_url_data, actual_url_data);
   TestPrefetchDataAreEqual(test_host_data_, actual_host_data);
+  TestRedirectDataAreEqual(test_url_redirect_data_, actual_url_redirect_data);
+  TestRedirectDataAreEqual(test_host_redirect_data_, actual_host_redirect_data);
 
   // Delete a host.
-  tables_->DeleteSingleDataPoint("www.facebook.com", PREFETCH_KEY_TYPE_HOST);
+  tables_->DeleteSingleResourceDataPoint("www.facebook.com",
+                                         PREFETCH_KEY_TYPE_HOST);
   actual_url_data.clear();
   actual_host_data.clear();
-  tables_->GetAllData(&actual_url_data, &actual_host_data);
+  actual_url_redirect_data.clear();
+  actual_host_redirect_data.clear();
+  tables_->GetAllData(&actual_url_data, &actual_host_data,
+                      &actual_url_redirect_data, &actual_host_redirect_data);
 
   PrefetchDataMap expected_host_data;
   AddKey(&expected_host_data, "www.yahoo.com");
 
   TestPrefetchDataAreEqual(expected_url_data, actual_url_data);
   TestPrefetchDataAreEqual(expected_host_data, actual_host_data);
+  TestRedirectDataAreEqual(test_url_redirect_data_, actual_url_redirect_data);
+  TestRedirectDataAreEqual(test_host_redirect_data_, actual_host_redirect_data);
+
+  // Delete a URL redirect.
+  tables_->DeleteSingleRedirectDataPoint("http://nyt.com",
+                                         PREFETCH_KEY_TYPE_URL);
+  actual_url_data.clear();
+  actual_host_data.clear();
+  actual_url_redirect_data.clear();
+  actual_host_redirect_data.clear();
+  tables_->GetAllData(&actual_url_data, &actual_host_data,
+                      &actual_url_redirect_data, &actual_host_redirect_data);
+
+  RedirectDataMap expected_url_redirect_data;
+  AddKey(&expected_url_redirect_data, "http://fb.com/google");
+  AddKey(&expected_url_redirect_data, "http://google.com");
+
+  TestPrefetchDataAreEqual(expected_url_data, actual_url_data);
+  TestPrefetchDataAreEqual(expected_host_data, actual_host_data);
+  TestRedirectDataAreEqual(expected_url_redirect_data,
+                           actual_url_redirect_data);
+  TestRedirectDataAreEqual(test_host_redirect_data_, actual_host_redirect_data);
+
+  // Delete a host redirect.
+  tables_->DeleteSingleRedirectDataPoint("bbc.com", PREFETCH_KEY_TYPE_HOST);
+  actual_url_data.clear();
+  actual_host_data.clear();
+  actual_url_redirect_data.clear();
+  actual_host_redirect_data.clear();
+  tables_->GetAllData(&actual_url_data, &actual_host_data,
+                      &actual_url_redirect_data, &actual_host_redirect_data);
+
+  RedirectDataMap expected_host_redirect_data;
+  AddKey(&expected_host_redirect_data, "microsoft.com");
+
+  TestPrefetchDataAreEqual(expected_url_data, actual_url_data);
+  TestPrefetchDataAreEqual(expected_host_data, actual_host_data);
+  TestRedirectDataAreEqual(expected_url_redirect_data,
+                           actual_url_redirect_data);
+  TestRedirectDataAreEqual(expected_host_redirect_data,
+                           actual_host_redirect_data);
 }
 
 void ResourcePrefetchPredictorTablesTest::TestUpdateData() {
@@ -170,12 +248,29 @@
       "http://www.yahoo.com/image.png", content::RESOURCE_TYPE_IMAGE, 120, 1, 1,
       10.0, net::MEDIUM, true, false));
 
-  tables_->UpdateData(google, yahoo);
+  RedirectData facebook;
+  facebook.set_primary_key("http://fb.com/google");
+  facebook.set_last_visit_time(20);
+  InitializeRedirectStat(facebook.add_redirect_endpoints(),
+                         "https://facebook.fr/google", 4, 2, 1);
+
+  RedirectData microsoft;
+  microsoft.set_primary_key("microsoft.com");
+  microsoft.set_last_visit_time(21);
+  InitializeRedirectStat(microsoft.add_redirect_endpoints(), "m.microsoft.com",
+                         5, 7, 1);
+  InitializeRedirectStat(microsoft.add_redirect_endpoints(), "microsoft.org", 7,
+                         2, 0);
+
+  tables_->UpdateData(google, yahoo, facebook, microsoft);
 
   PrefetchDataMap actual_url_data, actual_host_data;
-  tables_->GetAllData(&actual_url_data, &actual_host_data);
+  RedirectDataMap actual_url_redirect_data, actual_host_redirect_data;
+  tables_->GetAllData(&actual_url_data, &actual_host_data,
+                      &actual_url_redirect_data, &actual_host_redirect_data);
 
   PrefetchDataMap expected_url_data, expected_host_data;
+  RedirectDataMap expected_url_redirect_data, expected_host_redirect_data;
   AddKey(&expected_url_data, "http://www.reddit.com");
   AddKey(&expected_url_data, "http://www.yahoo.com");
   expected_url_data.insert(std::make_pair("http://www.google.com", google));
@@ -183,17 +278,34 @@
   AddKey(&expected_host_data, "www.facebook.com");
   expected_host_data.insert(std::make_pair("www.yahoo.com", yahoo));
 
+  AddKey(&expected_url_redirect_data, "http://nyt.com");
+  AddKey(&expected_url_redirect_data, "http://google.com");
+  expected_url_redirect_data.insert(
+      std::make_pair("http://fb.com/google", facebook));
+
+  AddKey(&expected_host_redirect_data, "bbc.com");
+  expected_host_redirect_data.insert(
+      std::make_pair("microsoft.com", microsoft));
+
   TestPrefetchDataAreEqual(expected_url_data, actual_url_data);
   TestPrefetchDataAreEqual(expected_host_data, actual_host_data);
+  TestRedirectDataAreEqual(expected_url_redirect_data,
+                           actual_url_redirect_data);
+  TestRedirectDataAreEqual(expected_host_redirect_data,
+                           actual_host_redirect_data);
 }
 
 void ResourcePrefetchPredictorTablesTest::TestDeleteAllData() {
   tables_->DeleteAllData();
 
   PrefetchDataMap actual_url_data, actual_host_data;
-  tables_->GetAllData(&actual_url_data, &actual_host_data);
+  RedirectDataMap actual_url_redirect_data, actual_host_redirect_data;
+  tables_->GetAllData(&actual_url_data, &actual_host_data,
+                      &actual_url_redirect_data, &actual_host_redirect_data);
   EXPECT_TRUE(actual_url_data.empty());
   EXPECT_TRUE(actual_host_data.empty());
+  EXPECT_TRUE(actual_url_redirect_data.empty());
+  EXPECT_TRUE(actual_host_redirect_data.empty());
 }
 
 void ResourcePrefetchPredictorTablesTest::TestPrefetchDataAreEqual(
@@ -202,8 +314,10 @@
   EXPECT_EQ(lhs.size(), rhs.size());
 
   for (const std::pair<std::string, PrefetchData>& p : rhs) {
-    PrefetchDataMap::const_iterator lhs_it = lhs.find(p.first);
+    const auto lhs_it = lhs.find(p.first);
     ASSERT_TRUE(lhs_it != lhs.end()) << p.first;
+    EXPECT_TRUE(lhs_it->second.key_type == p.second.key_type);
+    EXPECT_TRUE(lhs_it->second.last_visit == p.second.last_visit);
 
     TestResourcesAreEqual(lhs_it->second.resources, p.second.resources);
   }
@@ -230,19 +344,81 @@
   EXPECT_EQ(lhs.size(), resources_seen.size());
 }
 
+void ResourcePrefetchPredictorTablesTest::TestRedirectDataAreEqual(
+    const RedirectDataMap& lhs,
+    const RedirectDataMap& rhs) const {
+  EXPECT_EQ(lhs.size(), rhs.size());
+
+  for (const auto& p : rhs) {
+    const auto lhs_it = lhs.find(p.first);
+    ASSERT_TRUE(lhs_it != lhs.end()) << p.first;
+    EXPECT_EQ(lhs_it->second.primary_key(), p.second.primary_key());
+    EXPECT_EQ(lhs_it->second.last_visit_time(), p.second.last_visit_time());
+
+    std::vector<RedirectStat> lhs_redirects(
+        lhs_it->second.redirect_endpoints().begin(),
+        lhs_it->second.redirect_endpoints().end());
+    std::vector<RedirectStat> rhs_redirects(
+        p.second.redirect_endpoints().begin(),
+        p.second.redirect_endpoints().end());
+
+    TestRedirectsAreEqual(lhs_redirects, rhs_redirects);
+  }
+}
+
+void ResourcePrefetchPredictorTablesTest::TestRedirectsAreEqual(
+    const std::vector<RedirectStat>& lhs,
+    const std::vector<RedirectStat>& rhs) const {
+  EXPECT_EQ(lhs.size(), rhs.size());
+
+  std::map<std::string, RedirectStat> lhs_index;
+  // Repeated redirects are not allowed.
+  for (const auto& r : lhs)
+    EXPECT_TRUE(lhs_index.insert(std::make_pair(r.url(), r)).second);
+
+  for (const auto& r : rhs) {
+    auto lhs_it = lhs_index.find(r.url());
+    if (lhs_it != lhs_index.end()) {
+      EXPECT_EQ(r, lhs_it->second);
+      lhs_index.erase(lhs_it);
+    } else {
+      ADD_FAILURE() << r.url();
+    }
+  }
+
+  EXPECT_TRUE(lhs_index.empty());
+}
+
 void ResourcePrefetchPredictorTablesTest::AddKey(PrefetchDataMap* m,
                                                  const std::string& key) const {
   PrefetchDataMap::const_iterator it = test_url_data_.find(key);
   if (it != test_url_data_.end()) {
-    m->insert(std::make_pair(it->first, it->second));
+    m->insert(*it);
     return;
   }
   it = test_host_data_.find(key);
   ASSERT_TRUE(it != test_host_data_.end());
-  m->insert(std::make_pair(it->first, it->second));
+  m->insert(*it);
+}
+
+void ResourcePrefetchPredictorTablesTest::AddKey(RedirectDataMap* m,
+                                                 const std::string& key) const {
+  auto it = test_url_redirect_data_.find(key);
+  if (it != test_url_redirect_data_.end()) {
+    m->insert(*it);
+    return;
+  }
+  it = test_host_redirect_data_.find(key);
+  ASSERT_TRUE(it != test_host_redirect_data_.end());
+  m->insert(*it);
 }
 
 void ResourcePrefetchPredictorTablesTest::InitializeSampleData() {
+  PrefetchData empty_url_data(PREFETCH_KEY_TYPE_URL, std::string());
+  PrefetchData empty_host_data(PREFETCH_KEY_TYPE_HOST, std::string());
+  RedirectData empty_url_redirect_data;
+  RedirectData empty_host_redirect_data;
+
   {  // Url data.
     PrefetchData google(PREFETCH_KEY_TYPE_URL, "http://www.google.com");
     google.last_visit = base::Time::FromInternalValue(1);
@@ -283,10 +459,12 @@
     test_url_data_.insert(std::make_pair("http://www.reddit.com", reddit));
     test_url_data_.insert(std::make_pair("http://www.yahoo.com", yahoo));
 
-    PrefetchData empty_host_data(PREFETCH_KEY_TYPE_HOST, std::string());
-    tables_->UpdateData(google, empty_host_data);
-    tables_->UpdateData(reddit, empty_host_data);
-    tables_->UpdateData(yahoo, empty_host_data);
+    tables_->UpdateData(google, empty_host_data, empty_url_redirect_data,
+                        empty_host_redirect_data);
+    tables_->UpdateData(reddit, empty_host_data, empty_url_redirect_data,
+                        empty_host_redirect_data);
+    tables_->UpdateData(yahoo, empty_host_data, empty_url_redirect_data,
+                        empty_host_redirect_data);
   }
 
   {  // Host data.
@@ -319,9 +497,72 @@
     test_host_data_.insert(std::make_pair("www.facebook.com", facebook));
     test_host_data_.insert(std::make_pair("www.yahoo.com", yahoo));
 
-    PrefetchData empty_url_data(PREFETCH_KEY_TYPE_URL, std::string());
-    tables_->UpdateData(empty_url_data, facebook);
-    tables_->UpdateData(empty_url_data, yahoo);
+    tables_->UpdateData(empty_url_data, facebook, empty_url_redirect_data,
+                        empty_host_redirect_data);
+    tables_->UpdateData(empty_url_data, yahoo, empty_url_redirect_data,
+                        empty_host_redirect_data);
+  }
+
+  {  // Url redirect data.
+    RedirectData facebook;
+    facebook.set_primary_key("http://fb.com/google");
+    facebook.set_last_visit_time(6);
+    InitializeRedirectStat(facebook.add_redirect_endpoints(),
+                           "https://facebook.com/google", 5, 1, 0);
+    InitializeRedirectStat(facebook.add_redirect_endpoints(),
+                           "https://facebook.com/login", 3, 5, 1);
+
+    RedirectData nytimes;
+    nytimes.set_primary_key("http://nyt.com");
+    nytimes.set_last_visit_time(7);
+    InitializeRedirectStat(nytimes.add_redirect_endpoints(),
+                           "https://nytimes.com", 2, 0, 0);
+
+    RedirectData google;
+    google.set_primary_key("http://google.com");
+    google.set_last_visit_time(8);
+    InitializeRedirectStat(google.add_redirect_endpoints(),
+                           "https://google.com", 3, 0, 0);
+
+    test_url_redirect_data_.clear();
+    test_url_redirect_data_.insert(
+        std::make_pair(facebook.primary_key(), facebook));
+    test_url_redirect_data_.insert(
+        std::make_pair(nytimes.primary_key(), nytimes));
+    test_url_redirect_data_.insert(
+        std::make_pair(google.primary_key(), google));
+
+    tables_->UpdateData(empty_url_data, empty_host_data, facebook,
+                        empty_host_redirect_data);
+    tables_->UpdateData(empty_url_data, empty_host_data, nytimes,
+                        empty_host_redirect_data);
+    tables_->UpdateData(empty_url_data, empty_host_data, google,
+                        empty_host_redirect_data);
+  }
+
+  {  // Host redirect data.
+    RedirectData bbc;
+    bbc.set_primary_key("bbc.com");
+    bbc.set_last_visit_time(9);
+    InitializeRedirectStat(bbc.add_redirect_endpoints(), "www.bbc.com", 8, 4,
+                           1);
+    InitializeRedirectStat(bbc.add_redirect_endpoints(), "m.bbc.com", 5, 8, 0);
+    InitializeRedirectStat(bbc.add_redirect_endpoints(), "bbc.co.uk", 1, 3, 0);
+
+    RedirectData microsoft;
+    microsoft.set_primary_key("microsoft.com");
+    microsoft.set_last_visit_time(10);
+    InitializeRedirectStat(microsoft.add_redirect_endpoints(),
+                           "www.microsoft.com", 10, 0, 0);
+
+    test_host_redirect_data_.clear();
+    test_host_redirect_data_.insert(std::make_pair(bbc.primary_key(), bbc));
+    test_host_redirect_data_.insert(
+        std::make_pair(microsoft.primary_key(), microsoft));
+    tables_->UpdateData(empty_url_data, empty_host_data,
+                        empty_url_redirect_data, bbc);
+    tables_->UpdateData(empty_url_data, empty_host_data,
+                        empty_url_redirect_data, microsoft);
   }
 }
 
@@ -333,7 +574,7 @@
 
 // Test cases.
 
-TEST_F(ResourcePrefetchPredictorTablesTest, ComputeScore) {
+TEST_F(ResourcePrefetchPredictorTablesTest, ComputeResourceScore) {
   ResourceData js_resource = CreateResourceData(
       "http://www.resources.google.com/script.js",
       content::RESOURCE_TYPE_SCRIPT, 11, 0, 0, 1., net::MEDIUM, false, false);
@@ -349,13 +590,13 @@
                          content::RESOURCE_TYPE_FONT_RESOURCE, 11, 0, 0, 1.,
                          net::MEDIUM, false, false);
   float js_resource_score =
-      ResourcePrefetchPredictorTables::ComputeScore(js_resource);
+      ResourcePrefetchPredictorTables::ComputeResourceScore(js_resource);
   float css_resource_score =
-      ResourcePrefetchPredictorTables::ComputeScore(css_resource);
+      ResourcePrefetchPredictorTables::ComputeResourceScore(css_resource);
   float font_resource_score =
-      ResourcePrefetchPredictorTables::ComputeScore(font_resource);
+      ResourcePrefetchPredictorTables::ComputeResourceScore(font_resource);
   float image_resource_score =
-      ResourcePrefetchPredictorTables::ComputeScore(image_resource);
+      ResourcePrefetchPredictorTables::ComputeResourceScore(image_resource);
 
   EXPECT_TRUE(js_resource_score == css_resource_score);
   EXPECT_TRUE(js_resource_score == font_resource_score);
@@ -403,7 +644,9 @@
   ASSERT_EQ(version, ResourcePrefetchPredictorTables::GetDatabaseVersion(db));
 
   PrefetchDataMap url_data, host_data;
-  tables_->GetAllData(&url_data, &host_data);
+  RedirectDataMap url_redirect_data, host_redirect_data;
+  tables_->GetAllData(&url_data, &host_data, &url_redirect_data,
+                      &host_redirect_data);
   EXPECT_TRUE(url_data.empty());
   EXPECT_TRUE(host_data.empty());
 }
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_test_util.cc b/chrome/browser/predictors/resource_prefetch_predictor_test_util.cc
index 013e1d46..5e18536 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor_test_util.cc
+++ b/chrome/browser/predictors/resource_prefetch_predictor_test_util.cc
@@ -33,13 +33,21 @@
   return resource;
 }
 
-void PrintTo(const ResourceData& resource, ::std::ostream* os) {
-  *os << "[" << resource.resource_url() << "," << resource.resource_type()
-      << "," << resource.number_of_hits() << "," << resource.number_of_misses()
-      << "," << resource.consecutive_misses() << ","
-      << resource.average_position() << "," << resource.priority() << ","
-      << resource.has_validators() << "," << resource.always_revalidate()
-      << "]";
+void InitializeRedirectStat(RedirectStat* redirect,
+                            const std::string& url,
+                            int number_of_hits,
+                            int number_of_misses,
+                            int consecutive_misses) {
+  redirect->set_url(url);
+  redirect->set_number_of_hits(number_of_hits);
+  redirect->set_number_of_misses(number_of_misses);
+  redirect->set_consecutive_misses(consecutive_misses);
+}
+
+RedirectData CreateRedirectData(const std::string& primary_key) {
+  RedirectData data;
+  data.set_primary_key(primary_key);
+  return data;
 }
 
 void PrintTo(const PrefetchData& data, ::std::ostream* os) {
@@ -52,6 +60,44 @@
   }
 }
 
+void PrintTo(const ResourceData& resource, ::std::ostream* os) {
+  *os << "[" << resource.resource_url() << "," << resource.resource_type()
+      << "," << resource.number_of_hits() << "," << resource.number_of_misses()
+      << "," << resource.consecutive_misses() << ","
+      << resource.average_position() << "," << resource.priority() << ","
+      << resource.has_validators() << "," << resource.always_revalidate()
+      << "]";
+}
+
+void PrintTo(const RedirectStat& redirect, ::std::ostream* os) {
+  *os << "[" << redirect.url() << "," << redirect.number_of_hits() << ","
+      << redirect.number_of_misses() << "," << redirect.consecutive_misses()
+      << "]";
+}
+
+void PrintTo(const RedirectData& data, ::std::ostream* os) {
+  *os << "[" << data.primary_key() << "," << data.last_visit_time() << "]\n";
+  for (const RedirectStat& redirect : data.redirect_endpoints()) {
+    *os << "\t\t";
+    PrintTo(redirect, os);
+    *os << "\n";
+  }
+}
+
+bool operator==(const PrefetchData& lhs, const PrefetchData& rhs) {
+  bool equal = lhs.key_type == rhs.key_type &&
+               lhs.primary_key == rhs.primary_key &&
+               lhs.resources.size() == rhs.resources.size();
+
+  if (!equal)
+    return false;
+
+  for (size_t i = 0; i < lhs.resources.size(); ++i)
+    equal = equal && lhs.resources[i] == rhs.resources[i];
+
+  return equal;
+}
+
 bool operator==(const ResourceData& lhs, const ResourceData& rhs) {
   return lhs.resource_url() == rhs.resource_url() &&
          lhs.resource_type() == rhs.resource_type() &&
@@ -64,16 +110,22 @@
          lhs.always_revalidate() == rhs.always_revalidate();
 }
 
-bool operator==(const PrefetchData& lhs, const PrefetchData& rhs) {
-  bool equal = lhs.key_type == rhs.key_type &&
-               lhs.primary_key == rhs.primary_key &&
-               lhs.resources.size() == rhs.resources.size();
+bool operator==(const RedirectStat& lhs, const RedirectStat& rhs) {
+  return lhs.url() == rhs.url() &&
+         lhs.number_of_hits() == rhs.number_of_hits() &&
+         lhs.number_of_misses() == rhs.number_of_misses() &&
+         lhs.consecutive_misses() == rhs.consecutive_misses();
+}
+
+bool operator==(const RedirectData& lhs, const RedirectData& rhs) {
+  bool equal = lhs.primary_key() == rhs.primary_key() &&
+               lhs.redirect_endpoints_size() == rhs.redirect_endpoints_size();
 
   if (!equal)
     return false;
 
-  for (size_t i = 0; i < lhs.resources.size(); ++i)
-    equal = equal && lhs.resources[i] == rhs.resources[i];
+  for (int i = 0; i < lhs.redirect_endpoints_size(); ++i)
+    equal = equal && lhs.redirect_endpoints(i) == rhs.redirect_endpoints(i);
 
   return equal;
 }
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_test_util.h b/chrome/browser/predictors/resource_prefetch_predictor_test_util.h
index c07fc13..ff707a3 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor_test_util.h
+++ b/chrome/browser/predictors/resource_prefetch_predictor_test_util.h
@@ -4,6 +4,8 @@
 #ifndef CHROME_BROWSER_PREDICTORS_RESOURCE_PREFETCH_PREDICTOR_TEST_UTIL_H_
 #define CHROME_BROWSER_PREDICTORS_RESOURCE_PREFETCH_PREDICTOR_TEST_UTIL_H_
 
+#include <string>
+
 #include "chrome/browser/predictors/resource_prefetch_predictor_tables.h"
 
 namespace predictors {
@@ -18,14 +20,26 @@
                                 bool has_validators,
                                 bool always_revalidate);
 
+void InitializeRedirectStat(RedirectStat* redirect,
+                            const std::string& url,
+                            int number_of_hits,
+                            int number_of_misses,
+                            int consecutive_misses);
+
+RedirectData CreateRedirectData(const std::string& primary_key);
+
 // For printing failures nicely.
-void PrintTo(const ResourceData& resource, ::std::ostream* os);
 void PrintTo(const ResourcePrefetchPredictorTables::PrefetchData& data,
              ::std::ostream* os);
+void PrintTo(const ResourceData& resource, ::std::ostream* os);
+void PrintTo(const RedirectStat& redirect, ::std::ostream* os);
+void PrintTo(const RedirectData& data, ::std::ostream* os);
 
-bool operator==(const ResourceData& lhs, const ResourceData& rhs);
 bool operator==(const ResourcePrefetchPredictorTables::PrefetchData& lhs,
                 const ResourcePrefetchPredictorTables::PrefetchData& rhs);
+bool operator==(const ResourceData& lhs, const ResourceData& rhs);
+bool operator==(const RedirectStat& lhs, const RedirectStat& rhs);
+bool operator==(const RedirectData& lhs, const RedirectData& rhs);
 
 }  // namespace predictors
 
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc b/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
index 81f6d48..8829036b 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
+++ b/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <iostream>
 #include <memory>
+#include <utility>
 
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
@@ -24,7 +25,6 @@
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_job.h"
 #include "net/url_request/url_request_test_util.h"
-#include "net/url_request/url_request_test_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -38,6 +38,7 @@
 typedef ResourcePrefetchPredictor::URLRequestSummary URLRequestSummary;
 typedef ResourcePrefetchPredictorTables::PrefetchData PrefetchData;
 typedef ResourcePrefetchPredictorTables::PrefetchDataMap PrefetchDataMap;
+typedef ResourcePrefetchPredictorTables::RedirectDataMap RedirectDataMap;
 
 scoped_refptr<net::HttpResponseHeaders> MakeResponseHeaders(
     const char* headers) {
@@ -127,14 +128,26 @@
  public:
   MockResourcePrefetchPredictorTables() { }
 
-  MOCK_METHOD2(GetAllData, void(PrefetchDataMap* url_data_map,
-                                PrefetchDataMap* host_data_map));
-  MOCK_METHOD2(UpdateData, void(const PrefetchData& url_data,
-                                const PrefetchData& host_data));
-  MOCK_METHOD2(DeleteData, void(const std::vector<std::string>& urls,
-                                const std::vector<std::string>& hosts));
-  MOCK_METHOD2(DeleteSingleDataPoint, void(const std::string& key,
-                                           PrefetchKeyType key_type));
+  MOCK_METHOD4(GetAllData,
+               void(PrefetchDataMap* url_data_map,
+                    PrefetchDataMap* host_data_map,
+                    RedirectDataMap* url_redirect_data_map,
+                    RedirectDataMap* host_redirect_data_map));
+  MOCK_METHOD4(UpdateData,
+               void(const PrefetchData& url_data,
+                    const PrefetchData& host_data,
+                    const RedirectData& url_redirect_data,
+                    const RedirectData& host_redirect_data));
+  MOCK_METHOD2(DeleteResourceData,
+               void(const std::vector<std::string>& urls,
+                    const std::vector<std::string>& hosts));
+  MOCK_METHOD2(DeleteSingleResourceDataPoint,
+               void(const std::string& key, PrefetchKeyType key_type));
+  MOCK_METHOD2(DeleteRedirectData,
+               void(const std::vector<std::string>& urls,
+                    const std::vector<std::string>& hosts));
+  MOCK_METHOD2(DeleteSingleRedirectDataPoint,
+               void(const std::string& key, PrefetchKeyType key_type));
   MOCK_METHOD0(DeleteAllData, void());
 
  protected:
@@ -172,19 +185,20 @@
     return navigation_id;
   }
 
-  ResourcePrefetchPredictor::URLRequestSummary CreateURLRequestSummary(
+  URLRequestSummary CreateURLRequestSummary(
       int process_id,
       int render_frame_id,
       const std::string& main_frame_url,
-      const std::string& resource_url,
-      content::ResourceType resource_type,
-      net::RequestPriority priority,
-      const std::string& mime_type,
-      bool was_cached) {
-    ResourcePrefetchPredictor::URLRequestSummary summary;
+      const std::string& resource_url = std::string(),
+      content::ResourceType resource_type = content::RESOURCE_TYPE_MAIN_FRAME,
+      net::RequestPriority priority = net::MEDIUM,
+      const std::string& mime_type = std::string(),
+      bool was_cached = false) {
+    URLRequestSummary summary;
     summary.navigation_id = CreateNavigationID(process_id, render_frame_id,
                                                main_frame_url);
-    summary.resource_url = GURL(resource_url);
+    summary.resource_url =
+        resource_url.empty() ? GURL(main_frame_url) : GURL(resource_url);
     summary.resource_type = resource_type;
     summary.priority = priority;
     summary.mime_type = mime_type;
@@ -192,6 +206,17 @@
     return summary;
   }
 
+  URLRequestSummary CreateRedirectRequestSummary(
+      int process_id,
+      int render_frame_id,
+      const std::string& main_frame_url,
+      const std::string& redirect_url) {
+    URLRequestSummary summary =
+        CreateURLRequestSummary(process_id, render_frame_id, main_frame_url);
+    summary.redirect_url = GURL(redirect_url);
+    return summary;
+  }
+
   std::unique_ptr<net::URLRequest> CreateURLRequest(
       const GURL& url,
       net::RequestPriority priority,
@@ -254,8 +279,12 @@
 
   PrefetchDataMap test_url_data_;
   PrefetchDataMap test_host_data_;
+  RedirectDataMap test_url_redirect_data_;
+  RedirectDataMap test_host_redirect_data_;
   PrefetchData empty_url_data_;
   PrefetchData empty_host_data_;
+  RedirectData empty_url_redirect_data_;
+  RedirectData empty_host_redirect_data_;
 
   MockURLRequestJobFactory url_request_job_factory_;
   EmptyURLRequestDelegate url_request_delegate_;
@@ -268,7 +297,9 @@
       profile_(new TestingProfile()),
       mock_tables_(new StrictMock<MockResourcePrefetchPredictorTables>()),
       empty_url_data_(PREFETCH_KEY_TYPE_URL, std::string()),
-      empty_host_data_(PREFETCH_KEY_TYPE_HOST, std::string()) {}
+      empty_host_data_(PREFETCH_KEY_TYPE_HOST, std::string()),
+      empty_url_redirect_data_(),
+      empty_host_redirect_data_() {}
 
 ResourcePrefetchPredictorTest::~ResourcePrefetchPredictorTest() {
   profile_.reset(NULL);
@@ -288,7 +319,9 @@
             ResourcePrefetchPredictor::NOT_INITIALIZED);
   EXPECT_CALL(*mock_tables_.get(),
               GetAllData(Pointee(ContainerEq(PrefetchDataMap())),
-                         Pointee(ContainerEq(PrefetchDataMap()))));
+                         Pointee(ContainerEq(PrefetchDataMap())),
+                         Pointee(ContainerEq(RedirectDataMap())),
+                         Pointee(ContainerEq(RedirectDataMap()))));
   InitializePredictor();
   EXPECT_TRUE(predictor_->inflight_navigations_.empty());
   EXPECT_EQ(predictor_->initialization_state_,
@@ -373,24 +406,81 @@
     test_host_data_.insert(std::make_pair("www.facebook.com", facebook));
     test_host_data_.insert(std::make_pair("www.yahoo.com", yahoo));
   }
+
+  {  // Url redirect data.
+    RedirectData facebook;
+    facebook.set_primary_key("http://fb.com/google");
+    facebook.set_last_visit_time(6);
+    InitializeRedirectStat(facebook.add_redirect_endpoints(),
+                           "https://facebook.com/google", 5, 1, 0);
+    InitializeRedirectStat(facebook.add_redirect_endpoints(),
+                           "https://facebook.com/login", 3, 5, 1);
+
+    RedirectData nytimes;
+    nytimes.set_primary_key("http://nyt.com");
+    nytimes.set_last_visit_time(7);
+    InitializeRedirectStat(nytimes.add_redirect_endpoints(),
+                           "https://nytimes.com", 2, 0, 0);
+
+    RedirectData google;
+    google.set_primary_key("http://google.com");
+    google.set_last_visit_time(8);
+    InitializeRedirectStat(google.add_redirect_endpoints(),
+                           "https://google.com", 3, 0, 0);
+
+    test_url_redirect_data_.clear();
+    test_url_redirect_data_.insert(
+        std::make_pair(facebook.primary_key(), facebook));
+    test_url_redirect_data_.insert(
+        std::make_pair(nytimes.primary_key(), nytimes));
+    test_url_redirect_data_.insert(
+        std::make_pair(google.primary_key(), google));
+  }
+
+  {  // Host redirect data.
+    RedirectData bbc;
+    bbc.set_primary_key("bbc.com");
+    bbc.set_last_visit_time(9);
+    InitializeRedirectStat(bbc.add_redirect_endpoints(), "www.bbc.com", 8, 4,
+                           1);
+    InitializeRedirectStat(bbc.add_redirect_endpoints(), "m.bbc.com", 5, 8, 0);
+    InitializeRedirectStat(bbc.add_redirect_endpoints(), "bbc.co.uk", 1, 3, 0);
+
+    RedirectData microsoft;
+    microsoft.set_primary_key("microsoft.com");
+    microsoft.set_last_visit_time(10);
+    InitializeRedirectStat(microsoft.add_redirect_endpoints(),
+                           "www.microsoft.com", 10, 0, 0);
+
+    test_host_redirect_data_.clear();
+    test_host_redirect_data_.insert(std::make_pair(bbc.primary_key(), bbc));
+    test_host_redirect_data_.insert(
+        std::make_pair(microsoft.primary_key(), microsoft));
+  }
 }
 
+// Tests that the predictor initializes correctly without any data.
 TEST_F(ResourcePrefetchPredictorTest, LazilyInitializeEmpty) {
-  // Tests that the predictor initializes correctly without any data.
   EXPECT_TRUE(predictor_->url_table_cache_->empty());
   EXPECT_TRUE(predictor_->host_table_cache_->empty());
+  EXPECT_TRUE(predictor_->url_redirect_table_cache_->empty());
+  EXPECT_TRUE(predictor_->host_redirect_table_cache_->empty());
 }
 
+// Tests that the history and the db tables data are loaded correctly.
 TEST_F(ResourcePrefetchPredictorTest, LazilyInitializeWithData) {
-  // Tests that the history and the db tables data are loaded correctly.
   AddUrlToHistory("http://www.google.com/", 4);
   AddUrlToHistory("http://www.yahoo.com/", 2);
 
   EXPECT_CALL(*mock_tables_.get(),
               GetAllData(Pointee(ContainerEq(PrefetchDataMap())),
-                         Pointee(ContainerEq(PrefetchDataMap()))))
+                         Pointee(ContainerEq(PrefetchDataMap())),
+                         Pointee(ContainerEq(RedirectDataMap())),
+                         Pointee(ContainerEq(RedirectDataMap()))))
       .WillOnce(DoAll(SetArgPointee<0>(test_url_data_),
-                      SetArgPointee<1>(test_host_data_)));
+                      SetArgPointee<1>(test_host_data_),
+                      SetArgPointee<2>(test_url_redirect_data_),
+                      SetArgPointee<3>(test_host_redirect_data_)));
 
   ResetPredictor();
   InitializePredictor();
@@ -402,56 +492,64 @@
 
   EXPECT_EQ(test_url_data_, *predictor_->url_table_cache_);
   EXPECT_EQ(test_host_data_, *predictor_->host_table_cache_);
+  EXPECT_EQ(test_url_redirect_data_, *predictor_->url_redirect_table_cache_);
+  EXPECT_EQ(test_host_redirect_data_, *predictor_->host_redirect_table_cache_);
 }
 
+// Single navigation but history count is low, so should not record.
 TEST_F(ResourcePrefetchPredictorTest, NavigationNotRecorded) {
-  // Single navigation but history count is low, so should not record.
   AddUrlToHistory("http://www.google.com", 1);
 
-  URLRequestSummary main_frame = CreateURLRequestSummary(
-      1, 1, "http://www.google.com", "http://www.google.com",
-      content::RESOURCE_TYPE_MAIN_FRAME, net::MEDIUM, std::string(), false);
+  URLRequestSummary main_frame =
+      CreateURLRequestSummary(1, 1, "http://www.google.com");
   predictor_->RecordURLRequest(main_frame);
   EXPECT_EQ(1U, predictor_->inflight_navigations_.size());
 
+  URLRequestSummary main_frame_redirect = CreateRedirectRequestSummary(
+      1, 1, "http://www.google.com", "https://www.google.com");
+  predictor_->RecordURLRedirect(main_frame_redirect);
+  EXPECT_EQ(1U, predictor_->inflight_navigations_.size());
+  main_frame = CreateURLRequestSummary(1, 1, "https://www.google.com");
+
   // Now add a few subresources.
   URLRequestSummary resource1 = CreateURLRequestSummary(
-      1, 1, "http://www.google.com", "http://google.com/style1.css",
+      1, 1, "https://www.google.com", "https://google.com/style1.css",
       content::RESOURCE_TYPE_STYLESHEET, net::MEDIUM, "text/css", false);
   predictor_->RecordURLResponse(resource1);
   URLRequestSummary resource2 = CreateURLRequestSummary(
-      1, 1, "http://www.google.com", "http://google.com/script1.js",
+      1, 1, "https://www.google.com", "https://google.com/script1.js",
       content::RESOURCE_TYPE_SCRIPT, net::MEDIUM, "text/javascript", false);
   predictor_->RecordURLResponse(resource2);
   URLRequestSummary resource3 = CreateURLRequestSummary(
-      1, 1, "http://www.google.com", "http://google.com/script2.js",
+      1, 1, "https://www.google.com", "https://google.com/script2.js",
       content::RESOURCE_TYPE_SCRIPT, net::MEDIUM, "text/javascript", false);
   predictor_->RecordURLResponse(resource3);
 
   PrefetchData host_data(PREFETCH_KEY_TYPE_HOST, "www.google.com");
   host_data.resources.push_back(CreateResourceData(
-      "http://google.com/style1.css", content::RESOURCE_TYPE_STYLESHEET, 1, 0,
+      "https://google.com/style1.css", content::RESOURCE_TYPE_STYLESHEET, 1, 0,
       0, 1.0, net::MEDIUM, false, false));
   host_data.resources.push_back(CreateResourceData(
-      "http://google.com/script1.js", content::RESOURCE_TYPE_SCRIPT, 1, 0, 0,
+      "https://google.com/script1.js", content::RESOURCE_TYPE_SCRIPT, 1, 0, 0,
       2.0, net::MEDIUM, false, false));
   host_data.resources.push_back(CreateResourceData(
-      "http://google.com/script2.js", content::RESOURCE_TYPE_SCRIPT, 1, 0, 0,
+      "https://google.com/script2.js", content::RESOURCE_TYPE_SCRIPT, 1, 0, 0,
       3.0, net::MEDIUM, false, false));
-  EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data));
+  EXPECT_CALL(*mock_tables_.get(),
+              UpdateData(empty_url_data_, host_data, empty_url_redirect_data_,
+                         empty_host_redirect_data_));
 
-  predictor_->OnNavigationComplete(main_frame.navigation_id);
+  predictor_->RecordMainFrameLoadComplete(main_frame.navigation_id);
   profile_->BlockUntilHistoryProcessesPendingRequests();
 }
 
+// Single navigation that will be recorded. Will check for duplicate
+// resources and also for number of resources saved.
 TEST_F(ResourcePrefetchPredictorTest, NavigationUrlNotInDB) {
-  // Single navigation that will be recorded. Will check for duplicate
-  // resources and also for number of resources saved.
   AddUrlToHistory("http://www.google.com", 4);
 
-  URLRequestSummary main_frame = CreateURLRequestSummary(
-      1, 1, "http://www.google.com", "http://www.google.com",
-      content::RESOURCE_TYPE_MAIN_FRAME, net::MEDIUM, std::string(), false);
+  URLRequestSummary main_frame =
+      CreateURLRequestSummary(1, 1, "http://www.google.com");
   predictor_->RecordURLRequest(main_frame);
   EXPECT_EQ(1U, predictor_->inflight_navigations_.size());
 
@@ -497,24 +595,30 @@
   url_data.resources.push_back(CreateResourceData(
       "http://google.com/style2.css", content::RESOURCE_TYPE_STYLESHEET, 1, 0,
       0, 7.0, net::MEDIUM, false, false));
-  EXPECT_CALL(*mock_tables_.get(), UpdateData(url_data, empty_host_data_));
+  EXPECT_CALL(*mock_tables_.get(),
+              UpdateData(url_data, empty_host_data_, empty_url_redirect_data_,
+                         empty_host_redirect_data_));
 
   PrefetchData host_data(PREFETCH_KEY_TYPE_HOST, "www.google.com");
   host_data.resources = url_data.resources;
-  EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data));
+  EXPECT_CALL(*mock_tables_.get(),
+              UpdateData(empty_url_data_, host_data, empty_url_redirect_data_,
+                         empty_host_redirect_data_));
 
   predictor_->OnNavigationComplete(main_frame.navigation_id);
   profile_->BlockUntilHistoryProcessesPendingRequests();
 }
 
+// Tests that navigation is recorded correctly for URL already present in
+// the database cache.
 TEST_F(ResourcePrefetchPredictorTest, NavigationUrlInDB) {
-  // Tests that navigation is recorded correctly for URL already present in
-  // the database cache.
   AddUrlToHistory("http://www.google.com", 4);
 
   EXPECT_CALL(*mock_tables_.get(),
               GetAllData(Pointee(ContainerEq(PrefetchDataMap())),
-                         Pointee(ContainerEq(PrefetchDataMap()))))
+                         Pointee(ContainerEq(PrefetchDataMap())),
+                         Pointee(ContainerEq(RedirectDataMap())),
+                         Pointee(ContainerEq(RedirectDataMap()))))
       .WillOnce(DoAll(SetArgPointee<0>(test_url_data_),
                       SetArgPointee<1>(test_host_data_)));
   ResetPredictor();
@@ -570,11 +674,12 @@
   url_data.resources.push_back(CreateResourceData(
       "http://google.com/script2.js", content::RESOURCE_TYPE_SCRIPT, 1, 0, 0,
       3.0, net::MEDIUM, false, false));
-  EXPECT_CALL(*mock_tables_.get(), UpdateData(url_data, empty_host_data_));
-
-  EXPECT_CALL(
-      *mock_tables_.get(),
-      DeleteSingleDataPoint("www.facebook.com", PREFETCH_KEY_TYPE_HOST));
+  EXPECT_CALL(*mock_tables_.get(),
+              UpdateData(url_data, empty_host_data_, empty_url_redirect_data_,
+                         empty_host_redirect_data_));
+  EXPECT_CALL(*mock_tables_.get(),
+              DeleteSingleResourceDataPoint("www.facebook.com",
+                                            PREFETCH_KEY_TYPE_HOST));
 
   PrefetchData host_data(PREFETCH_KEY_TYPE_HOST, "www.google.com");
   host_data.resources.push_back(CreateResourceData(
@@ -589,19 +694,23 @@
   host_data.resources.push_back(CreateResourceData(
       "http://google.com/style2.css", content::RESOURCE_TYPE_STYLESHEET, 1, 0,
       0, 7.0, net::MEDIUM, false, false));
-  EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data));
+  EXPECT_CALL(*mock_tables_.get(),
+              UpdateData(empty_url_data_, host_data, empty_url_redirect_data_,
+                         empty_host_redirect_data_));
 
   predictor_->OnNavigationComplete(main_frame.navigation_id);
   profile_->BlockUntilHistoryProcessesPendingRequests();
 }
 
+// Tests that a URL is deleted before another is added if the cache is full.
 TEST_F(ResourcePrefetchPredictorTest, NavigationUrlNotInDBAndDBFull) {
-  // Tests that a URL is deleted before another is added if the cache is full.
   AddUrlToHistory("http://www.nike.com/", 4);
 
   EXPECT_CALL(*mock_tables_.get(),
               GetAllData(Pointee(ContainerEq(PrefetchDataMap())),
-                         Pointee(ContainerEq(PrefetchDataMap()))))
+                         Pointee(ContainerEq(PrefetchDataMap())),
+                         Pointee(ContainerEq(RedirectDataMap())),
+                         Pointee(ContainerEq(RedirectDataMap()))))
       .WillOnce(DoAll(SetArgPointee<0>(test_url_data_),
                       SetArgPointee<1>(test_host_data_)));
   ResetPredictor();
@@ -624,12 +733,12 @@
       content::RESOURCE_TYPE_IMAGE, net::MEDIUM, "image/png", false);
   predictor_->RecordURLResponse(resource2);
 
-  EXPECT_CALL(
-      *mock_tables_.get(),
-      DeleteSingleDataPoint("http://www.google.com/", PREFETCH_KEY_TYPE_URL));
-  EXPECT_CALL(
-      *mock_tables_.get(),
-      DeleteSingleDataPoint("www.facebook.com", PREFETCH_KEY_TYPE_HOST));
+  EXPECT_CALL(*mock_tables_.get(),
+              DeleteSingleResourceDataPoint("http://www.google.com/",
+                                            PREFETCH_KEY_TYPE_URL));
+  EXPECT_CALL(*mock_tables_.get(),
+              DeleteSingleResourceDataPoint("www.facebook.com",
+                                            PREFETCH_KEY_TYPE_HOST));
 
   PrefetchData url_data(PREFETCH_KEY_TYPE_URL, "http://www.nike.com/");
   url_data.resources.push_back(CreateResourceData(
@@ -638,16 +747,126 @@
   url_data.resources.push_back(CreateResourceData(
       "http://nike.com/image2.png", content::RESOURCE_TYPE_IMAGE, 1, 0, 0, 2.0,
       net::MEDIUM, false, false));
-  EXPECT_CALL(*mock_tables_.get(), UpdateData(url_data, empty_host_data_));
+  EXPECT_CALL(*mock_tables_.get(),
+              UpdateData(url_data, empty_host_data_, empty_url_redirect_data_,
+                         empty_host_redirect_data_));
 
   PrefetchData host_data(PREFETCH_KEY_TYPE_HOST, "www.nike.com");
   host_data.resources = url_data.resources;
-  EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data));
+  EXPECT_CALL(*mock_tables_.get(),
+              UpdateData(empty_url_data_, host_data, empty_url_redirect_data_,
+                         empty_host_redirect_data_));
 
   predictor_->OnNavigationComplete(main_frame.navigation_id);
   profile_->BlockUntilHistoryProcessesPendingRequests();
 }
 
+TEST_F(ResourcePrefetchPredictorTest, RedirectUrlNotInDB) {
+  AddUrlToHistory("https://facebook.com/google", 4);
+
+  URLRequestSummary fb1 = CreateURLRequestSummary(1, 1, "http://fb.com/google");
+  predictor_->RecordURLRequest(fb1);
+  EXPECT_EQ(1U, predictor_->inflight_navigations_.size());
+
+  URLRequestSummary fb2 = CreateRedirectRequestSummary(
+      1, 1, "http://fb.com/google", "http://facebook.com/google");
+  predictor_->RecordURLRedirect(fb2);
+  URLRequestSummary fb3 = CreateRedirectRequestSummary(
+      1, 1, "http://facebook.com/google", "https://facebook.com/google");
+  predictor_->RecordURLRedirect(fb3);
+  NavigationID fb_end = CreateNavigationID(1, 1, "https://facebook.com/google");
+
+  // Since the navigation hasn't resources, corresponding entry
+  // in resource table will be deleted.
+  EXPECT_CALL(*mock_tables_.get(),
+              DeleteSingleResourceDataPoint("https://facebook.com/google",
+                                            PREFETCH_KEY_TYPE_URL));
+  EXPECT_CALL(*mock_tables_.get(), DeleteSingleResourceDataPoint(
+                                       "facebook.com", PREFETCH_KEY_TYPE_HOST));
+
+  RedirectData url_redirect_data;
+  url_redirect_data.set_primary_key("http://fb.com/google");
+  InitializeRedirectStat(url_redirect_data.add_redirect_endpoints(),
+                         "https://facebook.com/google", 1, 0, 0);
+  EXPECT_CALL(*mock_tables_.get(),
+              UpdateData(empty_url_data_, empty_host_data_, url_redirect_data,
+                         empty_host_redirect_data_));
+
+  RedirectData host_redirect_data;
+  host_redirect_data.set_primary_key("fb.com");
+  InitializeRedirectStat(host_redirect_data.add_redirect_endpoints(),
+                         "facebook.com", 1, 0, 0);
+  EXPECT_CALL(*mock_tables_.get(),
+              UpdateData(empty_url_data_, empty_host_data_,
+                         empty_url_redirect_data_, host_redirect_data));
+
+  predictor_->RecordMainFrameLoadComplete(fb_end);
+  profile_->BlockUntilHistoryProcessesPendingRequests();
+}
+
+// Tests that redirect is recorded correctly for URL already present in
+// the database cache.
+TEST_F(ResourcePrefetchPredictorTest, RedirectUrlInDB) {
+  AddUrlToHistory("https://facebook.com/google", 4);
+
+  EXPECT_CALL(*mock_tables_.get(),
+              GetAllData(Pointee(ContainerEq(PrefetchDataMap())),
+                         Pointee(ContainerEq(PrefetchDataMap())),
+                         Pointee(ContainerEq(RedirectDataMap())),
+                         Pointee(ContainerEq(RedirectDataMap()))))
+      .WillOnce(DoAll(SetArgPointee<2>(test_url_redirect_data_),
+                      SetArgPointee<3>(test_host_redirect_data_)));
+  ResetPredictor();
+  InitializePredictor();
+  EXPECT_EQ(3U, predictor_->url_redirect_table_cache_->size());
+  EXPECT_EQ(2U, predictor_->host_redirect_table_cache_->size());
+
+  URLRequestSummary fb1 = CreateURLRequestSummary(1, 1, "http://fb.com/google");
+  predictor_->RecordURLRequest(fb1);
+  EXPECT_EQ(1U, predictor_->inflight_navigations_.size());
+
+  URLRequestSummary fb2 = CreateRedirectRequestSummary(
+      1, 1, "http://fb.com/google", "http://facebook.com/google");
+  predictor_->RecordURLRedirect(fb2);
+  URLRequestSummary fb3 = CreateRedirectRequestSummary(
+      1, 1, "http://facebook.com/google", "https://facebook.com/google");
+  predictor_->RecordURLRedirect(fb3);
+  NavigationID fb_end = CreateNavigationID(1, 1, "https://facebook.com/google");
+
+  // Oldest entries in tables will be superseded and deleted.
+  EXPECT_CALL(*mock_tables_.get(),
+              DeleteSingleRedirectDataPoint("bbc.com", PREFETCH_KEY_TYPE_HOST));
+
+  // Since the navigation hasn't resources, corresponding entry
+  // in resource table will be deleted.
+  EXPECT_CALL(*mock_tables_.get(),
+              DeleteSingleResourceDataPoint("https://facebook.com/google",
+                                            PREFETCH_KEY_TYPE_URL));
+  EXPECT_CALL(*mock_tables_.get(), DeleteSingleResourceDataPoint(
+                                       "facebook.com", PREFETCH_KEY_TYPE_HOST));
+
+  RedirectData url_redirect_data;
+  url_redirect_data.set_primary_key("http://fb.com/google");
+  InitializeRedirectStat(url_redirect_data.add_redirect_endpoints(),
+                         "https://facebook.com/google", 6, 1, 0);
+  // Existing redirect to https://facebook.com/login will be deleted because of
+  // too many consecutive misses.
+  EXPECT_CALL(*mock_tables_.get(),
+              UpdateData(empty_url_data_, empty_host_data_, url_redirect_data,
+                         empty_host_redirect_data_));
+
+  RedirectData host_redirect_data;
+  host_redirect_data.set_primary_key("fb.com");
+  InitializeRedirectStat(host_redirect_data.add_redirect_endpoints(),
+                         "facebook.com", 1, 0, 0);
+  EXPECT_CALL(*mock_tables_.get(),
+              UpdateData(empty_url_data_, empty_host_data_,
+                         empty_url_redirect_data_, host_redirect_data));
+
+  predictor_->RecordMainFrameLoadComplete(fb_end);
+  profile_->BlockUntilHistoryProcessesPendingRequests();
+}
+
 TEST_F(ResourcePrefetchPredictorTest, DeleteUrls) {
   // Add some dummy entries to cache.
   predictor_->url_table_cache_->insert(std::make_pair(
@@ -676,31 +895,61 @@
       "www.apple.com",
       PrefetchData(PREFETCH_KEY_TYPE_HOST, "www.apple.com")));
 
+  predictor_->url_redirect_table_cache_->insert(
+      std::make_pair("http://www.google.com/page1.html",
+                     CreateRedirectData("http://www.google.com/page1.html")));
+  predictor_->url_redirect_table_cache_->insert(
+      std::make_pair("http://www.google.com/page2.html",
+                     CreateRedirectData("http://www.google.com/page2.html")));
+  predictor_->url_redirect_table_cache_->insert(std::make_pair(
+      "http://www.apple.com/", CreateRedirectData("http://www.apple.com/")));
+  predictor_->url_redirect_table_cache_->insert(
+      std::make_pair("http://nyt.com/", CreateRedirectData("http://nyt.com/")));
+
+  predictor_->host_redirect_table_cache_->insert(
+      std::make_pair("www.google.com", CreateRedirectData("www.google.com")));
+  predictor_->host_redirect_table_cache_->insert(
+      std::make_pair("www.nike.com", CreateRedirectData("www.nike.com")));
+  predictor_->host_redirect_table_cache_->insert(std::make_pair(
+      "www.wikipedia.org", CreateRedirectData("www.wikipedia.org")));
+
   history::URLRows rows;
   rows.push_back(history::URLRow(GURL("http://www.google.com/page2.html")));
   rows.push_back(history::URLRow(GURL("http://www.apple.com")));
   rows.push_back(history::URLRow(GURL("http://www.nike.com")));
 
-  std::vector<std::string> urls_to_delete, hosts_to_delete;
+  std::vector<std::string> urls_to_delete, hosts_to_delete,
+      url_redirects_to_delete, host_redirects_to_delete;
   urls_to_delete.push_back("http://www.google.com/page2.html");
   urls_to_delete.push_back("http://www.apple.com/");
   urls_to_delete.push_back("http://www.nike.com/");
   hosts_to_delete.push_back("www.google.com");
   hosts_to_delete.push_back("www.apple.com");
+  url_redirects_to_delete.push_back("http://www.google.com/page2.html");
+  url_redirects_to_delete.push_back("http://www.apple.com/");
+  host_redirects_to_delete.push_back("www.google.com");
+  host_redirects_to_delete.push_back("www.nike.com");
 
-  EXPECT_CALL(
-      *mock_tables_.get(),
-      DeleteData(ContainerEq(urls_to_delete), ContainerEq(hosts_to_delete)));
+  EXPECT_CALL(*mock_tables_.get(),
+              DeleteResourceData(ContainerEq(urls_to_delete),
+                                 ContainerEq(hosts_to_delete)));
+  EXPECT_CALL(*mock_tables_.get(),
+              DeleteRedirectData(ContainerEq(url_redirects_to_delete),
+                                 ContainerEq(host_redirects_to_delete)));
 
   predictor_->DeleteUrls(rows);
   EXPECT_EQ(2U, predictor_->url_table_cache_->size());
   EXPECT_EQ(1U, predictor_->host_table_cache_->size());
+  EXPECT_EQ(2U, predictor_->url_redirect_table_cache_->size());
+  EXPECT_EQ(1U, predictor_->host_redirect_table_cache_->size());
 
   EXPECT_CALL(*mock_tables_.get(), DeleteAllData());
 
   predictor_->DeleteAllUrls();
   EXPECT_TRUE(predictor_->url_table_cache_->empty());
   EXPECT_TRUE(predictor_->host_table_cache_->empty());
+  EXPECT_TRUE(predictor_->url_redirect_table_cache_->empty());
+  EXPECT_TRUE(predictor_->host_redirect_table_cache_->empty());
 }
 
 TEST_F(ResourcePrefetchPredictorTest, OnMainFrameRequest) {
@@ -721,7 +970,7 @@
   predictor_->OnMainFrameRequest(summary3);
   EXPECT_EQ(3U, predictor_->inflight_navigations_.size());
 
-  // Insert anther with same navigation id. It should replace.
+  // Insert another with same navigation id. It should replace.
   URLRequestSummary summary4 = CreateURLRequestSummary(
       1, 1, "http://www.nike.com", "http://www.nike.com",
       content::RESOURCE_TYPE_MAIN_FRAME, net::MEDIUM, std::string(), false);
@@ -753,30 +1002,78 @@
 }
 
 TEST_F(ResourcePrefetchPredictorTest, OnMainFrameRedirect) {
-  URLRequestSummary summary1 = CreateURLRequestSummary(
-      1, 1, "http://www.google.com", "http://www.google.com",
-      content::RESOURCE_TYPE_MAIN_FRAME, net::MEDIUM, std::string(), false);
-  URLRequestSummary summary2 = CreateURLRequestSummary(
-      1, 2, "http://www.google.com", "http://www.google.com",
-      content::RESOURCE_TYPE_MAIN_FRAME, net::MEDIUM, std::string(), false);
-  URLRequestSummary summary3 = CreateURLRequestSummary(
-      2, 1, "http://www.yahoo.com", "http://www.yahoo.com",
-      content::RESOURCE_TYPE_MAIN_FRAME, net::MEDIUM, std::string(), false);
+  URLRequestSummary yahoo = CreateURLRequestSummary(1, 1, "http://yahoo.com");
 
-  predictor_->OnMainFrameRedirect(summary1);
+  URLRequestSummary bbc1 = CreateURLRequestSummary(2, 2, "http://bbc.com");
+  URLRequestSummary bbc2 = CreateRedirectRequestSummary(2, 2, "http://bbc.com",
+                                                        "https://www.bbc.com");
+  NavigationID bbc_end = CreateNavigationID(2, 2, "https://www.bbc.com");
+
+  URLRequestSummary youtube1 =
+      CreateURLRequestSummary(1, 2, "http://youtube.com");
+  URLRequestSummary youtube2 = CreateRedirectRequestSummary(
+      1, 2, "http://youtube.com", "https://youtube.com");
+  NavigationID youtube_end = CreateNavigationID(1, 2, "https://youtube.com");
+
+  URLRequestSummary nyt1 = CreateURLRequestSummary(2, 1, "http://nyt.com");
+  URLRequestSummary nyt2 = CreateRedirectRequestSummary(2, 1, "http://nyt.com",
+                                                        "http://nytimes.com");
+  URLRequestSummary nyt3 = CreateRedirectRequestSummary(
+      2, 1, "http://nytimes.com", "http://m.nytimes.com");
+  NavigationID nyt_end = CreateNavigationID(2, 1, "http://m.nytimes.com");
+
+  URLRequestSummary fb1 = CreateURLRequestSummary(1, 3, "http://fb.com");
+  URLRequestSummary fb2 = CreateRedirectRequestSummary(1, 3, "http://fb.com",
+                                                       "http://facebook.com");
+  URLRequestSummary fb3 = CreateRedirectRequestSummary(
+      1, 3, "http://facebook.com", "https://facebook.com");
+  URLRequestSummary fb4 = CreateRedirectRequestSummary(
+      1, 3, "https://facebook.com",
+      "https://m.facebook.com/?refsrc=https%3A%2F%2Fwww.facebook.com%2F&_rdr");
+  NavigationID fb_end = CreateNavigationID(
+      1, 3,
+      "https://m.facebook.com/?refsrc=https%3A%2F%2Fwww.facebook.com%2F&_rdr");
+
+  // Redirect with empty redirect_url will be deleted.
+  predictor_->OnMainFrameRequest(yahoo);
+  EXPECT_EQ(1U, predictor_->inflight_navigations_.size());
+  predictor_->OnMainFrameRedirect(yahoo);
   EXPECT_TRUE(predictor_->inflight_navigations_.empty());
 
-  predictor_->OnMainFrameRequest(summary1);
+  // Redirect without previous request works fine.
+  // predictor_->OnMainFrameRequest(bbc1) missing.
+  predictor_->OnMainFrameRedirect(bbc2);
   EXPECT_EQ(1U, predictor_->inflight_navigations_.size());
-  predictor_->OnMainFrameRequest(summary2);
-  EXPECT_EQ(2U, predictor_->inflight_navigations_.size());
+  EXPECT_EQ(bbc1.navigation_id.main_frame_url,
+            predictor_->inflight_navigations_[bbc_end]->initial_url);
 
-  predictor_->OnMainFrameRedirect(summary3);
+  // http://youtube.com -> https://youtube.com.
+  predictor_->OnMainFrameRequest(youtube1);
   EXPECT_EQ(2U, predictor_->inflight_navigations_.size());
-  predictor_->OnMainFrameRedirect(summary1);
-  EXPECT_EQ(1U, predictor_->inflight_navigations_.size());
-  predictor_->OnMainFrameRedirect(summary2);
-  EXPECT_TRUE(predictor_->inflight_navigations_.empty());
+  predictor_->OnMainFrameRedirect(youtube2);
+  EXPECT_EQ(2U, predictor_->inflight_navigations_.size());
+  EXPECT_EQ(youtube1.navigation_id.main_frame_url,
+            predictor_->inflight_navigations_[youtube_end]->initial_url);
+
+  // http://nyt.com -> http://nytimes.com -> http://m.nytimes.com.
+  predictor_->OnMainFrameRequest(nyt1);
+  EXPECT_EQ(3U, predictor_->inflight_navigations_.size());
+  predictor_->OnMainFrameRedirect(nyt2);
+  predictor_->OnMainFrameRedirect(nyt3);
+  EXPECT_EQ(3U, predictor_->inflight_navigations_.size());
+  EXPECT_EQ(nyt1.navigation_id.main_frame_url,
+            predictor_->inflight_navigations_[nyt_end]->initial_url);
+
+  // http://fb.com -> http://facebook.com -> https://facebook.com ->
+  // https://m.facebook.com/?refsrc=https%3A%2F%2Fwww.facebook.com%2F&_rdr.
+  predictor_->OnMainFrameRequest(fb1);
+  EXPECT_EQ(4U, predictor_->inflight_navigations_.size());
+  predictor_->OnMainFrameRedirect(fb2);
+  predictor_->OnMainFrameRedirect(fb3);
+  predictor_->OnMainFrameRedirect(fb4);
+  EXPECT_EQ(4U, predictor_->inflight_navigations_.size());
+  EXPECT_EQ(fb1.navigation_id.main_frame_url,
+            predictor_->inflight_navigations_[fb_end]->initial_url);
 }
 
 TEST_F(ResourcePrefetchPredictorTest, OnSubresourceResponse) {
@@ -806,17 +1103,17 @@
   predictor_->OnSubresourceResponse(resource3);
 
   EXPECT_EQ(1U, predictor_->inflight_navigations_.size());
-  EXPECT_EQ(3U,
-      predictor_->inflight_navigations_[main_frame1.navigation_id]->size());
+  EXPECT_EQ(3U, predictor_->inflight_navigations_[main_frame1.navigation_id]
+                    ->subresource_requests.size());
   EXPECT_TRUE(URLRequestSummaryAreEqual(
-      resource1,
-      predictor_->inflight_navigations_[main_frame1.navigation_id]->at(0)));
+      resource1, predictor_->inflight_navigations_[main_frame1.navigation_id]
+                     ->subresource_requests[0]));
   EXPECT_TRUE(URLRequestSummaryAreEqual(
-      resource2,
-      predictor_->inflight_navigations_[main_frame1.navigation_id]->at(1)));
+      resource2, predictor_->inflight_navigations_[main_frame1.navigation_id]
+                     ->subresource_requests[1]));
   EXPECT_TRUE(URLRequestSummaryAreEqual(
-      resource3,
-      predictor_->inflight_navigations_[main_frame1.navigation_id]->at(2)));
+      resource3, predictor_->inflight_navigations_[main_frame1.navigation_id]
+                     ->subresource_requests[2]));
 }
 
 TEST_F(ResourcePrefetchPredictorTest, HandledResourceTypes) {
@@ -911,7 +1208,7 @@
   response_info.was_cached = true;
   url_request_job_factory_.set_response_info(response_info);
 
-  // Protocol
+  // Protocol.
   std::unique_ptr<net::URLRequest> http_image_request =
       CreateURLRequest(GURL("http://www.google.com/cat.png"), net::MEDIUM,
                        content::RESOURCE_TYPE_IMAGE, 1, 1, true);
@@ -930,7 +1227,7 @@
   EXPECT_FALSE(ResourcePrefetchPredictor::ShouldRecordResponse(
       file_image_request.get()));
 
-  // ResourceType
+  // ResourceType.
   std::unique_ptr<net::URLRequest> sub_frame_request =
       CreateURLRequest(GURL("http://www.google.com/frame.html"), net::MEDIUM,
                        content::RESOURCE_TYPE_SUB_FRAME, 1, 1, true);
@@ -973,7 +1270,7 @@
   EXPECT_FALSE(ResourcePrefetchPredictor::ShouldRecordResponse(
       prefetch_unknown_font_request.get()));
 
-  // Not main frame
+  // Not main frame.
   std::unique_ptr<net::URLRequest> font_request_sub_frame = CreateURLRequest(
       GURL("http://www.google.com/comic-sans-ms.woff"), net::MEDIUM,
       content::RESOURCE_TYPE_FONT_RESOURCE, 1, 1, false);
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index ee6f76f..319ff29 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -78,8 +78,8 @@
 #include "components/metrics/metrics_service.h"
 #include "components/network_time/network_time_tracker.h"
 #include "components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h"
-#include "components/ntp_snippets/ntp_snippets_service.h"
-#include "components/ntp_snippets/request_throttler.h"
+#include "components/ntp_snippets/remote/ntp_snippets_service.h"
+#include "components/ntp_snippets/remote/request_throttler.h"
 #include "components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.h"
 #include "components/ntp_snippets/user_classifier.h"
 #include "components/omnibox/browser/zero_suggest_provider.h"
diff --git a/chrome/browser/prerender/prerender_contents.cc b/chrome/browser/prerender/prerender_contents.cc
index 890008a..a8eaeb8 100644
--- a/chrome/browser/prerender/prerender_contents.cc
+++ b/chrome/browser/prerender/prerender_contents.cc
@@ -112,7 +112,7 @@
     return NULL;
   }
 
-  bool ShouldTransferNavigation() override {
+  bool ShouldTransferNavigation(bool is_main_frame_navigation) override {
     // Cancel the prerender if the navigation attempts to transfer to a
     // different process.  Examples include server redirects to privileged pages
     // or cross-site subframe navigations in --site-per-process.
diff --git a/chrome/browser/renderer_host/chrome_navigation_ui_data.cc b/chrome/browser/renderer_host/chrome_navigation_ui_data.cc
new file mode 100644
index 0000000..cffc26b6
--- /dev/null
+++ b/chrome/browser/renderer_host/chrome_navigation_ui_data.cc
@@ -0,0 +1,46 @@
+// 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.
+
+#include "chrome/browser/renderer_host/chrome_navigation_ui_data.h"
+
+#include "base/memory/ptr_util.h"
+#include "chrome/browser/sessions/session_tab_helper.h"
+#include "content/public/browser/navigation_handle.h"
+
+ChromeNavigationUIData::ChromeNavigationUIData() {}
+
+ChromeNavigationUIData::ChromeNavigationUIData(
+    content::NavigationHandle* navigation_handle) {
+#if defined(ENABLE_EXTENSIONS)
+  SessionTabHelper* session_tab_helper =
+      SessionTabHelper::FromWebContents(navigation_handle->GetWebContents());
+  int tab_id = session_tab_helper ? session_tab_helper->session_id().id() : -1;
+  int window_id =
+      session_tab_helper ? session_tab_helper->window_id().id() : -1;
+  extension_data_ = base::MakeUnique<extensions::ExtensionNavigationUIData>(
+      navigation_handle, tab_id, window_id);
+#endif
+}
+
+ChromeNavigationUIData::~ChromeNavigationUIData() {}
+
+std::unique_ptr<content::NavigationUIData> ChromeNavigationUIData::Clone()
+    const {
+  std::unique_ptr<ChromeNavigationUIData> copy =
+      base::MakeUnique<ChromeNavigationUIData>();
+
+#if defined(ENABLE_EXTENSIONS)
+  if (extension_data_)
+    copy->SetExtensionNavigationUIData(extension_data_->DeepCopy());
+#endif
+
+  return std::move(copy);
+}
+
+#if defined(ENABLE_EXTENSIONS)
+void ChromeNavigationUIData::SetExtensionNavigationUIData(
+    std::unique_ptr<extensions::ExtensionNavigationUIData> extension_data) {
+  extension_data_ = std::move(extension_data);
+}
+#endif
diff --git a/chrome/browser/renderer_host/chrome_navigation_ui_data.h b/chrome/browser/renderer_host/chrome_navigation_ui_data.h
new file mode 100644
index 0000000..4f441e0
--- /dev/null
+++ b/chrome/browser/renderer_host/chrome_navigation_ui_data.h
@@ -0,0 +1,52 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_RENDERER_HOST_CHROME_NAVIGATION_UI_DATA_H_
+#define CHROME_BROWSER_RENDERER_HOST_CHROME_NAVIGATION_UI_DATA_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "content/public/browser/navigation_ui_data.h"
+#include "extensions/browser/extension_navigation_ui_data.h"
+
+namespace content {
+class NavigationHandle;
+}
+
+// PlzNavigate
+// Contains data that is passed from the UI thread to the IO thread at the
+// beginning of each navigation. The class is instantiated on the UI thread,
+// then a copy created using Clone is passed to the content::ResourceRequestInfo
+// on the IO thread.
+class ChromeNavigationUIData : public content::NavigationUIData {
+ public:
+  ChromeNavigationUIData();
+  explicit ChromeNavigationUIData(content::NavigationHandle* navigation_handle);
+  ~ChromeNavigationUIData() override;
+
+  // Creates a new ChromeNavigationUIData that is a deep copy of the original.
+  // Any changes to the original after the clone is created will not be
+  // reflected in the clone.  |extension_data_| is deep copied.
+  std::unique_ptr<content::NavigationUIData> Clone() const override;
+
+#if defined(ENABLE_EXTENSIONS)
+  void SetExtensionNavigationUIData(
+      std::unique_ptr<extensions::ExtensionNavigationUIData> extension_data);
+
+  extensions::ExtensionNavigationUIData* GetExtensionNavigationUIData() const {
+    return extension_data_.get();
+  }
+#endif
+
+ private:
+#if defined(ENABLE_EXTENSIONS)
+  // Manages the lifetime of optional ExtensionNavigationUIData information.
+  std::unique_ptr<extensions::ExtensionNavigationUIData> extension_data_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(ChromeNavigationUIData);
+};
+
+#endif  // CHROME_BROWSER_RENDERER_HOST_CHROME_NAVIGATION_UI_DATA_H_
diff --git a/chrome/browser/resources/chromeos/keyboard_overlay_data.js b/chrome/browser/resources/chromeos/keyboard_overlay_data.js
index 275cb4c..3501bd3 100644
--- a/chrome/browser/resources/chromeos/keyboard_overlay_data.js
+++ b/chrome/browser/resources/chromeos/keyboard_overlay_data.js
@@ -15870,6 +15870,7 @@
     'full screen<>SEARCH': 'keyboardOverlayF4',
     'g<>CTRL': 'keyboardOverlayFindTextAgain',
     'g<>CTRL<>SHIFT': 'keyboardOverlayFindPreviousText',
+    'h<>ALT<>CTRL': 'keyboardOverlayToggleHighContrastMode',
     'h<>CTRL': 'keyboardOverlayHistory',
     'i<>ALT<>SHIFT': 'keyboardOverlayReportIssue',
     'i<>CTRL<>SHIFT': 'keyboardOverlayDeveloperTools',
diff --git a/chrome/browser/resources/domain_reliability_internals.html b/chrome/browser/resources/domain_reliability_internals.html
index 446bcbf..00d273ef 100644
--- a/chrome/browser/resources/domain_reliability_internals.html
+++ b/chrome/browser/resources/domain_reliability_internals.html
@@ -20,7 +20,7 @@
       <span jscontent="error"></span>
     </div>
     <div jsselect="contexts">
-      <h2 jscontent="domain"></h2>
+      <h2 jscontent="origin"></h2>
       <p>
         <span jscontent="beacon_count"></span> beacons queued.</span>
         <span jsdisplay="scheduler.upload_pending">Upload pending.</span>
diff --git a/chrome/browser/resources/md_downloads/crisper.js b/chrome/browser/resources/md_downloads/crisper.js
index 34ccde3e..288a392 100644
--- a/chrome/browser/resources/md_downloads/crisper.js
+++ b/chrome/browser/resources/md_downloads/crisper.js
@@ -1,7030 +1,72 @@
 // Copyright (c) 2013 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.
-function assert(condition, opt_message) {
-  if (!condition) {
-    var message = 'Assertion failed';
-    if (opt_message) message = message + ': ' + opt_message;
-    var error = new Error(message);
-    var global = function() {
-      return this;
-    }();
-    if (global.traceAssertionsForTesting) console.warn(error.stack);
-    throw error;
-  }
-  return condition;
-}
-
-function assertNotReached(opt_message) {
-  assert(false, opt_message || 'Unreachable code hit');
-}
-
-function assertInstanceof(value, type, opt_message) {
-  if (!(value instanceof type)) {
-    assertNotReached(opt_message || 'Value ' + value + ' is not a[n] ' + (type.name || typeof type));
-  }
-  return value;
-}
-
+function assert(condition,opt_message){if(!condition){var message="Assertion failed";if(opt_message)message=message+": "+opt_message;var error=new Error(message);var global=function(){return this}();if(global.traceAssertionsForTesting)console.warn(error.stack);throw error}return condition}function assertNotReached(opt_message){assert(false,opt_message||"Unreachable code hit")}function assertInstanceof(value,type,opt_message){if(!(value instanceof type)){assertNotReached(opt_message||"Value "+value+" is not a[n] "+(type.name||typeof type))}return value}
 // 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.
-function PromiseResolver() {
-  this.resolve_;
-  this.reject_;
-  this.promise_ = new Promise(function(resolve, reject) {
-    this.resolve_ = resolve;
-    this.reject_ = reject;
-  }.bind(this));
-}
-
-PromiseResolver.prototype = {
-  get promise() {
-    return this.promise_;
-  },
-  set promise(p) {
-    assertNotReached();
-  },
-  get resolve() {
-    return this.resolve_;
-  },
-  set resolve(r) {
-    assertNotReached();
-  },
-  get reject() {
-    return this.reject_;
-  },
-  set reject(s) {
-    assertNotReached();
-  }
-};
-
+function PromiseResolver(){this.resolve_;this.reject_;this.promise_=new Promise(function(resolve,reject){this.resolve_=resolve;this.reject_=reject}.bind(this))}PromiseResolver.prototype={get promise(){return this.promise_},set promise(p){assertNotReached()},get resolve(){return this.resolve_},set resolve(r){assertNotReached()},get reject(){return this.reject_},set reject(s){assertNotReached()}};
 // 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.
-var global = this;
-
-var WebUIListener;
-
-var cr = cr || function() {
-  'use strict';
-  function exportPath(name, opt_object, opt_objectToExportTo) {
-    var parts = name.split('.');
-    var cur = opt_objectToExportTo || global;
-    for (var part; parts.length && (part = parts.shift()); ) {
-      if (!parts.length && opt_object !== undefined) {
-        cur[part] = opt_object;
-      } else if (part in cur) {
-        cur = cur[part];
-      } else {
-        cur = cur[part] = {};
-      }
-    }
-    return cur;
-  }
-  function dispatchPropertyChange(target, propertyName, newValue, oldValue) {
-    var e = new Event(propertyName + 'Change');
-    e.propertyName = propertyName;
-    e.newValue = newValue;
-    e.oldValue = oldValue;
-    target.dispatchEvent(e);
-  }
-  function getAttributeName(jsName) {
-    return jsName.replace(/([A-Z])/g, '-$1').toLowerCase();
-  }
-  var PropertyKind = {
-    JS: 'js',
-    ATTR: 'attr',
-    BOOL_ATTR: 'boolAttr'
-  };
-  function getGetter(name, kind) {
-    switch (kind) {
-     case PropertyKind.JS:
-      var privateName = name + '_';
-      return function() {
-        return this[privateName];
-      };
-
-     case PropertyKind.ATTR:
-      var attributeName = getAttributeName(name);
-      return function() {
-        return this.getAttribute(attributeName);
-      };
-
-     case PropertyKind.BOOL_ATTR:
-      var attributeName = getAttributeName(name);
-      return function() {
-        return this.hasAttribute(attributeName);
-      };
-    }
-    throw 'not reached';
-  }
-  function getSetter(name, kind, opt_setHook) {
-    switch (kind) {
-     case PropertyKind.JS:
-      var privateName = name + '_';
-      return function(value) {
-        var oldValue = this[name];
-        if (value !== oldValue) {
-          this[privateName] = value;
-          if (opt_setHook) opt_setHook.call(this, value, oldValue);
-          dispatchPropertyChange(this, name, value, oldValue);
-        }
-      };
-
-     case PropertyKind.ATTR:
-      var attributeName = getAttributeName(name);
-      return function(value) {
-        var oldValue = this[name];
-        if (value !== oldValue) {
-          if (value == undefined) this.removeAttribute(attributeName); else this.setAttribute(attributeName, value);
-          if (opt_setHook) opt_setHook.call(this, value, oldValue);
-          dispatchPropertyChange(this, name, value, oldValue);
-        }
-      };
-
-     case PropertyKind.BOOL_ATTR:
-      var attributeName = getAttributeName(name);
-      return function(value) {
-        var oldValue = this[name];
-        if (value !== oldValue) {
-          if (value) this.setAttribute(attributeName, name); else this.removeAttribute(attributeName);
-          if (opt_setHook) opt_setHook.call(this, value, oldValue);
-          dispatchPropertyChange(this, name, value, oldValue);
-        }
-      };
-    }
-    throw 'not reached';
-  }
-  function defineProperty(obj, name, opt_kind, opt_setHook) {
-    if (typeof obj == 'function') obj = obj.prototype;
-    var kind = opt_kind || PropertyKind.JS;
-    if (!obj.__lookupGetter__(name)) obj.__defineGetter__(name, getGetter(name, kind));
-    if (!obj.__lookupSetter__(name)) obj.__defineSetter__(name, getSetter(name, kind, opt_setHook));
-  }
-  var uidCounter = 1;
-  function createUid() {
-    return uidCounter++;
-  }
-  function getUid(item) {
-    if (item.hasOwnProperty('uid')) return item.uid;
-    return item.uid = createUid();
-  }
-  function dispatchSimpleEvent(target, type, opt_bubbles, opt_cancelable) {
-    var e = new Event(type, {
-      bubbles: opt_bubbles,
-      cancelable: opt_cancelable === undefined || opt_cancelable
-    });
-    return target.dispatchEvent(e);
-  }
-  function define(name, fun) {
-    var obj = exportPath(name);
-    var exports = fun();
-    for (var propertyName in exports) {
-      var propertyDescriptor = Object.getOwnPropertyDescriptor(exports, propertyName);
-      if (propertyDescriptor) Object.defineProperty(obj, propertyName, propertyDescriptor);
-    }
-  }
-  function addSingletonGetter(ctor) {
-    ctor.getInstance = function() {
-      return ctor.instance_ || (ctor.instance_ = new ctor());
-    };
-  }
-  function makePublic(ctor, methods, opt_target) {
-    methods.forEach(function(method) {
-      ctor[method] = function() {
-        var target = opt_target ? document.getElementById(opt_target) : ctor.getInstance();
-        return target[method + '_'].apply(target, arguments);
-      };
-    });
-  }
-  var chromeSendResolverMap = {};
-  function webUIResponse(id, isSuccess, response) {
-    var resolver = chromeSendResolverMap[id];
-    delete chromeSendResolverMap[id];
-    if (isSuccess) resolver.resolve(response); else resolver.reject(response);
-  }
-  function sendWithPromise(methodName, var_args) {
-    var args = Array.prototype.slice.call(arguments, 1);
-    var promiseResolver = new PromiseResolver();
-    var id = methodName + '_' + createUid();
-    chromeSendResolverMap[id] = promiseResolver;
-    chrome.send(methodName, [ id ].concat(args));
-    return promiseResolver.promise;
-  }
-  var webUIListenerMap = {};
-  function webUIListenerCallback(event, var_args) {
-    var eventListenersMap = webUIListenerMap[event];
-    if (!eventListenersMap) {
-      return;
-    }
-    var args = Array.prototype.slice.call(arguments, 1);
-    for (var listenerId in eventListenersMap) {
-      eventListenersMap[listenerId].apply(null, args);
-    }
-  }
-  function addWebUIListener(eventName, callback) {
-    webUIListenerMap[eventName] = webUIListenerMap[eventName] || {};
-    var uid = createUid();
-    webUIListenerMap[eventName][uid] = callback;
-    return {
-      eventName: eventName,
-      uid: uid
-    };
-  }
-  function removeWebUIListener(listener) {
-    var listenerExists = webUIListenerMap[listener.eventName] && webUIListenerMap[listener.eventName][listener.uid];
-    if (listenerExists) {
-      delete webUIListenerMap[listener.eventName][listener.uid];
-      return true;
-    }
-    return false;
-  }
-  return {
-    addSingletonGetter: addSingletonGetter,
-    createUid: createUid,
-    define: define,
-    defineProperty: defineProperty,
-    dispatchPropertyChange: dispatchPropertyChange,
-    dispatchSimpleEvent: dispatchSimpleEvent,
-    exportPath: exportPath,
-    getUid: getUid,
-    makePublic: makePublic,
-    PropertyKind: PropertyKind,
-    addWebUIListener: addWebUIListener,
-    removeWebUIListener: removeWebUIListener,
-    sendWithPromise: sendWithPromise,
-    webUIListenerCallback: webUIListenerCallback,
-    webUIResponse: webUIResponse,
-    get doc() {
-      return document;
-    },
-    get isMac() {
-      return /Mac/.test(navigator.platform);
-    },
-    get isWindows() {
-      return /Win/.test(navigator.platform);
-    },
-    get isChromeOS() {
-      return /CrOS/.test(navigator.userAgent);
-    },
-    get isLinux() {
-      return /Linux/.test(navigator.userAgent);
-    },
-    get isAndroid() {
-      return /Android/.test(navigator.userAgent);
-    },
-    get isIOS() {
-      return /iPad|iPhone|iPod/.test(navigator.platform);
-    }
-  };
-}();
-
+var global=this;var WebUIListener;var cr=cr||function(){"use strict";function exportPath(name,opt_object,opt_objectToExportTo){var parts=name.split(".");var cur=opt_objectToExportTo||global;for(var part;parts.length&&(part=parts.shift());){if(!parts.length&&opt_object!==undefined){cur[part]=opt_object}else if(part in cur){cur=cur[part]}else{cur=cur[part]={}}}return cur}function dispatchPropertyChange(target,propertyName,newValue,oldValue){var e=new Event(propertyName+"Change");e.propertyName=propertyName;e.newValue=newValue;e.oldValue=oldValue;target.dispatchEvent(e)}function getAttributeName(jsName){return jsName.replace(/([A-Z])/g,"-$1").toLowerCase()}var PropertyKind={JS:"js",ATTR:"attr",BOOL_ATTR:"boolAttr"};function getGetter(name,kind){switch(kind){case PropertyKind.JS:var privateName=name+"_";return function(){return this[privateName]};case PropertyKind.ATTR:var attributeName=getAttributeName(name);return function(){return this.getAttribute(attributeName)};case PropertyKind.BOOL_ATTR:var attributeName=getAttributeName(name);return function(){return this.hasAttribute(attributeName)}}throw"not reached"}function getSetter(name,kind,opt_setHook){switch(kind){case PropertyKind.JS:var privateName=name+"_";return function(value){var oldValue=this[name];if(value!==oldValue){this[privateName]=value;if(opt_setHook)opt_setHook.call(this,value,oldValue);dispatchPropertyChange(this,name,value,oldValue)}};case PropertyKind.ATTR:var attributeName=getAttributeName(name);return function(value){var oldValue=this[name];if(value!==oldValue){if(value==undefined)this.removeAttribute(attributeName);else this.setAttribute(attributeName,value);if(opt_setHook)opt_setHook.call(this,value,oldValue);dispatchPropertyChange(this,name,value,oldValue)}};case PropertyKind.BOOL_ATTR:var attributeName=getAttributeName(name);return function(value){var oldValue=this[name];if(value!==oldValue){if(value)this.setAttribute(attributeName,name);else this.removeAttribute(attributeName);if(opt_setHook)opt_setHook.call(this,value,oldValue);dispatchPropertyChange(this,name,value,oldValue)}}}throw"not reached"}function defineProperty(obj,name,opt_kind,opt_setHook){if(typeof obj=="function")obj=obj.prototype;var kind=opt_kind||PropertyKind.JS;if(!obj.__lookupGetter__(name))obj.__defineGetter__(name,getGetter(name,kind));if(!obj.__lookupSetter__(name))obj.__defineSetter__(name,getSetter(name,kind,opt_setHook))}var uidCounter=1;function createUid(){return uidCounter++}function getUid(item){if(item.hasOwnProperty("uid"))return item.uid;return item.uid=createUid()}function dispatchSimpleEvent(target,type,opt_bubbles,opt_cancelable){var e=new Event(type,{bubbles:opt_bubbles,cancelable:opt_cancelable===undefined||opt_cancelable});return target.dispatchEvent(e)}function define(name,fun){var obj=exportPath(name);var exports=fun();for(var propertyName in exports){var propertyDescriptor=Object.getOwnPropertyDescriptor(exports,propertyName);if(propertyDescriptor)Object.defineProperty(obj,propertyName,propertyDescriptor)}}function addSingletonGetter(ctor){ctor.getInstance=function(){return ctor.instance_||(ctor.instance_=new ctor)}}function makePublic(ctor,methods,opt_target){methods.forEach(function(method){ctor[method]=function(){var target=opt_target?document.getElementById(opt_target):ctor.getInstance();return target[method+"_"].apply(target,arguments)}})}var chromeSendResolverMap={};function webUIResponse(id,isSuccess,response){var resolver=chromeSendResolverMap[id];delete chromeSendResolverMap[id];if(isSuccess)resolver.resolve(response);else resolver.reject(response)}function sendWithPromise(methodName,var_args){var args=Array.prototype.slice.call(arguments,1);var promiseResolver=new PromiseResolver;var id=methodName+"_"+createUid();chromeSendResolverMap[id]=promiseResolver;chrome.send(methodName,[id].concat(args));return promiseResolver.promise}var webUIListenerMap={};function webUIListenerCallback(event,var_args){var eventListenersMap=webUIListenerMap[event];if(!eventListenersMap){return}var args=Array.prototype.slice.call(arguments,1);for(var listenerId in eventListenersMap){eventListenersMap[listenerId].apply(null,args)}}function addWebUIListener(eventName,callback){webUIListenerMap[eventName]=webUIListenerMap[eventName]||{};var uid=createUid();webUIListenerMap[eventName][uid]=callback;return{eventName:eventName,uid:uid}}function removeWebUIListener(listener){var listenerExists=webUIListenerMap[listener.eventName]&&webUIListenerMap[listener.eventName][listener.uid];if(listenerExists){delete webUIListenerMap[listener.eventName][listener.uid];return true}return false}return{addSingletonGetter:addSingletonGetter,createUid:createUid,define:define,defineProperty:defineProperty,dispatchPropertyChange:dispatchPropertyChange,dispatchSimpleEvent:dispatchSimpleEvent,exportPath:exportPath,getUid:getUid,makePublic:makePublic,PropertyKind:PropertyKind,addWebUIListener:addWebUIListener,removeWebUIListener:removeWebUIListener,sendWithPromise:sendWithPromise,webUIListenerCallback:webUIListenerCallback,webUIResponse:webUIResponse,get doc(){return document},get isMac(){return/Mac/.test(navigator.platform)},get isWindows(){return/Win/.test(navigator.platform)},get isChromeOS(){return/CrOS/.test(navigator.userAgent)},get isLinux(){return/Linux/.test(navigator.userAgent)},get isAndroid(){return/Android/.test(navigator.userAgent)},get isIOS(){return/iPad|iPhone|iPod/.test(navigator.platform)}}}();
 // 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.
-cr.define('cr.ui', function() {
-  function decorate(source, constr) {
-    var elements;
-    if (typeof source == 'string') elements = cr.doc.querySelectorAll(source); else elements = [ source ];
-    for (var i = 0, el; el = elements[i]; i++) {
-      if (!(el instanceof constr)) constr.decorate(el);
-    }
-  }
-  function createElementHelper(tagName, opt_bag) {
-    var doc;
-    if (opt_bag && opt_bag.ownerDocument) doc = opt_bag.ownerDocument; else doc = cr.doc;
-    return doc.createElement(tagName);
-  }
-  function define(tagNameOrFunction) {
-    var createFunction, tagName;
-    if (typeof tagNameOrFunction == 'function') {
-      createFunction = tagNameOrFunction;
-      tagName = '';
-    } else {
-      createFunction = createElementHelper;
-      tagName = tagNameOrFunction;
-    }
-    function f(opt_propertyBag) {
-      var el = createFunction(tagName, opt_propertyBag);
-      f.decorate(el);
-      for (var propertyName in opt_propertyBag) {
-        el[propertyName] = opt_propertyBag[propertyName];
-      }
-      return el;
-    }
-    f.decorate = function(el) {
-      el.__proto__ = f.prototype;
-      el.decorate();
-    };
-    return f;
-  }
-  function limitInputWidth(el, parentEl, min, opt_scale) {
-    el.style.width = '10px';
-    var doc = el.ownerDocument;
-    var win = doc.defaultView;
-    var computedStyle = win.getComputedStyle(el);
-    var parentComputedStyle = win.getComputedStyle(parentEl);
-    var rtl = computedStyle.direction == 'rtl';
-    var inputRect = el.getBoundingClientRect();
-    var parentRect = parentEl.getBoundingClientRect();
-    var startPos = rtl ? parentRect.right - inputRect.right : inputRect.left - parentRect.left;
-    var inner = parseInt(computedStyle.borderLeftWidth, 10) + parseInt(computedStyle.paddingLeft, 10) + parseInt(computedStyle.paddingRight, 10) + parseInt(computedStyle.borderRightWidth, 10);
-    var parentPadding = rtl ? parseInt(parentComputedStyle.paddingLeft, 10) : parseInt(parentComputedStyle.paddingRight, 10);
-    var max = parentEl.clientWidth - startPos - inner - parentPadding;
-    if (opt_scale) max *= opt_scale;
-    function limit() {
-      if (el.scrollWidth > max) {
-        el.style.width = max + 'px';
-      } else {
-        el.style.width = 0;
-        var sw = el.scrollWidth;
-        if (sw < min) {
-          el.style.width = min + 'px';
-        } else {
-          el.style.width = sw + 'px';
-        }
-      }
-    }
-    el.addEventListener('input', limit);
-    limit();
-  }
-  function toCssPx(pixels) {
-    if (!window.isFinite(pixels)) console.error('Pixel value is not a number: ' + pixels);
-    return Math.round(pixels) + 'px';
-  }
-  function swallowDoubleClick(e) {
-    var doc = e.target.ownerDocument;
-    var counter = Math.min(1, e.detail);
-    function swallow(e) {
-      e.stopPropagation();
-      e.preventDefault();
-    }
-    function onclick(e) {
-      if (e.detail > counter) {
-        counter = e.detail;
-        swallow(e);
-      } else {
-        doc.removeEventListener('dblclick', swallow, true);
-        doc.removeEventListener('click', onclick, true);
-      }
-    }
-    setTimeout(function() {
-      doc.addEventListener('click', onclick, true);
-      doc.addEventListener('dblclick', swallow, true);
-    }, 0);
-  }
-  return {
-    decorate: decorate,
-    define: define,
-    limitInputWidth: limitInputWidth,
-    toCssPx: toCssPx,
-    swallowDoubleClick: swallowDoubleClick
-  };
-});
-
+cr.define("cr.ui",function(){function decorate(source,constr){var elements;if(typeof source=="string")elements=cr.doc.querySelectorAll(source);else elements=[source];for(var i=0,el;el=elements[i];i++){if(!(el instanceof constr))constr.decorate(el)}}function createElementHelper(tagName,opt_bag){var doc;if(opt_bag&&opt_bag.ownerDocument)doc=opt_bag.ownerDocument;else doc=cr.doc;return doc.createElement(tagName)}function define(tagNameOrFunction){var createFunction,tagName;if(typeof tagNameOrFunction=="function"){createFunction=tagNameOrFunction;tagName=""}else{createFunction=createElementHelper;tagName=tagNameOrFunction}function f(opt_propertyBag){var el=createFunction(tagName,opt_propertyBag);f.decorate(el);for(var propertyName in opt_propertyBag){el[propertyName]=opt_propertyBag[propertyName]}return el}f.decorate=function(el){el.__proto__=f.prototype;el.decorate()};return f}function limitInputWidth(el,parentEl,min,opt_scale){el.style.width="10px";var doc=el.ownerDocument;var win=doc.defaultView;var computedStyle=win.getComputedStyle(el);var parentComputedStyle=win.getComputedStyle(parentEl);var rtl=computedStyle.direction=="rtl";var inputRect=el.getBoundingClientRect();var parentRect=parentEl.getBoundingClientRect();var startPos=rtl?parentRect.right-inputRect.right:inputRect.left-parentRect.left;var inner=parseInt(computedStyle.borderLeftWidth,10)+parseInt(computedStyle.paddingLeft,10)+parseInt(computedStyle.paddingRight,10)+parseInt(computedStyle.borderRightWidth,10);var parentPadding=rtl?parseInt(parentComputedStyle.paddingLeft,10):parseInt(parentComputedStyle.paddingRight,10);var max=parentEl.clientWidth-startPos-inner-parentPadding;if(opt_scale)max*=opt_scale;function limit(){if(el.scrollWidth>max){el.style.width=max+"px"}else{el.style.width=0;var sw=el.scrollWidth;if(sw<min){el.style.width=min+"px"}else{el.style.width=sw+"px"}}}el.addEventListener("input",limit);limit()}function toCssPx(pixels){if(!window.isFinite(pixels))console.error("Pixel value is not a number: "+pixels);return Math.round(pixels)+"px"}function swallowDoubleClick(e){var doc=e.target.ownerDocument;var counter=Math.min(1,e.detail);function swallow(e){e.stopPropagation();e.preventDefault()}function onclick(e){if(e.detail>counter){counter=e.detail;swallow(e)}else{doc.removeEventListener("dblclick",swallow,true);doc.removeEventListener("click",onclick,true)}}setTimeout(function(){doc.addEventListener("click",onclick,true);doc.addEventListener("dblclick",swallow,true)},0)}return{decorate:decorate,define:define,limitInputWidth:limitInputWidth,toCssPx:toCssPx,swallowDoubleClick:swallowDoubleClick}});
 // 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.
-cr.define('cr.ui', function() {
-  function KeyboardShortcut(shortcut) {
-    var mods = {};
-    var ident = '';
-    shortcut.split('|').forEach(function(part) {
-      var partLc = part.toLowerCase();
-      switch (partLc) {
-       case 'alt':
-       case 'ctrl':
-       case 'meta':
-       case 'shift':
-        mods[partLc + 'Key'] = true;
-        break;
-
-       default:
-        if (ident) throw Error('Invalid shortcut');
-        ident = part;
-      }
-    });
-    this.ident_ = ident;
-    this.mods_ = mods;
-  }
-  KeyboardShortcut.prototype = {
-    matchesEvent: function(e) {
-      if (e.key == this.ident_) {
-        var mods = this.mods_;
-        return [ 'altKey', 'ctrlKey', 'metaKey', 'shiftKey' ].every(function(k) {
-          return e[k] == !!mods[k];
-        });
-      }
-      return false;
-    }
-  };
-  var Command = cr.ui.define('command');
-  Command.prototype = {
-    __proto__: HTMLElement.prototype,
-    decorate: function() {
-      CommandManager.init(assert(this.ownerDocument));
-      if (this.hasAttribute('shortcut')) this.shortcut = this.getAttribute('shortcut');
-    },
-    execute: function(opt_element) {
-      if (this.disabled) return;
-      var doc = this.ownerDocument;
-      if (doc.activeElement) {
-        var e = new Event('command', {
-          bubbles: true
-        });
-        e.command = this;
-        (opt_element || doc.activeElement).dispatchEvent(e);
-      }
-    },
-    canExecuteChange: function(opt_node) {
-      dispatchCanExecuteEvent(this, opt_node || this.ownerDocument.activeElement);
-    },
-    shortcut_: '',
-    get shortcut() {
-      return this.shortcut_;
-    },
-    set shortcut(shortcut) {
-      var oldShortcut = this.shortcut_;
-      if (shortcut !== oldShortcut) {
-        this.keyboardShortcuts_ = shortcut.split(/\s+/).map(function(shortcut) {
-          return new KeyboardShortcut(shortcut);
-        });
-        this.shortcut_ = shortcut;
-        cr.dispatchPropertyChange(this, 'shortcut', this.shortcut_, oldShortcut);
-      }
-    },
-    matchesEvent: function(e) {
-      if (!this.keyboardShortcuts_) return false;
-      return this.keyboardShortcuts_.some(function(keyboardShortcut) {
-        return keyboardShortcut.matchesEvent(e);
-      });
-    }
-  };
-  cr.defineProperty(Command, 'label', cr.PropertyKind.ATTR);
-  cr.defineProperty(Command, 'disabled', cr.PropertyKind.BOOL_ATTR);
-  cr.defineProperty(Command, 'hidden', cr.PropertyKind.BOOL_ATTR);
-  cr.defineProperty(Command, 'checked', cr.PropertyKind.BOOL_ATTR);
-  cr.defineProperty(Command, 'hideShortcutText', cr.PropertyKind.BOOL_ATTR);
-  function dispatchCanExecuteEvent(command, target) {
-    var e = new CanExecuteEvent(command);
-    target.dispatchEvent(e);
-    command.disabled = !e.canExecute;
-  }
-  var commandManagers = {};
-  function CommandManager(doc) {
-    doc.addEventListener('focus', this.handleFocus_.bind(this), true);
-    doc.addEventListener('keydown', this.handleKeyDown_.bind(this), false);
-  }
-  CommandManager.init = function(doc) {
-    var uid = cr.getUid(doc);
-    if (!(uid in commandManagers)) {
-      commandManagers[uid] = new CommandManager(doc);
-    }
-  };
-  CommandManager.prototype = {
-    handleFocus_: function(e) {
-      var target = e.target;
-      if (target.menu || target.command) return;
-      var commands = Array.prototype.slice.call(target.ownerDocument.querySelectorAll('command'));
-      commands.forEach(function(command) {
-        dispatchCanExecuteEvent(command, target);
-      });
-    },
-    handleKeyDown_: function(e) {
-      var target = e.target;
-      var commands = Array.prototype.slice.call(target.ownerDocument.querySelectorAll('command'));
-      for (var i = 0, command; command = commands[i]; i++) {
-        if (command.matchesEvent(e)) {
-          command.canExecuteChange();
-          if (!command.disabled) {
-            e.preventDefault();
-            e.stopPropagation();
-            command.execute();
-            return;
-          }
-        }
-      }
-    }
-  };
-  function CanExecuteEvent(command) {
-    var e = new Event('canExecute', {
-      bubbles: true,
-      cancelable: true
-    });
-    e.__proto__ = CanExecuteEvent.prototype;
-    e.command = command;
-    return e;
-  }
-  CanExecuteEvent.prototype = {
-    __proto__: Event.prototype,
-    command: null,
-    canExecute_: false,
-    get canExecute() {
-      return this.canExecute_;
-    },
-    set canExecute(canExecute) {
-      this.canExecute_ = !!canExecute;
-      this.stopPropagation();
-      this.preventDefault();
-    }
-  };
-  return {
-    Command: Command,
-    CanExecuteEvent: CanExecuteEvent
-  };
-});
-
+cr.define("cr.ui",function(){function KeyboardShortcut(shortcut){var mods={};var ident="";shortcut.split("|").forEach(function(part){var partLc=part.toLowerCase();switch(partLc){case"alt":case"ctrl":case"meta":case"shift":mods[partLc+"Key"]=true;break;default:if(ident)throw Error("Invalid shortcut");ident=part}});this.ident_=ident;this.mods_=mods}KeyboardShortcut.prototype={matchesEvent:function(e){if(e.key==this.ident_){var mods=this.mods_;return["altKey","ctrlKey","metaKey","shiftKey"].every(function(k){return e[k]==!!mods[k]})}return false}};var Command=cr.ui.define("command");Command.prototype={__proto__:HTMLElement.prototype,decorate:function(){CommandManager.init(assert(this.ownerDocument));if(this.hasAttribute("shortcut"))this.shortcut=this.getAttribute("shortcut")},execute:function(opt_element){if(this.disabled)return;var doc=this.ownerDocument;if(doc.activeElement){var e=new Event("command",{bubbles:true});e.command=this;(opt_element||doc.activeElement).dispatchEvent(e)}},canExecuteChange:function(opt_node){dispatchCanExecuteEvent(this,opt_node||this.ownerDocument.activeElement)},shortcut_:"",get shortcut(){return this.shortcut_},set shortcut(shortcut){var oldShortcut=this.shortcut_;if(shortcut!==oldShortcut){this.keyboardShortcuts_=shortcut.split(/\s+/).map(function(shortcut){return new KeyboardShortcut(shortcut)});this.shortcut_=shortcut;cr.dispatchPropertyChange(this,"shortcut",this.shortcut_,oldShortcut)}},matchesEvent:function(e){if(!this.keyboardShortcuts_)return false;return this.keyboardShortcuts_.some(function(keyboardShortcut){return keyboardShortcut.matchesEvent(e)})}};cr.defineProperty(Command,"label",cr.PropertyKind.ATTR);cr.defineProperty(Command,"disabled",cr.PropertyKind.BOOL_ATTR);cr.defineProperty(Command,"hidden",cr.PropertyKind.BOOL_ATTR);cr.defineProperty(Command,"checked",cr.PropertyKind.BOOL_ATTR);cr.defineProperty(Command,"hideShortcutText",cr.PropertyKind.BOOL_ATTR);function dispatchCanExecuteEvent(command,target){var e=new CanExecuteEvent(command);target.dispatchEvent(e);command.disabled=!e.canExecute}var commandManagers={};function CommandManager(doc){doc.addEventListener("focus",this.handleFocus_.bind(this),true);doc.addEventListener("keydown",this.handleKeyDown_.bind(this),false)}CommandManager.init=function(doc){var uid=cr.getUid(doc);if(!(uid in commandManagers)){commandManagers[uid]=new CommandManager(doc)}};CommandManager.prototype={handleFocus_:function(e){var target=e.target;if(target.menu||target.command)return;var commands=Array.prototype.slice.call(target.ownerDocument.querySelectorAll("command"));commands.forEach(function(command){dispatchCanExecuteEvent(command,target)})},handleKeyDown_:function(e){var target=e.target;var commands=Array.prototype.slice.call(target.ownerDocument.querySelectorAll("command"));for(var i=0,command;command=commands[i];i++){if(command.matchesEvent(e)){command.canExecuteChange();if(!command.disabled){e.preventDefault();e.stopPropagation();command.execute();return}}}}};function CanExecuteEvent(command){var e=new Event("canExecute",{bubbles:true,cancelable:true});e.__proto__=CanExecuteEvent.prototype;e.command=command;return e}CanExecuteEvent.prototype={__proto__:Event.prototype,command:null,canExecute_:false,get canExecute(){return this.canExecute_},set canExecute(canExecute){this.canExecute_=!!canExecute;this.stopPropagation();this.preventDefault()}};return{Command:Command,CanExecuteEvent:CanExecuteEvent}});
 // 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.
-function $(id) {
-  var el = document.getElementById(id);
-  return el ? assertInstanceof(el, HTMLElement) : null;
-}
-
-function getSVGElement(id) {
-  var el = document.getElementById(id);
-  return el ? assertInstanceof(el, Element) : null;
-}
-
-function announceAccessibleMessage(msg) {
-  var element = document.createElement('div');
-  element.setAttribute('aria-live', 'polite');
-  element.style.position = 'relative';
-  element.style.left = '-9999px';
-  element.style.height = '0px';
-  element.innerText = msg;
-  document.body.appendChild(element);
-  window.setTimeout(function() {
-    document.body.removeChild(element);
-  }, 0);
-}
-
-function url(s) {
-  var s2 = s.replace(/(\(|\)|\,|\s|\'|\"|\\)/g, '\\$1');
-  if (/\\\\$/.test(s2)) {
-    s2 += ' ';
-  }
-  return 'url("' + s2 + '")';
-}
-
-function parseQueryParams(location) {
-  var params = {};
-  var query = unescape(location.search.substring(1));
-  var vars = query.split('&');
-  for (var i = 0; i < vars.length; i++) {
-    var pair = vars[i].split('=');
-    params[pair[0]] = pair[1];
-  }
-  return params;
-}
-
-function setQueryParam(location, key, value) {
-  var query = parseQueryParams(location);
-  query[encodeURIComponent(key)] = encodeURIComponent(value);
-  var newQuery = '';
-  for (var q in query) {
-    newQuery += (newQuery ? '&' : '?') + q + '=' + query[q];
-  }
-  return location.origin + location.pathname + newQuery + location.hash;
-}
-
-function findAncestorByClass(el, className) {
-  return findAncestor(el, function(el) {
-    return el.classList && el.classList.contains(className);
-  });
-}
-
-function findAncestor(node, predicate) {
-  var last = false;
-  while (node != null && !(last = predicate(node))) {
-    node = node.parentNode;
-  }
-  return last ? node : null;
-}
-
-function swapDomNodes(a, b) {
-  var afterA = a.nextSibling;
-  if (afterA == b) {
-    swapDomNodes(b, a);
-    return;
-  }
-  var aParent = a.parentNode;
-  b.parentNode.replaceChild(a, b);
-  aParent.insertBefore(b, afterA);
-}
-
-function disableTextSelectAndDrag(opt_allowSelectStart, opt_allowDragStart) {
-  document.onselectstart = function(e) {
-    if (!(opt_allowSelectStart && opt_allowSelectStart.call(this, e))) e.preventDefault();
-  };
-  document.ondragstart = function(e) {
-    if (!(opt_allowDragStart && opt_allowDragStart.call(this, e))) e.preventDefault();
-  };
-}
-
-function preventDefaultOnPoundLinkClicks() {
-  document.addEventListener('click', function(e) {
-    var anchor = findAncestor(e.target, function(el) {
-      return el.tagName == 'A';
-    });
-    if (anchor && anchor.getAttribute('href') == '#') e.preventDefault();
-  });
-}
-
-function isRTL() {
-  return document.documentElement.dir == 'rtl';
-}
-
-function getRequiredElement(id) {
-  return assertInstanceof($(id), HTMLElement, 'Missing required element: ' + id);
-}
-
-function queryRequiredElement(selectors, opt_context) {
-  var element = (opt_context || document).querySelector(selectors);
-  return assertInstanceof(element, HTMLElement, 'Missing required element: ' + selectors);
-}
-
-[ 'click', 'auxclick' ].forEach(function(eventName) {
-  document.addEventListener(eventName, function(e) {
-    if (e.button > 1) return;
-    if (e.defaultPrevented) return;
-    var eventPath = e.path;
-    var anchor = null;
-    if (eventPath) {
-      for (var i = 0; i < eventPath.length; i++) {
-        var element = eventPath[i];
-        if (element.tagName === 'A' && element.href) {
-          anchor = element;
-          break;
-        }
-      }
-    }
-    var el = e.target;
-    if (!anchor && el.nodeType == Node.ELEMENT_NODE && el.webkitMatchesSelector('A, A *')) {
-      while (el.tagName != 'A') {
-        el = el.parentElement;
-      }
-      anchor = el;
-    }
-    if (!anchor) return;
-    anchor = anchor;
-    if ((anchor.protocol == 'file:' || anchor.protocol == 'about:') && (e.button == 0 || e.button == 1)) {
-      chrome.send('navigateToUrl', [ anchor.href, anchor.target, e.button, e.altKey, e.ctrlKey, e.metaKey, e.shiftKey ]);
-      e.preventDefault();
-    }
-  });
-});
-
-function appendParam(url, key, value) {
-  var param = encodeURIComponent(key) + '=' + encodeURIComponent(value);
-  if (url.indexOf('?') == -1) return url + '?' + param;
-  return url + '&' + param;
-}
-
-function createElementWithClassName(type, className) {
-  var elm = document.createElement(type);
-  elm.className = className;
-  return elm;
-}
-
-function ensureTransitionEndEvent(el, opt_timeOut) {
-  if (opt_timeOut === undefined) {
-    var style = getComputedStyle(el);
-    opt_timeOut = parseFloat(style.transitionDuration) * 1e3;
-    opt_timeOut += 50;
-  }
-  var fired = false;
-  el.addEventListener('webkitTransitionEnd', function f(e) {
-    el.removeEventListener('webkitTransitionEnd', f);
-    fired = true;
-  });
-  window.setTimeout(function() {
-    if (!fired) cr.dispatchSimpleEvent(el, 'webkitTransitionEnd', true);
-  }, opt_timeOut);
-}
-
-function scrollTopForDocument(doc) {
-  return doc.documentElement.scrollTop || doc.body.scrollTop;
-}
-
-function setScrollTopForDocument(doc, value) {
-  doc.documentElement.scrollTop = doc.body.scrollTop = value;
-}
-
-function scrollLeftForDocument(doc) {
-  return doc.documentElement.scrollLeft || doc.body.scrollLeft;
-}
-
-function setScrollLeftForDocument(doc, value) {
-  doc.documentElement.scrollLeft = doc.body.scrollLeft = value;
-}
-
-function HTMLEscape(original) {
-  return original.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#39;');
-}
-
-function elide(original, maxLength) {
-  if (original.length <= maxLength) return original;
-  return original.substring(0, maxLength - 1) + '…';
-}
-
-function quoteString(str) {
-  return str.replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, '\\$1');
-}
-
-function listenOnce(target, eventNames, callback) {
-  if (!Array.isArray(eventNames)) eventNames = eventNames.split(/ +/);
-  var removeAllAndCallCallback = function(event) {
-    eventNames.forEach(function(eventName) {
-      target.removeEventListener(eventName, removeAllAndCallCallback, false);
-    });
-    return callback(event);
-  };
-  eventNames.forEach(function(eventName) {
-    target.addEventListener(eventName, removeAllAndCallCallback, false);
-  });
-}
-
+function $(id){var el=document.getElementById(id);return el?assertInstanceof(el,HTMLElement):null}function getSVGElement(id){var el=document.getElementById(id);return el?assertInstanceof(el,Element):null}function announceAccessibleMessage(msg){var element=document.createElement("div");element.setAttribute("aria-live","polite");element.style.position="relative";element.style.left="-9999px";element.style.height="0px";element.innerText=msg;document.body.appendChild(element);window.setTimeout(function(){document.body.removeChild(element)},0)}function url(s){var s2=s.replace(/(\(|\)|\,|\s|\'|\"|\\)/g,"\\$1");if(/\\\\$/.test(s2)){s2+=" "}return'url("'+s2+'")'}function parseQueryParams(location){var params={};var query=unescape(location.search.substring(1));var vars=query.split("&");for(var i=0;i<vars.length;i++){var pair=vars[i].split("=");params[pair[0]]=pair[1]}return params}function setQueryParam(location,key,value){var query=parseQueryParams(location);query[encodeURIComponent(key)]=encodeURIComponent(value);var newQuery="";for(var q in query){newQuery+=(newQuery?"&":"?")+q+"="+query[q]}return location.origin+location.pathname+newQuery+location.hash}function findAncestorByClass(el,className){return findAncestor(el,function(el){return el.classList&&el.classList.contains(className)})}function findAncestor(node,predicate){var last=false;while(node!=null&&!(last=predicate(node))){node=node.parentNode}return last?node:null}function swapDomNodes(a,b){var afterA=a.nextSibling;if(afterA==b){swapDomNodes(b,a);return}var aParent=a.parentNode;b.parentNode.replaceChild(a,b);aParent.insertBefore(b,afterA)}function disableTextSelectAndDrag(opt_allowSelectStart,opt_allowDragStart){document.onselectstart=function(e){if(!(opt_allowSelectStart&&opt_allowSelectStart.call(this,e)))e.preventDefault()};document.ondragstart=function(e){if(!(opt_allowDragStart&&opt_allowDragStart.call(this,e)))e.preventDefault()}}function preventDefaultOnPoundLinkClicks(){document.addEventListener("click",function(e){var anchor=findAncestor(e.target,function(el){return el.tagName=="A"});if(anchor&&anchor.getAttribute("href")=="#")e.preventDefault()})}function isRTL(){return document.documentElement.dir=="rtl"}function getRequiredElement(id){return assertInstanceof($(id),HTMLElement,"Missing required element: "+id)}function queryRequiredElement(selectors,opt_context){var element=(opt_context||document).querySelector(selectors);return assertInstanceof(element,HTMLElement,"Missing required element: "+selectors)}["click","auxclick"].forEach(function(eventName){document.addEventListener(eventName,function(e){if(e.button>1)return;if(e.defaultPrevented)return;var eventPath=e.path;var anchor=null;if(eventPath){for(var i=0;i<eventPath.length;i++){var element=eventPath[i];if(element.tagName==="A"&&element.href){anchor=element;break}}}var el=e.target;if(!anchor&&el.nodeType==Node.ELEMENT_NODE&&el.webkitMatchesSelector("A, A *")){while(el.tagName!="A"){el=el.parentElement}anchor=el}if(!anchor)return;anchor=anchor;if((anchor.protocol=="file:"||anchor.protocol=="about:")&&(e.button==0||e.button==1)){chrome.send("navigateToUrl",[anchor.href,anchor.target,e.button,e.altKey,e.ctrlKey,e.metaKey,e.shiftKey]);e.preventDefault()}})});function appendParam(url,key,value){var param=encodeURIComponent(key)+"="+encodeURIComponent(value);if(url.indexOf("?")==-1)return url+"?"+param;return url+"&"+param}function createElementWithClassName(type,className){var elm=document.createElement(type);elm.className=className;return elm}function ensureTransitionEndEvent(el,opt_timeOut){if(opt_timeOut===undefined){var style=getComputedStyle(el);opt_timeOut=parseFloat(style.transitionDuration)*1e3;opt_timeOut+=50}var fired=false;el.addEventListener("webkitTransitionEnd",function f(e){el.removeEventListener("webkitTransitionEnd",f);fired=true});window.setTimeout(function(){if(!fired)cr.dispatchSimpleEvent(el,"webkitTransitionEnd",true)},opt_timeOut)}function scrollTopForDocument(doc){return doc.documentElement.scrollTop||doc.body.scrollTop}function setScrollTopForDocument(doc,value){doc.documentElement.scrollTop=doc.body.scrollTop=value}function scrollLeftForDocument(doc){return doc.documentElement.scrollLeft||doc.body.scrollLeft}function setScrollLeftForDocument(doc,value){doc.documentElement.scrollLeft=doc.body.scrollLeft=value}function HTMLEscape(original){return original.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function elide(original,maxLength){if(original.length<=maxLength)return original;return original.substring(0,maxLength-1)+"…"}function quoteString(str){return str.replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g,"\\$1")}function listenOnce(target,eventNames,callback){if(!Array.isArray(eventNames))eventNames=eventNames.split(/ +/);var removeAllAndCallCallback=function(event){eventNames.forEach(function(eventName){target.removeEventListener(eventName,removeAllAndCallCallback,false)});return callback(event)};eventNames.forEach(function(eventName){target.addEventListener(eventName,removeAllAndCallCallback,false)})}
 // <if expr="is_ios">
-if (!('key' in KeyboardEvent.prototype)) {
-  Object.defineProperty(KeyboardEvent.prototype, 'key', {
-    get: function() {
-      if (this.keyCode >= 48 && this.keyCode <= 57) return String.fromCharCode(this.keyCode);
-      if (this.keyCode >= 65 && this.keyCode <= 90) {
-        var result = String.fromCharCode(this.keyCode).toLowerCase();
-        if (this.shiftKey) result = result.toUpperCase();
-        return result;
-      }
-      switch (this.keyCode) {
-       case 8:
-        return 'Backspace';
-
-       case 9:
-        return 'Tab';
-
-       case 13:
-        return 'Enter';
-
-       case 16:
-        return 'Shift';
-
-       case 17:
-        return 'Control';
-
-       case 18:
-        return 'Alt';
-
-       case 27:
-        return 'Escape';
-
-       case 32:
-        return ' ';
-
-       case 33:
-        return 'PageUp';
-
-       case 34:
-        return 'PageDown';
-
-       case 35:
-        return 'End';
-
-       case 36:
-        return 'Home';
-
-       case 37:
-        return 'ArrowLeft';
-
-       case 38:
-        return 'ArrowUp';
-
-       case 39:
-        return 'ArrowRight';
-
-       case 40:
-        return 'ArrowDown';
-
-       case 45:
-        return 'Insert';
-
-       case 46:
-        return 'Delete';
-
-       case 91:
-        return 'Meta';
-
-       case 112:
-        return 'F1';
-
-       case 113:
-        return 'F2';
-
-       case 114:
-        return 'F3';
-
-       case 115:
-        return 'F4';
-
-       case 116:
-        return 'F5';
-
-       case 117:
-        return 'F6';
-
-       case 118:
-        return 'F7';
-
-       case 119:
-        return 'F8';
-
-       case 120:
-        return 'F9';
-
-       case 121:
-        return 'F10';
-
-       case 122:
-        return 'F11';
-
-       case 123:
-        return 'F12';
-
-       case 187:
-        return '=';
-
-       case 189:
-        return '-';
-
-       case 219:
-        return '[';
-
-       case 221:
-        return ']';
-      }
-      return 'Unidentified';
-    }
-  });
-} else {
-  window.console.log("KeyboardEvent.Key polyfill not required");
-}
-
+if(!("key"in KeyboardEvent.prototype)){Object.defineProperty(KeyboardEvent.prototype,"key",{get:function(){if(this.keyCode>=48&&this.keyCode<=57)return String.fromCharCode(this.keyCode);if(this.keyCode>=65&&this.keyCode<=90){var result=String.fromCharCode(this.keyCode).toLowerCase();if(this.shiftKey)result=result.toUpperCase();return result}switch(this.keyCode){case 8:return"Backspace";case 9:return"Tab";case 13:return"Enter";case 16:return"Shift";case 17:return"Control";case 18:return"Alt";case 27:return"Escape";case 32:return" ";case 33:return"PageUp";case 34:return"PageDown";case 35:return"End";case 36:return"Home";case 37:return"ArrowLeft";case 38:return"ArrowUp";case 39:return"ArrowRight";case 40:return"ArrowDown";case 45:return"Insert";case 46:return"Delete";case 91:return"Meta";case 112:return"F1";case 113:return"F2";case 114:return"F3";case 115:return"F4";case 116:return"F5";case 117:return"F6";case 118:return"F7";case 119:return"F8";case 120:return"F9";case 121:return"F10";case 122:return"F11";case 123:return"F12";case 187:return"=";case 189:return"-";case 219:return"[";case 221:return"]"}return"Unidentified"}})}else{window.console.log("KeyboardEvent.Key polyfill not required")}
 // </if>  /* is_ios */
-Polymer.IronResizableBehavior = {
-  properties: {
-    _parentResizable: {
-      type: Object,
-      observer: '_parentResizableChanged'
-    },
-    _notifyingDescendant: {
-      type: Boolean,
-      value: false
-    }
-  },
-  listeners: {
-    'iron-request-resize-notifications': '_onIronRequestResizeNotifications'
-  },
-  created: function() {
-    this._interestedResizables = [];
-    this._boundNotifyResize = this.notifyResize.bind(this);
-  },
-  attached: function() {
-    this.fire('iron-request-resize-notifications', null, {
-      node: this,
-      bubbles: true,
-      cancelable: true
-    });
-    if (!this._parentResizable) {
-      window.addEventListener('resize', this._boundNotifyResize);
-      this.notifyResize();
-    }
-  },
-  detached: function() {
-    if (this._parentResizable) {
-      this._parentResizable.stopResizeNotificationsFor(this);
-    } else {
-      window.removeEventListener('resize', this._boundNotifyResize);
-    }
-    this._parentResizable = null;
-  },
-  notifyResize: function() {
-    if (!this.isAttached) {
-      return;
-    }
-    this._interestedResizables.forEach(function(resizable) {
-      if (this.resizerShouldNotify(resizable)) {
-        this._notifyDescendant(resizable);
-      }
-    }, this);
-    this._fireResize();
-  },
-  assignParentResizable: function(parentResizable) {
-    this._parentResizable = parentResizable;
-  },
-  stopResizeNotificationsFor: function(target) {
-    var index = this._interestedResizables.indexOf(target);
-    if (index > -1) {
-      this._interestedResizables.splice(index, 1);
-      this.unlisten(target, 'iron-resize', '_onDescendantIronResize');
-    }
-  },
-  resizerShouldNotify: function(element) {
-    return true;
-  },
-  _onDescendantIronResize: function(event) {
-    if (this._notifyingDescendant) {
-      event.stopPropagation();
-      return;
-    }
-    if (!Polymer.Settings.useShadow) {
-      this._fireResize();
-    }
-  },
-  _fireResize: function() {
-    this.fire('iron-resize', null, {
-      node: this,
-      bubbles: false
-    });
-  },
-  _onIronRequestResizeNotifications: function(event) {
-    var target = event.path ? event.path[0] : event.target;
-    if (target === this) {
-      return;
-    }
-    if (this._interestedResizables.indexOf(target) === -1) {
-      this._interestedResizables.push(target);
-      this.listen(target, 'iron-resize', '_onDescendantIronResize');
-    }
-    target.assignParentResizable(this);
-    this._notifyDescendant(target);
-    event.stopPropagation();
-  },
-  _parentResizableChanged: function(parentResizable) {
-    if (parentResizable) {
-      window.removeEventListener('resize', this._boundNotifyResize);
-    }
-  },
-  _notifyDescendant: function(descendant) {
-    if (!this.isAttached) {
-      return;
-    }
-    this._notifyingDescendant = true;
-    descendant.notifyResize();
-    this._notifyingDescendant = false;
-  }
-};
+Polymer.IronResizableBehavior={properties:{_parentResizable:{type:Object,observer:"_parentResizableChanged"},_notifyingDescendant:{type:Boolean,value:false}},listeners:{"iron-request-resize-notifications":"_onIronRequestResizeNotifications"},created:function(){this._interestedResizables=[];this._boundNotifyResize=this.notifyResize.bind(this)},attached:function(){this.fire("iron-request-resize-notifications",null,{node:this,bubbles:true,cancelable:true});if(!this._parentResizable){window.addEventListener("resize",this._boundNotifyResize);this.notifyResize()}},detached:function(){if(this._parentResizable){this._parentResizable.stopResizeNotificationsFor(this)}else{window.removeEventListener("resize",this._boundNotifyResize)}this._parentResizable=null},notifyResize:function(){if(!this.isAttached){return}this._interestedResizables.forEach(function(resizable){if(this.resizerShouldNotify(resizable)){this._notifyDescendant(resizable)}},this);this._fireResize()},assignParentResizable:function(parentResizable){this._parentResizable=parentResizable},stopResizeNotificationsFor:function(target){var index=this._interestedResizables.indexOf(target);if(index>-1){this._interestedResizables.splice(index,1);this.unlisten(target,"iron-resize","_onDescendantIronResize")}},resizerShouldNotify:function(element){return true},_onDescendantIronResize:function(event){if(this._notifyingDescendant){event.stopPropagation();return}if(!Polymer.Settings.useShadow){this._fireResize()}},_fireResize:function(){this.fire("iron-resize",null,{node:this,bubbles:false})},_onIronRequestResizeNotifications:function(event){var target=event.path?event.path[0]:event.target;if(target===this){return}if(this._interestedResizables.indexOf(target)===-1){this._interestedResizables.push(target);this.listen(target,"iron-resize","_onDescendantIronResize")}target.assignParentResizable(this);this._notifyDescendant(target);event.stopPropagation()},_parentResizableChanged:function(parentResizable){if(parentResizable){window.removeEventListener("resize",this._boundNotifyResize)}},_notifyDescendant:function(descendant){if(!this.isAttached){return}this._notifyingDescendant=true;descendant.notifyResize();this._notifyingDescendant=false}};(function(){"use strict";var KEY_IDENTIFIER={"U+0008":"backspace","U+0009":"tab","U+001B":"esc","U+0020":"space","U+007F":"del"};var KEY_CODE={8:"backspace",9:"tab",13:"enter",27:"esc",33:"pageup",34:"pagedown",35:"end",36:"home",32:"space",37:"left",38:"up",39:"right",40:"down",46:"del",106:"*"};var MODIFIER_KEYS={shift:"shiftKey",ctrl:"ctrlKey",alt:"altKey",meta:"metaKey"};var KEY_CHAR=/[a-z0-9*]/;var IDENT_CHAR=/U\+/;var ARROW_KEY=/^arrow/;var SPACE_KEY=/^space(bar)?/;var ESC_KEY=/^escape$/;function transformKey(key,noSpecialChars){var validKey="";if(key){var lKey=key.toLowerCase();if(lKey===" "||SPACE_KEY.test(lKey)){validKey="space"}else if(ESC_KEY.test(lKey)){validKey="esc"}else if(lKey.length==1){if(!noSpecialChars||KEY_CHAR.test(lKey)){validKey=lKey}}else if(ARROW_KEY.test(lKey)){validKey=lKey.replace("arrow","")}else if(lKey=="multiply"){validKey="*"}else{validKey=lKey}}return validKey}function transformKeyIdentifier(keyIdent){var validKey="";if(keyIdent){if(keyIdent in KEY_IDENTIFIER){validKey=KEY_IDENTIFIER[keyIdent]}else if(IDENT_CHAR.test(keyIdent)){keyIdent=parseInt(keyIdent.replace("U+","0x"),16);validKey=String.fromCharCode(keyIdent).toLowerCase()}else{validKey=keyIdent.toLowerCase()}}return validKey}function transformKeyCode(keyCode){var validKey="";if(Number(keyCode)){if(keyCode>=65&&keyCode<=90){validKey=String.fromCharCode(32+keyCode)}else if(keyCode>=112&&keyCode<=123){validKey="f"+(keyCode-112)}else if(keyCode>=48&&keyCode<=57){validKey=String(keyCode-48)}else if(keyCode>=96&&keyCode<=105){validKey=String(keyCode-96)}else{validKey=KEY_CODE[keyCode]}}return validKey}function normalizedKeyForEvent(keyEvent,noSpecialChars){if(keyEvent.key){return transformKey(keyEvent.key,noSpecialChars)}if(keyEvent.detail&&keyEvent.detail.key){return transformKey(keyEvent.detail.key,noSpecialChars)}return transformKeyIdentifier(keyEvent.keyIdentifier)||transformKeyCode(keyEvent.keyCode)||""}function keyComboMatchesEvent(keyCombo,event){var keyEvent=normalizedKeyForEvent(event,keyCombo.hasModifiers);return keyEvent===keyCombo.key&&(!keyCombo.hasModifiers||!!event.shiftKey===!!keyCombo.shiftKey&&!!event.ctrlKey===!!keyCombo.ctrlKey&&!!event.altKey===!!keyCombo.altKey&&!!event.metaKey===!!keyCombo.metaKey)}function parseKeyComboString(keyComboString){if(keyComboString.length===1){return{combo:keyComboString,key:keyComboString,event:"keydown"}}return keyComboString.split("+").reduce(function(parsedKeyCombo,keyComboPart){var eventParts=keyComboPart.split(":");var keyName=eventParts[0];var event=eventParts[1];if(keyName in MODIFIER_KEYS){parsedKeyCombo[MODIFIER_KEYS[keyName]]=true;parsedKeyCombo.hasModifiers=true}else{parsedKeyCombo.key=keyName;parsedKeyCombo.event=event||"keydown"}return parsedKeyCombo},{combo:keyComboString.split(":").shift()})}function parseEventString(eventString){return eventString.trim().split(" ").map(function(keyComboString){return parseKeyComboString(keyComboString)})}Polymer.IronA11yKeysBehavior={properties:{keyEventTarget:{type:Object,value:function(){return this}},stopKeyboardEventPropagation:{type:Boolean,value:false},_boundKeyHandlers:{type:Array,value:function(){return[]}},_imperativeKeyBindings:{type:Object,value:function(){return{}}}},observers:["_resetKeyEventListeners(keyEventTarget, _boundKeyHandlers)"],keyBindings:{},registered:function(){this._prepKeyBindings()},attached:function(){this._listenKeyEventListeners()},detached:function(){this._unlistenKeyEventListeners()},addOwnKeyBinding:function(eventString,handlerName){this._imperativeKeyBindings[eventString]=handlerName;this._prepKeyBindings();this._resetKeyEventListeners()},removeOwnKeyBindings:function(){this._imperativeKeyBindings={};this._prepKeyBindings();this._resetKeyEventListeners()},keyboardEventMatchesKeys:function(event,eventString){var keyCombos=parseEventString(eventString);for(var i=0;i<keyCombos.length;++i){if(keyComboMatchesEvent(keyCombos[i],event)){return true}}return false},_collectKeyBindings:function(){var keyBindings=this.behaviors.map(function(behavior){return behavior.keyBindings});if(keyBindings.indexOf(this.keyBindings)===-1){keyBindings.push(this.keyBindings)}return keyBindings},_prepKeyBindings:function(){this._keyBindings={};this._collectKeyBindings().forEach(function(keyBindings){for(var eventString in keyBindings){this._addKeyBinding(eventString,keyBindings[eventString])}},this);for(var eventString in this._imperativeKeyBindings){this._addKeyBinding(eventString,this._imperativeKeyBindings[eventString])}for(var eventName in this._keyBindings){this._keyBindings[eventName].sort(function(kb1,kb2){var b1=kb1[0].hasModifiers;var b2=kb2[0].hasModifiers;return b1===b2?0:b1?-1:1})}},_addKeyBinding:function(eventString,handlerName){parseEventString(eventString).forEach(function(keyCombo){this._keyBindings[keyCombo.event]=this._keyBindings[keyCombo.event]||[];this._keyBindings[keyCombo.event].push([keyCombo,handlerName])},this)},_resetKeyEventListeners:function(){this._unlistenKeyEventListeners();if(this.isAttached){this._listenKeyEventListeners()}},_listenKeyEventListeners:function(){if(!this.keyEventTarget){return}Object.keys(this._keyBindings).forEach(function(eventName){var keyBindings=this._keyBindings[eventName];var boundKeyHandler=this._onKeyBindingEvent.bind(this,keyBindings);this._boundKeyHandlers.push([this.keyEventTarget,eventName,boundKeyHandler]);this.keyEventTarget.addEventListener(eventName,boundKeyHandler)},this)},_unlistenKeyEventListeners:function(){var keyHandlerTuple;var keyEventTarget;var eventName;var boundKeyHandler;while(this._boundKeyHandlers.length){keyHandlerTuple=this._boundKeyHandlers.pop();keyEventTarget=keyHandlerTuple[0];eventName=keyHandlerTuple[1];boundKeyHandler=keyHandlerTuple[2];keyEventTarget.removeEventListener(eventName,boundKeyHandler)}},_onKeyBindingEvent:function(keyBindings,event){if(this.stopKeyboardEventPropagation){event.stopPropagation()}if(event.defaultPrevented){return}for(var i=0;i<keyBindings.length;i++){var keyCombo=keyBindings[i][0];var handlerName=keyBindings[i][1];if(keyComboMatchesEvent(keyCombo,event)){this._triggerKeyHandler(keyCombo,handlerName,event);if(event.defaultPrevented){return}}}},_triggerKeyHandler:function(keyCombo,handlerName,keyboardEvent){var detail=Object.create(keyCombo);detail.keyboardEvent=keyboardEvent;var event=new CustomEvent(keyCombo.event,{detail:detail,cancelable:true});this[handlerName].call(this,event);if(event.defaultPrevented){keyboardEvent.preventDefault()}}}})();Polymer.IronScrollTargetBehavior={properties:{scrollTarget:{type:HTMLElement,value:function(){return this._defaultScrollTarget}}},observers:["_scrollTargetChanged(scrollTarget, isAttached)"],_scrollTargetChanged:function(scrollTarget,isAttached){var eventTarget;if(this._oldScrollTarget){eventTarget=this._oldScrollTarget===this._doc?window:this._oldScrollTarget;eventTarget.removeEventListener("scroll",this._boundScrollHandler);this._oldScrollTarget=null}if(!isAttached){return}if(scrollTarget==="document"){this.scrollTarget=this._doc}else if(typeof scrollTarget==="string"){this.scrollTarget=this.domHost?this.domHost.$[scrollTarget]:Polymer.dom(this.ownerDocument).querySelector("#"+scrollTarget)}else if(this._isValidScrollTarget()){eventTarget=scrollTarget===this._doc?window:scrollTarget;this._boundScrollHandler=this._boundScrollHandler||this._scrollHandler.bind(this);this._oldScrollTarget=scrollTarget;eventTarget.addEventListener("scroll",this._boundScrollHandler)}},_scrollHandler:function scrollHandler(){},get _defaultScrollTarget(){return this._doc},get _doc(){return this.ownerDocument.documentElement},get _scrollTop(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.pageYOffset:this.scrollTarget.scrollTop}return 0},get _scrollLeft(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.pageXOffset:this.scrollTarget.scrollLeft}return 0},set _scrollTop(top){if(this.scrollTarget===this._doc){window.scrollTo(window.pageXOffset,top)}else if(this._isValidScrollTarget()){this.scrollTarget.scrollTop=top}},set _scrollLeft(left){if(this.scrollTarget===this._doc){window.scrollTo(left,window.pageYOffset)}else if(this._isValidScrollTarget()){this.scrollTarget.scrollLeft=left}},scroll:function(left,top){if(this.scrollTarget===this._doc){window.scrollTo(left,top)}else if(this._isValidScrollTarget()){this.scrollTarget.scrollLeft=left;this.scrollTarget.scrollTop=top}},get _scrollTargetWidth(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.innerWidth:this.scrollTarget.offsetWidth}return 0},get _scrollTargetHeight(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.innerHeight:this.scrollTarget.offsetHeight}return 0},_isValidScrollTarget:function(){return this.scrollTarget instanceof HTMLElement}};(function(){var IOS=navigator.userAgent.match(/iP(?:hone|ad;(?: U;)? CPU) OS (\d+)/);var IOS_TOUCH_SCROLLING=IOS&&IOS[1]>=8;var DEFAULT_PHYSICAL_COUNT=3;var HIDDEN_Y="-10000px";var DEFAULT_GRID_SIZE=200;var SECRET_TABINDEX=-100;Polymer({is:"iron-list",properties:{items:{type:Array},maxPhysicalCount:{type:Number,value:500},as:{type:String,value:"item"},indexAs:{type:String,value:"index"},selectedAs:{type:String,value:"selected"},grid:{type:Boolean,value:false,reflectToAttribute:true},selectionEnabled:{type:Boolean,value:false},selectedItem:{type:Object,notify:true},selectedItems:{type:Object,notify:true},multiSelection:{type:Boolean,value:false}},observers:["_itemsChanged(items.*)","_selectionEnabledChanged(selectionEnabled)","_multiSelectionChanged(multiSelection)","_setOverflow(scrollTarget)"],behaviors:[Polymer.Templatizer,Polymer.IronResizableBehavior,Polymer.IronA11yKeysBehavior,Polymer.IronScrollTargetBehavior],keyBindings:{up:"_didMoveUp",down:"_didMoveDown",enter:"_didEnter"},_ratio:.5,_scrollerPaddingTop:0,_scrollPosition:0,_physicalSize:0,_physicalAverage:0,_physicalAverageCount:0,_physicalTop:0,_virtualCount:0,_physicalIndexForKey:null,_estScrollHeight:0,_scrollHeight:0,_viewportHeight:0,_viewportWidth:0,_physicalItems:null,_physicalSizes:null,_firstVisibleIndexVal:null,_lastVisibleIndexVal:null,_collection:null,_maxPages:3,_focusedItem:null,_focusedIndex:-1,_offscreenFocusedItem:null,_focusBackfillItem:null,_itemsPerRow:1,_itemWidth:0,_rowHeight:0,_templateCost:0,get _physicalBottom(){return this._physicalTop+this._physicalSize},get _scrollBottom(){return this._scrollPosition+this._viewportHeight},get _virtualEnd(){return this._virtualStart+this._physicalCount-1},get _hiddenContentSize(){var size=this.grid?this._physicalRows*this._rowHeight:this._physicalSize;return size-this._viewportHeight},get _maxScrollTop(){return this._estScrollHeight-this._viewportHeight+this._scrollerPaddingTop},_minVirtualStart:0,get _maxVirtualStart(){return Math.max(0,this._virtualCount-this._physicalCount)},_virtualStartVal:0,set _virtualStart(val){this._virtualStartVal=Math.min(this._maxVirtualStart,Math.max(this._minVirtualStart,val))},get _virtualStart(){return this._virtualStartVal||0},_physicalStartVal:0,set _physicalStart(val){this._physicalStartVal=val%this._physicalCount;if(this._physicalStartVal<0){this._physicalStartVal=this._physicalCount+this._physicalStartVal}this._physicalEnd=(this._physicalStart+this._physicalCount-1)%this._physicalCount},get _physicalStart(){return this._physicalStartVal||0},_physicalCountVal:0,set _physicalCount(val){this._physicalCountVal=val;this._physicalEnd=(this._physicalStart+this._physicalCount-1)%this._physicalCount},get _physicalCount(){return this._physicalCountVal},_physicalEnd:0,get _optPhysicalSize(){if(this.grid){return this._estRowsInView*this._rowHeight*this._maxPages}return this._viewportHeight*this._maxPages},get _optPhysicalCount(){return this._estRowsInView*this._itemsPerRow*this._maxPages},get _isVisible(){return Boolean(this.offsetWidth||this.offsetHeight)},get firstVisibleIndex(){if(this._firstVisibleIndexVal===null){var physicalOffset=Math.floor(this._physicalTop+this._scrollerPaddingTop);this._firstVisibleIndexVal=this._iterateItems(function(pidx,vidx){physicalOffset+=this._getPhysicalSizeIncrement(pidx);if(physicalOffset>this._scrollPosition){return this.grid?vidx-vidx%this._itemsPerRow:vidx}if(this.grid&&this._virtualCount-1===vidx){return vidx-vidx%this._itemsPerRow}})||0}return this._firstVisibleIndexVal},get lastVisibleIndex(){if(this._lastVisibleIndexVal===null){if(this.grid){var lastIndex=this.firstVisibleIndex+this._estRowsInView*this._itemsPerRow-1;this._lastVisibleIndexVal=Math.min(this._virtualCount,lastIndex)}else{var physicalOffset=this._physicalTop;this._iterateItems(function(pidx,vidx){if(physicalOffset<this._scrollBottom){this._lastVisibleIndexVal=vidx}else{return true}physicalOffset+=this._getPhysicalSizeIncrement(pidx)})}}return this._lastVisibleIndexVal},get _defaultScrollTarget(){return this},get _virtualRowCount(){return Math.ceil(this._virtualCount/this._itemsPerRow)},get _estRowsInView(){return Math.ceil(this._viewportHeight/this._rowHeight)},get _physicalRows(){return Math.ceil(this._physicalCount/this._itemsPerRow)},ready:function(){this.addEventListener("focus",this._didFocus.bind(this),true)},attached:function(){this.updateViewportBoundaries();if(this._physicalCount===0){this._debounceTemplate(this._render)}this.listen(this,"iron-resize","_resizeHandler")},detached:function(){this.unlisten(this,"iron-resize","_resizeHandler")},_setOverflow:function(scrollTarget){this.style.webkitOverflowScrolling=scrollTarget===this?"touch":"";this.style.overflow=scrollTarget===this?"auto":""},updateViewportBoundaries:function(){this._scrollerPaddingTop=this.scrollTarget===this?0:parseInt(window.getComputedStyle(this)["padding-top"],10);this._viewportHeight=this._scrollTargetHeight;if(this.grid){this._updateGridMetrics()}},_scrollHandler:function(){var scrollTop=Math.max(0,Math.min(this._maxScrollTop,this._scrollTop));var delta=scrollTop-this._scrollPosition;var tileHeight,tileTop,kth,recycledTileSet,scrollBottom,physicalBottom;var ratio=this._ratio;var recycledTiles=0;var hiddenContentSize=this._hiddenContentSize;var currentRatio=ratio;var movingUp=[];this._scrollPosition=scrollTop;this._firstVisibleIndexVal=null;this._lastVisibleIndexVal=null;scrollBottom=this._scrollBottom;physicalBottom=this._physicalBottom;if(Math.abs(delta)>this._physicalSize){this._physicalTop+=delta;recycledTiles=Math.round(delta/this._physicalAverage)}else if(delta<0){var topSpace=scrollTop-this._physicalTop;var virtualStart=this._virtualStart;recycledTileSet=[];kth=this._physicalEnd;currentRatio=topSpace/hiddenContentSize;while(currentRatio<ratio&&recycledTiles<this._physicalCount&&virtualStart-recycledTiles>0&&physicalBottom-this._getPhysicalSizeIncrement(kth)>scrollBottom){tileHeight=this._getPhysicalSizeIncrement(kth);currentRatio+=tileHeight/hiddenContentSize;physicalBottom-=tileHeight;recycledTileSet.push(kth);recycledTiles++;kth=kth===0?this._physicalCount-1:kth-1}movingUp=recycledTileSet;recycledTiles=-recycledTiles}else if(delta>0){var bottomSpace=physicalBottom-scrollBottom;var virtualEnd=this._virtualEnd;var lastVirtualItemIndex=this._virtualCount-1;recycledTileSet=[];kth=this._physicalStart;currentRatio=bottomSpace/hiddenContentSize;while(currentRatio<ratio&&recycledTiles<this._physicalCount&&virtualEnd+recycledTiles<lastVirtualItemIndex&&this._physicalTop+this._getPhysicalSizeIncrement(kth)<scrollTop){tileHeight=this._getPhysicalSizeIncrement(kth);currentRatio+=tileHeight/hiddenContentSize;this._physicalTop+=tileHeight;recycledTileSet.push(kth);recycledTiles++;kth=(kth+1)%this._physicalCount}}if(recycledTiles===0){if(physicalBottom<scrollBottom||this._physicalTop>scrollTop){this._increasePoolIfNeeded()}}else{this._virtualStart=this._virtualStart+recycledTiles;this._physicalStart=this._physicalStart+recycledTiles;this._update(recycledTileSet,movingUp)}},_update:function(itemSet,movingUp){this._manageFocus();this._assignModels(itemSet);this._updateMetrics(itemSet);if(movingUp){while(movingUp.length){var idx=movingUp.pop();this._physicalTop-=this._getPhysicalSizeIncrement(idx)}}this._positionItems();this._updateScrollerSize();this._increasePoolIfNeeded()},_createPool:function(size){var physicalItems=new Array(size);this._ensureTemplatized();for(var i=0;i<size;i++){var inst=this.stamp(null);physicalItems[i]=inst.root.querySelector("*");Polymer.dom(this).appendChild(inst.root)}return physicalItems},_increasePoolIfNeeded:function(){if(this._viewportHeight===0){return false}var self=this;var isClientFull=this._physicalBottom>=this._scrollBottom&&this._physicalTop<=this._scrollPosition;if(this._physicalSize>=this._optPhysicalSize&&isClientFull){return false}var maxPoolSize=Math.round(this._physicalCount*.5);if(!isClientFull){this._debounceTemplate(this._increasePool.bind(this,maxPoolSize));return true}this._yield(function(){self._increasePool(Math.min(maxPoolSize,Math.max(1,Math.round(50/self._templateCost))))});return true},_yield:function(cb){var g=window;var handle=g.requestIdleCallback?g.requestIdleCallback(cb):g.setTimeout(cb,16);Polymer.dom.addDebouncer({complete:function(){g.cancelIdleCallback?g.cancelIdleCallback(handle):g.clearTimeout(handle);cb()}})},_increasePool:function(missingItems){var nextPhysicalCount=Math.min(this._physicalCount+missingItems,this._virtualCount-this._virtualStart,Math.max(this.maxPhysicalCount,DEFAULT_PHYSICAL_COUNT));var prevPhysicalCount=this._physicalCount;var delta=nextPhysicalCount-prevPhysicalCount;var ts=window.performance.now();if(delta<=0){return}[].push.apply(this._physicalItems,this._createPool(delta));[].push.apply(this._physicalSizes,new Array(delta));this._physicalCount=prevPhysicalCount+delta;if(this._physicalStart>this._physicalEnd&&this._isIndexRendered(this._focusedIndex)&&this._getPhysicalIndex(this._focusedIndex)<this._physicalEnd){this._physicalStart=this._physicalStart+delta}this._update();this._templateCost=(window.performance.now()-ts)/delta},_render:function(){if(this.isAttached&&this._isVisible){if(this._physicalCount===0){this._increasePool(DEFAULT_PHYSICAL_COUNT)}else{this._update()}}},_ensureTemplatized:function(){if(!this.ctor){var props={};props.__key__=true;props[this.as]=true;props[this.indexAs]=true;props[this.selectedAs]=true;props.tabIndex=true;this._instanceProps=props;this._userTemplate=Polymer.dom(this).querySelector("template");if(this._userTemplate){this.templatize(this._userTemplate)}else{console.warn("iron-list requires a template to be provided in light-dom")}}},_getStampedChildren:function(){return this._physicalItems},_forwardInstancePath:function(inst,path,value){if(path.indexOf(this.as+".")===0){this.notifyPath("items."+inst.__key__+"."+path.slice(this.as.length+1),value)}},_forwardParentProp:function(prop,value){if(this._physicalItems){this._physicalItems.forEach(function(item){item._templateInstance[prop]=value},this)}},_forwardParentPath:function(path,value){if(this._physicalItems){this._physicalItems.forEach(function(item){item._templateInstance.notifyPath(path,value,true)},this)}},_forwardItemPath:function(path,value){if(!this._physicalIndexForKey){return}var dot=path.indexOf(".");var key=path.substring(0,dot<0?path.length:dot);var idx=this._physicalIndexForKey[key];var offscreenItem=this._offscreenFocusedItem;var el=offscreenItem&&offscreenItem._templateInstance.__key__===key?offscreenItem:this._physicalItems[idx];if(!el||el._templateInstance.__key__!==key){return}if(dot>=0){path=this.as+"."+path.substring(dot+1);el._templateInstance.notifyPath(path,value,true)}else{var currentItem=el._templateInstance[this.as];if(Array.isArray(this.selectedItems)){for(var i=0;i<this.selectedItems.length;i++){if(this.selectedItems[i]===currentItem){this.set("selectedItems."+i,value);break}}}else if(this.selectedItem===currentItem){this.set("selectedItem",value)}el._templateInstance[this.as]=value}},_itemsChanged:function(change){if(change.path==="items"){this._virtualStart=0;this._physicalTop=0;this._virtualCount=this.items?this.items.length:0;this._collection=this.items?Polymer.Collection.get(this.items):null;this._physicalIndexForKey={};this._firstVisibleIndexVal=null;this._lastVisibleIndexVal=null;this._physicalCount=this._physicalCount||0;this._physicalItems=this._physicalItems||[];this._physicalSizes=this._physicalSizes||[];this._physicalStart=0;this._resetScrollPosition(0);this._removeFocusedItem();this._debounceTemplate(this._render)}else if(change.path==="items.splices"){this._adjustVirtualIndex(change.value.indexSplices);this._virtualCount=this.items?this.items.length:0;this._debounceTemplate(this._render)}else{this._forwardItemPath(change.path.split(".").slice(1).join("."),change.value)}},_adjustVirtualIndex:function(splices){splices.forEach(function(splice){splice.removed.forEach(this._removeItem,this);if(splice.index<this._virtualStart){var delta=Math.max(splice.addedCount-splice.removed.length,splice.index-this._virtualStart);this._virtualStart=this._virtualStart+delta;if(this._focusedIndex>=0){this._focusedIndex=this._focusedIndex+delta}}},this)},_removeItem:function(item){this.$.selector.deselect(item);if(this._focusedItem&&this._focusedItem._templateInstance[this.as]===item){this._removeFocusedItem()}},_iterateItems:function(fn,itemSet){var pidx,vidx,rtn,i;if(arguments.length===2&&itemSet){for(i=0;i<itemSet.length;i++){pidx=itemSet[i];vidx=this._computeVidx(pidx);if((rtn=fn.call(this,pidx,vidx))!=null){return rtn}}}else{pidx=this._physicalStart;vidx=this._virtualStart;for(;pidx<this._physicalCount;pidx++,vidx++){if((rtn=fn.call(this,pidx,vidx))!=null){return rtn}}for(pidx=0;pidx<this._physicalStart;pidx++,vidx++){if((rtn=fn.call(this,pidx,vidx))!=null){return rtn}}}},_computeVidx:function(pidx){if(pidx>=this._physicalStart){return this._virtualStart+(pidx-this._physicalStart)}return this._virtualStart+(this._physicalCount-this._physicalStart)+pidx},_assignModels:function(itemSet){this._iterateItems(function(pidx,vidx){var el=this._physicalItems[pidx];var inst=el._templateInstance;var item=this.items&&this.items[vidx];if(item!=null){inst[this.as]=item;inst.__key__=this._collection.getKey(item);inst[this.selectedAs]=this.$.selector.isSelected(item);inst[this.indexAs]=vidx;inst.tabIndex=this._focusedIndex===vidx?0:-1;this._physicalIndexForKey[inst.__key__]=pidx;el.removeAttribute("hidden")}else{inst.__key__=null;el.setAttribute("hidden","")}},itemSet)},_updateMetrics:function(itemSet){Polymer.dom.flush();var newPhysicalSize=0;var oldPhysicalSize=0;var prevAvgCount=this._physicalAverageCount;var prevPhysicalAvg=this._physicalAverage;this._iterateItems(function(pidx,vidx){oldPhysicalSize+=this._physicalSizes[pidx]||0;this._physicalSizes[pidx]=this._physicalItems[pidx].offsetHeight;newPhysicalSize+=this._physicalSizes[pidx];this._physicalAverageCount+=this._physicalSizes[pidx]?1:0},itemSet);this._viewportHeight=this._scrollTargetHeight;if(this.grid){this._updateGridMetrics();this._physicalSize=Math.ceil(this._physicalCount/this._itemsPerRow)*this._rowHeight}else{this._physicalSize=this._physicalSize+newPhysicalSize-oldPhysicalSize}if(this._physicalAverageCount!==prevAvgCount){this._physicalAverage=Math.round((prevPhysicalAvg*prevAvgCount+newPhysicalSize)/this._physicalAverageCount)}},_updateGridMetrics:function(){this._viewportWidth=this.$.items.offsetWidth;this._itemWidth=this._physicalCount>0?this._physicalItems[0].getBoundingClientRect().width:DEFAULT_GRID_SIZE;this._rowHeight=this._physicalCount>0?this._physicalItems[0].offsetHeight:DEFAULT_GRID_SIZE;this._itemsPerRow=this._itemWidth?Math.floor(this._viewportWidth/this._itemWidth):this._itemsPerRow},_positionItems:function(){this._adjustScrollPosition();var y=this._physicalTop;if(this.grid){var totalItemWidth=this._itemsPerRow*this._itemWidth;var rowOffset=(this._viewportWidth-totalItemWidth)/2;this._iterateItems(function(pidx,vidx){var modulus=vidx%this._itemsPerRow;var x=Math.floor(modulus*this._itemWidth+rowOffset);this.translate3d(x+"px",y+"px",0,this._physicalItems[pidx]);if(this._shouldRenderNextRow(vidx)){y+=this._rowHeight}})}else{this._iterateItems(function(pidx,vidx){this.translate3d(0,y+"px",0,this._physicalItems[pidx]);y+=this._physicalSizes[pidx]})}},_getPhysicalSizeIncrement:function(pidx){if(!this.grid){return this._physicalSizes[pidx]}if(this._computeVidx(pidx)%this._itemsPerRow!==this._itemsPerRow-1){return 0}return this._rowHeight},_shouldRenderNextRow:function(vidx){return vidx%this._itemsPerRow===this._itemsPerRow-1},_adjustScrollPosition:function(){var deltaHeight=this._virtualStart===0?this._physicalTop:Math.min(this._scrollPosition+this._physicalTop,0);if(deltaHeight){this._physicalTop=this._physicalTop-deltaHeight;if(!IOS_TOUCH_SCROLLING&&this._physicalTop!==0){this._resetScrollPosition(this._scrollTop-deltaHeight)}}},_resetScrollPosition:function(pos){if(this.scrollTarget){this._scrollTop=pos;this._scrollPosition=this._scrollTop}},_updateScrollerSize:function(forceUpdate){if(this.grid){this._estScrollHeight=this._virtualRowCount*this._rowHeight}else{this._estScrollHeight=this._physicalBottom+Math.max(this._virtualCount-this._physicalCount-this._virtualStart,0)*this._physicalAverage}forceUpdate=forceUpdate||this._scrollHeight===0;forceUpdate=forceUpdate||this._scrollPosition>=this._estScrollHeight-this._physicalSize;forceUpdate=forceUpdate||this.grid&&this.$.items.style.height<this._estScrollHeight;if(forceUpdate||Math.abs(this._estScrollHeight-this._scrollHeight)>=this._optPhysicalSize){this.$.items.style.height=this._estScrollHeight+"px";this._scrollHeight=this._estScrollHeight}},scrollToItem:function(item){return this.scrollToIndex(this.items.indexOf(item))},scrollToIndex:function(idx){if(typeof idx!=="number"||idx<0||idx>this.items.length-1){return}Polymer.dom.flush();if(this._physicalCount===0){return}idx=Math.min(Math.max(idx,0),this._virtualCount-1);if(!this._isIndexRendered(idx)||idx>=this._maxVirtualStart){this._virtualStart=this.grid?idx-this._itemsPerRow*2:idx-1}this._manageFocus();this._assignModels();this._updateMetrics();this._physicalTop=Math.floor(this._virtualStart/this._itemsPerRow)*this._physicalAverage;var currentTopItem=this._physicalStart;var currentVirtualItem=this._virtualStart;var targetOffsetTop=0;var hiddenContentSize=this._hiddenContentSize;while(currentVirtualItem<idx&&targetOffsetTop<=hiddenContentSize){targetOffsetTop=targetOffsetTop+this._getPhysicalSizeIncrement(currentTopItem);currentTopItem=(currentTopItem+1)%this._physicalCount;currentVirtualItem++}this._updateScrollerSize(true);this._positionItems();this._resetScrollPosition(this._physicalTop+this._scrollerPaddingTop+targetOffsetTop);this._increasePoolIfNeeded();this._firstVisibleIndexVal=null;this._lastVisibleIndexVal=null},_resetAverage:function(){this._physicalAverage=0;this._physicalAverageCount=0},_resizeHandler:function(){if(IOS&&Math.abs(this._viewportHeight-this._scrollTargetHeight)<100){return}Polymer.dom.addDebouncer(this.debounce("_debounceTemplate",function(){this.updateViewportBoundaries();this._render();if(this._physicalCount>0&&this._isVisible){this._resetAverage();this.scrollToIndex(this.firstVisibleIndex)}}.bind(this),1))},_getModelFromItem:function(item){var key=this._collection.getKey(item);var pidx=this._physicalIndexForKey[key];if(pidx!=null){return this._physicalItems[pidx]._templateInstance}return null},_getNormalizedItem:function(item){if(this._collection.getKey(item)===undefined){if(typeof item==="number"){item=this.items[item];if(!item){throw new RangeError("<item> not found")}return item}throw new TypeError("<item> should be a valid item")}return item},selectItem:function(item){item=this._getNormalizedItem(item);var model=this._getModelFromItem(item);if(!this.multiSelection&&this.selectedItem){this.deselectItem(this.selectedItem)}if(model){model[this.selectedAs]=true}this.$.selector.select(item);this.updateSizeForItem(item)},deselectItem:function(item){item=this._getNormalizedItem(item);var model=this._getModelFromItem(item);if(model){model[this.selectedAs]=false}this.$.selector.deselect(item);this.updateSizeForItem(item)},toggleSelectionForItem:function(item){item=this._getNormalizedItem(item);if(this.$.selector.isSelected(item)){this.deselectItem(item)}else{this.selectItem(item)}},clearSelection:function(){function unselect(item){var model=this._getModelFromItem(item);if(model){model[this.selectedAs]=false}}if(Array.isArray(this.selectedItems)){this.selectedItems.forEach(unselect,this)}else if(this.selectedItem){unselect.call(this,this.selectedItem)}this.$.selector.clearSelection()},_selectionEnabledChanged:function(selectionEnabled){var handler=selectionEnabled?this.listen:this.unlisten;handler.call(this,this,"tap","_selectionHandler")},_selectionHandler:function(e){var model=this.modelForElement(e.target);if(!model){return}var modelTabIndex,activeElTabIndex;var target=Polymer.dom(e).path[0];var activeEl=Polymer.dom(this.domHost?this.domHost.root:document).activeElement;var physicalItem=this._physicalItems[this._getPhysicalIndex(model[this.indexAs])];if(target.localName==="input"||target.localName==="button"||target.localName==="select"){return}modelTabIndex=model.tabIndex;model.tabIndex=SECRET_TABINDEX;activeElTabIndex=activeEl?activeEl.tabIndex:-1;model.tabIndex=modelTabIndex;if(activeEl&&physicalItem!==activeEl&&physicalItem.contains(activeEl)&&activeElTabIndex!==SECRET_TABINDEX){return}this.toggleSelectionForItem(model[this.as])},_multiSelectionChanged:function(multiSelection){this.clearSelection();this.$.selector.multi=multiSelection},updateSizeForItem:function(item){item=this._getNormalizedItem(item);var key=this._collection.getKey(item);var pidx=this._physicalIndexForKey[key];if(pidx!=null){this._updateMetrics([pidx]);this._positionItems()}},_manageFocus:function(){var fidx=this._focusedIndex;if(fidx>=0&&fidx<this._virtualCount){if(this._isIndexRendered(fidx)){this._restoreFocusedItem();
 
-(function() {
-  'use strict';
-  var KEY_IDENTIFIER = {
-    'U+0008': 'backspace',
-    'U+0009': 'tab',
-    'U+001B': 'esc',
-    'U+0020': 'space',
-    'U+007F': 'del'
-  };
-  var KEY_CODE = {
-    8: 'backspace',
-    9: 'tab',
-    13: 'enter',
-    27: 'esc',
-    33: 'pageup',
-    34: 'pagedown',
-    35: 'end',
-    36: 'home',
-    32: 'space',
-    37: 'left',
-    38: 'up',
-    39: 'right',
-    40: 'down',
-    46: 'del',
-    106: '*'
-  };
-  var MODIFIER_KEYS = {
-    shift: 'shiftKey',
-    ctrl: 'ctrlKey',
-    alt: 'altKey',
-    meta: 'metaKey'
-  };
-  var KEY_CHAR = /[a-z0-9*]/;
-  var IDENT_CHAR = /U\+/;
-  var ARROW_KEY = /^arrow/;
-  var SPACE_KEY = /^space(bar)?/;
-  var ESC_KEY = /^escape$/;
-  function transformKey(key, noSpecialChars) {
-    var validKey = '';
-    if (key) {
-      var lKey = key.toLowerCase();
-      if (lKey === ' ' || SPACE_KEY.test(lKey)) {
-        validKey = 'space';
-      } else if (ESC_KEY.test(lKey)) {
-        validKey = 'esc';
-      } else if (lKey.length == 1) {
-        if (!noSpecialChars || KEY_CHAR.test(lKey)) {
-          validKey = lKey;
-        }
-      } else if (ARROW_KEY.test(lKey)) {
-        validKey = lKey.replace('arrow', '');
-      } else if (lKey == 'multiply') {
-        validKey = '*';
-      } else {
-        validKey = lKey;
-      }
-    }
-    return validKey;
-  }
-  function transformKeyIdentifier(keyIdent) {
-    var validKey = '';
-    if (keyIdent) {
-      if (keyIdent in KEY_IDENTIFIER) {
-        validKey = KEY_IDENTIFIER[keyIdent];
-      } else if (IDENT_CHAR.test(keyIdent)) {
-        keyIdent = parseInt(keyIdent.replace('U+', '0x'), 16);
-        validKey = String.fromCharCode(keyIdent).toLowerCase();
-      } else {
-        validKey = keyIdent.toLowerCase();
-      }
-    }
-    return validKey;
-  }
-  function transformKeyCode(keyCode) {
-    var validKey = '';
-    if (Number(keyCode)) {
-      if (keyCode >= 65 && keyCode <= 90) {
-        validKey = String.fromCharCode(32 + keyCode);
-      } else if (keyCode >= 112 && keyCode <= 123) {
-        validKey = 'f' + (keyCode - 112);
-      } else if (keyCode >= 48 && keyCode <= 57) {
-        validKey = String(keyCode - 48);
-      } else if (keyCode >= 96 && keyCode <= 105) {
-        validKey = String(keyCode - 96);
-      } else {
-        validKey = KEY_CODE[keyCode];
-      }
-    }
-    return validKey;
-  }
-  function normalizedKeyForEvent(keyEvent, noSpecialChars) {
-    if (keyEvent.key) {
-      return transformKey(keyEvent.key, noSpecialChars);
-    }
-    if (keyEvent.detail && keyEvent.detail.key) {
-      return transformKey(keyEvent.detail.key, noSpecialChars);
-    }
-    return transformKeyIdentifier(keyEvent.keyIdentifier) || transformKeyCode(keyEvent.keyCode) || '';
-  }
-  function keyComboMatchesEvent(keyCombo, event) {
-    var keyEvent = normalizedKeyForEvent(event, keyCombo.hasModifiers);
-    return keyEvent === keyCombo.key && (!keyCombo.hasModifiers || !!event.shiftKey === !!keyCombo.shiftKey && !!event.ctrlKey === !!keyCombo.ctrlKey && !!event.altKey === !!keyCombo.altKey && !!event.metaKey === !!keyCombo.metaKey);
-  }
-  function parseKeyComboString(keyComboString) {
-    if (keyComboString.length === 1) {
-      return {
-        combo: keyComboString,
-        key: keyComboString,
-        event: 'keydown'
-      };
-    }
-    return keyComboString.split('+').reduce(function(parsedKeyCombo, keyComboPart) {
-      var eventParts = keyComboPart.split(':');
-      var keyName = eventParts[0];
-      var event = eventParts[1];
-      if (keyName in MODIFIER_KEYS) {
-        parsedKeyCombo[MODIFIER_KEYS[keyName]] = true;
-        parsedKeyCombo.hasModifiers = true;
-      } else {
-        parsedKeyCombo.key = keyName;
-        parsedKeyCombo.event = event || 'keydown';
-      }
-      return parsedKeyCombo;
-    }, {
-      combo: keyComboString.split(':').shift()
-    });
-  }
-  function parseEventString(eventString) {
-    return eventString.trim().split(' ').map(function(keyComboString) {
-      return parseKeyComboString(keyComboString);
-    });
-  }
-  Polymer.IronA11yKeysBehavior = {
-    properties: {
-      keyEventTarget: {
-        type: Object,
-        value: function() {
-          return this;
-        }
-      },
-      stopKeyboardEventPropagation: {
-        type: Boolean,
-        value: false
-      },
-      _boundKeyHandlers: {
-        type: Array,
-        value: function() {
-          return [];
-        }
-      },
-      _imperativeKeyBindings: {
-        type: Object,
-        value: function() {
-          return {};
-        }
-      }
-    },
-    observers: [ '_resetKeyEventListeners(keyEventTarget, _boundKeyHandlers)' ],
-    keyBindings: {},
-    registered: function() {
-      this._prepKeyBindings();
-    },
-    attached: function() {
-      this._listenKeyEventListeners();
-    },
-    detached: function() {
-      this._unlistenKeyEventListeners();
-    },
-    addOwnKeyBinding: function(eventString, handlerName) {
-      this._imperativeKeyBindings[eventString] = handlerName;
-      this._prepKeyBindings();
-      this._resetKeyEventListeners();
-    },
-    removeOwnKeyBindings: function() {
-      this._imperativeKeyBindings = {};
-      this._prepKeyBindings();
-      this._resetKeyEventListeners();
-    },
-    keyboardEventMatchesKeys: function(event, eventString) {
-      var keyCombos = parseEventString(eventString);
-      for (var i = 0; i < keyCombos.length; ++i) {
-        if (keyComboMatchesEvent(keyCombos[i], event)) {
-          return true;
-        }
-      }
-      return false;
-    },
-    _collectKeyBindings: function() {
-      var keyBindings = this.behaviors.map(function(behavior) {
-        return behavior.keyBindings;
-      });
-      if (keyBindings.indexOf(this.keyBindings) === -1) {
-        keyBindings.push(this.keyBindings);
-      }
-      return keyBindings;
-    },
-    _prepKeyBindings: function() {
-      this._keyBindings = {};
-      this._collectKeyBindings().forEach(function(keyBindings) {
-        for (var eventString in keyBindings) {
-          this._addKeyBinding(eventString, keyBindings[eventString]);
-        }
-      }, this);
-      for (var eventString in this._imperativeKeyBindings) {
-        this._addKeyBinding(eventString, this._imperativeKeyBindings[eventString]);
-      }
-      for (var eventName in this._keyBindings) {
-        this._keyBindings[eventName].sort(function(kb1, kb2) {
-          var b1 = kb1[0].hasModifiers;
-          var b2 = kb2[0].hasModifiers;
-          return b1 === b2 ? 0 : b1 ? -1 : 1;
-        });
-      }
-    },
-    _addKeyBinding: function(eventString, handlerName) {
-      parseEventString(eventString).forEach(function(keyCombo) {
-        this._keyBindings[keyCombo.event] = this._keyBindings[keyCombo.event] || [];
-        this._keyBindings[keyCombo.event].push([ keyCombo, handlerName ]);
-      }, this);
-    },
-    _resetKeyEventListeners: function() {
-      this._unlistenKeyEventListeners();
-      if (this.isAttached) {
-        this._listenKeyEventListeners();
-      }
-    },
-    _listenKeyEventListeners: function() {
-      if (!this.keyEventTarget) {
-        return;
-      }
-      Object.keys(this._keyBindings).forEach(function(eventName) {
-        var keyBindings = this._keyBindings[eventName];
-        var boundKeyHandler = this._onKeyBindingEvent.bind(this, keyBindings);
-        this._boundKeyHandlers.push([ this.keyEventTarget, eventName, boundKeyHandler ]);
-        this.keyEventTarget.addEventListener(eventName, boundKeyHandler);
-      }, this);
-    },
-    _unlistenKeyEventListeners: function() {
-      var keyHandlerTuple;
-      var keyEventTarget;
-      var eventName;
-      var boundKeyHandler;
-      while (this._boundKeyHandlers.length) {
-        keyHandlerTuple = this._boundKeyHandlers.pop();
-        keyEventTarget = keyHandlerTuple[0];
-        eventName = keyHandlerTuple[1];
-        boundKeyHandler = keyHandlerTuple[2];
-        keyEventTarget.removeEventListener(eventName, boundKeyHandler);
-      }
-    },
-    _onKeyBindingEvent: function(keyBindings, event) {
-      if (this.stopKeyboardEventPropagation) {
-        event.stopPropagation();
-      }
-      if (event.defaultPrevented) {
-        return;
-      }
-      for (var i = 0; i < keyBindings.length; i++) {
-        var keyCombo = keyBindings[i][0];
-        var handlerName = keyBindings[i][1];
-        if (keyComboMatchesEvent(keyCombo, event)) {
-          this._triggerKeyHandler(keyCombo, handlerName, event);
-          if (event.defaultPrevented) {
-            return;
-          }
-        }
-      }
-    },
-    _triggerKeyHandler: function(keyCombo, handlerName, keyboardEvent) {
-      var detail = Object.create(keyCombo);
-      detail.keyboardEvent = keyboardEvent;
-      var event = new CustomEvent(keyCombo.event, {
-        detail: detail,
-        cancelable: true
-      });
-      this[handlerName].call(this, event);
-      if (event.defaultPrevented) {
-        keyboardEvent.preventDefault();
-      }
-    }
-  };
-})();
-
-Polymer.IronScrollTargetBehavior = {
-  properties: {
-    scrollTarget: {
-      type: HTMLElement,
-      value: function() {
-        return this._defaultScrollTarget;
-      }
-    }
-  },
-  observers: [ '_scrollTargetChanged(scrollTarget, isAttached)' ],
-  _scrollTargetChanged: function(scrollTarget, isAttached) {
-    var eventTarget;
-    if (this._oldScrollTarget) {
-      eventTarget = this._oldScrollTarget === this._doc ? window : this._oldScrollTarget;
-      eventTarget.removeEventListener('scroll', this._boundScrollHandler);
-      this._oldScrollTarget = null;
-    }
-    if (!isAttached) {
-      return;
-    }
-    if (scrollTarget === 'document') {
-      this.scrollTarget = this._doc;
-    } else if (typeof scrollTarget === 'string') {
-      this.scrollTarget = this.domHost ? this.domHost.$[scrollTarget] : Polymer.dom(this.ownerDocument).querySelector('#' + scrollTarget);
-    } else if (this._isValidScrollTarget()) {
-      eventTarget = scrollTarget === this._doc ? window : scrollTarget;
-      this._boundScrollHandler = this._boundScrollHandler || this._scrollHandler.bind(this);
-      this._oldScrollTarget = scrollTarget;
-      eventTarget.addEventListener('scroll', this._boundScrollHandler);
-    }
-  },
-  _scrollHandler: function scrollHandler() {},
-  get _defaultScrollTarget() {
-    return this._doc;
-  },
-  get _doc() {
-    return this.ownerDocument.documentElement;
-  },
-  get _scrollTop() {
-    if (this._isValidScrollTarget()) {
-      return this.scrollTarget === this._doc ? window.pageYOffset : this.scrollTarget.scrollTop;
-    }
-    return 0;
-  },
-  get _scrollLeft() {
-    if (this._isValidScrollTarget()) {
-      return this.scrollTarget === this._doc ? window.pageXOffset : this.scrollTarget.scrollLeft;
-    }
-    return 0;
-  },
-  set _scrollTop(top) {
-    if (this.scrollTarget === this._doc) {
-      window.scrollTo(window.pageXOffset, top);
-    } else if (this._isValidScrollTarget()) {
-      this.scrollTarget.scrollTop = top;
-    }
-  },
-  set _scrollLeft(left) {
-    if (this.scrollTarget === this._doc) {
-      window.scrollTo(left, window.pageYOffset);
-    } else if (this._isValidScrollTarget()) {
-      this.scrollTarget.scrollLeft = left;
-    }
-  },
-  scroll: function(left, top) {
-    if (this.scrollTarget === this._doc) {
-      window.scrollTo(left, top);
-    } else if (this._isValidScrollTarget()) {
-      this.scrollTarget.scrollLeft = left;
-      this.scrollTarget.scrollTop = top;
-    }
-  },
-  get _scrollTargetWidth() {
-    if (this._isValidScrollTarget()) {
-      return this.scrollTarget === this._doc ? window.innerWidth : this.scrollTarget.offsetWidth;
-    }
-    return 0;
-  },
-  get _scrollTargetHeight() {
-    if (this._isValidScrollTarget()) {
-      return this.scrollTarget === this._doc ? window.innerHeight : this.scrollTarget.offsetHeight;
-    }
-    return 0;
-  },
-  _isValidScrollTarget: function() {
-    return this.scrollTarget instanceof HTMLElement;
-  }
-};
-
-(function() {
-  var IOS = navigator.userAgent.match(/iP(?:hone|ad;(?: U;)? CPU) OS (\d+)/);
-  var IOS_TOUCH_SCROLLING = IOS && IOS[1] >= 8;
-  var DEFAULT_PHYSICAL_COUNT = 3;
-  var HIDDEN_Y = '-10000px';
-  var DEFAULT_GRID_SIZE = 200;
-  var SECRET_TABINDEX = -100;
-  Polymer({
-    is: 'iron-list',
-    properties: {
-      items: {
-        type: Array
-      },
-      maxPhysicalCount: {
-        type: Number,
-        value: 500
-      },
-      as: {
-        type: String,
-        value: 'item'
-      },
-      indexAs: {
-        type: String,
-        value: 'index'
-      },
-      selectedAs: {
-        type: String,
-        value: 'selected'
-      },
-      grid: {
-        type: Boolean,
-        value: false,
-        reflectToAttribute: true
-      },
-      selectionEnabled: {
-        type: Boolean,
-        value: false
-      },
-      selectedItem: {
-        type: Object,
-        notify: true
-      },
-      selectedItems: {
-        type: Object,
-        notify: true
-      },
-      multiSelection: {
-        type: Boolean,
-        value: false
-      }
-    },
-    observers: [ '_itemsChanged(items.*)', '_selectionEnabledChanged(selectionEnabled)', '_multiSelectionChanged(multiSelection)', '_setOverflow(scrollTarget)' ],
-    behaviors: [ Polymer.Templatizer, Polymer.IronResizableBehavior, Polymer.IronA11yKeysBehavior, Polymer.IronScrollTargetBehavior ],
-    keyBindings: {
-      up: '_didMoveUp',
-      down: '_didMoveDown',
-      enter: '_didEnter'
-    },
-    _ratio: .5,
-    _scrollerPaddingTop: 0,
-    _scrollPosition: 0,
-    _physicalSize: 0,
-    _physicalAverage: 0,
-    _physicalAverageCount: 0,
-    _physicalTop: 0,
-    _virtualCount: 0,
-    _physicalIndexForKey: null,
-    _estScrollHeight: 0,
-    _scrollHeight: 0,
-    _viewportHeight: 0,
-    _viewportWidth: 0,
-    _physicalItems: null,
-    _physicalSizes: null,
-    _firstVisibleIndexVal: null,
-    _lastVisibleIndexVal: null,
-    _collection: null,
-    _maxPages: 3,
-    _focusedItem: null,
-    _focusedIndex: -1,
-    _offscreenFocusedItem: null,
-    _focusBackfillItem: null,
-    _itemsPerRow: 1,
-    _itemWidth: 0,
-    _rowHeight: 0,
-    _templateCost: 0,
-    get _physicalBottom() {
-      return this._physicalTop + this._physicalSize;
-    },
-    get _scrollBottom() {
-      return this._scrollPosition + this._viewportHeight;
-    },
-    get _virtualEnd() {
-      return this._virtualStart + this._physicalCount - 1;
-    },
-    get _hiddenContentSize() {
-      var size = this.grid ? this._physicalRows * this._rowHeight : this._physicalSize;
-      return size - this._viewportHeight;
-    },
-    get _maxScrollTop() {
-      return this._estScrollHeight - this._viewportHeight + this._scrollerPaddingTop;
-    },
-    _minVirtualStart: 0,
-    get _maxVirtualStart() {
-      return Math.max(0, this._virtualCount - this._physicalCount);
-    },
-    _virtualStartVal: 0,
-    set _virtualStart(val) {
-      this._virtualStartVal = Math.min(this._maxVirtualStart, Math.max(this._minVirtualStart, val));
-    },
-    get _virtualStart() {
-      return this._virtualStartVal || 0;
-    },
-    _physicalStartVal: 0,
-    set _physicalStart(val) {
-      this._physicalStartVal = val % this._physicalCount;
-      if (this._physicalStartVal < 0) {
-        this._physicalStartVal = this._physicalCount + this._physicalStartVal;
-      }
-      this._physicalEnd = (this._physicalStart + this._physicalCount - 1) % this._physicalCount;
-    },
-    get _physicalStart() {
-      return this._physicalStartVal || 0;
-    },
-    _physicalCountVal: 0,
-    set _physicalCount(val) {
-      this._physicalCountVal = val;
-      this._physicalEnd = (this._physicalStart + this._physicalCount - 1) % this._physicalCount;
-    },
-    get _physicalCount() {
-      return this._physicalCountVal;
-    },
-    _physicalEnd: 0,
-    get _optPhysicalSize() {
-      if (this.grid) {
-        return this._estRowsInView * this._rowHeight * this._maxPages;
-      }
-      return this._viewportHeight * this._maxPages;
-    },
-    get _optPhysicalCount() {
-      return this._estRowsInView * this._itemsPerRow * this._maxPages;
-    },
-    get _isVisible() {
-      return Boolean(this.offsetWidth || this.offsetHeight);
-    },
-    get firstVisibleIndex() {
-      if (this._firstVisibleIndexVal === null) {
-        var physicalOffset = Math.floor(this._physicalTop + this._scrollerPaddingTop);
-        this._firstVisibleIndexVal = this._iterateItems(function(pidx, vidx) {
-          physicalOffset += this._getPhysicalSizeIncrement(pidx);
-          if (physicalOffset > this._scrollPosition) {
-            return this.grid ? vidx - vidx % this._itemsPerRow : vidx;
-          }
-          if (this.grid && this._virtualCount - 1 === vidx) {
-            return vidx - vidx % this._itemsPerRow;
-          }
-        }) || 0;
-      }
-      return this._firstVisibleIndexVal;
-    },
-    get lastVisibleIndex() {
-      if (this._lastVisibleIndexVal === null) {
-        if (this.grid) {
-          var lastIndex = this.firstVisibleIndex + this._estRowsInView * this._itemsPerRow - 1;
-          this._lastVisibleIndexVal = Math.min(this._virtualCount, lastIndex);
-        } else {
-          var physicalOffset = this._physicalTop;
-          this._iterateItems(function(pidx, vidx) {
-            if (physicalOffset < this._scrollBottom) {
-              this._lastVisibleIndexVal = vidx;
-            } else {
-              return true;
-            }
-            physicalOffset += this._getPhysicalSizeIncrement(pidx);
-          });
-        }
-      }
-      return this._lastVisibleIndexVal;
-    },
-    get _defaultScrollTarget() {
-      return this;
-    },
-    get _virtualRowCount() {
-      return Math.ceil(this._virtualCount / this._itemsPerRow);
-    },
-    get _estRowsInView() {
-      return Math.ceil(this._viewportHeight / this._rowHeight);
-    },
-    get _physicalRows() {
-      return Math.ceil(this._physicalCount / this._itemsPerRow);
-    },
-    ready: function() {
-      this.addEventListener('focus', this._didFocus.bind(this), true);
-    },
-    attached: function() {
-      this.updateViewportBoundaries();
-      if (this._physicalCount === 0) {
-        this._debounceTemplate(this._render);
-      }
-      this.listen(this, 'iron-resize', '_resizeHandler');
-    },
-    detached: function() {
-      this.unlisten(this, 'iron-resize', '_resizeHandler');
-    },
-    _setOverflow: function(scrollTarget) {
-      this.style.webkitOverflowScrolling = scrollTarget === this ? 'touch' : '';
-      this.style.overflow = scrollTarget === this ? 'auto' : '';
-    },
-    updateViewportBoundaries: function() {
-      this._scrollerPaddingTop = this.scrollTarget === this ? 0 : parseInt(window.getComputedStyle(this)['padding-top'], 10);
-      this._viewportHeight = this._scrollTargetHeight;
-      if (this.grid) {
-        this._updateGridMetrics();
-      }
-    },
-    _scrollHandler: function() {
-      var scrollTop = Math.max(0, Math.min(this._maxScrollTop, this._scrollTop));
-      var delta = scrollTop - this._scrollPosition;
-      var tileHeight, tileTop, kth, recycledTileSet, scrollBottom, physicalBottom;
-      var ratio = this._ratio;
-      var recycledTiles = 0;
-      var hiddenContentSize = this._hiddenContentSize;
-      var currentRatio = ratio;
-      var movingUp = [];
-      this._scrollPosition = scrollTop;
-      this._firstVisibleIndexVal = null;
-      this._lastVisibleIndexVal = null;
-      scrollBottom = this._scrollBottom;
-      physicalBottom = this._physicalBottom;
-      if (Math.abs(delta) > this._physicalSize) {
-        this._physicalTop += delta;
-        recycledTiles = Math.round(delta / this._physicalAverage);
-      } else if (delta < 0) {
-        var topSpace = scrollTop - this._physicalTop;
-        var virtualStart = this._virtualStart;
-        recycledTileSet = [];
-        kth = this._physicalEnd;
-        currentRatio = topSpace / hiddenContentSize;
-        while (currentRatio < ratio && recycledTiles < this._physicalCount && virtualStart - recycledTiles > 0 && physicalBottom - this._getPhysicalSizeIncrement(kth) > scrollBottom) {
-          tileHeight = this._getPhysicalSizeIncrement(kth);
-          currentRatio += tileHeight / hiddenContentSize;
-          physicalBottom -= tileHeight;
-          recycledTileSet.push(kth);
-          recycledTiles++;
-          kth = kth === 0 ? this._physicalCount - 1 : kth - 1;
-        }
-        movingUp = recycledTileSet;
-        recycledTiles = -recycledTiles;
-      } else if (delta > 0) {
-        var bottomSpace = physicalBottom - scrollBottom;
-        var virtualEnd = this._virtualEnd;
-        var lastVirtualItemIndex = this._virtualCount - 1;
-        recycledTileSet = [];
-        kth = this._physicalStart;
-        currentRatio = bottomSpace / hiddenContentSize;
-        while (currentRatio < ratio && recycledTiles < this._physicalCount && virtualEnd + recycledTiles < lastVirtualItemIndex && this._physicalTop + this._getPhysicalSizeIncrement(kth) < scrollTop) {
-          tileHeight = this._getPhysicalSizeIncrement(kth);
-          currentRatio += tileHeight / hiddenContentSize;
-          this._physicalTop += tileHeight;
-          recycledTileSet.push(kth);
-          recycledTiles++;
-          kth = (kth + 1) % this._physicalCount;
-        }
-      }
-      if (recycledTiles === 0) {
-        if (physicalBottom < scrollBottom || this._physicalTop > scrollTop) {
-          this._increasePoolIfNeeded();
-        }
-      } else {
-        this._virtualStart = this._virtualStart + recycledTiles;
-        this._physicalStart = this._physicalStart + recycledTiles;
-        this._update(recycledTileSet, movingUp);
-      }
-    },
-    _update: function(itemSet, movingUp) {
-      this._manageFocus();
-      this._assignModels(itemSet);
-      this._updateMetrics(itemSet);
-      if (movingUp) {
-        while (movingUp.length) {
-          var idx = movingUp.pop();
-          this._physicalTop -= this._getPhysicalSizeIncrement(idx);
-        }
-      }
-      this._positionItems();
-      this._updateScrollerSize();
-      this._increasePoolIfNeeded();
-    },
-    _createPool: function(size) {
-      var physicalItems = new Array(size);
-      this._ensureTemplatized();
-      for (var i = 0; i < size; i++) {
-        var inst = this.stamp(null);
-        physicalItems[i] = inst.root.querySelector('*');
-        Polymer.dom(this).appendChild(inst.root);
-      }
-      return physicalItems;
-    },
-    _increasePoolIfNeeded: function() {
-      if (this._viewportHeight === 0) {
-        return false;
-      }
-      var self = this;
-      var isClientFull = this._physicalBottom >= this._scrollBottom && this._physicalTop <= this._scrollPosition;
-      if (this._physicalSize >= this._optPhysicalSize && isClientFull) {
-        return false;
-      }
-      var maxPoolSize = Math.round(this._physicalCount * .5);
-      if (!isClientFull) {
-        this._debounceTemplate(this._increasePool.bind(this, maxPoolSize));
-        return true;
-      }
-      this._yield(function() {
-        self._increasePool(Math.min(maxPoolSize, Math.max(1, Math.round(50 / self._templateCost))));
-      });
-      return true;
-    },
-    _yield: function(cb) {
-      var g = window;
-      var handle = g.requestIdleCallback ? g.requestIdleCallback(cb) : g.setTimeout(cb, 16);
-      Polymer.dom.addDebouncer({
-        complete: function() {
-          g.cancelIdleCallback ? g.cancelIdleCallback(handle) : g.clearTimeout(handle);
-          cb();
-        }
-      });
-    },
-    _increasePool: function(missingItems) {
-      var nextPhysicalCount = Math.min(this._physicalCount + missingItems, this._virtualCount - this._virtualStart, Math.max(this.maxPhysicalCount, DEFAULT_PHYSICAL_COUNT));
-      var prevPhysicalCount = this._physicalCount;
-      var delta = nextPhysicalCount - prevPhysicalCount;
-      var ts = window.performance.now();
-      if (delta <= 0) {
-        return;
-      }
-      [].push.apply(this._physicalItems, this._createPool(delta));
-      [].push.apply(this._physicalSizes, new Array(delta));
-      this._physicalCount = prevPhysicalCount + delta;
-      if (this._physicalStart > this._physicalEnd && this._isIndexRendered(this._focusedIndex) && this._getPhysicalIndex(this._focusedIndex) < this._physicalEnd) {
-        this._physicalStart = this._physicalStart + delta;
-      }
-      this._update();
-      this._templateCost = (window.performance.now() - ts) / delta;
-    },
-    _render: function() {
-      if (this.isAttached && this._isVisible) {
-        if (this._physicalCount === 0) {
-          this._increasePool(DEFAULT_PHYSICAL_COUNT);
-        } else {
-          this._update();
-        }
-      }
-    },
-    _ensureTemplatized: function() {
-      if (!this.ctor) {
-        var props = {};
-        props.__key__ = true;
-        props[this.as] = true;
-        props[this.indexAs] = true;
-        props[this.selectedAs] = true;
-        props.tabIndex = true;
-        this._instanceProps = props;
-        this._userTemplate = Polymer.dom(this).querySelector('template');
-        if (this._userTemplate) {
-          this.templatize(this._userTemplate);
-        } else {
-          console.warn('iron-list requires a template to be provided in light-dom');
-        }
-      }
-    },
-    _getStampedChildren: function() {
-      return this._physicalItems;
-    },
-    _forwardInstancePath: function(inst, path, value) {
-      if (path.indexOf(this.as + '.') === 0) {
-        this.notifyPath('items.' + inst.__key__ + '.' + path.slice(this.as.length + 1), value);
-      }
-    },
-    _forwardParentProp: function(prop, value) {
-      if (this._physicalItems) {
-        this._physicalItems.forEach(function(item) {
-          item._templateInstance[prop] = value;
-        }, this);
-      }
-    },
-    _forwardParentPath: function(path, value) {
-      if (this._physicalItems) {
-        this._physicalItems.forEach(function(item) {
-          item._templateInstance.notifyPath(path, value, true);
-        }, this);
-      }
-    },
-    _forwardItemPath: function(path, value) {
-      if (!this._physicalIndexForKey) {
-        return;
-      }
-      var dot = path.indexOf('.');
-      var key = path.substring(0, dot < 0 ? path.length : dot);
-      var idx = this._physicalIndexForKey[key];
-      var offscreenItem = this._offscreenFocusedItem;
-      var el = offscreenItem && offscreenItem._templateInstance.__key__ === key ? offscreenItem : this._physicalItems[idx];
-      if (!el || el._templateInstance.__key__ !== key) {
-        return;
-      }
-      if (dot >= 0) {
-        path = this.as + '.' + path.substring(dot + 1);
-        el._templateInstance.notifyPath(path, value, true);
-      } else {
-        var currentItem = el._templateInstance[this.as];
-        if (Array.isArray(this.selectedItems)) {
-          for (var i = 0; i < this.selectedItems.length; i++) {
-            if (this.selectedItems[i] === currentItem) {
-              this.set('selectedItems.' + i, value);
-              break;
-            }
-          }
-        } else if (this.selectedItem === currentItem) {
-          this.set('selectedItem', value);
-        }
-        el._templateInstance[this.as] = value;
-      }
-    },
-    _itemsChanged: function(change) {
-      if (change.path === 'items') {
-        this._virtualStart = 0;
-        this._physicalTop = 0;
-        this._virtualCount = this.items ? this.items.length : 0;
-        this._collection = this.items ? Polymer.Collection.get(this.items) : null;
-        this._physicalIndexForKey = {};
-        this._firstVisibleIndexVal = null;
-        this._lastVisibleIndexVal = null;
-        this._physicalCount = this._physicalCount || 0;
-        this._physicalItems = this._physicalItems || [];
-        this._physicalSizes = this._physicalSizes || [];
-        this._physicalStart = 0;
-        this._resetScrollPosition(0);
-        this._removeFocusedItem();
-        this._debounceTemplate(this._render);
-      } else if (change.path === 'items.splices') {
-        this._adjustVirtualIndex(change.value.indexSplices);
-        this._virtualCount = this.items ? this.items.length : 0;
-        this._debounceTemplate(this._render);
-      } else {
-        this._forwardItemPath(change.path.split('.').slice(1).join('.'), change.value);
-      }
-    },
-    _adjustVirtualIndex: function(splices) {
-      splices.forEach(function(splice) {
-        splice.removed.forEach(this._removeItem, this);
-        if (splice.index < this._virtualStart) {
-          var delta = Math.max(splice.addedCount - splice.removed.length, splice.index - this._virtualStart);
-          this._virtualStart = this._virtualStart + delta;
-          if (this._focusedIndex >= 0) {
-            this._focusedIndex = this._focusedIndex + delta;
-          }
-        }
-      }, this);
-    },
-    _removeItem: function(item) {
-      this.$.selector.deselect(item);
-      if (this._focusedItem && this._focusedItem._templateInstance[this.as] === item) {
-        this._removeFocusedItem();
-      }
-    },
-    _iterateItems: function(fn, itemSet) {
-      var pidx, vidx, rtn, i;
-      if (arguments.length === 2 && itemSet) {
-        for (i = 0; i < itemSet.length; i++) {
-          pidx = itemSet[i];
-          vidx = this._computeVidx(pidx);
-          if ((rtn = fn.call(this, pidx, vidx)) != null) {
-            return rtn;
-          }
-        }
-      } else {
-        pidx = this._physicalStart;
-        vidx = this._virtualStart;
-        for (;pidx < this._physicalCount; pidx++, vidx++) {
-          if ((rtn = fn.call(this, pidx, vidx)) != null) {
-            return rtn;
-          }
-        }
-        for (pidx = 0; pidx < this._physicalStart; pidx++, vidx++) {
-          if ((rtn = fn.call(this, pidx, vidx)) != null) {
-            return rtn;
-          }
-        }
-      }
-    },
-    _computeVidx: function(pidx) {
-      if (pidx >= this._physicalStart) {
-        return this._virtualStart + (pidx - this._physicalStart);
-      }
-      return this._virtualStart + (this._physicalCount - this._physicalStart) + pidx;
-    },
-    _assignModels: function(itemSet) {
-      this._iterateItems(function(pidx, vidx) {
-        var el = this._physicalItems[pidx];
-        var inst = el._templateInstance;
-        var item = this.items && this.items[vidx];
-        if (item != null) {
-          inst[this.as] = item;
-          inst.__key__ = this._collection.getKey(item);
-          inst[this.selectedAs] = this.$.selector.isSelected(item);
-          inst[this.indexAs] = vidx;
-          inst.tabIndex = this._focusedIndex === vidx ? 0 : -1;
-          this._physicalIndexForKey[inst.__key__] = pidx;
-          el.removeAttribute('hidden');
-        } else {
-          inst.__key__ = null;
-          el.setAttribute('hidden', '');
-        }
-      }, itemSet);
-    },
-    _updateMetrics: function(itemSet) {
-      Polymer.dom.flush();
-      var newPhysicalSize = 0;
-      var oldPhysicalSize = 0;
-      var prevAvgCount = this._physicalAverageCount;
-      var prevPhysicalAvg = this._physicalAverage;
-      this._iterateItems(function(pidx, vidx) {
-        oldPhysicalSize += this._physicalSizes[pidx] || 0;
-        this._physicalSizes[pidx] = this._physicalItems[pidx].offsetHeight;
-        newPhysicalSize += this._physicalSizes[pidx];
-        this._physicalAverageCount += this._physicalSizes[pidx] ? 1 : 0;
-      }, itemSet);
-      this._viewportHeight = this._scrollTargetHeight;
-      if (this.grid) {
-        this._updateGridMetrics();
-        this._physicalSize = Math.ceil(this._physicalCount / this._itemsPerRow) * this._rowHeight;
-      } else {
-        this._physicalSize = this._physicalSize + newPhysicalSize - oldPhysicalSize;
-      }
-      if (this._physicalAverageCount !== prevAvgCount) {
-        this._physicalAverage = Math.round((prevPhysicalAvg * prevAvgCount + newPhysicalSize) / this._physicalAverageCount);
-      }
-    },
-    _updateGridMetrics: function() {
-      this._viewportWidth = this.$.items.offsetWidth;
-      this._itemWidth = this._physicalCount > 0 ? this._physicalItems[0].getBoundingClientRect().width : DEFAULT_GRID_SIZE;
-      this._rowHeight = this._physicalCount > 0 ? this._physicalItems[0].offsetHeight : DEFAULT_GRID_SIZE;
-      this._itemsPerRow = this._itemWidth ? Math.floor(this._viewportWidth / this._itemWidth) : this._itemsPerRow;
-    },
-    _positionItems: function() {
-      this._adjustScrollPosition();
-      var y = this._physicalTop;
-      if (this.grid) {
-        var totalItemWidth = this._itemsPerRow * this._itemWidth;
-        var rowOffset = (this._viewportWidth - totalItemWidth) / 2;
-        this._iterateItems(function(pidx, vidx) {
-          var modulus = vidx % this._itemsPerRow;
-          var x = Math.floor(modulus * this._itemWidth + rowOffset);
-          this.translate3d(x + 'px', y + 'px', 0, this._physicalItems[pidx]);
-          if (this._shouldRenderNextRow(vidx)) {
-            y += this._rowHeight;
-          }
-        });
-      } else {
-        this._iterateItems(function(pidx, vidx) {
-          this.translate3d(0, y + 'px', 0, this._physicalItems[pidx]);
-          y += this._physicalSizes[pidx];
-        });
-      }
-    },
-    _getPhysicalSizeIncrement: function(pidx) {
-      if (!this.grid) {
-        return this._physicalSizes[pidx];
-      }
-      if (this._computeVidx(pidx) % this._itemsPerRow !== this._itemsPerRow - 1) {
-        return 0;
-      }
-      return this._rowHeight;
-    },
-    _shouldRenderNextRow: function(vidx) {
-      return vidx % this._itemsPerRow === this._itemsPerRow - 1;
-    },
-    _adjustScrollPosition: function() {
-      var deltaHeight = this._virtualStart === 0 ? this._physicalTop : Math.min(this._scrollPosition + this._physicalTop, 0);
-      if (deltaHeight) {
-        this._physicalTop = this._physicalTop - deltaHeight;
-        if (!IOS_TOUCH_SCROLLING && this._physicalTop !== 0) {
-          this._resetScrollPosition(this._scrollTop - deltaHeight);
-        }
-      }
-    },
-    _resetScrollPosition: function(pos) {
-      if (this.scrollTarget) {
-        this._scrollTop = pos;
-        this._scrollPosition = this._scrollTop;
-      }
-    },
-    _updateScrollerSize: function(forceUpdate) {
-      if (this.grid) {
-        this._estScrollHeight = this._virtualRowCount * this._rowHeight;
-      } else {
-        this._estScrollHeight = this._physicalBottom + Math.max(this._virtualCount - this._physicalCount - this._virtualStart, 0) * this._physicalAverage;
-      }
-      forceUpdate = forceUpdate || this._scrollHeight === 0;
-      forceUpdate = forceUpdate || this._scrollPosition >= this._estScrollHeight - this._physicalSize;
-      forceUpdate = forceUpdate || this.grid && this.$.items.style.height < this._estScrollHeight;
-      if (forceUpdate || Math.abs(this._estScrollHeight - this._scrollHeight) >= this._optPhysicalSize) {
-        this.$.items.style.height = this._estScrollHeight + 'px';
-        this._scrollHeight = this._estScrollHeight;
-      }
-    },
-    scrollToItem: function(item) {
-      return this.scrollToIndex(this.items.indexOf(item));
-    },
-    scrollToIndex: function(idx) {
-      if (typeof idx !== 'number' || idx < 0 || idx > this.items.length - 1) {
-        return;
-      }
-      Polymer.dom.flush();
-      if (this._physicalCount === 0) {
-        return;
-      }
-      idx = Math.min(Math.max(idx, 0), this._virtualCount - 1);
-      if (!this._isIndexRendered(idx) || idx >= this._maxVirtualStart) {
-        this._virtualStart = this.grid ? idx - this._itemsPerRow * 2 : idx - 1;
-      }
-      this._manageFocus();
-      this._assignModels();
-      this._updateMetrics();
-      this._physicalTop = Math.floor(this._virtualStart / this._itemsPerRow) * this._physicalAverage;
-      var currentTopItem = this._physicalStart;
-      var currentVirtualItem = this._virtualStart;
-      var targetOffsetTop = 0;
-      var hiddenContentSize = this._hiddenContentSize;
-      while (currentVirtualItem < idx && targetOffsetTop <= hiddenContentSize) {
-        targetOffsetTop = targetOffsetTop + this._getPhysicalSizeIncrement(currentTopItem);
-        currentTopItem = (currentTopItem + 1) % this._physicalCount;
-        currentVirtualItem++;
-      }
-      this._updateScrollerSize(true);
-      this._positionItems();
-      this._resetScrollPosition(this._physicalTop + this._scrollerPaddingTop + targetOffsetTop);
-      this._increasePoolIfNeeded();
-      this._firstVisibleIndexVal = null;
-      this._lastVisibleIndexVal = null;
-    },
-    _resetAverage: function() {
-      this._physicalAverage = 0;
-      this._physicalAverageCount = 0;
-    },
-    _resizeHandler: function() {
-      if (IOS && Math.abs(this._viewportHeight - this._scrollTargetHeight) < 100) {
-        return;
-      }
-      Polymer.dom.addDebouncer(this.debounce('_debounceTemplate', function() {
-        this.updateViewportBoundaries();
-        this._render();
-        if (this._physicalCount > 0 && this._isVisible) {
-          this._resetAverage();
-          this.scrollToIndex(this.firstVisibleIndex);
-        }
-      }.bind(this), 1));
-    },
-    _getModelFromItem: function(item) {
-      var key = this._collection.getKey(item);
-      var pidx = this._physicalIndexForKey[key];
-      if (pidx != null) {
-        return this._physicalItems[pidx]._templateInstance;
-      }
-      return null;
-    },
-    _getNormalizedItem: function(item) {
-      if (this._collection.getKey(item) === undefined) {
-        if (typeof item === 'number') {
-          item = this.items[item];
-          if (!item) {
-            throw new RangeError('<item> not found');
-          }
-          return item;
-        }
-        throw new TypeError('<item> should be a valid item');
-      }
-      return item;
-    },
-    selectItem: function(item) {
-      item = this._getNormalizedItem(item);
-      var model = this._getModelFromItem(item);
-      if (!this.multiSelection && this.selectedItem) {
-        this.deselectItem(this.selectedItem);
-      }
-      if (model) {
-        model[this.selectedAs] = true;
-      }
-      this.$.selector.select(item);
-      this.updateSizeForItem(item);
-    },
-    deselectItem: function(item) {
-      item = this._getNormalizedItem(item);
-      var model = this._getModelFromItem(item);
-      if (model) {
-        model[this.selectedAs] = false;
-      }
-      this.$.selector.deselect(item);
-      this.updateSizeForItem(item);
-    },
-    toggleSelectionForItem: function(item) {
-      item = this._getNormalizedItem(item);
-      if (this.$.selector.isSelected(item)) {
-        this.deselectItem(item);
-      } else {
-        this.selectItem(item);
-      }
-    },
-    clearSelection: function() {
-      function unselect(item) {
-        var model = this._getModelFromItem(item);
-        if (model) {
-          model[this.selectedAs] = false;
-        }
-      }
-      if (Array.isArray(this.selectedItems)) {
-        this.selectedItems.forEach(unselect, this);
-      } else if (this.selectedItem) {
-        unselect.call(this, this.selectedItem);
-      }
-      this.$.selector.clearSelection();
-    },
-    _selectionEnabledChanged: function(selectionEnabled) {
-      var handler = selectionEnabled ? this.listen : this.unlisten;
-      handler.call(this, this, 'tap', '_selectionHandler');
-    },
-    _selectionHandler: function(e) {
-      var model = this.modelForElement(e.target);
-      if (!model) {
-        return;
-      }
-      var modelTabIndex, activeElTabIndex;
-      var target = Polymer.dom(e).path[0];
-      var activeEl = Polymer.dom(this.domHost ? this.domHost.root : document).activeElement;
-      var physicalItem = this._physicalItems[this._getPhysicalIndex(model[this.indexAs])];
-      if (target.localName === 'input' || target.localName === 'button' || target.localName === 'select') {
-        return;
-      }
-      modelTabIndex = model.tabIndex;
-      model.tabIndex = SECRET_TABINDEX;
-      activeElTabIndex = activeEl ? activeEl.tabIndex : -1;
-      model.tabIndex = modelTabIndex;
-      if (activeEl && physicalItem !== activeEl && physicalItem.contains(activeEl) && activeElTabIndex !== SECRET_TABINDEX) {
-        return;
-      }
-      this.toggleSelectionForItem(model[this.as]);
-    },
-    _multiSelectionChanged: function(multiSelection) {
-      this.clearSelection();
-      this.$.selector.multi = multiSelection;
-    },
-    updateSizeForItem: function(item) {
-      item = this._getNormalizedItem(item);
-      var key = this._collection.getKey(item);
-      var pidx = this._physicalIndexForKey[key];
-      if (pidx != null) {
-        this._updateMetrics([ pidx ]);
-        this._positionItems();
-      }
-    },
-    _manageFocus: function() {
-      var fidx = this._focusedIndex;
-      if (fidx >= 0 && fidx < this._virtualCount) {
-        if (this._isIndexRendered(fidx)) {
-          this._restoreFocusedItem();
-        } else {
-          this._createFocusBackfillItem();
-        }
-      } else if (this._virtualCount > 0 && this._physicalCount > 0) {
-        this._focusedIndex = this._virtualStart;
-        this._focusedItem = this._physicalItems[this._physicalStart];
-      }
-    },
-    _isIndexRendered: function(idx) {
-      return idx >= this._virtualStart && idx <= this._virtualEnd;
-    },
-    _isIndexVisible: function(idx) {
-      return idx >= this.firstVisibleIndex && idx <= this.lastVisibleIndex;
-    },
-    _getPhysicalIndex: function(idx) {
-      return this._physicalIndexForKey[this._collection.getKey(this._getNormalizedItem(idx))];
-    },
-    _focusPhysicalItem: function(idx) {
-      if (idx < 0 || idx >= this._virtualCount) {
-        return;
-      }
-      this._restoreFocusedItem();
-      if (!this._isIndexRendered(idx)) {
-        this.scrollToIndex(idx);
-      }
-      var physicalItem = this._physicalItems[this._getPhysicalIndex(idx)];
-      var model = physicalItem._templateInstance;
-      var focusable;
-      model.tabIndex = SECRET_TABINDEX;
-      if (physicalItem.tabIndex === SECRET_TABINDEX) {
-        focusable = physicalItem;
-      }
-      if (!focusable) {
-        focusable = Polymer.dom(physicalItem).querySelector('[tabindex="' + SECRET_TABINDEX + '"]');
-      }
-      model.tabIndex = 0;
-      this._focusedIndex = idx;
-      focusable && focusable.focus();
-    },
-    _removeFocusedItem: function() {
-      if (this._offscreenFocusedItem) {
-        Polymer.dom(this).removeChild(this._offscreenFocusedItem);
-      }
-      this._offscreenFocusedItem = null;
-      this._focusBackfillItem = null;
-      this._focusedItem = null;
-      this._focusedIndex = -1;
-    },
-    _createFocusBackfillItem: function() {
-      var pidx, fidx = this._focusedIndex;
-      if (this._offscreenFocusedItem || fidx < 0) {
-        return;
-      }
-      if (!this._focusBackfillItem) {
-        var stampedTemplate = this.stamp(null);
-        this._focusBackfillItem = stampedTemplate.root.querySelector('*');
-        Polymer.dom(this).appendChild(stampedTemplate.root);
-      }
-      pidx = this._getPhysicalIndex(fidx);
-      if (pidx != null) {
-        this._offscreenFocusedItem = this._physicalItems[pidx];
-        this._physicalItems[pidx] = this._focusBackfillItem;
-        this.translate3d(0, HIDDEN_Y, 0, this._offscreenFocusedItem);
-      }
-    },
-    _restoreFocusedItem: function() {
-      var pidx, fidx = this._focusedIndex;
-      if (!this._offscreenFocusedItem || this._focusedIndex < 0) {
-        return;
-      }
-      this._assignModels();
-      pidx = this._getPhysicalIndex(fidx);
-      if (pidx != null) {
-        this._focusBackfillItem = this._physicalItems[pidx];
-        this._physicalItems[pidx] = this._offscreenFocusedItem;
-        this._offscreenFocusedItem = null;
-        this.translate3d(0, HIDDEN_Y, 0, this._focusBackfillItem);
-      }
-    },
-    _didFocus: function(e) {
-      var targetModel = this.modelForElement(e.target);
-      var focusedModel = this._focusedItem ? this._focusedItem._templateInstance : null;
-      var hasOffscreenFocusedItem = this._offscreenFocusedItem !== null;
-      var fidx = this._focusedIndex;
-      if (!targetModel || !focusedModel) {
-        return;
-      }
-      if (focusedModel === targetModel) {
-        if (!this._isIndexVisible(fidx)) {
-          this.scrollToIndex(fidx);
-        }
-      } else {
-        this._restoreFocusedItem();
-        focusedModel.tabIndex = -1;
-        targetModel.tabIndex = 0;
-        fidx = targetModel[this.indexAs];
-        this._focusedIndex = fidx;
-        this._focusedItem = this._physicalItems[this._getPhysicalIndex(fidx)];
-        if (hasOffscreenFocusedItem && !this._offscreenFocusedItem) {
-          this._update();
-        }
-      }
-    },
-    _didMoveUp: function() {
-      this._focusPhysicalItem(this._focusedIndex - 1);
-    },
-    _didMoveDown: function(e) {
-      e.detail.keyboardEvent.preventDefault();
-      this._focusPhysicalItem(this._focusedIndex + 1);
-    },
-    _didEnter: function(e) {
-      this._focusPhysicalItem(this._focusedIndex);
-      this._selectionHandler(e.detail.keyboardEvent);
-    }
-  });
-})();
-
+}else{this._createFocusBackfillItem()}}else if(this._virtualCount>0&&this._physicalCount>0){this._focusedIndex=this._virtualStart;this._focusedItem=this._physicalItems[this._physicalStart]}},_isIndexRendered:function(idx){return idx>=this._virtualStart&&idx<=this._virtualEnd},_isIndexVisible:function(idx){return idx>=this.firstVisibleIndex&&idx<=this.lastVisibleIndex},_getPhysicalIndex:function(idx){return this._physicalIndexForKey[this._collection.getKey(this._getNormalizedItem(idx))]},_focusPhysicalItem:function(idx){if(idx<0||idx>=this._virtualCount){return}this._restoreFocusedItem();if(!this._isIndexRendered(idx)){this.scrollToIndex(idx)}var physicalItem=this._physicalItems[this._getPhysicalIndex(idx)];var model=physicalItem._templateInstance;var focusable;model.tabIndex=SECRET_TABINDEX;if(physicalItem.tabIndex===SECRET_TABINDEX){focusable=physicalItem}if(!focusable){focusable=Polymer.dom(physicalItem).querySelector('[tabindex="'+SECRET_TABINDEX+'"]')}model.tabIndex=0;this._focusedIndex=idx;focusable&&focusable.focus()},_removeFocusedItem:function(){if(this._offscreenFocusedItem){Polymer.dom(this).removeChild(this._offscreenFocusedItem)}this._offscreenFocusedItem=null;this._focusBackfillItem=null;this._focusedItem=null;this._focusedIndex=-1},_createFocusBackfillItem:function(){var pidx,fidx=this._focusedIndex;if(this._offscreenFocusedItem||fidx<0){return}if(!this._focusBackfillItem){var stampedTemplate=this.stamp(null);this._focusBackfillItem=stampedTemplate.root.querySelector("*");Polymer.dom(this).appendChild(stampedTemplate.root)}pidx=this._getPhysicalIndex(fidx);if(pidx!=null){this._offscreenFocusedItem=this._physicalItems[pidx];this._physicalItems[pidx]=this._focusBackfillItem;this.translate3d(0,HIDDEN_Y,0,this._offscreenFocusedItem)}},_restoreFocusedItem:function(){var pidx,fidx=this._focusedIndex;if(!this._offscreenFocusedItem||this._focusedIndex<0){return}this._assignModels();pidx=this._getPhysicalIndex(fidx);if(pidx!=null){this._focusBackfillItem=this._physicalItems[pidx];this._physicalItems[pidx]=this._offscreenFocusedItem;this._offscreenFocusedItem=null;this.translate3d(0,HIDDEN_Y,0,this._focusBackfillItem)}},_didFocus:function(e){var targetModel=this.modelForElement(e.target);var focusedModel=this._focusedItem?this._focusedItem._templateInstance:null;var hasOffscreenFocusedItem=this._offscreenFocusedItem!==null;var fidx=this._focusedIndex;if(!targetModel||!focusedModel){return}if(focusedModel===targetModel){if(!this._isIndexVisible(fidx)){this.scrollToIndex(fidx)}}else{this._restoreFocusedItem();focusedModel.tabIndex=-1;targetModel.tabIndex=0;fidx=targetModel[this.indexAs];this._focusedIndex=fidx;this._focusedItem=this._physicalItems[this._getPhysicalIndex(fidx)];if(hasOffscreenFocusedItem&&!this._offscreenFocusedItem){this._update()}}},_didMoveUp:function(){this._focusPhysicalItem(this._focusedIndex-1)},_didMoveDown:function(e){e.detail.keyboardEvent.preventDefault();this._focusPhysicalItem(this._focusedIndex+1)},_didEnter:function(e){this._focusPhysicalItem(this._focusedIndex);this._selectionHandler(e.detail.keyboardEvent)}})})();
 // 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.
-cr.define('downloads', function() {
-  function chromeSendWithId(chromeSendName) {
-    return function(id) {
-      chrome.send(chromeSendName, [ id ]);
-    };
-  }
-  function ActionService() {
-    this.searchTerms_ = [];
-  }
-  function trim(s) {
-    return s.trim();
-  }
-  function truthy(value) {
-    return !!value;
-  }
-  ActionService.splitTerms = function(searchText) {
-    return searchText.split(/"([^"]*)"/).map(trim).filter(truthy);
-  };
-  ActionService.prototype = {
-    cancel: chromeSendWithId('cancel'),
-    clearAll: function() {
-      if (loadTimeData.getBoolean('allowDeletingHistory')) {
-        chrome.send('clearAll');
-        this.search('');
-      }
-    },
-    discardDangerous: chromeSendWithId('discardDangerous'),
-    download: function(url) {
-      var a = document.createElement('a');
-      a.href = url;
-      a.setAttribute('download', '');
-      a.click();
-    },
-    drag: chromeSendWithId('drag'),
-    loadMore: function() {
-      chrome.send('getDownloads', this.searchTerms_);
-    },
-    isSearching: function() {
-      return this.searchTerms_.length > 0;
-    },
-    openDownloadsFolder: chrome.send.bind(chrome, 'openDownloadsFolder'),
-    openFile: chromeSendWithId('openFile'),
-    pause: chromeSendWithId('pause'),
-    remove: chromeSendWithId('remove'),
-    resume: chromeSendWithId('resume'),
-    saveDangerous: chromeSendWithId('saveDangerous'),
-    search: function(searchText) {
-      var searchTerms = ActionService.splitTerms(searchText);
-      var sameTerms = searchTerms.length == this.searchTerms_.length;
-      for (var i = 0; sameTerms && i < searchTerms.length; ++i) {
-        if (searchTerms[i] != this.searchTerms_[i]) sameTerms = false;
-      }
-      if (sameTerms) return false;
-      this.searchTerms_ = searchTerms;
-      this.loadMore();
-      return true;
-    },
-    show: chromeSendWithId('show'),
-    undo: chrome.send.bind(chrome, 'undo')
-  };
-  cr.addSingletonGetter(ActionService);
-  return {
-    ActionService: ActionService
-  };
-});
-
+cr.define("downloads",function(){function chromeSendWithId(chromeSendName){return function(id){chrome.send(chromeSendName,[id])}}function ActionService(){this.searchTerms_=[]}function trim(s){return s.trim()}function truthy(value){return!!value}ActionService.splitTerms=function(searchText){return searchText.split(/"([^"]*)"/).map(trim).filter(truthy)};ActionService.prototype={cancel:chromeSendWithId("cancel"),clearAll:function(){if(loadTimeData.getBoolean("allowDeletingHistory")){chrome.send("clearAll");this.search("")}},discardDangerous:chromeSendWithId("discardDangerous"),download:function(url){var a=document.createElement("a");a.href=url;a.setAttribute("download","");a.click()},drag:chromeSendWithId("drag"),loadMore:function(){chrome.send("getDownloads",this.searchTerms_)},isSearching:function(){return this.searchTerms_.length>0},openDownloadsFolder:chrome.send.bind(chrome,"openDownloadsFolder"),openFile:chromeSendWithId("openFile"),pause:chromeSendWithId("pause"),remove:chromeSendWithId("remove"),resume:chromeSendWithId("resume"),saveDangerous:chromeSendWithId("saveDangerous"),search:function(searchText){var searchTerms=ActionService.splitTerms(searchText);var sameTerms=searchTerms.length==this.searchTerms_.length;for(var i=0;sameTerms&&i<searchTerms.length;++i){if(searchTerms[i]!=this.searchTerms_[i])sameTerms=false}if(sameTerms)return false;this.searchTerms_=searchTerms;this.loadMore();return true},show:chromeSendWithId("show"),undo:chrome.send.bind(chrome,"undo")};cr.addSingletonGetter(ActionService);return{ActionService:ActionService}});
 // 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.
-cr.define('downloads', function() {
-  var DangerType = {
-    NOT_DANGEROUS: 'NOT_DANGEROUS',
-    DANGEROUS_FILE: 'DANGEROUS_FILE',
-    DANGEROUS_URL: 'DANGEROUS_URL',
-    DANGEROUS_CONTENT: 'DANGEROUS_CONTENT',
-    UNCOMMON_CONTENT: 'UNCOMMON_CONTENT',
-    DANGEROUS_HOST: 'DANGEROUS_HOST',
-    POTENTIALLY_UNWANTED: 'POTENTIALLY_UNWANTED'
-  };
-  var States = {
-    IN_PROGRESS: 'IN_PROGRESS',
-    CANCELLED: 'CANCELLED',
-    COMPLETE: 'COMPLETE',
-    PAUSED: 'PAUSED',
-    DANGEROUS: 'DANGEROUS',
-    INTERRUPTED: 'INTERRUPTED'
-  };
-  return {
-    DangerType: DangerType,
-    States: States
-  };
-});
-
+cr.define("downloads",function(){var DangerType={NOT_DANGEROUS:"NOT_DANGEROUS",DANGEROUS_FILE:"DANGEROUS_FILE",DANGEROUS_URL:"DANGEROUS_URL",DANGEROUS_CONTENT:"DANGEROUS_CONTENT",UNCOMMON_CONTENT:"UNCOMMON_CONTENT",DANGEROUS_HOST:"DANGEROUS_HOST",POTENTIALLY_UNWANTED:"POTENTIALLY_UNWANTED"};var States={IN_PROGRESS:"IN_PROGRESS",CANCELLED:"CANCELLED",COMPLETE:"COMPLETE",PAUSED:"PAUSED",DANGEROUS:"DANGEROUS",INTERRUPTED:"INTERRUPTED"};return{DangerType:DangerType,States:States}});
 // 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.
-var ActionLink = document.registerElement('action-link', {
-  prototype: {
-    __proto__: HTMLAnchorElement.prototype,
-    createdCallback: function() {
-      this.tabIndex = this.disabled ? -1 : 0;
-      if (!this.hasAttribute('role')) this.setAttribute('role', 'link');
-      this.addEventListener('keydown', function(e) {
-        if (!this.disabled && e.key == 'Enter' && !this.href) {
-          window.setTimeout(this.click.bind(this), 0);
-        }
-      });
-      function preventDefault(e) {
-        e.preventDefault();
-      }
-      function removePreventDefault() {
-        document.removeEventListener('selectstart', preventDefault);
-        document.removeEventListener('mouseup', removePreventDefault);
-      }
-      this.addEventListener('mousedown', function() {
-        document.addEventListener('selectstart', preventDefault);
-        document.addEventListener('mouseup', removePreventDefault);
-        if (document.activeElement != this) this.classList.add('no-outline');
-      });
-      this.addEventListener('blur', function() {
-        this.classList.remove('no-outline');
-      });
-    },
-    set disabled(disabled) {
-      if (disabled) HTMLAnchorElement.prototype.setAttribute.call(this, 'disabled', ''); else HTMLAnchorElement.prototype.removeAttribute.call(this, 'disabled');
-      this.tabIndex = disabled ? -1 : 0;
-    },
-    get disabled() {
-      return this.hasAttribute('disabled');
-    },
-    setAttribute: function(attr, val) {
-      if (attr.toLowerCase() == 'disabled') this.disabled = true; else HTMLAnchorElement.prototype.setAttribute.apply(this, arguments);
-    },
-    removeAttribute: function(attr) {
-      if (attr.toLowerCase() == 'disabled') this.disabled = false; else HTMLAnchorElement.prototype.removeAttribute.apply(this, arguments);
-    }
-  },
-  "extends": 'a'
-});
-
-(function() {
-  var metaDatas = {};
-  var metaArrays = {};
-  var singleton = null;
-  Polymer.IronMeta = Polymer({
-    is: 'iron-meta',
-    properties: {
-      type: {
-        type: String,
-        value: 'default',
-        observer: '_typeChanged'
-      },
-      key: {
-        type: String,
-        observer: '_keyChanged'
-      },
-      value: {
-        type: Object,
-        notify: true,
-        observer: '_valueChanged'
-      },
-      self: {
-        type: Boolean,
-        observer: '_selfChanged'
-      },
-      list: {
-        type: Array,
-        notify: true
-      }
-    },
-    hostAttributes: {
-      hidden: true
-    },
-    factoryImpl: function(config) {
-      if (config) {
-        for (var n in config) {
-          switch (n) {
-           case 'type':
-           case 'key':
-           case 'value':
-            this[n] = config[n];
-            break;
-          }
-        }
-      }
-    },
-    created: function() {
-      this._metaDatas = metaDatas;
-      this._metaArrays = metaArrays;
-    },
-    _keyChanged: function(key, old) {
-      this._resetRegistration(old);
-    },
-    _valueChanged: function(value) {
-      this._resetRegistration(this.key);
-    },
-    _selfChanged: function(self) {
-      if (self) {
-        this.value = this;
-      }
-    },
-    _typeChanged: function(type) {
-      this._unregisterKey(this.key);
-      if (!metaDatas[type]) {
-        metaDatas[type] = {};
-      }
-      this._metaData = metaDatas[type];
-      if (!metaArrays[type]) {
-        metaArrays[type] = [];
-      }
-      this.list = metaArrays[type];
-      this._registerKeyValue(this.key, this.value);
-    },
-    byKey: function(key) {
-      return this._metaData && this._metaData[key];
-    },
-    _resetRegistration: function(oldKey) {
-      this._unregisterKey(oldKey);
-      this._registerKeyValue(this.key, this.value);
-    },
-    _unregisterKey: function(key) {
-      this._unregister(key, this._metaData, this.list);
-    },
-    _registerKeyValue: function(key, value) {
-      this._register(key, value, this._metaData, this.list);
-    },
-    _register: function(key, value, data, list) {
-      if (key && data && value !== undefined) {
-        data[key] = value;
-        list.push(value);
-      }
-    },
-    _unregister: function(key, data, list) {
-      if (key && data) {
-        if (key in data) {
-          var value = data[key];
-          delete data[key];
-          this.arrayDelete(list, value);
-        }
-      }
-    }
-  });
-  Polymer.IronMeta.getIronMeta = function getIronMeta() {
-    if (singleton === null) {
-      singleton = new Polymer.IronMeta();
-    }
-    return singleton;
-  };
-  Polymer.IronMetaQuery = Polymer({
-    is: 'iron-meta-query',
-    properties: {
-      type: {
-        type: String,
-        value: 'default',
-        observer: '_typeChanged'
-      },
-      key: {
-        type: String,
-        observer: '_keyChanged'
-      },
-      value: {
-        type: Object,
-        notify: true,
-        readOnly: true
-      },
-      list: {
-        type: Array,
-        notify: true
-      }
-    },
-    factoryImpl: function(config) {
-      if (config) {
-        for (var n in config) {
-          switch (n) {
-           case 'type':
-           case 'key':
-            this[n] = config[n];
-            break;
-          }
-        }
-      }
-    },
-    created: function() {
-      this._metaDatas = metaDatas;
-      this._metaArrays = metaArrays;
-    },
-    _keyChanged: function(key) {
-      this._setValue(this._metaData && this._metaData[key]);
-    },
-    _typeChanged: function(type) {
-      this._metaData = metaDatas[type];
-      this.list = metaArrays[type];
-      if (this.key) {
-        this._keyChanged(this.key);
-      }
-    },
-    byKey: function(key) {
-      return this._metaData && this._metaData[key];
-    }
-  });
-})();
-
-Polymer({
-  is: 'iron-icon',
-  properties: {
-    icon: {
-      type: String,
-      observer: '_iconChanged'
-    },
-    theme: {
-      type: String,
-      observer: '_updateIcon'
-    },
-    src: {
-      type: String,
-      observer: '_srcChanged'
-    },
-    _meta: {
-      value: Polymer.Base.create('iron-meta', {
-        type: 'iconset'
-      }),
-      observer: '_updateIcon'
-    }
-  },
-  _DEFAULT_ICONSET: 'icons',
-  _iconChanged: function(icon) {
-    var parts = (icon || '').split(':');
-    this._iconName = parts.pop();
-    this._iconsetName = parts.pop() || this._DEFAULT_ICONSET;
-    this._updateIcon();
-  },
-  _srcChanged: function(src) {
-    this._updateIcon();
-  },
-  _usesIconset: function() {
-    return this.icon || !this.src;
-  },
-  _updateIcon: function() {
-    if (this._usesIconset()) {
-      if (this._img && this._img.parentNode) {
-        Polymer.dom(this.root).removeChild(this._img);
-      }
-      if (this._iconName === "") {
-        if (this._iconset) {
-          this._iconset.removeIcon(this);
-        }
-      } else if (this._iconsetName && this._meta) {
-        this._iconset = this._meta.byKey(this._iconsetName);
-        if (this._iconset) {
-          this._iconset.applyIcon(this, this._iconName, this.theme);
-          this.unlisten(window, 'iron-iconset-added', '_updateIcon');
-        } else {
-          this.listen(window, 'iron-iconset-added', '_updateIcon');
-        }
-      }
-    } else {
-      if (this._iconset) {
-        this._iconset.removeIcon(this);
-      }
-      if (!this._img) {
-        this._img = document.createElement('img');
-        this._img.style.width = '100%';
-        this._img.style.height = '100%';
-        this._img.draggable = false;
-      }
-      this._img.src = this.src;
-      Polymer.dom(this.root).appendChild(this._img);
-    }
-  }
-});
-
-Polymer.IronControlState = {
-  properties: {
-    focused: {
-      type: Boolean,
-      value: false,
-      notify: true,
-      readOnly: true,
-      reflectToAttribute: true
-    },
-    disabled: {
-      type: Boolean,
-      value: false,
-      notify: true,
-      observer: '_disabledChanged',
-      reflectToAttribute: true
-    },
-    _oldTabIndex: {
-      type: Number
-    },
-    _boundFocusBlurHandler: {
-      type: Function,
-      value: function() {
-        return this._focusBlurHandler.bind(this);
-      }
-    }
-  },
-  observers: [ '_changedControlState(focused, disabled)' ],
-  ready: function() {
-    this.addEventListener('focus', this._boundFocusBlurHandler, true);
-    this.addEventListener('blur', this._boundFocusBlurHandler, true);
-  },
-  _focusBlurHandler: function(event) {
-    if (event.target === this) {
-      this._setFocused(event.type === 'focus');
-    } else if (!this.shadowRoot) {
-      var target = Polymer.dom(event).localTarget;
-      if (!this.isLightDescendant(target)) {
-        this.fire(event.type, {
-          sourceEvent: event
-        }, {
-          node: this,
-          bubbles: event.bubbles,
-          cancelable: event.cancelable
-        });
-      }
-    }
-  },
-  _disabledChanged: function(disabled, old) {
-    this.setAttribute('aria-disabled', disabled ? 'true' : 'false');
-    this.style.pointerEvents = disabled ? 'none' : '';
-    if (disabled) {
-      this._oldTabIndex = this.tabIndex;
-      this._setFocused(false);
-      this.tabIndex = -1;
-      this.blur();
-    } else if (this._oldTabIndex !== undefined) {
-      this.tabIndex = this._oldTabIndex;
-    }
-  },
-  _changedControlState: function() {
-    if (this._controlStateChanged) {
-      this._controlStateChanged();
-    }
-  }
-};
-
-Polymer.IronButtonStateImpl = {
-  properties: {
-    pressed: {
-      type: Boolean,
-      readOnly: true,
-      value: false,
-      reflectToAttribute: true,
-      observer: '_pressedChanged'
-    },
-    toggles: {
-      type: Boolean,
-      value: false,
-      reflectToAttribute: true
-    },
-    active: {
-      type: Boolean,
-      value: false,
-      notify: true,
-      reflectToAttribute: true
-    },
-    pointerDown: {
-      type: Boolean,
-      readOnly: true,
-      value: false
-    },
-    receivedFocusFromKeyboard: {
-      type: Boolean,
-      readOnly: true
-    },
-    ariaActiveAttribute: {
-      type: String,
-      value: 'aria-pressed',
-      observer: '_ariaActiveAttributeChanged'
-    }
-  },
-  listeners: {
-    down: '_downHandler',
-    up: '_upHandler',
-    tap: '_tapHandler'
-  },
-  observers: [ '_detectKeyboardFocus(focused)', '_activeChanged(active, ariaActiveAttribute)' ],
-  keyBindings: {
-    'enter:keydown': '_asyncClick',
-    'space:keydown': '_spaceKeyDownHandler',
-    'space:keyup': '_spaceKeyUpHandler'
-  },
-  _mouseEventRe: /^mouse/,
-  _tapHandler: function() {
-    if (this.toggles) {
-      this._userActivate(!this.active);
-    } else {
-      this.active = false;
-    }
-  },
-  _detectKeyboardFocus: function(focused) {
-    this._setReceivedFocusFromKeyboard(!this.pointerDown && focused);
-  },
-  _userActivate: function(active) {
-    if (this.active !== active) {
-      this.active = active;
-      this.fire('change');
-    }
-  },
-  _downHandler: function(event) {
-    this._setPointerDown(true);
-    this._setPressed(true);
-    this._setReceivedFocusFromKeyboard(false);
-  },
-  _upHandler: function() {
-    this._setPointerDown(false);
-    this._setPressed(false);
-  },
-  _spaceKeyDownHandler: function(event) {
-    var keyboardEvent = event.detail.keyboardEvent;
-    var target = Polymer.dom(keyboardEvent).localTarget;
-    if (this.isLightDescendant(target)) return;
-    keyboardEvent.preventDefault();
-    keyboardEvent.stopImmediatePropagation();
-    this._setPressed(true);
-  },
-  _spaceKeyUpHandler: function(event) {
-    var keyboardEvent = event.detail.keyboardEvent;
-    var target = Polymer.dom(keyboardEvent).localTarget;
-    if (this.isLightDescendant(target)) return;
-    if (this.pressed) {
-      this._asyncClick();
-    }
-    this._setPressed(false);
-  },
-  _asyncClick: function() {
-    this.async(function() {
-      this.click();
-    }, 1);
-  },
-  _pressedChanged: function(pressed) {
-    this._changedButtonState();
-  },
-  _ariaActiveAttributeChanged: function(value, oldValue) {
-    if (oldValue && oldValue != value && this.hasAttribute(oldValue)) {
-      this.removeAttribute(oldValue);
-    }
-  },
-  _activeChanged: function(active, ariaActiveAttribute) {
-    if (this.toggles) {
-      this.setAttribute(this.ariaActiveAttribute, active ? 'true' : 'false');
-    } else {
-      this.removeAttribute(this.ariaActiveAttribute);
-    }
-    this._changedButtonState();
-  },
-  _controlStateChanged: function() {
-    if (this.disabled) {
-      this._setPressed(false);
-    } else {
-      this._changedButtonState();
-    }
-  },
-  _changedButtonState: function() {
-    if (this._buttonStateChanged) {
-      this._buttonStateChanged();
-    }
-  }
-};
-
-Polymer.IronButtonState = [ Polymer.IronA11yKeysBehavior, Polymer.IronButtonStateImpl ];
-
-(function() {
-  var Utility = {
-    distance: function(x1, y1, x2, y2) {
-      var xDelta = x1 - x2;
-      var yDelta = y1 - y2;
-      return Math.sqrt(xDelta * xDelta + yDelta * yDelta);
-    },
-    now: window.performance && window.performance.now ? window.performance.now.bind(window.performance) : Date.now
-  };
-  function ElementMetrics(element) {
-    this.element = element;
-    this.width = this.boundingRect.width;
-    this.height = this.boundingRect.height;
-    this.size = Math.max(this.width, this.height);
-  }
-  ElementMetrics.prototype = {
-    get boundingRect() {
-      return this.element.getBoundingClientRect();
-    },
-    furthestCornerDistanceFrom: function(x, y) {
-      var topLeft = Utility.distance(x, y, 0, 0);
-      var topRight = Utility.distance(x, y, this.width, 0);
-      var bottomLeft = Utility.distance(x, y, 0, this.height);
-      var bottomRight = Utility.distance(x, y, this.width, this.height);
-      return Math.max(topLeft, topRight, bottomLeft, bottomRight);
-    }
-  };
-  function Ripple(element) {
-    this.element = element;
-    this.color = window.getComputedStyle(element).color;
-    this.wave = document.createElement('div');
-    this.waveContainer = document.createElement('div');
-    this.wave.style.backgroundColor = this.color;
-    this.wave.classList.add('wave');
-    this.waveContainer.classList.add('wave-container');
-    Polymer.dom(this.waveContainer).appendChild(this.wave);
-    this.resetInteractionState();
-  }
-  Ripple.MAX_RADIUS = 300;
-  Ripple.prototype = {
-    get recenters() {
-      return this.element.recenters;
-    },
-    get center() {
-      return this.element.center;
-    },
-    get mouseDownElapsed() {
-      var elapsed;
-      if (!this.mouseDownStart) {
-        return 0;
-      }
-      elapsed = Utility.now() - this.mouseDownStart;
-      if (this.mouseUpStart) {
-        elapsed -= this.mouseUpElapsed;
-      }
-      return elapsed;
-    },
-    get mouseUpElapsed() {
-      return this.mouseUpStart ? Utility.now() - this.mouseUpStart : 0;
-    },
-    get mouseDownElapsedSeconds() {
-      return this.mouseDownElapsed / 1e3;
-    },
-    get mouseUpElapsedSeconds() {
-      return this.mouseUpElapsed / 1e3;
-    },
-    get mouseInteractionSeconds() {
-      return this.mouseDownElapsedSeconds + this.mouseUpElapsedSeconds;
-    },
-    get initialOpacity() {
-      return this.element.initialOpacity;
-    },
-    get opacityDecayVelocity() {
-      return this.element.opacityDecayVelocity;
-    },
-    get radius() {
-      var width2 = this.containerMetrics.width * this.containerMetrics.width;
-      var height2 = this.containerMetrics.height * this.containerMetrics.height;
-      var waveRadius = Math.min(Math.sqrt(width2 + height2), Ripple.MAX_RADIUS) * 1.1 + 5;
-      var duration = 1.1 - .2 * (waveRadius / Ripple.MAX_RADIUS);
-      var timeNow = this.mouseInteractionSeconds / duration;
-      var size = waveRadius * (1 - Math.pow(80, -timeNow));
-      return Math.abs(size);
-    },
-    get opacity() {
-      if (!this.mouseUpStart) {
-        return this.initialOpacity;
-      }
-      return Math.max(0, this.initialOpacity - this.mouseUpElapsedSeconds * this.opacityDecayVelocity);
-    },
-    get outerOpacity() {
-      var outerOpacity = this.mouseUpElapsedSeconds * .3;
-      var waveOpacity = this.opacity;
-      return Math.max(0, Math.min(outerOpacity, waveOpacity));
-    },
-    get isOpacityFullyDecayed() {
-      return this.opacity < .01 && this.radius >= Math.min(this.maxRadius, Ripple.MAX_RADIUS);
-    },
-    get isRestingAtMaxRadius() {
-      return this.opacity >= this.initialOpacity && this.radius >= Math.min(this.maxRadius, Ripple.MAX_RADIUS);
-    },
-    get isAnimationComplete() {
-      return this.mouseUpStart ? this.isOpacityFullyDecayed : this.isRestingAtMaxRadius;
-    },
-    get translationFraction() {
-      return Math.min(1, this.radius / this.containerMetrics.size * 2 / Math.sqrt(2));
-    },
-    get xNow() {
-      if (this.xEnd) {
-        return this.xStart + this.translationFraction * (this.xEnd - this.xStart);
-      }
-      return this.xStart;
-    },
-    get yNow() {
-      if (this.yEnd) {
-        return this.yStart + this.translationFraction * (this.yEnd - this.yStart);
-      }
-      return this.yStart;
-    },
-    get isMouseDown() {
-      return this.mouseDownStart && !this.mouseUpStart;
-    },
-    resetInteractionState: function() {
-      this.maxRadius = 0;
-      this.mouseDownStart = 0;
-      this.mouseUpStart = 0;
-      this.xStart = 0;
-      this.yStart = 0;
-      this.xEnd = 0;
-      this.yEnd = 0;
-      this.slideDistance = 0;
-      this.containerMetrics = new ElementMetrics(this.element);
-    },
-    draw: function() {
-      var scale;
-      var translateString;
-      var dx;
-      var dy;
-      this.wave.style.opacity = this.opacity;
-      scale = this.radius / (this.containerMetrics.size / 2);
-      dx = this.xNow - this.containerMetrics.width / 2;
-      dy = this.yNow - this.containerMetrics.height / 2;
-      this.waveContainer.style.webkitTransform = 'translate(' + dx + 'px, ' + dy + 'px)';
-      this.waveContainer.style.transform = 'translate3d(' + dx + 'px, ' + dy + 'px, 0)';
-      this.wave.style.webkitTransform = 'scale(' + scale + ',' + scale + ')';
-      this.wave.style.transform = 'scale3d(' + scale + ',' + scale + ',1)';
-    },
-    downAction: function(event) {
-      var xCenter = this.containerMetrics.width / 2;
-      var yCenter = this.containerMetrics.height / 2;
-      this.resetInteractionState();
-      this.mouseDownStart = Utility.now();
-      if (this.center) {
-        this.xStart = xCenter;
-        this.yStart = yCenter;
-        this.slideDistance = Utility.distance(this.xStart, this.yStart, this.xEnd, this.yEnd);
-      } else {
-        this.xStart = event ? event.detail.x - this.containerMetrics.boundingRect.left : this.containerMetrics.width / 2;
-        this.yStart = event ? event.detail.y - this.containerMetrics.boundingRect.top : this.containerMetrics.height / 2;
-      }
-      if (this.recenters) {
-        this.xEnd = xCenter;
-        this.yEnd = yCenter;
-        this.slideDistance = Utility.distance(this.xStart, this.yStart, this.xEnd, this.yEnd);
-      }
-      this.maxRadius = this.containerMetrics.furthestCornerDistanceFrom(this.xStart, this.yStart);
-      this.waveContainer.style.top = (this.containerMetrics.height - this.containerMetrics.size) / 2 + 'px';
-      this.waveContainer.style.left = (this.containerMetrics.width - this.containerMetrics.size) / 2 + 'px';
-      this.waveContainer.style.width = this.containerMetrics.size + 'px';
-      this.waveContainer.style.height = this.containerMetrics.size + 'px';
-    },
-    upAction: function(event) {
-      if (!this.isMouseDown) {
-        return;
-      }
-      this.mouseUpStart = Utility.now();
-    },
-    remove: function() {
-      Polymer.dom(this.waveContainer.parentNode).removeChild(this.waveContainer);
-    }
-  };
-  Polymer({
-    is: 'paper-ripple',
-    behaviors: [ Polymer.IronA11yKeysBehavior ],
-    properties: {
-      initialOpacity: {
-        type: Number,
-        value: .25
-      },
-      opacityDecayVelocity: {
-        type: Number,
-        value: .8
-      },
-      recenters: {
-        type: Boolean,
-        value: false
-      },
-      center: {
-        type: Boolean,
-        value: false
-      },
-      ripples: {
-        type: Array,
-        value: function() {
-          return [];
-        }
-      },
-      animating: {
-        type: Boolean,
-        readOnly: true,
-        reflectToAttribute: true,
-        value: false
-      },
-      holdDown: {
-        type: Boolean,
-        value: false,
-        observer: '_holdDownChanged'
-      },
-      noink: {
-        type: Boolean,
-        value: false
-      },
-      _animating: {
-        type: Boolean
-      },
-      _boundAnimate: {
-        type: Function,
-        value: function() {
-          return this.animate.bind(this);
-        }
-      }
-    },
-    get target() {
-      return this.keyEventTarget;
-    },
-    keyBindings: {
-      'enter:keydown': '_onEnterKeydown',
-      'space:keydown': '_onSpaceKeydown',
-      'space:keyup': '_onSpaceKeyup'
-    },
-    attached: function() {
-      if (this.parentNode.nodeType == 11) {
-        this.keyEventTarget = Polymer.dom(this).getOwnerRoot().host;
-      } else {
-        this.keyEventTarget = this.parentNode;
-      }
-      var keyEventTarget = this.keyEventTarget;
-      this.listen(keyEventTarget, 'up', 'uiUpAction');
-      this.listen(keyEventTarget, 'down', 'uiDownAction');
-    },
-    detached: function() {
-      this.unlisten(this.keyEventTarget, 'up', 'uiUpAction');
-      this.unlisten(this.keyEventTarget, 'down', 'uiDownAction');
-      this.keyEventTarget = null;
-    },
-    get shouldKeepAnimating() {
-      for (var index = 0; index < this.ripples.length; ++index) {
-        if (!this.ripples[index].isAnimationComplete) {
-          return true;
-        }
-      }
-      return false;
-    },
-    simulatedRipple: function() {
-      this.downAction(null);
-      this.async(function() {
-        this.upAction();
-      }, 1);
-    },
-    uiDownAction: function(event) {
-      if (!this.noink) {
-        this.downAction(event);
-      }
-    },
-    downAction: function(event) {
-      if (this.holdDown && this.ripples.length > 0) {
-        return;
-      }
-      var ripple = this.addRipple();
-      ripple.downAction(event);
-      if (!this._animating) {
-        this._animating = true;
-        this.animate();
-      }
-    },
-    uiUpAction: function(event) {
-      if (!this.noink) {
-        this.upAction(event);
-      }
-    },
-    upAction: function(event) {
-      if (this.holdDown) {
-        return;
-      }
-      this.ripples.forEach(function(ripple) {
-        ripple.upAction(event);
-      });
-      this._animating = true;
-      this.animate();
-    },
-    onAnimationComplete: function() {
-      this._animating = false;
-      this.$.background.style.backgroundColor = null;
-      this.fire('transitionend');
-    },
-    addRipple: function() {
-      var ripple = new Ripple(this);
-      Polymer.dom(this.$.waves).appendChild(ripple.waveContainer);
-      this.$.background.style.backgroundColor = ripple.color;
-      this.ripples.push(ripple);
-      this._setAnimating(true);
-      return ripple;
-    },
-    removeRipple: function(ripple) {
-      var rippleIndex = this.ripples.indexOf(ripple);
-      if (rippleIndex < 0) {
-        return;
-      }
-      this.ripples.splice(rippleIndex, 1);
-      ripple.remove();
-      if (!this.ripples.length) {
-        this._setAnimating(false);
-      }
-    },
-    animate: function() {
-      if (!this._animating) {
-        return;
-      }
-      var index;
-      var ripple;
-      for (index = 0; index < this.ripples.length; ++index) {
-        ripple = this.ripples[index];
-        ripple.draw();
-        this.$.background.style.opacity = ripple.outerOpacity;
-        if (ripple.isOpacityFullyDecayed && !ripple.isRestingAtMaxRadius) {
-          this.removeRipple(ripple);
-        }
-      }
-      if (!this.shouldKeepAnimating && this.ripples.length === 0) {
-        this.onAnimationComplete();
-      } else {
-        window.requestAnimationFrame(this._boundAnimate);
-      }
-    },
-    _onEnterKeydown: function() {
-      this.uiDownAction();
-      this.async(this.uiUpAction, 1);
-    },
-    _onSpaceKeydown: function() {
-      this.uiDownAction();
-    },
-    _onSpaceKeyup: function() {
-      this.uiUpAction();
-    },
-    _holdDownChanged: function(newVal, oldVal) {
-      if (oldVal === undefined) {
-        return;
-      }
-      if (newVal) {
-        this.downAction();
-      } else {
-        this.upAction();
-      }
-    }
-  });
-})();
-
-Polymer.PaperRippleBehavior = {
-  properties: {
-    noink: {
-      type: Boolean,
-      observer: '_noinkChanged'
-    },
-    _rippleContainer: {
-      type: Object
-    }
-  },
-  _buttonStateChanged: function() {
-    if (this.focused) {
-      this.ensureRipple();
-    }
-  },
-  _downHandler: function(event) {
-    Polymer.IronButtonStateImpl._downHandler.call(this, event);
-    if (this.pressed) {
-      this.ensureRipple(event);
-    }
-  },
-  ensureRipple: function(optTriggeringEvent) {
-    if (!this.hasRipple()) {
-      this._ripple = this._createRipple();
-      this._ripple.noink = this.noink;
-      var rippleContainer = this._rippleContainer || this.root;
-      if (rippleContainer) {
-        Polymer.dom(rippleContainer).appendChild(this._ripple);
-      }
-      if (optTriggeringEvent) {
-        var domContainer = Polymer.dom(this._rippleContainer || this);
-        var target = Polymer.dom(optTriggeringEvent).rootTarget;
-        if (domContainer.deepContains(target)) {
-          this._ripple.uiDownAction(optTriggeringEvent);
-        }
-      }
-    }
-  },
-  getRipple: function() {
-    this.ensureRipple();
-    return this._ripple;
-  },
-  hasRipple: function() {
-    return Boolean(this._ripple);
-  },
-  _createRipple: function() {
-    return document.createElement('paper-ripple');
-  },
-  _noinkChanged: function(noink) {
-    if (this.hasRipple()) {
-      this._ripple.noink = noink;
-    }
-  }
-};
-
-Polymer.PaperButtonBehaviorImpl = {
-  properties: {
-    elevation: {
-      type: Number,
-      reflectToAttribute: true,
-      readOnly: true
-    }
-  },
-  observers: [ '_calculateElevation(focused, disabled, active, pressed, receivedFocusFromKeyboard)', '_computeKeyboardClass(receivedFocusFromKeyboard)' ],
-  hostAttributes: {
-    role: 'button',
-    tabindex: '0',
-    animated: true
-  },
-  _calculateElevation: function() {
-    var e = 1;
-    if (this.disabled) {
-      e = 0;
-    } else if (this.active || this.pressed) {
-      e = 4;
-    } else if (this.receivedFocusFromKeyboard) {
-      e = 3;
-    }
-    this._setElevation(e);
-  },
-  _computeKeyboardClass: function(receivedFocusFromKeyboard) {
-    this.toggleClass('keyboard-focus', receivedFocusFromKeyboard);
-  },
-  _spaceKeyDownHandler: function(event) {
-    Polymer.IronButtonStateImpl._spaceKeyDownHandler.call(this, event);
-    if (this.hasRipple() && this.getRipple().ripples.length < 1) {
-      this._ripple.uiDownAction();
-    }
-  },
-  _spaceKeyUpHandler: function(event) {
-    Polymer.IronButtonStateImpl._spaceKeyUpHandler.call(this, event);
-    if (this.hasRipple()) {
-      this._ripple.uiUpAction();
-    }
-  }
-};
-
-Polymer.PaperButtonBehavior = [ Polymer.IronButtonState, Polymer.IronControlState, Polymer.PaperRippleBehavior, Polymer.PaperButtonBehaviorImpl ];
-
-Polymer({
-  is: 'paper-button',
-  behaviors: [ Polymer.PaperButtonBehavior ],
-  properties: {
-    raised: {
-      type: Boolean,
-      reflectToAttribute: true,
-      value: false,
-      observer: '_calculateElevation'
-    }
-  },
-  _calculateElevation: function() {
-    if (!this.raised) {
-      this._setElevation(0);
-    } else {
-      Polymer.PaperButtonBehaviorImpl._calculateElevation.apply(this);
-    }
-  }
-});
-
-Polymer({
-  is: 'paper-icon-button-light',
-  "extends": 'button',
-  behaviors: [ Polymer.PaperRippleBehavior ],
-  listeners: {
-    down: '_rippleDown',
-    up: '_rippleUp',
-    focus: '_rippleDown',
-    blur: '_rippleUp'
-  },
-  _rippleDown: function() {
-    this.getRipple().downAction();
-  },
-  _rippleUp: function() {
-    this.getRipple().upAction();
-  },
-  ensureRipple: function(var_args) {
-    var lastRipple = this._ripple;
-    Polymer.PaperRippleBehavior.ensureRipple.apply(this, arguments);
-    if (this._ripple && this._ripple !== lastRipple) {
-      this._ripple.center = true;
-      this._ripple.classList.add('circle');
-    }
-  }
-});
-
-Polymer.IronRangeBehavior = {
-  properties: {
-    value: {
-      type: Number,
-      value: 0,
-      notify: true,
-      reflectToAttribute: true
-    },
-    min: {
-      type: Number,
-      value: 0,
-      notify: true
-    },
-    max: {
-      type: Number,
-      value: 100,
-      notify: true
-    },
-    step: {
-      type: Number,
-      value: 1,
-      notify: true
-    },
-    ratio: {
-      type: Number,
-      value: 0,
-      readOnly: true,
-      notify: true
-    }
-  },
-  observers: [ '_update(value, min, max, step)' ],
-  _calcRatio: function(value) {
-    return (this._clampValue(value) - this.min) / (this.max - this.min);
-  },
-  _clampValue: function(value) {
-    return Math.min(this.max, Math.max(this.min, this._calcStep(value)));
-  },
-  _calcStep: function(value) {
-    value = parseFloat(value);
-    if (!this.step) {
-      return value;
-    }
-    var numSteps = Math.round((value - this.min) / this.step);
-    if (this.step < 1) {
-      return numSteps / (1 / this.step) + this.min;
-    } else {
-      return numSteps * this.step + this.min;
-    }
-  },
-  _validateValue: function() {
-    var v = this._clampValue(this.value);
-    this.value = this.oldValue = isNaN(v) ? this.oldValue : v;
-    return this.value !== v;
-  },
-  _update: function() {
-    this._validateValue();
-    this._setRatio(this._calcRatio(this.value) * 100);
-  }
-};
-
-Polymer({
-  is: 'paper-progress',
-  behaviors: [ Polymer.IronRangeBehavior ],
-  properties: {
-    secondaryProgress: {
-      type: Number,
-      value: 0
-    },
-    secondaryRatio: {
-      type: Number,
-      value: 0,
-      readOnly: true
-    },
-    indeterminate: {
-      type: Boolean,
-      value: false,
-      observer: '_toggleIndeterminate'
-    },
-    disabled: {
-      type: Boolean,
-      value: false,
-      reflectToAttribute: true,
-      observer: '_disabledChanged'
-    }
-  },
-  observers: [ '_progressChanged(secondaryProgress, value, min, max)' ],
-  hostAttributes: {
-    role: 'progressbar'
-  },
-  _toggleIndeterminate: function(indeterminate) {
-    this.toggleClass('indeterminate', indeterminate, this.$.primaryProgress);
-  },
-  _transformProgress: function(progress, ratio) {
-    var transform = 'scaleX(' + ratio / 100 + ')';
-    progress.style.transform = progress.style.webkitTransform = transform;
-  },
-  _mainRatioChanged: function(ratio) {
-    this._transformProgress(this.$.primaryProgress, ratio);
-  },
-  _progressChanged: function(secondaryProgress, value, min, max) {
-    secondaryProgress = this._clampValue(secondaryProgress);
-    value = this._clampValue(value);
-    var secondaryRatio = this._calcRatio(secondaryProgress) * 100;
-    var mainRatio = this._calcRatio(value) * 100;
-    this._setSecondaryRatio(secondaryRatio);
-    this._transformProgress(this.$.secondaryProgress, secondaryRatio);
-    this._transformProgress(this.$.primaryProgress, mainRatio);
-    this.secondaryProgress = secondaryProgress;
-    this.setAttribute('aria-valuenow', value);
-    this.setAttribute('aria-valuemin', min);
-    this.setAttribute('aria-valuemax', max);
-  },
-  _disabledChanged: function(disabled) {
-    this.setAttribute('aria-disabled', disabled ? 'true' : 'false');
-  },
-  _hideSecondaryProgress: function(secondaryRatio) {
-    return secondaryRatio === 0;
-  }
-});
-
-Polymer({
-  is: 'iron-iconset-svg',
-  properties: {
-    name: {
-      type: String,
-      observer: '_nameChanged'
-    },
-    size: {
-      type: Number,
-      value: 24
-    }
-  },
-  attached: function() {
-    this.style.display = 'none';
-  },
-  getIconNames: function() {
-    this._icons = this._createIconMap();
-    return Object.keys(this._icons).map(function(n) {
-      return this.name + ':' + n;
-    }, this);
-  },
-  applyIcon: function(element, iconName) {
-    element = element.root || element;
-    this.removeIcon(element);
-    var svg = this._cloneIcon(iconName);
-    if (svg) {
-      var pde = Polymer.dom(element);
-      pde.insertBefore(svg, pde.childNodes[0]);
-      return element._svgIcon = svg;
-    }
-    return null;
-  },
-  removeIcon: function(element) {
-    if (element._svgIcon) {
-      Polymer.dom(element).removeChild(element._svgIcon);
-      element._svgIcon = null;
-    }
-  },
-  _nameChanged: function() {
-    new Polymer.IronMeta({
-      type: 'iconset',
-      key: this.name,
-      value: this
-    });
-    this.async(function() {
-      this.fire('iron-iconset-added', this, {
-        node: window
-      });
-    });
-  },
-  _createIconMap: function() {
-    var icons = Object.create(null);
-    Polymer.dom(this).querySelectorAll('[id]').forEach(function(icon) {
-      icons[icon.id] = icon;
-    });
-    return icons;
-  },
-  _cloneIcon: function(id) {
-    this._icons = this._icons || this._createIconMap();
-    return this._prepareSvgClone(this._icons[id], this.size);
-  },
-  _prepareSvgClone: function(sourceSvg, size) {
-    if (sourceSvg) {
-      var content = sourceSvg.cloneNode(true), svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'), viewBox = content.getAttribute('viewBox') || '0 0 ' + size + ' ' + size;
-      svg.setAttribute('viewBox', viewBox);
-      svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
-      svg.style.cssText = 'pointer-events: none; display: block; width: 100%; height: 100%;';
-      svg.appendChild(content).removeAttribute('id');
-      return svg;
-    }
-    return null;
-  }
-});
-
+var ActionLink=document.registerElement("action-link",{prototype:{__proto__:HTMLAnchorElement.prototype,createdCallback:function(){this.tabIndex=this.disabled?-1:0;if(!this.hasAttribute("role"))this.setAttribute("role","link");this.addEventListener("keydown",function(e){if(!this.disabled&&e.key=="Enter"&&!this.href){window.setTimeout(this.click.bind(this),0)}});function preventDefault(e){e.preventDefault()}function removePreventDefault(){document.removeEventListener("selectstart",preventDefault);document.removeEventListener("mouseup",removePreventDefault)}this.addEventListener("mousedown",function(){document.addEventListener("selectstart",preventDefault);document.addEventListener("mouseup",removePreventDefault);if(document.activeElement!=this)this.classList.add("no-outline")});this.addEventListener("blur",function(){this.classList.remove("no-outline")})},set disabled(disabled){if(disabled)HTMLAnchorElement.prototype.setAttribute.call(this,"disabled","");else HTMLAnchorElement.prototype.removeAttribute.call(this,"disabled");this.tabIndex=disabled?-1:0},get disabled(){return this.hasAttribute("disabled")},setAttribute:function(attr,val){if(attr.toLowerCase()=="disabled")this.disabled=true;else HTMLAnchorElement.prototype.setAttribute.apply(this,arguments)},removeAttribute:function(attr){if(attr.toLowerCase()=="disabled")this.disabled=false;else HTMLAnchorElement.prototype.removeAttribute.apply(this,arguments)}},"extends":"a"});(function(){var metaDatas={};var metaArrays={};var singleton=null;Polymer.IronMeta=Polymer({is:"iron-meta",properties:{type:{type:String,value:"default",observer:"_typeChanged"},key:{type:String,observer:"_keyChanged"},value:{type:Object,notify:true,observer:"_valueChanged"},self:{type:Boolean,observer:"_selfChanged"},list:{type:Array,notify:true}},hostAttributes:{hidden:true},factoryImpl:function(config){if(config){for(var n in config){switch(n){case"type":case"key":case"value":this[n]=config[n];break}}}},created:function(){this._metaDatas=metaDatas;this._metaArrays=metaArrays},_keyChanged:function(key,old){this._resetRegistration(old)},_valueChanged:function(value){this._resetRegistration(this.key)},_selfChanged:function(self){if(self){this.value=this}},_typeChanged:function(type){this._unregisterKey(this.key);if(!metaDatas[type]){metaDatas[type]={}}this._metaData=metaDatas[type];if(!metaArrays[type]){metaArrays[type]=[]}this.list=metaArrays[type];this._registerKeyValue(this.key,this.value)},byKey:function(key){return this._metaData&&this._metaData[key]},_resetRegistration:function(oldKey){this._unregisterKey(oldKey);this._registerKeyValue(this.key,this.value)},_unregisterKey:function(key){this._unregister(key,this._metaData,this.list)},_registerKeyValue:function(key,value){this._register(key,value,this._metaData,this.list)},_register:function(key,value,data,list){if(key&&data&&value!==undefined){data[key]=value;list.push(value)}},_unregister:function(key,data,list){if(key&&data){if(key in data){var value=data[key];delete data[key];this.arrayDelete(list,value)}}}});Polymer.IronMeta.getIronMeta=function getIronMeta(){if(singleton===null){singleton=new Polymer.IronMeta}return singleton};Polymer.IronMetaQuery=Polymer({is:"iron-meta-query",properties:{type:{type:String,value:"default",observer:"_typeChanged"},key:{type:String,observer:"_keyChanged"},value:{type:Object,notify:true,readOnly:true},list:{type:Array,notify:true}},factoryImpl:function(config){if(config){for(var n in config){switch(n){case"type":case"key":this[n]=config[n];break}}}},created:function(){this._metaDatas=metaDatas;this._metaArrays=metaArrays},_keyChanged:function(key){this._setValue(this._metaData&&this._metaData[key])},_typeChanged:function(type){this._metaData=metaDatas[type];this.list=metaArrays[type];if(this.key){this._keyChanged(this.key)}},byKey:function(key){return this._metaData&&this._metaData[key]}})})();Polymer({is:"iron-icon",properties:{icon:{type:String,observer:"_iconChanged"},theme:{type:String,observer:"_updateIcon"},src:{type:String,observer:"_srcChanged"},_meta:{value:Polymer.Base.create("iron-meta",{type:"iconset"}),observer:"_updateIcon"}},_DEFAULT_ICONSET:"icons",_iconChanged:function(icon){var parts=(icon||"").split(":");this._iconName=parts.pop();this._iconsetName=parts.pop()||this._DEFAULT_ICONSET;this._updateIcon()},_srcChanged:function(src){this._updateIcon()},_usesIconset:function(){return this.icon||!this.src},_updateIcon:function(){if(this._usesIconset()){if(this._img&&this._img.parentNode){Polymer.dom(this.root).removeChild(this._img)}if(this._iconName===""){if(this._iconset){this._iconset.removeIcon(this)}}else if(this._iconsetName&&this._meta){this._iconset=this._meta.byKey(this._iconsetName);if(this._iconset){this._iconset.applyIcon(this,this._iconName,this.theme);this.unlisten(window,"iron-iconset-added","_updateIcon")}else{this.listen(window,"iron-iconset-added","_updateIcon")}}}else{if(this._iconset){this._iconset.removeIcon(this)}if(!this._img){this._img=document.createElement("img");this._img.style.width="100%";this._img.style.height="100%";this._img.draggable=false}this._img.src=this.src;Polymer.dom(this.root).appendChild(this._img)}}});Polymer.IronControlState={properties:{focused:{type:Boolean,value:false,notify:true,readOnly:true,reflectToAttribute:true},disabled:{type:Boolean,value:false,notify:true,observer:"_disabledChanged",reflectToAttribute:true},_oldTabIndex:{type:Number},_boundFocusBlurHandler:{type:Function,value:function(){return this._focusBlurHandler.bind(this)}}},observers:["_changedControlState(focused, disabled)"],ready:function(){this.addEventListener("focus",this._boundFocusBlurHandler,true);this.addEventListener("blur",this._boundFocusBlurHandler,true)},_focusBlurHandler:function(event){if(event.target===this){this._setFocused(event.type==="focus")}else if(!this.shadowRoot){var target=Polymer.dom(event).localTarget;if(!this.isLightDescendant(target)){this.fire(event.type,{sourceEvent:event},{node:this,bubbles:event.bubbles,cancelable:event.cancelable})}}},_disabledChanged:function(disabled,old){this.setAttribute("aria-disabled",disabled?"true":"false");this.style.pointerEvents=disabled?"none":"";if(disabled){this._oldTabIndex=this.tabIndex;this._setFocused(false);this.tabIndex=-1;this.blur()}else if(this._oldTabIndex!==undefined){this.tabIndex=this._oldTabIndex}},_changedControlState:function(){if(this._controlStateChanged){this._controlStateChanged()}}};Polymer.IronButtonStateImpl={properties:{pressed:{type:Boolean,readOnly:true,value:false,reflectToAttribute:true,observer:"_pressedChanged"},toggles:{type:Boolean,value:false,reflectToAttribute:true},active:{type:Boolean,value:false,notify:true,reflectToAttribute:true},pointerDown:{type:Boolean,readOnly:true,value:false},receivedFocusFromKeyboard:{type:Boolean,readOnly:true},ariaActiveAttribute:{type:String,value:"aria-pressed",observer:"_ariaActiveAttributeChanged"}},listeners:{down:"_downHandler",up:"_upHandler",tap:"_tapHandler"},observers:["_detectKeyboardFocus(focused)","_activeChanged(active, ariaActiveAttribute)"],keyBindings:{"enter:keydown":"_asyncClick","space:keydown":"_spaceKeyDownHandler","space:keyup":"_spaceKeyUpHandler"},_mouseEventRe:/^mouse/,_tapHandler:function(){if(this.toggles){this._userActivate(!this.active)}else{this.active=false}},_detectKeyboardFocus:function(focused){this._setReceivedFocusFromKeyboard(!this.pointerDown&&focused)},_userActivate:function(active){if(this.active!==active){this.active=active;this.fire("change")}},_downHandler:function(event){this._setPointerDown(true);this._setPressed(true);this._setReceivedFocusFromKeyboard(false)},_upHandler:function(){this._setPointerDown(false);this._setPressed(false)},_spaceKeyDownHandler:function(event){var keyboardEvent=event.detail.keyboardEvent;var target=Polymer.dom(keyboardEvent).localTarget;if(this.isLightDescendant(target))return;keyboardEvent.preventDefault();keyboardEvent.stopImmediatePropagation();this._setPressed(true)},_spaceKeyUpHandler:function(event){var keyboardEvent=event.detail.keyboardEvent;var target=Polymer.dom(keyboardEvent).localTarget;if(this.isLightDescendant(target))return;if(this.pressed){this._asyncClick()}this._setPressed(false)},_asyncClick:function(){this.async(function(){this.click()},1)},_pressedChanged:function(pressed){this._changedButtonState()},_ariaActiveAttributeChanged:function(value,oldValue){if(oldValue&&oldValue!=value&&this.hasAttribute(oldValue)){this.removeAttribute(oldValue)}},_activeChanged:function(active,ariaActiveAttribute){if(this.toggles){this.setAttribute(this.ariaActiveAttribute,active?"true":"false")}else{this.removeAttribute(this.ariaActiveAttribute)}this._changedButtonState()},_controlStateChanged:function(){if(this.disabled){this._setPressed(false)}else{this._changedButtonState()}},_changedButtonState:function(){if(this._buttonStateChanged){this._buttonStateChanged()}}};Polymer.IronButtonState=[Polymer.IronA11yKeysBehavior,Polymer.IronButtonStateImpl];(function(){var Utility={distance:function(x1,y1,x2,y2){var xDelta=x1-x2;var yDelta=y1-y2;return Math.sqrt(xDelta*xDelta+yDelta*yDelta)},now:window.performance&&window.performance.now?window.performance.now.bind(window.performance):Date.now};function ElementMetrics(element){this.element=element;this.width=this.boundingRect.width;this.height=this.boundingRect.height;this.size=Math.max(this.width,this.height)}ElementMetrics.prototype={get boundingRect(){return this.element.getBoundingClientRect()},furthestCornerDistanceFrom:function(x,y){var topLeft=Utility.distance(x,y,0,0);var topRight=Utility.distance(x,y,this.width,0);var bottomLeft=Utility.distance(x,y,0,this.height);var bottomRight=Utility.distance(x,y,this.width,this.height);return Math.max(topLeft,topRight,bottomLeft,bottomRight)}};function Ripple(element){this.element=element;this.color=window.getComputedStyle(element).color;this.wave=document.createElement("div");this.waveContainer=document.createElement("div");this.wave.style.backgroundColor=this.color;this.wave.classList.add("wave");this.waveContainer.classList.add("wave-container");Polymer.dom(this.waveContainer).appendChild(this.wave);this.resetInteractionState()}Ripple.MAX_RADIUS=300;Ripple.prototype={get recenters(){return this.element.recenters},get center(){return this.element.center},get mouseDownElapsed(){var elapsed;if(!this.mouseDownStart){return 0}elapsed=Utility.now()-this.mouseDownStart;if(this.mouseUpStart){elapsed-=this.mouseUpElapsed}return elapsed},get mouseUpElapsed(){return this.mouseUpStart?Utility.now()-this.mouseUpStart:0},get mouseDownElapsedSeconds(){return this.mouseDownElapsed/1e3},get mouseUpElapsedSeconds(){return this.mouseUpElapsed/1e3},get mouseInteractionSeconds(){return this.mouseDownElapsedSeconds+this.mouseUpElapsedSeconds},get initialOpacity(){return this.element.initialOpacity},get opacityDecayVelocity(){return this.element.opacityDecayVelocity},get radius(){var width2=this.containerMetrics.width*this.containerMetrics.width;var height2=this.containerMetrics.height*this.containerMetrics.height;var waveRadius=Math.min(Math.sqrt(width2+height2),Ripple.MAX_RADIUS)*1.1+5;var duration=1.1-.2*(waveRadius/Ripple.MAX_RADIUS);var timeNow=this.mouseInteractionSeconds/duration;var size=waveRadius*(1-Math.pow(80,-timeNow));return Math.abs(size)},get opacity(){if(!this.mouseUpStart){return this.initialOpacity}return Math.max(0,this.initialOpacity-this.mouseUpElapsedSeconds*this.opacityDecayVelocity)},get outerOpacity(){var outerOpacity=this.mouseUpElapsedSeconds*.3;var waveOpacity=this.opacity;return Math.max(0,Math.min(outerOpacity,waveOpacity))},get isOpacityFullyDecayed(){return this.opacity<.01&&this.radius>=Math.min(this.maxRadius,Ripple.MAX_RADIUS)},get isRestingAtMaxRadius(){return this.opacity>=this.initialOpacity&&this.radius>=Math.min(this.maxRadius,Ripple.MAX_RADIUS)},get isAnimationComplete(){return this.mouseUpStart?this.isOpacityFullyDecayed:this.isRestingAtMaxRadius},get translationFraction(){return Math.min(1,this.radius/this.containerMetrics.size*2/Math.sqrt(2))},get xNow(){if(this.xEnd){return this.xStart+this.translationFraction*(this.xEnd-this.xStart)}return this.xStart},get yNow(){if(this.yEnd){return this.yStart+this.translationFraction*(this.yEnd-this.yStart)}return this.yStart},get isMouseDown(){return this.mouseDownStart&&!this.mouseUpStart},resetInteractionState:function(){this.maxRadius=0;this.mouseDownStart=0;this.mouseUpStart=0;this.xStart=0;this.yStart=0;this.xEnd=0;this.yEnd=0;this.slideDistance=0;this.containerMetrics=new ElementMetrics(this.element)},draw:function(){var scale;var translateString;var dx;var dy;this.wave.style.opacity=this.opacity;scale=this.radius/(this.containerMetrics.size/2);dx=this.xNow-this.containerMetrics.width/2;dy=this.yNow-this.containerMetrics.height/2;this.waveContainer.style.webkitTransform="translate("+dx+"px, "+dy+"px)";this.waveContainer.style.transform="translate3d("+dx+"px, "+dy+"px, 0)";this.wave.style.webkitTransform="scale("+scale+","+scale+")";this.wave.style.transform="scale3d("+scale+","+scale+",1)"},downAction:function(event){var xCenter=this.containerMetrics.width/2;var yCenter=this.containerMetrics.height/2;this.resetInteractionState();this.mouseDownStart=Utility.now();if(this.center){this.xStart=xCenter;this.yStart=yCenter;this.slideDistance=Utility.distance(this.xStart,this.yStart,this.xEnd,this.yEnd)}else{this.xStart=event?event.detail.x-this.containerMetrics.boundingRect.left:this.containerMetrics.width/2;this.yStart=event?event.detail.y-this.containerMetrics.boundingRect.top:this.containerMetrics.height/2}if(this.recenters){this.xEnd=xCenter;this.yEnd=yCenter;this.slideDistance=Utility.distance(this.xStart,this.yStart,this.xEnd,this.yEnd)}this.maxRadius=this.containerMetrics.furthestCornerDistanceFrom(this.xStart,this.yStart);this.waveContainer.style.top=(this.containerMetrics.height-this.containerMetrics.size)/2+"px";this.waveContainer.style.left=(this.containerMetrics.width-this.containerMetrics.size)/2+"px";this.waveContainer.style.width=this.containerMetrics.size+"px";this.waveContainer.style.height=this.containerMetrics.size+"px"},upAction:function(event){if(!this.isMouseDown){return}this.mouseUpStart=Utility.now()},remove:function(){Polymer.dom(this.waveContainer.parentNode).removeChild(this.waveContainer)}};Polymer({is:"paper-ripple",behaviors:[Polymer.IronA11yKeysBehavior],properties:{initialOpacity:{type:Number,value:.25},opacityDecayVelocity:{type:Number,value:.8},recenters:{type:Boolean,value:false},center:{type:Boolean,value:false},ripples:{type:Array,value:function(){return[]}},animating:{type:Boolean,readOnly:true,reflectToAttribute:true,value:false},holdDown:{type:Boolean,value:false,observer:"_holdDownChanged"},noink:{type:Boolean,value:false},_animating:{type:Boolean},_boundAnimate:{type:Function,value:function(){return this.animate.bind(this)}}},get target(){return this.keyEventTarget},keyBindings:{"enter:keydown":"_onEnterKeydown","space:keydown":"_onSpaceKeydown","space:keyup":"_onSpaceKeyup"},attached:function(){if(this.parentNode.nodeType==11){this.keyEventTarget=Polymer.dom(this).getOwnerRoot().host}else{this.keyEventTarget=this.parentNode}var keyEventTarget=this.keyEventTarget;this.listen(keyEventTarget,"up","uiUpAction");this.listen(keyEventTarget,"down","uiDownAction")},detached:function(){this.unlisten(this.keyEventTarget,"up","uiUpAction");this.unlisten(this.keyEventTarget,"down","uiDownAction");this.keyEventTarget=null},get shouldKeepAnimating(){for(var index=0;index<this.ripples.length;++index){if(!this.ripples[index].isAnimationComplete){return true}}return false},simulatedRipple:function(){this.downAction(null);this.async(function(){this.upAction()},1)},uiDownAction:function(event){if(!this.noink){this.downAction(event)}},downAction:function(event){if(this.holdDown&&this.ripples.length>0){return}var ripple=this.addRipple();ripple.downAction(event);if(!this._animating){this._animating=true;this.animate()}},uiUpAction:function(event){if(!this.noink){this.upAction(event)}},upAction:function(event){if(this.holdDown){return}this.ripples.forEach(function(ripple){ripple.upAction(event)});this._animating=true;this.animate()},onAnimationComplete:function(){this._animating=false;this.$.background.style.backgroundColor=null;this.fire("transitionend")},addRipple:function(){var ripple=new Ripple(this);Polymer.dom(this.$.waves).appendChild(ripple.waveContainer);this.$.background.style.backgroundColor=ripple.color;this.ripples.push(ripple);this._setAnimating(true);return ripple},removeRipple:function(ripple){var rippleIndex=this.ripples.indexOf(ripple);if(rippleIndex<0){return}this.ripples.splice(rippleIndex,1);ripple.remove();if(!this.ripples.length){this._setAnimating(false)}},animate:function(){if(!this._animating){return}var index;var ripple;for(index=0;index<this.ripples.length;++index){ripple=this.ripples[index];ripple.draw();this.$.background.style.opacity=ripple.outerOpacity;if(ripple.isOpacityFullyDecayed&&!ripple.isRestingAtMaxRadius){this.removeRipple(ripple)}}if(!this.shouldKeepAnimating&&this.ripples.length===0){this.onAnimationComplete()}else{window.requestAnimationFrame(this._boundAnimate)}},_onEnterKeydown:function(){this.uiDownAction();this.async(this.uiUpAction,1)},_onSpaceKeydown:function(){this.uiDownAction()},_onSpaceKeyup:function(){this.uiUpAction()},_holdDownChanged:function(newVal,oldVal){if(oldVal===undefined){return}if(newVal){this.downAction()}else{this.upAction()}}})})();Polymer.PaperRippleBehavior={properties:{noink:{type:Boolean,observer:"_noinkChanged"},_rippleContainer:{type:Object}},_buttonStateChanged:function(){if(this.focused){this.ensureRipple()}},_downHandler:function(event){Polymer.IronButtonStateImpl._downHandler.call(this,event);if(this.pressed){this.ensureRipple(event)}},ensureRipple:function(optTriggeringEvent){if(!this.hasRipple()){this._ripple=this._createRipple();this._ripple.noink=this.noink;var rippleContainer=this._rippleContainer||this.root;if(rippleContainer){Polymer.dom(rippleContainer).appendChild(this._ripple)}if(optTriggeringEvent){var domContainer=Polymer.dom(this._rippleContainer||this);var target=Polymer.dom(optTriggeringEvent).rootTarget;if(domContainer.deepContains(target)){this._ripple.uiDownAction(optTriggeringEvent)}}}},getRipple:function(){this.ensureRipple();return this._ripple},hasRipple:function(){return Boolean(this._ripple)},_createRipple:function(){return document.createElement("paper-ripple")},_noinkChanged:function(noink){if(this.hasRipple()){this._ripple.noink=noink}}};Polymer.PaperButtonBehaviorImpl={properties:{elevation:{type:Number,reflectToAttribute:true,readOnly:true}},observers:["_calculateElevation(focused, disabled, active, pressed, receivedFocusFromKeyboard)","_computeKeyboardClass(receivedFocusFromKeyboard)"],hostAttributes:{role:"button",tabindex:"0",animated:true},_calculateElevation:function(){var e=1;if(this.disabled){e=0}else if(this.active||this.pressed){e=4}else if(this.receivedFocusFromKeyboard){e=3}this._setElevation(e)},_computeKeyboardClass:function(receivedFocusFromKeyboard){this.toggleClass("keyboard-focus",receivedFocusFromKeyboard)},_spaceKeyDownHandler:function(event){Polymer.IronButtonStateImpl._spaceKeyDownHandler.call(this,event);if(this.hasRipple()&&this.getRipple().ripples.length<1){this._ripple.uiDownAction()}},_spaceKeyUpHandler:function(event){Polymer.IronButtonStateImpl._spaceKeyUpHandler.call(this,event);if(this.hasRipple()){this._ripple.uiUpAction()}}};Polymer.PaperButtonBehavior=[Polymer.IronButtonState,Polymer.IronControlState,Polymer.PaperRippleBehavior,Polymer.PaperButtonBehaviorImpl];Polymer({is:"paper-button",behaviors:[Polymer.PaperButtonBehavior],properties:{raised:{type:Boolean,reflectToAttribute:true,value:false,observer:"_calculateElevation"}},_calculateElevation:function(){if(!this.raised){this._setElevation(0)}else{Polymer.PaperButtonBehaviorImpl._calculateElevation.apply(this)}}});Polymer({is:"paper-icon-button-light","extends":"button",behaviors:[Polymer.PaperRippleBehavior],listeners:{down:"_rippleDown",up:"_rippleUp",focus:"_rippleDown",blur:"_rippleUp"},_rippleDown:function(){this.getRipple().downAction()},_rippleUp:function(){this.getRipple().upAction()},ensureRipple:function(var_args){var lastRipple=this._ripple;Polymer.PaperRippleBehavior.ensureRipple.apply(this,arguments);if(this._ripple&&this._ripple!==lastRipple){this._ripple.center=true;this._ripple.classList.add("circle")}}});Polymer.IronRangeBehavior={properties:{value:{type:Number,value:0,notify:true,reflectToAttribute:true},min:{type:Number,value:0,notify:true},max:{type:Number,value:100,notify:true},step:{type:Number,value:1,notify:true},ratio:{type:Number,value:0,readOnly:true,notify:true}},observers:["_update(value, min, max, step)"],_calcRatio:function(value){return(this._clampValue(value)-this.min)/(this.max-this.min)},_clampValue:function(value){return Math.min(this.max,Math.max(this.min,this._calcStep(value)))},_calcStep:function(value){value=parseFloat(value);if(!this.step){return value}var numSteps=Math.round((value-this.min)/this.step);if(this.step<1){return numSteps/(1/this.step)+this.min}else{return numSteps*this.step+this.min}},_validateValue:function(){var v=this._clampValue(this.value);this.value=this.oldValue=isNaN(v)?this.oldValue:v;return this.value!==v},_update:function(){this._validateValue();this._setRatio(this._calcRatio(this.value)*100)}};Polymer({is:"paper-progress",behaviors:[Polymer.IronRangeBehavior],properties:{secondaryProgress:{type:Number,value:0},secondaryRatio:{type:Number,value:0,readOnly:true},indeterminate:{type:Boolean,value:false,observer:"_toggleIndeterminate"},disabled:{type:Boolean,value:false,reflectToAttribute:true,observer:"_disabledChanged"}},observers:["_progressChanged(secondaryProgress, value, min, max)"],hostAttributes:{role:"progressbar"},_toggleIndeterminate:function(indeterminate){this.toggleClass("indeterminate",indeterminate,this.$.primaryProgress)},_transformProgress:function(progress,ratio){var transform="scaleX("+ratio/100+")";progress.style.transform=progress.style.webkitTransform=transform},_mainRatioChanged:function(ratio){this._transformProgress(this.$.primaryProgress,ratio)},_progressChanged:function(secondaryProgress,value,min,max){secondaryProgress=this._clampValue(secondaryProgress);value=this._clampValue(value);var secondaryRatio=this._calcRatio(secondaryProgress)*100;var mainRatio=this._calcRatio(value)*100;this._setSecondaryRatio(secondaryRatio);this._transformProgress(this.$.secondaryProgress,secondaryRatio);this._transformProgress(this.$.primaryProgress,mainRatio);this.secondaryProgress=secondaryProgress;this.setAttribute("aria-valuenow",value);this.setAttribute("aria-valuemin",min);this.setAttribute("aria-valuemax",max)},_disabledChanged:function(disabled){this.setAttribute("aria-disabled",disabled?"true":"false")},_hideSecondaryProgress:function(secondaryRatio){return secondaryRatio===0}});Polymer({is:"iron-iconset-svg",properties:{name:{type:String,observer:"_nameChanged"},size:{type:Number,value:24}},attached:function(){this.style.display="none"},getIconNames:function(){this._icons=this._createIconMap();return Object.keys(this._icons).map(function(n){return this.name+":"+n},this)},applyIcon:function(element,iconName){element=element.root||element;this.removeIcon(element);var svg=this._cloneIcon(iconName);if(svg){var pde=Polymer.dom(element);pde.insertBefore(svg,pde.childNodes[0]);return element._svgIcon=svg}return null},removeIcon:function(element){if(element._svgIcon){Polymer.dom(element).removeChild(element._svgIcon);element._svgIcon=null}},_nameChanged:function(){new Polymer.IronMeta({type:"iconset",key:this.name,value:this});this.async(function(){this.fire("iron-iconset-added",this,{node:window})})},_createIconMap:function(){var icons=Object.create(null);Polymer.dom(this).querySelectorAll("[id]").forEach(function(icon){icons[icon.id]=icon});return icons},_cloneIcon:function(id){this._icons=this._icons||this._createIconMap();return this._prepareSvgClone(this._icons[id],this.size)},_prepareSvgClone:function(sourceSvg,size){if(sourceSvg){var content=sourceSvg.cloneNode(true),svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),viewBox=content.getAttribute("viewBox")||"0 0 "+size+" "+size;svg.setAttribute("viewBox",viewBox);svg.setAttribute("preserveAspectRatio","xMidYMid meet");svg.style.cssText="pointer-events: none; display: block; width: 100%; height: 100%;";svg.appendChild(content).removeAttribute("id");return svg}return null}});
 // 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.
-cr.define('downloads', function() {
-  var Item = Polymer({
-    is: 'downloads-item',
-    properties: {
-      data: {
-        type: Object
-      },
-      completelyOnDisk_: {
-        computed: 'computeCompletelyOnDisk_(' + 'data.state, data.file_externally_removed)',
-        type: Boolean,
-        value: true
-      },
-      controlledBy_: {
-        computed: 'computeControlledBy_(data.by_ext_id, data.by_ext_name)',
-        type: String,
-        value: ''
-      },
-      isActive_: {
-        computed: 'computeIsActive_(' + 'data.state, data.file_externally_removed)',
-        type: Boolean,
-        value: true
-      },
-      isDangerous_: {
-        computed: 'computeIsDangerous_(data.state)',
-        type: Boolean,
-        value: false
-      },
-      isMalware_: {
-        computed: 'computeIsMalware_(isDangerous_, data.danger_type)',
-        type: Boolean,
-        value: false
-      },
-      isInProgress_: {
-        computed: 'computeIsInProgress_(data.state)',
-        type: Boolean,
-        value: false
-      },
-      pauseOrResumeText_: {
-        computed: 'computePauseOrResumeText_(isInProgress_, data.resume)',
-        type: String
-      },
-      showCancel_: {
-        computed: 'computeShowCancel_(data.state)',
-        type: Boolean,
-        value: false
-      },
-      showProgress_: {
-        computed: 'computeShowProgress_(showCancel_, data.percent)',
-        type: Boolean,
-        value: false
-      }
-    },
-    observers: [ 'observeControlledBy_(controlledBy_)', 'observeIsDangerous_(isDangerous_, data)' ],
-    ready: function() {
-      this.content = this.$.content;
-    },
-    computeClass_: function() {
-      var classes = [];
-      if (this.isActive_) classes.push('is-active');
-      if (this.isDangerous_) classes.push('dangerous');
-      if (this.showProgress_) classes.push('show-progress');
-      return classes.join(' ');
-    },
-    computeCompletelyOnDisk_: function() {
-      return this.data.state == downloads.States.COMPLETE && !this.data.file_externally_removed;
-    },
-    computeControlledBy_: function() {
-      if (!this.data.by_ext_id || !this.data.by_ext_name) return '';
-      var url = 'chrome://extensions#' + this.data.by_ext_id;
-      var name = this.data.by_ext_name;
-      return loadTimeData.getStringF('controlledByUrl', url, name);
-    },
-    computeDangerIcon_: function() {
-      if (!this.isDangerous_) return '';
-      switch (this.data.danger_type) {
-       case downloads.DangerType.DANGEROUS_CONTENT:
-       case downloads.DangerType.DANGEROUS_HOST:
-       case downloads.DangerType.DANGEROUS_URL:
-       case downloads.DangerType.POTENTIALLY_UNWANTED:
-       case downloads.DangerType.UNCOMMON_CONTENT:
-        return 'downloads:remove-circle';
-
-       default:
-        return 'cr:warning';
-      }
-    },
-    computeDate_: function() {
-      assert(typeof this.data.hideDate == 'boolean');
-      if (this.data.hideDate) return '';
-      return assert(this.data.since_string || this.data.date_string);
-    },
-    computeDescription_: function() {
-      var data = this.data;
-      switch (data.state) {
-       case downloads.States.DANGEROUS:
-        var fileName = data.file_name;
-        switch (data.danger_type) {
-         case downloads.DangerType.DANGEROUS_FILE:
-          return loadTimeData.getString('dangerFileDesc');
-
-         case downloads.DangerType.DANGEROUS_URL:
-         case downloads.DangerType.DANGEROUS_CONTENT:
-         case downloads.DangerType.DANGEROUS_HOST:
-          return loadTimeData.getString('dangerDownloadDesc');
-
-         case downloads.DangerType.UNCOMMON_CONTENT:
-          return loadTimeData.getString('dangerUncommonDesc');
-
-         case downloads.DangerType.POTENTIALLY_UNWANTED:
-          return loadTimeData.getString('dangerSettingsDesc');
-        }
-        break;
-
-       case downloads.States.IN_PROGRESS:
-       case downloads.States.PAUSED:
-        return data.progress_status_text;
-      }
-      return '';
-    },
-    computeIsActive_: function() {
-      return this.data.state != downloads.States.CANCELLED && this.data.state != downloads.States.INTERRUPTED && !this.data.file_externally_removed;
-    },
-    computeIsDangerous_: function() {
-      return this.data.state == downloads.States.DANGEROUS;
-    },
-    computeIsInProgress_: function() {
-      return this.data.state == downloads.States.IN_PROGRESS;
-    },
-    computeIsMalware_: function() {
-      return this.isDangerous_ && (this.data.danger_type == downloads.DangerType.DANGEROUS_CONTENT || this.data.danger_type == downloads.DangerType.DANGEROUS_HOST || this.data.danger_type == downloads.DangerType.DANGEROUS_URL || this.data.danger_type == downloads.DangerType.POTENTIALLY_UNWANTED);
-    },
-    computePauseOrResumeText_: function() {
-      if (this.isInProgress_) return loadTimeData.getString('controlPause');
-      if (this.data.resume) return loadTimeData.getString('controlResume');
-      return '';
-    },
-    computeRemoveStyle_: function() {
-      var canDelete = loadTimeData.getBoolean('allowDeletingHistory');
-      var hideRemove = this.isDangerous_ || this.showCancel_ || !canDelete;
-      return hideRemove ? 'visibility: hidden' : '';
-    },
-    computeShowCancel_: function() {
-      return this.data.state == downloads.States.IN_PROGRESS || this.data.state == downloads.States.PAUSED;
-    },
-    computeShowProgress_: function() {
-      return this.showCancel_ && this.data.percent >= -1;
-    },
-    computeTag_: function() {
-      switch (this.data.state) {
-       case downloads.States.CANCELLED:
-        return loadTimeData.getString('statusCancelled');
-
-       case downloads.States.INTERRUPTED:
-        return this.data.last_reason_text;
-
-       case downloads.States.COMPLETE:
-        return this.data.file_externally_removed ? loadTimeData.getString('statusRemoved') : '';
-      }
-      return '';
-    },
-    isIndeterminate_: function() {
-      return this.data.percent == -1;
-    },
-    observeControlledBy_: function() {
-      this.$['controlled-by'].innerHTML = this.controlledBy_;
-    },
-    observeIsDangerous_: function() {
-      if (!this.data) return;
-      if (this.isDangerous_) {
-        this.$.url.removeAttribute('href');
-      } else {
-        this.$.url.href = assert(this.data.url);
-        var filePath = encodeURIComponent(this.data.file_path);
-        var scaleFactor = '?scale=' + window.devicePixelRatio + 'x';
-        this.$['file-icon'].src = 'chrome://fileicon/' + filePath + scaleFactor;
-      }
-    },
-    onCancelTap_: function() {
-      downloads.ActionService.getInstance().cancel(this.data.id);
-    },
-    onDiscardDangerousTap_: function() {
-      downloads.ActionService.getInstance().discardDangerous(this.data.id);
-    },
-    onDragStart_: function(e) {
-      e.preventDefault();
-      downloads.ActionService.getInstance().drag(this.data.id);
-    },
-    onFileLinkTap_: function(e) {
-      e.preventDefault();
-      downloads.ActionService.getInstance().openFile(this.data.id);
-    },
-    onPauseOrResumeTap_: function() {
-      if (this.isInProgress_) downloads.ActionService.getInstance().pause(this.data.id); else downloads.ActionService.getInstance().resume(this.data.id);
-    },
-    onRemoveTap_: function() {
-      downloads.ActionService.getInstance().remove(this.data.id);
-    },
-    onRetryTap_: function() {
-      downloads.ActionService.getInstance().download(this.data.url);
-    },
-    onSaveDangerousTap_: function() {
-      downloads.ActionService.getInstance().saveDangerous(this.data.id);
-    },
-    onShowTap_: function() {
-      downloads.ActionService.getInstance().show(this.data.id);
-    }
-  });
-  return {
-    Item: Item
-  };
-});
-
-Polymer.PaperItemBehaviorImpl = {
-  hostAttributes: {
-    role: 'option',
-    tabindex: '0'
-  }
-};
-
-Polymer.PaperItemBehavior = [ Polymer.IronButtonState, Polymer.IronControlState, Polymer.PaperItemBehaviorImpl ];
-
-Polymer({
-  is: 'paper-item',
-  behaviors: [ Polymer.PaperItemBehavior ]
-});
-
-Polymer.IronSelection = function(selectCallback) {
-  this.selection = [];
-  this.selectCallback = selectCallback;
-};
-
-Polymer.IronSelection.prototype = {
-  get: function() {
-    return this.multi ? this.selection.slice() : this.selection[0];
-  },
-  clear: function(excludes) {
-    this.selection.slice().forEach(function(item) {
-      if (!excludes || excludes.indexOf(item) < 0) {
-        this.setItemSelected(item, false);
-      }
-    }, this);
-  },
-  isSelected: function(item) {
-    return this.selection.indexOf(item) >= 0;
-  },
-  setItemSelected: function(item, isSelected) {
-    if (item != null) {
-      if (isSelected !== this.isSelected(item)) {
-        if (isSelected) {
-          this.selection.push(item);
-        } else {
-          var i = this.selection.indexOf(item);
-          if (i >= 0) {
-            this.selection.splice(i, 1);
-          }
-        }
-        if (this.selectCallback) {
-          this.selectCallback(item, isSelected);
-        }
-      }
-    }
-  },
-  select: function(item) {
-    if (this.multi) {
-      this.toggle(item);
-    } else if (this.get() !== item) {
-      this.setItemSelected(this.get(), false);
-      this.setItemSelected(item, true);
-    }
-  },
-  toggle: function(item) {
-    this.setItemSelected(item, !this.isSelected(item));
-  }
-};
-
-Polymer.IronSelectableBehavior = {
-  properties: {
-    attrForSelected: {
-      type: String,
-      value: null
-    },
-    selected: {
-      type: String,
-      notify: true
-    },
-    selectedItem: {
-      type: Object,
-      readOnly: true,
-      notify: true
-    },
-    activateEvent: {
-      type: String,
-      value: 'tap',
-      observer: '_activateEventChanged'
-    },
-    selectable: String,
-    selectedClass: {
-      type: String,
-      value: 'iron-selected'
-    },
-    selectedAttribute: {
-      type: String,
-      value: null
-    },
-    fallbackSelection: {
-      type: String,
-      value: null
-    },
-    items: {
-      type: Array,
-      readOnly: true,
-      notify: true,
-      value: function() {
-        return [];
-      }
-    },
-    _excludedLocalNames: {
-      type: Object,
-      value: function() {
-        return {
-          template: 1
-        };
-      }
-    }
-  },
-  observers: [ '_updateAttrForSelected(attrForSelected)', '_updateSelected(selected)', '_checkFallback(fallbackSelection)' ],
-  created: function() {
-    this._bindFilterItem = this._filterItem.bind(this);
-    this._selection = new Polymer.IronSelection(this._applySelection.bind(this));
-  },
-  attached: function() {
-    this._observer = this._observeItems(this);
-    this._updateItems();
-    if (!this._shouldUpdateSelection) {
-      this._updateSelected();
-    }
-    this._addListener(this.activateEvent);
-  },
-  detached: function() {
-    if (this._observer) {
-      Polymer.dom(this).unobserveNodes(this._observer);
-    }
-    this._removeListener(this.activateEvent);
-  },
-  indexOf: function(item) {
-    return this.items.indexOf(item);
-  },
-  select: function(value) {
-    this.selected = value;
-  },
-  selectPrevious: function() {
-    var length = this.items.length;
-    var index = (Number(this._valueToIndex(this.selected)) - 1 + length) % length;
-    this.selected = this._indexToValue(index);
-  },
-  selectNext: function() {
-    var index = (Number(this._valueToIndex(this.selected)) + 1) % this.items.length;
-    this.selected = this._indexToValue(index);
-  },
-  selectIndex: function(index) {
-    this.select(this._indexToValue(index));
-  },
-  forceSynchronousItemUpdate: function() {
-    this._updateItems();
-  },
-  get _shouldUpdateSelection() {
-    return this.selected != null;
-  },
-  _checkFallback: function() {
-    if (this._shouldUpdateSelection) {
-      this._updateSelected();
-    }
-  },
-  _addListener: function(eventName) {
-    this.listen(this, eventName, '_activateHandler');
-  },
-  _removeListener: function(eventName) {
-    this.unlisten(this, eventName, '_activateHandler');
-  },
-  _activateEventChanged: function(eventName, old) {
-    this._removeListener(old);
-    this._addListener(eventName);
-  },
-  _updateItems: function() {
-    var nodes = Polymer.dom(this).queryDistributedElements(this.selectable || '*');
-    nodes = Array.prototype.filter.call(nodes, this._bindFilterItem);
-    this._setItems(nodes);
-  },
-  _updateAttrForSelected: function() {
-    if (this._shouldUpdateSelection) {
-      this.selected = this._indexToValue(this.indexOf(this.selectedItem));
-    }
-  },
-  _updateSelected: function() {
-    this._selectSelected(this.selected);
-  },
-  _selectSelected: function(selected) {
-    this._selection.select(this._valueToItem(this.selected));
-    if (this.fallbackSelection && this.items.length && this._selection.get() === undefined) {
-      this.selected = this.fallbackSelection;
-    }
-  },
-  _filterItem: function(node) {
-    return !this._excludedLocalNames[node.localName];
-  },
-  _valueToItem: function(value) {
-    return value == null ? null : this.items[this._valueToIndex(value)];
-  },
-  _valueToIndex: function(value) {
-    if (this.attrForSelected) {
-      for (var i = 0, item; item = this.items[i]; i++) {
-        if (this._valueForItem(item) == value) {
-          return i;
-        }
-      }
-    } else {
-      return Number(value);
-    }
-  },
-  _indexToValue: function(index) {
-    if (this.attrForSelected) {
-      var item = this.items[index];
-      if (item) {
-        return this._valueForItem(item);
-      }
-    } else {
-      return index;
-    }
-  },
-  _valueForItem: function(item) {
-    var propValue = item[Polymer.CaseMap.dashToCamelCase(this.attrForSelected)];
-    return propValue != undefined ? propValue : item.getAttribute(this.attrForSelected);
-  },
-  _applySelection: function(item, isSelected) {
-    if (this.selectedClass) {
-      this.toggleClass(this.selectedClass, isSelected, item);
-    }
-    if (this.selectedAttribute) {
-      this.toggleAttribute(this.selectedAttribute, isSelected, item);
-    }
-    this._selectionChange();
-    this.fire('iron-' + (isSelected ? 'select' : 'deselect'), {
-      item: item
-    });
-  },
-  _selectionChange: function() {
-    this._setSelectedItem(this._selection.get());
-  },
-  _observeItems: function(node) {
-    return Polymer.dom(node).observeNodes(function(mutation) {
-      this._updateItems();
-      if (this._shouldUpdateSelection) {
-        this._updateSelected();
-      }
-      this.fire('iron-items-changed', mutation, {
-        bubbles: false,
-        cancelable: false
-      });
-    });
-  },
-  _activateHandler: function(e) {
-    var t = e.target;
-    var items = this.items;
-    while (t && t != this) {
-      var i = items.indexOf(t);
-      if (i >= 0) {
-        var value = this._indexToValue(i);
-        this._itemActivate(value, t);
-        return;
-      }
-      t = t.parentNode;
-    }
-  },
-  _itemActivate: function(value, item) {
-    if (!this.fire('iron-activate', {
-      selected: value,
-      item: item
-    }, {
-      cancelable: true
-    }).defaultPrevented) {
-      this.select(value);
-    }
-  }
-};
-
-Polymer.IronMultiSelectableBehaviorImpl = {
-  properties: {
-    multi: {
-      type: Boolean,
-      value: false,
-      observer: 'multiChanged'
-    },
-    selectedValues: {
-      type: Array,
-      notify: true
-    },
-    selectedItems: {
-      type: Array,
-      readOnly: true,
-      notify: true
-    }
-  },
-  observers: [ '_updateSelected(selectedValues.splices)' ],
-  select: function(value) {
-    if (this.multi) {
-      if (this.selectedValues) {
-        this._toggleSelected(value);
-      } else {
-        this.selectedValues = [ value ];
-      }
-    } else {
-      this.selected = value;
-    }
-  },
-  multiChanged: function(multi) {
-    this._selection.multi = multi;
-  },
-  get _shouldUpdateSelection() {
-    return this.selected != null || this.selectedValues != null && this.selectedValues.length;
-  },
-  _updateAttrForSelected: function() {
-    if (!this.multi) {
-      Polymer.IronSelectableBehavior._updateAttrForSelected.apply(this);
-    } else if (this._shouldUpdateSelection) {
-      this.selectedValues = this.selectedItems.map(function(selectedItem) {
-        return this._indexToValue(this.indexOf(selectedItem));
-      }, this).filter(function(unfilteredValue) {
-        return unfilteredValue != null;
-      }, this);
-    }
-  },
-  _updateSelected: function() {
-    if (this.multi) {
-      this._selectMulti(this.selectedValues);
-    } else {
-      this._selectSelected(this.selected);
-    }
-  },
-  _selectMulti: function(values) {
-    if (values) {
-      var selectedItems = this._valuesToItems(values);
-      this._selection.clear(selectedItems);
-      for (var i = 0; i < selectedItems.length; i++) {
-        this._selection.setItemSelected(selectedItems[i], true);
-      }
-      if (this.fallbackSelection && this.items.length && !this._selection.get().length) {
-        var fallback = this._valueToItem(this.fallbackSelection);
-        if (fallback) {
-          this.selectedValues = [ this.fallbackSelection ];
-        }
-      }
-    } else {
-      this._selection.clear();
-    }
-  },
-  _selectionChange: function() {
-    var s = this._selection.get();
-    if (this.multi) {
-      this._setSelectedItems(s);
-    } else {
-      this._setSelectedItems([ s ]);
-      this._setSelectedItem(s);
-    }
-  },
-  _toggleSelected: function(value) {
-    var i = this.selectedValues.indexOf(value);
-    var unselected = i < 0;
-    if (unselected) {
-      this.push('selectedValues', value);
-    } else {
-      this.splice('selectedValues', i, 1);
-    }
-  },
-  _valuesToItems: function(values) {
-    return values == null ? null : values.map(function(value) {
-      return this._valueToItem(value);
-    }, this);
-  }
-};
-
-Polymer.IronMultiSelectableBehavior = [ Polymer.IronSelectableBehavior, Polymer.IronMultiSelectableBehaviorImpl ];
-
-Polymer.IronMenuBehaviorImpl = {
-  properties: {
-    focusedItem: {
-      observer: '_focusedItemChanged',
-      readOnly: true,
-      type: Object
-    },
-    attrForItemTitle: {
-      type: String
-    }
-  },
-  hostAttributes: {
-    role: 'menu',
-    tabindex: '0'
-  },
-  observers: [ '_updateMultiselectable(multi)' ],
-  listeners: {
-    focus: '_onFocus',
-    keydown: '_onKeydown',
-    'iron-items-changed': '_onIronItemsChanged'
-  },
-  keyBindings: {
-    up: '_onUpKey',
-    down: '_onDownKey',
-    esc: '_onEscKey',
-    'shift+tab:keydown': '_onShiftTabDown'
-  },
-  attached: function() {
-    this._resetTabindices();
-  },
-  select: function(value) {
-    if (this._defaultFocusAsync) {
-      this.cancelAsync(this._defaultFocusAsync);
-      this._defaultFocusAsync = null;
-    }
-    var item = this._valueToItem(value);
-    if (item && item.hasAttribute('disabled')) return;
-    this._setFocusedItem(item);
-    Polymer.IronMultiSelectableBehaviorImpl.select.apply(this, arguments);
-  },
-  _resetTabindices: function() {
-    var selectedItem = this.multi ? this.selectedItems && this.selectedItems[0] : this.selectedItem;
-    this.items.forEach(function(item) {
-      item.setAttribute('tabindex', item === selectedItem ? '0' : '-1');
-    }, this);
-  },
-  _updateMultiselectable: function(multi) {
-    if (multi) {
-      this.setAttribute('aria-multiselectable', 'true');
-    } else {
-      this.removeAttribute('aria-multiselectable');
-    }
-  },
-  _focusWithKeyboardEvent: function(event) {
-    for (var i = 0, item; item = this.items[i]; i++) {
-      var attr = this.attrForItemTitle || 'textContent';
-      var title = item[attr] || item.getAttribute(attr);
-      if (!item.hasAttribute('disabled') && title && title.trim().charAt(0).toLowerCase() === String.fromCharCode(event.keyCode).toLowerCase()) {
-        this._setFocusedItem(item);
-        break;
-      }
-    }
-  },
-  _focusPrevious: function() {
-    var length = this.items.length;
-    var curFocusIndex = Number(this.indexOf(this.focusedItem));
-    for (var i = 1; i < length + 1; i++) {
-      var item = this.items[(curFocusIndex - i + length) % length];
-      if (!item.hasAttribute('disabled')) {
-        var owner = Polymer.dom(item).getOwnerRoot() || document;
-        this._setFocusedItem(item);
-        if (Polymer.dom(owner).activeElement == item) {
-          return;
-        }
-      }
-    }
-  },
-  _focusNext: function() {
-    var length = this.items.length;
-    var curFocusIndex = Number(this.indexOf(this.focusedItem));
-    for (var i = 1; i < length + 1; i++) {
-      var item = this.items[(curFocusIndex + i) % length];
-      if (!item.hasAttribute('disabled')) {
-        var owner = Polymer.dom(item).getOwnerRoot() || document;
-        this._setFocusedItem(item);
-        if (Polymer.dom(owner).activeElement == item) {
-          return;
-        }
-      }
-    }
-  },
-  _applySelection: function(item, isSelected) {
-    if (isSelected) {
-      item.setAttribute('aria-selected', 'true');
-    } else {
-      item.removeAttribute('aria-selected');
-    }
-    Polymer.IronSelectableBehavior._applySelection.apply(this, arguments);
-  },
-  _focusedItemChanged: function(focusedItem, old) {
-    old && old.setAttribute('tabindex', '-1');
-    if (focusedItem) {
-      focusedItem.setAttribute('tabindex', '0');
-      focusedItem.focus();
-    }
-  },
-  _onIronItemsChanged: function(event) {
-    if (event.detail.addedNodes.length) {
-      this._resetTabindices();
-    }
-  },
-  _onShiftTabDown: function(event) {
-    var oldTabIndex = this.getAttribute('tabindex');
-    Polymer.IronMenuBehaviorImpl._shiftTabPressed = true;
-    this._setFocusedItem(null);
-    this.setAttribute('tabindex', '-1');
-    this.async(function() {
-      this.setAttribute('tabindex', oldTabIndex);
-      Polymer.IronMenuBehaviorImpl._shiftTabPressed = false;
-    }, 1);
-  },
-  _onFocus: function(event) {
-    if (Polymer.IronMenuBehaviorImpl._shiftTabPressed) {
-      return;
-    }
-    var rootTarget = Polymer.dom(event).rootTarget;
-    if (rootTarget !== this && typeof rootTarget.tabIndex !== "undefined" && !this.isLightDescendant(rootTarget)) {
-      return;
-    }
-    this._defaultFocusAsync = this.async(function() {
-      var selectedItem = this.multi ? this.selectedItems && this.selectedItems[0] : this.selectedItem;
-      this._setFocusedItem(null);
-      if (selectedItem) {
-        this._setFocusedItem(selectedItem);
-      } else if (this.items[0]) {
-        this._focusNext();
-      }
-    });
-  },
-  _onUpKey: function(event) {
-    this._focusPrevious();
-    event.detail.keyboardEvent.preventDefault();
-  },
-  _onDownKey: function(event) {
-    this._focusNext();
-    event.detail.keyboardEvent.preventDefault();
-  },
-  _onEscKey: function(event) {
-    this.focusedItem.blur();
-  },
-  _onKeydown: function(event) {
-    if (!this.keyboardEventMatchesKeys(event, 'up down esc')) {
-      this._focusWithKeyboardEvent(event);
-    }
-    event.stopPropagation();
-  },
-  _activateHandler: function(event) {
-    Polymer.IronSelectableBehavior._activateHandler.call(this, event);
-    event.stopPropagation();
-  }
-};
-
-Polymer.IronMenuBehaviorImpl._shiftTabPressed = false;
-
-Polymer.IronMenuBehavior = [ Polymer.IronMultiSelectableBehavior, Polymer.IronA11yKeysBehavior, Polymer.IronMenuBehaviorImpl ];
-
-(function() {
-  Polymer({
-    is: 'paper-menu',
-    behaviors: [ Polymer.IronMenuBehavior ]
-  });
-})();
-
-Polymer.IronFitBehavior = {
-  properties: {
-    sizingTarget: {
-      type: Object,
-      value: function() {
-        return this;
-      }
-    },
-    fitInto: {
-      type: Object,
-      value: window
-    },
-    noOverlap: {
-      type: Boolean
-    },
-    positionTarget: {
-      type: Element
-    },
-    horizontalAlign: {
-      type: String
-    },
-    verticalAlign: {
-      type: String
-    },
-    dynamicAlign: {
-      type: Boolean
-    },
-    horizontalOffset: {
-      type: Number,
-      value: 0,
-      notify: true
-    },
-    verticalOffset: {
-      type: Number,
-      value: 0,
-      notify: true
-    },
-    autoFitOnAttach: {
-      type: Boolean,
-      value: false
-    },
-    _fitInfo: {
-      type: Object
-    }
-  },
-  get _fitWidth() {
-    var fitWidth;
-    if (this.fitInto === window) {
-      fitWidth = this.fitInto.innerWidth;
-    } else {
-      fitWidth = this.fitInto.getBoundingClientRect().width;
-    }
-    return fitWidth;
-  },
-  get _fitHeight() {
-    var fitHeight;
-    if (this.fitInto === window) {
-      fitHeight = this.fitInto.innerHeight;
-    } else {
-      fitHeight = this.fitInto.getBoundingClientRect().height;
-    }
-    return fitHeight;
-  },
-  get _fitLeft() {
-    var fitLeft;
-    if (this.fitInto === window) {
-      fitLeft = 0;
-    } else {
-      fitLeft = this.fitInto.getBoundingClientRect().left;
-    }
-    return fitLeft;
-  },
-  get _fitTop() {
-    var fitTop;
-    if (this.fitInto === window) {
-      fitTop = 0;
-    } else {
-      fitTop = this.fitInto.getBoundingClientRect().top;
-    }
-    return fitTop;
-  },
-  get _defaultPositionTarget() {
-    var parent = Polymer.dom(this).parentNode;
-    if (parent && parent.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
-      parent = parent.host;
-    }
-    return parent;
-  },
-  get _localeHorizontalAlign() {
-    if (this._isRTL) {
-      if (this.horizontalAlign === 'right') {
-        return 'left';
-      }
-      if (this.horizontalAlign === 'left') {
-        return 'right';
-      }
-    }
-    return this.horizontalAlign;
-  },
-  attached: function() {
-    this._isRTL = window.getComputedStyle(this).direction == 'rtl';
-    this.positionTarget = this.positionTarget || this._defaultPositionTarget;
-    if (this.autoFitOnAttach) {
-      if (window.getComputedStyle(this).display === 'none') {
-        setTimeout(function() {
-          this.fit();
-        }.bind(this));
-      } else {
-        this.fit();
-      }
-    }
-  },
-  fit: function() {
-    this.position();
-    this.constrain();
-    this.center();
-  },
-  _discoverInfo: function() {
-    if (this._fitInfo) {
-      return;
-    }
-    var target = window.getComputedStyle(this);
-    var sizer = window.getComputedStyle(this.sizingTarget);
-    this._fitInfo = {
-      inlineStyle: {
-        top: this.style.top || '',
-        left: this.style.left || '',
-        position: this.style.position || ''
-      },
-      sizerInlineStyle: {
-        maxWidth: this.sizingTarget.style.maxWidth || '',
-        maxHeight: this.sizingTarget.style.maxHeight || '',
-        boxSizing: this.sizingTarget.style.boxSizing || ''
-      },
-      positionedBy: {
-        vertically: target.top !== 'auto' ? 'top' : target.bottom !== 'auto' ? 'bottom' : null,
-        horizontally: target.left !== 'auto' ? 'left' : target.right !== 'auto' ? 'right' : null
-      },
-      sizedBy: {
-        height: sizer.maxHeight !== 'none',
-        width: sizer.maxWidth !== 'none',
-        minWidth: parseInt(sizer.minWidth, 10) || 0,
-        minHeight: parseInt(sizer.minHeight, 10) || 0
-      },
-      margin: {
-        top: parseInt(target.marginTop, 10) || 0,
-        right: parseInt(target.marginRight, 10) || 0,
-        bottom: parseInt(target.marginBottom, 10) || 0,
-        left: parseInt(target.marginLeft, 10) || 0
-      }
-    };
-    if (this.verticalOffset) {
-      this._fitInfo.margin.top = this._fitInfo.margin.bottom = this.verticalOffset;
-      this._fitInfo.inlineStyle.marginTop = this.style.marginTop || '';
-      this._fitInfo.inlineStyle.marginBottom = this.style.marginBottom || '';
-      this.style.marginTop = this.style.marginBottom = this.verticalOffset + 'px';
-    }
-    if (this.horizontalOffset) {
-      this._fitInfo.margin.left = this._fitInfo.margin.right = this.horizontalOffset;
-      this._fitInfo.inlineStyle.marginLeft = this.style.marginLeft || '';
-      this._fitInfo.inlineStyle.marginRight = this.style.marginRight || '';
-      this.style.marginLeft = this.style.marginRight = this.horizontalOffset + 'px';
-    }
-  },
-  resetFit: function() {
-    var info = this._fitInfo || {};
-    for (var property in info.sizerInlineStyle) {
-      this.sizingTarget.style[property] = info.sizerInlineStyle[property];
-    }
-    for (var property in info.inlineStyle) {
-      this.style[property] = info.inlineStyle[property];
-    }
-    this._fitInfo = null;
-  },
-  refit: function() {
-    var scrollLeft = this.sizingTarget.scrollLeft;
-    var scrollTop = this.sizingTarget.scrollTop;
-    this.resetFit();
-    this.fit();
-    this.sizingTarget.scrollLeft = scrollLeft;
-    this.sizingTarget.scrollTop = scrollTop;
-  },
-  position: function() {
-    if (!this.horizontalAlign && !this.verticalAlign) {
-      return;
-    }
-    this._discoverInfo();
-    this.style.position = 'fixed';
-    this.sizingTarget.style.boxSizing = 'border-box';
-    this.style.left = '0px';
-    this.style.top = '0px';
-    var rect = this.getBoundingClientRect();
-    var positionRect = this.__getNormalizedRect(this.positionTarget);
-    var fitRect = this.__getNormalizedRect(this.fitInto);
-    var margin = this._fitInfo.margin;
-    var size = {
-      width: rect.width + margin.left + margin.right,
-      height: rect.height + margin.top + margin.bottom
-    };
-    var position = this.__getPosition(this._localeHorizontalAlign, this.verticalAlign, size, positionRect, fitRect);
-    var left = position.left + margin.left;
-    var top = position.top + margin.top;
-    var right = Math.min(fitRect.right - margin.right, left + rect.width);
-    var bottom = Math.min(fitRect.bottom - margin.bottom, top + rect.height);
-    var minWidth = this._fitInfo.sizedBy.minWidth;
-    var minHeight = this._fitInfo.sizedBy.minHeight;
-    if (left < margin.left) {
-      left = margin.left;
-      if (right - left < minWidth) {
-        left = right - minWidth;
-      }
-    }
-    if (top < margin.top) {
-      top = margin.top;
-      if (bottom - top < minHeight) {
-        top = bottom - minHeight;
-      }
-    }
-    this.sizingTarget.style.maxWidth = right - left + 'px';
-    this.sizingTarget.style.maxHeight = bottom - top + 'px';
-    this.style.left = left - rect.left + 'px';
-    this.style.top = top - rect.top + 'px';
-  },
-  constrain: function() {
-    if (this.horizontalAlign || this.verticalAlign) {
-      return;
-    }
-    this._discoverInfo();
-    var info = this._fitInfo;
-    if (!info.positionedBy.vertically) {
-      this.style.position = 'fixed';
-      this.style.top = '0px';
-    }
-    if (!info.positionedBy.horizontally) {
-      this.style.position = 'fixed';
-      this.style.left = '0px';
-    }
-    this.sizingTarget.style.boxSizing = 'border-box';
-    var rect = this.getBoundingClientRect();
-    if (!info.sizedBy.height) {
-      this.__sizeDimension(rect, info.positionedBy.vertically, 'top', 'bottom', 'Height');
-    }
-    if (!info.sizedBy.width) {
-      this.__sizeDimension(rect, info.positionedBy.horizontally, 'left', 'right', 'Width');
-    }
-  },
-  _sizeDimension: function(rect, positionedBy, start, end, extent) {
-    this.__sizeDimension(rect, positionedBy, start, end, extent);
-  },
-  __sizeDimension: function(rect, positionedBy, start, end, extent) {
-    var info = this._fitInfo;
-    var fitRect = this.__getNormalizedRect(this.fitInto);
-    var max = extent === 'Width' ? fitRect.width : fitRect.height;
-    var flip = positionedBy === end;
-    var offset = flip ? max - rect[end] : rect[start];
-    var margin = info.margin[flip ? start : end];
-    var offsetExtent = 'offset' + extent;
-    var sizingOffset = this[offsetExtent] - this.sizingTarget[offsetExtent];
-    this.sizingTarget.style['max' + extent] = max - margin - offset - sizingOffset + 'px';
-  },
-  center: function() {
-    if (this.horizontalAlign || this.verticalAlign) {
-      return;
-    }
-    this._discoverInfo();
-    var positionedBy = this._fitInfo.positionedBy;
-    if (positionedBy.vertically && positionedBy.horizontally) {
-      return;
-    }
-    this.style.position = 'fixed';
-    if (!positionedBy.vertically) {
-      this.style.top = '0px';
-    }
-    if (!positionedBy.horizontally) {
-      this.style.left = '0px';
-    }
-    var rect = this.getBoundingClientRect();
-    var fitRect = this.__getNormalizedRect(this.fitInto);
-    if (!positionedBy.vertically) {
-      var top = fitRect.top - rect.top + (fitRect.height - rect.height) / 2;
-      this.style.top = top + 'px';
-    }
-    if (!positionedBy.horizontally) {
-      var left = fitRect.left - rect.left + (fitRect.width - rect.width) / 2;
-      this.style.left = left + 'px';
-    }
-  },
-  __getNormalizedRect: function(target) {
-    if (target === document.documentElement || target === window) {
-      return {
-        top: 0,
-        left: 0,
-        width: window.innerWidth,
-        height: window.innerHeight,
-        right: window.innerWidth,
-        bottom: window.innerHeight
-      };
-    }
-    return target.getBoundingClientRect();
-  },
-  __getCroppedArea: function(position, size, fitRect) {
-    var verticalCrop = Math.min(0, position.top) + Math.min(0, fitRect.bottom - (position.top + size.height));
-    var horizontalCrop = Math.min(0, position.left) + Math.min(0, fitRect.right - (position.left + size.width));
-    return Math.abs(verticalCrop) * size.width + Math.abs(horizontalCrop) * size.height;
-  },
-  __getPosition: function(hAlign, vAlign, size, positionRect, fitRect) {
-    var positions = [ {
-      verticalAlign: 'top',
-      horizontalAlign: 'left',
-      top: positionRect.top,
-      left: positionRect.left
-    }, {
-      verticalAlign: 'top',
-      horizontalAlign: 'right',
-      top: positionRect.top,
-      left: positionRect.right - size.width
-    }, {
-      verticalAlign: 'bottom',
-      horizontalAlign: 'left',
-      top: positionRect.bottom - size.height,
-      left: positionRect.left
-    }, {
-      verticalAlign: 'bottom',
-      horizontalAlign: 'right',
-      top: positionRect.bottom - size.height,
-      left: positionRect.right - size.width
-    } ];
-    if (this.noOverlap) {
-      for (var i = 0, l = positions.length; i < l; i++) {
-        var copy = {};
-        for (var key in positions[i]) {
-          copy[key] = positions[i][key];
-        }
-        positions.push(copy);
-      }
-      positions[0].top = positions[1].top += positionRect.height;
-      positions[2].top = positions[3].top -= positionRect.height;
-      positions[4].left = positions[6].left += positionRect.width;
-      positions[5].left = positions[7].left -= positionRect.width;
-    }
-    vAlign = vAlign === 'auto' ? null : vAlign;
-    hAlign = hAlign === 'auto' ? null : hAlign;
-    var position;
-    for (var i = 0; i < positions.length; i++) {
-      var pos = positions[i];
-      if (!this.dynamicAlign && !this.noOverlap && pos.verticalAlign === vAlign && pos.horizontalAlign === hAlign) {
-        position = pos;
-        break;
-      }
-      var alignOk = (!vAlign || pos.verticalAlign === vAlign) && (!hAlign || pos.horizontalAlign === hAlign);
-      if (!this.dynamicAlign && !alignOk) {
-        continue;
-      }
-      position = position || pos;
-      pos.croppedArea = this.__getCroppedArea(pos, size, fitRect);
-      var diff = pos.croppedArea - position.croppedArea;
-      if (diff < 0 || diff === 0 && alignOk) {
-        position = pos;
-      }
-      if (position.croppedArea === 0 && alignOk) {
-        break;
-      }
-    }
-    return position;
-  }
-};
-
-(function() {
-  'use strict';
-  Polymer({
-    is: 'iron-overlay-backdrop',
-    properties: {
-      opened: {
-        reflectToAttribute: true,
-        type: Boolean,
-        value: false,
-        observer: '_openedChanged'
-      }
-    },
-    listeners: {
-      transitionend: '_onTransitionend'
-    },
-    created: function() {
-      this.__openedRaf = null;
-    },
-    attached: function() {
-      this.opened && this._openedChanged(this.opened);
-    },
-    prepare: function() {
-      if (this.opened && !this.parentNode) {
-        Polymer.dom(document.body).appendChild(this);
-      }
-    },
-    open: function() {
-      this.opened = true;
-    },
-    close: function() {
-      this.opened = false;
-    },
-    complete: function() {
-      if (!this.opened && this.parentNode === document.body) {
-        Polymer.dom(this.parentNode).removeChild(this);
-      }
-    },
-    _onTransitionend: function(event) {
-      if (event && event.target === this) {
-        this.complete();
-      }
-    },
-    _openedChanged: function(opened) {
-      if (opened) {
-        this.prepare();
-      } else {
-        var cs = window.getComputedStyle(this);
-        if (cs.transitionDuration === '0s' || cs.opacity == 0) {
-          this.complete();
-        }
-      }
-      if (!this.isAttached) {
-        return;
-      }
-      if (this.__openedRaf) {
-        window.cancelAnimationFrame(this.__openedRaf);
-        this.__openedRaf = null;
-      }
-      this.scrollTop = this.scrollTop;
-      this.__openedRaf = window.requestAnimationFrame(function() {
-        this.__openedRaf = null;
-        this.toggleClass('opened', this.opened);
-      }.bind(this));
-    }
-  });
-})();
-
-Polymer.IronOverlayManagerClass = function() {
-  this._overlays = [];
-  this._minimumZ = 101;
-  this._backdropElement = null;
-  Polymer.Gestures.add(document, 'tap', this._onCaptureClick.bind(this));
-  document.addEventListener('focus', this._onCaptureFocus.bind(this), true);
-  document.addEventListener('keydown', this._onCaptureKeyDown.bind(this), true);
-};
-
-Polymer.IronOverlayManagerClass.prototype = {
-  constructor: Polymer.IronOverlayManagerClass,
-  get backdropElement() {
-    if (!this._backdropElement) {
-      this._backdropElement = document.createElement('iron-overlay-backdrop');
-    }
-    return this._backdropElement;
-  },
-  get deepActiveElement() {
-    var active = document.activeElement || document.body;
-    while (active.root && Polymer.dom(active.root).activeElement) {
-      active = Polymer.dom(active.root).activeElement;
-    }
-    return active;
-  },
-  _bringOverlayAtIndexToFront: function(i) {
-    var overlay = this._overlays[i];
-    if (!overlay) {
-      return;
-    }
-    var lastI = this._overlays.length - 1;
-    var currentOverlay = this._overlays[lastI];
-    if (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay)) {
-      lastI--;
-    }
-    if (i >= lastI) {
-      return;
-    }
-    var minimumZ = Math.max(this.currentOverlayZ(), this._minimumZ);
-    if (this._getZ(overlay) <= minimumZ) {
-      this._applyOverlayZ(overlay, minimumZ);
-    }
-    while (i < lastI) {
-      this._overlays[i] = this._overlays[i + 1];
-      i++;
-    }
-    this._overlays[lastI] = overlay;
-  },
-  addOrRemoveOverlay: function(overlay) {
-    if (overlay.opened) {
-      this.addOverlay(overlay);
-    } else {
-      this.removeOverlay(overlay);
-    }
-  },
-  addOverlay: function(overlay) {
-    var i = this._overlays.indexOf(overlay);
-    if (i >= 0) {
-      this._bringOverlayAtIndexToFront(i);
-      this.trackBackdrop();
-      return;
-    }
-    var insertionIndex = this._overlays.length;
-    var currentOverlay = this._overlays[insertionIndex - 1];
-    var minimumZ = Math.max(this._getZ(currentOverlay), this._minimumZ);
-    var newZ = this._getZ(overlay);
-    if (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay)) {
-      this._applyOverlayZ(currentOverlay, minimumZ);
-      insertionIndex--;
-      var previousOverlay = this._overlays[insertionIndex - 1];
-      minimumZ = Math.max(this._getZ(previousOverlay), this._minimumZ);
-    }
-    if (newZ <= minimumZ) {
-      this._applyOverlayZ(overlay, minimumZ);
-    }
-    this._overlays.splice(insertionIndex, 0, overlay);
-    this.trackBackdrop();
-  },
-  removeOverlay: function(overlay) {
-    var i = this._overlays.indexOf(overlay);
-    if (i === -1) {
-      return;
-    }
-    this._overlays.splice(i, 1);
-    this.trackBackdrop();
-  },
-  currentOverlay: function() {
-    var i = this._overlays.length - 1;
-    return this._overlays[i];
-  },
-  currentOverlayZ: function() {
-    return this._getZ(this.currentOverlay());
-  },
-  ensureMinimumZ: function(minimumZ) {
-    this._minimumZ = Math.max(this._minimumZ, minimumZ);
-  },
-  focusOverlay: function() {
-    var current = this.currentOverlay();
-    if (current) {
-      current._applyFocus();
-    }
-  },
-  trackBackdrop: function() {
-    var overlay = this._overlayWithBackdrop();
-    if (!overlay && !this._backdropElement) {
-      return;
-    }
-    this.backdropElement.style.zIndex = this._getZ(overlay) - 1;
-    this.backdropElement.opened = !!overlay;
-  },
-  getBackdrops: function() {
-    var backdrops = [];
-    for (var i = 0; i < this._overlays.length; i++) {
-      if (this._overlays[i].withBackdrop) {
-        backdrops.push(this._overlays[i]);
-      }
-    }
-    return backdrops;
-  },
-  backdropZ: function() {
-    return this._getZ(this._overlayWithBackdrop()) - 1;
-  },
-  _overlayWithBackdrop: function() {
-    for (var i = 0; i < this._overlays.length; i++) {
-      if (this._overlays[i].withBackdrop) {
-        return this._overlays[i];
-      }
-    }
-  },
-  _getZ: function(overlay) {
-    var z = this._minimumZ;
-    if (overlay) {
-      var z1 = Number(overlay.style.zIndex || window.getComputedStyle(overlay).zIndex);
-      if (z1 === z1) {
-        z = z1;
-      }
-    }
-    return z;
-  },
-  _setZ: function(element, z) {
-    element.style.zIndex = z;
-  },
-  _applyOverlayZ: function(overlay, aboveZ) {
-    this._setZ(overlay, aboveZ + 2);
-  },
-  _overlayInPath: function(path) {
-    path = path || [];
-    for (var i = 0; i < path.length; i++) {
-      if (path[i]._manager === this) {
-        return path[i];
-      }
-    }
-  },
-  _onCaptureClick: function(event) {
-    var overlay = this.currentOverlay();
-    if (overlay && this._overlayInPath(Polymer.dom(event).path) !== overlay) {
-      overlay._onCaptureClick(event);
-    }
-  },
-  _onCaptureFocus: function(event) {
-    var overlay = this.currentOverlay();
-    if (overlay) {
-      overlay._onCaptureFocus(event);
-    }
-  },
-  _onCaptureKeyDown: function(event) {
-    var overlay = this.currentOverlay();
-    if (overlay) {
-      if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 'esc')) {
-        overlay._onCaptureEsc(event);
-      } else if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 'tab')) {
-        overlay._onCaptureTab(event);
-      }
-    }
-  },
-  _shouldBeBehindOverlay: function(overlay1, overlay2) {
-    return !overlay1.alwaysOnTop && overlay2.alwaysOnTop;
-  }
-};
-
-Polymer.IronOverlayManager = new Polymer.IronOverlayManagerClass();
-
-(function() {
-  'use strict';
-  Polymer.IronOverlayBehaviorImpl = {
-    properties: {
-      opened: {
-        observer: '_openedChanged',
-        type: Boolean,
-        value: false,
-        notify: true
-      },
-      canceled: {
-        observer: '_canceledChanged',
-        readOnly: true,
-        type: Boolean,
-        value: false
-      },
-      withBackdrop: {
-        observer: '_withBackdropChanged',
-        type: Boolean
-      },
-      noAutoFocus: {
-        type: Boolean,
-        value: false
-      },
-      noCancelOnEscKey: {
-        type: Boolean,
-        value: false
-      },
-      noCancelOnOutsideClick: {
-        type: Boolean,
-        value: false
-      },
-      closingReason: {
-        type: Object
-      },
-      restoreFocusOnClose: {
-        type: Boolean,
-        value: false
-      },
-      alwaysOnTop: {
-        type: Boolean
-      },
-      _manager: {
-        type: Object,
-        value: Polymer.IronOverlayManager
-      },
-      _focusedChild: {
-        type: Object
-      }
-    },
-    listeners: {
-      'iron-resize': '_onIronResize'
-    },
-    get backdropElement() {
-      return this._manager.backdropElement;
-    },
-    get _focusNode() {
-      return this._focusedChild || Polymer.dom(this).querySelector('[autofocus]') || this;
-    },
-    get _focusableNodes() {
-      var FOCUSABLE_WITH_DISABLED = [ 'a[href]', 'area[href]', 'iframe', '[tabindex]', '[contentEditable=true]' ];
-      var FOCUSABLE_WITHOUT_DISABLED = [ 'input', 'select', 'textarea', 'button' ];
-      var selector = FOCUSABLE_WITH_DISABLED.join(':not([tabindex="-1"]),') + ':not([tabindex="-1"]),' + FOCUSABLE_WITHOUT_DISABLED.join(':not([disabled]):not([tabindex="-1"]),') + ':not([disabled]):not([tabindex="-1"])';
-      var focusables = Polymer.dom(this).querySelectorAll(selector);
-      if (this.tabIndex >= 0) {
-        focusables.splice(0, 0, this);
-      }
-      return focusables.sort(function(a, b) {
-        if (a.tabIndex === b.tabIndex) {
-          return 0;
-        }
-        if (a.tabIndex === 0 || a.tabIndex > b.tabIndex) {
-          return 1;
-        }
-        return -1;
-      });
-    },
-    ready: function() {
-      this.__isAnimating = false;
-      this.__shouldRemoveTabIndex = false;
-      this.__firstFocusableNode = this.__lastFocusableNode = null;
-      this.__raf = null;
-      this.__restoreFocusNode = null;
-      this._ensureSetup();
-    },
-    attached: function() {
-      if (this.opened) {
-        this._openedChanged(this.opened);
-      }
-      this._observer = Polymer.dom(this).observeNodes(this._onNodesChange);
-    },
-    detached: function() {
-      Polymer.dom(this).unobserveNodes(this._observer);
-      this._observer = null;
-      if (this.__raf) {
-        window.cancelAnimationFrame(this.__raf);
-        this.__raf = null;
-      }
-      this._manager.removeOverlay(this);
-    },
-    toggle: function() {
-      this._setCanceled(false);
-      this.opened = !this.opened;
-    },
-    open: function() {
-      this._setCanceled(false);
-      this.opened = true;
-    },
-    close: function() {
-      this._setCanceled(false);
-      this.opened = false;
-    },
-    cancel: function(event) {
-      var cancelEvent = this.fire('iron-overlay-canceled', event, {
-        cancelable: true
-      });
-      if (cancelEvent.defaultPrevented) {
-        return;
-      }
-      this._setCanceled(true);
-      this.opened = false;
-    },
-    _ensureSetup: function() {
-      if (this._overlaySetup) {
-        return;
-      }
-      this._overlaySetup = true;
-      this.style.outline = 'none';
-      this.style.display = 'none';
-    },
-    _openedChanged: function(opened) {
-      if (opened) {
-        this.removeAttribute('aria-hidden');
-      } else {
-        this.setAttribute('aria-hidden', 'true');
-      }
-      if (!this.isAttached) {
-        return;
-      }
-      this.__isAnimating = true;
-      this.__onNextAnimationFrame(this.__openedChanged);
-    },
-    _canceledChanged: function() {
-      this.closingReason = this.closingReason || {};
-      this.closingReason.canceled = this.canceled;
-    },
-    _withBackdropChanged: function() {
-      if (this.withBackdrop && !this.hasAttribute('tabindex')) {
-        this.setAttribute('tabindex', '-1');
-        this.__shouldRemoveTabIndex = true;
-      } else if (this.__shouldRemoveTabIndex) {
-        this.removeAttribute('tabindex');
-        this.__shouldRemoveTabIndex = false;
-      }
-      if (this.opened && this.isAttached) {
-        this._manager.trackBackdrop();
-      }
-    },
-    _prepareRenderOpened: function() {
-      this.__restoreFocusNode = this._manager.deepActiveElement;
-      this._preparePositioning();
-      this.refit();
-      this._finishPositioning();
-      if (this.noAutoFocus && document.activeElement === this._focusNode) {
-        this._focusNode.blur();
-        this.__restoreFocusNode.focus();
-      }
-    },
-    _renderOpened: function() {
-      this._finishRenderOpened();
-    },
-    _renderClosed: function() {
-      this._finishRenderClosed();
-    },
-    _finishRenderOpened: function() {
-      this.notifyResize();
-      this.__isAnimating = false;
-      var focusableNodes = this._focusableNodes;
-      this.__firstFocusableNode = focusableNodes[0];
-      this.__lastFocusableNode = focusableNodes[focusableNodes.length - 1];
-      this.fire('iron-overlay-opened');
-    },
-    _finishRenderClosed: function() {
-      this.style.display = 'none';
-      this.style.zIndex = '';
-      this.notifyResize();
-      this.__isAnimating = false;
-      this.fire('iron-overlay-closed', this.closingReason);
-    },
-    _preparePositioning: function() {
-      this.style.transition = this.style.webkitTransition = 'none';
-      this.style.transform = this.style.webkitTransform = 'none';
-      this.style.display = '';
-    },
-    _finishPositioning: function() {
-      this.style.display = 'none';
-      this.scrollTop = this.scrollTop;
-      this.style.transition = this.style.webkitTransition = '';
-      this.style.transform = this.style.webkitTransform = '';
-      this.style.display = '';
-      this.scrollTop = this.scrollTop;
-    },
-    _applyFocus: function() {
-      if (this.opened) {
-        if (!this.noAutoFocus) {
-          this._focusNode.focus();
-        }
-      } else {
-        this._focusNode.blur();
-        this._focusedChild = null;
-        if (this.restoreFocusOnClose && this.__restoreFocusNode) {
-          this.__restoreFocusNode.focus();
-        }
-        this.__restoreFocusNode = null;
-        var currentOverlay = this._manager.currentOverlay();
-        if (currentOverlay && this !== currentOverlay) {
-          currentOverlay._applyFocus();
-        }
-      }
-    },
-    _onCaptureClick: function(event) {
-      if (!this.noCancelOnOutsideClick) {
-        this.cancel(event);
-      }
-    },
-    _onCaptureFocus: function(event) {
-      if (!this.withBackdrop) {
-        return;
-      }
-      var path = Polymer.dom(event).path;
-      if (path.indexOf(this) === -1) {
-        event.stopPropagation();
-        this._applyFocus();
-      } else {
-        this._focusedChild = path[0];
-      }
-    },
-    _onCaptureEsc: function(event) {
-      if (!this.noCancelOnEscKey) {
-        this.cancel(event);
-      }
-    },
-    _onCaptureTab: function(event) {
-      if (!this.withBackdrop) {
-        return;
-      }
-      var shift = event.shiftKey;
-      var nodeToCheck = shift ? this.__firstFocusableNode : this.__lastFocusableNode;
-      var nodeToSet = shift ? this.__lastFocusableNode : this.__firstFocusableNode;
-      var shouldWrap = false;
-      if (nodeToCheck === nodeToSet) {
-        shouldWrap = true;
-      } else {
-        var focusedNode = this._manager.deepActiveElement;
-        shouldWrap = focusedNode === nodeToCheck || focusedNode === this;
-      }
-      if (shouldWrap) {
-        event.preventDefault();
-        this._focusedChild = nodeToSet;
-        this._applyFocus();
-      }
-    },
-    _onIronResize: function() {
-      if (this.opened && !this.__isAnimating) {
-        this.__onNextAnimationFrame(this.refit);
-      }
-    },
-    _onNodesChange: function() {
-      if (this.opened && !this.__isAnimating) {
-        this.notifyResize();
-      }
-    },
-    __openedChanged: function() {
-      if (this.opened) {
-        this._prepareRenderOpened();
-        this._manager.addOverlay(this);
-        this._applyFocus();
-        this._renderOpened();
-      } else {
-        this._manager.removeOverlay(this);
-        this._applyFocus();
-        this._renderClosed();
-      }
-    },
-    __onNextAnimationFrame: function(callback) {
-      if (this.__raf) {
-        window.cancelAnimationFrame(this.__raf);
-      }
-      var self = this;
-      this.__raf = window.requestAnimationFrame(function nextAnimationFrame() {
-        self.__raf = null;
-        callback.call(self);
-      });
-    }
-  };
-  Polymer.IronOverlayBehavior = [ Polymer.IronFitBehavior, Polymer.IronResizableBehavior, Polymer.IronOverlayBehaviorImpl ];
-})();
-
-Polymer.NeonAnimatableBehavior = {
-  properties: {
-    animationConfig: {
-      type: Object
-    },
-    entryAnimation: {
-      observer: '_entryAnimationChanged',
-      type: String
-    },
-    exitAnimation: {
-      observer: '_exitAnimationChanged',
-      type: String
-    }
-  },
-  _entryAnimationChanged: function() {
-    this.animationConfig = this.animationConfig || {};
-    this.animationConfig['entry'] = [ {
-      name: this.entryAnimation,
-      node: this
-    } ];
-  },
-  _exitAnimationChanged: function() {
-    this.animationConfig = this.animationConfig || {};
-    this.animationConfig['exit'] = [ {
-      name: this.exitAnimation,
-      node: this
-    } ];
-  },
-  _copyProperties: function(config1, config2) {
-    for (var property in config2) {
-      config1[property] = config2[property];
-    }
-  },
-  _cloneConfig: function(config) {
-    var clone = {
-      isClone: true
-    };
-    this._copyProperties(clone, config);
-    return clone;
-  },
-  _getAnimationConfigRecursive: function(type, map, allConfigs) {
-    if (!this.animationConfig) {
-      return;
-    }
-    if (this.animationConfig.value && typeof this.animationConfig.value === 'function') {
-      this._warn(this._logf('playAnimation', "Please put 'animationConfig' inside of your components 'properties' object instead of outside of it."));
-      return;
-    }
-    var thisConfig;
-    if (type) {
-      thisConfig = this.animationConfig[type];
-    } else {
-      thisConfig = this.animationConfig;
-    }
-    if (!Array.isArray(thisConfig)) {
-      thisConfig = [ thisConfig ];
-    }
-    if (thisConfig) {
-      for (var config, index = 0; config = thisConfig[index]; index++) {
-        if (config.animatable) {
-          config.animatable._getAnimationConfigRecursive(config.type || type, map, allConfigs);
-        } else {
-          if (config.id) {
-            var cachedConfig = map[config.id];
-            if (cachedConfig) {
-              if (!cachedConfig.isClone) {
-                map[config.id] = this._cloneConfig(cachedConfig);
-                cachedConfig = map[config.id];
-              }
-              this._copyProperties(cachedConfig, config);
-            } else {
-              map[config.id] = config;
-            }
-          } else {
-            allConfigs.push(config);
-          }
-        }
-      }
-    }
-  },
-  getAnimationConfig: function(type) {
-    var map = {};
-    var allConfigs = [];
-    this._getAnimationConfigRecursive(type, map, allConfigs);
-    for (var key in map) {
-      allConfigs.push(map[key]);
-    }
-    return allConfigs;
-  }
-};
-
-Polymer.NeonAnimationRunnerBehaviorImpl = {
-  _configureAnimations: function(configs) {
-    var results = [];
-    if (configs.length > 0) {
-      for (var config, index = 0; config = configs[index]; index++) {
-        var neonAnimation = document.createElement(config.name);
-        if (neonAnimation.isNeonAnimation) {
-          var result = null;
-          try {
-            result = neonAnimation.configure(config);
-            if (typeof result.cancel != 'function') {
-              result = document.timeline.play(result);
-            }
-          } catch (e) {
-            result = null;
-            console.warn('Couldnt play', '(', config.name, ').', e);
-          }
-          if (result) {
-            results.push({
-              neonAnimation: neonAnimation,
-              config: config,
-              animation: result
-            });
-          }
-        } else {
-          console.warn(this.is + ':', config.name, 'not found!');
-        }
-      }
-    }
-    return results;
-  },
-  _shouldComplete: function(activeEntries) {
-    var finished = true;
-    for (var i = 0; i < activeEntries.length; i++) {
-      if (activeEntries[i].animation.playState != 'finished') {
-        finished = false;
-        break;
-      }
-    }
-    return finished;
-  },
-  _complete: function(activeEntries) {
-    for (var i = 0; i < activeEntries.length; i++) {
-      activeEntries[i].neonAnimation.complete(activeEntries[i].config);
-    }
-    for (var i = 0; i < activeEntries.length; i++) {
-      activeEntries[i].animation.cancel();
-    }
-  },
-  playAnimation: function(type, cookie) {
-    var configs = this.getAnimationConfig(type);
-    if (!configs) {
-      return;
-    }
-    this._active = this._active || {};
-    if (this._active[type]) {
-      this._complete(this._active[type]);
-      delete this._active[type];
-    }
-    var activeEntries = this._configureAnimations(configs);
-    if (activeEntries.length == 0) {
-      this.fire('neon-animation-finish', cookie, {
-        bubbles: false
-      });
-      return;
-    }
-    this._active[type] = activeEntries;
-    for (var i = 0; i < activeEntries.length; i++) {
-      activeEntries[i].animation.onfinish = function() {
-        if (this._shouldComplete(activeEntries)) {
-          this._complete(activeEntries);
-          delete this._active[type];
-          this.fire('neon-animation-finish', cookie, {
-            bubbles: false
-          });
-        }
-      }.bind(this);
-    }
-  },
-  cancelAnimation: function() {
-    for (var k in this._animations) {
-      this._animations[k].cancel();
-    }
-    this._animations = {};
-  }
-};
-
-Polymer.NeonAnimationRunnerBehavior = [ Polymer.NeonAnimatableBehavior, Polymer.NeonAnimationRunnerBehaviorImpl ];
-
-Polymer.NeonAnimationBehavior = {
-  properties: {
-    animationTiming: {
-      type: Object,
-      value: function() {
-        return {
-          duration: 500,
-          easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
-          fill: 'both'
-        };
-      }
-    }
-  },
-  isNeonAnimation: true,
-  timingFromConfig: function(config) {
-    if (config.timing) {
-      for (var property in config.timing) {
-        this.animationTiming[property] = config.timing[property];
-      }
-    }
-    return this.animationTiming;
-  },
-  setPrefixedProperty: function(node, property, value) {
-    var map = {
-      transform: [ 'webkitTransform' ],
-      transformOrigin: [ 'mozTransformOrigin', 'webkitTransformOrigin' ]
-    };
-    var prefixes = map[property];
-    for (var prefix, index = 0; prefix = prefixes[index]; index++) {
-      node.style[prefix] = value;
-    }
-    node.style[property] = value;
-  },
-  complete: function() {}
-};
-
-Polymer({
-  is: 'opaque-animation',
-  behaviors: [ Polymer.NeonAnimationBehavior ],
-  configure: function(config) {
-    var node = config.node;
-    this._effect = new KeyframeEffect(node, [ {
-      opacity: '1'
-    }, {
-      opacity: '1'
-    } ], this.timingFromConfig(config));
-    node.style.opacity = '0';
-    return this._effect;
-  },
-  complete: function(config) {
-    config.node.style.opacity = '';
-  }
-});
-
-(function() {
-  'use strict';
-  var LAST_TOUCH_POSITION = {
-    pageX: 0,
-    pageY: 0
-  };
-  var ROOT_TARGET = null;
-  var SCROLLABLE_NODES = [];
-  Polymer.IronDropdownScrollManager = {
-    get currentLockingElement() {
-      return this._lockingElements[this._lockingElements.length - 1];
-    },
-    elementIsScrollLocked: function(element) {
-      var currentLockingElement = this.currentLockingElement;
-      if (currentLockingElement === undefined) return false;
-      var scrollLocked;
-      if (this._hasCachedLockedElement(element)) {
-        return true;
-      }
-      if (this._hasCachedUnlockedElement(element)) {
-        return false;
-      }
-      scrollLocked = !!currentLockingElement && currentLockingElement !== element && !this._composedTreeContains(currentLockingElement, element);
-      if (scrollLocked) {
-        this._lockedElementCache.push(element);
-      } else {
-        this._unlockedElementCache.push(element);
-      }
-      return scrollLocked;
-    },
-    pushScrollLock: function(element) {
-      if (this._lockingElements.indexOf(element) >= 0) {
-        return;
-      }
-      if (this._lockingElements.length === 0) {
-        this._lockScrollInteractions();
-      }
-      this._lockingElements.push(element);
-      this._lockedElementCache = [];
-      this._unlockedElementCache = [];
-    },
-    removeScrollLock: function(element) {
-      var index = this._lockingElements.indexOf(element);
-      if (index === -1) {
-        return;
-      }
-      this._lockingElements.splice(index, 1);
-      this._lockedElementCache = [];
-      this._unlockedElementCache = [];
-      if (this._lockingElements.length === 0) {
-        this._unlockScrollInteractions();
-      }
-    },
-    _lockingElements: [],
-    _lockedElementCache: null,
-    _unlockedElementCache: null,
-    _hasCachedLockedElement: function(element) {
-      return this._lockedElementCache.indexOf(element) > -1;
-    },
-    _hasCachedUnlockedElement: function(element) {
-      return this._unlockedElementCache.indexOf(element) > -1;
-    },
-    _composedTreeContains: function(element, child) {
-      var contentElements;
-      var distributedNodes;
-      var contentIndex;
-      var nodeIndex;
-      if (element.contains(child)) {
-        return true;
-      }
-      contentElements = Polymer.dom(element).querySelectorAll('content');
-      for (contentIndex = 0; contentIndex < contentElements.length; ++contentIndex) {
-        distributedNodes = Polymer.dom(contentElements[contentIndex]).getDistributedNodes();
-        for (nodeIndex = 0; nodeIndex < distributedNodes.length; ++nodeIndex) {
-          if (this._composedTreeContains(distributedNodes[nodeIndex], child)) {
-            return true;
-          }
-        }
-      }
-      return false;
-    },
-    _scrollInteractionHandler: function(event) {
-      if (event.cancelable && this._shouldPreventScrolling(event)) {
-        event.preventDefault();
-      }
-      if (event.targetTouches) {
-        var touch = event.targetTouches[0];
-        LAST_TOUCH_POSITION.pageX = touch.pageX;
-        LAST_TOUCH_POSITION.pageY = touch.pageY;
-      }
-    },
-    _lockScrollInteractions: function() {
-      this._boundScrollHandler = this._boundScrollHandler || this._scrollInteractionHandler.bind(this);
-      document.addEventListener('wheel', this._boundScrollHandler, true);
-      document.addEventListener('mousewheel', this._boundScrollHandler, true);
-      document.addEventListener('DOMMouseScroll', this._boundScrollHandler, true);
-      document.addEventListener('touchstart', this._boundScrollHandler, true);
-      document.addEventListener('touchmove', this._boundScrollHandler, true);
-    },
-    _unlockScrollInteractions: function() {
-      document.removeEventListener('wheel', this._boundScrollHandler, true);
-      document.removeEventListener('mousewheel', this._boundScrollHandler, true);
-      document.removeEventListener('DOMMouseScroll', this._boundScrollHandler, true);
-      document.removeEventListener('touchstart', this._boundScrollHandler, true);
-      document.removeEventListener('touchmove', this._boundScrollHandler, true);
-    },
-    _shouldPreventScrolling: function(event) {
-      var target = Polymer.dom(event).rootTarget;
-      if (event.type !== 'touchmove' && ROOT_TARGET !== target) {
-        ROOT_TARGET = target;
-        SCROLLABLE_NODES = this._getScrollableNodes(Polymer.dom(event).path);
-      }
-      if (!SCROLLABLE_NODES.length) {
-        return true;
-      }
-      if (event.type === 'touchstart') {
-        return false;
-      }
-      var info = this._getScrollInfo(event);
-      return !this._getScrollingNode(SCROLLABLE_NODES, info.deltaX, info.deltaY);
-    },
-    _getScrollableNodes: function(nodes) {
-      var scrollables = [];
-      var lockingIndex = nodes.indexOf(this.currentLockingElement);
-      for (var i = 0; i <= lockingIndex; i++) {
-        var node = nodes[i];
-        if (node.nodeType === 11) {
-          continue;
-        }
-        var style = node.style;
-        if (style.overflow !== 'scroll' && style.overflow !== 'auto') {
-          style = window.getComputedStyle(node);
-        }
-        if (style.overflow === 'scroll' || style.overflow === 'auto') {
-          scrollables.push(node);
-        }
-      }
-      return scrollables;
-    },
-    _getScrollingNode: function(nodes, deltaX, deltaY) {
-      if (!deltaX && !deltaY) {
-        return;
-      }
-      var verticalScroll = Math.abs(deltaY) >= Math.abs(deltaX);
-      for (var i = 0; i < nodes.length; i++) {
-        var node = nodes[i];
-        var canScroll = false;
-        if (verticalScroll) {
-          canScroll = deltaY < 0 ? node.scrollTop > 0 : node.scrollTop < node.scrollHeight - node.clientHeight;
-        } else {
-          canScroll = deltaX < 0 ? node.scrollLeft > 0 : node.scrollLeft < node.scrollWidth - node.clientWidth;
-        }
-        if (canScroll) {
-          return node;
-        }
-      }
-    },
-    _getScrollInfo: function(event) {
-      var info = {
-        deltaX: event.deltaX,
-        deltaY: event.deltaY
-      };
-      if ('deltaX' in event) {} else if ('wheelDeltaX' in event) {
-        info.deltaX = -event.wheelDeltaX;
-        info.deltaY = -event.wheelDeltaY;
-      } else if ('axis' in event) {
-        info.deltaX = event.axis === 1 ? event.detail : 0;
-        info.deltaY = event.axis === 2 ? event.detail : 0;
-      } else if (event.targetTouches) {
-        var touch = event.targetTouches[0];
-        info.deltaX = LAST_TOUCH_POSITION.pageX - touch.pageX;
-        info.deltaY = LAST_TOUCH_POSITION.pageY - touch.pageY;
-      }
-      return info;
-    }
-  };
-})();
-
-(function() {
-  'use strict';
-  Polymer({
-    is: 'iron-dropdown',
-    behaviors: [ Polymer.IronControlState, Polymer.IronA11yKeysBehavior, Polymer.IronOverlayBehavior, Polymer.NeonAnimationRunnerBehavior ],
-    properties: {
-      horizontalAlign: {
-        type: String,
-        value: 'left',
-        reflectToAttribute: true
-      },
-      verticalAlign: {
-        type: String,
-        value: 'top',
-        reflectToAttribute: true
-      },
-      openAnimationConfig: {
-        type: Object
-      },
-      closeAnimationConfig: {
-        type: Object
-      },
-      focusTarget: {
-        type: Object
-      },
-      noAnimations: {
-        type: Boolean,
-        value: false
-      },
-      allowOutsideScroll: {
-        type: Boolean,
-        value: false
-      },
-      _boundOnCaptureScroll: {
-        type: Function,
-        value: function() {
-          return this._onCaptureScroll.bind(this);
-        }
-      }
-    },
-    listeners: {
-      'neon-animation-finish': '_onNeonAnimationFinish'
-    },
-    observers: [ '_updateOverlayPosition(positionTarget, verticalAlign, horizontalAlign, verticalOffset, horizontalOffset)' ],
-    get containedElement() {
-      return Polymer.dom(this.$.content).getDistributedNodes()[0];
-    },
-    get _focusTarget() {
-      return this.focusTarget || this.containedElement;
-    },
-    ready: function() {
-      this._scrollTop = 0;
-      this._scrollLeft = 0;
-      this._refitOnScrollRAF = null;
-    },
-    attached: function() {
-      if (!this.sizingTarget || this.sizingTarget === this) {
-        this.sizingTarget = this.containedElement;
-      }
-    },
-    detached: function() {
-      this.cancelAnimation();
-      document.removeEventListener('scroll', this._boundOnCaptureScroll);
-      Polymer.IronDropdownScrollManager.removeScrollLock(this);
-    },
-    _openedChanged: function() {
-      if (this.opened && this.disabled) {
-        this.cancel();
-      } else {
-        this.cancelAnimation();
-        this._updateAnimationConfig();
-        this._saveScrollPosition();
-        if (this.opened) {
-          document.addEventListener('scroll', this._boundOnCaptureScroll);
-          !this.allowOutsideScroll && Polymer.IronDropdownScrollManager.pushScrollLock(this);
-        } else {
-          document.removeEventListener('scroll', this._boundOnCaptureScroll);
-          Polymer.IronDropdownScrollManager.removeScrollLock(this);
-        }
-        Polymer.IronOverlayBehaviorImpl._openedChanged.apply(this, arguments);
-      }
-    },
-    _renderOpened: function() {
-      if (!this.noAnimations && this.animationConfig.open) {
-        this.$.contentWrapper.classList.add('animating');
-        this.playAnimation('open');
-      } else {
-        Polymer.IronOverlayBehaviorImpl._renderOpened.apply(this, arguments);
-      }
-    },
-    _renderClosed: function() {
-      if (!this.noAnimations && this.animationConfig.close) {
-        this.$.contentWrapper.classList.add('animating');
-        this.playAnimation('close');
-      } else {
-        Polymer.IronOverlayBehaviorImpl._renderClosed.apply(this, arguments);
-      }
-    },
-    _onNeonAnimationFinish: function() {
-      this.$.contentWrapper.classList.remove('animating');
-      if (this.opened) {
-        this._finishRenderOpened();
-      } else {
-        this._finishRenderClosed();
-      }
-    },
-    _onCaptureScroll: function() {
-      if (!this.allowOutsideScroll) {
-        this._restoreScrollPosition();
-      } else {
-        this._refitOnScrollRAF && window.cancelAnimationFrame(this._refitOnScrollRAF);
-        this._refitOnScrollRAF = window.requestAnimationFrame(this.refit.bind(this));
-      }
-    },
-    _saveScrollPosition: function() {
-      if (document.scrollingElement) {
-        this._scrollTop = document.scrollingElement.scrollTop;
-        this._scrollLeft = document.scrollingElement.scrollLeft;
-      } else {
-        this._scrollTop = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
-        this._scrollLeft = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft);
-      }
-    },
-    _restoreScrollPosition: function() {
-      if (document.scrollingElement) {
-        document.scrollingElement.scrollTop = this._scrollTop;
-        document.scrollingElement.scrollLeft = this._scrollLeft;
-      } else {
-        document.documentElement.scrollTop = this._scrollTop;
-        document.documentElement.scrollLeft = this._scrollLeft;
-        document.body.scrollTop = this._scrollTop;
-        document.body.scrollLeft = this._scrollLeft;
-      }
-    },
-    _updateAnimationConfig: function() {
-      var animations = (this.openAnimationConfig || []).concat(this.closeAnimationConfig || []);
-      for (var i = 0; i < animations.length; i++) {
-        animations[i].node = this.containedElement;
-      }
-      this.animationConfig = {
-        open: this.openAnimationConfig,
-        close: this.closeAnimationConfig
-      };
-    },
-    _updateOverlayPosition: function() {
-      if (this.isAttached) {
-        this.notifyResize();
-      }
-    },
-    _applyFocus: function() {
-      var focusTarget = this.focusTarget || this.containedElement;
-      if (focusTarget && this.opened && !this.noAutoFocus) {
-        focusTarget.focus();
-      } else {
-        Polymer.IronOverlayBehaviorImpl._applyFocus.apply(this, arguments);
-      }
-    }
-  });
-})();
-
-Polymer({
-  is: 'fade-in-animation',
-  behaviors: [ Polymer.NeonAnimationBehavior ],
-  configure: function(config) {
-    var node = config.node;
-    this._effect = new KeyframeEffect(node, [ {
-      opacity: '0'
-    }, {
-      opacity: '1'
-    } ], this.timingFromConfig(config));
-    return this._effect;
-  }
-});
-
-Polymer({
-  is: 'fade-out-animation',
-  behaviors: [ Polymer.NeonAnimationBehavior ],
-  configure: function(config) {
-    var node = config.node;
-    this._effect = new KeyframeEffect(node, [ {
-      opacity: '1'
-    }, {
-      opacity: '0'
-    } ], this.timingFromConfig(config));
-    return this._effect;
-  }
-});
-
-Polymer({
-  is: 'paper-menu-grow-height-animation',
-  behaviors: [ Polymer.NeonAnimationBehavior ],
-  configure: function(config) {
-    var node = config.node;
-    var rect = node.getBoundingClientRect();
-    var height = rect.height;
-    this._effect = new KeyframeEffect(node, [ {
-      height: height / 2 + 'px'
-    }, {
-      height: height + 'px'
-    } ], this.timingFromConfig(config));
-    return this._effect;
-  }
-});
-
-Polymer({
-  is: 'paper-menu-grow-width-animation',
-  behaviors: [ Polymer.NeonAnimationBehavior ],
-  configure: function(config) {
-    var node = config.node;
-    var rect = node.getBoundingClientRect();
-    var width = rect.width;
-    this._effect = new KeyframeEffect(node, [ {
-      width: width / 2 + 'px'
-    }, {
-      width: width + 'px'
-    } ], this.timingFromConfig(config));
-    return this._effect;
-  }
-});
-
-Polymer({
-  is: 'paper-menu-shrink-width-animation',
-  behaviors: [ Polymer.NeonAnimationBehavior ],
-  configure: function(config) {
-    var node = config.node;
-    var rect = node.getBoundingClientRect();
-    var width = rect.width;
-    this._effect = new KeyframeEffect(node, [ {
-      width: width + 'px'
-    }, {
-      width: width - width / 20 + 'px'
-    } ], this.timingFromConfig(config));
-    return this._effect;
-  }
-});
-
-Polymer({
-  is: 'paper-menu-shrink-height-animation',
-  behaviors: [ Polymer.NeonAnimationBehavior ],
-  configure: function(config) {
-    var node = config.node;
-    var rect = node.getBoundingClientRect();
-    var height = rect.height;
-    var top = rect.top;
-    this.setPrefixedProperty(node, 'transformOrigin', '0 0');
-    this._effect = new KeyframeEffect(node, [ {
-      height: height + 'px',
-      transform: 'translateY(0)'
-    }, {
-      height: height / 2 + 'px',
-      transform: 'translateY(-20px)'
-    } ], this.timingFromConfig(config));
-    return this._effect;
-  }
-});
-
-(function() {
-  'use strict';
-  var config = {
-    ANIMATION_CUBIC_BEZIER: 'cubic-bezier(.3,.95,.5,1)',
-    MAX_ANIMATION_TIME_MS: 400
-  };
-  var PaperMenuButton = Polymer({
-    is: 'paper-menu-button',
-    behaviors: [ Polymer.IronA11yKeysBehavior, Polymer.IronControlState ],
-    properties: {
-      opened: {
-        type: Boolean,
-        value: false,
-        notify: true,
-        observer: '_openedChanged'
-      },
-      horizontalAlign: {
-        type: String,
-        value: 'left',
-        reflectToAttribute: true
-      },
-      verticalAlign: {
-        type: String,
-        value: 'top',
-        reflectToAttribute: true
-      },
-      dynamicAlign: {
-        type: Boolean
-      },
-      horizontalOffset: {
-        type: Number,
-        value: 0,
-        notify: true
-      },
-      verticalOffset: {
-        type: Number,
-        value: 0,
-        notify: true
-      },
-      noOverlap: {
-        type: Boolean
-      },
-      noAnimations: {
-        type: Boolean,
-        value: false
-      },
-      ignoreSelect: {
-        type: Boolean,
-        value: false
-      },
-      closeOnActivate: {
-        type: Boolean,
-        value: false
-      },
-      openAnimationConfig: {
-        type: Object,
-        value: function() {
-          return [ {
-            name: 'fade-in-animation',
-            timing: {
-              delay: 100,
-              duration: 200
-            }
-          }, {
-            name: 'paper-menu-grow-width-animation',
-            timing: {
-              delay: 100,
-              duration: 150,
-              easing: config.ANIMATION_CUBIC_BEZIER
-            }
-          }, {
-            name: 'paper-menu-grow-height-animation',
-            timing: {
-              delay: 100,
-              duration: 275,
-              easing: config.ANIMATION_CUBIC_BEZIER
-            }
-          } ];
-        }
-      },
-      closeAnimationConfig: {
-        type: Object,
-        value: function() {
-          return [ {
-            name: 'fade-out-animation',
-            timing: {
-              duration: 150
-            }
-          }, {
-            name: 'paper-menu-shrink-width-animation',
-            timing: {
-              delay: 100,
-              duration: 50,
-              easing: config.ANIMATION_CUBIC_BEZIER
-            }
-          }, {
-            name: 'paper-menu-shrink-height-animation',
-            timing: {
-              duration: 200,
-              easing: 'ease-in'
-            }
-          } ];
-        }
-      },
-      allowOutsideScroll: {
-        type: Boolean,
-        value: false
-      },
-      restoreFocusOnClose: {
-        type: Boolean,
-        value: true
-      },
-      _dropdownContent: {
-        type: Object
-      }
-    },
-    hostAttributes: {
-      role: 'group',
-      'aria-haspopup': 'true'
-    },
-    listeners: {
-      'iron-activate': '_onIronActivate',
-      'iron-select': '_onIronSelect'
-    },
-    get contentElement() {
-      return Polymer.dom(this.$.content).getDistributedNodes()[0];
-    },
-    toggle: function() {
-      if (this.opened) {
-        this.close();
-      } else {
-        this.open();
-      }
-    },
-    open: function() {
-      if (this.disabled) {
-        return;
-      }
-      this.$.dropdown.open();
-    },
-    close: function() {
-      this.$.dropdown.close();
-    },
-    _onIronSelect: function(event) {
-      if (!this.ignoreSelect) {
-        this.close();
-      }
-    },
-    _onIronActivate: function(event) {
-      if (this.closeOnActivate) {
-        this.close();
-      }
-    },
-    _openedChanged: function(opened, oldOpened) {
-      if (opened) {
-        this._dropdownContent = this.contentElement;
-        this.fire('paper-dropdown-open');
-      } else if (oldOpened != null) {
-        this.fire('paper-dropdown-close');
-      }
-    },
-    _disabledChanged: function(disabled) {
-      Polymer.IronControlState._disabledChanged.apply(this, arguments);
-      if (disabled && this.opened) {
-        this.close();
-      }
-    },
-    __onIronOverlayCanceled: function(event) {
-      var uiEvent = event.detail;
-      var target = Polymer.dom(uiEvent).rootTarget;
-      var trigger = this.$.trigger;
-      var path = Polymer.dom(uiEvent).path;
-      if (path.indexOf(trigger) > -1) {
-        event.preventDefault();
-      }
-    }
-  });
-  Object.keys(config).forEach(function(key) {
-    PaperMenuButton[key] = config[key];
-  });
-  Polymer.PaperMenuButton = PaperMenuButton;
-})();
-
-Polymer.PaperInkyFocusBehaviorImpl = {
-  observers: [ '_focusedChanged(receivedFocusFromKeyboard)' ],
-  _focusedChanged: function(receivedFocusFromKeyboard) {
-    if (receivedFocusFromKeyboard) {
-      this.ensureRipple();
-    }
-    if (this.hasRipple()) {
-      this._ripple.holdDown = receivedFocusFromKeyboard;
-    }
-  },
-  _createRipple: function() {
-    var ripple = Polymer.PaperRippleBehavior._createRipple();
-    ripple.id = 'ink';
-    ripple.setAttribute('center', '');
-    ripple.classList.add('circle');
-    return ripple;
-  }
-};
-
-Polymer.PaperInkyFocusBehavior = [ Polymer.IronButtonState, Polymer.IronControlState, Polymer.PaperRippleBehavior, Polymer.PaperInkyFocusBehaviorImpl ];
-
-Polymer({
-  is: 'paper-icon-button',
-  hostAttributes: {
-    role: 'button',
-    tabindex: '0'
-  },
-  behaviors: [ Polymer.PaperInkyFocusBehavior ],
-  properties: {
-    src: {
-      type: String
-    },
-    icon: {
-      type: String
-    },
-    alt: {
-      type: String,
-      observer: "_altChanged"
-    }
-  },
-  _altChanged: function(newValue, oldValue) {
-    var label = this.getAttribute('aria-label');
-    if (!label || oldValue == label) {
-      this.setAttribute('aria-label', newValue);
-    }
-  }
-});
-
-Polymer({
-  is: 'iron-media-query',
-  properties: {
-    queryMatches: {
-      type: Boolean,
-      value: false,
-      readOnly: true,
-      notify: true
-    },
-    query: {
-      type: String,
-      observer: 'queryChanged'
-    },
-    full: {
-      type: Boolean,
-      value: false
-    },
-    _boundMQHandler: {
-      value: function() {
-        return this.queryHandler.bind(this);
-      }
-    },
-    _mq: {
-      value: null
-    }
-  },
-  attached: function() {
-    this.style.display = 'none';
-    this.queryChanged();
-  },
-  detached: function() {
-    this._remove();
-  },
-  _add: function() {
-    if (this._mq) {
-      this._mq.addListener(this._boundMQHandler);
-    }
-  },
-  _remove: function() {
-    if (this._mq) {
-      this._mq.removeListener(this._boundMQHandler);
-    }
-    this._mq = null;
-  },
-  queryChanged: function() {
-    this._remove();
-    var query = this.query;
-    if (!query) {
-      return;
-    }
-    if (!this.full && query[0] !== '(') {
-      query = '(' + query + ')';
-    }
-    this._mq = window.matchMedia(query);
-    this._add();
-    this.queryHandler(this._mq);
-  },
-  queryHandler: function(mq) {
-    this._setQueryMatches(mq.matches);
-  }
-});
-
-(function() {
-  'use strict';
-  Polymer.IronA11yAnnouncer = Polymer({
-    is: 'iron-a11y-announcer',
-    properties: {
-      mode: {
-        type: String,
-        value: 'polite'
-      },
-      _text: {
-        type: String,
-        value: ''
-      }
-    },
-    created: function() {
-      if (!Polymer.IronA11yAnnouncer.instance) {
-        Polymer.IronA11yAnnouncer.instance = this;
-      }
-      document.body.addEventListener('iron-announce', this._onIronAnnounce.bind(this));
-    },
-    announce: function(text) {
-      this._text = '';
-      this.async(function() {
-        this._text = text;
-      }, 100);
-    },
-    _onIronAnnounce: function(event) {
-      if (event.detail && event.detail.text) {
-        this.announce(event.detail.text);
-      }
-    }
-  });
-  Polymer.IronA11yAnnouncer.instance = null;
-  Polymer.IronA11yAnnouncer.requestAvailability = function() {
-    if (!Polymer.IronA11yAnnouncer.instance) {
-      Polymer.IronA11yAnnouncer.instance = document.createElement('iron-a11y-announcer');
-    }
-    document.body.appendChild(Polymer.IronA11yAnnouncer.instance);
-  };
-})();
-
-Polymer.IronValidatableBehaviorMeta = null;
-
-Polymer.IronValidatableBehavior = {
-  properties: {
-    validator: {
-      type: String
-    },
-    invalid: {
-      notify: true,
-      reflectToAttribute: true,
-      type: Boolean,
-      value: false
-    },
-    _validatorMeta: {
-      type: Object
-    },
-    validatorType: {
-      type: String,
-      value: 'validator'
-    },
-    _validator: {
-      type: Object,
-      computed: '__computeValidator(validator)'
-    }
-  },
-  observers: [ '_invalidChanged(invalid)' ],
-  registered: function() {
-    Polymer.IronValidatableBehaviorMeta = new Polymer.IronMeta({
-      type: 'validator'
-    });
-  },
-  _invalidChanged: function() {
-    if (this.invalid) {
-      this.setAttribute('aria-invalid', 'true');
-    } else {
-      this.removeAttribute('aria-invalid');
-    }
-  },
-  hasValidator: function() {
-    return this._validator != null;
-  },
-  validate: function(value) {
-    this.invalid = !this._getValidity(value);
-    return !this.invalid;
-  },
-  _getValidity: function(value) {
-    if (this.hasValidator()) {
-      return this._validator.validate(value);
-    }
-    return true;
-  },
-  __computeValidator: function() {
-    return Polymer.IronValidatableBehaviorMeta && Polymer.IronValidatableBehaviorMeta.byKey(this.validator);
-  }
-};
-
-Polymer({
-  is: 'iron-input',
-  "extends": 'input',
-  behaviors: [ Polymer.IronValidatableBehavior ],
-  properties: {
-    bindValue: {
-      observer: '_bindValueChanged',
-      type: String
-    },
-    preventInvalidInput: {
-      type: Boolean
-    },
-    allowedPattern: {
-      type: String,
-      observer: "_allowedPatternChanged"
-    },
-    _previousValidInput: {
-      type: String,
-      value: ''
-    },
-    _patternAlreadyChecked: {
-      type: Boolean,
-      value: false
-    }
-  },
-  listeners: {
-    input: '_onInput',
-    keypress: '_onKeypress'
-  },
-  registered: function() {
-    if (!this._canDispatchEventOnDisabled()) {
-      this._origDispatchEvent = this.dispatchEvent;
-      this.dispatchEvent = this._dispatchEventFirefoxIE;
-    }
-  },
-  created: function() {
-    Polymer.IronA11yAnnouncer.requestAvailability();
-  },
-  _canDispatchEventOnDisabled: function() {
-    var input = document.createElement('input');
-    var canDispatch = false;
-    input.disabled = true;
-    input.addEventListener('feature-check-dispatch-event', function() {
-      canDispatch = true;
-    });
-    try {
-      input.dispatchEvent(new Event('feature-check-dispatch-event'));
-    } catch (e) {}
-    return canDispatch;
-  },
-  _dispatchEventFirefoxIE: function() {
-    var disabled = this.disabled;
-    this.disabled = false;
-    this._origDispatchEvent.apply(this, arguments);
-    this.disabled = disabled;
-  },
-  get _patternRegExp() {
-    var pattern;
-    if (this.allowedPattern) {
-      pattern = new RegExp(this.allowedPattern);
-    } else {
-      switch (this.type) {
-       case 'number':
-        pattern = /[0-9.,e-]/;
-        break;
-      }
-    }
-    return pattern;
-  },
-  ready: function() {
-    this.bindValue = this.value;
-  },
-  _bindValueChanged: function() {
-    if (this.value !== this.bindValue) {
-      this.value = !(this.bindValue || this.bindValue === 0 || this.bindValue === false) ? '' : this.bindValue;
-    }
-    this.fire('bind-value-changed', {
-      value: this.bindValue
-    });
-  },
-  _allowedPatternChanged: function() {
-    this.preventInvalidInput = this.allowedPattern ? true : false;
-  },
-  _onInput: function() {
-    if (this.preventInvalidInput && !this._patternAlreadyChecked) {
-      var valid = this._checkPatternValidity();
-      if (!valid) {
-        this._announceInvalidCharacter('Invalid string of characters not entered.');
-        this.value = this._previousValidInput;
-      }
-    }
-    this.bindValue = this.value;
-    this._previousValidInput = this.value;
-    this._patternAlreadyChecked = false;
-  },
-  _isPrintable: function(event) {
-    var anyNonPrintable = event.keyCode == 8 || event.keyCode == 9 || event.keyCode == 13 || event.keyCode == 27;
-    var mozNonPrintable = event.keyCode == 19 || event.keyCode == 20 || event.keyCode == 45 || event.keyCode == 46 || event.keyCode == 144 || event.keyCode == 145 || event.keyCode > 32 && event.keyCode < 41 || event.keyCode > 111 && event.keyCode < 124;
-    return !anyNonPrintable && !(event.charCode == 0 && mozNonPrintable);
-  },
-  _onKeypress: function(event) {
-    if (!this.preventInvalidInput && this.type !== 'number') {
-      return;
-    }
-    var regexp = this._patternRegExp;
-    if (!regexp) {
-      return;
-    }
-    if (event.metaKey || event.ctrlKey || event.altKey) return;
-    this._patternAlreadyChecked = true;
-    var thisChar = String.fromCharCode(event.charCode);
-    if (this._isPrintable(event) && !regexp.test(thisChar)) {
-      event.preventDefault();
-      this._announceInvalidCharacter('Invalid character ' + thisChar + ' not entered.');
-    }
-  },
-  _checkPatternValidity: function() {
-    var regexp = this._patternRegExp;
-    if (!regexp) {
-      return true;
-    }
-    for (var i = 0; i < this.value.length; i++) {
-      if (!regexp.test(this.value[i])) {
-        return false;
-      }
-    }
-    return true;
-  },
-  validate: function() {
-    var valid = this.checkValidity();
-    if (valid) {
-      if (this.required && this.value === '') {
-        valid = false;
-      } else if (this.hasValidator()) {
-        valid = Polymer.IronValidatableBehavior.validate.call(this, this.value);
-      }
-    }
-    this.invalid = !valid;
-    this.fire('iron-input-validate');
-    return valid;
-  },
-  _announceInvalidCharacter: function(message) {
-    this.fire('iron-announce', {
-      text: message
-    });
-  }
-});
-
-Polymer({
-  is: 'paper-input-container',
-  properties: {
-    noLabelFloat: {
-      type: Boolean,
-      value: false
-    },
-    alwaysFloatLabel: {
-      type: Boolean,
-      value: false
-    },
-    attrForValue: {
-      type: String,
-      value: 'bind-value'
-    },
-    autoValidate: {
-      type: Boolean,
-      value: false
-    },
-    invalid: {
-      observer: '_invalidChanged',
-      type: Boolean,
-      value: false
-    },
-    focused: {
-      readOnly: true,
-      type: Boolean,
-      value: false,
-      notify: true
-    },
-    _addons: {
-      type: Array
-    },
-    _inputHasContent: {
-      type: Boolean,
-      value: false
-    },
-    _inputSelector: {
-      type: String,
-      value: 'input,textarea,.paper-input-input'
-    },
-    _boundOnFocus: {
-      type: Function,
-      value: function() {
-        return this._onFocus.bind(this);
-      }
-    },
-    _boundOnBlur: {
-      type: Function,
-      value: function() {
-        return this._onBlur.bind(this);
-      }
-    },
-    _boundOnInput: {
-      type: Function,
-      value: function() {
-        return this._onInput.bind(this);
-      }
-    },
-    _boundValueChanged: {
-      type: Function,
-      value: function() {
-        return this._onValueChanged.bind(this);
-      }
-    }
-  },
-  listeners: {
-    'addon-attached': '_onAddonAttached',
-    'iron-input-validate': '_onIronInputValidate'
-  },
-  get _valueChangedEvent() {
-    return this.attrForValue + '-changed';
-  },
-  get _propertyForValue() {
-    return Polymer.CaseMap.dashToCamelCase(this.attrForValue);
-  },
-  get _inputElement() {
-    return Polymer.dom(this).querySelector(this._inputSelector);
-  },
-  get _inputElementValue() {
-    return this._inputElement[this._propertyForValue] || this._inputElement.value;
-  },
-  ready: function() {
-    if (!this._addons) {
-      this._addons = [];
-    }
-    this.addEventListener('focus', this._boundOnFocus, true);
-    this.addEventListener('blur', this._boundOnBlur, true);
-  },
-  attached: function() {
-    if (this.attrForValue) {
-      this._inputElement.addEventListener(this._valueChangedEvent, this._boundValueChanged);
-    } else {
-      this.addEventListener('input', this._onInput);
-    }
-    if (this._inputElementValue != '') {
-      this._handleValueAndAutoValidate(this._inputElement);
-    } else {
-      this._handleValue(this._inputElement);
-    }
-  },
-  _onAddonAttached: function(event) {
-    if (!this._addons) {
-      this._addons = [];
-    }
-    var target = event.target;
-    if (this._addons.indexOf(target) === -1) {
-      this._addons.push(target);
-      if (this.isAttached) {
-        this._handleValue(this._inputElement);
-      }
-    }
-  },
-  _onFocus: function() {
-    this._setFocused(true);
-  },
-  _onBlur: function() {
-    this._setFocused(false);
-    this._handleValueAndAutoValidate(this._inputElement);
-  },
-  _onInput: function(event) {
-    this._handleValueAndAutoValidate(event.target);
-  },
-  _onValueChanged: function(event) {
-    this._handleValueAndAutoValidate(event.target);
-  },
-  _handleValue: function(inputElement) {
-    var value = this._inputElementValue;
-    if (value || value === 0 || inputElement.type === 'number' && !inputElement.checkValidity()) {
-      this._inputHasContent = true;
-    } else {
-      this._inputHasContent = false;
-    }
-    this.updateAddons({
-      inputElement: inputElement,
-      value: value,
-      invalid: this.invalid
-    });
-  },
-  _handleValueAndAutoValidate: function(inputElement) {
-    if (this.autoValidate) {
-      var valid;
-      if (inputElement.validate) {
-        valid = inputElement.validate(this._inputElementValue);
-      } else {
-        valid = inputElement.checkValidity();
-      }
-      this.invalid = !valid;
-    }
-    this._handleValue(inputElement);
-  },
-  _onIronInputValidate: function(event) {
-    this.invalid = this._inputElement.invalid;
-  },
-  _invalidChanged: function() {
-    if (this._addons) {
-      this.updateAddons({
-        invalid: this.invalid
-      });
-    }
-  },
-  updateAddons: function(state) {
-    for (var addon, index = 0; addon = this._addons[index]; index++) {
-      addon.update(state);
-    }
-  },
-  _computeInputContentClass: function(noLabelFloat, alwaysFloatLabel, focused, invalid, _inputHasContent) {
-    var cls = 'input-content';
-    if (!noLabelFloat) {
-      var label = this.querySelector('label');
-      if (alwaysFloatLabel || _inputHasContent) {
-        cls += ' label-is-floating';
-        this.$.labelAndInputContainer.style.position = 'static';
-        if (invalid) {
-          cls += ' is-invalid';
-        } else if (focused) {
-          cls += " label-is-highlighted";
-        }
-      } else {
-        if (label) {
-          this.$.labelAndInputContainer.style.position = 'relative';
-        }
-      }
-    } else {
-      if (_inputHasContent) {
-        cls += ' label-is-hidden';
-      }
-    }
-    return cls;
-  },
-  _computeUnderlineClass: function(focused, invalid) {
-    var cls = 'underline';
-    if (invalid) {
-      cls += ' is-invalid';
-    } else if (focused) {
-      cls += ' is-highlighted';
-    }
-    return cls;
-  },
-  _computeAddOnContentClass: function(focused, invalid) {
-    var cls = 'add-on-content';
-    if (invalid) {
-      cls += ' is-invalid';
-    } else if (focused) {
-      cls += ' is-highlighted';
-    }
-    return cls;
-  }
-});
-
-Polymer.PaperSpinnerBehavior = {
-  listeners: {
-    animationend: '__reset',
-    webkitAnimationEnd: '__reset'
-  },
-  properties: {
-    active: {
-      type: Boolean,
-      value: false,
-      reflectToAttribute: true,
-      observer: '__activeChanged'
-    },
-    alt: {
-      type: String,
-      value: 'loading',
-      observer: '__altChanged'
-    },
-    __coolingDown: {
-      type: Boolean,
-      value: false
-    }
-  },
-  __computeContainerClasses: function(active, coolingDown) {
-    return [ active || coolingDown ? 'active' : '', coolingDown ? 'cooldown' : '' ].join(' ');
-  },
-  __activeChanged: function(active, old) {
-    this.__setAriaHidden(!active);
-    this.__coolingDown = !active && old;
-  },
-  __altChanged: function(alt) {
-    if (alt === this.getPropertyInfo('alt').value) {
-      this.alt = this.getAttribute('aria-label') || alt;
-    } else {
-      this.__setAriaHidden(alt === '');
-      this.setAttribute('aria-label', alt);
-    }
-  },
-  __setAriaHidden: function(hidden) {
-    var attr = 'aria-hidden';
-    if (hidden) {
-      this.setAttribute(attr, 'true');
-    } else {
-      this.removeAttribute(attr);
-    }
-  },
-  __reset: function() {
-    this.active = false;
-    this.__coolingDown = false;
-  }
-};
-
-Polymer({
-  is: 'paper-spinner-lite',
-  behaviors: [ Polymer.PaperSpinnerBehavior ]
-});
-
+cr.define("downloads",function(){var Item=Polymer({is:"downloads-item",properties:{data:{type:Object},completelyOnDisk_:{computed:"computeCompletelyOnDisk_("+"data.state, data.file_externally_removed)",type:Boolean,value:true},controlledBy_:{computed:"computeControlledBy_(data.by_ext_id, data.by_ext_name)",type:String,value:""},isActive_:{computed:"computeIsActive_("+"data.state, data.file_externally_removed)",type:Boolean,value:true},isDangerous_:{computed:"computeIsDangerous_(data.state)",type:Boolean,value:false},isMalware_:{computed:"computeIsMalware_(isDangerous_, data.danger_type)",type:Boolean,value:false},isInProgress_:{computed:"computeIsInProgress_(data.state)",type:Boolean,value:false},pauseOrResumeText_:{computed:"computePauseOrResumeText_(isInProgress_, data.resume)",type:String},showCancel_:{computed:"computeShowCancel_(data.state)",type:Boolean,value:false},showProgress_:{computed:"computeShowProgress_(showCancel_, data.percent)",type:Boolean,value:false}},observers:["observeControlledBy_(controlledBy_)","observeIsDangerous_(isDangerous_, data)"],ready:function(){this.content=this.$.content},computeClass_:function(){var classes=[];if(this.isActive_)classes.push("is-active");if(this.isDangerous_)classes.push("dangerous");if(this.showProgress_)classes.push("show-progress");return classes.join(" ")},computeCompletelyOnDisk_:function(){return this.data.state==downloads.States.COMPLETE&&!this.data.file_externally_removed},computeControlledBy_:function(){if(!this.data.by_ext_id||!this.data.by_ext_name)return"";var url="chrome://extensions#"+this.data.by_ext_id;var name=this.data.by_ext_name;return loadTimeData.getStringF("controlledByUrl",url,name)},computeDangerIcon_:function(){if(!this.isDangerous_)return"";switch(this.data.danger_type){case downloads.DangerType.DANGEROUS_CONTENT:case downloads.DangerType.DANGEROUS_HOST:case downloads.DangerType.DANGEROUS_URL:case downloads.DangerType.POTENTIALLY_UNWANTED:case downloads.DangerType.UNCOMMON_CONTENT:return"downloads:remove-circle";default:return"cr:warning"}},computeDate_:function(){assert(typeof this.data.hideDate=="boolean");if(this.data.hideDate)return"";return assert(this.data.since_string||this.data.date_string)},computeDescription_:function(){var data=this.data;switch(data.state){case downloads.States.DANGEROUS:var fileName=data.file_name;switch(data.danger_type){case downloads.DangerType.DANGEROUS_FILE:return loadTimeData.getString("dangerFileDesc");case downloads.DangerType.DANGEROUS_URL:case downloads.DangerType.DANGEROUS_CONTENT:case downloads.DangerType.DANGEROUS_HOST:return loadTimeData.getString("dangerDownloadDesc");case downloads.DangerType.UNCOMMON_CONTENT:return loadTimeData.getString("dangerUncommonDesc");case downloads.DangerType.POTENTIALLY_UNWANTED:return loadTimeData.getString("dangerSettingsDesc")}break;case downloads.States.IN_PROGRESS:case downloads.States.PAUSED:return data.progress_status_text}return""},computeIsActive_:function(){return this.data.state!=downloads.States.CANCELLED&&this.data.state!=downloads.States.INTERRUPTED&&!this.data.file_externally_removed},computeIsDangerous_:function(){return this.data.state==downloads.States.DANGEROUS},computeIsInProgress_:function(){return this.data.state==downloads.States.IN_PROGRESS},computeIsMalware_:function(){return this.isDangerous_&&(this.data.danger_type==downloads.DangerType.DANGEROUS_CONTENT||this.data.danger_type==downloads.DangerType.DANGEROUS_HOST||this.data.danger_type==downloads.DangerType.DANGEROUS_URL||this.data.danger_type==downloads.DangerType.POTENTIALLY_UNWANTED)},computePauseOrResumeText_:function(){if(this.isInProgress_)return loadTimeData.getString("controlPause");if(this.data.resume)return loadTimeData.getString("controlResume");return""},computeRemoveStyle_:function(){var canDelete=loadTimeData.getBoolean("allowDeletingHistory");var hideRemove=this.isDangerous_||this.showCancel_||!canDelete;return hideRemove?"visibility: hidden":""},computeShowCancel_:function(){return this.data.state==downloads.States.IN_PROGRESS||this.data.state==downloads.States.PAUSED},computeShowProgress_:function(){return this.showCancel_&&this.data.percent>=-1},computeTag_:function(){switch(this.data.state){case downloads.States.CANCELLED:return loadTimeData.getString("statusCancelled");case downloads.States.INTERRUPTED:return this.data.last_reason_text;case downloads.States.COMPLETE:return this.data.file_externally_removed?loadTimeData.getString("statusRemoved"):""}return""},isIndeterminate_:function(){return this.data.percent==-1},observeControlledBy_:function(){this.$["controlled-by"].innerHTML=this.controlledBy_},observeIsDangerous_:function(){if(!this.data)return;if(this.isDangerous_){this.$.url.removeAttribute("href")}else{this.$.url.href=assert(this.data.url);var filePath=encodeURIComponent(this.data.file_path);var scaleFactor="?scale="+window.devicePixelRatio+"x";this.$["file-icon"].src="chrome://fileicon/"+filePath+scaleFactor}},onCancelTap_:function(){downloads.ActionService.getInstance().cancel(this.data.id)},onDiscardDangerousTap_:function(){downloads.ActionService.getInstance().discardDangerous(this.data.id)},onDragStart_:function(e){e.preventDefault();downloads.ActionService.getInstance().drag(this.data.id)},onFileLinkTap_:function(e){e.preventDefault();downloads.ActionService.getInstance().openFile(this.data.id)},onPauseOrResumeTap_:function(){if(this.isInProgress_)downloads.ActionService.getInstance().pause(this.data.id);else downloads.ActionService.getInstance().resume(this.data.id)},onRemoveTap_:function(){downloads.ActionService.getInstance().remove(this.data.id)},onRetryTap_:function(){downloads.ActionService.getInstance().download(this.data.url)},onSaveDangerousTap_:function(){downloads.ActionService.getInstance().saveDangerous(this.data.id)},onShowTap_:function(){downloads.ActionService.getInstance().show(this.data.id)}});return{Item:Item}});Polymer.PaperItemBehaviorImpl={hostAttributes:{role:"option",tabindex:"0"}};Polymer.PaperItemBehavior=[Polymer.IronButtonState,Polymer.IronControlState,Polymer.PaperItemBehaviorImpl];Polymer({is:"paper-item",behaviors:[Polymer.PaperItemBehavior]});Polymer.IronSelection=function(selectCallback){this.selection=[];this.selectCallback=selectCallback};Polymer.IronSelection.prototype={get:function(){return this.multi?this.selection.slice():this.selection[0]},clear:function(excludes){this.selection.slice().forEach(function(item){if(!excludes||excludes.indexOf(item)<0){this.setItemSelected(item,false)}},this)},isSelected:function(item){return this.selection.indexOf(item)>=0},setItemSelected:function(item,isSelected){if(item!=null){if(isSelected!==this.isSelected(item)){if(isSelected){this.selection.push(item)}else{var i=this.selection.indexOf(item);if(i>=0){this.selection.splice(i,1)}}if(this.selectCallback){this.selectCallback(item,isSelected)}}}},select:function(item){if(this.multi){this.toggle(item)}else if(this.get()!==item){this.setItemSelected(this.get(),false);this.setItemSelected(item,true)}},toggle:function(item){this.setItemSelected(item,!this.isSelected(item))}};Polymer.IronSelectableBehavior={properties:{attrForSelected:{type:String,value:null},selected:{type:String,notify:true},selectedItem:{type:Object,readOnly:true,notify:true},activateEvent:{type:String,value:"tap",observer:"_activateEventChanged"},selectable:String,selectedClass:{type:String,value:"iron-selected"},selectedAttribute:{type:String,value:null},fallbackSelection:{type:String,value:null},items:{type:Array,readOnly:true,notify:true,value:function(){return[]}},_excludedLocalNames:{type:Object,value:function(){return{template:1}}}},observers:["_updateAttrForSelected(attrForSelected)","_updateSelected(selected)","_checkFallback(fallbackSelection)"],created:function(){this._bindFilterItem=this._filterItem.bind(this);this._selection=new Polymer.IronSelection(this._applySelection.bind(this))},attached:function(){this._observer=this._observeItems(this);this._updateItems();if(!this._shouldUpdateSelection){this._updateSelected()}this._addListener(this.activateEvent)},detached:function(){if(this._observer){Polymer.dom(this).unobserveNodes(this._observer)}this._removeListener(this.activateEvent)},indexOf:function(item){return this.items.indexOf(item)},select:function(value){this.selected=value},selectPrevious:function(){var length=this.items.length;var index=(Number(this._valueToIndex(this.selected))-1+length)%length;this.selected=this._indexToValue(index)},selectNext:function(){var index=(Number(this._valueToIndex(this.selected))+1)%this.items.length;this.selected=this._indexToValue(index)},selectIndex:function(index){this.select(this._indexToValue(index))},forceSynchronousItemUpdate:function(){this._updateItems()},get _shouldUpdateSelection(){return this.selected!=null},_checkFallback:function(){if(this._shouldUpdateSelection){this._updateSelected()}},_addListener:function(eventName){this.listen(this,eventName,"_activateHandler")},_removeListener:function(eventName){this.unlisten(this,eventName,"_activateHandler")},_activateEventChanged:function(eventName,old){this._removeListener(old);this._addListener(eventName)},_updateItems:function(){var nodes=Polymer.dom(this).queryDistributedElements(this.selectable||"*");nodes=Array.prototype.filter.call(nodes,this._bindFilterItem);this._setItems(nodes)},_updateAttrForSelected:function(){if(this._shouldUpdateSelection){this.selected=this._indexToValue(this.indexOf(this.selectedItem))}},_updateSelected:function(){this._selectSelected(this.selected)},_selectSelected:function(selected){this._selection.select(this._valueToItem(this.selected));if(this.fallbackSelection&&this.items.length&&this._selection.get()===undefined){this.selected=this.fallbackSelection}},_filterItem:function(node){return!this._excludedLocalNames[node.localName]},_valueToItem:function(value){return value==null?null:this.items[this._valueToIndex(value)]},_valueToIndex:function(value){if(this.attrForSelected){for(var i=0,item;item=this.items[i];i++){if(this._valueForItem(item)==value){return i}}}else{return Number(value)}},_indexToValue:function(index){if(this.attrForSelected){var item=this.items[index];if(item){return this._valueForItem(item)}}else{return index}},_valueForItem:function(item){var propValue=item[Polymer.CaseMap.dashToCamelCase(this.attrForSelected)];return propValue!=undefined?propValue:item.getAttribute(this.attrForSelected)},_applySelection:function(item,isSelected){if(this.selectedClass){this.toggleClass(this.selectedClass,isSelected,item)}if(this.selectedAttribute){this.toggleAttribute(this.selectedAttribute,isSelected,item)}this._selectionChange();this.fire("iron-"+(isSelected?"select":"deselect"),{item:item})},_selectionChange:function(){this._setSelectedItem(this._selection.get())},_observeItems:function(node){return Polymer.dom(node).observeNodes(function(mutation){this._updateItems();if(this._shouldUpdateSelection){this._updateSelected()}this.fire("iron-items-changed",mutation,{bubbles:false,cancelable:false})})},_activateHandler:function(e){var t=e.target;var items=this.items;while(t&&t!=this){var i=items.indexOf(t);if(i>=0){var value=this._indexToValue(i);this._itemActivate(value,t);return}t=t.parentNode}},_itemActivate:function(value,item){if(!this.fire("iron-activate",{selected:value,item:item},{cancelable:true}).defaultPrevented){this.select(value)}}};Polymer.IronMultiSelectableBehaviorImpl={properties:{multi:{type:Boolean,value:false,observer:"multiChanged"},selectedValues:{type:Array,notify:true},selectedItems:{type:Array,readOnly:true,notify:true}},observers:["_updateSelected(selectedValues.splices)"],select:function(value){if(this.multi){if(this.selectedValues){this._toggleSelected(value)}else{this.selectedValues=[value]}}else{this.selected=value}},multiChanged:function(multi){this._selection.multi=multi},get _shouldUpdateSelection(){return this.selected!=null||this.selectedValues!=null&&this.selectedValues.length},_updateAttrForSelected:function(){if(!this.multi){Polymer.IronSelectableBehavior._updateAttrForSelected.apply(this)}else if(this._shouldUpdateSelection){this.selectedValues=this.selectedItems.map(function(selectedItem){return this._indexToValue(this.indexOf(selectedItem))},this).filter(function(unfilteredValue){return unfilteredValue!=null},this)}},_updateSelected:function(){if(this.multi){this._selectMulti(this.selectedValues)}else{this._selectSelected(this.selected)}},_selectMulti:function(values){if(values){var selectedItems=this._valuesToItems(values);this._selection.clear(selectedItems);for(var i=0;i<selectedItems.length;i++){this._selection.setItemSelected(selectedItems[i],true)}if(this.fallbackSelection&&this.items.length&&!this._selection.get().length){var fallback=this._valueToItem(this.fallbackSelection);if(fallback){this.selectedValues=[this.fallbackSelection]}}}else{this._selection.clear()}},_selectionChange:function(){var s=this._selection.get();if(this.multi){this._setSelectedItems(s)}else{this._setSelectedItems([s]);this._setSelectedItem(s)}},_toggleSelected:function(value){var i=this.selectedValues.indexOf(value);var unselected=i<0;if(unselected){this.push("selectedValues",value)}else{this.splice("selectedValues",i,1)}},_valuesToItems:function(values){return values==null?null:values.map(function(value){return this._valueToItem(value)},this)}};Polymer.IronMultiSelectableBehavior=[Polymer.IronSelectableBehavior,Polymer.IronMultiSelectableBehaviorImpl];Polymer.IronMenuBehaviorImpl={properties:{focusedItem:{observer:"_focusedItemChanged",readOnly:true,type:Object},attrForItemTitle:{type:String}},hostAttributes:{role:"menu",tabindex:"0"},observers:["_updateMultiselectable(multi)"],listeners:{focus:"_onFocus",keydown:"_onKeydown","iron-items-changed":"_onIronItemsChanged"},keyBindings:{up:"_onUpKey",down:"_onDownKey",esc:"_onEscKey","shift+tab:keydown":"_onShiftTabDown"},attached:function(){this._resetTabindices()},select:function(value){if(this._defaultFocusAsync){this.cancelAsync(this._defaultFocusAsync);this._defaultFocusAsync=null}var item=this._valueToItem(value);if(item&&item.hasAttribute("disabled"))return;this._setFocusedItem(item);Polymer.IronMultiSelectableBehaviorImpl.select.apply(this,arguments)},_resetTabindices:function(){var selectedItem=this.multi?this.selectedItems&&this.selectedItems[0]:this.selectedItem;this.items.forEach(function(item){item.setAttribute("tabindex",item===selectedItem?"0":"-1")},this)},_updateMultiselectable:function(multi){if(multi){this.setAttribute("aria-multiselectable","true")}else{this.removeAttribute("aria-multiselectable")}},_focusWithKeyboardEvent:function(event){for(var i=0,item;item=this.items[i];i++){var attr=this.attrForItemTitle||"textContent";var title=item[attr]||item.getAttribute(attr);if(!item.hasAttribute("disabled")&&title&&title.trim().charAt(0).toLowerCase()===String.fromCharCode(event.keyCode).toLowerCase()){this._setFocusedItem(item);break}}},_focusPrevious:function(){var length=this.items.length;var curFocusIndex=Number(this.indexOf(this.focusedItem));for(var i=1;i<length+1;i++){var item=this.items[(curFocusIndex-i+length)%length];if(!item.hasAttribute("disabled")){var owner=Polymer.dom(item).getOwnerRoot()||document;this._setFocusedItem(item);if(Polymer.dom(owner).activeElement==item){return}}}},_focusNext:function(){var length=this.items.length;var curFocusIndex=Number(this.indexOf(this.focusedItem));for(var i=1;i<length+1;i++){var item=this.items[(curFocusIndex+i)%length];if(!item.hasAttribute("disabled")){var owner=Polymer.dom(item).getOwnerRoot()||document;this._setFocusedItem(item);if(Polymer.dom(owner).activeElement==item){return}}}},_applySelection:function(item,isSelected){if(isSelected){item.setAttribute("aria-selected","true")}else{item.removeAttribute("aria-selected")}Polymer.IronSelectableBehavior._applySelection.apply(this,arguments)},_focusedItemChanged:function(focusedItem,old){old&&old.setAttribute("tabindex","-1");if(focusedItem){focusedItem.setAttribute("tabindex","0");focusedItem.focus()}},_onIronItemsChanged:function(event){if(event.detail.addedNodes.length){this._resetTabindices()}},_onShiftTabDown:function(event){var oldTabIndex=this.getAttribute("tabindex");Polymer.IronMenuBehaviorImpl._shiftTabPressed=true;this._setFocusedItem(null);this.setAttribute("tabindex","-1");this.async(function(){this.setAttribute("tabindex",oldTabIndex);Polymer.IronMenuBehaviorImpl._shiftTabPressed=false},1)},_onFocus:function(event){if(Polymer.IronMenuBehaviorImpl._shiftTabPressed){return}var rootTarget=Polymer.dom(event).rootTarget;if(rootTarget!==this&&typeof rootTarget.tabIndex!=="undefined"&&!this.isLightDescendant(rootTarget)){return}this._defaultFocusAsync=this.async(function(){var selectedItem=this.multi?this.selectedItems&&this.selectedItems[0]:this.selectedItem;this._setFocusedItem(null);if(selectedItem){this._setFocusedItem(selectedItem)}else if(this.items[0]){this._focusNext()}})},_onUpKey:function(event){this._focusPrevious();event.detail.keyboardEvent.preventDefault()},_onDownKey:function(event){this._focusNext();event.detail.keyboardEvent.preventDefault()},_onEscKey:function(event){this.focusedItem.blur()},_onKeydown:function(event){if(!this.keyboardEventMatchesKeys(event,"up down esc")){this._focusWithKeyboardEvent(event)}event.stopPropagation()},_activateHandler:function(event){Polymer.IronSelectableBehavior._activateHandler.call(this,event);event.stopPropagation()}};Polymer.IronMenuBehaviorImpl._shiftTabPressed=false;Polymer.IronMenuBehavior=[Polymer.IronMultiSelectableBehavior,Polymer.IronA11yKeysBehavior,Polymer.IronMenuBehaviorImpl];(function(){Polymer({is:"paper-menu",behaviors:[Polymer.IronMenuBehavior]})})();Polymer.IronFitBehavior={properties:{sizingTarget:{type:Object,value:function(){return this}},fitInto:{type:Object,value:window},noOverlap:{type:Boolean},positionTarget:{type:Element},horizontalAlign:{type:String},verticalAlign:{type:String},dynamicAlign:{type:Boolean},horizontalOffset:{type:Number,value:0,notify:true},verticalOffset:{type:Number,value:0,notify:true},autoFitOnAttach:{type:Boolean,value:false},_fitInfo:{type:Object}},get _fitWidth(){var fitWidth;if(this.fitInto===window){fitWidth=this.fitInto.innerWidth}else{fitWidth=this.fitInto.getBoundingClientRect().width}return fitWidth},get _fitHeight(){var fitHeight;if(this.fitInto===window){fitHeight=this.fitInto.innerHeight}else{fitHeight=this.fitInto.getBoundingClientRect().height}return fitHeight},get _fitLeft(){var fitLeft;if(this.fitInto===window){fitLeft=0}else{fitLeft=this.fitInto.getBoundingClientRect().left}return fitLeft},get _fitTop(){var fitTop;if(this.fitInto===window){fitTop=0}else{fitTop=this.fitInto.getBoundingClientRect().top}return fitTop},get _defaultPositionTarget(){var parent=Polymer.dom(this).parentNode;if(parent&&parent.nodeType===Node.DOCUMENT_FRAGMENT_NODE){parent=parent.host}return parent},get _localeHorizontalAlign(){if(this._isRTL){if(this.horizontalAlign==="right"){return"left"}if(this.horizontalAlign==="left"){return"right"}}return this.horizontalAlign},attached:function(){this._isRTL=window.getComputedStyle(this).direction=="rtl";this.positionTarget=this.positionTarget||this._defaultPositionTarget;if(this.autoFitOnAttach){if(window.getComputedStyle(this).display==="none"){setTimeout(function(){this.fit()}.bind(this))}else{this.fit()}}},fit:function(){this.position();this.constrain();this.center()},_discoverInfo:function(){if(this._fitInfo){return}var target=window.getComputedStyle(this);var sizer=window.getComputedStyle(this.sizingTarget);this._fitInfo={inlineStyle:{top:this.style.top||"",left:this.style.left||"",position:this.style.position||""},sizerInlineStyle:{maxWidth:this.sizingTarget.style.maxWidth||"",maxHeight:this.sizingTarget.style.maxHeight||"",boxSizing:this.sizingTarget.style.boxSizing||""},positionedBy:{vertically:target.top!=="auto"?"top":target.bottom!=="auto"?"bottom":null,horizontally:target.left!=="auto"?"left":target.right!=="auto"?"right":null},sizedBy:{height:sizer.maxHeight!=="none",width:sizer.maxWidth!=="none",minWidth:parseInt(sizer.minWidth,10)||0,minHeight:parseInt(sizer.minHeight,10)||0},margin:{top:parseInt(target.marginTop,10)||0,right:parseInt(target.marginRight,10)||0,bottom:parseInt(target.marginBottom,10)||0,left:parseInt(target.marginLeft,10)||0}};if(this.verticalOffset){this._fitInfo.margin.top=this._fitInfo.margin.bottom=this.verticalOffset;this._fitInfo.inlineStyle.marginTop=this.style.marginTop||"";this._fitInfo.inlineStyle.marginBottom=this.style.marginBottom||"";this.style.marginTop=this.style.marginBottom=this.verticalOffset+"px"}if(this.horizontalOffset){this._fitInfo.margin.left=this._fitInfo.margin.right=this.horizontalOffset;this._fitInfo.inlineStyle.marginLeft=this.style.marginLeft||"";this._fitInfo.inlineStyle.marginRight=this.style.marginRight||"";this.style.marginLeft=this.style.marginRight=this.horizontalOffset+"px"}},resetFit:function(){var info=this._fitInfo||{};for(var property in info.sizerInlineStyle){this.sizingTarget.style[property]=info.sizerInlineStyle[property]}for(var property in info.inlineStyle){this.style[property]=info.inlineStyle[property]}this._fitInfo=null},refit:function(){var scrollLeft=this.sizingTarget.scrollLeft;var scrollTop=this.sizingTarget.scrollTop;this.resetFit();this.fit();this.sizingTarget.scrollLeft=scrollLeft;this.sizingTarget.scrollTop=scrollTop},position:function(){if(!this.horizontalAlign&&!this.verticalAlign){return}this._discoverInfo();this.style.position="fixed";this.sizingTarget.style.boxSizing="border-box";this.style.left="0px";this.style.top="0px";var rect=this.getBoundingClientRect();var positionRect=this.__getNormalizedRect(this.positionTarget);var fitRect=this.__getNormalizedRect(this.fitInto);var margin=this._fitInfo.margin;var size={width:rect.width+margin.left+margin.right,height:rect.height+margin.top+margin.bottom};var position=this.__getPosition(this._localeHorizontalAlign,this.verticalAlign,size,positionRect,fitRect);var left=position.left+margin.left;var top=position.top+margin.top;var right=Math.min(fitRect.right-margin.right,left+rect.width);var bottom=Math.min(fitRect.bottom-margin.bottom,top+rect.height);var minWidth=this._fitInfo.sizedBy.minWidth;var minHeight=this._fitInfo.sizedBy.minHeight;if(left<margin.left){left=margin.left;if(right-left<minWidth){left=right-minWidth}}if(top<margin.top){top=margin.top;if(bottom-top<minHeight){top=bottom-minHeight}}this.sizingTarget.style.maxWidth=right-left+"px";this.sizingTarget.style.maxHeight=bottom-top+"px";this.style.left=left-rect.left+"px";this.style.top=top-rect.top+"px"},constrain:function(){if(this.horizontalAlign||this.verticalAlign){return}this._discoverInfo();var info=this._fitInfo;if(!info.positionedBy.vertically){this.style.position="fixed";this.style.top="0px"}if(!info.positionedBy.horizontally){this.style.position="fixed";this.style.left="0px"}this.sizingTarget.style.boxSizing="border-box";var rect=this.getBoundingClientRect();if(!info.sizedBy.height){this.__sizeDimension(rect,info.positionedBy.vertically,"top","bottom","Height")}if(!info.sizedBy.width){this.__sizeDimension(rect,info.positionedBy.horizontally,"left","right","Width")}},_sizeDimension:function(rect,positionedBy,start,end,extent){this.__sizeDimension(rect,positionedBy,start,end,extent)},__sizeDimension:function(rect,positionedBy,start,end,extent){var info=this._fitInfo;var fitRect=this.__getNormalizedRect(this.fitInto);var max=extent==="Width"?fitRect.width:fitRect.height;var flip=positionedBy===end;var offset=flip?max-rect[end]:rect[start];var margin=info.margin[flip?start:end];var offsetExtent="offset"+extent;var sizingOffset=this[offsetExtent]-this.sizingTarget[offsetExtent];this.sizingTarget.style["max"+extent]=max-margin-offset-sizingOffset+"px"},center:function(){if(this.horizontalAlign||this.verticalAlign){return}this._discoverInfo();var positionedBy=this._fitInfo.positionedBy;if(positionedBy.vertically&&positionedBy.horizontally){return}this.style.position="fixed";if(!positionedBy.vertically){this.style.top="0px"}if(!positionedBy.horizontally){this.style.left="0px"}var rect=this.getBoundingClientRect();var fitRect=this.__getNormalizedRect(this.fitInto);if(!positionedBy.vertically){var top=fitRect.top-rect.top+(fitRect.height-rect.height)/2;this.style.top=top+"px"}if(!positionedBy.horizontally){var left=fitRect.left-rect.left+(fitRect.width-rect.width)/2;this.style.left=left+"px"}},__getNormalizedRect:function(target){if(target===document.documentElement||target===window){return{top:0,left:0,width:window.innerWidth,height:window.innerHeight,right:window.innerWidth,bottom:window.innerHeight}}return target.getBoundingClientRect()},__getCroppedArea:function(position,size,fitRect){var verticalCrop=Math.min(0,position.top)+Math.min(0,fitRect.bottom-(position.top+size.height));var horizontalCrop=Math.min(0,position.left)+Math.min(0,fitRect.right-(position.left+size.width));return Math.abs(verticalCrop)*size.width+Math.abs(horizontalCrop)*size.height},__getPosition:function(hAlign,vAlign,size,positionRect,fitRect){var positions=[{verticalAlign:"top",horizontalAlign:"left",top:positionRect.top,left:positionRect.left},{verticalAlign:"top",horizontalAlign:"right",top:positionRect.top,left:positionRect.right-size.width},{verticalAlign:"bottom",horizontalAlign:"left",top:positionRect.bottom-size.height,left:positionRect.left},{verticalAlign:"bottom",horizontalAlign:"right",top:positionRect.bottom-size.height,left:positionRect.right-size.width}];if(this.noOverlap){for(var i=0,l=positions.length;i<l;i++){var copy={};for(var key in positions[i]){copy[key]=positions[i][key]}positions.push(copy)}positions[0].top=positions[1].top+=positionRect.height;positions[2].top=positions[3].top-=positionRect.height;positions[4].left=positions[6].left+=positionRect.width;positions[5].left=positions[7].left-=positionRect.width}vAlign=vAlign==="auto"?null:vAlign;hAlign=hAlign==="auto"?null:hAlign;var position;for(var i=0;i<positions.length;i++){var pos=positions[i];if(!this.dynamicAlign&&!this.noOverlap&&pos.verticalAlign===vAlign&&pos.horizontalAlign===hAlign){position=pos;break}var alignOk=(!vAlign||pos.verticalAlign===vAlign)&&(!hAlign||pos.horizontalAlign===hAlign);if(!this.dynamicAlign&&!alignOk){continue}position=position||pos;pos.croppedArea=this.__getCroppedArea(pos,size,fitRect);var diff=pos.croppedArea-position.croppedArea;if(diff<0||diff===0&&alignOk){position=pos}if(position.croppedArea===0&&alignOk){break}}return position}};(function(){"use strict";Polymer({is:"iron-overlay-backdrop",properties:{opened:{reflectToAttribute:true,type:Boolean,value:false,observer:"_openedChanged"}},listeners:{transitionend:"_onTransitionend"},created:function(){this.__openedRaf=null},attached:function(){this.opened&&this._openedChanged(this.opened)},prepare:function(){if(this.opened&&!this.parentNode){Polymer.dom(document.body).appendChild(this)}},open:function(){this.opened=true},close:function(){this.opened=false},complete:function(){if(!this.opened&&this.parentNode===document.body){Polymer.dom(this.parentNode).removeChild(this)}},_onTransitionend:function(event){if(event&&event.target===this){this.complete()}},_openedChanged:function(opened){if(opened){this.prepare()}else{var cs=window.getComputedStyle(this);if(cs.transitionDuration==="0s"||cs.opacity==0){this.complete()}}if(!this.isAttached){return}if(this.__openedRaf){window.cancelAnimationFrame(this.__openedRaf);this.__openedRaf=null}this.scrollTop=this.scrollTop;this.__openedRaf=window.requestAnimationFrame(function(){this.__openedRaf=null;this.toggleClass("opened",this.opened)}.bind(this))}})})();Polymer.IronOverlayManagerClass=function(){this._overlays=[];this._minimumZ=101;this._backdropElement=null;Polymer.Gestures.add(document,"tap",this._onCaptureClick.bind(this));document.addEventListener("focus",this._onCaptureFocus.bind(this),true);document.addEventListener("keydown",this._onCaptureKeyDown.bind(this),true)};Polymer.IronOverlayManagerClass.prototype={constructor:Polymer.IronOverlayManagerClass,get backdropElement(){if(!this._backdropElement){this._backdropElement=document.createElement("iron-overlay-backdrop")}return this._backdropElement},get deepActiveElement(){var active=document.activeElement||document.body;while(active.root&&Polymer.dom(active.root).activeElement){active=Polymer.dom(active.root).activeElement}return active},_bringOverlayAtIndexToFront:function(i){var overlay=this._overlays[i];if(!overlay){return}var lastI=this._overlays.length-1;var currentOverlay=this._overlays[lastI];if(currentOverlay&&this._shouldBeBehindOverlay(overlay,currentOverlay)){lastI--}if(i>=lastI){return}var minimumZ=Math.max(this.currentOverlayZ(),this._minimumZ);if(this._getZ(overlay)<=minimumZ){this._applyOverlayZ(overlay,minimumZ)}while(i<lastI){this._overlays[i]=this._overlays[i+1];i++}this._overlays[lastI]=overlay},addOrRemoveOverlay:function(overlay){if(overlay.opened){this.addOverlay(overlay)}else{this.removeOverlay(overlay)}},addOverlay:function(overlay){var i=this._overlays.indexOf(overlay);if(i>=0){this._bringOverlayAtIndexToFront(i);this.trackBackdrop();return}var insertionIndex=this._overlays.length;var currentOverlay=this._overlays[insertionIndex-1];var minimumZ=Math.max(this._getZ(currentOverlay),this._minimumZ);var newZ=this._getZ(overlay);if(currentOverlay&&this._shouldBeBehindOverlay(overlay,currentOverlay)){this._applyOverlayZ(currentOverlay,minimumZ);insertionIndex--;var previousOverlay=this._overlays[insertionIndex-1];minimumZ=Math.max(this._getZ(previousOverlay),this._minimumZ)}if(newZ<=minimumZ){this._applyOverlayZ(overlay,minimumZ)}this._overlays.splice(insertionIndex,0,overlay);this.trackBackdrop()},removeOverlay:function(overlay){var i=this._overlays.indexOf(overlay);if(i===-1){return}this._overlays.splice(i,1);this.trackBackdrop()},currentOverlay:function(){var i=this._overlays.length-1;return this._overlays[i]},currentOverlayZ:function(){return this._getZ(this.currentOverlay())},ensureMinimumZ:function(minimumZ){this._minimumZ=Math.max(this._minimumZ,minimumZ)},focusOverlay:function(){var current=this.currentOverlay();if(current){current._applyFocus()}},trackBackdrop:function(){var overlay=this._overlayWithBackdrop();if(!overlay&&!this._backdropElement){return}this.backdropElement.style.zIndex=this._getZ(overlay)-1;this.backdropElement.opened=!!overlay},getBackdrops:function(){var backdrops=[];for(var i=0;i<this._overlays.length;i++){if(this._overlays[i].withBackdrop){backdrops.push(this._overlays[i])}}return backdrops},backdropZ:function(){return this._getZ(this._overlayWithBackdrop())-1},_overlayWithBackdrop:function(){for(var i=0;i<this._overlays.length;i++){if(this._overlays[i].withBackdrop){return this._overlays[i]}}},_getZ:function(overlay){var z=this._minimumZ;if(overlay){var z1=Number(overlay.style.zIndex||window.getComputedStyle(overlay).zIndex);if(z1===z1){z=z1}}return z},_setZ:function(element,z){element.style.zIndex=z},_applyOverlayZ:function(overlay,aboveZ){this._setZ(overlay,aboveZ+2)},_overlayInPath:function(path){path=path||[];for(var i=0;i<path.length;i++){if(path[i]._manager===this){return path[i]}}},_onCaptureClick:function(event){var overlay=this.currentOverlay();if(overlay&&this._overlayInPath(Polymer.dom(event).path)!==overlay){overlay._onCaptureClick(event)}},_onCaptureFocus:function(event){var overlay=this.currentOverlay();if(overlay){overlay._onCaptureFocus(event)}},_onCaptureKeyDown:function(event){var overlay=this.currentOverlay();if(overlay){if(Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event,"esc")){overlay._onCaptureEsc(event)}else if(Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event,"tab")){overlay._onCaptureTab(event)}}},_shouldBeBehindOverlay:function(overlay1,overlay2){return!overlay1.alwaysOnTop&&overlay2.alwaysOnTop}};Polymer.IronOverlayManager=new Polymer.IronOverlayManagerClass;(function(){"use strict";Polymer.IronOverlayBehaviorImpl={properties:{opened:{observer:"_openedChanged",type:Boolean,value:false,notify:true},canceled:{observer:"_canceledChanged",readOnly:true,
+type:Boolean,value:false},withBackdrop:{observer:"_withBackdropChanged",type:Boolean},noAutoFocus:{type:Boolean,value:false},noCancelOnEscKey:{type:Boolean,value:false},noCancelOnOutsideClick:{type:Boolean,value:false},closingReason:{type:Object},restoreFocusOnClose:{type:Boolean,value:false},alwaysOnTop:{type:Boolean},_manager:{type:Object,value:Polymer.IronOverlayManager},_focusedChild:{type:Object}},listeners:{"iron-resize":"_onIronResize"},get backdropElement(){return this._manager.backdropElement},get _focusNode(){return this._focusedChild||Polymer.dom(this).querySelector("[autofocus]")||this},get _focusableNodes(){var FOCUSABLE_WITH_DISABLED=["a[href]","area[href]","iframe","[tabindex]","[contentEditable=true]"];var FOCUSABLE_WITHOUT_DISABLED=["input","select","textarea","button"];var selector=FOCUSABLE_WITH_DISABLED.join(':not([tabindex="-1"]),')+':not([tabindex="-1"]),'+FOCUSABLE_WITHOUT_DISABLED.join(':not([disabled]):not([tabindex="-1"]),')+':not([disabled]):not([tabindex="-1"])';var focusables=Polymer.dom(this).querySelectorAll(selector);if(this.tabIndex>=0){focusables.splice(0,0,this)}return focusables.sort(function(a,b){if(a.tabIndex===b.tabIndex){return 0}if(a.tabIndex===0||a.tabIndex>b.tabIndex){return 1}return-1})},ready:function(){this.__isAnimating=false;this.__shouldRemoveTabIndex=false;this.__firstFocusableNode=this.__lastFocusableNode=null;this.__raf=null;this.__restoreFocusNode=null;this._ensureSetup()},attached:function(){if(this.opened){this._openedChanged(this.opened)}this._observer=Polymer.dom(this).observeNodes(this._onNodesChange)},detached:function(){Polymer.dom(this).unobserveNodes(this._observer);this._observer=null;if(this.__raf){window.cancelAnimationFrame(this.__raf);this.__raf=null}this._manager.removeOverlay(this)},toggle:function(){this._setCanceled(false);this.opened=!this.opened},open:function(){this._setCanceled(false);this.opened=true},close:function(){this._setCanceled(false);this.opened=false},cancel:function(event){var cancelEvent=this.fire("iron-overlay-canceled",event,{cancelable:true});if(cancelEvent.defaultPrevented){return}this._setCanceled(true);this.opened=false},_ensureSetup:function(){if(this._overlaySetup){return}this._overlaySetup=true;this.style.outline="none";this.style.display="none"},_openedChanged:function(opened){if(opened){this.removeAttribute("aria-hidden")}else{this.setAttribute("aria-hidden","true")}if(!this.isAttached){return}this.__isAnimating=true;this.__onNextAnimationFrame(this.__openedChanged)},_canceledChanged:function(){this.closingReason=this.closingReason||{};this.closingReason.canceled=this.canceled},_withBackdropChanged:function(){if(this.withBackdrop&&!this.hasAttribute("tabindex")){this.setAttribute("tabindex","-1");this.__shouldRemoveTabIndex=true}else if(this.__shouldRemoveTabIndex){this.removeAttribute("tabindex");this.__shouldRemoveTabIndex=false}if(this.opened&&this.isAttached){this._manager.trackBackdrop()}},_prepareRenderOpened:function(){this.__restoreFocusNode=this._manager.deepActiveElement;this._preparePositioning();this.refit();this._finishPositioning();if(this.noAutoFocus&&document.activeElement===this._focusNode){this._focusNode.blur();this.__restoreFocusNode.focus()}},_renderOpened:function(){this._finishRenderOpened()},_renderClosed:function(){this._finishRenderClosed()},_finishRenderOpened:function(){this.notifyResize();this.__isAnimating=false;var focusableNodes=this._focusableNodes;this.__firstFocusableNode=focusableNodes[0];this.__lastFocusableNode=focusableNodes[focusableNodes.length-1];this.fire("iron-overlay-opened")},_finishRenderClosed:function(){this.style.display="none";this.style.zIndex="";this.notifyResize();this.__isAnimating=false;this.fire("iron-overlay-closed",this.closingReason)},_preparePositioning:function(){this.style.transition=this.style.webkitTransition="none";this.style.transform=this.style.webkitTransform="none";this.style.display=""},_finishPositioning:function(){this.style.display="none";this.scrollTop=this.scrollTop;this.style.transition=this.style.webkitTransition="";this.style.transform=this.style.webkitTransform="";this.style.display="";this.scrollTop=this.scrollTop},_applyFocus:function(){if(this.opened){if(!this.noAutoFocus){this._focusNode.focus()}}else{this._focusNode.blur();this._focusedChild=null;if(this.restoreFocusOnClose&&this.__restoreFocusNode){this.__restoreFocusNode.focus()}this.__restoreFocusNode=null;var currentOverlay=this._manager.currentOverlay();if(currentOverlay&&this!==currentOverlay){currentOverlay._applyFocus()}}},_onCaptureClick:function(event){if(!this.noCancelOnOutsideClick){this.cancel(event)}},_onCaptureFocus:function(event){if(!this.withBackdrop){return}var path=Polymer.dom(event).path;if(path.indexOf(this)===-1){event.stopPropagation();this._applyFocus()}else{this._focusedChild=path[0]}},_onCaptureEsc:function(event){if(!this.noCancelOnEscKey){this.cancel(event)}},_onCaptureTab:function(event){if(!this.withBackdrop){return}var shift=event.shiftKey;var nodeToCheck=shift?this.__firstFocusableNode:this.__lastFocusableNode;var nodeToSet=shift?this.__lastFocusableNode:this.__firstFocusableNode;var shouldWrap=false;if(nodeToCheck===nodeToSet){shouldWrap=true}else{var focusedNode=this._manager.deepActiveElement;shouldWrap=focusedNode===nodeToCheck||focusedNode===this}if(shouldWrap){event.preventDefault();this._focusedChild=nodeToSet;this._applyFocus()}},_onIronResize:function(){if(this.opened&&!this.__isAnimating){this.__onNextAnimationFrame(this.refit)}},_onNodesChange:function(){if(this.opened&&!this.__isAnimating){this.notifyResize()}},__openedChanged:function(){if(this.opened){this._prepareRenderOpened();this._manager.addOverlay(this);this._applyFocus();this._renderOpened()}else{this._manager.removeOverlay(this);this._applyFocus();this._renderClosed()}},__onNextAnimationFrame:function(callback){if(this.__raf){window.cancelAnimationFrame(this.__raf)}var self=this;this.__raf=window.requestAnimationFrame(function nextAnimationFrame(){self.__raf=null;callback.call(self)})}};Polymer.IronOverlayBehavior=[Polymer.IronFitBehavior,Polymer.IronResizableBehavior,Polymer.IronOverlayBehaviorImpl]})();Polymer.NeonAnimatableBehavior={properties:{animationConfig:{type:Object},entryAnimation:{observer:"_entryAnimationChanged",type:String},exitAnimation:{observer:"_exitAnimationChanged",type:String}},_entryAnimationChanged:function(){this.animationConfig=this.animationConfig||{};this.animationConfig["entry"]=[{name:this.entryAnimation,node:this}]},_exitAnimationChanged:function(){this.animationConfig=this.animationConfig||{};this.animationConfig["exit"]=[{name:this.exitAnimation,node:this}]},_copyProperties:function(config1,config2){for(var property in config2){config1[property]=config2[property]}},_cloneConfig:function(config){var clone={isClone:true};this._copyProperties(clone,config);return clone},_getAnimationConfigRecursive:function(type,map,allConfigs){if(!this.animationConfig){return}if(this.animationConfig.value&&typeof this.animationConfig.value==="function"){this._warn(this._logf("playAnimation","Please put 'animationConfig' inside of your components 'properties' object instead of outside of it."));return}var thisConfig;if(type){thisConfig=this.animationConfig[type]}else{thisConfig=this.animationConfig}if(!Array.isArray(thisConfig)){thisConfig=[thisConfig]}if(thisConfig){for(var config,index=0;config=thisConfig[index];index++){if(config.animatable){config.animatable._getAnimationConfigRecursive(config.type||type,map,allConfigs)}else{if(config.id){var cachedConfig=map[config.id];if(cachedConfig){if(!cachedConfig.isClone){map[config.id]=this._cloneConfig(cachedConfig);cachedConfig=map[config.id]}this._copyProperties(cachedConfig,config)}else{map[config.id]=config}}else{allConfigs.push(config)}}}}},getAnimationConfig:function(type){var map={};var allConfigs=[];this._getAnimationConfigRecursive(type,map,allConfigs);for(var key in map){allConfigs.push(map[key])}return allConfigs}};Polymer.NeonAnimationRunnerBehaviorImpl={_configureAnimations:function(configs){var results=[];if(configs.length>0){for(var config,index=0;config=configs[index];index++){var neonAnimation=document.createElement(config.name);if(neonAnimation.isNeonAnimation){var result=null;try{result=neonAnimation.configure(config);if(typeof result.cancel!="function"){result=document.timeline.play(result)}}catch(e){result=null;console.warn("Couldnt play","(",config.name,").",e)}if(result){results.push({neonAnimation:neonAnimation,config:config,animation:result})}}else{console.warn(this.is+":",config.name,"not found!")}}}return results},_shouldComplete:function(activeEntries){var finished=true;for(var i=0;i<activeEntries.length;i++){if(activeEntries[i].animation.playState!="finished"){finished=false;break}}return finished},_complete:function(activeEntries){for(var i=0;i<activeEntries.length;i++){activeEntries[i].neonAnimation.complete(activeEntries[i].config)}for(var i=0;i<activeEntries.length;i++){activeEntries[i].animation.cancel()}},playAnimation:function(type,cookie){var configs=this.getAnimationConfig(type);if(!configs){return}this._active=this._active||{};if(this._active[type]){this._complete(this._active[type]);delete this._active[type]}var activeEntries=this._configureAnimations(configs);if(activeEntries.length==0){this.fire("neon-animation-finish",cookie,{bubbles:false});return}this._active[type]=activeEntries;for(var i=0;i<activeEntries.length;i++){activeEntries[i].animation.onfinish=function(){if(this._shouldComplete(activeEntries)){this._complete(activeEntries);delete this._active[type];this.fire("neon-animation-finish",cookie,{bubbles:false})}}.bind(this)}},cancelAnimation:function(){for(var k in this._animations){this._animations[k].cancel()}this._animations={}}};Polymer.NeonAnimationRunnerBehavior=[Polymer.NeonAnimatableBehavior,Polymer.NeonAnimationRunnerBehaviorImpl];Polymer.NeonAnimationBehavior={properties:{animationTiming:{type:Object,value:function(){return{duration:500,easing:"cubic-bezier(0.4, 0, 0.2, 1)",fill:"both"}}}},isNeonAnimation:true,timingFromConfig:function(config){if(config.timing){for(var property in config.timing){this.animationTiming[property]=config.timing[property]}}return this.animationTiming},setPrefixedProperty:function(node,property,value){var map={transform:["webkitTransform"],transformOrigin:["mozTransformOrigin","webkitTransformOrigin"]};var prefixes=map[property];for(var prefix,index=0;prefix=prefixes[index];index++){node.style[prefix]=value}node.style[property]=value},complete:function(){}};Polymer({is:"opaque-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;this._effect=new KeyframeEffect(node,[{opacity:"1"},{opacity:"1"}],this.timingFromConfig(config));node.style.opacity="0";return this._effect},complete:function(config){config.node.style.opacity=""}});(function(){"use strict";var LAST_TOUCH_POSITION={pageX:0,pageY:0};var ROOT_TARGET=null;var SCROLLABLE_NODES=[];Polymer.IronDropdownScrollManager={get currentLockingElement(){return this._lockingElements[this._lockingElements.length-1]},elementIsScrollLocked:function(element){var currentLockingElement=this.currentLockingElement;if(currentLockingElement===undefined)return false;var scrollLocked;if(this._hasCachedLockedElement(element)){return true}if(this._hasCachedUnlockedElement(element)){return false}scrollLocked=!!currentLockingElement&&currentLockingElement!==element&&!this._composedTreeContains(currentLockingElement,element);if(scrollLocked){this._lockedElementCache.push(element)}else{this._unlockedElementCache.push(element)}return scrollLocked},pushScrollLock:function(element){if(this._lockingElements.indexOf(element)>=0){return}if(this._lockingElements.length===0){this._lockScrollInteractions()}this._lockingElements.push(element);this._lockedElementCache=[];this._unlockedElementCache=[]},removeScrollLock:function(element){var index=this._lockingElements.indexOf(element);if(index===-1){return}this._lockingElements.splice(index,1);this._lockedElementCache=[];this._unlockedElementCache=[];if(this._lockingElements.length===0){this._unlockScrollInteractions()}},_lockingElements:[],_lockedElementCache:null,_unlockedElementCache:null,_hasCachedLockedElement:function(element){return this._lockedElementCache.indexOf(element)>-1},_hasCachedUnlockedElement:function(element){return this._unlockedElementCache.indexOf(element)>-1},_composedTreeContains:function(element,child){var contentElements;var distributedNodes;var contentIndex;var nodeIndex;if(element.contains(child)){return true}contentElements=Polymer.dom(element).querySelectorAll("content");for(contentIndex=0;contentIndex<contentElements.length;++contentIndex){distributedNodes=Polymer.dom(contentElements[contentIndex]).getDistributedNodes();for(nodeIndex=0;nodeIndex<distributedNodes.length;++nodeIndex){if(this._composedTreeContains(distributedNodes[nodeIndex],child)){return true}}}return false},_scrollInteractionHandler:function(event){if(event.cancelable&&this._shouldPreventScrolling(event)){event.preventDefault()}if(event.targetTouches){var touch=event.targetTouches[0];LAST_TOUCH_POSITION.pageX=touch.pageX;LAST_TOUCH_POSITION.pageY=touch.pageY}},_lockScrollInteractions:function(){this._boundScrollHandler=this._boundScrollHandler||this._scrollInteractionHandler.bind(this);document.addEventListener("wheel",this._boundScrollHandler,true);document.addEventListener("mousewheel",this._boundScrollHandler,true);document.addEventListener("DOMMouseScroll",this._boundScrollHandler,true);document.addEventListener("touchstart",this._boundScrollHandler,true);document.addEventListener("touchmove",this._boundScrollHandler,true)},_unlockScrollInteractions:function(){document.removeEventListener("wheel",this._boundScrollHandler,true);document.removeEventListener("mousewheel",this._boundScrollHandler,true);document.removeEventListener("DOMMouseScroll",this._boundScrollHandler,true);document.removeEventListener("touchstart",this._boundScrollHandler,true);document.removeEventListener("touchmove",this._boundScrollHandler,true)},_shouldPreventScrolling:function(event){var target=Polymer.dom(event).rootTarget;if(event.type!=="touchmove"&&ROOT_TARGET!==target){ROOT_TARGET=target;SCROLLABLE_NODES=this._getScrollableNodes(Polymer.dom(event).path)}if(!SCROLLABLE_NODES.length){return true}if(event.type==="touchstart"){return false}var info=this._getScrollInfo(event);return!this._getScrollingNode(SCROLLABLE_NODES,info.deltaX,info.deltaY)},_getScrollableNodes:function(nodes){var scrollables=[];var lockingIndex=nodes.indexOf(this.currentLockingElement);for(var i=0;i<=lockingIndex;i++){var node=nodes[i];if(node.nodeType===11){continue}var style=node.style;if(style.overflow!=="scroll"&&style.overflow!=="auto"){style=window.getComputedStyle(node)}if(style.overflow==="scroll"||style.overflow==="auto"){scrollables.push(node)}}return scrollables},_getScrollingNode:function(nodes,deltaX,deltaY){if(!deltaX&&!deltaY){return}var verticalScroll=Math.abs(deltaY)>=Math.abs(deltaX);for(var i=0;i<nodes.length;i++){var node=nodes[i];var canScroll=false;if(verticalScroll){canScroll=deltaY<0?node.scrollTop>0:node.scrollTop<node.scrollHeight-node.clientHeight}else{canScroll=deltaX<0?node.scrollLeft>0:node.scrollLeft<node.scrollWidth-node.clientWidth}if(canScroll){return node}}},_getScrollInfo:function(event){var info={deltaX:event.deltaX,deltaY:event.deltaY};if("deltaX"in event){}else if("wheelDeltaX"in event){info.deltaX=-event.wheelDeltaX;info.deltaY=-event.wheelDeltaY}else if("axis"in event){info.deltaX=event.axis===1?event.detail:0;info.deltaY=event.axis===2?event.detail:0}else if(event.targetTouches){var touch=event.targetTouches[0];info.deltaX=LAST_TOUCH_POSITION.pageX-touch.pageX;info.deltaY=LAST_TOUCH_POSITION.pageY-touch.pageY}return info}}})();(function(){"use strict";Polymer({is:"iron-dropdown",behaviors:[Polymer.IronControlState,Polymer.IronA11yKeysBehavior,Polymer.IronOverlayBehavior,Polymer.NeonAnimationRunnerBehavior],properties:{horizontalAlign:{type:String,value:"left",reflectToAttribute:true},verticalAlign:{type:String,value:"top",reflectToAttribute:true},openAnimationConfig:{type:Object},closeAnimationConfig:{type:Object},focusTarget:{type:Object},noAnimations:{type:Boolean,value:false},allowOutsideScroll:{type:Boolean,value:false},_boundOnCaptureScroll:{type:Function,value:function(){return this._onCaptureScroll.bind(this)}}},listeners:{"neon-animation-finish":"_onNeonAnimationFinish"},observers:["_updateOverlayPosition(positionTarget, verticalAlign, horizontalAlign, verticalOffset, horizontalOffset)"],get containedElement(){return Polymer.dom(this.$.content).getDistributedNodes()[0]},get _focusTarget(){return this.focusTarget||this.containedElement},ready:function(){this._scrollTop=0;this._scrollLeft=0;this._refitOnScrollRAF=null},attached:function(){if(!this.sizingTarget||this.sizingTarget===this){this.sizingTarget=this.containedElement}},detached:function(){this.cancelAnimation();document.removeEventListener("scroll",this._boundOnCaptureScroll);Polymer.IronDropdownScrollManager.removeScrollLock(this)},_openedChanged:function(){if(this.opened&&this.disabled){this.cancel()}else{this.cancelAnimation();this._updateAnimationConfig();this._saveScrollPosition();if(this.opened){document.addEventListener("scroll",this._boundOnCaptureScroll);!this.allowOutsideScroll&&Polymer.IronDropdownScrollManager.pushScrollLock(this)}else{document.removeEventListener("scroll",this._boundOnCaptureScroll);Polymer.IronDropdownScrollManager.removeScrollLock(this)}Polymer.IronOverlayBehaviorImpl._openedChanged.apply(this,arguments)}},_renderOpened:function(){if(!this.noAnimations&&this.animationConfig.open){this.$.contentWrapper.classList.add("animating");this.playAnimation("open")}else{Polymer.IronOverlayBehaviorImpl._renderOpened.apply(this,arguments)}},_renderClosed:function(){if(!this.noAnimations&&this.animationConfig.close){this.$.contentWrapper.classList.add("animating");this.playAnimation("close")}else{Polymer.IronOverlayBehaviorImpl._renderClosed.apply(this,arguments)}},_onNeonAnimationFinish:function(){this.$.contentWrapper.classList.remove("animating");if(this.opened){this._finishRenderOpened()}else{this._finishRenderClosed()}},_onCaptureScroll:function(){if(!this.allowOutsideScroll){this._restoreScrollPosition()}else{this._refitOnScrollRAF&&window.cancelAnimationFrame(this._refitOnScrollRAF);this._refitOnScrollRAF=window.requestAnimationFrame(this.refit.bind(this))}},_saveScrollPosition:function(){if(document.scrollingElement){this._scrollTop=document.scrollingElement.scrollTop;this._scrollLeft=document.scrollingElement.scrollLeft}else{this._scrollTop=Math.max(document.documentElement.scrollTop,document.body.scrollTop);this._scrollLeft=Math.max(document.documentElement.scrollLeft,document.body.scrollLeft)}},_restoreScrollPosition:function(){if(document.scrollingElement){document.scrollingElement.scrollTop=this._scrollTop;document.scrollingElement.scrollLeft=this._scrollLeft}else{document.documentElement.scrollTop=this._scrollTop;document.documentElement.scrollLeft=this._scrollLeft;document.body.scrollTop=this._scrollTop;document.body.scrollLeft=this._scrollLeft}},_updateAnimationConfig:function(){var animations=(this.openAnimationConfig||[]).concat(this.closeAnimationConfig||[]);for(var i=0;i<animations.length;i++){animations[i].node=this.containedElement}this.animationConfig={open:this.openAnimationConfig,close:this.closeAnimationConfig}},_updateOverlayPosition:function(){if(this.isAttached){this.notifyResize()}},_applyFocus:function(){var focusTarget=this.focusTarget||this.containedElement;if(focusTarget&&this.opened&&!this.noAutoFocus){focusTarget.focus()}else{Polymer.IronOverlayBehaviorImpl._applyFocus.apply(this,arguments)}}})})();Polymer({is:"fade-in-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;this._effect=new KeyframeEffect(node,[{opacity:"0"},{opacity:"1"}],this.timingFromConfig(config));return this._effect}});Polymer({is:"fade-out-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;this._effect=new KeyframeEffect(node,[{opacity:"1"},{opacity:"0"}],this.timingFromConfig(config));return this._effect}});Polymer({is:"paper-menu-grow-height-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;var rect=node.getBoundingClientRect();var height=rect.height;this._effect=new KeyframeEffect(node,[{height:height/2+"px"},{height:height+"px"}],this.timingFromConfig(config));return this._effect}});Polymer({is:"paper-menu-grow-width-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;var rect=node.getBoundingClientRect();var width=rect.width;this._effect=new KeyframeEffect(node,[{width:width/2+"px"},{width:width+"px"}],this.timingFromConfig(config));return this._effect}});Polymer({is:"paper-menu-shrink-width-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;var rect=node.getBoundingClientRect();var width=rect.width;this._effect=new KeyframeEffect(node,[{width:width+"px"},{width:width-width/20+"px"}],this.timingFromConfig(config));return this._effect}});Polymer({is:"paper-menu-shrink-height-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;var rect=node.getBoundingClientRect();var height=rect.height;var top=rect.top;this.setPrefixedProperty(node,"transformOrigin","0 0");this._effect=new KeyframeEffect(node,[{height:height+"px",transform:"translateY(0)"},{height:height/2+"px",transform:"translateY(-20px)"}],this.timingFromConfig(config));return this._effect}});(function(){"use strict";var config={ANIMATION_CUBIC_BEZIER:"cubic-bezier(.3,.95,.5,1)",MAX_ANIMATION_TIME_MS:400};var PaperMenuButton=Polymer({is:"paper-menu-button",behaviors:[Polymer.IronA11yKeysBehavior,Polymer.IronControlState],properties:{opened:{type:Boolean,value:false,notify:true,observer:"_openedChanged"},horizontalAlign:{type:String,value:"left",reflectToAttribute:true},verticalAlign:{type:String,value:"top",reflectToAttribute:true},dynamicAlign:{type:Boolean},horizontalOffset:{type:Number,value:0,notify:true},verticalOffset:{type:Number,value:0,notify:true},noOverlap:{type:Boolean},noAnimations:{type:Boolean,value:false},ignoreSelect:{type:Boolean,value:false},closeOnActivate:{type:Boolean,value:false},openAnimationConfig:{type:Object,value:function(){return[{name:"fade-in-animation",timing:{delay:100,duration:200}},{name:"paper-menu-grow-width-animation",timing:{delay:100,duration:150,easing:config.ANIMATION_CUBIC_BEZIER}},{name:"paper-menu-grow-height-animation",timing:{delay:100,duration:275,easing:config.ANIMATION_CUBIC_BEZIER}}]}},closeAnimationConfig:{type:Object,value:function(){return[{name:"fade-out-animation",timing:{duration:150}},{name:"paper-menu-shrink-width-animation",timing:{delay:100,duration:50,easing:config.ANIMATION_CUBIC_BEZIER}},{name:"paper-menu-shrink-height-animation",timing:{duration:200,easing:"ease-in"}}]}},allowOutsideScroll:{type:Boolean,value:false},restoreFocusOnClose:{type:Boolean,value:true},_dropdownContent:{type:Object}},hostAttributes:{role:"group","aria-haspopup":"true"},listeners:{"iron-activate":"_onIronActivate","iron-select":"_onIronSelect"},get contentElement(){return Polymer.dom(this.$.content).getDistributedNodes()[0]},toggle:function(){if(this.opened){this.close()}else{this.open()}},open:function(){if(this.disabled){return}this.$.dropdown.open()},close:function(){this.$.dropdown.close()},_onIronSelect:function(event){if(!this.ignoreSelect){this.close()}},_onIronActivate:function(event){if(this.closeOnActivate){this.close()}},_openedChanged:function(opened,oldOpened){if(opened){this._dropdownContent=this.contentElement;this.fire("paper-dropdown-open")}else if(oldOpened!=null){this.fire("paper-dropdown-close")}},_disabledChanged:function(disabled){Polymer.IronControlState._disabledChanged.apply(this,arguments);if(disabled&&this.opened){this.close()}},__onIronOverlayCanceled:function(event){var uiEvent=event.detail;var target=Polymer.dom(uiEvent).rootTarget;var trigger=this.$.trigger;var path=Polymer.dom(uiEvent).path;if(path.indexOf(trigger)>-1){event.preventDefault()}}});Object.keys(config).forEach(function(key){PaperMenuButton[key]=config[key]});Polymer.PaperMenuButton=PaperMenuButton})();Polymer.PaperInkyFocusBehaviorImpl={observers:["_focusedChanged(receivedFocusFromKeyboard)"],_focusedChanged:function(receivedFocusFromKeyboard){if(receivedFocusFromKeyboard){this.ensureRipple()}if(this.hasRipple()){this._ripple.holdDown=receivedFocusFromKeyboard}},_createRipple:function(){var ripple=Polymer.PaperRippleBehavior._createRipple();ripple.id="ink";ripple.setAttribute("center","");ripple.classList.add("circle");return ripple}};Polymer.PaperInkyFocusBehavior=[Polymer.IronButtonState,Polymer.IronControlState,Polymer.PaperRippleBehavior,Polymer.PaperInkyFocusBehaviorImpl];Polymer({is:"paper-icon-button",hostAttributes:{role:"button",tabindex:"0"},behaviors:[Polymer.PaperInkyFocusBehavior],properties:{src:{type:String},icon:{type:String},alt:{type:String,observer:"_altChanged"}},_altChanged:function(newValue,oldValue){var label=this.getAttribute("aria-label");if(!label||oldValue==label){this.setAttribute("aria-label",newValue)}}});Polymer({is:"iron-media-query",properties:{queryMatches:{type:Boolean,value:false,readOnly:true,notify:true},query:{type:String,observer:"queryChanged"},full:{type:Boolean,value:false},_boundMQHandler:{value:function(){return this.queryHandler.bind(this)}},_mq:{value:null}},attached:function(){this.style.display="none";this.queryChanged()},detached:function(){this._remove()},_add:function(){if(this._mq){this._mq.addListener(this._boundMQHandler)}},_remove:function(){if(this._mq){this._mq.removeListener(this._boundMQHandler)}this._mq=null},queryChanged:function(){this._remove();var query=this.query;if(!query){return}if(!this.full&&query[0]!=="("){query="("+query+")"}this._mq=window.matchMedia(query);this._add();this.queryHandler(this._mq)},queryHandler:function(mq){this._setQueryMatches(mq.matches)}});(function(){"use strict";Polymer.IronA11yAnnouncer=Polymer({is:"iron-a11y-announcer",properties:{mode:{type:String,value:"polite"},_text:{type:String,value:""}},created:function(){if(!Polymer.IronA11yAnnouncer.instance){Polymer.IronA11yAnnouncer.instance=this}document.body.addEventListener("iron-announce",this._onIronAnnounce.bind(this))},announce:function(text){this._text="";this.async(function(){this._text=text},100)},_onIronAnnounce:function(event){if(event.detail&&event.detail.text){this.announce(event.detail.text)}}});Polymer.IronA11yAnnouncer.instance=null;Polymer.IronA11yAnnouncer.requestAvailability=function(){if(!Polymer.IronA11yAnnouncer.instance){Polymer.IronA11yAnnouncer.instance=document.createElement("iron-a11y-announcer")}document.body.appendChild(Polymer.IronA11yAnnouncer.instance)}})();Polymer.IronValidatableBehaviorMeta=null;Polymer.IronValidatableBehavior={properties:{validator:{type:String},invalid:{notify:true,reflectToAttribute:true,type:Boolean,value:false},_validatorMeta:{type:Object},validatorType:{type:String,value:"validator"},_validator:{type:Object,computed:"__computeValidator(validator)"}},observers:["_invalidChanged(invalid)"],registered:function(){Polymer.IronValidatableBehaviorMeta=new Polymer.IronMeta({type:"validator"})},_invalidChanged:function(){if(this.invalid){this.setAttribute("aria-invalid","true")}else{this.removeAttribute("aria-invalid")}},hasValidator:function(){return this._validator!=null},validate:function(value){this.invalid=!this._getValidity(value);return!this.invalid},_getValidity:function(value){if(this.hasValidator()){return this._validator.validate(value)}return true},__computeValidator:function(){return Polymer.IronValidatableBehaviorMeta&&Polymer.IronValidatableBehaviorMeta.byKey(this.validator)}};Polymer({is:"iron-input","extends":"input",behaviors:[Polymer.IronValidatableBehavior],properties:{bindValue:{observer:"_bindValueChanged",type:String},preventInvalidInput:{type:Boolean},allowedPattern:{type:String,observer:"_allowedPatternChanged"},_previousValidInput:{type:String,value:""},_patternAlreadyChecked:{type:Boolean,value:false}},listeners:{input:"_onInput",keypress:"_onKeypress"},registered:function(){if(!this._canDispatchEventOnDisabled()){this._origDispatchEvent=this.dispatchEvent;this.dispatchEvent=this._dispatchEventFirefoxIE}},created:function(){Polymer.IronA11yAnnouncer.requestAvailability()},_canDispatchEventOnDisabled:function(){var input=document.createElement("input");var canDispatch=false;input.disabled=true;input.addEventListener("feature-check-dispatch-event",function(){canDispatch=true});try{input.dispatchEvent(new Event("feature-check-dispatch-event"))}catch(e){}return canDispatch},_dispatchEventFirefoxIE:function(){var disabled=this.disabled;this.disabled=false;this._origDispatchEvent.apply(this,arguments);this.disabled=disabled},get _patternRegExp(){var pattern;if(this.allowedPattern){pattern=new RegExp(this.allowedPattern)}else{switch(this.type){case"number":pattern=/[0-9.,e-]/;break}}return pattern},ready:function(){this.bindValue=this.value},_bindValueChanged:function(){if(this.value!==this.bindValue){this.value=!(this.bindValue||this.bindValue===0||this.bindValue===false)?"":this.bindValue}this.fire("bind-value-changed",{value:this.bindValue})},_allowedPatternChanged:function(){this.preventInvalidInput=this.allowedPattern?true:false},_onInput:function(){if(this.preventInvalidInput&&!this._patternAlreadyChecked){var valid=this._checkPatternValidity();if(!valid){this._announceInvalidCharacter("Invalid string of characters not entered.");this.value=this._previousValidInput}}this.bindValue=this.value;this._previousValidInput=this.value;this._patternAlreadyChecked=false},_isPrintable:function(event){var anyNonPrintable=event.keyCode==8||event.keyCode==9||event.keyCode==13||event.keyCode==27;var mozNonPrintable=event.keyCode==19||event.keyCode==20||event.keyCode==45||event.keyCode==46||event.keyCode==144||event.keyCode==145||event.keyCode>32&&event.keyCode<41||event.keyCode>111&&event.keyCode<124;return!anyNonPrintable&&!(event.charCode==0&&mozNonPrintable)},_onKeypress:function(event){if(!this.preventInvalidInput&&this.type!=="number"){return}var regexp=this._patternRegExp;if(!regexp){return}if(event.metaKey||event.ctrlKey||event.altKey)return;this._patternAlreadyChecked=true;var thisChar=String.fromCharCode(event.charCode);if(this._isPrintable(event)&&!regexp.test(thisChar)){event.preventDefault();this._announceInvalidCharacter("Invalid character "+thisChar+" not entered.")}},_checkPatternValidity:function(){var regexp=this._patternRegExp;if(!regexp){return true}for(var i=0;i<this.value.length;i++){if(!regexp.test(this.value[i])){return false}}return true},validate:function(){var valid=this.checkValidity();if(valid){if(this.required&&this.value===""){valid=false}else if(this.hasValidator()){valid=Polymer.IronValidatableBehavior.validate.call(this,this.value)}}this.invalid=!valid;this.fire("iron-input-validate");return valid},_announceInvalidCharacter:function(message){this.fire("iron-announce",{text:message})}});Polymer({is:"paper-input-container",properties:{noLabelFloat:{type:Boolean,value:false},alwaysFloatLabel:{type:Boolean,value:false},attrForValue:{type:String,value:"bind-value"},autoValidate:{type:Boolean,value:false},invalid:{observer:"_invalidChanged",type:Boolean,value:false},focused:{readOnly:true,type:Boolean,value:false,notify:true},_addons:{type:Array},_inputHasContent:{type:Boolean,value:false},_inputSelector:{type:String,value:"input,textarea,.paper-input-input"},_boundOnFocus:{type:Function,value:function(){return this._onFocus.bind(this)}},_boundOnBlur:{type:Function,value:function(){return this._onBlur.bind(this)}},_boundOnInput:{type:Function,value:function(){return this._onInput.bind(this)}},_boundValueChanged:{
+type:Function,value:function(){return this._onValueChanged.bind(this)}}},listeners:{"addon-attached":"_onAddonAttached","iron-input-validate":"_onIronInputValidate"},get _valueChangedEvent(){return this.attrForValue+"-changed"},get _propertyForValue(){return Polymer.CaseMap.dashToCamelCase(this.attrForValue)},get _inputElement(){return Polymer.dom(this).querySelector(this._inputSelector)},get _inputElementValue(){return this._inputElement[this._propertyForValue]||this._inputElement.value},ready:function(){if(!this._addons){this._addons=[]}this.addEventListener("focus",this._boundOnFocus,true);this.addEventListener("blur",this._boundOnBlur,true)},attached:function(){if(this.attrForValue){this._inputElement.addEventListener(this._valueChangedEvent,this._boundValueChanged)}else{this.addEventListener("input",this._onInput)}if(this._inputElementValue!=""){this._handleValueAndAutoValidate(this._inputElement)}else{this._handleValue(this._inputElement)}},_onAddonAttached:function(event){if(!this._addons){this._addons=[]}var target=event.target;if(this._addons.indexOf(target)===-1){this._addons.push(target);if(this.isAttached){this._handleValue(this._inputElement)}}},_onFocus:function(){this._setFocused(true)},_onBlur:function(){this._setFocused(false);this._handleValueAndAutoValidate(this._inputElement)},_onInput:function(event){this._handleValueAndAutoValidate(event.target)},_onValueChanged:function(event){this._handleValueAndAutoValidate(event.target)},_handleValue:function(inputElement){var value=this._inputElementValue;if(value||value===0||inputElement.type==="number"&&!inputElement.checkValidity()){this._inputHasContent=true}else{this._inputHasContent=false}this.updateAddons({inputElement:inputElement,value:value,invalid:this.invalid})},_handleValueAndAutoValidate:function(inputElement){if(this.autoValidate){var valid;if(inputElement.validate){valid=inputElement.validate(this._inputElementValue)}else{valid=inputElement.checkValidity()}this.invalid=!valid}this._handleValue(inputElement)},_onIronInputValidate:function(event){this.invalid=this._inputElement.invalid},_invalidChanged:function(){if(this._addons){this.updateAddons({invalid:this.invalid})}},updateAddons:function(state){for(var addon,index=0;addon=this._addons[index];index++){addon.update(state)}},_computeInputContentClass:function(noLabelFloat,alwaysFloatLabel,focused,invalid,_inputHasContent){var cls="input-content";if(!noLabelFloat){var label=this.querySelector("label");if(alwaysFloatLabel||_inputHasContent){cls+=" label-is-floating";this.$.labelAndInputContainer.style.position="static";if(invalid){cls+=" is-invalid"}else if(focused){cls+=" label-is-highlighted"}}else{if(label){this.$.labelAndInputContainer.style.position="relative"}}}else{if(_inputHasContent){cls+=" label-is-hidden"}}return cls},_computeUnderlineClass:function(focused,invalid){var cls="underline";if(invalid){cls+=" is-invalid"}else if(focused){cls+=" is-highlighted"}return cls},_computeAddOnContentClass:function(focused,invalid){var cls="add-on-content";if(invalid){cls+=" is-invalid"}else if(focused){cls+=" is-highlighted"}return cls}});Polymer.PaperSpinnerBehavior={listeners:{animationend:"__reset",webkitAnimationEnd:"__reset"},properties:{active:{type:Boolean,value:false,reflectToAttribute:true,observer:"__activeChanged"},alt:{type:String,value:"loading",observer:"__altChanged"},__coolingDown:{type:Boolean,value:false}},__computeContainerClasses:function(active,coolingDown){return[active||coolingDown?"active":"",coolingDown?"cooldown":""].join(" ")},__activeChanged:function(active,old){this.__setAriaHidden(!active);this.__coolingDown=!active&&old},__altChanged:function(alt){if(alt===this.getPropertyInfo("alt").value){this.alt=this.getAttribute("aria-label")||alt}else{this.__setAriaHidden(alt==="");this.setAttribute("aria-label",alt)}},__setAriaHidden:function(hidden){var attr="aria-hidden";if(hidden){this.setAttribute(attr,"true")}else{this.removeAttribute(attr)}},__reset:function(){this.active=false;this.__coolingDown=false}};Polymer({is:"paper-spinner-lite",behaviors:[Polymer.PaperSpinnerBehavior]});
 // 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.
-var CrSearchFieldBehavior = {
-  properties: {
-    label: {
-      type: String,
-      value: ''
-    },
-    clearLabel: {
-      type: String,
-      value: ''
-    },
-    showingSearch: {
-      type: Boolean,
-      value: false,
-      notify: true,
-      observer: 'showingSearchChanged_',
-      reflectToAttribute: true
-    },
-    lastValue_: {
-      type: String,
-      value: ''
-    }
-  },
-  getSearchInput: function() {},
-  getValue: function() {
-    return this.getSearchInput().value;
-  },
-  setValue: function(value) {
-    this.getSearchInput().bindValue = value;
-    this.onValueChanged_(value);
-  },
-  showAndFocus: function() {
-    this.showingSearch = true;
-    this.focus_();
-  },
-  focus_: function() {
-    this.getSearchInput().focus();
-  },
-  onSearchTermSearch: function() {
-    this.onValueChanged_(this.getValue());
-  },
-  onValueChanged_: function(newValue) {
-    if (newValue == this.lastValue_) return;
-    this.fire('search-changed', newValue);
-    this.lastValue_ = newValue;
-  },
-  onSearchTermKeydown: function(e) {
-    if (e.key == 'Escape') this.showingSearch = false;
-  },
-  showingSearchChanged_: function() {
-    if (this.showingSearch) {
-      this.focus_();
-      return;
-    }
-    this.setValue('');
-    this.getSearchInput().blur();
-  }
-};
-
+var CrSearchFieldBehavior={properties:{label:{type:String,value:""},clearLabel:{type:String,value:""},showingSearch:{type:Boolean,value:false,notify:true,observer:"showingSearchChanged_",reflectToAttribute:true},lastValue_:{type:String,value:""}},getSearchInput:function(){},getValue:function(){return this.getSearchInput().value},setValue:function(value){this.getSearchInput().bindValue=value;this.onValueChanged_(value)},showAndFocus:function(){this.showingSearch=true;this.focus_()},focus_:function(){this.getSearchInput().focus()},onSearchTermSearch:function(){this.onValueChanged_(this.getValue())},onValueChanged_:function(newValue){if(newValue==this.lastValue_)return;this.fire("search-changed",newValue);this.lastValue_=newValue},onSearchTermKeydown:function(e){if(e.key=="Escape")this.showingSearch=false},showingSearchChanged_:function(){if(this.showingSearch){this.focus_();return}this.setValue("");this.getSearchInput().blur()}};
 // 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.
-Polymer({
-  is: 'cr-toolbar-search-field',
-  behaviors: [ CrSearchFieldBehavior ],
-  properties: {
-    narrow: {
-      type: Boolean,
-      reflectToAttribute: true
-    },
-    label: String,
-    clearLabel: String,
-    spinnerActive: {
-      type: Boolean,
-      reflectToAttribute: true
-    },
-    hasSearchText_: Boolean,
-    isSpinnerShown_: {
-      type: Boolean,
-      computed: 'computeIsSpinnerShown_(spinnerActive, showingSearch)'
-    }
-  },
-  listeners: {
-    tap: 'showSearch_',
-    'searchInput.bind-value-changed': 'onBindValueChanged_'
-  },
-  getSearchInput: function() {
-    return this.$.searchInput;
-  },
-  isSearchFocused: function() {
-    return this.$.searchTerm.focused;
-  },
-  computeIconTabIndex_: function(narrow) {
-    return narrow ? 0 : -1;
-  },
-  computeIsSpinnerShown_: function() {
-    return this.spinnerActive && this.showingSearch;
-  },
-  onInputBlur_: function() {
-    if (!this.hasSearchText_) this.showingSearch = false;
-  },
-  onBindValueChanged_: function() {
-    var newValue = this.$.searchInput.bindValue;
-    this.hasSearchText_ = newValue != '';
-    if (newValue != '') this.showingSearch = true;
-  },
-  showSearch_: function(e) {
-    if (e.target != this.$.clearSearch) this.showingSearch = true;
-  },
-  hideSearch_: function(e) {
-    this.showingSearch = false;
-    e.stopPropagation();
-  }
-});
-
+Polymer({is:"cr-toolbar-search-field",behaviors:[CrSearchFieldBehavior],properties:{narrow:{type:Boolean,reflectToAttribute:true},label:String,clearLabel:String,spinnerActive:{type:Boolean,reflectToAttribute:true},hasSearchText_:Boolean,isSpinnerShown_:{type:Boolean,computed:"computeIsSpinnerShown_(spinnerActive, showingSearch)"}},listeners:{tap:"showSearch_","searchInput.bind-value-changed":"onBindValueChanged_"},getSearchInput:function(){return this.$.searchInput},isSearchFocused:function(){return this.$.searchTerm.focused},computeIconTabIndex_:function(narrow){return narrow?0:-1},computeIsSpinnerShown_:function(){return this.spinnerActive&&this.showingSearch},onInputBlur_:function(){if(!this.hasSearchText_)this.showingSearch=false},onBindValueChanged_:function(){var newValue=this.$.searchInput.bindValue;this.hasSearchText_=newValue!="";if(newValue!="")this.showingSearch=true},showSearch_:function(e){if(e.target!=this.$.clearSearch)this.showingSearch=true},hideSearch_:function(e){this.showingSearch=false;e.stopPropagation()}});
 // 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.
-Polymer({
-  is: 'cr-toolbar',
-  properties: {
-    pageName: String,
-    searchPrompt: String,
-    clearLabel: String,
-    menuLabel: String,
-    menuPromo: String,
-    spinnerActive: Boolean,
-    showMenu: {
-      type: Boolean,
-      value: false
-    },
-    showMenuPromo: {
-      type: Boolean,
-      value: false
-    },
-    closeMenuPromo: String,
-    narrow_: {
-      type: Boolean,
-      reflectToAttribute: true
-    },
-    showingSearch_: {
-      type: Boolean,
-      reflectToAttribute: true
-    }
-  },
-  observers: [ 'possiblyShowMenuPromo_(showMenu, showMenuPromo, showingSearch_)' ],
-  getSearchField: function() {
-    return this.$.search;
-  },
-  onClosePromoTap_: function() {
-    this.showMenuPromo = false;
-  },
-  onMenuTap_: function() {
-    this.fire('cr-menu-tap');
-    this.onClosePromoTap_();
-  },
-  possiblyShowMenuPromo_: function() {
-    Polymer.RenderStatus.afterNextRender(this, function() {
-      if (this.showMenu && this.showMenuPromo && !this.showingSearch_) {
-        this.$$('#menuPromo').animate({
-          opacity: [ 0, .9 ]
-        }, {
-          duration: 500,
-          fill: 'forwards'
-        });
-        this.fire('cr-menu-promo-shown');
-      }
-    }.bind(this));
-  },
-  titleIfNotShowMenuPromo_: function(title, showMenuPromo) {
-    return showMenuPromo ? '' : title;
-  }
-});
-
+Polymer({is:"cr-toolbar",properties:{pageName:String,searchPrompt:String,clearLabel:String,menuLabel:String,menuPromo:String,spinnerActive:Boolean,showMenu:{type:Boolean,value:false},showMenuPromo:{type:Boolean,value:false},closeMenuPromo:String,narrow_:{type:Boolean,reflectToAttribute:true},showingSearch_:{type:Boolean,reflectToAttribute:true}},observers:["possiblyShowMenuPromo_(showMenu, showMenuPromo, showingSearch_)"],getSearchField:function(){return this.$.search},onClosePromoTap_:function(){this.showMenuPromo=false},onMenuTap_:function(){this.fire("cr-menu-tap");this.onClosePromoTap_()},possiblyShowMenuPromo_:function(){Polymer.RenderStatus.afterNextRender(this,function(){if(this.showMenu&&this.showMenuPromo&&!this.showingSearch_){this.$$("#menuPromo").animate({opacity:[0,.9]},{duration:500,fill:"forwards"});this.fire("cr-menu-promo-shown")}}.bind(this))},titleIfNotShowMenuPromo_:function(title,showMenuPromo){return showMenuPromo?"":title}});
 // 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.
-cr.define('downloads', function() {
-  var Toolbar = Polymer({
-    is: 'downloads-toolbar',
-    properties: {
-      downloadsShowing: {
-        reflectToAttribute: true,
-        type: Boolean,
-        value: false,
-        observer: 'downloadsShowingChanged_'
-      },
-      spinnerActive: {
-        type: Boolean,
-        notify: true
-      }
-    },
-    listeners: {
-      'paper-dropdown-close': 'onPaperDropdownClose_',
-      'paper-dropdown-open': 'onPaperDropdownOpen_'
-    },
-    canUndo: function() {
-      return !this.$.toolbar.getSearchField().isSearchFocused();
-    },
-    canClearAll: function() {
-      return !this.$.toolbar.getSearchField().getValue() && this.downloadsShowing;
-    },
-    onFindCommand: function() {
-      this.$.toolbar.getSearchField().showAndFocus();
-    },
-    closeMoreActions_: function() {
-      this.$.more.close();
-    },
-    downloadsShowingChanged_: function() {
-      this.updateClearAll_();
-    },
-    onClearAllTap_: function() {
-      assert(this.canClearAll());
-      downloads.ActionService.getInstance().clearAll();
-    },
-    onPaperDropdownClose_: function() {
-      window.removeEventListener('resize', assert(this.boundClose_));
-    },
-    onItemBlur_: function(e) {
-      var menu = this.$$('paper-menu');
-      if (menu.items.indexOf(e.relatedTarget) >= 0) return;
-      this.$.more.restoreFocusOnClose = false;
-      this.closeMoreActions_();
-      this.$.more.restoreFocusOnClose = true;
-    },
-    onPaperDropdownOpen_: function() {
-      this.boundClose_ = this.boundClose_ || this.closeMoreActions_.bind(this);
-      window.addEventListener('resize', this.boundClose_);
-    },
-    onSearchChanged_: function(event) {
-      var actionService = downloads.ActionService.getInstance();
-      if (actionService.search(event.detail)) this.spinnerActive = actionService.isSearching();
-      this.updateClearAll_();
-    },
-    onOpenDownloadsFolderTap_: function() {
-      downloads.ActionService.getInstance().openDownloadsFolder();
-    },
-    updateClearAll_: function() {
-      this.$$('paper-menu .clear-all').hidden = !this.canClearAll();
-    }
-  });
-  return {
-    Toolbar: Toolbar
-  };
-});
-
+cr.define("downloads",function(){var Toolbar=Polymer({is:"downloads-toolbar",properties:{downloadsShowing:{reflectToAttribute:true,type:Boolean,value:false,observer:"downloadsShowingChanged_"},spinnerActive:{type:Boolean,notify:true}},listeners:{"paper-dropdown-close":"onPaperDropdownClose_","paper-dropdown-open":"onPaperDropdownOpen_"},canUndo:function(){return!this.$.toolbar.getSearchField().isSearchFocused()},canClearAll:function(){return!this.$.toolbar.getSearchField().getValue()&&this.downloadsShowing},onFindCommand:function(){this.$.toolbar.getSearchField().showAndFocus()},closeMoreActions_:function(){this.$.more.close()},downloadsShowingChanged_:function(){this.updateClearAll_()},onClearAllTap_:function(){assert(this.canClearAll());downloads.ActionService.getInstance().clearAll()},onPaperDropdownClose_:function(){window.removeEventListener("resize",assert(this.boundClose_))},onItemBlur_:function(e){var menu=this.$$("paper-menu");if(menu.items.indexOf(e.relatedTarget)>=0)return;this.$.more.restoreFocusOnClose=false;this.closeMoreActions_();this.$.more.restoreFocusOnClose=true},onPaperDropdownOpen_:function(){this.boundClose_=this.boundClose_||this.closeMoreActions_.bind(this);window.addEventListener("resize",this.boundClose_)},onSearchChanged_:function(event){var actionService=downloads.ActionService.getInstance();if(actionService.search(event.detail))this.spinnerActive=actionService.isSearching();this.updateClearAll_()},onOpenDownloadsFolderTap_:function(){downloads.ActionService.getInstance().openDownloadsFolder()},updateClearAll_:function(){this.$$("paper-menu .clear-all").hidden=!this.canClearAll()}});return{Toolbar:Toolbar}});
 // 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.
-cr.define('downloads', function() {
-  var Manager = Polymer({
-    is: 'downloads-manager',
-    properties: {
-      hasDownloads_: {
-        observer: 'hasDownloadsChanged_',
-        type: Boolean
-      },
-      hasShadow_: {
-        type: Boolean,
-        value: false,
-        reflectToAttribute: true
-      },
-      items_: {
-        type: Array,
-        value: function() {
-          return [];
-        }
-      },
-      spinnerActive_: {
-        type: Boolean,
-        notify: true
-      }
-    },
-    hostAttributes: {
-      loading: true
-    },
-    listeners: {
-      'downloads-list.scroll': 'onListScroll_'
-    },
-    observers: [ 'itemsChanged_(items_.*)' ],
-    clearAll_: function() {
-      this.set('items_', []);
-    },
-    hasDownloadsChanged_: function() {
-      if (loadTimeData.getBoolean('allowDeletingHistory')) this.$.toolbar.downloadsShowing = this.hasDownloads_;
-      if (this.hasDownloads_) {
-        this.$['downloads-list'].fire('iron-resize');
-      } else {
-        var isSearching = downloads.ActionService.getInstance().isSearching();
-        var messageToShow = isSearching ? 'noSearchResults' : 'noDownloads';
-        this.$['no-downloads'].querySelector('span').textContent = loadTimeData.getString(messageToShow);
-      }
-    },
-    insertItems_: function(index, list) {
-      this.splice.apply(this, [ 'items_', index, 0 ].concat(list));
-      this.updateHideDates_(index, index + list.length);
-      this.removeAttribute('loading');
-      this.spinnerActive_ = false;
-    },
-    itemsChanged_: function() {
-      this.hasDownloads_ = this.items_.length > 0;
-    },
-    onCanExecute_: function(e) {
-      e = e;
-      switch (e.command.id) {
-       case 'undo-command':
-        e.canExecute = this.$.toolbar.canUndo();
-        break;
-
-       case 'clear-all-command':
-        e.canExecute = this.$.toolbar.canClearAll();
-        break;
-
-       case 'find-command':
-        e.canExecute = true;
-        break;
-      }
-    },
-    onCommand_: function(e) {
-      if (e.command.id == 'clear-all-command') downloads.ActionService.getInstance().clearAll(); else if (e.command.id == 'undo-command') downloads.ActionService.getInstance().undo(); else if (e.command.id == 'find-command') this.$.toolbar.onFindCommand();
-    },
-    onListScroll_: function() {
-      var list = this.$['downloads-list'];
-      if (list.scrollHeight - list.scrollTop - list.offsetHeight <= 100) {
-        downloads.ActionService.getInstance().loadMore();
-      }
-      this.hasShadow_ = list.scrollTop > 0;
-    },
-    onLoad_: function() {
-      cr.ui.decorate('command', cr.ui.Command);
-      document.addEventListener('canExecute', this.onCanExecute_.bind(this));
-      document.addEventListener('command', this.onCommand_.bind(this));
-      downloads.ActionService.getInstance().loadMore();
-    },
-    removeItem_: function(index) {
-      this.splice('items_', index, 1);
-      this.updateHideDates_(index, index);
-      this.onListScroll_();
-    },
-    updateHideDates_: function(start, end) {
-      for (var i = start; i <= end; ++i) {
-        var current = this.items_[i];
-        if (!current) continue;
-        var prev = this.items_[i - 1];
-        current.hideDate = !!prev && prev.date_string == current.date_string;
-      }
-    },
-    updateItem_: function(index, data) {
-      this.set('items_.' + index, data);
-      this.updateHideDates_(index, index);
-      var list = this.$['downloads-list'];
-      list.updateSizeForItem(index);
-    }
-  });
-  Manager.clearAll = function() {
-    Manager.get().clearAll_();
-  };
-  Manager.get = function() {
-    return queryRequiredElement('downloads-manager');
-  };
-  Manager.insertItems = function(index, list) {
-    Manager.get().insertItems_(index, list);
-  };
-  Manager.onLoad = function() {
-    Manager.get().onLoad_();
-  };
-  Manager.removeItem = function(index) {
-    Manager.get().removeItem_(index);
-  };
-  Manager.updateItem = function(index, data) {
-    Manager.get().updateItem_(index, data);
-  };
-  return {
-    Manager: Manager
-  };
-});
-
+cr.define("downloads",function(){var Manager=Polymer({is:"downloads-manager",properties:{hasDownloads_:{observer:"hasDownloadsChanged_",type:Boolean},hasShadow_:{type:Boolean,value:false,reflectToAttribute:true},items_:{type:Array,value:function(){return[]}},spinnerActive_:{type:Boolean,notify:true}},hostAttributes:{loading:true},listeners:{"downloads-list.scroll":"onListScroll_"},observers:["itemsChanged_(items_.*)"],clearAll_:function(){this.set("items_",[])},hasDownloadsChanged_:function(){if(loadTimeData.getBoolean("allowDeletingHistory"))this.$.toolbar.downloadsShowing=this.hasDownloads_;if(this.hasDownloads_){this.$["downloads-list"].fire("iron-resize")}else{var isSearching=downloads.ActionService.getInstance().isSearching();var messageToShow=isSearching?"noSearchResults":"noDownloads";this.$["no-downloads"].querySelector("span").textContent=loadTimeData.getString(messageToShow)}},insertItems_:function(index,list){this.splice.apply(this,["items_",index,0].concat(list));this.updateHideDates_(index,index+list.length);this.removeAttribute("loading");this.spinnerActive_=false},itemsChanged_:function(){this.hasDownloads_=this.items_.length>0},onCanExecute_:function(e){e=e;switch(e.command.id){case"undo-command":e.canExecute=this.$.toolbar.canUndo();break;case"clear-all-command":e.canExecute=this.$.toolbar.canClearAll();break;case"find-command":e.canExecute=true;break}},onCommand_:function(e){if(e.command.id=="clear-all-command")downloads.ActionService.getInstance().clearAll();else if(e.command.id=="undo-command")downloads.ActionService.getInstance().undo();else if(e.command.id=="find-command")this.$.toolbar.onFindCommand()},onListScroll_:function(){var list=this.$["downloads-list"];if(list.scrollHeight-list.scrollTop-list.offsetHeight<=100){downloads.ActionService.getInstance().loadMore()}this.hasShadow_=list.scrollTop>0},onLoad_:function(){cr.ui.decorate("command",cr.ui.Command);document.addEventListener("canExecute",this.onCanExecute_.bind(this));document.addEventListener("command",this.onCommand_.bind(this));downloads.ActionService.getInstance().loadMore()},removeItem_:function(index){this.splice("items_",index,1);this.updateHideDates_(index,index);this.onListScroll_()},updateHideDates_:function(start,end){for(var i=start;i<=end;++i){var current=this.items_[i];if(!current)continue;var prev=this.items_[i-1];current.hideDate=!!prev&&prev.date_string==current.date_string}},updateItem_:function(index,data){this.set("items_."+index,data);this.updateHideDates_(index,index);var list=this.$["downloads-list"];list.updateSizeForItem(index)}});Manager.clearAll=function(){Manager.get().clearAll_()};Manager.get=function(){return queryRequiredElement("downloads-manager")};Manager.insertItems=function(index,list){Manager.get().insertItems_(index,list)};Manager.onLoad=function(){Manager.get().onLoad_()};Manager.removeItem=function(index){Manager.get().removeItem_(index)};Manager.updateItem=function(index,data){Manager.get().updateItem_(index,data)};return{Manager:Manager}});
 // 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.
-window.addEventListener('load', function() {
-  downloads.Manager.onLoad();
-  document.fonts.load('bold 12px Roboto');
-});
+window.addEventListener("load",function(){downloads.Manager.onLoad();document.fonts.load("bold 12px Roboto")});
\ No newline at end of file
diff --git a/chrome/browser/resources/md_downloads/vulcanized.html b/chrome/browser/resources/md_downloads/vulcanized.html
index 2a45dc6..b810aaa 100644
--- a/chrome/browser/resources/md_downloads/vulcanized.html
+++ b/chrome/browser/resources/md_downloads/vulcanized.html
@@ -1082,7 +1082,8 @@
 
 #content:not(.is-active) {
   background: rgba(255, 255, 255, .6);
-        box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .03), 0 1px 4px 0 rgba(0, 0, 0, .048),
+        box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .03),
+                    0 1px 4px 0 rgba(0, 0, 0, .048),
                     0 3px 1px -2px rgba(0, 0, 0, .12);
 }
 
diff --git a/chrome/browser/resources/md_history/app.crisper.js b/chrome/browser/resources/md_history/app.crisper.js
index 7f6560e2..d2666ee0 100644
--- a/chrome/browser/resources/md_history/app.crisper.js
+++ b/chrome/browser/resources/md_history/app.crisper.js
@@ -1,5527 +1,86 @@
 // 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.
-function PromiseResolver() {
-  this.resolve_;
-  this.reject_;
-  this.promise_ = new Promise(function(resolve, reject) {
-    this.resolve_ = resolve;
-    this.reject_ = reject;
-  }.bind(this));
-}
-
-PromiseResolver.prototype = {
-  get promise() {
-    return this.promise_;
-  },
-  set promise(p) {
-    assertNotReached();
-  },
-  get resolve() {
-    return this.resolve_;
-  },
-  set resolve(r) {
-    assertNotReached();
-  },
-  get reject() {
-    return this.reject_;
-  },
-  set reject(s) {
-    assertNotReached();
-  }
-};
-
+function PromiseResolver(){this.resolve_;this.reject_;this.promise_=new Promise(function(resolve,reject){this.resolve_=resolve;this.reject_=reject}.bind(this))}PromiseResolver.prototype={get promise(){return this.promise_},set promise(p){assertNotReached()},get resolve(){return this.resolve_},set resolve(r){assertNotReached()},get reject(){return this.reject_},set reject(s){assertNotReached()}};
 // 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.
-var global = this;
-
-var WebUIListener;
-
-var cr = cr || function() {
-  'use strict';
-  function exportPath(name, opt_object, opt_objectToExportTo) {
-    var parts = name.split('.');
-    var cur = opt_objectToExportTo || global;
-    for (var part; parts.length && (part = parts.shift()); ) {
-      if (!parts.length && opt_object !== undefined) {
-        cur[part] = opt_object;
-      } else if (part in cur) {
-        cur = cur[part];
-      } else {
-        cur = cur[part] = {};
-      }
-    }
-    return cur;
-  }
-  function dispatchPropertyChange(target, propertyName, newValue, oldValue) {
-    var e = new Event(propertyName + 'Change');
-    e.propertyName = propertyName;
-    e.newValue = newValue;
-    e.oldValue = oldValue;
-    target.dispatchEvent(e);
-  }
-  function getAttributeName(jsName) {
-    return jsName.replace(/([A-Z])/g, '-$1').toLowerCase();
-  }
-  var PropertyKind = {
-    JS: 'js',
-    ATTR: 'attr',
-    BOOL_ATTR: 'boolAttr'
-  };
-  function getGetter(name, kind) {
-    switch (kind) {
-     case PropertyKind.JS:
-      var privateName = name + '_';
-      return function() {
-        return this[privateName];
-      };
-
-     case PropertyKind.ATTR:
-      var attributeName = getAttributeName(name);
-      return function() {
-        return this.getAttribute(attributeName);
-      };
-
-     case PropertyKind.BOOL_ATTR:
-      var attributeName = getAttributeName(name);
-      return function() {
-        return this.hasAttribute(attributeName);
-      };
-    }
-    throw 'not reached';
-  }
-  function getSetter(name, kind, opt_setHook) {
-    switch (kind) {
-     case PropertyKind.JS:
-      var privateName = name + '_';
-      return function(value) {
-        var oldValue = this[name];
-        if (value !== oldValue) {
-          this[privateName] = value;
-          if (opt_setHook) opt_setHook.call(this, value, oldValue);
-          dispatchPropertyChange(this, name, value, oldValue);
-        }
-      };
-
-     case PropertyKind.ATTR:
-      var attributeName = getAttributeName(name);
-      return function(value) {
-        var oldValue = this[name];
-        if (value !== oldValue) {
-          if (value == undefined) this.removeAttribute(attributeName); else this.setAttribute(attributeName, value);
-          if (opt_setHook) opt_setHook.call(this, value, oldValue);
-          dispatchPropertyChange(this, name, value, oldValue);
-        }
-      };
-
-     case PropertyKind.BOOL_ATTR:
-      var attributeName = getAttributeName(name);
-      return function(value) {
-        var oldValue = this[name];
-        if (value !== oldValue) {
-          if (value) this.setAttribute(attributeName, name); else this.removeAttribute(attributeName);
-          if (opt_setHook) opt_setHook.call(this, value, oldValue);
-          dispatchPropertyChange(this, name, value, oldValue);
-        }
-      };
-    }
-    throw 'not reached';
-  }
-  function defineProperty(obj, name, opt_kind, opt_setHook) {
-    if (typeof obj == 'function') obj = obj.prototype;
-    var kind = opt_kind || PropertyKind.JS;
-    if (!obj.__lookupGetter__(name)) obj.__defineGetter__(name, getGetter(name, kind));
-    if (!obj.__lookupSetter__(name)) obj.__defineSetter__(name, getSetter(name, kind, opt_setHook));
-  }
-  var uidCounter = 1;
-  function createUid() {
-    return uidCounter++;
-  }
-  function getUid(item) {
-    if (item.hasOwnProperty('uid')) return item.uid;
-    return item.uid = createUid();
-  }
-  function dispatchSimpleEvent(target, type, opt_bubbles, opt_cancelable) {
-    var e = new Event(type, {
-      bubbles: opt_bubbles,
-      cancelable: opt_cancelable === undefined || opt_cancelable
-    });
-    return target.dispatchEvent(e);
-  }
-  function define(name, fun) {
-    var obj = exportPath(name);
-    var exports = fun();
-    for (var propertyName in exports) {
-      var propertyDescriptor = Object.getOwnPropertyDescriptor(exports, propertyName);
-      if (propertyDescriptor) Object.defineProperty(obj, propertyName, propertyDescriptor);
-    }
-  }
-  function addSingletonGetter(ctor) {
-    ctor.getInstance = function() {
-      return ctor.instance_ || (ctor.instance_ = new ctor());
-    };
-  }
-  function makePublic(ctor, methods, opt_target) {
-    methods.forEach(function(method) {
-      ctor[method] = function() {
-        var target = opt_target ? document.getElementById(opt_target) : ctor.getInstance();
-        return target[method + '_'].apply(target, arguments);
-      };
-    });
-  }
-  var chromeSendResolverMap = {};
-  function webUIResponse(id, isSuccess, response) {
-    var resolver = chromeSendResolverMap[id];
-    delete chromeSendResolverMap[id];
-    if (isSuccess) resolver.resolve(response); else resolver.reject(response);
-  }
-  function sendWithPromise(methodName, var_args) {
-    var args = Array.prototype.slice.call(arguments, 1);
-    var promiseResolver = new PromiseResolver();
-    var id = methodName + '_' + createUid();
-    chromeSendResolverMap[id] = promiseResolver;
-    chrome.send(methodName, [ id ].concat(args));
-    return promiseResolver.promise;
-  }
-  var webUIListenerMap = {};
-  function webUIListenerCallback(event, var_args) {
-    var eventListenersMap = webUIListenerMap[event];
-    if (!eventListenersMap) {
-      return;
-    }
-    var args = Array.prototype.slice.call(arguments, 1);
-    for (var listenerId in eventListenersMap) {
-      eventListenersMap[listenerId].apply(null, args);
-    }
-  }
-  function addWebUIListener(eventName, callback) {
-    webUIListenerMap[eventName] = webUIListenerMap[eventName] || {};
-    var uid = createUid();
-    webUIListenerMap[eventName][uid] = callback;
-    return {
-      eventName: eventName,
-      uid: uid
-    };
-  }
-  function removeWebUIListener(listener) {
-    var listenerExists = webUIListenerMap[listener.eventName] && webUIListenerMap[listener.eventName][listener.uid];
-    if (listenerExists) {
-      delete webUIListenerMap[listener.eventName][listener.uid];
-      return true;
-    }
-    return false;
-  }
-  return {
-    addSingletonGetter: addSingletonGetter,
-    createUid: createUid,
-    define: define,
-    defineProperty: defineProperty,
-    dispatchPropertyChange: dispatchPropertyChange,
-    dispatchSimpleEvent: dispatchSimpleEvent,
-    exportPath: exportPath,
-    getUid: getUid,
-    makePublic: makePublic,
-    PropertyKind: PropertyKind,
-    addWebUIListener: addWebUIListener,
-    removeWebUIListener: removeWebUIListener,
-    sendWithPromise: sendWithPromise,
-    webUIListenerCallback: webUIListenerCallback,
-    webUIResponse: webUIResponse,
-    get doc() {
-      return document;
-    },
-    get isMac() {
-      return /Mac/.test(navigator.platform);
-    },
-    get isWindows() {
-      return /Win/.test(navigator.platform);
-    },
-    get isChromeOS() {
-      return /CrOS/.test(navigator.userAgent);
-    },
-    get isLinux() {
-      return /Linux/.test(navigator.userAgent);
-    },
-    get isAndroid() {
-      return /Android/.test(navigator.userAgent);
-    },
-    get isIOS() {
-      return /iPad|iPhone|iPod/.test(navigator.platform);
-    }
-  };
-}();
-
+var global=this;var WebUIListener;var cr=cr||function(){"use strict";function exportPath(name,opt_object,opt_objectToExportTo){var parts=name.split(".");var cur=opt_objectToExportTo||global;for(var part;parts.length&&(part=parts.shift());){if(!parts.length&&opt_object!==undefined){cur[part]=opt_object}else if(part in cur){cur=cur[part]}else{cur=cur[part]={}}}return cur}function dispatchPropertyChange(target,propertyName,newValue,oldValue){var e=new Event(propertyName+"Change");e.propertyName=propertyName;e.newValue=newValue;e.oldValue=oldValue;target.dispatchEvent(e)}function getAttributeName(jsName){return jsName.replace(/([A-Z])/g,"-$1").toLowerCase()}var PropertyKind={JS:"js",ATTR:"attr",BOOL_ATTR:"boolAttr"};function getGetter(name,kind){switch(kind){case PropertyKind.JS:var privateName=name+"_";return function(){return this[privateName]};case PropertyKind.ATTR:var attributeName=getAttributeName(name);return function(){return this.getAttribute(attributeName)};case PropertyKind.BOOL_ATTR:var attributeName=getAttributeName(name);return function(){return this.hasAttribute(attributeName)}}throw"not reached"}function getSetter(name,kind,opt_setHook){switch(kind){case PropertyKind.JS:var privateName=name+"_";return function(value){var oldValue=this[name];if(value!==oldValue){this[privateName]=value;if(opt_setHook)opt_setHook.call(this,value,oldValue);dispatchPropertyChange(this,name,value,oldValue)}};case PropertyKind.ATTR:var attributeName=getAttributeName(name);return function(value){var oldValue=this[name];if(value!==oldValue){if(value==undefined)this.removeAttribute(attributeName);else this.setAttribute(attributeName,value);if(opt_setHook)opt_setHook.call(this,value,oldValue);dispatchPropertyChange(this,name,value,oldValue)}};case PropertyKind.BOOL_ATTR:var attributeName=getAttributeName(name);return function(value){var oldValue=this[name];if(value!==oldValue){if(value)this.setAttribute(attributeName,name);else this.removeAttribute(attributeName);if(opt_setHook)opt_setHook.call(this,value,oldValue);dispatchPropertyChange(this,name,value,oldValue)}}}throw"not reached"}function defineProperty(obj,name,opt_kind,opt_setHook){if(typeof obj=="function")obj=obj.prototype;var kind=opt_kind||PropertyKind.JS;if(!obj.__lookupGetter__(name))obj.__defineGetter__(name,getGetter(name,kind));if(!obj.__lookupSetter__(name))obj.__defineSetter__(name,getSetter(name,kind,opt_setHook))}var uidCounter=1;function createUid(){return uidCounter++}function getUid(item){if(item.hasOwnProperty("uid"))return item.uid;return item.uid=createUid()}function dispatchSimpleEvent(target,type,opt_bubbles,opt_cancelable){var e=new Event(type,{bubbles:opt_bubbles,cancelable:opt_cancelable===undefined||opt_cancelable});return target.dispatchEvent(e)}function define(name,fun){var obj=exportPath(name);var exports=fun();for(var propertyName in exports){var propertyDescriptor=Object.getOwnPropertyDescriptor(exports,propertyName);if(propertyDescriptor)Object.defineProperty(obj,propertyName,propertyDescriptor)}}function addSingletonGetter(ctor){ctor.getInstance=function(){return ctor.instance_||(ctor.instance_=new ctor)}}function makePublic(ctor,methods,opt_target){methods.forEach(function(method){ctor[method]=function(){var target=opt_target?document.getElementById(opt_target):ctor.getInstance();return target[method+"_"].apply(target,arguments)}})}var chromeSendResolverMap={};function webUIResponse(id,isSuccess,response){var resolver=chromeSendResolverMap[id];delete chromeSendResolverMap[id];if(isSuccess)resolver.resolve(response);else resolver.reject(response)}function sendWithPromise(methodName,var_args){var args=Array.prototype.slice.call(arguments,1);var promiseResolver=new PromiseResolver;var id=methodName+"_"+createUid();chromeSendResolverMap[id]=promiseResolver;chrome.send(methodName,[id].concat(args));return promiseResolver.promise}var webUIListenerMap={};function webUIListenerCallback(event,var_args){var eventListenersMap=webUIListenerMap[event];if(!eventListenersMap){return}var args=Array.prototype.slice.call(arguments,1);for(var listenerId in eventListenersMap){eventListenersMap[listenerId].apply(null,args)}}function addWebUIListener(eventName,callback){webUIListenerMap[eventName]=webUIListenerMap[eventName]||{};var uid=createUid();webUIListenerMap[eventName][uid]=callback;return{eventName:eventName,uid:uid}}function removeWebUIListener(listener){var listenerExists=webUIListenerMap[listener.eventName]&&webUIListenerMap[listener.eventName][listener.uid];if(listenerExists){delete webUIListenerMap[listener.eventName][listener.uid];return true}return false}return{addSingletonGetter:addSingletonGetter,createUid:createUid,define:define,defineProperty:defineProperty,dispatchPropertyChange:dispatchPropertyChange,dispatchSimpleEvent:dispatchSimpleEvent,exportPath:exportPath,getUid:getUid,makePublic:makePublic,PropertyKind:PropertyKind,addWebUIListener:addWebUIListener,removeWebUIListener:removeWebUIListener,sendWithPromise:sendWithPromise,webUIListenerCallback:webUIListenerCallback,webUIResponse:webUIResponse,get doc(){return document},get isMac(){return/Mac/.test(navigator.platform)},get isWindows(){return/Win/.test(navigator.platform)},get isChromeOS(){return/CrOS/.test(navigator.userAgent)},get isLinux(){return/Linux/.test(navigator.userAgent)},get isAndroid(){return/Android/.test(navigator.userAgent)},get isIOS(){return/iPad|iPhone|iPod/.test(navigator.platform)}}}();
 // 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.
-cr.define('cr.ui', function() {
-  function decorate(source, constr) {
-    var elements;
-    if (typeof source == 'string') elements = cr.doc.querySelectorAll(source); else elements = [ source ];
-    for (var i = 0, el; el = elements[i]; i++) {
-      if (!(el instanceof constr)) constr.decorate(el);
-    }
-  }
-  function createElementHelper(tagName, opt_bag) {
-    var doc;
-    if (opt_bag && opt_bag.ownerDocument) doc = opt_bag.ownerDocument; else doc = cr.doc;
-    return doc.createElement(tagName);
-  }
-  function define(tagNameOrFunction) {
-    var createFunction, tagName;
-    if (typeof tagNameOrFunction == 'function') {
-      createFunction = tagNameOrFunction;
-      tagName = '';
-    } else {
-      createFunction = createElementHelper;
-      tagName = tagNameOrFunction;
-    }
-    function f(opt_propertyBag) {
-      var el = createFunction(tagName, opt_propertyBag);
-      f.decorate(el);
-      for (var propertyName in opt_propertyBag) {
-        el[propertyName] = opt_propertyBag[propertyName];
-      }
-      return el;
-    }
-    f.decorate = function(el) {
-      el.__proto__ = f.prototype;
-      el.decorate();
-    };
-    return f;
-  }
-  function limitInputWidth(el, parentEl, min, opt_scale) {
-    el.style.width = '10px';
-    var doc = el.ownerDocument;
-    var win = doc.defaultView;
-    var computedStyle = win.getComputedStyle(el);
-    var parentComputedStyle = win.getComputedStyle(parentEl);
-    var rtl = computedStyle.direction == 'rtl';
-    var inputRect = el.getBoundingClientRect();
-    var parentRect = parentEl.getBoundingClientRect();
-    var startPos = rtl ? parentRect.right - inputRect.right : inputRect.left - parentRect.left;
-    var inner = parseInt(computedStyle.borderLeftWidth, 10) + parseInt(computedStyle.paddingLeft, 10) + parseInt(computedStyle.paddingRight, 10) + parseInt(computedStyle.borderRightWidth, 10);
-    var parentPadding = rtl ? parseInt(parentComputedStyle.paddingLeft, 10) : parseInt(parentComputedStyle.paddingRight, 10);
-    var max = parentEl.clientWidth - startPos - inner - parentPadding;
-    if (opt_scale) max *= opt_scale;
-    function limit() {
-      if (el.scrollWidth > max) {
-        el.style.width = max + 'px';
-      } else {
-        el.style.width = 0;
-        var sw = el.scrollWidth;
-        if (sw < min) {
-          el.style.width = min + 'px';
-        } else {
-          el.style.width = sw + 'px';
-        }
-      }
-    }
-    el.addEventListener('input', limit);
-    limit();
-  }
-  function toCssPx(pixels) {
-    if (!window.isFinite(pixels)) console.error('Pixel value is not a number: ' + pixels);
-    return Math.round(pixels) + 'px';
-  }
-  function swallowDoubleClick(e) {
-    var doc = e.target.ownerDocument;
-    var counter = Math.min(1, e.detail);
-    function swallow(e) {
-      e.stopPropagation();
-      e.preventDefault();
-    }
-    function onclick(e) {
-      if (e.detail > counter) {
-        counter = e.detail;
-        swallow(e);
-      } else {
-        doc.removeEventListener('dblclick', swallow, true);
-        doc.removeEventListener('click', onclick, true);
-      }
-    }
-    setTimeout(function() {
-      doc.addEventListener('click', onclick, true);
-      doc.addEventListener('dblclick', swallow, true);
-    }, 0);
-  }
-  return {
-    decorate: decorate,
-    define: define,
-    limitInputWidth: limitInputWidth,
-    toCssPx: toCssPx,
-    swallowDoubleClick: swallowDoubleClick
-  };
-});
-
+cr.define("cr.ui",function(){function decorate(source,constr){var elements;if(typeof source=="string")elements=cr.doc.querySelectorAll(source);else elements=[source];for(var i=0,el;el=elements[i];i++){if(!(el instanceof constr))constr.decorate(el)}}function createElementHelper(tagName,opt_bag){var doc;if(opt_bag&&opt_bag.ownerDocument)doc=opt_bag.ownerDocument;else doc=cr.doc;return doc.createElement(tagName)}function define(tagNameOrFunction){var createFunction,tagName;if(typeof tagNameOrFunction=="function"){createFunction=tagNameOrFunction;tagName=""}else{createFunction=createElementHelper;tagName=tagNameOrFunction}function f(opt_propertyBag){var el=createFunction(tagName,opt_propertyBag);f.decorate(el);for(var propertyName in opt_propertyBag){el[propertyName]=opt_propertyBag[propertyName]}return el}f.decorate=function(el){el.__proto__=f.prototype;el.decorate()};return f}function limitInputWidth(el,parentEl,min,opt_scale){el.style.width="10px";var doc=el.ownerDocument;var win=doc.defaultView;var computedStyle=win.getComputedStyle(el);var parentComputedStyle=win.getComputedStyle(parentEl);var rtl=computedStyle.direction=="rtl";var inputRect=el.getBoundingClientRect();var parentRect=parentEl.getBoundingClientRect();var startPos=rtl?parentRect.right-inputRect.right:inputRect.left-parentRect.left;var inner=parseInt(computedStyle.borderLeftWidth,10)+parseInt(computedStyle.paddingLeft,10)+parseInt(computedStyle.paddingRight,10)+parseInt(computedStyle.borderRightWidth,10);var parentPadding=rtl?parseInt(parentComputedStyle.paddingLeft,10):parseInt(parentComputedStyle.paddingRight,10);var max=parentEl.clientWidth-startPos-inner-parentPadding;if(opt_scale)max*=opt_scale;function limit(){if(el.scrollWidth>max){el.style.width=max+"px"}else{el.style.width=0;var sw=el.scrollWidth;if(sw<min){el.style.width=min+"px"}else{el.style.width=sw+"px"}}}el.addEventListener("input",limit);limit()}function toCssPx(pixels){if(!window.isFinite(pixels))console.error("Pixel value is not a number: "+pixels);return Math.round(pixels)+"px"}function swallowDoubleClick(e){var doc=e.target.ownerDocument;var counter=Math.min(1,e.detail);function swallow(e){e.stopPropagation();e.preventDefault()}function onclick(e){if(e.detail>counter){counter=e.detail;swallow(e)}else{doc.removeEventListener("dblclick",swallow,true);doc.removeEventListener("click",onclick,true)}}setTimeout(function(){doc.addEventListener("click",onclick,true);doc.addEventListener("dblclick",swallow,true)},0)}return{decorate:decorate,define:define,limitInputWidth:limitInputWidth,toCssPx:toCssPx,swallowDoubleClick:swallowDoubleClick}});
 // 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.
-cr.define('cr.ui', function() {
-  function KeyboardShortcut(shortcut) {
-    var mods = {};
-    var ident = '';
-    shortcut.split('|').forEach(function(part) {
-      var partLc = part.toLowerCase();
-      switch (partLc) {
-       case 'alt':
-       case 'ctrl':
-       case 'meta':
-       case 'shift':
-        mods[partLc + 'Key'] = true;
-        break;
+cr.define("cr.ui",function(){function KeyboardShortcut(shortcut){var mods={};var ident="";shortcut.split("|").forEach(function(part){var partLc=part.toLowerCase();switch(partLc){case"alt":case"ctrl":case"meta":case"shift":mods[partLc+"Key"]=true;break;default:if(ident)throw Error("Invalid shortcut");ident=part}});this.ident_=ident;this.mods_=mods}KeyboardShortcut.prototype={matchesEvent:function(e){if(e.key==this.ident_){var mods=this.mods_;return["altKey","ctrlKey","metaKey","shiftKey"].every(function(k){return e[k]==!!mods[k]})}return false}};var Command=cr.ui.define("command");Command.prototype={__proto__:HTMLElement.prototype,decorate:function(){CommandManager.init(assert(this.ownerDocument));if(this.hasAttribute("shortcut"))this.shortcut=this.getAttribute("shortcut")},execute:function(opt_element){if(this.disabled)return;var doc=this.ownerDocument;if(doc.activeElement){var e=new Event("command",{bubbles:true});e.command=this;(opt_element||doc.activeElement).dispatchEvent(e)}},canExecuteChange:function(opt_node){dispatchCanExecuteEvent(this,opt_node||this.ownerDocument.activeElement)},shortcut_:"",get shortcut(){return this.shortcut_},set shortcut(shortcut){var oldShortcut=this.shortcut_;if(shortcut!==oldShortcut){this.keyboardShortcuts_=shortcut.split(/\s+/).map(function(shortcut){return new KeyboardShortcut(shortcut)});this.shortcut_=shortcut;cr.dispatchPropertyChange(this,"shortcut",this.shortcut_,oldShortcut)}},matchesEvent:function(e){if(!this.keyboardShortcuts_)return false;return this.keyboardShortcuts_.some(function(keyboardShortcut){return keyboardShortcut.matchesEvent(e)})}};cr.defineProperty(Command,"label",cr.PropertyKind.ATTR);cr.defineProperty(Command,"disabled",cr.PropertyKind.BOOL_ATTR);cr.defineProperty(Command,"hidden",cr.PropertyKind.BOOL_ATTR);cr.defineProperty(Command,"checked",cr.PropertyKind.BOOL_ATTR);cr.defineProperty(Command,"hideShortcutText",cr.PropertyKind.BOOL_ATTR);function dispatchCanExecuteEvent(command,target){var e=new CanExecuteEvent(command);target.dispatchEvent(e);command.disabled=!e.canExecute}var commandManagers={};function CommandManager(doc){doc.addEventListener("focus",this.handleFocus_.bind(this),true);doc.addEventListener("keydown",this.handleKeyDown_.bind(this),false)}CommandManager.init=function(doc){var uid=cr.getUid(doc);if(!(uid in commandManagers)){commandManagers[uid]=new CommandManager(doc)}};CommandManager.prototype={handleFocus_:function(e){var target=e.target;if(target.menu||target.command)return;var commands=Array.prototype.slice.call(target.ownerDocument.querySelectorAll("command"));commands.forEach(function(command){dispatchCanExecuteEvent(command,target)})},handleKeyDown_:function(e){var target=e.target;var commands=Array.prototype.slice.call(target.ownerDocument.querySelectorAll("command"));for(var i=0,command;command=commands[i];i++){if(command.matchesEvent(e)){command.canExecuteChange();if(!command.disabled){e.preventDefault();e.stopPropagation();command.execute();return}}}}};function CanExecuteEvent(command){var e=new Event("canExecute",{bubbles:true,cancelable:true});e.__proto__=CanExecuteEvent.prototype;e.command=command;return e}CanExecuteEvent.prototype={__proto__:Event.prototype,command:null,canExecute_:false,get canExecute(){return this.canExecute_},set canExecute(canExecute){this.canExecute_=!!canExecute;this.stopPropagation();this.preventDefault()}};return{Command:Command,CanExecuteEvent:CanExecuteEvent}});Polymer({is:"iron-media-query",properties:{queryMatches:{type:Boolean,value:false,readOnly:true,notify:true},query:{type:String,observer:"queryChanged"},full:{type:Boolean,value:false},_boundMQHandler:{value:function(){return this.queryHandler.bind(this)}},_mq:{value:null}},attached:function(){this.style.display="none";this.queryChanged()},detached:function(){this._remove()},_add:function(){if(this._mq){this._mq.addListener(this._boundMQHandler)}},_remove:function(){if(this._mq){this._mq.removeListener(this._boundMQHandler)}this._mq=null},queryChanged:function(){this._remove();var query=this.query;if(!query){return}if(!this.full&&query[0]!=="("){query="("+query+")"}this._mq=window.matchMedia(query);this._add();this.queryHandler(this._mq)},queryHandler:function(mq){this._setQueryMatches(mq.matches)}});Polymer.IronResizableBehavior={properties:{_parentResizable:{type:Object,observer:"_parentResizableChanged"},_notifyingDescendant:{type:Boolean,value:false}},listeners:{"iron-request-resize-notifications":"_onIronRequestResizeNotifications"},created:function(){this._interestedResizables=[];this._boundNotifyResize=this.notifyResize.bind(this)},attached:function(){this.fire("iron-request-resize-notifications",null,{node:this,bubbles:true,cancelable:true});if(!this._parentResizable){window.addEventListener("resize",this._boundNotifyResize);this.notifyResize()}},detached:function(){if(this._parentResizable){this._parentResizable.stopResizeNotificationsFor(this)}else{window.removeEventListener("resize",this._boundNotifyResize)}this._parentResizable=null},notifyResize:function(){if(!this.isAttached){return}this._interestedResizables.forEach(function(resizable){if(this.resizerShouldNotify(resizable)){this._notifyDescendant(resizable)}},this);this._fireResize()},assignParentResizable:function(parentResizable){this._parentResizable=parentResizable},stopResizeNotificationsFor:function(target){var index=this._interestedResizables.indexOf(target);if(index>-1){this._interestedResizables.splice(index,1);this.unlisten(target,"iron-resize","_onDescendantIronResize")}},resizerShouldNotify:function(element){return true},_onDescendantIronResize:function(event){if(this._notifyingDescendant){event.stopPropagation();return}if(!Polymer.Settings.useShadow){this._fireResize()}},_fireResize:function(){this.fire("iron-resize",null,{node:this,bubbles:false})},_onIronRequestResizeNotifications:function(event){var target=event.path?event.path[0]:event.target;if(target===this){return}if(this._interestedResizables.indexOf(target)===-1){this._interestedResizables.push(target);this.listen(target,"iron-resize","_onDescendantIronResize")}target.assignParentResizable(this);this._notifyDescendant(target);event.stopPropagation()},_parentResizableChanged:function(parentResizable){if(parentResizable){window.removeEventListener("resize",this._boundNotifyResize)}},_notifyDescendant:function(descendant){if(!this.isAttached){return}this._notifyingDescendant=true;descendant.notifyResize();this._notifyingDescendant=false}};Polymer.IronSelection=function(selectCallback){this.selection=[];this.selectCallback=selectCallback};Polymer.IronSelection.prototype={get:function(){return this.multi?this.selection.slice():this.selection[0]},clear:function(excludes){this.selection.slice().forEach(function(item){if(!excludes||excludes.indexOf(item)<0){this.setItemSelected(item,false)}},this)},isSelected:function(item){return this.selection.indexOf(item)>=0},setItemSelected:function(item,isSelected){if(item!=null){if(isSelected!==this.isSelected(item)){if(isSelected){this.selection.push(item)}else{var i=this.selection.indexOf(item);if(i>=0){this.selection.splice(i,1)}}if(this.selectCallback){this.selectCallback(item,isSelected)}}}},select:function(item){if(this.multi){this.toggle(item)}else if(this.get()!==item){this.setItemSelected(this.get(),false);this.setItemSelected(item,true)}},toggle:function(item){this.setItemSelected(item,!this.isSelected(item))}};Polymer.IronSelectableBehavior={properties:{attrForSelected:{type:String,value:null},selected:{type:String,notify:true},selectedItem:{type:Object,readOnly:true,notify:true},activateEvent:{type:String,value:"tap",observer:"_activateEventChanged"},selectable:String,selectedClass:{type:String,value:"iron-selected"},selectedAttribute:{type:String,value:null},fallbackSelection:{type:String,value:null},items:{type:Array,readOnly:true,notify:true,value:function(){return[]}},_excludedLocalNames:{type:Object,value:function(){return{template:1}}}},observers:["_updateAttrForSelected(attrForSelected)","_updateSelected(selected)","_checkFallback(fallbackSelection)"],created:function(){this._bindFilterItem=this._filterItem.bind(this);this._selection=new Polymer.IronSelection(this._applySelection.bind(this))},attached:function(){this._observer=this._observeItems(this);this._updateItems();if(!this._shouldUpdateSelection){this._updateSelected()}this._addListener(this.activateEvent)},detached:function(){if(this._observer){Polymer.dom(this).unobserveNodes(this._observer)}this._removeListener(this.activateEvent)},indexOf:function(item){return this.items.indexOf(item)},select:function(value){this.selected=value},selectPrevious:function(){var length=this.items.length;var index=(Number(this._valueToIndex(this.selected))-1+length)%length;this.selected=this._indexToValue(index)},selectNext:function(){var index=(Number(this._valueToIndex(this.selected))+1)%this.items.length;this.selected=this._indexToValue(index)},selectIndex:function(index){this.select(this._indexToValue(index))},forceSynchronousItemUpdate:function(){this._updateItems()},get _shouldUpdateSelection(){return this.selected!=null},_checkFallback:function(){if(this._shouldUpdateSelection){this._updateSelected()}},_addListener:function(eventName){this.listen(this,eventName,"_activateHandler")},_removeListener:function(eventName){this.unlisten(this,eventName,"_activateHandler")},_activateEventChanged:function(eventName,old){this._removeListener(old);this._addListener(eventName)},_updateItems:function(){var nodes=Polymer.dom(this).queryDistributedElements(this.selectable||"*");nodes=Array.prototype.filter.call(nodes,this._bindFilterItem);this._setItems(nodes)},_updateAttrForSelected:function(){if(this._shouldUpdateSelection){this.selected=this._indexToValue(this.indexOf(this.selectedItem))}},_updateSelected:function(){this._selectSelected(this.selected)},_selectSelected:function(selected){this._selection.select(this._valueToItem(this.selected));if(this.fallbackSelection&&this.items.length&&this._selection.get()===undefined){this.selected=this.fallbackSelection}},_filterItem:function(node){return!this._excludedLocalNames[node.localName]},_valueToItem:function(value){return value==null?null:this.items[this._valueToIndex(value)]},_valueToIndex:function(value){if(this.attrForSelected){for(var i=0,item;item=this.items[i];i++){if(this._valueForItem(item)==value){return i}}}else{return Number(value)}},_indexToValue:function(index){if(this.attrForSelected){var item=this.items[index];if(item){return this._valueForItem(item)}}else{return index}},_valueForItem:function(item){var propValue=item[Polymer.CaseMap.dashToCamelCase(this.attrForSelected)];return propValue!=undefined?propValue:item.getAttribute(this.attrForSelected)},_applySelection:function(item,isSelected){if(this.selectedClass){this.toggleClass(this.selectedClass,isSelected,item)}if(this.selectedAttribute){this.toggleAttribute(this.selectedAttribute,isSelected,item)}this._selectionChange();this.fire("iron-"+(isSelected?"select":"deselect"),{item:item})},_selectionChange:function(){this._setSelectedItem(this._selection.get())},_observeItems:function(node){return Polymer.dom(node).observeNodes(function(mutation){this._updateItems();if(this._shouldUpdateSelection){this._updateSelected()}this.fire("iron-items-changed",mutation,{bubbles:false,cancelable:false})})},_activateHandler:function(e){var t=e.target;var items=this.items;while(t&&t!=this){var i=items.indexOf(t);if(i>=0){var value=this._indexToValue(i);this._itemActivate(value,t);return}t=t.parentNode}},_itemActivate:function(value,item){if(!this.fire("iron-activate",{selected:value,item:item},{cancelable:true}).defaultPrevented){this.select(value)}}};Polymer({is:"iron-pages",behaviors:[Polymer.IronResizableBehavior,Polymer.IronSelectableBehavior],properties:{activateEvent:{type:String,value:null}},observers:["_selectedPageChanged(selected)"],_selectedPageChanged:function(selected,old){this.async(this.notifyResize)}});Polymer.IronScrollTargetBehavior={properties:{scrollTarget:{type:HTMLElement,value:function(){return this._defaultScrollTarget}}},observers:["_scrollTargetChanged(scrollTarget, isAttached)"],_scrollTargetChanged:function(scrollTarget,isAttached){var eventTarget;if(this._oldScrollTarget){eventTarget=this._oldScrollTarget===this._doc?window:this._oldScrollTarget;eventTarget.removeEventListener("scroll",this._boundScrollHandler);this._oldScrollTarget=null}if(!isAttached){return}if(scrollTarget==="document"){this.scrollTarget=this._doc}else if(typeof scrollTarget==="string"){this.scrollTarget=this.domHost?this.domHost.$[scrollTarget]:Polymer.dom(this.ownerDocument).querySelector("#"+scrollTarget)}else if(this._isValidScrollTarget()){eventTarget=scrollTarget===this._doc?window:scrollTarget;this._boundScrollHandler=this._boundScrollHandler||this._scrollHandler.bind(this);this._oldScrollTarget=scrollTarget;eventTarget.addEventListener("scroll",this._boundScrollHandler)}},_scrollHandler:function scrollHandler(){},get _defaultScrollTarget(){return this._doc},get _doc(){return this.ownerDocument.documentElement},get _scrollTop(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.pageYOffset:this.scrollTarget.scrollTop}return 0},get _scrollLeft(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.pageXOffset:this.scrollTarget.scrollLeft}return 0},set _scrollTop(top){if(this.scrollTarget===this._doc){window.scrollTo(window.pageXOffset,top)}else if(this._isValidScrollTarget()){this.scrollTarget.scrollTop=top}},set _scrollLeft(left){if(this.scrollTarget===this._doc){window.scrollTo(left,window.pageYOffset)}else if(this._isValidScrollTarget()){this.scrollTarget.scrollLeft=left}},scroll:function(left,top){if(this.scrollTarget===this._doc){window.scrollTo(left,top)}else if(this._isValidScrollTarget()){this.scrollTarget.scrollLeft=left;this.scrollTarget.scrollTop=top}},get _scrollTargetWidth(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.innerWidth:this.scrollTarget.offsetWidth}return 0},get _scrollTargetHeight(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.innerHeight:this.scrollTarget.offsetHeight}return 0},_isValidScrollTarget:function(){return this.scrollTarget instanceof HTMLElement}};(function(){var metaDatas={};var metaArrays={};var singleton=null;Polymer.IronMeta=Polymer({is:"iron-meta",properties:{type:{type:String,value:"default",observer:"_typeChanged"},key:{type:String,observer:"_keyChanged"},value:{type:Object,notify:true,observer:"_valueChanged"},self:{type:Boolean,observer:"_selfChanged"},list:{type:Array,notify:true}},hostAttributes:{hidden:true},factoryImpl:function(config){if(config){for(var n in config){switch(n){case"type":case"key":case"value":this[n]=config[n];break}}}},created:function(){this._metaDatas=metaDatas;this._metaArrays=metaArrays},_keyChanged:function(key,old){this._resetRegistration(old)},_valueChanged:function(value){this._resetRegistration(this.key)},_selfChanged:function(self){if(self){this.value=this}},_typeChanged:function(type){this._unregisterKey(this.key);if(!metaDatas[type]){metaDatas[type]={}}this._metaData=metaDatas[type];if(!metaArrays[type]){metaArrays[type]=[]}this.list=metaArrays[type];this._registerKeyValue(this.key,this.value)},byKey:function(key){return this._metaData&&this._metaData[key]},_resetRegistration:function(oldKey){this._unregisterKey(oldKey);this._registerKeyValue(this.key,this.value)},_unregisterKey:function(key){this._unregister(key,this._metaData,this.list)},_registerKeyValue:function(key,value){this._register(key,value,this._metaData,this.list)},_register:function(key,value,data,list){if(key&&data&&value!==undefined){data[key]=value;list.push(value)}},_unregister:function(key,data,list){if(key&&data){if(key in data){var value=data[key];delete data[key];this.arrayDelete(list,value)}}}});Polymer.IronMeta.getIronMeta=function getIronMeta(){if(singleton===null){singleton=new Polymer.IronMeta}return singleton};Polymer.IronMetaQuery=Polymer({is:"iron-meta-query",properties:{type:{type:String,value:"default",observer:"_typeChanged"},key:{type:String,observer:"_keyChanged"},value:{type:Object,notify:true,readOnly:true},list:{type:Array,notify:true}},factoryImpl:function(config){if(config){for(var n in config){switch(n){case"type":case"key":this[n]=config[n];break}}}},created:function(){this._metaDatas=metaDatas;this._metaArrays=metaArrays},_keyChanged:function(key){this._setValue(this._metaData&&this._metaData[key])},_typeChanged:function(type){this._metaData=metaDatas[type];this.list=metaArrays[type];if(this.key){this._keyChanged(this.key)}},byKey:function(key){return this._metaData&&this._metaData[key]}})})();Polymer({is:"iron-icon",properties:{icon:{type:String,observer:"_iconChanged"},theme:{type:String,observer:"_updateIcon"},src:{type:String,observer:"_srcChanged"},_meta:{value:Polymer.Base.create("iron-meta",{type:"iconset"}),observer:"_updateIcon"}},_DEFAULT_ICONSET:"icons",_iconChanged:function(icon){var parts=(icon||"").split(":");this._iconName=parts.pop();this._iconsetName=parts.pop()||this._DEFAULT_ICONSET;this._updateIcon()},_srcChanged:function(src){this._updateIcon()},_usesIconset:function(){return this.icon||!this.src},_updateIcon:function(){if(this._usesIconset()){if(this._img&&this._img.parentNode){Polymer.dom(this.root).removeChild(this._img)}if(this._iconName===""){if(this._iconset){this._iconset.removeIcon(this)}}else if(this._iconsetName&&this._meta){this._iconset=this._meta.byKey(this._iconsetName);if(this._iconset){this._iconset.applyIcon(this,this._iconName,this.theme);this.unlisten(window,"iron-iconset-added","_updateIcon")}else{this.listen(window,"iron-iconset-added","_updateIcon")}}}else{if(this._iconset){this._iconset.removeIcon(this)}if(!this._img){this._img=document.createElement("img");this._img.style.width="100%";this._img.style.height="100%";this._img.draggable=false}this._img.src=this.src;Polymer.dom(this.root).appendChild(this._img)}}});(function(){"use strict";var KEY_IDENTIFIER={"U+0008":"backspace","U+0009":"tab","U+001B":"esc","U+0020":"space","U+007F":"del"};var KEY_CODE={8:"backspace",9:"tab",13:"enter",27:"esc",33:"pageup",34:"pagedown",35:"end",36:"home",32:"space",37:"left",38:"up",39:"right",40:"down",46:"del",106:"*"};var MODIFIER_KEYS={shift:"shiftKey",ctrl:"ctrlKey",alt:"altKey",meta:"metaKey"};var KEY_CHAR=/[a-z0-9*]/;var IDENT_CHAR=/U\+/;var ARROW_KEY=/^arrow/;var SPACE_KEY=/^space(bar)?/;var ESC_KEY=/^escape$/;function transformKey(key,noSpecialChars){var validKey="";if(key){var lKey=key.toLowerCase();if(lKey===" "||SPACE_KEY.test(lKey)){validKey="space"}else if(ESC_KEY.test(lKey)){validKey="esc"}else if(lKey.length==1){if(!noSpecialChars||KEY_CHAR.test(lKey)){validKey=lKey}}else if(ARROW_KEY.test(lKey)){validKey=lKey.replace("arrow","")}else if(lKey=="multiply"){validKey="*"}else{validKey=lKey}}return validKey}function transformKeyIdentifier(keyIdent){var validKey="";if(keyIdent){if(keyIdent in KEY_IDENTIFIER){validKey=KEY_IDENTIFIER[keyIdent]}else if(IDENT_CHAR.test(keyIdent)){keyIdent=parseInt(keyIdent.replace("U+","0x"),16);validKey=String.fromCharCode(keyIdent).toLowerCase()}else{validKey=keyIdent.toLowerCase()}}return validKey}function transformKeyCode(keyCode){var validKey="";if(Number(keyCode)){if(keyCode>=65&&keyCode<=90){validKey=String.fromCharCode(32+keyCode)}else if(keyCode>=112&&keyCode<=123){validKey="f"+(keyCode-112)}else if(keyCode>=48&&keyCode<=57){validKey=String(keyCode-48)}else if(keyCode>=96&&keyCode<=105){validKey=String(keyCode-96)}else{validKey=KEY_CODE[keyCode]}}return validKey}function normalizedKeyForEvent(keyEvent,noSpecialChars){if(keyEvent.key){return transformKey(keyEvent.key,noSpecialChars)}if(keyEvent.detail&&keyEvent.detail.key){return transformKey(keyEvent.detail.key,noSpecialChars)}return transformKeyIdentifier(keyEvent.keyIdentifier)||transformKeyCode(keyEvent.keyCode)||""}function keyComboMatchesEvent(keyCombo,event){var keyEvent=normalizedKeyForEvent(event,keyCombo.hasModifiers);return keyEvent===keyCombo.key&&(!keyCombo.hasModifiers||!!event.shiftKey===!!keyCombo.shiftKey&&!!event.ctrlKey===!!keyCombo.ctrlKey&&!!event.altKey===!!keyCombo.altKey&&!!event.metaKey===!!keyCombo.metaKey)}function parseKeyComboString(keyComboString){if(keyComboString.length===1){return{combo:keyComboString,key:keyComboString,event:"keydown"}}return keyComboString.split("+").reduce(function(parsedKeyCombo,keyComboPart){var eventParts=keyComboPart.split(":");var keyName=eventParts[0];var event=eventParts[1];if(keyName in MODIFIER_KEYS){parsedKeyCombo[MODIFIER_KEYS[keyName]]=true;parsedKeyCombo.hasModifiers=true}else{parsedKeyCombo.key=keyName;parsedKeyCombo.event=event||"keydown"}return parsedKeyCombo},{combo:keyComboString.split(":").shift()})}function parseEventString(eventString){return eventString.trim().split(" ").map(function(keyComboString){return parseKeyComboString(keyComboString)})}Polymer.IronA11yKeysBehavior={properties:{keyEventTarget:{type:Object,value:function(){return this}},stopKeyboardEventPropagation:{type:Boolean,value:false},_boundKeyHandlers:{type:Array,value:function(){return[]}},_imperativeKeyBindings:{type:Object,value:function(){return{}}}},observers:["_resetKeyEventListeners(keyEventTarget, _boundKeyHandlers)"],keyBindings:{},registered:function(){this._prepKeyBindings()},attached:function(){this._listenKeyEventListeners()},detached:function(){this._unlistenKeyEventListeners()},addOwnKeyBinding:function(eventString,handlerName){this._imperativeKeyBindings[eventString]=handlerName;this._prepKeyBindings();this._resetKeyEventListeners()},removeOwnKeyBindings:function(){this._imperativeKeyBindings={};this._prepKeyBindings();this._resetKeyEventListeners()},keyboardEventMatchesKeys:function(event,eventString){var keyCombos=parseEventString(eventString);for(var i=0;i<keyCombos.length;++i){if(keyComboMatchesEvent(keyCombos[i],event)){return true}}return false},_collectKeyBindings:function(){var keyBindings=this.behaviors.map(function(behavior){return behavior.keyBindings});if(keyBindings.indexOf(this.keyBindings)===-1){keyBindings.push(this.keyBindings)}return keyBindings},_prepKeyBindings:function(){this._keyBindings={};this._collectKeyBindings().forEach(function(keyBindings){for(var eventString in keyBindings){this._addKeyBinding(eventString,keyBindings[eventString])}},this);for(var eventString in this._imperativeKeyBindings){this._addKeyBinding(eventString,this._imperativeKeyBindings[eventString])}for(var eventName in this._keyBindings){this._keyBindings[eventName].sort(function(kb1,kb2){var b1=kb1[0].hasModifiers;var b2=kb2[0].hasModifiers;return b1===b2?0:b1?-1:1})}},_addKeyBinding:function(eventString,handlerName){parseEventString(eventString).forEach(function(keyCombo){this._keyBindings[keyCombo.event]=this._keyBindings[keyCombo.event]||[];this._keyBindings[keyCombo.event].push([keyCombo,handlerName])},this)},_resetKeyEventListeners:function(){this._unlistenKeyEventListeners();if(this.isAttached){this._listenKeyEventListeners()}},_listenKeyEventListeners:function(){if(!this.keyEventTarget){return}Object.keys(this._keyBindings).forEach(function(eventName){var keyBindings=this._keyBindings[eventName];var boundKeyHandler=this._onKeyBindingEvent.bind(this,keyBindings);this._boundKeyHandlers.push([this.keyEventTarget,eventName,boundKeyHandler]);this.keyEventTarget.addEventListener(eventName,boundKeyHandler)},this)},_unlistenKeyEventListeners:function(){var keyHandlerTuple;var keyEventTarget;var eventName;var boundKeyHandler;while(this._boundKeyHandlers.length){keyHandlerTuple=this._boundKeyHandlers.pop();keyEventTarget=keyHandlerTuple[0];eventName=keyHandlerTuple[1];boundKeyHandler=keyHandlerTuple[2];keyEventTarget.removeEventListener(eventName,boundKeyHandler)}},_onKeyBindingEvent:function(keyBindings,event){if(this.stopKeyboardEventPropagation){event.stopPropagation()}if(event.defaultPrevented){return}for(var i=0;i<keyBindings.length;i++){var keyCombo=keyBindings[i][0];var handlerName=keyBindings[i][1];if(keyComboMatchesEvent(keyCombo,event)){this._triggerKeyHandler(keyCombo,handlerName,event);if(event.defaultPrevented){return}}}},_triggerKeyHandler:function(keyCombo,handlerName,keyboardEvent){var detail=Object.create(keyCombo);detail.keyboardEvent=keyboardEvent;var event=new CustomEvent(keyCombo.event,{detail:detail,cancelable:true});this[handlerName].call(this,event);if(event.defaultPrevented){keyboardEvent.preventDefault()}}}})();Polymer.IronControlState={properties:{focused:{type:Boolean,value:false,notify:true,readOnly:true,reflectToAttribute:true},disabled:{type:Boolean,value:false,notify:true,observer:"_disabledChanged",reflectToAttribute:true},_oldTabIndex:{type:Number},_boundFocusBlurHandler:{type:Function,value:function(){return this._focusBlurHandler.bind(this)}}},observers:["_changedControlState(focused, disabled)"],ready:function(){this.addEventListener("focus",this._boundFocusBlurHandler,true);this.addEventListener("blur",this._boundFocusBlurHandler,true)},_focusBlurHandler:function(event){if(event.target===this){this._setFocused(event.type==="focus")}else if(!this.shadowRoot){var target=Polymer.dom(event).localTarget;if(!this.isLightDescendant(target)){this.fire(event.type,{sourceEvent:event},{node:this,bubbles:event.bubbles,cancelable:event.cancelable})}}},_disabledChanged:function(disabled,old){this.setAttribute("aria-disabled",disabled?"true":"false");this.style.pointerEvents=disabled?"none":"";if(disabled){this._oldTabIndex=this.tabIndex;this._setFocused(false);this.tabIndex=-1;this.blur()}else if(this._oldTabIndex!==undefined){this.tabIndex=this._oldTabIndex}},_changedControlState:function(){if(this._controlStateChanged){this._controlStateChanged()}}};Polymer.IronButtonStateImpl={properties:{pressed:{type:Boolean,readOnly:true,value:false,reflectToAttribute:true,observer:"_pressedChanged"},toggles:{type:Boolean,value:false,reflectToAttribute:true},active:{type:Boolean,value:false,notify:true,reflectToAttribute:true},pointerDown:{type:Boolean,readOnly:true,value:false},receivedFocusFromKeyboard:{type:Boolean,readOnly:true},ariaActiveAttribute:{type:String,value:"aria-pressed",observer:"_ariaActiveAttributeChanged"}},listeners:{down:"_downHandler",up:"_upHandler",tap:"_tapHandler"},observers:["_detectKeyboardFocus(focused)","_activeChanged(active, ariaActiveAttribute)"],keyBindings:{"enter:keydown":"_asyncClick","space:keydown":"_spaceKeyDownHandler","space:keyup":"_spaceKeyUpHandler"},_mouseEventRe:/^mouse/,_tapHandler:function(){if(this.toggles){this._userActivate(!this.active)}else{this.active=false}},_detectKeyboardFocus:function(focused){this._setReceivedFocusFromKeyboard(!this.pointerDown&&focused)},_userActivate:function(active){if(this.active!==active){this.active=active;this.fire("change")}},_downHandler:function(event){this._setPointerDown(true);this._setPressed(true);this._setReceivedFocusFromKeyboard(false)},_upHandler:function(){this._setPointerDown(false);this._setPressed(false)},_spaceKeyDownHandler:function(event){var keyboardEvent=event.detail.keyboardEvent;var target=Polymer.dom(keyboardEvent).localTarget;if(this.isLightDescendant(target))return;keyboardEvent.preventDefault();keyboardEvent.stopImmediatePropagation();this._setPressed(true)},_spaceKeyUpHandler:function(event){var keyboardEvent=event.detail.keyboardEvent;var target=Polymer.dom(keyboardEvent).localTarget;if(this.isLightDescendant(target))return;if(this.pressed){this._asyncClick()}this._setPressed(false)},_asyncClick:function(){this.async(function(){this.click()},1)},_pressedChanged:function(pressed){this._changedButtonState()},_ariaActiveAttributeChanged:function(value,oldValue){if(oldValue&&oldValue!=value&&this.hasAttribute(oldValue)){this.removeAttribute(oldValue)}},_activeChanged:function(active,ariaActiveAttribute){if(this.toggles){this.setAttribute(this.ariaActiveAttribute,active?"true":"false")}else{this.removeAttribute(this.ariaActiveAttribute)}this._changedButtonState()},_controlStateChanged:function(){if(this.disabled){this._setPressed(false)}else{this._changedButtonState()}},_changedButtonState:function(){if(this._buttonStateChanged){this._buttonStateChanged()}}};Polymer.IronButtonState=[Polymer.IronA11yKeysBehavior,Polymer.IronButtonStateImpl];(function(){var Utility={distance:function(x1,y1,x2,y2){var xDelta=x1-x2;var yDelta=y1-y2;return Math.sqrt(xDelta*xDelta+yDelta*yDelta)},now:window.performance&&window.performance.now?window.performance.now.bind(window.performance):Date.now};function ElementMetrics(element){this.element=element;this.width=this.boundingRect.width;this.height=this.boundingRect.height;this.size=Math.max(this.width,this.height)}ElementMetrics.prototype={get boundingRect(){return this.element.getBoundingClientRect()},furthestCornerDistanceFrom:function(x,y){var topLeft=Utility.distance(x,y,0,0);var topRight=Utility.distance(x,y,this.width,0);var bottomLeft=Utility.distance(x,y,0,this.height);var bottomRight=Utility.distance(x,y,this.width,this.height);return Math.max(topLeft,topRight,bottomLeft,bottomRight)}};function Ripple(element){this.element=element;this.color=window.getComputedStyle(element).color;this.wave=document.createElement("div");this.waveContainer=document.createElement("div");this.wave.style.backgroundColor=this.color;this.wave.classList.add("wave");this.waveContainer.classList.add("wave-container");Polymer.dom(this.waveContainer).appendChild(this.wave);this.resetInteractionState()}Ripple.MAX_RADIUS=300;Ripple.prototype={get recenters(){return this.element.recenters},get center(){return this.element.center},get mouseDownElapsed(){var elapsed;if(!this.mouseDownStart){return 0}elapsed=Utility.now()-this.mouseDownStart;if(this.mouseUpStart){elapsed-=this.mouseUpElapsed}return elapsed},get mouseUpElapsed(){return this.mouseUpStart?Utility.now()-this.mouseUpStart:0},get mouseDownElapsedSeconds(){return this.mouseDownElapsed/1e3},get mouseUpElapsedSeconds(){return this.mouseUpElapsed/1e3},get mouseInteractionSeconds(){return this.mouseDownElapsedSeconds+this.mouseUpElapsedSeconds},get initialOpacity(){return this.element.initialOpacity},get opacityDecayVelocity(){return this.element.opacityDecayVelocity},get radius(){var width2=this.containerMetrics.width*this.containerMetrics.width;var height2=this.containerMetrics.height*this.containerMetrics.height;var waveRadius=Math.min(Math.sqrt(width2+height2),Ripple.MAX_RADIUS)*1.1+5;var duration=1.1-.2*(waveRadius/Ripple.MAX_RADIUS);var timeNow=this.mouseInteractionSeconds/duration;var size=waveRadius*(1-Math.pow(80,-timeNow));return Math.abs(size)},get opacity(){if(!this.mouseUpStart){return this.initialOpacity}return Math.max(0,this.initialOpacity-this.mouseUpElapsedSeconds*this.opacityDecayVelocity)},get outerOpacity(){var outerOpacity=this.mouseUpElapsedSeconds*.3;var waveOpacity=this.opacity;return Math.max(0,Math.min(outerOpacity,waveOpacity))},get isOpacityFullyDecayed(){return this.opacity<.01&&this.radius>=Math.min(this.maxRadius,Ripple.MAX_RADIUS)},get isRestingAtMaxRadius(){return this.opacity>=this.initialOpacity&&this.radius>=Math.min(this.maxRadius,Ripple.MAX_RADIUS)},get isAnimationComplete(){return this.mouseUpStart?this.isOpacityFullyDecayed:this.isRestingAtMaxRadius},get translationFraction(){return Math.min(1,this.radius/this.containerMetrics.size*2/Math.sqrt(2))},get xNow(){if(this.xEnd){return this.xStart+this.translationFraction*(this.xEnd-this.xStart)}return this.xStart},get yNow(){if(this.yEnd){return this.yStart+this.translationFraction*(this.yEnd-this.yStart)}return this.yStart},get isMouseDown(){return this.mouseDownStart&&!this.mouseUpStart},resetInteractionState:function(){this.maxRadius=0;this.mouseDownStart=0;this.mouseUpStart=0;this.xStart=0;this.yStart=0;this.xEnd=0;this.yEnd=0;this.slideDistance=0;this.containerMetrics=new ElementMetrics(this.element)},draw:function(){var scale;var translateString;var dx;var dy;this.wave.style.opacity=this.opacity;scale=this.radius/(this.containerMetrics.size/2);dx=this.xNow-this.containerMetrics.width/2;
 
-       default:
-        if (ident) throw Error('Invalid shortcut');
-        ident = part;
-      }
-    });
-    this.ident_ = ident;
-    this.mods_ = mods;
-  }
-  KeyboardShortcut.prototype = {
-    matchesEvent: function(e) {
-      if (e.key == this.ident_) {
-        var mods = this.mods_;
-        return [ 'altKey', 'ctrlKey', 'metaKey', 'shiftKey' ].every(function(k) {
-          return e[k] == !!mods[k];
-        });
-      }
-      return false;
-    }
-  };
-  var Command = cr.ui.define('command');
-  Command.prototype = {
-    __proto__: HTMLElement.prototype,
-    decorate: function() {
-      CommandManager.init(assert(this.ownerDocument));
-      if (this.hasAttribute('shortcut')) this.shortcut = this.getAttribute('shortcut');
-    },
-    execute: function(opt_element) {
-      if (this.disabled) return;
-      var doc = this.ownerDocument;
-      if (doc.activeElement) {
-        var e = new Event('command', {
-          bubbles: true
-        });
-        e.command = this;
-        (opt_element || doc.activeElement).dispatchEvent(e);
-      }
-    },
-    canExecuteChange: function(opt_node) {
-      dispatchCanExecuteEvent(this, opt_node || this.ownerDocument.activeElement);
-    },
-    shortcut_: '',
-    get shortcut() {
-      return this.shortcut_;
-    },
-    set shortcut(shortcut) {
-      var oldShortcut = this.shortcut_;
-      if (shortcut !== oldShortcut) {
-        this.keyboardShortcuts_ = shortcut.split(/\s+/).map(function(shortcut) {
-          return new KeyboardShortcut(shortcut);
-        });
-        this.shortcut_ = shortcut;
-        cr.dispatchPropertyChange(this, 'shortcut', this.shortcut_, oldShortcut);
-      }
-    },
-    matchesEvent: function(e) {
-      if (!this.keyboardShortcuts_) return false;
-      return this.keyboardShortcuts_.some(function(keyboardShortcut) {
-        return keyboardShortcut.matchesEvent(e);
-      });
-    }
-  };
-  cr.defineProperty(Command, 'label', cr.PropertyKind.ATTR);
-  cr.defineProperty(Command, 'disabled', cr.PropertyKind.BOOL_ATTR);
-  cr.defineProperty(Command, 'hidden', cr.PropertyKind.BOOL_ATTR);
-  cr.defineProperty(Command, 'checked', cr.PropertyKind.BOOL_ATTR);
-  cr.defineProperty(Command, 'hideShortcutText', cr.PropertyKind.BOOL_ATTR);
-  function dispatchCanExecuteEvent(command, target) {
-    var e = new CanExecuteEvent(command);
-    target.dispatchEvent(e);
-    command.disabled = !e.canExecute;
-  }
-  var commandManagers = {};
-  function CommandManager(doc) {
-    doc.addEventListener('focus', this.handleFocus_.bind(this), true);
-    doc.addEventListener('keydown', this.handleKeyDown_.bind(this), false);
-  }
-  CommandManager.init = function(doc) {
-    var uid = cr.getUid(doc);
-    if (!(uid in commandManagers)) {
-      commandManagers[uid] = new CommandManager(doc);
-    }
-  };
-  CommandManager.prototype = {
-    handleFocus_: function(e) {
-      var target = e.target;
-      if (target.menu || target.command) return;
-      var commands = Array.prototype.slice.call(target.ownerDocument.querySelectorAll('command'));
-      commands.forEach(function(command) {
-        dispatchCanExecuteEvent(command, target);
-      });
-    },
-    handleKeyDown_: function(e) {
-      var target = e.target;
-      var commands = Array.prototype.slice.call(target.ownerDocument.querySelectorAll('command'));
-      for (var i = 0, command; command = commands[i]; i++) {
-        if (command.matchesEvent(e)) {
-          command.canExecuteChange();
-          if (!command.disabled) {
-            e.preventDefault();
-            e.stopPropagation();
-            command.execute();
-            return;
-          }
-        }
-      }
-    }
-  };
-  function CanExecuteEvent(command) {
-    var e = new Event('canExecute', {
-      bubbles: true,
-      cancelable: true
-    });
-    e.__proto__ = CanExecuteEvent.prototype;
-    e.command = command;
-    return e;
-  }
-  CanExecuteEvent.prototype = {
-    __proto__: Event.prototype,
-    command: null,
-    canExecute_: false,
-    get canExecute() {
-      return this.canExecute_;
-    },
-    set canExecute(canExecute) {
-      this.canExecute_ = !!canExecute;
-      this.stopPropagation();
-      this.preventDefault();
-    }
-  };
-  return {
-    Command: Command,
-    CanExecuteEvent: CanExecuteEvent
-  };
-});
-
-Polymer({
-  is: 'iron-media-query',
-  properties: {
-    queryMatches: {
-      type: Boolean,
-      value: false,
-      readOnly: true,
-      notify: true
-    },
-    query: {
-      type: String,
-      observer: 'queryChanged'
-    },
-    full: {
-      type: Boolean,
-      value: false
-    },
-    _boundMQHandler: {
-      value: function() {
-        return this.queryHandler.bind(this);
-      }
-    },
-    _mq: {
-      value: null
-    }
-  },
-  attached: function() {
-    this.style.display = 'none';
-    this.queryChanged();
-  },
-  detached: function() {
-    this._remove();
-  },
-  _add: function() {
-    if (this._mq) {
-      this._mq.addListener(this._boundMQHandler);
-    }
-  },
-  _remove: function() {
-    if (this._mq) {
-      this._mq.removeListener(this._boundMQHandler);
-    }
-    this._mq = null;
-  },
-  queryChanged: function() {
-    this._remove();
-    var query = this.query;
-    if (!query) {
-      return;
-    }
-    if (!this.full && query[0] !== '(') {
-      query = '(' + query + ')';
-    }
-    this._mq = window.matchMedia(query);
-    this._add();
-    this.queryHandler(this._mq);
-  },
-  queryHandler: function(mq) {
-    this._setQueryMatches(mq.matches);
-  }
-});
-
-Polymer.IronResizableBehavior = {
-  properties: {
-    _parentResizable: {
-      type: Object,
-      observer: '_parentResizableChanged'
-    },
-    _notifyingDescendant: {
-      type: Boolean,
-      value: false
-    }
-  },
-  listeners: {
-    'iron-request-resize-notifications': '_onIronRequestResizeNotifications'
-  },
-  created: function() {
-    this._interestedResizables = [];
-    this._boundNotifyResize = this.notifyResize.bind(this);
-  },
-  attached: function() {
-    this.fire('iron-request-resize-notifications', null, {
-      node: this,
-      bubbles: true,
-      cancelable: true
-    });
-    if (!this._parentResizable) {
-      window.addEventListener('resize', this._boundNotifyResize);
-      this.notifyResize();
-    }
-  },
-  detached: function() {
-    if (this._parentResizable) {
-      this._parentResizable.stopResizeNotificationsFor(this);
-    } else {
-      window.removeEventListener('resize', this._boundNotifyResize);
-    }
-    this._parentResizable = null;
-  },
-  notifyResize: function() {
-    if (!this.isAttached) {
-      return;
-    }
-    this._interestedResizables.forEach(function(resizable) {
-      if (this.resizerShouldNotify(resizable)) {
-        this._notifyDescendant(resizable);
-      }
-    }, this);
-    this._fireResize();
-  },
-  assignParentResizable: function(parentResizable) {
-    this._parentResizable = parentResizable;
-  },
-  stopResizeNotificationsFor: function(target) {
-    var index = this._interestedResizables.indexOf(target);
-    if (index > -1) {
-      this._interestedResizables.splice(index, 1);
-      this.unlisten(target, 'iron-resize', '_onDescendantIronResize');
-    }
-  },
-  resizerShouldNotify: function(element) {
-    return true;
-  },
-  _onDescendantIronResize: function(event) {
-    if (this._notifyingDescendant) {
-      event.stopPropagation();
-      return;
-    }
-    if (!Polymer.Settings.useShadow) {
-      this._fireResize();
-    }
-  },
-  _fireResize: function() {
-    this.fire('iron-resize', null, {
-      node: this,
-      bubbles: false
-    });
-  },
-  _onIronRequestResizeNotifications: function(event) {
-    var target = event.path ? event.path[0] : event.target;
-    if (target === this) {
-      return;
-    }
-    if (this._interestedResizables.indexOf(target) === -1) {
-      this._interestedResizables.push(target);
-      this.listen(target, 'iron-resize', '_onDescendantIronResize');
-    }
-    target.assignParentResizable(this);
-    this._notifyDescendant(target);
-    event.stopPropagation();
-  },
-  _parentResizableChanged: function(parentResizable) {
-    if (parentResizable) {
-      window.removeEventListener('resize', this._boundNotifyResize);
-    }
-  },
-  _notifyDescendant: function(descendant) {
-    if (!this.isAttached) {
-      return;
-    }
-    this._notifyingDescendant = true;
-    descendant.notifyResize();
-    this._notifyingDescendant = false;
-  }
-};
-
-Polymer.IronSelection = function(selectCallback) {
-  this.selection = [];
-  this.selectCallback = selectCallback;
-};
-
-Polymer.IronSelection.prototype = {
-  get: function() {
-    return this.multi ? this.selection.slice() : this.selection[0];
-  },
-  clear: function(excludes) {
-    this.selection.slice().forEach(function(item) {
-      if (!excludes || excludes.indexOf(item) < 0) {
-        this.setItemSelected(item, false);
-      }
-    }, this);
-  },
-  isSelected: function(item) {
-    return this.selection.indexOf(item) >= 0;
-  },
-  setItemSelected: function(item, isSelected) {
-    if (item != null) {
-      if (isSelected !== this.isSelected(item)) {
-        if (isSelected) {
-          this.selection.push(item);
-        } else {
-          var i = this.selection.indexOf(item);
-          if (i >= 0) {
-            this.selection.splice(i, 1);
-          }
-        }
-        if (this.selectCallback) {
-          this.selectCallback(item, isSelected);
-        }
-      }
-    }
-  },
-  select: function(item) {
-    if (this.multi) {
-      this.toggle(item);
-    } else if (this.get() !== item) {
-      this.setItemSelected(this.get(), false);
-      this.setItemSelected(item, true);
-    }
-  },
-  toggle: function(item) {
-    this.setItemSelected(item, !this.isSelected(item));
-  }
-};
-
-Polymer.IronSelectableBehavior = {
-  properties: {
-    attrForSelected: {
-      type: String,
-      value: null
-    },
-    selected: {
-      type: String,
-      notify: true
-    },
-    selectedItem: {
-      type: Object,
-      readOnly: true,
-      notify: true
-    },
-    activateEvent: {
-      type: String,
-      value: 'tap',
-      observer: '_activateEventChanged'
-    },
-    selectable: String,
-    selectedClass: {
-      type: String,
-      value: 'iron-selected'
-    },
-    selectedAttribute: {
-      type: String,
-      value: null
-    },
-    fallbackSelection: {
-      type: String,
-      value: null
-    },
-    items: {
-      type: Array,
-      readOnly: true,
-      notify: true,
-      value: function() {
-        return [];
-      }
-    },
-    _excludedLocalNames: {
-      type: Object,
-      value: function() {
-        return {
-          template: 1
-        };
-      }
-    }
-  },
-  observers: [ '_updateAttrForSelected(attrForSelected)', '_updateSelected(selected)', '_checkFallback(fallbackSelection)' ],
-  created: function() {
-    this._bindFilterItem = this._filterItem.bind(this);
-    this._selection = new Polymer.IronSelection(this._applySelection.bind(this));
-  },
-  attached: function() {
-    this._observer = this._observeItems(this);
-    this._updateItems();
-    if (!this._shouldUpdateSelection) {
-      this._updateSelected();
-    }
-    this._addListener(this.activateEvent);
-  },
-  detached: function() {
-    if (this._observer) {
-      Polymer.dom(this).unobserveNodes(this._observer);
-    }
-    this._removeListener(this.activateEvent);
-  },
-  indexOf: function(item) {
-    return this.items.indexOf(item);
-  },
-  select: function(value) {
-    this.selected = value;
-  },
-  selectPrevious: function() {
-    var length = this.items.length;
-    var index = (Number(this._valueToIndex(this.selected)) - 1 + length) % length;
-    this.selected = this._indexToValue(index);
-  },
-  selectNext: function() {
-    var index = (Number(this._valueToIndex(this.selected)) + 1) % this.items.length;
-    this.selected = this._indexToValue(index);
-  },
-  selectIndex: function(index) {
-    this.select(this._indexToValue(index));
-  },
-  forceSynchronousItemUpdate: function() {
-    this._updateItems();
-  },
-  get _shouldUpdateSelection() {
-    return this.selected != null;
-  },
-  _checkFallback: function() {
-    if (this._shouldUpdateSelection) {
-      this._updateSelected();
-    }
-  },
-  _addListener: function(eventName) {
-    this.listen(this, eventName, '_activateHandler');
-  },
-  _removeListener: function(eventName) {
-    this.unlisten(this, eventName, '_activateHandler');
-  },
-  _activateEventChanged: function(eventName, old) {
-    this._removeListener(old);
-    this._addListener(eventName);
-  },
-  _updateItems: function() {
-    var nodes = Polymer.dom(this).queryDistributedElements(this.selectable || '*');
-    nodes = Array.prototype.filter.call(nodes, this._bindFilterItem);
-    this._setItems(nodes);
-  },
-  _updateAttrForSelected: function() {
-    if (this._shouldUpdateSelection) {
-      this.selected = this._indexToValue(this.indexOf(this.selectedItem));
-    }
-  },
-  _updateSelected: function() {
-    this._selectSelected(this.selected);
-  },
-  _selectSelected: function(selected) {
-    this._selection.select(this._valueToItem(this.selected));
-    if (this.fallbackSelection && this.items.length && this._selection.get() === undefined) {
-      this.selected = this.fallbackSelection;
-    }
-  },
-  _filterItem: function(node) {
-    return !this._excludedLocalNames[node.localName];
-  },
-  _valueToItem: function(value) {
-    return value == null ? null : this.items[this._valueToIndex(value)];
-  },
-  _valueToIndex: function(value) {
-    if (this.attrForSelected) {
-      for (var i = 0, item; item = this.items[i]; i++) {
-        if (this._valueForItem(item) == value) {
-          return i;
-        }
-      }
-    } else {
-      return Number(value);
-    }
-  },
-  _indexToValue: function(index) {
-    if (this.attrForSelected) {
-      var item = this.items[index];
-      if (item) {
-        return this._valueForItem(item);
-      }
-    } else {
-      return index;
-    }
-  },
-  _valueForItem: function(item) {
-    var propValue = item[Polymer.CaseMap.dashToCamelCase(this.attrForSelected)];
-    return propValue != undefined ? propValue : item.getAttribute(this.attrForSelected);
-  },
-  _applySelection: function(item, isSelected) {
-    if (this.selectedClass) {
-      this.toggleClass(this.selectedClass, isSelected, item);
-    }
-    if (this.selectedAttribute) {
-      this.toggleAttribute(this.selectedAttribute, isSelected, item);
-    }
-    this._selectionChange();
-    this.fire('iron-' + (isSelected ? 'select' : 'deselect'), {
-      item: item
-    });
-  },
-  _selectionChange: function() {
-    this._setSelectedItem(this._selection.get());
-  },
-  _observeItems: function(node) {
-    return Polymer.dom(node).observeNodes(function(mutation) {
-      this._updateItems();
-      if (this._shouldUpdateSelection) {
-        this._updateSelected();
-      }
-      this.fire('iron-items-changed', mutation, {
-        bubbles: false,
-        cancelable: false
-      });
-    });
-  },
-  _activateHandler: function(e) {
-    var t = e.target;
-    var items = this.items;
-    while (t && t != this) {
-      var i = items.indexOf(t);
-      if (i >= 0) {
-        var value = this._indexToValue(i);
-        this._itemActivate(value, t);
-        return;
-      }
-      t = t.parentNode;
-    }
-  },
-  _itemActivate: function(value, item) {
-    if (!this.fire('iron-activate', {
-      selected: value,
-      item: item
-    }, {
-      cancelable: true
-    }).defaultPrevented) {
-      this.select(value);
-    }
-  }
-};
-
-Polymer({
-  is: 'iron-pages',
-  behaviors: [ Polymer.IronResizableBehavior, Polymer.IronSelectableBehavior ],
-  properties: {
-    activateEvent: {
-      type: String,
-      value: null
-    }
-  },
-  observers: [ '_selectedPageChanged(selected)' ],
-  _selectedPageChanged: function(selected, old) {
-    this.async(this.notifyResize);
-  }
-});
-
-Polymer.IronScrollTargetBehavior = {
-  properties: {
-    scrollTarget: {
-      type: HTMLElement,
-      value: function() {
-        return this._defaultScrollTarget;
-      }
-    }
-  },
-  observers: [ '_scrollTargetChanged(scrollTarget, isAttached)' ],
-  _scrollTargetChanged: function(scrollTarget, isAttached) {
-    var eventTarget;
-    if (this._oldScrollTarget) {
-      eventTarget = this._oldScrollTarget === this._doc ? window : this._oldScrollTarget;
-      eventTarget.removeEventListener('scroll', this._boundScrollHandler);
-      this._oldScrollTarget = null;
-    }
-    if (!isAttached) {
-      return;
-    }
-    if (scrollTarget === 'document') {
-      this.scrollTarget = this._doc;
-    } else if (typeof scrollTarget === 'string') {
-      this.scrollTarget = this.domHost ? this.domHost.$[scrollTarget] : Polymer.dom(this.ownerDocument).querySelector('#' + scrollTarget);
-    } else if (this._isValidScrollTarget()) {
-      eventTarget = scrollTarget === this._doc ? window : scrollTarget;
-      this._boundScrollHandler = this._boundScrollHandler || this._scrollHandler.bind(this);
-      this._oldScrollTarget = scrollTarget;
-      eventTarget.addEventListener('scroll', this._boundScrollHandler);
-    }
-  },
-  _scrollHandler: function scrollHandler() {},
-  get _defaultScrollTarget() {
-    return this._doc;
-  },
-  get _doc() {
-    return this.ownerDocument.documentElement;
-  },
-  get _scrollTop() {
-    if (this._isValidScrollTarget()) {
-      return this.scrollTarget === this._doc ? window.pageYOffset : this.scrollTarget.scrollTop;
-    }
-    return 0;
-  },
-  get _scrollLeft() {
-    if (this._isValidScrollTarget()) {
-      return this.scrollTarget === this._doc ? window.pageXOffset : this.scrollTarget.scrollLeft;
-    }
-    return 0;
-  },
-  set _scrollTop(top) {
-    if (this.scrollTarget === this._doc) {
-      window.scrollTo(window.pageXOffset, top);
-    } else if (this._isValidScrollTarget()) {
-      this.scrollTarget.scrollTop = top;
-    }
-  },
-  set _scrollLeft(left) {
-    if (this.scrollTarget === this._doc) {
-      window.scrollTo(left, window.pageYOffset);
-    } else if (this._isValidScrollTarget()) {
-      this.scrollTarget.scrollLeft = left;
-    }
-  },
-  scroll: function(left, top) {
-    if (this.scrollTarget === this._doc) {
-      window.scrollTo(left, top);
-    } else if (this._isValidScrollTarget()) {
-      this.scrollTarget.scrollLeft = left;
-      this.scrollTarget.scrollTop = top;
-    }
-  },
-  get _scrollTargetWidth() {
-    if (this._isValidScrollTarget()) {
-      return this.scrollTarget === this._doc ? window.innerWidth : this.scrollTarget.offsetWidth;
-    }
-    return 0;
-  },
-  get _scrollTargetHeight() {
-    if (this._isValidScrollTarget()) {
-      return this.scrollTarget === this._doc ? window.innerHeight : this.scrollTarget.offsetHeight;
-    }
-    return 0;
-  },
-  _isValidScrollTarget: function() {
-    return this.scrollTarget instanceof HTMLElement;
-  }
-};
-
-(function() {
-  var metaDatas = {};
-  var metaArrays = {};
-  var singleton = null;
-  Polymer.IronMeta = Polymer({
-    is: 'iron-meta',
-    properties: {
-      type: {
-        type: String,
-        value: 'default',
-        observer: '_typeChanged'
-      },
-      key: {
-        type: String,
-        observer: '_keyChanged'
-      },
-      value: {
-        type: Object,
-        notify: true,
-        observer: '_valueChanged'
-      },
-      self: {
-        type: Boolean,
-        observer: '_selfChanged'
-      },
-      list: {
-        type: Array,
-        notify: true
-      }
-    },
-    hostAttributes: {
-      hidden: true
-    },
-    factoryImpl: function(config) {
-      if (config) {
-        for (var n in config) {
-          switch (n) {
-           case 'type':
-           case 'key':
-           case 'value':
-            this[n] = config[n];
-            break;
-          }
-        }
-      }
-    },
-    created: function() {
-      this._metaDatas = metaDatas;
-      this._metaArrays = metaArrays;
-    },
-    _keyChanged: function(key, old) {
-      this._resetRegistration(old);
-    },
-    _valueChanged: function(value) {
-      this._resetRegistration(this.key);
-    },
-    _selfChanged: function(self) {
-      if (self) {
-        this.value = this;
-      }
-    },
-    _typeChanged: function(type) {
-      this._unregisterKey(this.key);
-      if (!metaDatas[type]) {
-        metaDatas[type] = {};
-      }
-      this._metaData = metaDatas[type];
-      if (!metaArrays[type]) {
-        metaArrays[type] = [];
-      }
-      this.list = metaArrays[type];
-      this._registerKeyValue(this.key, this.value);
-    },
-    byKey: function(key) {
-      return this._metaData && this._metaData[key];
-    },
-    _resetRegistration: function(oldKey) {
-      this._unregisterKey(oldKey);
-      this._registerKeyValue(this.key, this.value);
-    },
-    _unregisterKey: function(key) {
-      this._unregister(key, this._metaData, this.list);
-    },
-    _registerKeyValue: function(key, value) {
-      this._register(key, value, this._metaData, this.list);
-    },
-    _register: function(key, value, data, list) {
-      if (key && data && value !== undefined) {
-        data[key] = value;
-        list.push(value);
-      }
-    },
-    _unregister: function(key, data, list) {
-      if (key && data) {
-        if (key in data) {
-          var value = data[key];
-          delete data[key];
-          this.arrayDelete(list, value);
-        }
-      }
-    }
-  });
-  Polymer.IronMeta.getIronMeta = function getIronMeta() {
-    if (singleton === null) {
-      singleton = new Polymer.IronMeta();
-    }
-    return singleton;
-  };
-  Polymer.IronMetaQuery = Polymer({
-    is: 'iron-meta-query',
-    properties: {
-      type: {
-        type: String,
-        value: 'default',
-        observer: '_typeChanged'
-      },
-      key: {
-        type: String,
-        observer: '_keyChanged'
-      },
-      value: {
-        type: Object,
-        notify: true,
-        readOnly: true
-      },
-      list: {
-        type: Array,
-        notify: true
-      }
-    },
-    factoryImpl: function(config) {
-      if (config) {
-        for (var n in config) {
-          switch (n) {
-           case 'type':
-           case 'key':
-            this[n] = config[n];
-            break;
-          }
-        }
-      }
-    },
-    created: function() {
-      this._metaDatas = metaDatas;
-      this._metaArrays = metaArrays;
-    },
-    _keyChanged: function(key) {
-      this._setValue(this._metaData && this._metaData[key]);
-    },
-    _typeChanged: function(type) {
-      this._metaData = metaDatas[type];
-      this.list = metaArrays[type];
-      if (this.key) {
-        this._keyChanged(this.key);
-      }
-    },
-    byKey: function(key) {
-      return this._metaData && this._metaData[key];
-    }
-  });
-})();
-
-Polymer({
-  is: 'iron-icon',
-  properties: {
-    icon: {
-      type: String,
-      observer: '_iconChanged'
-    },
-    theme: {
-      type: String,
-      observer: '_updateIcon'
-    },
-    src: {
-      type: String,
-      observer: '_srcChanged'
-    },
-    _meta: {
-      value: Polymer.Base.create('iron-meta', {
-        type: 'iconset'
-      }),
-      observer: '_updateIcon'
-    }
-  },
-  _DEFAULT_ICONSET: 'icons',
-  _iconChanged: function(icon) {
-    var parts = (icon || '').split(':');
-    this._iconName = parts.pop();
-    this._iconsetName = parts.pop() || this._DEFAULT_ICONSET;
-    this._updateIcon();
-  },
-  _srcChanged: function(src) {
-    this._updateIcon();
-  },
-  _usesIconset: function() {
-    return this.icon || !this.src;
-  },
-  _updateIcon: function() {
-    if (this._usesIconset()) {
-      if (this._img && this._img.parentNode) {
-        Polymer.dom(this.root).removeChild(this._img);
-      }
-      if (this._iconName === "") {
-        if (this._iconset) {
-          this._iconset.removeIcon(this);
-        }
-      } else if (this._iconsetName && this._meta) {
-        this._iconset = this._meta.byKey(this._iconsetName);
-        if (this._iconset) {
-          this._iconset.applyIcon(this, this._iconName, this.theme);
-          this.unlisten(window, 'iron-iconset-added', '_updateIcon');
-        } else {
-          this.listen(window, 'iron-iconset-added', '_updateIcon');
-        }
-      }
-    } else {
-      if (this._iconset) {
-        this._iconset.removeIcon(this);
-      }
-      if (!this._img) {
-        this._img = document.createElement('img');
-        this._img.style.width = '100%';
-        this._img.style.height = '100%';
-        this._img.draggable = false;
-      }
-      this._img.src = this.src;
-      Polymer.dom(this.root).appendChild(this._img);
-    }
-  }
-});
-
-(function() {
-  'use strict';
-  var KEY_IDENTIFIER = {
-    'U+0008': 'backspace',
-    'U+0009': 'tab',
-    'U+001B': 'esc',
-    'U+0020': 'space',
-    'U+007F': 'del'
-  };
-  var KEY_CODE = {
-    8: 'backspace',
-    9: 'tab',
-    13: 'enter',
-    27: 'esc',
-    33: 'pageup',
-    34: 'pagedown',
-    35: 'end',
-    36: 'home',
-    32: 'space',
-    37: 'left',
-    38: 'up',
-    39: 'right',
-    40: 'down',
-    46: 'del',
-    106: '*'
-  };
-  var MODIFIER_KEYS = {
-    shift: 'shiftKey',
-    ctrl: 'ctrlKey',
-    alt: 'altKey',
-    meta: 'metaKey'
-  };
-  var KEY_CHAR = /[a-z0-9*]/;
-  var IDENT_CHAR = /U\+/;
-  var ARROW_KEY = /^arrow/;
-  var SPACE_KEY = /^space(bar)?/;
-  var ESC_KEY = /^escape$/;
-  function transformKey(key, noSpecialChars) {
-    var validKey = '';
-    if (key) {
-      var lKey = key.toLowerCase();
-      if (lKey === ' ' || SPACE_KEY.test(lKey)) {
-        validKey = 'space';
-      } else if (ESC_KEY.test(lKey)) {
-        validKey = 'esc';
-      } else if (lKey.length == 1) {
-        if (!noSpecialChars || KEY_CHAR.test(lKey)) {
-          validKey = lKey;
-        }
-      } else if (ARROW_KEY.test(lKey)) {
-        validKey = lKey.replace('arrow', '');
-      } else if (lKey == 'multiply') {
-        validKey = '*';
-      } else {
-        validKey = lKey;
-      }
-    }
-    return validKey;
-  }
-  function transformKeyIdentifier(keyIdent) {
-    var validKey = '';
-    if (keyIdent) {
-      if (keyIdent in KEY_IDENTIFIER) {
-        validKey = KEY_IDENTIFIER[keyIdent];
-      } else if (IDENT_CHAR.test(keyIdent)) {
-        keyIdent = parseInt(keyIdent.replace('U+', '0x'), 16);
-        validKey = String.fromCharCode(keyIdent).toLowerCase();
-      } else {
-        validKey = keyIdent.toLowerCase();
-      }
-    }
-    return validKey;
-  }
-  function transformKeyCode(keyCode) {
-    var validKey = '';
-    if (Number(keyCode)) {
-      if (keyCode >= 65 && keyCode <= 90) {
-        validKey = String.fromCharCode(32 + keyCode);
-      } else if (keyCode >= 112 && keyCode <= 123) {
-        validKey = 'f' + (keyCode - 112);
-      } else if (keyCode >= 48 && keyCode <= 57) {
-        validKey = String(keyCode - 48);
-      } else if (keyCode >= 96 && keyCode <= 105) {
-        validKey = String(keyCode - 96);
-      } else {
-        validKey = KEY_CODE[keyCode];
-      }
-    }
-    return validKey;
-  }
-  function normalizedKeyForEvent(keyEvent, noSpecialChars) {
-    if (keyEvent.key) {
-      return transformKey(keyEvent.key, noSpecialChars);
-    }
-    if (keyEvent.detail && keyEvent.detail.key) {
-      return transformKey(keyEvent.detail.key, noSpecialChars);
-    }
-    return transformKeyIdentifier(keyEvent.keyIdentifier) || transformKeyCode(keyEvent.keyCode) || '';
-  }
-  function keyComboMatchesEvent(keyCombo, event) {
-    var keyEvent = normalizedKeyForEvent(event, keyCombo.hasModifiers);
-    return keyEvent === keyCombo.key && (!keyCombo.hasModifiers || !!event.shiftKey === !!keyCombo.shiftKey && !!event.ctrlKey === !!keyCombo.ctrlKey && !!event.altKey === !!keyCombo.altKey && !!event.metaKey === !!keyCombo.metaKey);
-  }
-  function parseKeyComboString(keyComboString) {
-    if (keyComboString.length === 1) {
-      return {
-        combo: keyComboString,
-        key: keyComboString,
-        event: 'keydown'
-      };
-    }
-    return keyComboString.split('+').reduce(function(parsedKeyCombo, keyComboPart) {
-      var eventParts = keyComboPart.split(':');
-      var keyName = eventParts[0];
-      var event = eventParts[1];
-      if (keyName in MODIFIER_KEYS) {
-        parsedKeyCombo[MODIFIER_KEYS[keyName]] = true;
-        parsedKeyCombo.hasModifiers = true;
-      } else {
-        parsedKeyCombo.key = keyName;
-        parsedKeyCombo.event = event || 'keydown';
-      }
-      return parsedKeyCombo;
-    }, {
-      combo: keyComboString.split(':').shift()
-    });
-  }
-  function parseEventString(eventString) {
-    return eventString.trim().split(' ').map(function(keyComboString) {
-      return parseKeyComboString(keyComboString);
-    });
-  }
-  Polymer.IronA11yKeysBehavior = {
-    properties: {
-      keyEventTarget: {
-        type: Object,
-        value: function() {
-          return this;
-        }
-      },
-      stopKeyboardEventPropagation: {
-        type: Boolean,
-        value: false
-      },
-      _boundKeyHandlers: {
-        type: Array,
-        value: function() {
-          return [];
-        }
-      },
-      _imperativeKeyBindings: {
-        type: Object,
-        value: function() {
-          return {};
-        }
-      }
-    },
-    observers: [ '_resetKeyEventListeners(keyEventTarget, _boundKeyHandlers)' ],
-    keyBindings: {},
-    registered: function() {
-      this._prepKeyBindings();
-    },
-    attached: function() {
-      this._listenKeyEventListeners();
-    },
-    detached: function() {
-      this._unlistenKeyEventListeners();
-    },
-    addOwnKeyBinding: function(eventString, handlerName) {
-      this._imperativeKeyBindings[eventString] = handlerName;
-      this._prepKeyBindings();
-      this._resetKeyEventListeners();
-    },
-    removeOwnKeyBindings: function() {
-      this._imperativeKeyBindings = {};
-      this._prepKeyBindings();
-      this._resetKeyEventListeners();
-    },
-    keyboardEventMatchesKeys: function(event, eventString) {
-      var keyCombos = parseEventString(eventString);
-      for (var i = 0; i < keyCombos.length; ++i) {
-        if (keyComboMatchesEvent(keyCombos[i], event)) {
-          return true;
-        }
-      }
-      return false;
-    },
-    _collectKeyBindings: function() {
-      var keyBindings = this.behaviors.map(function(behavior) {
-        return behavior.keyBindings;
-      });
-      if (keyBindings.indexOf(this.keyBindings) === -1) {
-        keyBindings.push(this.keyBindings);
-      }
-      return keyBindings;
-    },
-    _prepKeyBindings: function() {
-      this._keyBindings = {};
-      this._collectKeyBindings().forEach(function(keyBindings) {
-        for (var eventString in keyBindings) {
-          this._addKeyBinding(eventString, keyBindings[eventString]);
-        }
-      }, this);
-      for (var eventString in this._imperativeKeyBindings) {
-        this._addKeyBinding(eventString, this._imperativeKeyBindings[eventString]);
-      }
-      for (var eventName in this._keyBindings) {
-        this._keyBindings[eventName].sort(function(kb1, kb2) {
-          var b1 = kb1[0].hasModifiers;
-          var b2 = kb2[0].hasModifiers;
-          return b1 === b2 ? 0 : b1 ? -1 : 1;
-        });
-      }
-    },
-    _addKeyBinding: function(eventString, handlerName) {
-      parseEventString(eventString).forEach(function(keyCombo) {
-        this._keyBindings[keyCombo.event] = this._keyBindings[keyCombo.event] || [];
-        this._keyBindings[keyCombo.event].push([ keyCombo, handlerName ]);
-      }, this);
-    },
-    _resetKeyEventListeners: function() {
-      this._unlistenKeyEventListeners();
-      if (this.isAttached) {
-        this._listenKeyEventListeners();
-      }
-    },
-    _listenKeyEventListeners: function() {
-      if (!this.keyEventTarget) {
-        return;
-      }
-      Object.keys(this._keyBindings).forEach(function(eventName) {
-        var keyBindings = this._keyBindings[eventName];
-        var boundKeyHandler = this._onKeyBindingEvent.bind(this, keyBindings);
-        this._boundKeyHandlers.push([ this.keyEventTarget, eventName, boundKeyHandler ]);
-        this.keyEventTarget.addEventListener(eventName, boundKeyHandler);
-      }, this);
-    },
-    _unlistenKeyEventListeners: function() {
-      var keyHandlerTuple;
-      var keyEventTarget;
-      var eventName;
-      var boundKeyHandler;
-      while (this._boundKeyHandlers.length) {
-        keyHandlerTuple = this._boundKeyHandlers.pop();
-        keyEventTarget = keyHandlerTuple[0];
-        eventName = keyHandlerTuple[1];
-        boundKeyHandler = keyHandlerTuple[2];
-        keyEventTarget.removeEventListener(eventName, boundKeyHandler);
-      }
-    },
-    _onKeyBindingEvent: function(keyBindings, event) {
-      if (this.stopKeyboardEventPropagation) {
-        event.stopPropagation();
-      }
-      if (event.defaultPrevented) {
-        return;
-      }
-      for (var i = 0; i < keyBindings.length; i++) {
-        var keyCombo = keyBindings[i][0];
-        var handlerName = keyBindings[i][1];
-        if (keyComboMatchesEvent(keyCombo, event)) {
-          this._triggerKeyHandler(keyCombo, handlerName, event);
-          if (event.defaultPrevented) {
-            return;
-          }
-        }
-      }
-    },
-    _triggerKeyHandler: function(keyCombo, handlerName, keyboardEvent) {
-      var detail = Object.create(keyCombo);
-      detail.keyboardEvent = keyboardEvent;
-      var event = new CustomEvent(keyCombo.event, {
-        detail: detail,
-        cancelable: true
-      });
-      this[handlerName].call(this, event);
-      if (event.defaultPrevented) {
-        keyboardEvent.preventDefault();
-      }
-    }
-  };
-})();
-
-Polymer.IronControlState = {
-  properties: {
-    focused: {
-      type: Boolean,
-      value: false,
-      notify: true,
-      readOnly: true,
-      reflectToAttribute: true
-    },
-    disabled: {
-      type: Boolean,
-      value: false,
-      notify: true,
-      observer: '_disabledChanged',
-      reflectToAttribute: true
-    },
-    _oldTabIndex: {
-      type: Number
-    },
-    _boundFocusBlurHandler: {
-      type: Function,
-      value: function() {
-        return this._focusBlurHandler.bind(this);
-      }
-    }
-  },
-  observers: [ '_changedControlState(focused, disabled)' ],
-  ready: function() {
-    this.addEventListener('focus', this._boundFocusBlurHandler, true);
-    this.addEventListener('blur', this._boundFocusBlurHandler, true);
-  },
-  _focusBlurHandler: function(event) {
-    if (event.target === this) {
-      this._setFocused(event.type === 'focus');
-    } else if (!this.shadowRoot) {
-      var target = Polymer.dom(event).localTarget;
-      if (!this.isLightDescendant(target)) {
-        this.fire(event.type, {
-          sourceEvent: event
-        }, {
-          node: this,
-          bubbles: event.bubbles,
-          cancelable: event.cancelable
-        });
-      }
-    }
-  },
-  _disabledChanged: function(disabled, old) {
-    this.setAttribute('aria-disabled', disabled ? 'true' : 'false');
-    this.style.pointerEvents = disabled ? 'none' : '';
-    if (disabled) {
-      this._oldTabIndex = this.tabIndex;
-      this._setFocused(false);
-      this.tabIndex = -1;
-      this.blur();
-    } else if (this._oldTabIndex !== undefined) {
-      this.tabIndex = this._oldTabIndex;
-    }
-  },
-  _changedControlState: function() {
-    if (this._controlStateChanged) {
-      this._controlStateChanged();
-    }
-  }
-};
-
-Polymer.IronButtonStateImpl = {
-  properties: {
-    pressed: {
-      type: Boolean,
-      readOnly: true,
-      value: false,
-      reflectToAttribute: true,
-      observer: '_pressedChanged'
-    },
-    toggles: {
-      type: Boolean,
-      value: false,
-      reflectToAttribute: true
-    },
-    active: {
-      type: Boolean,
-      value: false,
-      notify: true,
-      reflectToAttribute: true
-    },
-    pointerDown: {
-      type: Boolean,
-      readOnly: true,
-      value: false
-    },
-    receivedFocusFromKeyboard: {
-      type: Boolean,
-      readOnly: true
-    },
-    ariaActiveAttribute: {
-      type: String,
-      value: 'aria-pressed',
-      observer: '_ariaActiveAttributeChanged'
-    }
-  },
-  listeners: {
-    down: '_downHandler',
-    up: '_upHandler',
-    tap: '_tapHandler'
-  },
-  observers: [ '_detectKeyboardFocus(focused)', '_activeChanged(active, ariaActiveAttribute)' ],
-  keyBindings: {
-    'enter:keydown': '_asyncClick',
-    'space:keydown': '_spaceKeyDownHandler',
-    'space:keyup': '_spaceKeyUpHandler'
-  },
-  _mouseEventRe: /^mouse/,
-  _tapHandler: function() {
-    if (this.toggles) {
-      this._userActivate(!this.active);
-    } else {
-      this.active = false;
-    }
-  },
-  _detectKeyboardFocus: function(focused) {
-    this._setReceivedFocusFromKeyboard(!this.pointerDown && focused);
-  },
-  _userActivate: function(active) {
-    if (this.active !== active) {
-      this.active = active;
-      this.fire('change');
-    }
-  },
-  _downHandler: function(event) {
-    this._setPointerDown(true);
-    this._setPressed(true);
-    this._setReceivedFocusFromKeyboard(false);
-  },
-  _upHandler: function() {
-    this._setPointerDown(false);
-    this._setPressed(false);
-  },
-  _spaceKeyDownHandler: function(event) {
-    var keyboardEvent = event.detail.keyboardEvent;
-    var target = Polymer.dom(keyboardEvent).localTarget;
-    if (this.isLightDescendant(target)) return;
-    keyboardEvent.preventDefault();
-    keyboardEvent.stopImmediatePropagation();
-    this._setPressed(true);
-  },
-  _spaceKeyUpHandler: function(event) {
-    var keyboardEvent = event.detail.keyboardEvent;
-    var target = Polymer.dom(keyboardEvent).localTarget;
-    if (this.isLightDescendant(target)) return;
-    if (this.pressed) {
-      this._asyncClick();
-    }
-    this._setPressed(false);
-  },
-  _asyncClick: function() {
-    this.async(function() {
-      this.click();
-    }, 1);
-  },
-  _pressedChanged: function(pressed) {
-    this._changedButtonState();
-  },
-  _ariaActiveAttributeChanged: function(value, oldValue) {
-    if (oldValue && oldValue != value && this.hasAttribute(oldValue)) {
-      this.removeAttribute(oldValue);
-    }
-  },
-  _activeChanged: function(active, ariaActiveAttribute) {
-    if (this.toggles) {
-      this.setAttribute(this.ariaActiveAttribute, active ? 'true' : 'false');
-    } else {
-      this.removeAttribute(this.ariaActiveAttribute);
-    }
-    this._changedButtonState();
-  },
-  _controlStateChanged: function() {
-    if (this.disabled) {
-      this._setPressed(false);
-    } else {
-      this._changedButtonState();
-    }
-  },
-  _changedButtonState: function() {
-    if (this._buttonStateChanged) {
-      this._buttonStateChanged();
-    }
-  }
-};
-
-Polymer.IronButtonState = [ Polymer.IronA11yKeysBehavior, Polymer.IronButtonStateImpl ];
-
-(function() {
-  var Utility = {
-    distance: function(x1, y1, x2, y2) {
-      var xDelta = x1 - x2;
-      var yDelta = y1 - y2;
-      return Math.sqrt(xDelta * xDelta + yDelta * yDelta);
-    },
-    now: window.performance && window.performance.now ? window.performance.now.bind(window.performance) : Date.now
-  };
-  function ElementMetrics(element) {
-    this.element = element;
-    this.width = this.boundingRect.width;
-    this.height = this.boundingRect.height;
-    this.size = Math.max(this.width, this.height);
-  }
-  ElementMetrics.prototype = {
-    get boundingRect() {
-      return this.element.getBoundingClientRect();
-    },
-    furthestCornerDistanceFrom: function(x, y) {
-      var topLeft = Utility.distance(x, y, 0, 0);
-      var topRight = Utility.distance(x, y, this.width, 0);
-      var bottomLeft = Utility.distance(x, y, 0, this.height);
-      var bottomRight = Utility.distance(x, y, this.width, this.height);
-      return Math.max(topLeft, topRight, bottomLeft, bottomRight);
-    }
-  };
-  function Ripple(element) {
-    this.element = element;
-    this.color = window.getComputedStyle(element).color;
-    this.wave = document.createElement('div');
-    this.waveContainer = document.createElement('div');
-    this.wave.style.backgroundColor = this.color;
-    this.wave.classList.add('wave');
-    this.waveContainer.classList.add('wave-container');
-    Polymer.dom(this.waveContainer).appendChild(this.wave);
-    this.resetInteractionState();
-  }
-  Ripple.MAX_RADIUS = 300;
-  Ripple.prototype = {
-    get recenters() {
-      return this.element.recenters;
-    },
-    get center() {
-      return this.element.center;
-    },
-    get mouseDownElapsed() {
-      var elapsed;
-      if (!this.mouseDownStart) {
-        return 0;
-      }
-      elapsed = Utility.now() - this.mouseDownStart;
-      if (this.mouseUpStart) {
-        elapsed -= this.mouseUpElapsed;
-      }
-      return elapsed;
-    },
-    get mouseUpElapsed() {
-      return this.mouseUpStart ? Utility.now() - this.mouseUpStart : 0;
-    },
-    get mouseDownElapsedSeconds() {
-      return this.mouseDownElapsed / 1e3;
-    },
-    get mouseUpElapsedSeconds() {
-      return this.mouseUpElapsed / 1e3;
-    },
-    get mouseInteractionSeconds() {
-      return this.mouseDownElapsedSeconds + this.mouseUpElapsedSeconds;
-    },
-    get initialOpacity() {
-      return this.element.initialOpacity;
-    },
-    get opacityDecayVelocity() {
-      return this.element.opacityDecayVelocity;
-    },
-    get radius() {
-      var width2 = this.containerMetrics.width * this.containerMetrics.width;
-      var height2 = this.containerMetrics.height * this.containerMetrics.height;
-      var waveRadius = Math.min(Math.sqrt(width2 + height2), Ripple.MAX_RADIUS) * 1.1 + 5;
-      var duration = 1.1 - .2 * (waveRadius / Ripple.MAX_RADIUS);
-      var timeNow = this.mouseInteractionSeconds / duration;
-      var size = waveRadius * (1 - Math.pow(80, -timeNow));
-      return Math.abs(size);
-    },
-    get opacity() {
-      if (!this.mouseUpStart) {
-        return this.initialOpacity;
-      }
-      return Math.max(0, this.initialOpacity - this.mouseUpElapsedSeconds * this.opacityDecayVelocity);
-    },
-    get outerOpacity() {
-      var outerOpacity = this.mouseUpElapsedSeconds * .3;
-      var waveOpacity = this.opacity;
-      return Math.max(0, Math.min(outerOpacity, waveOpacity));
-    },
-    get isOpacityFullyDecayed() {
-      return this.opacity < .01 && this.radius >= Math.min(this.maxRadius, Ripple.MAX_RADIUS);
-    },
-    get isRestingAtMaxRadius() {
-      return this.opacity >= this.initialOpacity && this.radius >= Math.min(this.maxRadius, Ripple.MAX_RADIUS);
-    },
-    get isAnimationComplete() {
-      return this.mouseUpStart ? this.isOpacityFullyDecayed : this.isRestingAtMaxRadius;
-    },
-    get translationFraction() {
-      return Math.min(1, this.radius / this.containerMetrics.size * 2 / Math.sqrt(2));
-    },
-    get xNow() {
-      if (this.xEnd) {
-        return this.xStart + this.translationFraction * (this.xEnd - this.xStart);
-      }
-      return this.xStart;
-    },
-    get yNow() {
-      if (this.yEnd) {
-        return this.yStart + this.translationFraction * (this.yEnd - this.yStart);
-      }
-      return this.yStart;
-    },
-    get isMouseDown() {
-      return this.mouseDownStart && !this.mouseUpStart;
-    },
-    resetInteractionState: function() {
-      this.maxRadius = 0;
-      this.mouseDownStart = 0;
-      this.mouseUpStart = 0;
-      this.xStart = 0;
-      this.yStart = 0;
-      this.xEnd = 0;
-      this.yEnd = 0;
-      this.slideDistance = 0;
-      this.containerMetrics = new ElementMetrics(this.element);
-    },
-    draw: function() {
-      var scale;
-      var translateString;
-      var dx;
-      var dy;
-      this.wave.style.opacity = this.opacity;
-      scale = this.radius / (this.containerMetrics.size / 2);
-      dx = this.xNow - this.containerMetrics.width / 2;
-      dy = this.yNow - this.containerMetrics.height / 2;
-      this.waveContainer.style.webkitTransform = 'translate(' + dx + 'px, ' + dy + 'px)';
-      this.waveContainer.style.transform = 'translate3d(' + dx + 'px, ' + dy + 'px, 0)';
-      this.wave.style.webkitTransform = 'scale(' + scale + ',' + scale + ')';
-      this.wave.style.transform = 'scale3d(' + scale + ',' + scale + ',1)';
-    },
-    downAction: function(event) {
-      var xCenter = this.containerMetrics.width / 2;
-      var yCenter = this.containerMetrics.height / 2;
-      this.resetInteractionState();
-      this.mouseDownStart = Utility.now();
-      if (this.center) {
-        this.xStart = xCenter;
-        this.yStart = yCenter;
-        this.slideDistance = Utility.distance(this.xStart, this.yStart, this.xEnd, this.yEnd);
-      } else {
-        this.xStart = event ? event.detail.x - this.containerMetrics.boundingRect.left : this.containerMetrics.width / 2;
-        this.yStart = event ? event.detail.y - this.containerMetrics.boundingRect.top : this.containerMetrics.height / 2;
-      }
-      if (this.recenters) {
-        this.xEnd = xCenter;
-        this.yEnd = yCenter;
-        this.slideDistance = Utility.distance(this.xStart, this.yStart, this.xEnd, this.yEnd);
-      }
-      this.maxRadius = this.containerMetrics.furthestCornerDistanceFrom(this.xStart, this.yStart);
-      this.waveContainer.style.top = (this.containerMetrics.height - this.containerMetrics.size) / 2 + 'px';
-      this.waveContainer.style.left = (this.containerMetrics.width - this.containerMetrics.size) / 2 + 'px';
-      this.waveContainer.style.width = this.containerMetrics.size + 'px';
-      this.waveContainer.style.height = this.containerMetrics.size + 'px';
-    },
-    upAction: function(event) {
-      if (!this.isMouseDown) {
-        return;
-      }
-      this.mouseUpStart = Utility.now();
-    },
-    remove: function() {
-      Polymer.dom(this.waveContainer.parentNode).removeChild(this.waveContainer);
-    }
-  };
-  Polymer({
-    is: 'paper-ripple',
-    behaviors: [ Polymer.IronA11yKeysBehavior ],
-    properties: {
-      initialOpacity: {
-        type: Number,
-        value: .25
-      },
-      opacityDecayVelocity: {
-        type: Number,
-        value: .8
-      },
-      recenters: {
-        type: Boolean,
-        value: false
-      },
-      center: {
-        type: Boolean,
-        value: false
-      },
-      ripples: {
-        type: Array,
-        value: function() {
-          return [];
-        }
-      },
-      animating: {
-        type: Boolean,
-        readOnly: true,
-        reflectToAttribute: true,
-        value: false
-      },
-      holdDown: {
-        type: Boolean,
-        value: false,
-        observer: '_holdDownChanged'
-      },
-      noink: {
-        type: Boolean,
-        value: false
-      },
-      _animating: {
-        type: Boolean
-      },
-      _boundAnimate: {
-        type: Function,
-        value: function() {
-          return this.animate.bind(this);
-        }
-      }
-    },
-    get target() {
-      return this.keyEventTarget;
-    },
-    keyBindings: {
-      'enter:keydown': '_onEnterKeydown',
-      'space:keydown': '_onSpaceKeydown',
-      'space:keyup': '_onSpaceKeyup'
-    },
-    attached: function() {
-      if (this.parentNode.nodeType == 11) {
-        this.keyEventTarget = Polymer.dom(this).getOwnerRoot().host;
-      } else {
-        this.keyEventTarget = this.parentNode;
-      }
-      var keyEventTarget = this.keyEventTarget;
-      this.listen(keyEventTarget, 'up', 'uiUpAction');
-      this.listen(keyEventTarget, 'down', 'uiDownAction');
-    },
-    detached: function() {
-      this.unlisten(this.keyEventTarget, 'up', 'uiUpAction');
-      this.unlisten(this.keyEventTarget, 'down', 'uiDownAction');
-      this.keyEventTarget = null;
-    },
-    get shouldKeepAnimating() {
-      for (var index = 0; index < this.ripples.length; ++index) {
-        if (!this.ripples[index].isAnimationComplete) {
-          return true;
-        }
-      }
-      return false;
-    },
-    simulatedRipple: function() {
-      this.downAction(null);
-      this.async(function() {
-        this.upAction();
-      }, 1);
-    },
-    uiDownAction: function(event) {
-      if (!this.noink) {
-        this.downAction(event);
-      }
-    },
-    downAction: function(event) {
-      if (this.holdDown && this.ripples.length > 0) {
-        return;
-      }
-      var ripple = this.addRipple();
-      ripple.downAction(event);
-      if (!this._animating) {
-        this._animating = true;
-        this.animate();
-      }
-    },
-    uiUpAction: function(event) {
-      if (!this.noink) {
-        this.upAction(event);
-      }
-    },
-    upAction: function(event) {
-      if (this.holdDown) {
-        return;
-      }
-      this.ripples.forEach(function(ripple) {
-        ripple.upAction(event);
-      });
-      this._animating = true;
-      this.animate();
-    },
-    onAnimationComplete: function() {
-      this._animating = false;
-      this.$.background.style.backgroundColor = null;
-      this.fire('transitionend');
-    },
-    addRipple: function() {
-      var ripple = new Ripple(this);
-      Polymer.dom(this.$.waves).appendChild(ripple.waveContainer);
-      this.$.background.style.backgroundColor = ripple.color;
-      this.ripples.push(ripple);
-      this._setAnimating(true);
-      return ripple;
-    },
-    removeRipple: function(ripple) {
-      var rippleIndex = this.ripples.indexOf(ripple);
-      if (rippleIndex < 0) {
-        return;
-      }
-      this.ripples.splice(rippleIndex, 1);
-      ripple.remove();
-      if (!this.ripples.length) {
-        this._setAnimating(false);
-      }
-    },
-    animate: function() {
-      if (!this._animating) {
-        return;
-      }
-      var index;
-      var ripple;
-      for (index = 0; index < this.ripples.length; ++index) {
-        ripple = this.ripples[index];
-        ripple.draw();
-        this.$.background.style.opacity = ripple.outerOpacity;
-        if (ripple.isOpacityFullyDecayed && !ripple.isRestingAtMaxRadius) {
-          this.removeRipple(ripple);
-        }
-      }
-      if (!this.shouldKeepAnimating && this.ripples.length === 0) {
-        this.onAnimationComplete();
-      } else {
-        window.requestAnimationFrame(this._boundAnimate);
-      }
-    },
-    _onEnterKeydown: function() {
-      this.uiDownAction();
-      this.async(this.uiUpAction, 1);
-    },
-    _onSpaceKeydown: function() {
-      this.uiDownAction();
-    },
-    _onSpaceKeyup: function() {
-      this.uiUpAction();
-    },
-    _holdDownChanged: function(newVal, oldVal) {
-      if (oldVal === undefined) {
-        return;
-      }
-      if (newVal) {
-        this.downAction();
-      } else {
-        this.upAction();
-      }
-    }
-  });
-})();
-
-Polymer.PaperRippleBehavior = {
-  properties: {
-    noink: {
-      type: Boolean,
-      observer: '_noinkChanged'
-    },
-    _rippleContainer: {
-      type: Object
-    }
-  },
-  _buttonStateChanged: function() {
-    if (this.focused) {
-      this.ensureRipple();
-    }
-  },
-  _downHandler: function(event) {
-    Polymer.IronButtonStateImpl._downHandler.call(this, event);
-    if (this.pressed) {
-      this.ensureRipple(event);
-    }
-  },
-  ensureRipple: function(optTriggeringEvent) {
-    if (!this.hasRipple()) {
-      this._ripple = this._createRipple();
-      this._ripple.noink = this.noink;
-      var rippleContainer = this._rippleContainer || this.root;
-      if (rippleContainer) {
-        Polymer.dom(rippleContainer).appendChild(this._ripple);
-      }
-      if (optTriggeringEvent) {
-        var domContainer = Polymer.dom(this._rippleContainer || this);
-        var target = Polymer.dom(optTriggeringEvent).rootTarget;
-        if (domContainer.deepContains(target)) {
-          this._ripple.uiDownAction(optTriggeringEvent);
-        }
-      }
-    }
-  },
-  getRipple: function() {
-    this.ensureRipple();
-    return this._ripple;
-  },
-  hasRipple: function() {
-    return Boolean(this._ripple);
-  },
-  _createRipple: function() {
-    return document.createElement('paper-ripple');
-  },
-  _noinkChanged: function(noink) {
-    if (this.hasRipple()) {
-      this._ripple.noink = noink;
-    }
-  }
-};
-
-Polymer.PaperInkyFocusBehaviorImpl = {
-  observers: [ '_focusedChanged(receivedFocusFromKeyboard)' ],
-  _focusedChanged: function(receivedFocusFromKeyboard) {
-    if (receivedFocusFromKeyboard) {
-      this.ensureRipple();
-    }
-    if (this.hasRipple()) {
-      this._ripple.holdDown = receivedFocusFromKeyboard;
-    }
-  },
-  _createRipple: function() {
-    var ripple = Polymer.PaperRippleBehavior._createRipple();
-    ripple.id = 'ink';
-    ripple.setAttribute('center', '');
-    ripple.classList.add('circle');
-    return ripple;
-  }
-};
-
-Polymer.PaperInkyFocusBehavior = [ Polymer.IronButtonState, Polymer.IronControlState, Polymer.PaperRippleBehavior, Polymer.PaperInkyFocusBehaviorImpl ];
-
-Polymer({
-  is: 'paper-icon-button',
-  hostAttributes: {
-    role: 'button',
-    tabindex: '0'
-  },
-  behaviors: [ Polymer.PaperInkyFocusBehavior ],
-  properties: {
-    src: {
-      type: String
-    },
-    icon: {
-      type: String
-    },
-    alt: {
-      type: String,
-      observer: "_altChanged"
-    }
-  },
-  _altChanged: function(newValue, oldValue) {
-    var label = this.getAttribute('aria-label');
-    if (!label || oldValue == label) {
-      this.setAttribute('aria-label', newValue);
-    }
-  }
-});
-
-Polymer({
-  is: 'iron-iconset-svg',
-  properties: {
-    name: {
-      type: String,
-      observer: '_nameChanged'
-    },
-    size: {
-      type: Number,
-      value: 24
-    }
-  },
-  attached: function() {
-    this.style.display = 'none';
-  },
-  getIconNames: function() {
-    this._icons = this._createIconMap();
-    return Object.keys(this._icons).map(function(n) {
-      return this.name + ':' + n;
-    }, this);
-  },
-  applyIcon: function(element, iconName) {
-    element = element.root || element;
-    this.removeIcon(element);
-    var svg = this._cloneIcon(iconName);
-    if (svg) {
-      var pde = Polymer.dom(element);
-      pde.insertBefore(svg, pde.childNodes[0]);
-      return element._svgIcon = svg;
-    }
-    return null;
-  },
-  removeIcon: function(element) {
-    if (element._svgIcon) {
-      Polymer.dom(element).removeChild(element._svgIcon);
-      element._svgIcon = null;
-    }
-  },
-  _nameChanged: function() {
-    new Polymer.IronMeta({
-      type: 'iconset',
-      key: this.name,
-      value: this
-    });
-    this.async(function() {
-      this.fire('iron-iconset-added', this, {
-        node: window
-      });
-    });
-  },
-  _createIconMap: function() {
-    var icons = Object.create(null);
-    Polymer.dom(this).querySelectorAll('[id]').forEach(function(icon) {
-      icons[icon.id] = icon;
-    });
-    return icons;
-  },
-  _cloneIcon: function(id) {
-    this._icons = this._icons || this._createIconMap();
-    return this._prepareSvgClone(this._icons[id], this.size);
-  },
-  _prepareSvgClone: function(sourceSvg, size) {
-    if (sourceSvg) {
-      var content = sourceSvg.cloneNode(true), svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'), viewBox = content.getAttribute('viewBox') || '0 0 ' + size + ' ' + size;
-      svg.setAttribute('viewBox', viewBox);
-      svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
-      svg.style.cssText = 'pointer-events: none; display: block; width: 100%; height: 100%;';
-      svg.appendChild(content).removeAttribute('id');
-      return svg;
-    }
-    return null;
-  }
-});
-
+dy=this.yNow-this.containerMetrics.height/2;this.waveContainer.style.webkitTransform="translate("+dx+"px, "+dy+"px)";this.waveContainer.style.transform="translate3d("+dx+"px, "+dy+"px, 0)";this.wave.style.webkitTransform="scale("+scale+","+scale+")";this.wave.style.transform="scale3d("+scale+","+scale+",1)"},downAction:function(event){var xCenter=this.containerMetrics.width/2;var yCenter=this.containerMetrics.height/2;this.resetInteractionState();this.mouseDownStart=Utility.now();if(this.center){this.xStart=xCenter;this.yStart=yCenter;this.slideDistance=Utility.distance(this.xStart,this.yStart,this.xEnd,this.yEnd)}else{this.xStart=event?event.detail.x-this.containerMetrics.boundingRect.left:this.containerMetrics.width/2;this.yStart=event?event.detail.y-this.containerMetrics.boundingRect.top:this.containerMetrics.height/2}if(this.recenters){this.xEnd=xCenter;this.yEnd=yCenter;this.slideDistance=Utility.distance(this.xStart,this.yStart,this.xEnd,this.yEnd)}this.maxRadius=this.containerMetrics.furthestCornerDistanceFrom(this.xStart,this.yStart);this.waveContainer.style.top=(this.containerMetrics.height-this.containerMetrics.size)/2+"px";this.waveContainer.style.left=(this.containerMetrics.width-this.containerMetrics.size)/2+"px";this.waveContainer.style.width=this.containerMetrics.size+"px";this.waveContainer.style.height=this.containerMetrics.size+"px"},upAction:function(event){if(!this.isMouseDown){return}this.mouseUpStart=Utility.now()},remove:function(){Polymer.dom(this.waveContainer.parentNode).removeChild(this.waveContainer)}};Polymer({is:"paper-ripple",behaviors:[Polymer.IronA11yKeysBehavior],properties:{initialOpacity:{type:Number,value:.25},opacityDecayVelocity:{type:Number,value:.8},recenters:{type:Boolean,value:false},center:{type:Boolean,value:false},ripples:{type:Array,value:function(){return[]}},animating:{type:Boolean,readOnly:true,reflectToAttribute:true,value:false},holdDown:{type:Boolean,value:false,observer:"_holdDownChanged"},noink:{type:Boolean,value:false},_animating:{type:Boolean},_boundAnimate:{type:Function,value:function(){return this.animate.bind(this)}}},get target(){return this.keyEventTarget},keyBindings:{"enter:keydown":"_onEnterKeydown","space:keydown":"_onSpaceKeydown","space:keyup":"_onSpaceKeyup"},attached:function(){if(this.parentNode.nodeType==11){this.keyEventTarget=Polymer.dom(this).getOwnerRoot().host}else{this.keyEventTarget=this.parentNode}var keyEventTarget=this.keyEventTarget;this.listen(keyEventTarget,"up","uiUpAction");this.listen(keyEventTarget,"down","uiDownAction")},detached:function(){this.unlisten(this.keyEventTarget,"up","uiUpAction");this.unlisten(this.keyEventTarget,"down","uiDownAction");this.keyEventTarget=null},get shouldKeepAnimating(){for(var index=0;index<this.ripples.length;++index){if(!this.ripples[index].isAnimationComplete){return true}}return false},simulatedRipple:function(){this.downAction(null);this.async(function(){this.upAction()},1)},uiDownAction:function(event){if(!this.noink){this.downAction(event)}},downAction:function(event){if(this.holdDown&&this.ripples.length>0){return}var ripple=this.addRipple();ripple.downAction(event);if(!this._animating){this._animating=true;this.animate()}},uiUpAction:function(event){if(!this.noink){this.upAction(event)}},upAction:function(event){if(this.holdDown){return}this.ripples.forEach(function(ripple){ripple.upAction(event)});this._animating=true;this.animate()},onAnimationComplete:function(){this._animating=false;this.$.background.style.backgroundColor=null;this.fire("transitionend")},addRipple:function(){var ripple=new Ripple(this);Polymer.dom(this.$.waves).appendChild(ripple.waveContainer);this.$.background.style.backgroundColor=ripple.color;this.ripples.push(ripple);this._setAnimating(true);return ripple},removeRipple:function(ripple){var rippleIndex=this.ripples.indexOf(ripple);if(rippleIndex<0){return}this.ripples.splice(rippleIndex,1);ripple.remove();if(!this.ripples.length){this._setAnimating(false)}},animate:function(){if(!this._animating){return}var index;var ripple;for(index=0;index<this.ripples.length;++index){ripple=this.ripples[index];ripple.draw();this.$.background.style.opacity=ripple.outerOpacity;if(ripple.isOpacityFullyDecayed&&!ripple.isRestingAtMaxRadius){this.removeRipple(ripple)}}if(!this.shouldKeepAnimating&&this.ripples.length===0){this.onAnimationComplete()}else{window.requestAnimationFrame(this._boundAnimate)}},_onEnterKeydown:function(){this.uiDownAction();this.async(this.uiUpAction,1)},_onSpaceKeydown:function(){this.uiDownAction()},_onSpaceKeyup:function(){this.uiUpAction()},_holdDownChanged:function(newVal,oldVal){if(oldVal===undefined){return}if(newVal){this.downAction()}else{this.upAction()}}})})();Polymer.PaperRippleBehavior={properties:{noink:{type:Boolean,observer:"_noinkChanged"},_rippleContainer:{type:Object}},_buttonStateChanged:function(){if(this.focused){this.ensureRipple()}},_downHandler:function(event){Polymer.IronButtonStateImpl._downHandler.call(this,event);if(this.pressed){this.ensureRipple(event)}},ensureRipple:function(optTriggeringEvent){if(!this.hasRipple()){this._ripple=this._createRipple();this._ripple.noink=this.noink;var rippleContainer=this._rippleContainer||this.root;if(rippleContainer){Polymer.dom(rippleContainer).appendChild(this._ripple)}if(optTriggeringEvent){var domContainer=Polymer.dom(this._rippleContainer||this);var target=Polymer.dom(optTriggeringEvent).rootTarget;if(domContainer.deepContains(target)){this._ripple.uiDownAction(optTriggeringEvent)}}}},getRipple:function(){this.ensureRipple();return this._ripple},hasRipple:function(){return Boolean(this._ripple)},_createRipple:function(){return document.createElement("paper-ripple")},_noinkChanged:function(noink){if(this.hasRipple()){this._ripple.noink=noink}}};Polymer.PaperInkyFocusBehaviorImpl={observers:["_focusedChanged(receivedFocusFromKeyboard)"],_focusedChanged:function(receivedFocusFromKeyboard){if(receivedFocusFromKeyboard){this.ensureRipple()}if(this.hasRipple()){this._ripple.holdDown=receivedFocusFromKeyboard}},_createRipple:function(){var ripple=Polymer.PaperRippleBehavior._createRipple();ripple.id="ink";ripple.setAttribute("center","");ripple.classList.add("circle");return ripple}};Polymer.PaperInkyFocusBehavior=[Polymer.IronButtonState,Polymer.IronControlState,Polymer.PaperRippleBehavior,Polymer.PaperInkyFocusBehaviorImpl];Polymer({is:"paper-icon-button",hostAttributes:{role:"button",tabindex:"0"},behaviors:[Polymer.PaperInkyFocusBehavior],properties:{src:{type:String},icon:{type:String},alt:{type:String,observer:"_altChanged"}},_altChanged:function(newValue,oldValue){var label=this.getAttribute("aria-label");if(!label||oldValue==label){this.setAttribute("aria-label",newValue)}}});Polymer({is:"iron-iconset-svg",properties:{name:{type:String,observer:"_nameChanged"},size:{type:Number,value:24}},attached:function(){this.style.display="none"},getIconNames:function(){this._icons=this._createIconMap();return Object.keys(this._icons).map(function(n){return this.name+":"+n},this)},applyIcon:function(element,iconName){element=element.root||element;this.removeIcon(element);var svg=this._cloneIcon(iconName);if(svg){var pde=Polymer.dom(element);pde.insertBefore(svg,pde.childNodes[0]);return element._svgIcon=svg}return null},removeIcon:function(element){if(element._svgIcon){Polymer.dom(element).removeChild(element._svgIcon);element._svgIcon=null}},_nameChanged:function(){new Polymer.IronMeta({type:"iconset",key:this.name,value:this});this.async(function(){this.fire("iron-iconset-added",this,{node:window})})},_createIconMap:function(){var icons=Object.create(null);Polymer.dom(this).querySelectorAll("[id]").forEach(function(icon){icons[icon.id]=icon});return icons},_cloneIcon:function(id){this._icons=this._icons||this._createIconMap();return this._prepareSvgClone(this._icons[id],this.size)},_prepareSvgClone:function(sourceSvg,size){if(sourceSvg){var content=sourceSvg.cloneNode(true),svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),viewBox=content.getAttribute("viewBox")||"0 0 "+size+" "+size;svg.setAttribute("viewBox",viewBox);svg.setAttribute("preserveAspectRatio","xMidYMid meet");svg.style.cssText="pointer-events: none; display: block; width: 100%; height: 100%;";svg.appendChild(content).removeAttribute("id");return svg}return null}});
 // 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.
-Polymer({
-  is: 'cr-lazy-render',
-  "extends": 'template',
-  behaviors: [ Polymer.Templatizer ],
-  child_: null,
-  get: function() {
-    if (!this.child_) this.render_();
-    return this.child_;
-  },
-  getIfExists: function() {
-    return this.child_;
-  },
-  render_: function() {
-    if (!this.ctor) this.templatize(this);
-    var parentNode = this.parentNode;
-    if (parentNode && !this.child_) {
-      var instance = this.stamp({});
-      this.child_ = instance.root.firstElementChild;
-      parentNode.insertBefore(instance.root, this);
-    }
-  },
-  _forwardParentProp: function(prop, value) {
-    if (this.child_) this.child_._templateInstance[prop] = value;
-  },
-  _forwardParentPath: function(path, value) {
-    if (this.child_) this.child_._templateInstance.notifyPath(path, value, true);
-  }
-});
-
-(function() {
-  'use strict';
-  Polymer.IronA11yAnnouncer = Polymer({
-    is: 'iron-a11y-announcer',
-    properties: {
-      mode: {
-        type: String,
-        value: 'polite'
-      },
-      _text: {
-        type: String,
-        value: ''
-      }
-    },
-    created: function() {
-      if (!Polymer.IronA11yAnnouncer.instance) {
-        Polymer.IronA11yAnnouncer.instance = this;
-      }
-      document.body.addEventListener('iron-announce', this._onIronAnnounce.bind(this));
-    },
-    announce: function(text) {
-      this._text = '';
-      this.async(function() {
-        this._text = text;
-      }, 100);
-    },
-    _onIronAnnounce: function(event) {
-      if (event.detail && event.detail.text) {
-        this.announce(event.detail.text);
-      }
-    }
-  });
-  Polymer.IronA11yAnnouncer.instance = null;
-  Polymer.IronA11yAnnouncer.requestAvailability = function() {
-    if (!Polymer.IronA11yAnnouncer.instance) {
-      Polymer.IronA11yAnnouncer.instance = document.createElement('iron-a11y-announcer');
-    }
-    document.body.appendChild(Polymer.IronA11yAnnouncer.instance);
-  };
-})();
-
-Polymer.IronValidatableBehaviorMeta = null;
-
-Polymer.IronValidatableBehavior = {
-  properties: {
-    validator: {
-      type: String
-    },
-    invalid: {
-      notify: true,
-      reflectToAttribute: true,
-      type: Boolean,
-      value: false
-    },
-    _validatorMeta: {
-      type: Object
-    },
-    validatorType: {
-      type: String,
-      value: 'validator'
-    },
-    _validator: {
-      type: Object,
-      computed: '__computeValidator(validator)'
-    }
-  },
-  observers: [ '_invalidChanged(invalid)' ],
-  registered: function() {
-    Polymer.IronValidatableBehaviorMeta = new Polymer.IronMeta({
-      type: 'validator'
-    });
-  },
-  _invalidChanged: function() {
-    if (this.invalid) {
-      this.setAttribute('aria-invalid', 'true');
-    } else {
-      this.removeAttribute('aria-invalid');
-    }
-  },
-  hasValidator: function() {
-    return this._validator != null;
-  },
-  validate: function(value) {
-    this.invalid = !this._getValidity(value);
-    return !this.invalid;
-  },
-  _getValidity: function(value) {
-    if (this.hasValidator()) {
-      return this._validator.validate(value);
-    }
-    return true;
-  },
-  __computeValidator: function() {
-    return Polymer.IronValidatableBehaviorMeta && Polymer.IronValidatableBehaviorMeta.byKey(this.validator);
-  }
-};
-
-Polymer({
-  is: 'iron-input',
-  "extends": 'input',
-  behaviors: [ Polymer.IronValidatableBehavior ],
-  properties: {
-    bindValue: {
-      observer: '_bindValueChanged',
-      type: String
-    },
-    preventInvalidInput: {
-      type: Boolean
-    },
-    allowedPattern: {
-      type: String,
-      observer: "_allowedPatternChanged"
-    },
-    _previousValidInput: {
-      type: String,
-      value: ''
-    },
-    _patternAlreadyChecked: {
-      type: Boolean,
-      value: false
-    }
-  },
-  listeners: {
-    input: '_onInput',
-    keypress: '_onKeypress'
-  },
-  registered: function() {
-    if (!this._canDispatchEventOnDisabled()) {
-      this._origDispatchEvent = this.dispatchEvent;
-      this.dispatchEvent = this._dispatchEventFirefoxIE;
-    }
-  },
-  created: function() {
-    Polymer.IronA11yAnnouncer.requestAvailability();
-  },
-  _canDispatchEventOnDisabled: function() {
-    var input = document.createElement('input');
-    var canDispatch = false;
-    input.disabled = true;
-    input.addEventListener('feature-check-dispatch-event', function() {
-      canDispatch = true;
-    });
-    try {
-      input.dispatchEvent(new Event('feature-check-dispatch-event'));
-    } catch (e) {}
-    return canDispatch;
-  },
-  _dispatchEventFirefoxIE: function() {
-    var disabled = this.disabled;
-    this.disabled = false;
-    this._origDispatchEvent.apply(this, arguments);
-    this.disabled = disabled;
-  },
-  get _patternRegExp() {
-    var pattern;
-    if (this.allowedPattern) {
-      pattern = new RegExp(this.allowedPattern);
-    } else {
-      switch (this.type) {
-       case 'number':
-        pattern = /[0-9.,e-]/;
-        break;
-      }
-    }
-    return pattern;
-  },
-  ready: function() {
-    this.bindValue = this.value;
-  },
-  _bindValueChanged: function() {
-    if (this.value !== this.bindValue) {
-      this.value = !(this.bindValue || this.bindValue === 0 || this.bindValue === false) ? '' : this.bindValue;
-    }
-    this.fire('bind-value-changed', {
-      value: this.bindValue
-    });
-  },
-  _allowedPatternChanged: function() {
-    this.preventInvalidInput = this.allowedPattern ? true : false;
-  },
-  _onInput: function() {
-    if (this.preventInvalidInput && !this._patternAlreadyChecked) {
-      var valid = this._checkPatternValidity();
-      if (!valid) {
-        this._announceInvalidCharacter('Invalid string of characters not entered.');
-        this.value = this._previousValidInput;
-      }
-    }
-    this.bindValue = this.value;
-    this._previousValidInput = this.value;
-    this._patternAlreadyChecked = false;
-  },
-  _isPrintable: function(event) {
-    var anyNonPrintable = event.keyCode == 8 || event.keyCode == 9 || event.keyCode == 13 || event.keyCode == 27;
-    var mozNonPrintable = event.keyCode == 19 || event.keyCode == 20 || event.keyCode == 45 || event.keyCode == 46 || event.keyCode == 144 || event.keyCode == 145 || event.keyCode > 32 && event.keyCode < 41 || event.keyCode > 111 && event.keyCode < 124;
-    return !anyNonPrintable && !(event.charCode == 0 && mozNonPrintable);
-  },
-  _onKeypress: function(event) {
-    if (!this.preventInvalidInput && this.type !== 'number') {
-      return;
-    }
-    var regexp = this._patternRegExp;
-    if (!regexp) {
-      return;
-    }
-    if (event.metaKey || event.ctrlKey || event.altKey) return;
-    this._patternAlreadyChecked = true;
-    var thisChar = String.fromCharCode(event.charCode);
-    if (this._isPrintable(event) && !regexp.test(thisChar)) {
-      event.preventDefault();
-      this._announceInvalidCharacter('Invalid character ' + thisChar + ' not entered.');
-    }
-  },
-  _checkPatternValidity: function() {
-    var regexp = this._patternRegExp;
-    if (!regexp) {
-      return true;
-    }
-    for (var i = 0; i < this.value.length; i++) {
-      if (!regexp.test(this.value[i])) {
-        return false;
-      }
-    }
-    return true;
-  },
-  validate: function() {
-    var valid = this.checkValidity();
-    if (valid) {
-      if (this.required && this.value === '') {
-        valid = false;
-      } else if (this.hasValidator()) {
-        valid = Polymer.IronValidatableBehavior.validate.call(this, this.value);
-      }
-    }
-    this.invalid = !valid;
-    this.fire('iron-input-validate');
-    return valid;
-  },
-  _announceInvalidCharacter: function(message) {
-    this.fire('iron-announce', {
-      text: message
-    });
-  }
-});
-
-Polymer({
-  is: 'paper-input-container',
-  properties: {
-    noLabelFloat: {
-      type: Boolean,
-      value: false
-    },
-    alwaysFloatLabel: {
-      type: Boolean,
-      value: false
-    },
-    attrForValue: {
-      type: String,
-      value: 'bind-value'
-    },
-    autoValidate: {
-      type: Boolean,
-      value: false
-    },
-    invalid: {
-      observer: '_invalidChanged',
-      type: Boolean,
-      value: false
-    },
-    focused: {
-      readOnly: true,
-      type: Boolean,
-      value: false,
-      notify: true
-    },
-    _addons: {
-      type: Array
-    },
-    _inputHasContent: {
-      type: Boolean,
-      value: false
-    },
-    _inputSelector: {
-      type: String,
-      value: 'input,textarea,.paper-input-input'
-    },
-    _boundOnFocus: {
-      type: Function,
-      value: function() {
-        return this._onFocus.bind(this);
-      }
-    },
-    _boundOnBlur: {
-      type: Function,
-      value: function() {
-        return this._onBlur.bind(this);
-      }
-    },
-    _boundOnInput: {
-      type: Function,
-      value: function() {
-        return this._onInput.bind(this);
-      }
-    },
-    _boundValueChanged: {
-      type: Function,
-      value: function() {
-        return this._onValueChanged.bind(this);
-      }
-    }
-  },
-  listeners: {
-    'addon-attached': '_onAddonAttached',
-    'iron-input-validate': '_onIronInputValidate'
-  },
-  get _valueChangedEvent() {
-    return this.attrForValue + '-changed';
-  },
-  get _propertyForValue() {
-    return Polymer.CaseMap.dashToCamelCase(this.attrForValue);
-  },
-  get _inputElement() {
-    return Polymer.dom(this).querySelector(this._inputSelector);
-  },
-  get _inputElementValue() {
-    return this._inputElement[this._propertyForValue] || this._inputElement.value;
-  },
-  ready: function() {
-    if (!this._addons) {
-      this._addons = [];
-    }
-    this.addEventListener('focus', this._boundOnFocus, true);
-    this.addEventListener('blur', this._boundOnBlur, true);
-  },
-  attached: function() {
-    if (this.attrForValue) {
-      this._inputElement.addEventListener(this._valueChangedEvent, this._boundValueChanged);
-    } else {
-      this.addEventListener('input', this._onInput);
-    }
-    if (this._inputElementValue != '') {
-      this._handleValueAndAutoValidate(this._inputElement);
-    } else {
-      this._handleValue(this._inputElement);
-    }
-  },
-  _onAddonAttached: function(event) {
-    if (!this._addons) {
-      this._addons = [];
-    }
-    var target = event.target;
-    if (this._addons.indexOf(target) === -1) {
-      this._addons.push(target);
-      if (this.isAttached) {
-        this._handleValue(this._inputElement);
-      }
-    }
-  },
-  _onFocus: function() {
-    this._setFocused(true);
-  },
-  _onBlur: function() {
-    this._setFocused(false);
-    this._handleValueAndAutoValidate(this._inputElement);
-  },
-  _onInput: function(event) {
-    this._handleValueAndAutoValidate(event.target);
-  },
-  _onValueChanged: function(event) {
-    this._handleValueAndAutoValidate(event.target);
-  },
-  _handleValue: function(inputElement) {
-    var value = this._inputElementValue;
-    if (value || value === 0 || inputElement.type === 'number' && !inputElement.checkValidity()) {
-      this._inputHasContent = true;
-    } else {
-      this._inputHasContent = false;
-    }
-    this.updateAddons({
-      inputElement: inputElement,
-      value: value,
-      invalid: this.invalid
-    });
-  },
-  _handleValueAndAutoValidate: function(inputElement) {
-    if (this.autoValidate) {
-      var valid;
-      if (inputElement.validate) {
-        valid = inputElement.validate(this._inputElementValue);
-      } else {
-        valid = inputElement.checkValidity();
-      }
-      this.invalid = !valid;
-    }
-    this._handleValue(inputElement);
-  },
-  _onIronInputValidate: function(event) {
-    this.invalid = this._inputElement.invalid;
-  },
-  _invalidChanged: function() {
-    if (this._addons) {
-      this.updateAddons({
-        invalid: this.invalid
-      });
-    }
-  },
-  updateAddons: function(state) {
-    for (var addon, index = 0; addon = this._addons[index]; index++) {
-      addon.update(state);
-    }
-  },
-  _computeInputContentClass: function(noLabelFloat, alwaysFloatLabel, focused, invalid, _inputHasContent) {
-    var cls = 'input-content';
-    if (!noLabelFloat) {
-      var label = this.querySelector('label');
-      if (alwaysFloatLabel || _inputHasContent) {
-        cls += ' label-is-floating';
-        this.$.labelAndInputContainer.style.position = 'static';
-        if (invalid) {
-          cls += ' is-invalid';
-        } else if (focused) {
-          cls += " label-is-highlighted";
-        }
-      } else {
-        if (label) {
-          this.$.labelAndInputContainer.style.position = 'relative';
-        }
-      }
-    } else {
-      if (_inputHasContent) {
-        cls += ' label-is-hidden';
-      }
-    }
-    return cls;
-  },
-  _computeUnderlineClass: function(focused, invalid) {
-    var cls = 'underline';
-    if (invalid) {
-      cls += ' is-invalid';
-    } else if (focused) {
-      cls += ' is-highlighted';
-    }
-    return cls;
-  },
-  _computeAddOnContentClass: function(focused, invalid) {
-    var cls = 'add-on-content';
-    if (invalid) {
-      cls += ' is-invalid';
-    } else if (focused) {
-      cls += ' is-highlighted';
-    }
-    return cls;
-  }
-});
-
-Polymer.PaperSpinnerBehavior = {
-  listeners: {
-    animationend: '__reset',
-    webkitAnimationEnd: '__reset'
-  },
-  properties: {
-    active: {
-      type: Boolean,
-      value: false,
-      reflectToAttribute: true,
-      observer: '__activeChanged'
-    },
-    alt: {
-      type: String,
-      value: 'loading',
-      observer: '__altChanged'
-    },
-    __coolingDown: {
-      type: Boolean,
-      value: false
-    }
-  },
-  __computeContainerClasses: function(active, coolingDown) {
-    return [ active || coolingDown ? 'active' : '', coolingDown ? 'cooldown' : '' ].join(' ');
-  },
-  __activeChanged: function(active, old) {
-    this.__setAriaHidden(!active);
-    this.__coolingDown = !active && old;
-  },
-  __altChanged: function(alt) {
-    if (alt === this.getPropertyInfo('alt').value) {
-      this.alt = this.getAttribute('aria-label') || alt;
-    } else {
-      this.__setAriaHidden(alt === '');
-      this.setAttribute('aria-label', alt);
-    }
-  },
-  __setAriaHidden: function(hidden) {
-    var attr = 'aria-hidden';
-    if (hidden) {
-      this.setAttribute(attr, 'true');
-    } else {
-      this.removeAttribute(attr);
-    }
-  },
-  __reset: function() {
-    this.active = false;
-    this.__coolingDown = false;
-  }
-};
-
-Polymer({
-  is: 'paper-spinner-lite',
-  behaviors: [ Polymer.PaperSpinnerBehavior ]
-});
-
+Polymer({is:"cr-lazy-render","extends":"template",behaviors:[Polymer.Templatizer],child_:null,get:function(){if(!this.child_)this.render_();return this.child_},getIfExists:function(){return this.child_},render_:function(){if(!this.ctor)this.templatize(this);var parentNode=this.parentNode;if(parentNode&&!this.child_){var instance=this.stamp({});this.child_=instance.root.firstElementChild;parentNode.insertBefore(instance.root,this)}},_forwardParentProp:function(prop,value){if(this.child_)this.child_._templateInstance[prop]=value},_forwardParentPath:function(path,value){if(this.child_)this.child_._templateInstance.notifyPath(path,value,true)}});(function(){"use strict";Polymer.IronA11yAnnouncer=Polymer({is:"iron-a11y-announcer",properties:{mode:{type:String,value:"polite"},_text:{type:String,value:""}},created:function(){if(!Polymer.IronA11yAnnouncer.instance){Polymer.IronA11yAnnouncer.instance=this}document.body.addEventListener("iron-announce",this._onIronAnnounce.bind(this))},announce:function(text){this._text="";this.async(function(){this._text=text},100)},_onIronAnnounce:function(event){if(event.detail&&event.detail.text){this.announce(event.detail.text)}}});Polymer.IronA11yAnnouncer.instance=null;Polymer.IronA11yAnnouncer.requestAvailability=function(){if(!Polymer.IronA11yAnnouncer.instance){Polymer.IronA11yAnnouncer.instance=document.createElement("iron-a11y-announcer")}document.body.appendChild(Polymer.IronA11yAnnouncer.instance)}})();Polymer.IronValidatableBehaviorMeta=null;Polymer.IronValidatableBehavior={properties:{validator:{type:String},invalid:{notify:true,reflectToAttribute:true,type:Boolean,value:false},_validatorMeta:{type:Object},validatorType:{type:String,value:"validator"},_validator:{type:Object,computed:"__computeValidator(validator)"}},observers:["_invalidChanged(invalid)"],registered:function(){Polymer.IronValidatableBehaviorMeta=new Polymer.IronMeta({type:"validator"})},_invalidChanged:function(){if(this.invalid){this.setAttribute("aria-invalid","true")}else{this.removeAttribute("aria-invalid")}},hasValidator:function(){return this._validator!=null},validate:function(value){this.invalid=!this._getValidity(value);return!this.invalid},_getValidity:function(value){if(this.hasValidator()){return this._validator.validate(value)}return true},__computeValidator:function(){return Polymer.IronValidatableBehaviorMeta&&Polymer.IronValidatableBehaviorMeta.byKey(this.validator)}};Polymer({is:"iron-input","extends":"input",behaviors:[Polymer.IronValidatableBehavior],properties:{bindValue:{observer:"_bindValueChanged",type:String},preventInvalidInput:{type:Boolean},allowedPattern:{type:String,observer:"_allowedPatternChanged"},_previousValidInput:{type:String,value:""},_patternAlreadyChecked:{type:Boolean,value:false}},listeners:{input:"_onInput",keypress:"_onKeypress"},registered:function(){if(!this._canDispatchEventOnDisabled()){this._origDispatchEvent=this.dispatchEvent;this.dispatchEvent=this._dispatchEventFirefoxIE}},created:function(){Polymer.IronA11yAnnouncer.requestAvailability()},_canDispatchEventOnDisabled:function(){var input=document.createElement("input");var canDispatch=false;input.disabled=true;input.addEventListener("feature-check-dispatch-event",function(){canDispatch=true});try{input.dispatchEvent(new Event("feature-check-dispatch-event"))}catch(e){}return canDispatch},_dispatchEventFirefoxIE:function(){var disabled=this.disabled;this.disabled=false;this._origDispatchEvent.apply(this,arguments);this.disabled=disabled},get _patternRegExp(){var pattern;if(this.allowedPattern){pattern=new RegExp(this.allowedPattern)}else{switch(this.type){case"number":pattern=/[0-9.,e-]/;break}}return pattern},ready:function(){this.bindValue=this.value},_bindValueChanged:function(){if(this.value!==this.bindValue){this.value=!(this.bindValue||this.bindValue===0||this.bindValue===false)?"":this.bindValue}this.fire("bind-value-changed",{value:this.bindValue})},_allowedPatternChanged:function(){this.preventInvalidInput=this.allowedPattern?true:false},_onInput:function(){if(this.preventInvalidInput&&!this._patternAlreadyChecked){var valid=this._checkPatternValidity();if(!valid){this._announceInvalidCharacter("Invalid string of characters not entered.");this.value=this._previousValidInput}}this.bindValue=this.value;this._previousValidInput=this.value;this._patternAlreadyChecked=false},_isPrintable:function(event){var anyNonPrintable=event.keyCode==8||event.keyCode==9||event.keyCode==13||event.keyCode==27;var mozNonPrintable=event.keyCode==19||event.keyCode==20||event.keyCode==45||event.keyCode==46||event.keyCode==144||event.keyCode==145||event.keyCode>32&&event.keyCode<41||event.keyCode>111&&event.keyCode<124;return!anyNonPrintable&&!(event.charCode==0&&mozNonPrintable)},_onKeypress:function(event){if(!this.preventInvalidInput&&this.type!=="number"){return}var regexp=this._patternRegExp;if(!regexp){return}if(event.metaKey||event.ctrlKey||event.altKey)return;this._patternAlreadyChecked=true;var thisChar=String.fromCharCode(event.charCode);if(this._isPrintable(event)&&!regexp.test(thisChar)){event.preventDefault();this._announceInvalidCharacter("Invalid character "+thisChar+" not entered.")}},_checkPatternValidity:function(){var regexp=this._patternRegExp;if(!regexp){return true}for(var i=0;i<this.value.length;i++){if(!regexp.test(this.value[i])){return false}}return true},validate:function(){var valid=this.checkValidity();if(valid){if(this.required&&this.value===""){valid=false}else if(this.hasValidator()){valid=Polymer.IronValidatableBehavior.validate.call(this,this.value)}}this.invalid=!valid;this.fire("iron-input-validate");return valid},_announceInvalidCharacter:function(message){this.fire("iron-announce",{text:message})}});Polymer({is:"paper-input-container",properties:{noLabelFloat:{type:Boolean,value:false},alwaysFloatLabel:{type:Boolean,value:false},attrForValue:{type:String,value:"bind-value"},autoValidate:{type:Boolean,value:false},invalid:{observer:"_invalidChanged",type:Boolean,value:false},focused:{readOnly:true,type:Boolean,value:false,notify:true},_addons:{type:Array},_inputHasContent:{type:Boolean,value:false},_inputSelector:{type:String,value:"input,textarea,.paper-input-input"},_boundOnFocus:{type:Function,value:function(){return this._onFocus.bind(this)}},_boundOnBlur:{type:Function,value:function(){return this._onBlur.bind(this)}},_boundOnInput:{type:Function,value:function(){return this._onInput.bind(this)}},_boundValueChanged:{type:Function,value:function(){return this._onValueChanged.bind(this)}}},listeners:{"addon-attached":"_onAddonAttached","iron-input-validate":"_onIronInputValidate"},get _valueChangedEvent(){return this.attrForValue+"-changed"},get _propertyForValue(){return Polymer.CaseMap.dashToCamelCase(this.attrForValue)},get _inputElement(){return Polymer.dom(this).querySelector(this._inputSelector)},get _inputElementValue(){return this._inputElement[this._propertyForValue]||this._inputElement.value},ready:function(){if(!this._addons){this._addons=[]}this.addEventListener("focus",this._boundOnFocus,true);this.addEventListener("blur",this._boundOnBlur,true)},attached:function(){if(this.attrForValue){this._inputElement.addEventListener(this._valueChangedEvent,this._boundValueChanged)}else{this.addEventListener("input",this._onInput)}if(this._inputElementValue!=""){this._handleValueAndAutoValidate(this._inputElement)}else{this._handleValue(this._inputElement)}},_onAddonAttached:function(event){if(!this._addons){this._addons=[]}var target=event.target;if(this._addons.indexOf(target)===-1){this._addons.push(target);if(this.isAttached){this._handleValue(this._inputElement)}}},_onFocus:function(){this._setFocused(true)},_onBlur:function(){this._setFocused(false);this._handleValueAndAutoValidate(this._inputElement)},_onInput:function(event){this._handleValueAndAutoValidate(event.target)},_onValueChanged:function(event){this._handleValueAndAutoValidate(event.target)},_handleValue:function(inputElement){var value=this._inputElementValue;if(value||value===0||inputElement.type==="number"&&!inputElement.checkValidity()){this._inputHasContent=true}else{this._inputHasContent=false}this.updateAddons({inputElement:inputElement,value:value,invalid:this.invalid})},_handleValueAndAutoValidate:function(inputElement){if(this.autoValidate){var valid;if(inputElement.validate){valid=inputElement.validate(this._inputElementValue)}else{valid=inputElement.checkValidity()}this.invalid=!valid}this._handleValue(inputElement)},_onIronInputValidate:function(event){this.invalid=this._inputElement.invalid},_invalidChanged:function(){if(this._addons){this.updateAddons({invalid:this.invalid})}},updateAddons:function(state){for(var addon,index=0;addon=this._addons[index];index++){addon.update(state)}},_computeInputContentClass:function(noLabelFloat,alwaysFloatLabel,focused,invalid,_inputHasContent){var cls="input-content";if(!noLabelFloat){var label=this.querySelector("label");if(alwaysFloatLabel||_inputHasContent){cls+=" label-is-floating";this.$.labelAndInputContainer.style.position="static";if(invalid){cls+=" is-invalid"}else if(focused){cls+=" label-is-highlighted"}}else{if(label){this.$.labelAndInputContainer.style.position="relative"}}}else{if(_inputHasContent){cls+=" label-is-hidden"}}return cls},_computeUnderlineClass:function(focused,invalid){var cls="underline";if(invalid){cls+=" is-invalid"}else if(focused){cls+=" is-highlighted"}return cls},_computeAddOnContentClass:function(focused,invalid){var cls="add-on-content";if(invalid){cls+=" is-invalid"}else if(focused){cls+=" is-highlighted"}return cls}});Polymer.PaperSpinnerBehavior={listeners:{animationend:"__reset",webkitAnimationEnd:"__reset"},properties:{active:{type:Boolean,value:false,reflectToAttribute:true,observer:"__activeChanged"},alt:{type:String,value:"loading",observer:"__altChanged"},__coolingDown:{type:Boolean,value:false}},__computeContainerClasses:function(active,coolingDown){return[active||coolingDown?"active":"",coolingDown?"cooldown":""].join(" ")},__activeChanged:function(active,old){this.__setAriaHidden(!active);this.__coolingDown=!active&&old},__altChanged:function(alt){if(alt===this.getPropertyInfo("alt").value){this.alt=this.getAttribute("aria-label")||alt}else{this.__setAriaHidden(alt==="");this.setAttribute("aria-label",alt)}},__setAriaHidden:function(hidden){var attr="aria-hidden";if(hidden){this.setAttribute(attr,"true")}else{this.removeAttribute(attr)}},__reset:function(){this.active=false;this.__coolingDown=false}};Polymer({is:"paper-spinner-lite",behaviors:[Polymer.PaperSpinnerBehavior]});
 // 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.
-var CrSearchFieldBehavior = {
-  properties: {
-    label: {
-      type: String,
-      value: ''
-    },
-    clearLabel: {
-      type: String,
-      value: ''
-    },
-    showingSearch: {
-      type: Boolean,
-      value: false,
-      notify: true,
-      observer: 'showingSearchChanged_',
-      reflectToAttribute: true
-    },
-    lastValue_: {
-      type: String,
-      value: ''
-    }
-  },
-  getSearchInput: function() {},
-  getValue: function() {
-    return this.getSearchInput().value;
-  },
-  setValue: function(value) {
-    this.getSearchInput().bindValue = value;
-    this.onValueChanged_(value);
-  },
-  showAndFocus: function() {
-    this.showingSearch = true;
-    this.focus_();
-  },
-  focus_: function() {
-    this.getSearchInput().focus();
-  },
-  onSearchTermSearch: function() {
-    this.onValueChanged_(this.getValue());
-  },
-  onValueChanged_: function(newValue) {
-    if (newValue == this.lastValue_) return;
-    this.fire('search-changed', newValue);
-    this.lastValue_ = newValue;
-  },
-  onSearchTermKeydown: function(e) {
-    if (e.key == 'Escape') this.showingSearch = false;
-  },
-  showingSearchChanged_: function() {
-    if (this.showingSearch) {
-      this.focus_();
-      return;
-    }
-    this.setValue('');
-    this.getSearchInput().blur();
-  }
-};
-
+var CrSearchFieldBehavior={properties:{label:{type:String,value:""},clearLabel:{type:String,value:""},showingSearch:{type:Boolean,value:false,notify:true,observer:"showingSearchChanged_",reflectToAttribute:true},lastValue_:{type:String,value:""}},getSearchInput:function(){},getValue:function(){return this.getSearchInput().value},setValue:function(value){this.getSearchInput().bindValue=value;this.onValueChanged_(value)},showAndFocus:function(){this.showingSearch=true;this.focus_()},focus_:function(){this.getSearchInput().focus()},onSearchTermSearch:function(){this.onValueChanged_(this.getValue())},onValueChanged_:function(newValue){if(newValue==this.lastValue_)return;this.fire("search-changed",newValue);this.lastValue_=newValue},onSearchTermKeydown:function(e){if(e.key=="Escape")this.showingSearch=false},showingSearchChanged_:function(){if(this.showingSearch){this.focus_();return}this.setValue("");this.getSearchInput().blur()}};
 // 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.
-Polymer({
-  is: 'cr-toolbar-search-field',
-  behaviors: [ CrSearchFieldBehavior ],
-  properties: {
-    narrow: {
-      type: Boolean,
-      reflectToAttribute: true
-    },
-    label: String,
-    clearLabel: String,
-    spinnerActive: {
-      type: Boolean,
-      reflectToAttribute: true
-    },
-    hasSearchText_: Boolean,
-    isSpinnerShown_: {
-      type: Boolean,
-      computed: 'computeIsSpinnerShown_(spinnerActive, showingSearch)'
-    }
-  },
-  listeners: {
-    tap: 'showSearch_',
-    'searchInput.bind-value-changed': 'onBindValueChanged_'
-  },
-  getSearchInput: function() {
-    return this.$.searchInput;
-  },
-  isSearchFocused: function() {
-    return this.$.searchTerm.focused;
-  },
-  computeIconTabIndex_: function(narrow) {
-    return narrow ? 0 : -1;
-  },
-  computeIsSpinnerShown_: function() {
-    return this.spinnerActive && this.showingSearch;
-  },
-  onInputBlur_: function() {
-    if (!this.hasSearchText_) this.showingSearch = false;
-  },
-  onBindValueChanged_: function() {
-    var newValue = this.$.searchInput.bindValue;
-    this.hasSearchText_ = newValue != '';
-    if (newValue != '') this.showingSearch = true;
-  },
-  showSearch_: function(e) {
-    if (e.target != this.$.clearSearch) this.showingSearch = true;
-  },
-  hideSearch_: function(e) {
-    this.showingSearch = false;
-    e.stopPropagation();
-  }
-});
-
+Polymer({is:"cr-toolbar-search-field",behaviors:[CrSearchFieldBehavior],properties:{narrow:{type:Boolean,reflectToAttribute:true},label:String,clearLabel:String,spinnerActive:{type:Boolean,reflectToAttribute:true},hasSearchText_:Boolean,isSpinnerShown_:{type:Boolean,computed:"computeIsSpinnerShown_(spinnerActive, showingSearch)"}},listeners:{tap:"showSearch_","searchInput.bind-value-changed":"onBindValueChanged_"},getSearchInput:function(){return this.$.searchInput},isSearchFocused:function(){return this.$.searchTerm.focused},computeIconTabIndex_:function(narrow){return narrow?0:-1},computeIsSpinnerShown_:function(){return this.spinnerActive&&this.showingSearch},onInputBlur_:function(){if(!this.hasSearchText_)this.showingSearch=false},onBindValueChanged_:function(){var newValue=this.$.searchInput.bindValue;this.hasSearchText_=newValue!="";if(newValue!="")this.showingSearch=true},showSearch_:function(e){if(e.target!=this.$.clearSearch)this.showingSearch=true},hideSearch_:function(e){this.showingSearch=false;e.stopPropagation()}});
 // 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.
-Polymer({
-  is: 'cr-toolbar',
-  properties: {
-    pageName: String,
-    searchPrompt: String,
-    clearLabel: String,
-    menuLabel: String,
-    menuPromo: String,
-    spinnerActive: Boolean,
-    showMenu: {
-      type: Boolean,
-      value: false
-    },
-    showMenuPromo: {
-      type: Boolean,
-      value: false
-    },
-    closeMenuPromo: String,
-    narrow_: {
-      type: Boolean,
-      reflectToAttribute: true
-    },
-    showingSearch_: {
-      type: Boolean,
-      reflectToAttribute: true
-    }
-  },
-  observers: [ 'possiblyShowMenuPromo_(showMenu, showMenuPromo, showingSearch_)' ],
-  getSearchField: function() {
-    return this.$.search;
-  },
-  onClosePromoTap_: function() {
-    this.showMenuPromo = false;
-  },
-  onMenuTap_: function() {
-    this.fire('cr-menu-tap');
-    this.onClosePromoTap_();
-  },
-  possiblyShowMenuPromo_: function() {
-    Polymer.RenderStatus.afterNextRender(this, function() {
-      if (this.showMenu && this.showMenuPromo && !this.showingSearch_) {
-        this.$$('#menuPromo').animate({
-          opacity: [ 0, .9 ]
-        }, {
-          duration: 500,
-          fill: 'forwards'
-        });
-        this.fire('cr-menu-promo-shown');
-      }
-    }.bind(this));
-  },
-  titleIfNotShowMenuPromo_: function(title, showMenuPromo) {
-    return showMenuPromo ? '' : title;
-  }
-});
-
+Polymer({is:"cr-toolbar",properties:{pageName:String,searchPrompt:String,clearLabel:String,menuLabel:String,menuPromo:String,spinnerActive:Boolean,showMenu:{type:Boolean,value:false},showMenuPromo:{type:Boolean,value:false},closeMenuPromo:String,narrow_:{type:Boolean,reflectToAttribute:true},showingSearch_:{type:Boolean,reflectToAttribute:true}},observers:["possiblyShowMenuPromo_(showMenu, showMenuPromo, showingSearch_)"],getSearchField:function(){return this.$.search},onClosePromoTap_:function(){this.showMenuPromo=false},onMenuTap_:function(){this.fire("cr-menu-tap");this.onClosePromoTap_()},possiblyShowMenuPromo_:function(){Polymer.RenderStatus.afterNextRender(this,function(){if(this.showMenu&&this.showMenuPromo&&!this.showingSearch_){this.$$("#menuPromo").animate({opacity:[0,.9]},{duration:500,fill:"forwards"});this.fire("cr-menu-promo-shown")}}.bind(this))},titleIfNotShowMenuPromo_:function(title,showMenuPromo){return showMenuPromo?"":title}});
 // 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.
-cr.define('md_history', function() {
-  function BrowserService() {
-    this.pendingDeleteItems_ = null;
-    this.pendingDeletePromise_ = null;
-  }
-  BrowserService.prototype = {
-    deleteItems: function(items) {
-      if (this.pendingDeleteItems_ != null) {
-        return new Promise(function(resolve, reject) {
-          reject(items);
-        });
-      }
-      var removalList = items.map(function(item) {
-        return {
-          url: item.url,
-          timestamps: item.allTimestamps
-        };
-      });
-      this.pendingDeleteItems_ = items;
-      this.pendingDeletePromise_ = new PromiseResolver();
-      chrome.send('removeVisits', removalList);
-      return this.pendingDeletePromise_.promise;
-    },
-    removeBookmark: function(url) {
-      chrome.send('removeBookmark', [ url ]);
-    },
-    openForeignSessionAllTabs: function(sessionTag) {
-      chrome.send('openForeignSession', [ sessionTag ]);
-    },
-    openForeignSessionTab: function(sessionTag, windowId, tabId, e) {
-      chrome.send('openForeignSession', [ sessionTag, String(windowId), String(tabId), e.button || 0, e.altKey, e.ctrlKey, e.metaKey, e.shiftKey ]);
-    },
-    deleteForeignSession: function(sessionTag) {
-      chrome.send('deleteForeignSession', [ sessionTag ]);
-    },
-    openClearBrowsingData: function() {
-      chrome.send('clearBrowsingData');
-    },
-    recordHistogram: function(histogram, value, max) {
-      chrome.send('metricsHandler:recordInHistogram', [ histogram, value, max ]);
-    },
-    recordAction: function(action) {
-      if (action.indexOf('_') == -1) action = 'HistoryPage_' + action;
-      chrome.send('metricsHandler:recordAction', [ action ]);
-    },
-    resolveDelete_: function(successful) {
-      if (this.pendingDeleteItems_ == null || this.pendingDeletePromise_ == null) {
-        return;
-      }
-      if (successful) this.pendingDeletePromise_.resolve(this.pendingDeleteItems_); else this.pendingDeletePromise_.reject(this.pendingDeleteItems_);
-      this.pendingDeleteItems_ = null;
-      this.pendingDeletePromise_ = null;
-    },
-    menuPromoShown: function() {
-      chrome.send('menuPromoShown');
-    }
-  };
-  cr.addSingletonGetter(BrowserService);
-  return {
-    BrowserService: BrowserService
-  };
-});
-
-function deleteComplete() {
-  md_history.BrowserService.getInstance().resolveDelete_(true);
-}
-
-function deleteFailed() {
-  md_history.BrowserService.getInstance().resolveDelete_(false);
-}
-
+cr.define("md_history",function(){function BrowserService(){this.pendingDeleteItems_=null;this.pendingDeletePromise_=null}BrowserService.prototype={deleteItems:function(items){if(this.pendingDeleteItems_!=null){return new Promise(function(resolve,reject){reject(items)})}var removalList=items.map(function(item){return{url:item.url,timestamps:item.allTimestamps}});this.pendingDeleteItems_=items;this.pendingDeletePromise_=new PromiseResolver;chrome.send("removeVisits",removalList);return this.pendingDeletePromise_.promise},removeBookmark:function(url){chrome.send("removeBookmark",[url])},openForeignSessionAllTabs:function(sessionTag){chrome.send("openForeignSession",[sessionTag])},openForeignSessionTab:function(sessionTag,windowId,tabId,e){chrome.send("openForeignSession",[sessionTag,String(windowId),String(tabId),e.button||0,e.altKey,e.ctrlKey,e.metaKey,e.shiftKey])},deleteForeignSession:function(sessionTag){chrome.send("deleteForeignSession",[sessionTag])},openClearBrowsingData:function(){chrome.send("clearBrowsingData")},recordHistogram:function(histogram,value,max){chrome.send("metricsHandler:recordInHistogram",[histogram,value,max])},recordAction:function(action){if(action.indexOf("_")==-1)action="HistoryPage_"+action;chrome.send("metricsHandler:recordAction",[action])},resolveDelete_:function(successful){if(this.pendingDeleteItems_==null||this.pendingDeletePromise_==null){return}if(successful)this.pendingDeletePromise_.resolve(this.pendingDeleteItems_);else this.pendingDeletePromise_.reject(this.pendingDeleteItems_);this.pendingDeleteItems_=null;this.pendingDeletePromise_=null},menuPromoShown:function(){chrome.send("menuPromoShown")}};cr.addSingletonGetter(BrowserService);return{BrowserService:BrowserService}});function deleteComplete(){md_history.BrowserService.getInstance().resolveDelete_(true)}function deleteFailed(){md_history.BrowserService.getInstance().resolveDelete_(false)}
 // 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.
-Polymer({
-  is: 'history-toolbar',
-  properties: {
-    count: {
-      type: Number,
-      value: 0,
-      observer: 'changeToolbarView_'
-    },
-    itemsSelected_: {
-      type: Boolean,
-      value: false,
-      reflectToAttribute: true
-    },
-    searchTerm: {
-      type: String,
-      observer: 'searchTermChanged_',
-      notify: true
-    },
-    spinnerActive: {
-      type: Boolean,
-      value: false
-    },
-    hasDrawer: {
-      type: Boolean,
-      observer: 'hasDrawerChanged_',
-      reflectToAttribute: true
-    },
-    showSyncNotice: Boolean,
-    isGroupedMode: {
-      type: Boolean,
-      reflectToAttribute: true
-    },
-    groupedRange: {
-      type: Number,
-      value: 0,
-      reflectToAttribute: true,
-      notify: true
-    },
-    queryStartTime: String,
-    queryEndTime: String,
-    showMenuPromo_: {
-      type: Boolean,
-      value: function() {
-        return loadTimeData.getBoolean('showMenuPromo');
-      }
-    }
-  },
-  get searchField() {
-    return this.$['main-toolbar'].getSearchField();
-  },
-  showSearchField: function() {
-    this.searchField.showAndFocus();
-  },
-  changeToolbarView_: function() {
-    this.itemsSelected_ = this.count > 0;
-  },
-  searchTermChanged_: function() {
-    if (this.searchField.getValue() != this.searchTerm) {
-      this.searchField.showAndFocus();
-      this.searchField.setValue(this.searchTerm);
-    }
-  },
-  onMenuPromoShown_: function() {
-    md_history.BrowserService.getInstance().menuPromoShown();
-  },
-  onSearchChanged_: function(event) {
-    this.searchTerm = event.detail;
-  },
-  onInfoButtonTap_: function() {
-    var dropdown = this.$.syncNotice.get();
-    dropdown.positionTarget = this.$$('#info-button-icon');
-    if (dropdown.style.display == 'none') dropdown.open();
-  },
-  onClearSelectionTap_: function() {
-    this.fire('unselect-all');
-  },
-  onDeleteTap_: function() {
-    this.fire('delete-selected');
-  },
-  deletingAllowed_: function() {
-    return loadTimeData.getBoolean('allowDeletingHistory');
-  },
-  numberOfItemsSelected_: function(count) {
-    return count > 0 ? loadTimeData.getStringF('itemsSelected', count) : '';
-  },
-  getHistoryInterval_: function(queryStartTime, queryEndTime) {
-    return loadTimeData.getStringF('historyInterval', queryStartTime, queryEndTime);
-  },
-  hasDrawerChanged_: function() {
-    this.updateStyles();
-  }
-});
-
-(function() {
-  var IOS = navigator.userAgent.match(/iP(?:hone|ad;(?: U;)? CPU) OS (\d+)/);
-  var IOS_TOUCH_SCROLLING = IOS && IOS[1] >= 8;
-  var DEFAULT_PHYSICAL_COUNT = 3;
-  var HIDDEN_Y = '-10000px';
-  var DEFAULT_GRID_SIZE = 200;
-  var SECRET_TABINDEX = -100;
-  Polymer({
-    is: 'iron-list',
-    properties: {
-      items: {
-        type: Array
-      },
-      maxPhysicalCount: {
-        type: Number,
-        value: 500
-      },
-      as: {
-        type: String,
-        value: 'item'
-      },
-      indexAs: {
-        type: String,
-        value: 'index'
-      },
-      selectedAs: {
-        type: String,
-        value: 'selected'
-      },
-      grid: {
-        type: Boolean,
-        value: false,
-        reflectToAttribute: true
-      },
-      selectionEnabled: {
-        type: Boolean,
-        value: false
-      },
-      selectedItem: {
-        type: Object,
-        notify: true
-      },
-      selectedItems: {
-        type: Object,
-        notify: true
-      },
-      multiSelection: {
-        type: Boolean,
-        value: false
-      }
-    },
-    observers: [ '_itemsChanged(items.*)', '_selectionEnabledChanged(selectionEnabled)', '_multiSelectionChanged(multiSelection)', '_setOverflow(scrollTarget)' ],
-    behaviors: [ Polymer.Templatizer, Polymer.IronResizableBehavior, Polymer.IronA11yKeysBehavior, Polymer.IronScrollTargetBehavior ],
-    keyBindings: {
-      up: '_didMoveUp',
-      down: '_didMoveDown',
-      enter: '_didEnter'
-    },
-    _ratio: .5,
-    _scrollerPaddingTop: 0,
-    _scrollPosition: 0,
-    _physicalSize: 0,
-    _physicalAverage: 0,
-    _physicalAverageCount: 0,
-    _physicalTop: 0,
-    _virtualCount: 0,
-    _physicalIndexForKey: null,
-    _estScrollHeight: 0,
-    _scrollHeight: 0,
-    _viewportHeight: 0,
-    _viewportWidth: 0,
-    _physicalItems: null,
-    _physicalSizes: null,
-    _firstVisibleIndexVal: null,
-    _lastVisibleIndexVal: null,
-    _collection: null,
-    _maxPages: 3,
-    _focusedItem: null,
-    _focusedIndex: -1,
-    _offscreenFocusedItem: null,
-    _focusBackfillItem: null,
-    _itemsPerRow: 1,
-    _itemWidth: 0,
-    _rowHeight: 0,
-    _templateCost: 0,
-    get _physicalBottom() {
-      return this._physicalTop + this._physicalSize;
-    },
-    get _scrollBottom() {
-      return this._scrollPosition + this._viewportHeight;
-    },
-    get _virtualEnd() {
-      return this._virtualStart + this._physicalCount - 1;
-    },
-    get _hiddenContentSize() {
-      var size = this.grid ? this._physicalRows * this._rowHeight : this._physicalSize;
-      return size - this._viewportHeight;
-    },
-    get _maxScrollTop() {
-      return this._estScrollHeight - this._viewportHeight + this._scrollerPaddingTop;
-    },
-    _minVirtualStart: 0,
-    get _maxVirtualStart() {
-      return Math.max(0, this._virtualCount - this._physicalCount);
-    },
-    _virtualStartVal: 0,
-    set _virtualStart(val) {
-      this._virtualStartVal = Math.min(this._maxVirtualStart, Math.max(this._minVirtualStart, val));
-    },
-    get _virtualStart() {
-      return this._virtualStartVal || 0;
-    },
-    _physicalStartVal: 0,
-    set _physicalStart(val) {
-      this._physicalStartVal = val % this._physicalCount;
-      if (this._physicalStartVal < 0) {
-        this._physicalStartVal = this._physicalCount + this._physicalStartVal;
-      }
-      this._physicalEnd = (this._physicalStart + this._physicalCount - 1) % this._physicalCount;
-    },
-    get _physicalStart() {
-      return this._physicalStartVal || 0;
-    },
-    _physicalCountVal: 0,
-    set _physicalCount(val) {
-      this._physicalCountVal = val;
-      this._physicalEnd = (this._physicalStart + this._physicalCount - 1) % this._physicalCount;
-    },
-    get _physicalCount() {
-      return this._physicalCountVal;
-    },
-    _physicalEnd: 0,
-    get _optPhysicalSize() {
-      if (this.grid) {
-        return this._estRowsInView * this._rowHeight * this._maxPages;
-      }
-      return this._viewportHeight * this._maxPages;
-    },
-    get _optPhysicalCount() {
-      return this._estRowsInView * this._itemsPerRow * this._maxPages;
-    },
-    get _isVisible() {
-      return Boolean(this.offsetWidth || this.offsetHeight);
-    },
-    get firstVisibleIndex() {
-      if (this._firstVisibleIndexVal === null) {
-        var physicalOffset = Math.floor(this._physicalTop + this._scrollerPaddingTop);
-        this._firstVisibleIndexVal = this._iterateItems(function(pidx, vidx) {
-          physicalOffset += this._getPhysicalSizeIncrement(pidx);
-          if (physicalOffset > this._scrollPosition) {
-            return this.grid ? vidx - vidx % this._itemsPerRow : vidx;
-          }
-          if (this.grid && this._virtualCount - 1 === vidx) {
-            return vidx - vidx % this._itemsPerRow;
-          }
-        }) || 0;
-      }
-      return this._firstVisibleIndexVal;
-    },
-    get lastVisibleIndex() {
-      if (this._lastVisibleIndexVal === null) {
-        if (this.grid) {
-          var lastIndex = this.firstVisibleIndex + this._estRowsInView * this._itemsPerRow - 1;
-          this._lastVisibleIndexVal = Math.min(this._virtualCount, lastIndex);
-        } else {
-          var physicalOffset = this._physicalTop;
-          this._iterateItems(function(pidx, vidx) {
-            if (physicalOffset < this._scrollBottom) {
-              this._lastVisibleIndexVal = vidx;
-            } else {
-              return true;
-            }
-            physicalOffset += this._getPhysicalSizeIncrement(pidx);
-          });
-        }
-      }
-      return this._lastVisibleIndexVal;
-    },
-    get _defaultScrollTarget() {
-      return this;
-    },
-    get _virtualRowCount() {
-      return Math.ceil(this._virtualCount / this._itemsPerRow);
-    },
-    get _estRowsInView() {
-      return Math.ceil(this._viewportHeight / this._rowHeight);
-    },
-    get _physicalRows() {
-      return Math.ceil(this._physicalCount / this._itemsPerRow);
-    },
-    ready: function() {
-      this.addEventListener('focus', this._didFocus.bind(this), true);
-    },
-    attached: function() {
-      this.updateViewportBoundaries();
-      if (this._physicalCount === 0) {
-        this._debounceTemplate(this._render);
-      }
-      this.listen(this, 'iron-resize', '_resizeHandler');
-    },
-    detached: function() {
-      this.unlisten(this, 'iron-resize', '_resizeHandler');
-    },
-    _setOverflow: function(scrollTarget) {
-      this.style.webkitOverflowScrolling = scrollTarget === this ? 'touch' : '';
-      this.style.overflow = scrollTarget === this ? 'auto' : '';
-    },
-    updateViewportBoundaries: function() {
-      this._scrollerPaddingTop = this.scrollTarget === this ? 0 : parseInt(window.getComputedStyle(this)['padding-top'], 10);
-      this._viewportHeight = this._scrollTargetHeight;
-      if (this.grid) {
-        this._updateGridMetrics();
-      }
-    },
-    _scrollHandler: function() {
-      var scrollTop = Math.max(0, Math.min(this._maxScrollTop, this._scrollTop));
-      var delta = scrollTop - this._scrollPosition;
-      var tileHeight, tileTop, kth, recycledTileSet, scrollBottom, physicalBottom;
-      var ratio = this._ratio;
-      var recycledTiles = 0;
-      var hiddenContentSize = this._hiddenContentSize;
-      var currentRatio = ratio;
-      var movingUp = [];
-      this._scrollPosition = scrollTop;
-      this._firstVisibleIndexVal = null;
-      this._lastVisibleIndexVal = null;
-      scrollBottom = this._scrollBottom;
-      physicalBottom = this._physicalBottom;
-      if (Math.abs(delta) > this._physicalSize) {
-        this._physicalTop += delta;
-        recycledTiles = Math.round(delta / this._physicalAverage);
-      } else if (delta < 0) {
-        var topSpace = scrollTop - this._physicalTop;
-        var virtualStart = this._virtualStart;
-        recycledTileSet = [];
-        kth = this._physicalEnd;
-        currentRatio = topSpace / hiddenContentSize;
-        while (currentRatio < ratio && recycledTiles < this._physicalCount && virtualStart - recycledTiles > 0 && physicalBottom - this._getPhysicalSizeIncrement(kth) > scrollBottom) {
-          tileHeight = this._getPhysicalSizeIncrement(kth);
-          currentRatio += tileHeight / hiddenContentSize;
-          physicalBottom -= tileHeight;
-          recycledTileSet.push(kth);
-          recycledTiles++;
-          kth = kth === 0 ? this._physicalCount - 1 : kth - 1;
-        }
-        movingUp = recycledTileSet;
-        recycledTiles = -recycledTiles;
-      } else if (delta > 0) {
-        var bottomSpace = physicalBottom - scrollBottom;
-        var virtualEnd = this._virtualEnd;
-        var lastVirtualItemIndex = this._virtualCount - 1;
-        recycledTileSet = [];
-        kth = this._physicalStart;
-        currentRatio = bottomSpace / hiddenContentSize;
-        while (currentRatio < ratio && recycledTiles < this._physicalCount && virtualEnd + recycledTiles < lastVirtualItemIndex && this._physicalTop + this._getPhysicalSizeIncrement(kth) < scrollTop) {
-          tileHeight = this._getPhysicalSizeIncrement(kth);
-          currentRatio += tileHeight / hiddenContentSize;
-          this._physicalTop += tileHeight;
-          recycledTileSet.push(kth);
-          recycledTiles++;
-          kth = (kth + 1) % this._physicalCount;
-        }
-      }
-      if (recycledTiles === 0) {
-        if (physicalBottom < scrollBottom || this._physicalTop > scrollTop) {
-          this._increasePoolIfNeeded();
-        }
-      } else {
-        this._virtualStart = this._virtualStart + recycledTiles;
-        this._physicalStart = this._physicalStart + recycledTiles;
-        this._update(recycledTileSet, movingUp);
-      }
-    },
-    _update: function(itemSet, movingUp) {
-      this._manageFocus();
-      this._assignModels(itemSet);
-      this._updateMetrics(itemSet);
-      if (movingUp) {
-        while (movingUp.length) {
-          var idx = movingUp.pop();
-          this._physicalTop -= this._getPhysicalSizeIncrement(idx);
-        }
-      }
-      this._positionItems();
-      this._updateScrollerSize();
-      this._increasePoolIfNeeded();
-    },
-    _createPool: function(size) {
-      var physicalItems = new Array(size);
-      this._ensureTemplatized();
-      for (var i = 0; i < size; i++) {
-        var inst = this.stamp(null);
-        physicalItems[i] = inst.root.querySelector('*');
-        Polymer.dom(this).appendChild(inst.root);
-      }
-      return physicalItems;
-    },
-    _increasePoolIfNeeded: function() {
-      if (this._viewportHeight === 0) {
-        return false;
-      }
-      var self = this;
-      var isClientFull = this._physicalBottom >= this._scrollBottom && this._physicalTop <= this._scrollPosition;
-      if (this._physicalSize >= this._optPhysicalSize && isClientFull) {
-        return false;
-      }
-      var maxPoolSize = Math.round(this._physicalCount * .5);
-      if (!isClientFull) {
-        this._debounceTemplate(this._increasePool.bind(this, maxPoolSize));
-        return true;
-      }
-      this._yield(function() {
-        self._increasePool(Math.min(maxPoolSize, Math.max(1, Math.round(50 / self._templateCost))));
-      });
-      return true;
-    },
-    _yield: function(cb) {
-      var g = window;
-      var handle = g.requestIdleCallback ? g.requestIdleCallback(cb) : g.setTimeout(cb, 16);
-      Polymer.dom.addDebouncer({
-        complete: function() {
-          g.cancelIdleCallback ? g.cancelIdleCallback(handle) : g.clearTimeout(handle);
-          cb();
-        }
-      });
-    },
-    _increasePool: function(missingItems) {
-      var nextPhysicalCount = Math.min(this._physicalCount + missingItems, this._virtualCount - this._virtualStart, Math.max(this.maxPhysicalCount, DEFAULT_PHYSICAL_COUNT));
-      var prevPhysicalCount = this._physicalCount;
-      var delta = nextPhysicalCount - prevPhysicalCount;
-      var ts = window.performance.now();
-      if (delta <= 0) {
-        return;
-      }
-      [].push.apply(this._physicalItems, this._createPool(delta));
-      [].push.apply(this._physicalSizes, new Array(delta));
-      this._physicalCount = prevPhysicalCount + delta;
-      if (this._physicalStart > this._physicalEnd && this._isIndexRendered(this._focusedIndex) && this._getPhysicalIndex(this._focusedIndex) < this._physicalEnd) {
-        this._physicalStart = this._physicalStart + delta;
-      }
-      this._update();
-      this._templateCost = (window.performance.now() - ts) / delta;
-    },
-    _render: function() {
-      if (this.isAttached && this._isVisible) {
-        if (this._physicalCount === 0) {
-          this._increasePool(DEFAULT_PHYSICAL_COUNT);
-        } else {
-          this._update();
-        }
-      }
-    },
-    _ensureTemplatized: function() {
-      if (!this.ctor) {
-        var props = {};
-        props.__key__ = true;
-        props[this.as] = true;
-        props[this.indexAs] = true;
-        props[this.selectedAs] = true;
-        props.tabIndex = true;
-        this._instanceProps = props;
-        this._userTemplate = Polymer.dom(this).querySelector('template');
-        if (this._userTemplate) {
-          this.templatize(this._userTemplate);
-        } else {
-          console.warn('iron-list requires a template to be provided in light-dom');
-        }
-      }
-    },
-    _getStampedChildren: function() {
-      return this._physicalItems;
-    },
-    _forwardInstancePath: function(inst, path, value) {
-      if (path.indexOf(this.as + '.') === 0) {
-        this.notifyPath('items.' + inst.__key__ + '.' + path.slice(this.as.length + 1), value);
-      }
-    },
-    _forwardParentProp: function(prop, value) {
-      if (this._physicalItems) {
-        this._physicalItems.forEach(function(item) {
-          item._templateInstance[prop] = value;
-        }, this);
-      }
-    },
-    _forwardParentPath: function(path, value) {
-      if (this._physicalItems) {
-        this._physicalItems.forEach(function(item) {
-          item._templateInstance.notifyPath(path, value, true);
-        }, this);
-      }
-    },
-    _forwardItemPath: function(path, value) {
-      if (!this._physicalIndexForKey) {
-        return;
-      }
-      var dot = path.indexOf('.');
-      var key = path.substring(0, dot < 0 ? path.length : dot);
-      var idx = this._physicalIndexForKey[key];
-      var offscreenItem = this._offscreenFocusedItem;
-      var el = offscreenItem && offscreenItem._templateInstance.__key__ === key ? offscreenItem : this._physicalItems[idx];
-      if (!el || el._templateInstance.__key__ !== key) {
-        return;
-      }
-      if (dot >= 0) {
-        path = this.as + '.' + path.substring(dot + 1);
-        el._templateInstance.notifyPath(path, value, true);
-      } else {
-        var currentItem = el._templateInstance[this.as];
-        if (Array.isArray(this.selectedItems)) {
-          for (var i = 0; i < this.selectedItems.length; i++) {
-            if (this.selectedItems[i] === currentItem) {
-              this.set('selectedItems.' + i, value);
-              break;
-            }
-          }
-        } else if (this.selectedItem === currentItem) {
-          this.set('selectedItem', value);
-        }
-        el._templateInstance[this.as] = value;
-      }
-    },
-    _itemsChanged: function(change) {
-      if (change.path === 'items') {
-        this._virtualStart = 0;
-        this._physicalTop = 0;
-        this._virtualCount = this.items ? this.items.length : 0;
-        this._collection = this.items ? Polymer.Collection.get(this.items) : null;
-        this._physicalIndexForKey = {};
-        this._firstVisibleIndexVal = null;
-        this._lastVisibleIndexVal = null;
-        this._physicalCount = this._physicalCount || 0;
-        this._physicalItems = this._physicalItems || [];
-        this._physicalSizes = this._physicalSizes || [];
-        this._physicalStart = 0;
-        this._resetScrollPosition(0);
-        this._removeFocusedItem();
-        this._debounceTemplate(this._render);
-      } else if (change.path === 'items.splices') {
-        this._adjustVirtualIndex(change.value.indexSplices);
-        this._virtualCount = this.items ? this.items.length : 0;
-        this._debounceTemplate(this._render);
-      } else {
-        this._forwardItemPath(change.path.split('.').slice(1).join('.'), change.value);
-      }
-    },
-    _adjustVirtualIndex: function(splices) {
-      splices.forEach(function(splice) {
-        splice.removed.forEach(this._removeItem, this);
-        if (splice.index < this._virtualStart) {
-          var delta = Math.max(splice.addedCount - splice.removed.length, splice.index - this._virtualStart);
-          this._virtualStart = this._virtualStart + delta;
-          if (this._focusedIndex >= 0) {
-            this._focusedIndex = this._focusedIndex + delta;
-          }
-        }
-      }, this);
-    },
-    _removeItem: function(item) {
-      this.$.selector.deselect(item);
-      if (this._focusedItem && this._focusedItem._templateInstance[this.as] === item) {
-        this._removeFocusedItem();
-      }
-    },
-    _iterateItems: function(fn, itemSet) {
-      var pidx, vidx, rtn, i;
-      if (arguments.length === 2 && itemSet) {
-        for (i = 0; i < itemSet.length; i++) {
-          pidx = itemSet[i];
-          vidx = this._computeVidx(pidx);
-          if ((rtn = fn.call(this, pidx, vidx)) != null) {
-            return rtn;
-          }
-        }
-      } else {
-        pidx = this._physicalStart;
-        vidx = this._virtualStart;
-        for (;pidx < this._physicalCount; pidx++, vidx++) {
-          if ((rtn = fn.call(this, pidx, vidx)) != null) {
-            return rtn;
-          }
-        }
-        for (pidx = 0; pidx < this._physicalStart; pidx++, vidx++) {
-          if ((rtn = fn.call(this, pidx, vidx)) != null) {
-            return rtn;
-          }
-        }
-      }
-    },
-    _computeVidx: function(pidx) {
-      if (pidx >= this._physicalStart) {
-        return this._virtualStart + (pidx - this._physicalStart);
-      }
-      return this._virtualStart + (this._physicalCount - this._physicalStart) + pidx;
-    },
-    _assignModels: function(itemSet) {
-      this._iterateItems(function(pidx, vidx) {
-        var el = this._physicalItems[pidx];
-        var inst = el._templateInstance;
-        var item = this.items && this.items[vidx];
-        if (item != null) {
-          inst[this.as] = item;
-          inst.__key__ = this._collection.getKey(item);
-          inst[this.selectedAs] = this.$.selector.isSelected(item);
-          inst[this.indexAs] = vidx;
-          inst.tabIndex = this._focusedIndex === vidx ? 0 : -1;
-          this._physicalIndexForKey[inst.__key__] = pidx;
-          el.removeAttribute('hidden');
-        } else {
-          inst.__key__ = null;
-          el.setAttribute('hidden', '');
-        }
-      }, itemSet);
-    },
-    _updateMetrics: function(itemSet) {
-      Polymer.dom.flush();
-      var newPhysicalSize = 0;
-      var oldPhysicalSize = 0;
-      var prevAvgCount = this._physicalAverageCount;
-      var prevPhysicalAvg = this._physicalAverage;
-      this._iterateItems(function(pidx, vidx) {
-        oldPhysicalSize += this._physicalSizes[pidx] || 0;
-        this._physicalSizes[pidx] = this._physicalItems[pidx].offsetHeight;
-        newPhysicalSize += this._physicalSizes[pidx];
-        this._physicalAverageCount += this._physicalSizes[pidx] ? 1 : 0;
-      }, itemSet);
-      this._viewportHeight = this._scrollTargetHeight;
-      if (this.grid) {
-        this._updateGridMetrics();
-        this._physicalSize = Math.ceil(this._physicalCount / this._itemsPerRow) * this._rowHeight;
-      } else {
-        this._physicalSize = this._physicalSize + newPhysicalSize - oldPhysicalSize;
-      }
-      if (this._physicalAverageCount !== prevAvgCount) {
-        this._physicalAverage = Math.round((prevPhysicalAvg * prevAvgCount + newPhysicalSize) / this._physicalAverageCount);
-      }
-    },
-    _updateGridMetrics: function() {
-      this._viewportWidth = this.$.items.offsetWidth;
-      this._itemWidth = this._physicalCount > 0 ? this._physicalItems[0].getBoundingClientRect().width : DEFAULT_GRID_SIZE;
-      this._rowHeight = this._physicalCount > 0 ? this._physicalItems[0].offsetHeight : DEFAULT_GRID_SIZE;
-      this._itemsPerRow = this._itemWidth ? Math.floor(this._viewportWidth / this._itemWidth) : this._itemsPerRow;
-    },
-    _positionItems: function() {
-      this._adjustScrollPosition();
-      var y = this._physicalTop;
-      if (this.grid) {
-        var totalItemWidth = this._itemsPerRow * this._itemWidth;
-        var rowOffset = (this._viewportWidth - totalItemWidth) / 2;
-        this._iterateItems(function(pidx, vidx) {
-          var modulus = vidx % this._itemsPerRow;
-          var x = Math.floor(modulus * this._itemWidth + rowOffset);
-          this.translate3d(x + 'px', y + 'px', 0, this._physicalItems[pidx]);
-          if (this._shouldRenderNextRow(vidx)) {
-            y += this._rowHeight;
-          }
-        });
-      } else {
-        this._iterateItems(function(pidx, vidx) {
-          this.translate3d(0, y + 'px', 0, this._physicalItems[pidx]);
-          y += this._physicalSizes[pidx];
-        });
-      }
-    },
-    _getPhysicalSizeIncrement: function(pidx) {
-      if (!this.grid) {
-        return this._physicalSizes[pidx];
-      }
-      if (this._computeVidx(pidx) % this._itemsPerRow !== this._itemsPerRow - 1) {
-        return 0;
-      }
-      return this._rowHeight;
-    },
-    _shouldRenderNextRow: function(vidx) {
-      return vidx % this._itemsPerRow === this._itemsPerRow - 1;
-    },
-    _adjustScrollPosition: function() {
-      var deltaHeight = this._virtualStart === 0 ? this._physicalTop : Math.min(this._scrollPosition + this._physicalTop, 0);
-      if (deltaHeight) {
-        this._physicalTop = this._physicalTop - deltaHeight;
-        if (!IOS_TOUCH_SCROLLING && this._physicalTop !== 0) {
-          this._resetScrollPosition(this._scrollTop - deltaHeight);
-        }
-      }
-    },
-    _resetScrollPosition: function(pos) {
-      if (this.scrollTarget) {
-        this._scrollTop = pos;
-        this._scrollPosition = this._scrollTop;
-      }
-    },
-    _updateScrollerSize: function(forceUpdate) {
-      if (this.grid) {
-        this._estScrollHeight = this._virtualRowCount * this._rowHeight;
-      } else {
-        this._estScrollHeight = this._physicalBottom + Math.max(this._virtualCount - this._physicalCount - this._virtualStart, 0) * this._physicalAverage;
-      }
-      forceUpdate = forceUpdate || this._scrollHeight === 0;
-      forceUpdate = forceUpdate || this._scrollPosition >= this._estScrollHeight - this._physicalSize;
-      forceUpdate = forceUpdate || this.grid && this.$.items.style.height < this._estScrollHeight;
-      if (forceUpdate || Math.abs(this._estScrollHeight - this._scrollHeight) >= this._optPhysicalSize) {
-        this.$.items.style.height = this._estScrollHeight + 'px';
-        this._scrollHeight = this._estScrollHeight;
-      }
-    },
-    scrollToItem: function(item) {
-      return this.scrollToIndex(this.items.indexOf(item));
-    },
-    scrollToIndex: function(idx) {
-      if (typeof idx !== 'number' || idx < 0 || idx > this.items.length - 1) {
-        return;
-      }
-      Polymer.dom.flush();
-      if (this._physicalCount === 0) {
-        return;
-      }
-      idx = Math.min(Math.max(idx, 0), this._virtualCount - 1);
-      if (!this._isIndexRendered(idx) || idx >= this._maxVirtualStart) {
-        this._virtualStart = this.grid ? idx - this._itemsPerRow * 2 : idx - 1;
-      }
-      this._manageFocus();
-      this._assignModels();
-      this._updateMetrics();
-      this._physicalTop = Math.floor(this._virtualStart / this._itemsPerRow) * this._physicalAverage;
-      var currentTopItem = this._physicalStart;
-      var currentVirtualItem = this._virtualStart;
-      var targetOffsetTop = 0;
-      var hiddenContentSize = this._hiddenContentSize;
-      while (currentVirtualItem < idx && targetOffsetTop <= hiddenContentSize) {
-        targetOffsetTop = targetOffsetTop + this._getPhysicalSizeIncrement(currentTopItem);
-        currentTopItem = (currentTopItem + 1) % this._physicalCount;
-        currentVirtualItem++;
-      }
-      this._updateScrollerSize(true);
-      this._positionItems();
-      this._resetScrollPosition(this._physicalTop + this._scrollerPaddingTop + targetOffsetTop);
-      this._increasePoolIfNeeded();
-      this._firstVisibleIndexVal = null;
-      this._lastVisibleIndexVal = null;
-    },
-    _resetAverage: function() {
-      this._physicalAverage = 0;
-      this._physicalAverageCount = 0;
-    },
-    _resizeHandler: function() {
-      if (IOS && Math.abs(this._viewportHeight - this._scrollTargetHeight) < 100) {
-        return;
-      }
-      Polymer.dom.addDebouncer(this.debounce('_debounceTemplate', function() {
-        this.updateViewportBoundaries();
-        this._render();
-        if (this._physicalCount > 0 && this._isVisible) {
-          this._resetAverage();
-          this.scrollToIndex(this.firstVisibleIndex);
-        }
-      }.bind(this), 1));
-    },
-    _getModelFromItem: function(item) {
-      var key = this._collection.getKey(item);
-      var pidx = this._physicalIndexForKey[key];
-      if (pidx != null) {
-        return this._physicalItems[pidx]._templateInstance;
-      }
-      return null;
-    },
-    _getNormalizedItem: function(item) {
-      if (this._collection.getKey(item) === undefined) {
-        if (typeof item === 'number') {
-          item = this.items[item];
-          if (!item) {
-            throw new RangeError('<item> not found');
-          }
-          return item;
-        }
-        throw new TypeError('<item> should be a valid item');
-      }
-      return item;
-    },
-    selectItem: function(item) {
-      item = this._getNormalizedItem(item);
-      var model = this._getModelFromItem(item);
-      if (!this.multiSelection && this.selectedItem) {
-        this.deselectItem(this.selectedItem);
-      }
-      if (model) {
-        model[this.selectedAs] = true;
-      }
-      this.$.selector.select(item);
-      this.updateSizeForItem(item);
-    },
-    deselectItem: function(item) {
-      item = this._getNormalizedItem(item);
-      var model = this._getModelFromItem(item);
-      if (model) {
-        model[this.selectedAs] = false;
-      }
-      this.$.selector.deselect(item);
-      this.updateSizeForItem(item);
-    },
-    toggleSelectionForItem: function(item) {
-      item = this._getNormalizedItem(item);
-      if (this.$.selector.isSelected(item)) {
-        this.deselectItem(item);
-      } else {
-        this.selectItem(item);
-      }
-    },
-    clearSelection: function() {
-      function unselect(item) {
-        var model = this._getModelFromItem(item);
-        if (model) {
-          model[this.selectedAs] = false;
-        }
-      }
-      if (Array.isArray(this.selectedItems)) {
-        this.selectedItems.forEach(unselect, this);
-      } else if (this.selectedItem) {
-        unselect.call(this, this.selectedItem);
-      }
-      this.$.selector.clearSelection();
-    },
-    _selectionEnabledChanged: function(selectionEnabled) {
-      var handler = selectionEnabled ? this.listen : this.unlisten;
-      handler.call(this, this, 'tap', '_selectionHandler');
-    },
-    _selectionHandler: function(e) {
-      var model = this.modelForElement(e.target);
-      if (!model) {
-        return;
-      }
-      var modelTabIndex, activeElTabIndex;
-      var target = Polymer.dom(e).path[0];
-      var activeEl = Polymer.dom(this.domHost ? this.domHost.root : document).activeElement;
-      var physicalItem = this._physicalItems[this._getPhysicalIndex(model[this.indexAs])];
-      if (target.localName === 'input' || target.localName === 'button' || target.localName === 'select') {
-        return;
-      }
-      modelTabIndex = model.tabIndex;
-      model.tabIndex = SECRET_TABINDEX;
-      activeElTabIndex = activeEl ? activeEl.tabIndex : -1;
-      model.tabIndex = modelTabIndex;
-      if (activeEl && physicalItem !== activeEl && physicalItem.contains(activeEl) && activeElTabIndex !== SECRET_TABINDEX) {
-        return;
-      }
-      this.toggleSelectionForItem(model[this.as]);
-    },
-    _multiSelectionChanged: function(multiSelection) {
-      this.clearSelection();
-      this.$.selector.multi = multiSelection;
-    },
-    updateSizeForItem: function(item) {
-      item = this._getNormalizedItem(item);
-      var key = this._collection.getKey(item);
-      var pidx = this._physicalIndexForKey[key];
-      if (pidx != null) {
-        this._updateMetrics([ pidx ]);
-        this._positionItems();
-      }
-    },
-    _manageFocus: function() {
-      var fidx = this._focusedIndex;
-      if (fidx >= 0 && fidx < this._virtualCount) {
-        if (this._isIndexRendered(fidx)) {
-          this._restoreFocusedItem();
-        } else {
-          this._createFocusBackfillItem();
-        }
-      } else if (this._virtualCount > 0 && this._physicalCount > 0) {
-        this._focusedIndex = this._virtualStart;
-        this._focusedItem = this._physicalItems[this._physicalStart];
-      }
-    },
-    _isIndexRendered: function(idx) {
-      return idx >= this._virtualStart && idx <= this._virtualEnd;
-    },
-    _isIndexVisible: function(idx) {
-      return idx >= this.firstVisibleIndex && idx <= this.lastVisibleIndex;
-    },
-    _getPhysicalIndex: function(idx) {
-      return this._physicalIndexForKey[this._collection.getKey(this._getNormalizedItem(idx))];
-    },
-    _focusPhysicalItem: function(idx) {
-      if (idx < 0 || idx >= this._virtualCount) {
-        return;
-      }
-      this._restoreFocusedItem();
-      if (!this._isIndexRendered(idx)) {
-        this.scrollToIndex(idx);
-      }
-      var physicalItem = this._physicalItems[this._getPhysicalIndex(idx)];
-      var model = physicalItem._templateInstance;
-      var focusable;
-      model.tabIndex = SECRET_TABINDEX;
-      if (physicalItem.tabIndex === SECRET_TABINDEX) {
-        focusable = physicalItem;
-      }
-      if (!focusable) {
-        focusable = Polymer.dom(physicalItem).querySelector('[tabindex="' + SECRET_TABINDEX + '"]');
-      }
-      model.tabIndex = 0;
-      this._focusedIndex = idx;
-      focusable && focusable.focus();
-    },
-    _removeFocusedItem: function() {
-      if (this._offscreenFocusedItem) {
-        Polymer.dom(this).removeChild(this._offscreenFocusedItem);
-      }
-      this._offscreenFocusedItem = null;
-      this._focusBackfillItem = null;
-      this._focusedItem = null;
-      this._focusedIndex = -1;
-    },
-    _createFocusBackfillItem: function() {
-      var pidx, fidx = this._focusedIndex;
-      if (this._offscreenFocusedItem || fidx < 0) {
-        return;
-      }
-      if (!this._focusBackfillItem) {
-        var stampedTemplate = this.stamp(null);
-        this._focusBackfillItem = stampedTemplate.root.querySelector('*');
-        Polymer.dom(this).appendChild(stampedTemplate.root);
-      }
-      pidx = this._getPhysicalIndex(fidx);
-      if (pidx != null) {
-        this._offscreenFocusedItem = this._physicalItems[pidx];
-        this._physicalItems[pidx] = this._focusBackfillItem;
-        this.translate3d(0, HIDDEN_Y, 0, this._offscreenFocusedItem);
-      }
-    },
-    _restoreFocusedItem: function() {
-      var pidx, fidx = this._focusedIndex;
-      if (!this._offscreenFocusedItem || this._focusedIndex < 0) {
-        return;
-      }
-      this._assignModels();
-      pidx = this._getPhysicalIndex(fidx);
-      if (pidx != null) {
-        this._focusBackfillItem = this._physicalItems[pidx];
-        this._physicalItems[pidx] = this._offscreenFocusedItem;
-        this._offscreenFocusedItem = null;
-        this.translate3d(0, HIDDEN_Y, 0, this._focusBackfillItem);
-      }
-    },
-    _didFocus: function(e) {
-      var targetModel = this.modelForElement(e.target);
-      var focusedModel = this._focusedItem ? this._focusedItem._templateInstance : null;
-      var hasOffscreenFocusedItem = this._offscreenFocusedItem !== null;
-      var fidx = this._focusedIndex;
-      if (!targetModel || !focusedModel) {
-        return;
-      }
-      if (focusedModel === targetModel) {
-        if (!this._isIndexVisible(fidx)) {
-          this.scrollToIndex(fidx);
-        }
-      } else {
-        this._restoreFocusedItem();
-        focusedModel.tabIndex = -1;
-        targetModel.tabIndex = 0;
-        fidx = targetModel[this.indexAs];
-        this._focusedIndex = fidx;
-        this._focusedItem = this._physicalItems[this._getPhysicalIndex(fidx)];
-        if (hasOffscreenFocusedItem && !this._offscreenFocusedItem) {
-          this._update();
-        }
-      }
-    },
-    _didMoveUp: function() {
-      this._focusPhysicalItem(this._focusedIndex - 1);
-    },
-    _didMoveDown: function(e) {
-      e.detail.keyboardEvent.preventDefault();
-      this._focusPhysicalItem(this._focusedIndex + 1);
-    },
-    _didEnter: function(e) {
-      this._focusPhysicalItem(this._focusedIndex);
-      this._selectionHandler(e.detail.keyboardEvent);
-    }
-  });
-})();
-
-Polymer({
-  is: 'iron-scroll-threshold',
-  properties: {
-    upperThreshold: {
-      type: Number,
-      value: 100
-    },
-    lowerThreshold: {
-      type: Number,
-      value: 100
-    },
-    upperTriggered: {
-      type: Boolean,
-      value: false,
-      notify: true,
-      readOnly: true
-    },
-    lowerTriggered: {
-      type: Boolean,
-      value: false,
-      notify: true,
-      readOnly: true
-    },
-    horizontal: {
-      type: Boolean,
-      value: false
-    }
-  },
-  behaviors: [ Polymer.IronScrollTargetBehavior ],
-  observers: [ '_setOverflow(scrollTarget)', '_initCheck(horizontal, isAttached)' ],
-  get _defaultScrollTarget() {
-    return this;
-  },
-  _setOverflow: function(scrollTarget) {
-    this.style.overflow = scrollTarget === this ? 'auto' : '';
-  },
-  _scrollHandler: function() {
-    var THROTTLE_THRESHOLD = 200;
-    if (!this.isDebouncerActive('_checkTheshold')) {
-      this.debounce('_checkTheshold', function() {
-        this.checkScrollThesholds();
-      }, THROTTLE_THRESHOLD);
-    }
-  },
-  _initCheck: function(horizontal, isAttached) {
-    if (isAttached) {
-      this.debounce('_init', function() {
-        this.clearTriggers();
-        this.checkScrollThesholds();
-      });
-    }
-  },
-  checkScrollThesholds: function() {
-    if (!this.scrollTarget || this.lowerTriggered && this.upperTriggered) {
-      return;
-    }
-    var upperScrollValue = this.horizontal ? this._scrollLeft : this._scrollTop;
-    var lowerScrollValue = this.horizontal ? this.scrollTarget.scrollWidth - this._scrollTargetWidth - this._scrollLeft : this.scrollTarget.scrollHeight - this._scrollTargetHeight - this._scrollTop;
-    if (upperScrollValue <= this.upperThreshold && !this.upperTriggered) {
-      this._setUpperTriggered(true);
-      this.fire('upper-threshold');
-    }
-    if (lowerScrollValue <= this.lowerThreshold && !this.lowerTriggered) {
-      this._setLowerTriggered(true);
-      this.fire('lower-threshold');
-    }
-  },
-  clearTriggers: function() {
-    this._setUpperTriggered(false);
-    this._setLowerTriggered(false);
-  }
-});
-
+Polymer({is:"history-toolbar",properties:{count:{type:Number,value:0,observer:"changeToolbarView_"},itemsSelected_:{type:Boolean,value:false,reflectToAttribute:true},searchTerm:{type:String,observer:"searchTermChanged_",notify:true},spinnerActive:{type:Boolean,value:false},hasDrawer:{type:Boolean,observer:"hasDrawerChanged_",reflectToAttribute:true},showSyncNotice:Boolean,isGroupedMode:{type:Boolean,reflectToAttribute:true},groupedRange:{type:Number,value:0,reflectToAttribute:true,notify:true},queryStartTime:String,queryEndTime:String,showMenuPromo_:{type:Boolean,value:function(){return loadTimeData.getBoolean("showMenuPromo")}}},get searchField(){return this.$["main-toolbar"].getSearchField()},showSearchField:function(){this.searchField.showAndFocus()},changeToolbarView_:function(){this.itemsSelected_=this.count>0},searchTermChanged_:function(){if(this.searchField.getValue()!=this.searchTerm){this.searchField.showAndFocus();this.searchField.setValue(this.searchTerm)}},onMenuPromoShown_:function(){md_history.BrowserService.getInstance().menuPromoShown()},onSearchChanged_:function(event){this.searchTerm=event.detail},onInfoButtonTap_:function(){var dropdown=this.$.syncNotice.get();dropdown.positionTarget=this.$$("#info-button-icon");if(dropdown.style.display=="none")dropdown.open()},onClearSelectionTap_:function(){this.fire("unselect-all")},onDeleteTap_:function(){this.fire("delete-selected")},deletingAllowed_:function(){return loadTimeData.getBoolean("allowDeletingHistory")},numberOfItemsSelected_:function(count){return count>0?loadTimeData.getStringF("itemsSelected",count):""},getHistoryInterval_:function(queryStartTime,queryEndTime){return loadTimeData.getStringF("historyInterval",queryStartTime,queryEndTime)},hasDrawerChanged_:function(){this.updateStyles()}});(function(){var IOS=navigator.userAgent.match(/iP(?:hone|ad;(?: U;)? CPU) OS (\d+)/);var IOS_TOUCH_SCROLLING=IOS&&IOS[1]>=8;var DEFAULT_PHYSICAL_COUNT=3;var HIDDEN_Y="-10000px";var DEFAULT_GRID_SIZE=200;var SECRET_TABINDEX=-100;Polymer({is:"iron-list",properties:{items:{type:Array},maxPhysicalCount:{type:Number,value:500},as:{type:String,value:"item"},indexAs:{type:String,value:"index"},selectedAs:{type:String,value:"selected"},grid:{type:Boolean,value:false,reflectToAttribute:true},selectionEnabled:{type:Boolean,value:false},selectedItem:{type:Object,notify:true},selectedItems:{type:Object,notify:true},multiSelection:{type:Boolean,value:false}},observers:["_itemsChanged(items.*)","_selectionEnabledChanged(selectionEnabled)","_multiSelectionChanged(multiSelection)","_setOverflow(scrollTarget)"],behaviors:[Polymer.Templatizer,Polymer.IronResizableBehavior,Polymer.IronA11yKeysBehavior,Polymer.IronScrollTargetBehavior],keyBindings:{up:"_didMoveUp",down:"_didMoveDown",enter:"_didEnter"},_ratio:.5,_scrollerPaddingTop:0,_scrollPosition:0,_physicalSize:0,_physicalAverage:0,_physicalAverageCount:0,_physicalTop:0,_virtualCount:0,_physicalIndexForKey:null,_estScrollHeight:0,_scrollHeight:0,_viewportHeight:0,_viewportWidth:0,_physicalItems:null,_physicalSizes:null,_firstVisibleIndexVal:null,_lastVisibleIndexVal:null,_collection:null,_maxPages:3,_focusedItem:null,_focusedIndex:-1,_offscreenFocusedItem:null,_focusBackfillItem:null,_itemsPerRow:1,_itemWidth:0,_rowHeight:0,_templateCost:0,get _physicalBottom(){return this._physicalTop+this._physicalSize},get _scrollBottom(){return this._scrollPosition+this._viewportHeight},get _virtualEnd(){return this._virtualStart+this._physicalCount-1},get _hiddenContentSize(){var size=this.grid?this._physicalRows*this._rowHeight:this._physicalSize;return size-this._viewportHeight},get _maxScrollTop(){return this._estScrollHeight-this._viewportHeight+this._scrollerPaddingTop},_minVirtualStart:0,get _maxVirtualStart(){return Math.max(0,this._virtualCount-this._physicalCount)},_virtualStartVal:0,set _virtualStart(val){this._virtualStartVal=Math.min(this._maxVirtualStart,Math.max(this._minVirtualStart,val))},get _virtualStart(){return this._virtualStartVal||0},_physicalStartVal:0,set _physicalStart(val){this._physicalStartVal=val%this._physicalCount;if(this._physicalStartVal<0){this._physicalStartVal=this._physicalCount+this._physicalStartVal}this._physicalEnd=(this._physicalStart+this._physicalCount-1)%this._physicalCount},get _physicalStart(){return this._physicalStartVal||0},_physicalCountVal:0,set _physicalCount(val){this._physicalCountVal=val;this._physicalEnd=(this._physicalStart+this._physicalCount-1)%this._physicalCount},get _physicalCount(){return this._physicalCountVal},_physicalEnd:0,get _optPhysicalSize(){if(this.grid){return this._estRowsInView*this._rowHeight*this._maxPages}return this._viewportHeight*this._maxPages},get _optPhysicalCount(){return this._estRowsInView*this._itemsPerRow*this._maxPages},get _isVisible(){return Boolean(this.offsetWidth||this.offsetHeight)},get firstVisibleIndex(){if(this._firstVisibleIndexVal===null){var physicalOffset=Math.floor(this._physicalTop+this._scrollerPaddingTop);this._firstVisibleIndexVal=this._iterateItems(function(pidx,vidx){physicalOffset+=this._getPhysicalSizeIncrement(pidx);if(physicalOffset>this._scrollPosition){return this.grid?vidx-vidx%this._itemsPerRow:vidx}if(this.grid&&this._virtualCount-1===vidx){return vidx-vidx%this._itemsPerRow}})||0}return this._firstVisibleIndexVal},get lastVisibleIndex(){if(this._lastVisibleIndexVal===null){if(this.grid){var lastIndex=this.firstVisibleIndex+this._estRowsInView*this._itemsPerRow-1;this._lastVisibleIndexVal=Math.min(this._virtualCount,lastIndex)}else{var physicalOffset=this._physicalTop;this._iterateItems(function(pidx,vidx){if(physicalOffset<this._scrollBottom){this._lastVisibleIndexVal=vidx}else{return true}physicalOffset+=this._getPhysicalSizeIncrement(pidx)})}}return this._lastVisibleIndexVal},get _defaultScrollTarget(){return this},get _virtualRowCount(){return Math.ceil(this._virtualCount/this._itemsPerRow)},get _estRowsInView(){return Math.ceil(this._viewportHeight/this._rowHeight)},get _physicalRows(){return Math.ceil(this._physicalCount/this._itemsPerRow)},ready:function(){this.addEventListener("focus",this._didFocus.bind(this),true)},attached:function(){this.updateViewportBoundaries();if(this._physicalCount===0){this._debounceTemplate(this._render)}this.listen(this,"iron-resize","_resizeHandler")},detached:function(){this.unlisten(this,"iron-resize","_resizeHandler")},_setOverflow:function(scrollTarget){this.style.webkitOverflowScrolling=scrollTarget===this?"touch":"";this.style.overflow=scrollTarget===this?"auto":""},updateViewportBoundaries:function(){this._scrollerPaddingTop=this.scrollTarget===this?0:parseInt(window.getComputedStyle(this)["padding-top"],10);this._viewportHeight=this._scrollTargetHeight;if(this.grid){this._updateGridMetrics()}},_scrollHandler:function(){var scrollTop=Math.max(0,Math.min(this._maxScrollTop,this._scrollTop));var delta=scrollTop-this._scrollPosition;var tileHeight,tileTop,kth,recycledTileSet,scrollBottom,physicalBottom;var ratio=this._ratio;var recycledTiles=0;var hiddenContentSize=this._hiddenContentSize;var currentRatio=ratio;var movingUp=[];this._scrollPosition=scrollTop;this._firstVisibleIndexVal=null;this._lastVisibleIndexVal=null;scrollBottom=this._scrollBottom;physicalBottom=this._physicalBottom;if(Math.abs(delta)>this._physicalSize){this._physicalTop+=delta;recycledTiles=Math.round(delta/this._physicalAverage)}else if(delta<0){var topSpace=scrollTop-this._physicalTop;var virtualStart=this._virtualStart;recycledTileSet=[];kth=this._physicalEnd;currentRatio=topSpace/hiddenContentSize;while(currentRatio<ratio&&recycledTiles<this._physicalCount&&virtualStart-recycledTiles>0&&physicalBottom-this._getPhysicalSizeIncrement(kth)>scrollBottom){tileHeight=this._getPhysicalSizeIncrement(kth);currentRatio+=tileHeight/hiddenContentSize;physicalBottom-=tileHeight;recycledTileSet.push(kth);recycledTiles++;kth=kth===0?this._physicalCount-1:kth-1}movingUp=recycledTileSet;recycledTiles=-recycledTiles}else if(delta>0){var bottomSpace=physicalBottom-scrollBottom;var virtualEnd=this._virtualEnd;var lastVirtualItemIndex=this._virtualCount-1;recycledTileSet=[];kth=this._physicalStart;currentRatio=bottomSpace/hiddenContentSize;while(currentRatio<ratio&&recycledTiles<this._physicalCount&&virtualEnd+recycledTiles<lastVirtualItemIndex&&this._physicalTop+this._getPhysicalSizeIncrement(kth)<scrollTop){tileHeight=this._getPhysicalSizeIncrement(kth);currentRatio+=tileHeight/hiddenContentSize;this._physicalTop+=tileHeight;recycledTileSet.push(kth);recycledTiles++;kth=(kth+1)%this._physicalCount}}if(recycledTiles===0){if(physicalBottom<scrollBottom||this._physicalTop>scrollTop){this._increasePoolIfNeeded()}}else{this._virtualStart=this._virtualStart+recycledTiles;this._physicalStart=this._physicalStart+recycledTiles;this._update(recycledTileSet,movingUp)}},_update:function(itemSet,movingUp){this._manageFocus();this._assignModels(itemSet);this._updateMetrics(itemSet);if(movingUp){while(movingUp.length){var idx=movingUp.pop();this._physicalTop-=this._getPhysicalSizeIncrement(idx)}}this._positionItems();this._updateScrollerSize();this._increasePoolIfNeeded()},_createPool:function(size){var physicalItems=new Array(size);this._ensureTemplatized();for(var i=0;i<size;i++){var inst=this.stamp(null);physicalItems[i]=inst.root.querySelector("*");Polymer.dom(this).appendChild(inst.root)}return physicalItems},_increasePoolIfNeeded:function(){if(this._viewportHeight===0){return false}var self=this;var isClientFull=this._physicalBottom>=this._scrollBottom&&this._physicalTop<=this._scrollPosition;if(this._physicalSize>=this._optPhysicalSize&&isClientFull){return false}var maxPoolSize=Math.round(this._physicalCount*.5);if(!isClientFull){this._debounceTemplate(this._increasePool.bind(this,maxPoolSize));return true}this._yield(function(){self._increasePool(Math.min(maxPoolSize,Math.max(1,Math.round(50/self._templateCost))))});return true},_yield:function(cb){var g=window;var handle=g.requestIdleCallback?g.requestIdleCallback(cb):g.setTimeout(cb,16);Polymer.dom.addDebouncer({complete:function(){g.cancelIdleCallback?g.cancelIdleCallback(handle):g.clearTimeout(handle);cb()}})},_increasePool:function(missingItems){var nextPhysicalCount=Math.min(this._physicalCount+missingItems,this._virtualCount-this._virtualStart,Math.max(this.maxPhysicalCount,DEFAULT_PHYSICAL_COUNT));var prevPhysicalCount=this._physicalCount;var delta=nextPhysicalCount-prevPhysicalCount;var ts=window.performance.now();if(delta<=0){return}[].push.apply(this._physicalItems,this._createPool(delta));[].push.apply(this._physicalSizes,new Array(delta));this._physicalCount=prevPhysicalCount+delta;if(this._physicalStart>this._physicalEnd&&this._isIndexRendered(this._focusedIndex)&&this._getPhysicalIndex(this._focusedIndex)<this._physicalEnd){this._physicalStart=this._physicalStart+delta}this._update();this._templateCost=(window.performance.now()-ts)/delta},_render:function(){if(this.isAttached&&this._isVisible){if(this._physicalCount===0){this._increasePool(DEFAULT_PHYSICAL_COUNT)}else{this._update()}}},_ensureTemplatized:function(){if(!this.ctor){var props={};props.__key__=true;props[this.as]=true;props[this.indexAs]=true;props[this.selectedAs]=true;props.tabIndex=true;this._instanceProps=props;this._userTemplate=Polymer.dom(this).querySelector("template");if(this._userTemplate){this.templatize(this._userTemplate)}else{console.warn("iron-list requires a template to be provided in light-dom")}}},_getStampedChildren:function(){return this._physicalItems},_forwardInstancePath:function(inst,path,value){if(path.indexOf(this.as+".")===0){this.notifyPath("items."+inst.__key__+"."+path.slice(this.as.length+1),value)}},_forwardParentProp:function(prop,value){if(this._physicalItems){this._physicalItems.forEach(function(item){item._templateInstance[prop]=value},this)}},_forwardParentPath:function(path,value){if(this._physicalItems){this._physicalItems.forEach(function(item){item._templateInstance.notifyPath(path,value,true)},this)}},_forwardItemPath:function(path,value){if(!this._physicalIndexForKey){return}var dot=path.indexOf(".");var key=path.substring(0,dot<0?path.length:dot);var idx=this._physicalIndexForKey[key];var offscreenItem=this._offscreenFocusedItem;var el=offscreenItem&&offscreenItem._templateInstance.__key__===key?offscreenItem:this._physicalItems[idx];if(!el||el._templateInstance.__key__!==key){return}if(dot>=0){path=this.as+"."+path.substring(dot+1);el._templateInstance.notifyPath(path,value,true)}else{var currentItem=el._templateInstance[this.as];if(Array.isArray(this.selectedItems)){for(var i=0;i<this.selectedItems.length;i++){if(this.selectedItems[i]===currentItem){this.set("selectedItems."+i,value);break}}}else if(this.selectedItem===currentItem){this.set("selectedItem",value)}el._templateInstance[this.as]=value}},_itemsChanged:function(change){if(change.path==="items"){this._virtualStart=0;this._physicalTop=0;this._virtualCount=this.items?this.items.length:0;this._collection=this.items?Polymer.Collection.get(this.items):null;this._physicalIndexForKey={};this._firstVisibleIndexVal=null;this._lastVisibleIndexVal=null;this._physicalCount=this._physicalCount||0;this._physicalItems=this._physicalItems||[];this._physicalSizes=this._physicalSizes||[];this._physicalStart=0;this._resetScrollPosition(0);this._removeFocusedItem();this._debounceTemplate(this._render)}else if(change.path==="items.splices"){this._adjustVirtualIndex(change.value.indexSplices);this._virtualCount=this.items?this.items.length:0;this._debounceTemplate(this._render)}else{this._forwardItemPath(change.path.split(".").slice(1).join("."),change.value)}},_adjustVirtualIndex:function(splices){splices.forEach(function(splice){splice.removed.forEach(this._removeItem,this);if(splice.index<this._virtualStart){var delta=Math.max(splice.addedCount-splice.removed.length,splice.index-this._virtualStart);this._virtualStart=this._virtualStart+delta;if(this._focusedIndex>=0){this._focusedIndex=this._focusedIndex+delta}}},this)},_removeItem:function(item){this.$.selector.deselect(item);if(this._focusedItem&&this._focusedItem._templateInstance[this.as]===item){this._removeFocusedItem()}},_iterateItems:function(fn,itemSet){var pidx,vidx,rtn,i;if(arguments.length===2&&itemSet){for(i=0;i<itemSet.length;i++){pidx=itemSet[i];vidx=this._computeVidx(pidx);if((rtn=fn.call(this,pidx,vidx))!=null){return rtn}}}else{pidx=this._physicalStart;vidx=this._virtualStart;for(;pidx<this._physicalCount;pidx++,vidx++){if((rtn=fn.call(this,pidx,vidx))!=null){return rtn}}for(pidx=0;pidx<this._physicalStart;pidx++,vidx++){if((rtn=fn.call(this,pidx,vidx))!=null){return rtn}}}},_computeVidx:function(pidx){if(pidx>=this._physicalStart){return this._virtualStart+(pidx-this._physicalStart)}return this._virtualStart+(this._physicalCount-this._physicalStart)+pidx},_assignModels:function(itemSet){this._iterateItems(function(pidx,vidx){var el=this._physicalItems[pidx];var inst=el._templateInstance;var item=this.items&&this.items[vidx];if(item!=null){inst[this.as]=item;inst.__key__=this._collection.getKey(item);inst[this.selectedAs]=this.$.selector.isSelected(item);inst[this.indexAs]=vidx;inst.tabIndex=this._focusedIndex===vidx?0:-1;this._physicalIndexForKey[inst.__key__]=pidx;el.removeAttribute("hidden")}else{inst.__key__=null;el.setAttribute("hidden","")}},itemSet)},_updateMetrics:function(itemSet){Polymer.dom.flush();var newPhysicalSize=0;var oldPhysicalSize=0;var prevAvgCount=this._physicalAverageCount;var prevPhysicalAvg=this._physicalAverage;this._iterateItems(function(pidx,vidx){oldPhysicalSize+=this._physicalSizes[pidx]||0;this._physicalSizes[pidx]=this._physicalItems[pidx].offsetHeight;newPhysicalSize+=this._physicalSizes[pidx];this._physicalAverageCount+=this._physicalSizes[pidx]?1:0},itemSet);this._viewportHeight=this._scrollTargetHeight;if(this.grid){this._updateGridMetrics();this._physicalSize=Math.ceil(this._physicalCount/this._itemsPerRow)*this._rowHeight}else{this._physicalSize=this._physicalSize+newPhysicalSize-oldPhysicalSize}if(this._physicalAverageCount!==prevAvgCount){this._physicalAverage=Math.round((prevPhysicalAvg*prevAvgCount+newPhysicalSize)/this._physicalAverageCount)}},_updateGridMetrics:function(){this._viewportWidth=this.$.items.offsetWidth;this._itemWidth=this._physicalCount>0?this._physicalItems[0].getBoundingClientRect().width:DEFAULT_GRID_SIZE;this._rowHeight=this._physicalCount>0?this._physicalItems[0].offsetHeight:DEFAULT_GRID_SIZE;this._itemsPerRow=this._itemWidth?Math.floor(this._viewportWidth/this._itemWidth):this._itemsPerRow},_positionItems:function(){this._adjustScrollPosition();var y=this._physicalTop;if(this.grid){var totalItemWidth=this._itemsPerRow*this._itemWidth;var rowOffset=(this._viewportWidth-totalItemWidth)/2;this._iterateItems(function(pidx,vidx){var modulus=vidx%this._itemsPerRow;var x=Math.floor(modulus*this._itemWidth+rowOffset);this.translate3d(x+"px",y+"px",0,this._physicalItems[pidx]);if(this._shouldRenderNextRow(vidx)){y+=this._rowHeight}})}else{this._iterateItems(function(pidx,vidx){this.translate3d(0,y+"px",0,this._physicalItems[pidx]);y+=this._physicalSizes[pidx]})}},_getPhysicalSizeIncrement:function(pidx){if(!this.grid){return this._physicalSizes[pidx]}if(this._computeVidx(pidx)%this._itemsPerRow!==this._itemsPerRow-1){return 0}return this._rowHeight},_shouldRenderNextRow:function(vidx){return vidx%this._itemsPerRow===this._itemsPerRow-1},_adjustScrollPosition:function(){var deltaHeight=this._virtualStart===0?this._physicalTop:Math.min(this._scrollPosition+this._physicalTop,0);if(deltaHeight){this._physicalTop=this._physicalTop-deltaHeight;if(!IOS_TOUCH_SCROLLING&&this._physicalTop!==0){this._resetScrollPosition(this._scrollTop-deltaHeight)}}},_resetScrollPosition:function(pos){if(this.scrollTarget){this._scrollTop=pos;this._scrollPosition=this._scrollTop}},_updateScrollerSize:function(forceUpdate){if(this.grid){this._estScrollHeight=this._virtualRowCount*this._rowHeight}else{this._estScrollHeight=this._physicalBottom+Math.max(this._virtualCount-this._physicalCount-this._virtualStart,0)*this._physicalAverage}forceUpdate=forceUpdate||this._scrollHeight===0;forceUpdate=forceUpdate||this._scrollPosition>=this._estScrollHeight-this._physicalSize;forceUpdate=forceUpdate||this.grid&&this.$.items.style.height<this._estScrollHeight;if(forceUpdate||Math.abs(this._estScrollHeight-this._scrollHeight)>=this._optPhysicalSize){this.$.items.style.height=this._estScrollHeight+"px";this._scrollHeight=this._estScrollHeight}},scrollToItem:function(item){return this.scrollToIndex(this.items.indexOf(item))},scrollToIndex:function(idx){if(typeof idx!=="number"||idx<0||idx>this.items.length-1){return}Polymer.dom.flush();if(this._physicalCount===0){return}idx=Math.min(Math.max(idx,0),this._virtualCount-1);if(!this._isIndexRendered(idx)||idx>=this._maxVirtualStart){this._virtualStart=this.grid?idx-this._itemsPerRow*2:idx-1}this._manageFocus();this._assignModels();this._updateMetrics();this._physicalTop=Math.floor(this._virtualStart/this._itemsPerRow)*this._physicalAverage;var currentTopItem=this._physicalStart;var currentVirtualItem=this._virtualStart;var targetOffsetTop=0;var hiddenContentSize=this._hiddenContentSize;while(currentVirtualItem<idx&&targetOffsetTop<=hiddenContentSize){targetOffsetTop=targetOffsetTop+this._getPhysicalSizeIncrement(currentTopItem);currentTopItem=(currentTopItem+1)%this._physicalCount;currentVirtualItem++}this._updateScrollerSize(true);this._positionItems();this._resetScrollPosition(this._physicalTop+this._scrollerPaddingTop+targetOffsetTop);this._increasePoolIfNeeded();this._firstVisibleIndexVal=null;this._lastVisibleIndexVal=null},_resetAverage:function(){this._physicalAverage=0;this._physicalAverageCount=0},_resizeHandler:function(){if(IOS&&Math.abs(this._viewportHeight-this._scrollTargetHeight)<100){return}Polymer.dom.addDebouncer(this.debounce("_debounceTemplate",function(){this.updateViewportBoundaries();this._render();if(this._physicalCount>0&&this._isVisible){this._resetAverage();this.scrollToIndex(this.firstVisibleIndex)}}.bind(this),1))},_getModelFromItem:function(item){var key=this._collection.getKey(item);var pidx=this._physicalIndexForKey[key];if(pidx!=null){return this._physicalItems[pidx]._templateInstance}return null},_getNormalizedItem:function(item){if(this._collection.getKey(item)===undefined){if(typeof item==="number"){item=this.items[item];if(!item){throw new RangeError("<item> not found")}return item}throw new TypeError("<item> should be a valid item")}return item},selectItem:function(item){item=this._getNormalizedItem(item);var model=this._getModelFromItem(item);if(!this.multiSelection&&this.selectedItem){this.deselectItem(this.selectedItem)}if(model){model[this.selectedAs]=true}this.$.selector.select(item);this.updateSizeForItem(item)},deselectItem:function(item){item=this._getNormalizedItem(item);var model=this._getModelFromItem(item);if(model){model[this.selectedAs]=false}this.$.selector.deselect(item);this.updateSizeForItem(item)},toggleSelectionForItem:function(item){item=this._getNormalizedItem(item);if(this.$.selector.isSelected(item)){this.deselectItem(item)}else{this.selectItem(item)}},clearSelection:function(){function unselect(item){var model=this._getModelFromItem(item);if(model){model[this.selectedAs]=false}}if(Array.isArray(this.selectedItems)){this.selectedItems.forEach(unselect,this)}else if(this.selectedItem){unselect.call(this,this.selectedItem)}this.$.selector.clearSelection()},_selectionEnabledChanged:function(selectionEnabled){var handler=selectionEnabled?this.listen:this.unlisten;handler.call(this,this,"tap","_selectionHandler")},_selectionHandler:function(e){var model=this.modelForElement(e.target);if(!model){return}var modelTabIndex,activeElTabIndex;var target=Polymer.dom(e).path[0];var activeEl=Polymer.dom(this.domHost?this.domHost.root:document).activeElement;var physicalItem=this._physicalItems[this._getPhysicalIndex(model[this.indexAs])];if(target.localName==="input"||target.localName==="button"||target.localName==="select"){return}modelTabIndex=model.tabIndex;model.tabIndex=SECRET_TABINDEX;activeElTabIndex=activeEl?activeEl.tabIndex:-1;model.tabIndex=modelTabIndex;if(activeEl&&physicalItem!==activeEl&&physicalItem.contains(activeEl)&&activeElTabIndex!==SECRET_TABINDEX){return}this.toggleSelectionForItem(model[this.as])},_multiSelectionChanged:function(multiSelection){this.clearSelection();this.$.selector.multi=multiSelection},updateSizeForItem:function(item){item=this._getNormalizedItem(item);var key=this._collection.getKey(item);var pidx=this._physicalIndexForKey[key];if(pidx!=null){this._updateMetrics([pidx]);this._positionItems()}},_manageFocus:function(){var fidx=this._focusedIndex;if(fidx>=0&&fidx<this._virtualCount){if(this._isIndexRendered(fidx)){this._restoreFocusedItem()}else{this._createFocusBackfillItem()}}else if(this._virtualCount>0&&this._physicalCount>0){this._focusedIndex=this._virtualStart;this._focusedItem=this._physicalItems[this._physicalStart]}},_isIndexRendered:function(idx){return idx>=this._virtualStart&&idx<=this._virtualEnd},_isIndexVisible:function(idx){return idx>=this.firstVisibleIndex&&idx<=this.lastVisibleIndex},_getPhysicalIndex:function(idx){return this._physicalIndexForKey[this._collection.getKey(this._getNormalizedItem(idx))]},_focusPhysicalItem:function(idx){if(idx<0||idx>=this._virtualCount){return}this._restoreFocusedItem();if(!this._isIndexRendered(idx)){this.scrollToIndex(idx)}var physicalItem=this._physicalItems[this._getPhysicalIndex(idx)];var model=physicalItem._templateInstance;var focusable;model.tabIndex=SECRET_TABINDEX;if(physicalItem.tabIndex===SECRET_TABINDEX){focusable=physicalItem}if(!focusable){focusable=Polymer.dom(physicalItem).querySelector('[tabindex="'+SECRET_TABINDEX+'"]')}model.tabIndex=0;this._focusedIndex=idx;focusable&&focusable.focus()},_removeFocusedItem:function(){if(this._offscreenFocusedItem){Polymer.dom(this).removeChild(this._offscreenFocusedItem)}this._offscreenFocusedItem=null;this._focusBackfillItem=null;this._focusedItem=null;this._focusedIndex=-1},_createFocusBackfillItem:function(){var pidx,fidx=this._focusedIndex;if(this._offscreenFocusedItem||fidx<0){return}if(!this._focusBackfillItem){var stampedTemplate=this.stamp(null);this._focusBackfillItem=stampedTemplate.root.querySelector("*");Polymer.dom(this).appendChild(stampedTemplate.root)}pidx=this._getPhysicalIndex(fidx);if(pidx!=null){this._offscreenFocusedItem=this._physicalItems[pidx];this._physicalItems[pidx]=this._focusBackfillItem;this.translate3d(0,HIDDEN_Y,0,this._offscreenFocusedItem)}},_restoreFocusedItem:function(){var pidx,fidx=this._focusedIndex;if(!this._offscreenFocusedItem||this._focusedIndex<0){return}this._assignModels();pidx=this._getPhysicalIndex(fidx);if(pidx!=null){this._focusBackfillItem=this._physicalItems[pidx];this._physicalItems[pidx]=this._offscreenFocusedItem;this._offscreenFocusedItem=null;this.translate3d(0,HIDDEN_Y,0,this._focusBackfillItem)}},_didFocus:function(e){var targetModel=this.modelForElement(e.target);var focusedModel=this._focusedItem?this._focusedItem._templateInstance:null;var hasOffscreenFocusedItem=this._offscreenFocusedItem!==null;var fidx=this._focusedIndex;if(!targetModel||!focusedModel){return}if(focusedModel===targetModel){if(!this._isIndexVisible(fidx)){this.scrollToIndex(fidx)}}else{this._restoreFocusedItem();focusedModel.tabIndex=-1;targetModel.tabIndex=0;fidx=targetModel[this.indexAs];this._focusedIndex=fidx;this._focusedItem=this._physicalItems[this._getPhysicalIndex(fidx)];if(hasOffscreenFocusedItem&&!this._offscreenFocusedItem){this._update()}}},_didMoveUp:function(){this._focusPhysicalItem(this._focusedIndex-1)},_didMoveDown:function(e){e.detail.keyboardEvent.preventDefault();this._focusPhysicalItem(this._focusedIndex+1)},_didEnter:function(e){this._focusPhysicalItem(this._focusedIndex);this._selectionHandler(e.detail.keyboardEvent)}})})();Polymer({is:"iron-scroll-threshold",properties:{upperThreshold:{type:Number,value:100},lowerThreshold:{type:Number,value:100},upperTriggered:{type:Boolean,value:false,notify:true,readOnly:true},lowerTriggered:{type:Boolean,value:false,notify:true,readOnly:true},horizontal:{type:Boolean,value:false}},behaviors:[Polymer.IronScrollTargetBehavior],observers:["_setOverflow(scrollTarget)","_initCheck(horizontal, isAttached)"],get _defaultScrollTarget(){return this},_setOverflow:function(scrollTarget){this.style.overflow=scrollTarget===this?"auto":""},_scrollHandler:function(){var THROTTLE_THRESHOLD=200;if(!this.isDebouncerActive("_checkTheshold")){this.debounce("_checkTheshold",function(){this.checkScrollThesholds()},THROTTLE_THRESHOLD)}},_initCheck:function(horizontal,isAttached){if(isAttached){this.debounce("_init",function(){this.clearTriggers();this.checkScrollThesholds()})}},checkScrollThesholds:function(){if(!this.scrollTarget||this.lowerTriggered&&this.upperTriggered){return}var upperScrollValue=this.horizontal?this._scrollLeft:this._scrollTop;var lowerScrollValue=this.horizontal?this.scrollTarget.scrollWidth-this._scrollTargetWidth-this._scrollLeft:this.scrollTarget.scrollHeight-this._scrollTargetHeight-this._scrollTop;if(upperScrollValue<=this.upperThreshold&&!this.upperTriggered){this._setUpperTriggered(true);this.fire("upper-threshold")}if(lowerScrollValue<=this.lowerThreshold&&!this.lowerTriggered){this._setLowerTriggered(true);this.fire("lower-threshold")}},clearTriggers:function(){this._setUpperTriggered(false);this._setLowerTriggered(false)}});
 // Copyright (c) 2011 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.
-var EventTrackerEntry;
-
-function EventTracker() {
-  this.listeners_ = [];
-}
-
-EventTracker.prototype = {
-  add: function(target, eventType, listener, opt_capture) {
-    var capture = !!opt_capture;
-    var h = {
-      target: target,
-      eventType: eventType,
-      listener: listener,
-      capture: capture
-    };
-    this.listeners_.push(h);
-    target.addEventListener(eventType, listener, capture);
-  },
-  remove: function(target, eventType) {
-    this.listeners_ = this.listeners_.filter(function(h) {
-      if (h.target == target && (!eventType || h.eventType == eventType)) {
-        EventTracker.removeEventListener_(h);
-        return false;
-      }
-      return true;
-    });
-  },
-  removeAll: function() {
-    this.listeners_.forEach(EventTracker.removeEventListener_);
-    this.listeners_ = [];
-  }
-};
-
-EventTracker.removeEventListener_ = function(h) {
-  h.target.removeEventListener(h.eventType, h.listener, h.capture);
-};
-
+var EventTrackerEntry;function EventTracker(){this.listeners_=[]}EventTracker.prototype={add:function(target,eventType,listener,opt_capture){var capture=!!opt_capture;var h={target:target,eventType:eventType,listener:listener,capture:capture};this.listeners_.push(h);target.addEventListener(eventType,listener,capture)},remove:function(target,eventType){this.listeners_=this.listeners_.filter(function(h){if(h.target==target&&(!eventType||h.eventType==eventType)){EventTracker.removeEventListener_(h);return false}return true})},removeAll:function(){this.listeners_.forEach(EventTracker.removeEventListener_);this.listeners_=[]}};EventTracker.removeEventListener_=function(h){h.target.removeEventListener(h.eventType,h.listener,h.capture)};
 // 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.
-cr.define('cr.ui', function() {
-  function FocusRow(root, boundary, opt_delegate) {
-    this.root = root;
-    this.boundary_ = boundary || document.documentElement;
-    this.delegate = opt_delegate;
-    this.eventTracker = new EventTracker();
-  }
-  FocusRow.Delegate = function() {};
-  FocusRow.Delegate.prototype = {
-    onKeydown: assertNotReached,
-    onFocus: assertNotReached
-  };
-  FocusRow.ACTIVE_CLASS = 'focus-row-active';
-  FocusRow.isFocusable = function(element) {
-    if (!element || element.disabled) return false;
-    function isVisible(element) {
-      assertInstanceof(element, Element);
-      var style = window.getComputedStyle(element);
-      if (style.visibility == 'hidden' || style.display == 'none') return false;
-      var parent = element.parentNode;
-      if (!parent) return false;
-      if (parent == element.ownerDocument || parent instanceof DocumentFragment) return true;
-      return isVisible(parent);
-    }
-    return isVisible(element);
-  };
-  FocusRow.prototype = {
-    addItem: function(type, query) {
-      assert(type);
-      var element = this.root.querySelector(query);
-      if (!element) return false;
-      element.setAttribute('focus-type', type);
-      element.tabIndex = this.isActive() ? 0 : -1;
-      this.eventTracker.add(element, 'blur', this.onBlur_.bind(this));
-      this.eventTracker.add(element, 'focus', this.onFocus_.bind(this));
-      this.eventTracker.add(element, 'keydown', this.onKeydown_.bind(this));
-      this.eventTracker.add(element, 'mousedown', this.onMousedown_.bind(this));
-      return true;
-    },
-    destroy: function() {
-      this.eventTracker.removeAll();
-    },
-    getCustomEquivalent: function(sampleElement) {
-      return assert(this.getFirstFocusable());
-    },
-    getElements: function() {
-      var elements = this.root.querySelectorAll('[focus-type]');
-      return Array.prototype.slice.call(elements);
-    },
-    getEquivalentElement: function(sampleElement) {
-      if (this.getFocusableElements().indexOf(sampleElement) >= 0) return sampleElement;
-      var sampleFocusType = this.getTypeForElement(sampleElement);
-      if (sampleFocusType) {
-        var sameType = this.getFirstFocusable(sampleFocusType);
-        if (sameType) return sameType;
-      }
-      return this.getCustomEquivalent(sampleElement);
-    },
-    getFirstFocusable: function(opt_type) {
-      var filter = opt_type ? '="' + opt_type + '"' : '';
-      var elements = this.root.querySelectorAll('[focus-type' + filter + ']');
-      for (var i = 0; i < elements.length; ++i) {
-        if (cr.ui.FocusRow.isFocusable(elements[i])) return elements[i];
-      }
-      return null;
-    },
-    getFocusableElements: function() {
-      return this.getElements().filter(cr.ui.FocusRow.isFocusable);
-    },
-    getTypeForElement: function(element) {
-      return element.getAttribute('focus-type') || '';
-    },
-    isActive: function() {
-      return this.root.classList.contains(FocusRow.ACTIVE_CLASS);
-    },
-    makeActive: function(active) {
-      if (active == this.isActive()) return;
-      this.getElements().forEach(function(element) {
-        element.tabIndex = active ? 0 : -1;
-      });
-      this.root.classList.toggle(FocusRow.ACTIVE_CLASS, active);
-    },
-    onBlur_: function(e) {
-      if (!this.boundary_.contains(e.relatedTarget)) return;
-      var currentTarget = e.currentTarget;
-      if (this.getFocusableElements().indexOf(currentTarget) >= 0) this.makeActive(false);
-    },
-    onFocus_: function(e) {
-      if (this.delegate) this.delegate.onFocus(this, e);
-    },
-    onMousedown_: function(e) {
-      if (e.button) return;
-      if (!e.currentTarget.disabled) e.currentTarget.tabIndex = 0;
-    },
-    onKeydown_: function(e) {
-      var elements = this.getFocusableElements();
-      var currentElement = e.currentTarget;
-      var elementIndex = elements.indexOf(currentElement);
-      assert(elementIndex >= 0);
-      if (this.delegate && this.delegate.onKeydown(this, e)) return;
-      if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) return;
-      var index = -1;
-      if (e.key == 'ArrowLeft') index = elementIndex + (isRTL() ? 1 : -1); else if (e.key == 'ArrowRight') index = elementIndex + (isRTL() ? -1 : 1); else if (e.key == 'Home') index = 0; else if (e.key == 'End') index = elements.length - 1;
-      var elementToFocus = elements[index];
-      if (elementToFocus) {
-        this.getEquivalentElement(elementToFocus).focus();
-        e.preventDefault();
-      }
-    }
-  };
-  return {
-    FocusRow: FocusRow
-  };
-});
-
+cr.define("cr.ui",function(){function FocusRow(root,boundary,opt_delegate){this.root=root;this.boundary_=boundary||document.documentElement;this.delegate=opt_delegate;this.eventTracker=new EventTracker}FocusRow.Delegate=function(){};FocusRow.Delegate.prototype={onKeydown:assertNotReached,onFocus:assertNotReached};FocusRow.ACTIVE_CLASS="focus-row-active";FocusRow.isFocusable=function(element){if(!element||element.disabled)return false;function isVisible(element){assertInstanceof(element,Element);var style=window.getComputedStyle(element);if(style.visibility=="hidden"||style.display=="none")return false;var parent=element.parentNode;if(!parent)return false;if(parent==element.ownerDocument||parent instanceof DocumentFragment)return true;return isVisible(parent)}return isVisible(element)};FocusRow.prototype={addItem:function(type,query){assert(type);var element=this.root.querySelector(query);if(!element)return false;element.setAttribute("focus-type",type);element.tabIndex=this.isActive()?0:-1;this.eventTracker.add(element,"blur",this.onBlur_.bind(this));this.eventTracker.add(element,"focus",this.onFocus_.bind(this));this.eventTracker.add(element,"keydown",this.onKeydown_.bind(this));this.eventTracker.add(element,"mousedown",this.onMousedown_.bind(this));return true},destroy:function(){this.eventTracker.removeAll()},getCustomEquivalent:function(sampleElement){return assert(this.getFirstFocusable())},getElements:function(){var elements=this.root.querySelectorAll("[focus-type]");return Array.prototype.slice.call(elements)},getEquivalentElement:function(sampleElement){if(this.getFocusableElements().indexOf(sampleElement)>=0)return sampleElement;var sampleFocusType=this.getTypeForElement(sampleElement);if(sampleFocusType){var sameType=this.getFirstFocusable(sampleFocusType);if(sameType)return sameType}return this.getCustomEquivalent(sampleElement)},getFirstFocusable:function(opt_type){var filter=opt_type?'="'+opt_type+'"':"";var elements=this.root.querySelectorAll("[focus-type"+filter+"]");for(var i=0;i<elements.length;++i){if(cr.ui.FocusRow.isFocusable(elements[i]))return elements[i]}return null},getFocusableElements:function(){return this.getElements().filter(cr.ui.FocusRow.isFocusable)},getTypeForElement:function(element){return element.getAttribute("focus-type")||""},isActive:function(){return this.root.classList.contains(FocusRow.ACTIVE_CLASS)},makeActive:function(active){if(active==this.isActive())return;this.getElements().forEach(function(element){element.tabIndex=active?0:-1});this.root.classList.toggle(FocusRow.ACTIVE_CLASS,active)},onBlur_:function(e){if(!this.boundary_.contains(e.relatedTarget))return;var currentTarget=e.currentTarget;if(this.getFocusableElements().indexOf(currentTarget)>=0)this.makeActive(false)},onFocus_:function(e){if(this.delegate)this.delegate.onFocus(this,e)},onMousedown_:function(e){if(e.button)return;if(!e.currentTarget.disabled)e.currentTarget.tabIndex=0},onKeydown_:function(e){var elements=this.getFocusableElements();var currentElement=e.currentTarget;var elementIndex=elements.indexOf(currentElement);assert(elementIndex>=0);if(this.delegate&&this.delegate.onKeydown(this,e))return;if(e.altKey||e.ctrlKey||e.metaKey||e.shiftKey)return;var index=-1;if(e.key=="ArrowLeft")index=elementIndex+(isRTL()?1:-1);else if(e.key=="ArrowRight")index=elementIndex+(isRTL()?-1:1);else if(e.key=="Home")index=0;else if(e.key=="End")index=elements.length-1;var elementToFocus=elements[index];if(elementToFocus){this.getEquivalentElement(elementToFocus).focus();e.preventDefault()}}};return{FocusRow:FocusRow}});
 // 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.
-cr.define('cr.icon', function() {
-  function getSupportedScaleFactors() {
-    var supportedScaleFactors = [];
-    if (!cr.isIOS) {
-      supportedScaleFactors.push(1);
-    }
-    if (cr.isMac || cr.isChromeOS || cr.isWindows || cr.isLinux) {
-      supportedScaleFactors.push(2);
-    } else {
-      supportedScaleFactors.push(window.devicePixelRatio);
-    }
-    return supportedScaleFactors;
-  }
-  function getImageSet(path) {
-    var supportedScaleFactors = getSupportedScaleFactors();
-    var replaceStartIndex = path.indexOf('scalefactor');
-    if (replaceStartIndex < 0) return url(path);
-    var s = '';
-    for (var i = 0; i < supportedScaleFactors.length; ++i) {
-      var scaleFactor = supportedScaleFactors[i];
-      var pathWithScaleFactor = path.substr(0, replaceStartIndex) + scaleFactor + path.substr(replaceStartIndex + 'scalefactor'.length);
-      s += url(pathWithScaleFactor) + ' ' + scaleFactor + 'x';
-      if (i != supportedScaleFactors.length - 1) s += ', ';
-    }
-    return '-webkit-image-set(' + s + ')';
-  }
-  function getImage(path) {
-    var chromeThemePath = 'chrome://theme';
-    var isChromeThemeUrl = path.slice(0, chromeThemePath.length) == chromeThemePath;
-    return isChromeThemeUrl ? getImageSet(path + '@scalefactorx') : url(path);
-  }
-  var FAVICON_URL_REGEX = /\.ico$/i;
-  function getFavicon(url, opt_size, opt_type) {
-    var size = opt_size || 16;
-    var type = opt_type || 'favicon';
-    return getImageSet('chrome://' + type + '/size/' + size + '@scalefactorx/' + (FAVICON_URL_REGEX.test(url) ? 'iconurl/' : '') + url);
-  }
-  return {
-    getImage: getImage,
-    getFavicon: getFavicon
-  };
-});
-
+cr.define("cr.icon",function(){function getSupportedScaleFactors(){var supportedScaleFactors=[];if(!cr.isIOS){supportedScaleFactors.push(1)}if(cr.isMac||cr.isChromeOS||cr.isWindows||cr.isLinux){supportedScaleFactors.push(2)}else{supportedScaleFactors.push(window.devicePixelRatio)}return supportedScaleFactors}function getImageSet(path){var supportedScaleFactors=getSupportedScaleFactors();var replaceStartIndex=path.indexOf("scalefactor");if(replaceStartIndex<0)return url(path);var s="";for(var i=0;i<supportedScaleFactors.length;++i){var scaleFactor=supportedScaleFactors[i];var pathWithScaleFactor=path.substr(0,replaceStartIndex)+scaleFactor+path.substr(replaceStartIndex+"scalefactor".length);s+=url(pathWithScaleFactor)+" "+scaleFactor+"x";if(i!=supportedScaleFactors.length-1)s+=", "}return"-webkit-image-set("+s+")"}function getImage(path){var chromeThemePath="chrome://theme";var isChromeThemeUrl=path.slice(0,chromeThemePath.length)==chromeThemePath;return isChromeThemeUrl?getImageSet(path+"@scalefactorx"):url(path)}var FAVICON_URL_REGEX=/\.ico$/i;function getFavicon(url,opt_size,opt_type){var size=opt_size||16;var type=opt_type||"favicon";return getImageSet("chrome://"+type+"/size/"+size+"@scalefactorx/"+(FAVICON_URL_REGEX.test(url)?"iconurl/":"")+url)}return{getImage:getImage,getFavicon:getFavicon}});
 // 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.
-Polymer({
-  is: 'history-searched-label',
-  properties: {
-    title: String,
-    searchTerm: String
-  },
-  observers: [ 'setSearchedTextToBold_(title, searchTerm)' ],
-  setSearchedTextToBold_: function() {
-    var i = 0;
-    var titleText = this.title;
-    if (this.searchTerm == '' || this.searchTerm == null) {
-      this.textContent = titleText;
-      return;
-    }
-    var re = new RegExp(quoteString(this.searchTerm), 'gim');
-    var match;
-    this.textContent = '';
-    while (match = re.exec(titleText)) {
-      if (match.index > i) this.appendChild(document.createTextNode(titleText.slice(i, match.index)));
-      i = re.lastIndex;
-      var b = document.createElement('b');
-      b.textContent = titleText.substring(match.index, i);
-      this.appendChild(b);
-    }
-    if (i < titleText.length) this.appendChild(document.createTextNode(titleText.slice(i)));
-  }
-});
-
+Polymer({is:"history-searched-label",properties:{title:String,searchTerm:String},observers:["setSearchedTextToBold_(title, searchTerm)"],setSearchedTextToBold_:function(){var i=0;var titleText=this.title;if(this.searchTerm==""||this.searchTerm==null){this.textContent=titleText;return}var re=new RegExp(quoteString(this.searchTerm),"gim");var match;this.textContent="";while(match=re.exec(titleText)){if(match.index>i)this.appendChild(document.createTextNode(titleText.slice(i,match.index)));i=re.lastIndex;var b=document.createElement("b");b.textContent=titleText.substring(match.index,i);this.appendChild(b)}if(i<titleText.length)this.appendChild(document.createTextNode(titleText.slice(i)))}});
 // 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.
-function HistoryFocusRow(root, boundary, delegate) {
-  cr.ui.FocusRow.call(this, root, boundary, delegate);
-  this.addItems();
-}
-
-HistoryFocusRow.prototype = {
-  __proto__: cr.ui.FocusRow.prototype,
-  getCustomEquivalent: function(sampleElement) {
-    var equivalent;
-    if (this.getTypeForElement(sampleElement) == 'star') equivalent = this.getFirstFocusable('title');
-    return equivalent || cr.ui.FocusRow.prototype.getCustomEquivalent.call(this, sampleElement);
-  },
-  addItems: function() {
-    this.destroy();
-    assert(this.addItem('checkbox', '#checkbox'));
-    assert(this.addItem('title', '#title'));
-    assert(this.addItem('menu-button', '#menu-button'));
-    this.addItem('star', '#bookmark-star');
-  }
-};
-
-cr.define('md_history', function() {
-  function FocusRowDelegate(historyItemElement) {
-    this.historyItemElement = historyItemElement;
-  }
-  FocusRowDelegate.prototype = {
-    onFocus: function(row, e) {
-      this.historyItemElement.lastFocused = e.path[0];
-    },
-    onKeydown: function(row, e) {
-      if (e.key == 'Enter') e.stopPropagation();
-      return false;
-    }
-  };
-  var HistoryItem = Polymer({
-    is: 'history-item',
-    properties: {
-      item: {
-        type: Object,
-        observer: 'showIcon_'
-      },
-      searchTerm: {
-        type: String
-      },
-      selected: {
-        type: Boolean,
-        reflectToAttribute: true
-      },
-      isCardStart: {
-        type: Boolean,
-        reflectToAttribute: true
-      },
-      isCardEnd: {
-        type: Boolean,
-        reflectToAttribute: true
-      },
-      embedded: {
-        type: Boolean,
-        reflectToAttribute: true
-      },
-      hasTimeGap: {
-        type: Boolean
-      },
-      numberOfItems: {
-        type: Number
-      },
-      path: String,
-      index: Number,
-      lastFocused: {
-        type: Object,
-        notify: true
-      },
-      ironListTabIndex: {
-        type: Number,
-        observer: 'ironListTabIndexChanged_'
-      }
-    },
-    row_: null,
-    attached: function() {
-      Polymer.RenderStatus.afterNextRender(this, function() {
-        this.row_ = new HistoryFocusRow(this.$['sizing-container'], null, new FocusRowDelegate(this));
-        this.row_.makeActive(this.ironListTabIndex == 0);
-        this.listen(this, 'focus', 'onFocus_');
-        this.listen(this, 'dom-change', 'onDomChange_');
-      });
-    },
-    detached: function() {
-      this.unlisten(this, 'focus', 'onFocus_');
-      this.unlisten(this, 'dom-change', 'onDomChange_');
-      if (this.row_) this.row_.destroy();
-    },
-    onFocus_: function() {
-      if (this.lastFocused) this.row_.getEquivalentElement(this.lastFocused).focus(); else this.row_.getFirstFocusable().focus();
-      this.tabIndex = -1;
-    },
-    ironListTabIndexChanged_: function() {
-      if (this.row_) this.row_.makeActive(this.ironListTabIndex == 0);
-    },
-    onDomChange_: function() {
-      if (this.row_) this.row_.addItems();
-    },
-    onCheckboxSelected_: function(e) {
-      this.fire('history-checkbox-select', {
-        element: this,
-        shiftKey: e.shiftKey
-      });
-      e.preventDefault();
-    },
-    onCheckboxMousedown_: function(e) {
-      if (e.shiftKey) e.preventDefault();
-    },
-    getEntrySummary_: function() {
-      var item = this.item;
-      return loadTimeData.getStringF('entrySummary', item.dateTimeOfDay, item.starred ? loadTimeData.getString('bookmarked') : '', item.title, item.domain);
-    },
-    getAriaChecked_: function(selected) {
-      return selected ? 'true' : 'false';
-    },
-    onRemoveBookmarkTap_: function() {
-      if (!this.item.starred) return;
-      if (this.$$('#bookmark-star') == this.root.activeElement) this.$['menu-button'].focus();
-      var browserService = md_history.BrowserService.getInstance();
-      browserService.removeBookmark(this.item.url);
-      browserService.recordAction('BookmarkStarClicked');
-      this.fire('remove-bookmark-stars', this.item.url);
-    },
-    onMenuButtonTap_: function(e) {
-      this.fire('toggle-menu', {
-        target: Polymer.dom(e).localTarget,
-        index: this.index,
-        item: this.item,
-        path: this.path
-      });
-      e.stopPropagation();
-    },
-    onLinkClick_: function() {
-      var browserService = md_history.BrowserService.getInstance();
-      browserService.recordAction('EntryLinkClick');
-      if (this.searchTerm) browserService.recordAction('SearchResultClick');
-      if (this.index == undefined) return;
-      browserService.recordHistogram('HistoryPage.ClickPosition', this.index, UMA_MAX_BUCKET_VALUE);
-      if (this.index <= UMA_MAX_SUBSET_BUCKET_VALUE) {
-        browserService.recordHistogram('HistoryPage.ClickPositionSubset', this.index, UMA_MAX_SUBSET_BUCKET_VALUE);
-      }
-    },
-    onLinkRightClick_: function() {
-      md_history.BrowserService.getInstance().recordAction('EntryLinkRightClick');
-    },
-    showIcon_: function() {
-      this.$.icon.style.backgroundImage = cr.icon.getFavicon(this.item.url);
-    },
-    selectionNotAllowed_: function() {
-      return !loadTimeData.getBoolean('allowDeletingHistory');
-    },
-    cardTitle_: function(numberOfItems, historyDate, search) {
-      if (!search) return this.item.dateRelativeDay;
-      var resultId = numberOfItems == 1 ? 'searchResult' : 'searchResults';
-      return loadTimeData.getStringF('foundSearchResults', numberOfItems, loadTimeData.getString(resultId), search);
-    }
-  });
-  HistoryItem.needsTimeGap = function(visits, currentIndex, searchedTerm) {
-    if (currentIndex >= visits.length - 1 || visits.length == 0) return false;
-    var currentItem = visits[currentIndex];
-    var nextItem = visits[currentIndex + 1];
-    if (searchedTerm) return currentItem.dateShort != nextItem.dateShort;
-    return currentItem.time - nextItem.time > BROWSING_GAP_TIME && currentItem.dateRelativeDay == nextItem.dateRelativeDay;
-  };
-  return {
-    HistoryItem: HistoryItem
-  };
-});
-
+function HistoryFocusRow(root,boundary,delegate){cr.ui.FocusRow.call(this,root,boundary,delegate);this.addItems()}HistoryFocusRow.prototype={__proto__:cr.ui.FocusRow.prototype,getCustomEquivalent:function(sampleElement){var equivalent;if(this.getTypeForElement(sampleElement)=="star")equivalent=this.getFirstFocusable("title");return equivalent||cr.ui.FocusRow.prototype.getCustomEquivalent.call(this,sampleElement)},addItems:function(){this.destroy();assert(this.addItem("checkbox","#checkbox"));assert(this.addItem("title","#title"));assert(this.addItem("menu-button","#menu-button"));this.addItem("star","#bookmark-star")}};cr.define("md_history",function(){function FocusRowDelegate(historyItemElement){this.historyItemElement=historyItemElement}FocusRowDelegate.prototype={onFocus:function(row,e){this.historyItemElement.lastFocused=e.path[0]},onKeydown:function(row,e){if(e.key=="Enter")e.stopPropagation();return false}};var HistoryItem=Polymer({is:"history-item",properties:{item:{type:Object,observer:"showIcon_"},searchTerm:{type:String},selected:{type:Boolean,reflectToAttribute:true},isCardStart:{type:Boolean,reflectToAttribute:true},isCardEnd:{type:Boolean,reflectToAttribute:true},embedded:{type:Boolean,reflectToAttribute:true},hasTimeGap:{type:Boolean},numberOfItems:{type:Number},path:String,index:Number,lastFocused:{type:Object,notify:true},ironListTabIndex:{type:Number,observer:"ironListTabIndexChanged_"}},row_:null,attached:function(){Polymer.RenderStatus.afterNextRender(this,function(){this.row_=new HistoryFocusRow(this.$["sizing-container"],null,new FocusRowDelegate(this));this.row_.makeActive(this.ironListTabIndex==0);this.listen(this,"focus","onFocus_");this.listen(this,"dom-change","onDomChange_")})},detached:function(){this.unlisten(this,"focus","onFocus_");this.unlisten(this,"dom-change","onDomChange_");if(this.row_)this.row_.destroy()},onFocus_:function(){if(this.lastFocused)this.row_.getEquivalentElement(this.lastFocused).focus();else this.row_.getFirstFocusable().focus();this.tabIndex=-1},ironListTabIndexChanged_:function(){if(this.row_)this.row_.makeActive(this.ironListTabIndex==0)},onDomChange_:function(){if(this.row_)this.row_.addItems()},onCheckboxSelected_:function(e){this.fire("history-checkbox-select",{element:this,shiftKey:e.shiftKey});e.preventDefault()},onCheckboxMousedown_:function(e){if(e.shiftKey)e.preventDefault()},getEntrySummary_:function(){var item=this.item;return loadTimeData.getStringF("entrySummary",item.dateTimeOfDay,item.starred?loadTimeData.getString("bookmarked"):"",item.title,item.domain)},getAriaChecked_:function(selected){return selected?"true":"false"},onRemoveBookmarkTap_:function(){if(!this.item.starred)return;if(this.$$("#bookmark-star")==this.root.activeElement)this.$["menu-button"].focus();var browserService=md_history.BrowserService.getInstance();browserService.removeBookmark(this.item.url);browserService.recordAction("BookmarkStarClicked");this.fire("remove-bookmark-stars",this.item.url)},onMenuButtonTap_:function(e){this.fire("toggle-menu",{target:Polymer.dom(e).localTarget,index:this.index,item:this.item,path:this.path});e.stopPropagation()},onLinkClick_:function(){var browserService=md_history.BrowserService.getInstance();browserService.recordAction("EntryLinkClick");if(this.searchTerm)browserService.recordAction("SearchResultClick");if(this.index==undefined)return;browserService.recordHistogram("HistoryPage.ClickPosition",this.index,UMA_MAX_BUCKET_VALUE);if(this.index<=UMA_MAX_SUBSET_BUCKET_VALUE){browserService.recordHistogram("HistoryPage.ClickPositionSubset",this.index,UMA_MAX_SUBSET_BUCKET_VALUE)}},onLinkRightClick_:function(){md_history.BrowserService.getInstance().recordAction("EntryLinkRightClick")},showIcon_:function(){this.$.icon.style.backgroundImage=cr.icon.getFavicon(this.item.url)},selectionNotAllowed_:function(){return!loadTimeData.getBoolean("allowDeletingHistory")},cardTitle_:function(numberOfItems,historyDate,search){if(!search)return this.item.dateRelativeDay;var resultId=numberOfItems==1?"searchResult":"searchResults";return loadTimeData.getStringF("foundSearchResults",numberOfItems,loadTimeData.getString(resultId),search)}});HistoryItem.needsTimeGap=function(visits,currentIndex,searchedTerm){if(currentIndex>=visits.length-1||visits.length==0)return false;var currentItem=visits[currentIndex];var nextItem=visits[currentIndex+1];if(searchedTerm)return currentItem.dateShort!=nextItem.dateShort;return currentItem.time-nextItem.time>BROWSING_GAP_TIME&&currentItem.dateRelativeDay==nextItem.dateRelativeDay};return{HistoryItem:HistoryItem}});
 // 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.
-var SelectionTreeNode = function(currentPath) {
-  this.currentPath = currentPath;
-  this.leaf = false;
-  this.indexes = [];
-  this.children = [];
-};
-
-SelectionTreeNode.prototype.addChild = function(index, path) {
-  this.indexes.push(index);
-  this.children[index] = new SelectionTreeNode(path);
-};
-
-var HistoryListBehavior = {
-  properties: {
-    selectedPaths: {
-      type: Object,
-      value: function() {
-        return new Set();
-      }
-    },
-    lastSelectedPath: String
-  },
-  listeners: {
-    'history-checkbox-select': 'itemSelected_'
-  },
-  hasResults: function(historyDataLength) {
-    return historyDataLength > 0;
-  },
-  noResultsMessage: function(searchedTerm, isLoading) {
-    if (isLoading) return '';
-    var messageId = searchedTerm !== '' ? 'noSearchResults' : 'noResults';
-    return loadTimeData.getString(messageId);
-  },
-  unselectAllItems: function() {
-    this.selectedPaths.forEach(function(path) {
-      this.set(path + '.selected', false);
-    }.bind(this));
-    this.selectedPaths.clear();
-  },
-  deleteSelected: function() {
-    var toBeRemoved = Array.from(this.selectedPaths.values()).map(function(path) {
-      return this.get(path);
-    }.bind(this));
-    md_history.BrowserService.getInstance().deleteItems(toBeRemoved).then(function() {
-      this.removeItemsByPath(Array.from(this.selectedPaths));
-      this.fire('unselect-all');
-    }.bind(this));
-  },
-  removeItemsByPath: function(paths) {
-    if (paths.length == 0) return;
-    this.removeItemsBeneathNode_(this.buildRemovalTree_(paths));
-  },
-  buildRemovalTree_: function(paths) {
-    var rootNode = new SelectionTreeNode(paths[0].split('.')[0]);
-    paths.forEach(function(path) {
-      var components = path.split('.');
-      var node = rootNode;
-      components.shift();
-      while (components.length > 1) {
-        var index = Number(components.shift());
-        var arrayName = components.shift();
-        if (!node.children[index]) node.addChild(index, [ node.currentPath, index, arrayName ].join('.'));
-        node = node.children[index];
-      }
-      node.leaf = true;
-      node.indexes.push(Number(components.shift()));
-    });
-    return rootNode;
-  },
-  removeItemsBeneathNode_: function(node) {
-    var array = this.get(node.currentPath);
-    var splices = [];
-    node.indexes.sort(function(a, b) {
-      return b - a;
-    });
-    node.indexes.forEach(function(index) {
-      if (node.leaf || this.removeItemsBeneathNode_(node.children[index])) {
-        var item = array.splice(index, 1)[0];
-        splices.push({
-          index: index,
-          removed: [ item ],
-          addedCount: 0,
-          object: array,
-          type: 'splice'
-        });
-      }
-    }.bind(this));
-    if (array.length == 0 && node.currentPath.indexOf('.') != -1) return true;
-    this.notifySplices(node.currentPath, splices);
-    return false;
-  },
-  itemSelected_: function(e) {
-    var item = e.detail.element;
-    var paths = [];
-    var itemPath = item.path;
-    if (e.detail.shiftKey && this.lastSelectedPath) {
-      var itemPathComponents = itemPath.split('.');
-      var itemIndex = Number(itemPathComponents.pop());
-      var itemArrayPath = itemPathComponents.join('.');
-      var lastItemPathComponents = this.lastSelectedPath.split('.');
-      var lastItemIndex = Number(lastItemPathComponents.pop());
-      if (itemArrayPath == lastItemPathComponents.join('.')) {
-        for (var i = Math.min(itemIndex, lastItemIndex); i <= Math.max(itemIndex, lastItemIndex); i++) {
-          paths.push(itemArrayPath + '.' + i);
-        }
-      }
-    }
-    if (paths.length == 0) paths.push(item.path);
-    var selected = !this.selectedPaths.has(item.path);
-    paths.forEach(function(path) {
-      this.set(path + '.selected', selected);
-      if (selected) {
-        this.selectedPaths.add(path);
-        return;
-      }
-      this.selectedPaths.delete(path);
-    }.bind(this));
-    this.lastSelectedPath = itemPath;
-  }
-};
-
+var SelectionTreeNode=function(currentPath){this.currentPath=currentPath;this.leaf=false;this.indexes=[];this.children=[]};SelectionTreeNode.prototype.addChild=function(index,path){this.indexes.push(index);this.children[index]=new SelectionTreeNode(path)};var HistoryListBehavior={properties:{selectedPaths:{type:Object,value:function(){return new Set}},lastSelectedPath:String},listeners:{"history-checkbox-select":"itemSelected_"},hasResults:function(historyDataLength){return historyDataLength>0},noResultsMessage:function(searchedTerm,isLoading){if(isLoading)return"";var messageId=searchedTerm!==""?"noSearchResults":"noResults";return loadTimeData.getString(messageId)},unselectAllItems:function(){this.selectedPaths.forEach(function(path){this.set(path+".selected",false)}.bind(this));this.selectedPaths.clear()},deleteSelected:function(){var toBeRemoved=Array.from(this.selectedPaths.values()).map(function(path){return this.get(path)}.bind(this));md_history.BrowserService.getInstance().deleteItems(toBeRemoved).then(function(){this.removeItemsByPath(Array.from(this.selectedPaths));this.fire("unselect-all")}.bind(this))},removeItemsByPath:function(paths){if(paths.length==0)return;this.removeItemsBeneathNode_(this.buildRemovalTree_(paths))},buildRemovalTree_:function(paths){var rootNode=new SelectionTreeNode(paths[0].split(".")[0]);paths.forEach(function(path){var components=path.split(".");var node=rootNode;components.shift();while(components.length>1){var index=Number(components.shift());var arrayName=components.shift();if(!node.children[index])node.addChild(index,[node.currentPath,index,arrayName].join("."));node=node.children[index]}node.leaf=true;node.indexes.push(Number(components.shift()))});return rootNode},removeItemsBeneathNode_:function(node){var array=this.get(node.currentPath);var splices=[];node.indexes.sort(function(a,b){return b-a});node.indexes.forEach(function(index){if(node.leaf||this.removeItemsBeneathNode_(node.children[index])){var item=array.splice(index,1)[0];splices.push({index:index,removed:[item],addedCount:0,object:array,type:"splice"})}}.bind(this));if(array.length==0&&node.currentPath.indexOf(".")!=-1)return true;this.notifySplices(node.currentPath,splices);return false},itemSelected_:function(e){var item=e.detail.element;var paths=[];var itemPath=item.path;if(e.detail.shiftKey&&this.lastSelectedPath){var itemPathComponents=itemPath.split(".");var itemIndex=Number(itemPathComponents.pop());var itemArrayPath=itemPathComponents.join(".");var lastItemPathComponents=this.lastSelectedPath.split(".");var lastItemIndex=Number(lastItemPathComponents.pop());if(itemArrayPath==lastItemPathComponents.join(".")){for(var i=Math.min(itemIndex,lastItemIndex);i<=Math.max(itemIndex,lastItemIndex);i++){paths.push(itemArrayPath+"."+i)}}}if(paths.length==0)paths.push(item.path);var selected=!this.selectedPaths.has(item.path);paths.forEach(function(path){this.set(path+".selected",selected);if(selected){this.selectedPaths.add(path);return}this.selectedPaths.delete(path)}.bind(this));this.lastSelectedPath=itemPath}};
 // 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.
-Polymer({
-  is: 'history-list',
-  behaviors: [ HistoryListBehavior ],
-  properties: {
-    searchedTerm: {
-      type: String,
-      value: ''
-    },
-    querying: Boolean,
-    historyData_: Array,
-    resultLoadingDisabled_: {
-      type: Boolean,
-      value: false
-    },
-    lastFocused_: Object
-  },
-  listeners: {
-    scroll: 'notifyListScroll_',
-    'remove-bookmark-stars': 'removeBookmarkStars_'
-  },
-  attached: function() {
-    this.$['infinite-list'].notifyResize();
-    this.$['infinite-list'].scrollTarget = this;
-    this.$['scroll-threshold'].scrollTarget = this;
-  },
-  removeBookmarkStars_: function(e) {
-    var url = e.detail;
-    if (this.historyData_ === undefined) return;
-    for (var i = 0; i < this.historyData_.length; i++) {
-      if (this.historyData_[i].url == url) this.set('historyData_.' + i + '.starred', false);
-    }
-  },
-  disableResultLoading: function() {
-    this.resultLoadingDisabled_ = true;
-  },
-  addNewResults: function(historyResults, incremental) {
-    var results = historyResults.slice();
-    this.$['scroll-threshold'].clearTriggers();
-    if (!incremental) {
-      this.resultLoadingDisabled_ = false;
-      if (this.historyData_) this.splice('historyData_', 0, this.historyData_.length);
-      this.fire('unselect-all');
-    }
-    if (this.historyData_) {
-      results.unshift('historyData_');
-      this.push.apply(this, results);
-    } else {
-      this.set('historyData_', results);
-    }
-  },
-  loadMoreData_: function() {
-    if (this.resultLoadingDisabled_ || this.querying) return;
-    this.fire('load-more-history');
-  },
-  needsTimeGap_: function(item, index, length) {
-    return md_history.HistoryItem.needsTimeGap(this.historyData_, index, this.searchedTerm);
-  },
-  isCardStart_: function(item, i, length) {
-    if (length == 0 || i > length - 1) return false;
-    return i == 0 || this.historyData_[i].dateRelativeDay != this.historyData_[i - 1].dateRelativeDay;
-  },
-  isCardEnd_: function(item, i, length) {
-    if (length == 0 || i > length - 1) return false;
-    return i == length - 1 || this.historyData_[i].dateRelativeDay != this.historyData_[i + 1].dateRelativeDay;
-  },
-  notifyListScroll_: function() {
-    this.fire('history-list-scrolled');
-  },
-  pathForItem_: function(index) {
-    return 'historyData_.' + index;
-  }
-});
-
+Polymer({is:"history-list",behaviors:[HistoryListBehavior],properties:{searchedTerm:{type:String,value:""},querying:Boolean,historyData_:Array,resultLoadingDisabled_:{type:Boolean,value:false},lastFocused_:Object},listeners:{scroll:"notifyListScroll_","remove-bookmark-stars":"removeBookmarkStars_"},attached:function(){this.$["infinite-list"].notifyResize();this.$["infinite-list"].scrollTarget=this;this.$["scroll-threshold"].scrollTarget=this},removeBookmarkStars_:function(e){var url=e.detail;if(this.historyData_===undefined)return;for(var i=0;i<this.historyData_.length;i++){if(this.historyData_[i].url==url)this.set("historyData_."+i+".starred",false)}},disableResultLoading:function(){this.resultLoadingDisabled_=true},addNewResults:function(historyResults,incremental){var results=historyResults.slice();this.$["scroll-threshold"].clearTriggers();if(!incremental){this.resultLoadingDisabled_=false;if(this.historyData_)this.splice("historyData_",0,this.historyData_.length);this.fire("unselect-all")}if(this.historyData_){results.unshift("historyData_");this.push.apply(this,results)}else{this.set("historyData_",results)}},loadMoreData_:function(){if(this.resultLoadingDisabled_||this.querying)return;this.fire("load-more-history")},needsTimeGap_:function(item,index,length){return md_history.HistoryItem.needsTimeGap(this.historyData_,index,this.searchedTerm)},isCardStart_:function(item,i,length){if(length==0||i>length-1)return false;return i==0||this.historyData_[i].dateRelativeDay!=this.historyData_[i-1].dateRelativeDay},isCardEnd_:function(item,i,length){if(length==0||i>length-1)return false;return i==length-1||this.historyData_[i].dateRelativeDay!=this.historyData_[i+1].dateRelativeDay},notifyListScroll_:function(){this.fire("history-list-scrolled")},pathForItem_:function(index){return"historyData_."+index}});
 // 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.
-Polymer({
-  is: 'history-list-container',
-  properties: {
-    selectedPage_: String,
-    grouped: Boolean,
-    groupedRange: {
-      type: Number,
-      observer: 'groupedRangeChanged_'
-    },
-    queryState: Object,
-    queryResult: Object
-  },
-  observers: [ 'searchTermChanged_(queryState.searchTerm)' ],
-  listeners: {
-    'history-list-scrolled': 'closeMenu_',
-    'load-more-history': 'loadMoreHistory_',
-    'toggle-menu': 'toggleMenu_'
-  },
-  historyResult: function(info, results) {
-    this.initializeResults_(info, results);
-    this.closeMenu_();
-    if (this.selectedPage_ == 'grouped-list') {
-      this.$$('#grouped-list').historyData = results;
-      return;
-    }
-    var list = this.$['infinite-list'];
-    list.addNewResults(results, this.queryState.incremental);
-    if (info.finished) list.disableResultLoading();
-  },
-  queryHistory: function(incremental) {
-    var queryState = this.queryState;
-    var noResults = !this.queryResult || this.queryResult.results == null;
-    if (queryState.queryingDisabled || !this.queryState.searchTerm && noResults) {
-      return;
-    }
-    var dialog = this.$.dialog.getIfExists();
-    if (!incremental && dialog && dialog.open) dialog.close();
-    this.set('queryState.querying', true);
-    this.set('queryState.incremental', incremental);
-    var lastVisitTime = 0;
-    if (incremental) {
-      var lastVisit = this.queryResult.results.slice(-1)[0];
-      lastVisitTime = lastVisit ? lastVisit.time : 0;
-    }
-    var maxResults = this.groupedRange == HistoryRange.ALL_TIME ? RESULTS_PER_PAGE : 0;
-    chrome.send('queryHistory', [ queryState.searchTerm, queryState.groupedOffset, queryState.range, lastVisitTime, maxResults ]);
-  },
-  historyDeleted: function() {
-    if (this.getSelectedItemCount() > 0) return;
-    this.queryHistory(false);
-  },
-  getContentScrollTarget: function() {
-    return this.getSelectedList_();
-  },
-  getSelectedItemCount: function() {
-    return this.getSelectedList_().selectedPaths.size;
-  },
-  unselectAllItems: function(count) {
-    var selectedList = this.getSelectedList_();
-    if (selectedList) selectedList.unselectAllItems(count);
-  },
-  deleteSelectedWithPrompt: function() {
-    if (!loadTimeData.getBoolean('allowDeletingHistory')) return;
-    var browserService = md_history.BrowserService.getInstance();
-    browserService.recordAction('RemoveSelected');
-    if (this.queryState.searchTerm != '') browserService.recordAction('SearchResultRemove');
-    this.$.dialog.get().showModal();
-  },
-  groupedRangeChanged_: function(range, oldRange) {
-    this.selectedPage_ = range == HistoryRange.ALL_TIME ? 'infinite-list' : 'grouped-list';
-    if (oldRange == undefined) return;
-    this.queryHistory(false);
-    this.fire('history-view-changed');
-  },
-  searchTermChanged_: function() {
-    this.queryHistory(false);
-    if (this.queryState.searchTerm) md_history.BrowserService.getInstance().recordAction('Search');
-  },
-  loadMoreHistory_: function() {
-    this.queryHistory(true);
-  },
-  initializeResults_: function(info, results) {
-    if (results.length == 0) return;
-    var currentDate = results[0].dateRelativeDay;
-    for (var i = 0; i < results.length; i++) {
-      results[i].selected = false;
-      results[i].readableTimestamp = info.term == '' ? results[i].dateTimeOfDay : results[i].dateShort;
-      if (results[i].dateRelativeDay != currentDate) {
-        currentDate = results[i].dateRelativeDay;
-      }
-    }
-  },
-  onDialogConfirmTap_: function() {
-    md_history.BrowserService.getInstance().recordAction('ConfirmRemoveSelected');
-    this.getSelectedList_().deleteSelected();
-    var dialog = assert(this.$.dialog.getIfExists());
-    dialog.close();
-  },
-  onDialogCancelTap_: function() {
-    md_history.BrowserService.getInstance().recordAction('CancelRemoveSelected');
-    var dialog = assert(this.$.dialog.getIfExists());
-    dialog.close();
-  },
-  closeMenu_: function() {
-    var menu = this.$.sharedMenu.getIfExists();
-    if (menu) menu.closeMenu();
-  },
-  toggleMenu_: function(e) {
-    var target = e.detail.target;
-    var menu = this.$.sharedMenu.get();
-    menu.toggleMenu(target, e.detail);
-  },
-  onMoreFromSiteTap_: function() {
-    md_history.BrowserService.getInstance().recordAction('EntryMenuShowMoreFromSite');
-    var menu = assert(this.$.sharedMenu.getIfExists());
-    this.set('queryState.searchTerm', menu.itemData.item.domain);
-    menu.closeMenu();
-  },
-  onRemoveFromHistoryTap_: function() {
-    var browserService = md_history.BrowserService.getInstance();
-    browserService.recordAction('EntryMenuRemoveFromHistory');
-    var menu = assert(this.$.sharedMenu.getIfExists());
-    var itemData = menu.itemData;
-    browserService.deleteItems([ itemData.item ]).then(function(items) {
-      this.getSelectedList_().removeItemsByPath([ itemData.path ]);
-      this.fire('unselect-all');
-      var index = itemData.index;
-      if (index == undefined) return;
-      var browserService = md_history.BrowserService.getInstance();
-      browserService.recordHistogram('HistoryPage.RemoveEntryPosition', index, UMA_MAX_BUCKET_VALUE);
-      if (index <= UMA_MAX_SUBSET_BUCKET_VALUE) {
-        browserService.recordHistogram('HistoryPage.RemoveEntryPositionSubset', index, UMA_MAX_SUBSET_BUCKET_VALUE);
-      }
-    }.bind(this));
-    menu.closeMenu();
-  },
-  getSelectedList_: function() {
-    return this.$.content.selectedItem;
-  }
-});
-
-(function() {
-  'use strict';
-  Polymer({
-    is: 'iron-location',
-    properties: {
-      path: {
-        type: String,
-        notify: true,
-        value: function() {
-          return window.decodeURIComponent(window.location.pathname);
-        }
-      },
-      query: {
-        type: String,
-        notify: true,
-        value: function() {
-          return window.decodeURIComponent(window.location.search.slice(1));
-        }
-      },
-      hash: {
-        type: String,
-        notify: true,
-        value: function() {
-          return window.decodeURIComponent(window.location.hash.slice(1));
-        }
-      },
-      dwellTime: {
-        type: Number,
-        value: 2e3
-      },
-      urlSpaceRegex: {
-        type: String,
-        value: ''
-      },
-      _urlSpaceRegExp: {
-        computed: '_makeRegExp(urlSpaceRegex)'
-      },
-      _lastChangedAt: {
-        type: Number
-      },
-      _initialized: {
-        type: Boolean,
-        value: false
-      }
-    },
-    hostAttributes: {
-      hidden: true
-    },
-    observers: [ '_updateUrl(path, query, hash)' ],
-    attached: function() {
-      this.listen(window, 'hashchange', '_hashChanged');
-      this.listen(window, 'location-changed', '_urlChanged');
-      this.listen(window, 'popstate', '_urlChanged');
-      this.listen(document.body, 'click', '_globalOnClick');
-      this._lastChangedAt = window.performance.now() - (this.dwellTime - 200);
-      this._initialized = true;
-      this._urlChanged();
-    },
-    detached: function() {
-      this.unlisten(window, 'hashchange', '_hashChanged');
-      this.unlisten(window, 'location-changed', '_urlChanged');
-      this.unlisten(window, 'popstate', '_urlChanged');
-      this.unlisten(document.body, 'click', '_globalOnClick');
-      this._initialized = false;
-    },
-    _hashChanged: function() {
-      this.hash = window.decodeURIComponent(window.location.hash.substring(1));
-    },
-    _urlChanged: function() {
-      this._dontUpdateUrl = true;
-      this._hashChanged();
-      this.path = window.decodeURIComponent(window.location.pathname);
-      this.query = window.decodeURIComponent(window.location.search.substring(1));
-      this._dontUpdateUrl = false;
-      this._updateUrl();
-    },
-    _getUrl: function() {
-      var partiallyEncodedPath = window.encodeURI(this.path).replace(/\#/g, '%23').replace(/\?/g, '%3F');
-      var partiallyEncodedQuery = '';
-      if (this.query) {
-        partiallyEncodedQuery = '?' + window.encodeURI(this.query).replace(/\#/g, '%23');
-      }
-      var partiallyEncodedHash = '';
-      if (this.hash) {
-        partiallyEncodedHash = '#' + window.encodeURI(this.hash);
-      }
-      return partiallyEncodedPath + partiallyEncodedQuery + partiallyEncodedHash;
-    },
-    _updateUrl: function() {
-      if (this._dontUpdateUrl || !this._initialized) {
-        return;
-      }
-      if (this.path === window.decodeURIComponent(window.location.pathname) && this.query === window.decodeURIComponent(window.location.search.substring(1)) && this.hash === window.decodeURIComponent(window.location.hash.substring(1))) {
-        return;
-      }
-      var newUrl = this._getUrl();
-      var fullNewUrl = new URL(newUrl, window.location.protocol + '//' + window.location.host).href;
-      var now = window.performance.now();
-      var shouldReplace = this._lastChangedAt + this.dwellTime > now;
-      this._lastChangedAt = now;
-      if (shouldReplace) {
-        window.history.replaceState({}, '', fullNewUrl);
-      } else {
-        window.history.pushState({}, '', fullNewUrl);
-      }
-      this.fire('location-changed', {}, {
-        node: window
-      });
-    },
-    _globalOnClick: function(event) {
-      if (event.defaultPrevented) {
-        return;
-      }
-      var href = this._getSameOriginLinkHref(event);
-      if (!href) {
-        return;
-      }
-      event.preventDefault();
-      if (href === window.location.href) {
-        return;
-      }
-      window.history.pushState({}, '', href);
-      this.fire('location-changed', {}, {
-        node: window
-      });
-    },
-    _getSameOriginLinkHref: function(event) {
-      if (event.button !== 0) {
-        return null;
-      }
-      if (event.metaKey || event.ctrlKey) {
-        return null;
-      }
-      var eventPath = Polymer.dom(event).path;
-      var anchor = null;
-      for (var i = 0; i < eventPath.length; i++) {
-        var element = eventPath[i];
-        if (element.tagName === 'A' && element.href) {
-          anchor = element;
-          break;
-        }
-      }
-      if (!anchor) {
-        return null;
-      }
-      if (anchor.target === '_blank') {
-        return null;
-      }
-      if ((anchor.target === '_top' || anchor.target === '_parent') && window.top !== window) {
-        return null;
-      }
-      var href = anchor.href;
-      var url;
-      if (document.baseURI != null) {
-        url = new URL(href, document.baseURI);
-      } else {
-        url = new URL(href);
-      }
-      var origin;
-      if (window.location.origin) {
-        origin = window.location.origin;
-      } else {
-        origin = window.location.protocol + '//' + window.location.hostname;
-        if (window.location.port) {
-          origin += ':' + window.location.port;
-        }
-      }
-      if (url.origin !== origin) {
-        return null;
-      }
-      var normalizedHref = url.pathname + url.search + url.hash;
-      if (this._urlSpaceRegExp && !this._urlSpaceRegExp.test(normalizedHref)) {
-        return null;
-      }
-      var fullNormalizedHref = new URL(normalizedHref, window.location.href).href;
-      return fullNormalizedHref;
-    },
-    _makeRegExp: function(urlSpaceRegex) {
-      return RegExp(urlSpaceRegex);
-    }
-  });
-})();
-
-'use strict';
-
-Polymer({
-  is: 'iron-query-params',
-  properties: {
-    paramsString: {
-      type: String,
-      notify: true,
-      observer: 'paramsStringChanged'
-    },
-    paramsObject: {
-      type: Object,
-      notify: true,
-      value: function() {
-        return {};
-      }
-    },
-    _dontReact: {
-      type: Boolean,
-      value: false
-    }
-  },
-  hostAttributes: {
-    hidden: true
-  },
-  observers: [ 'paramsObjectChanged(paramsObject.*)' ],
-  paramsStringChanged: function() {
-    this._dontReact = true;
-    this.paramsObject = this._decodeParams(this.paramsString);
-    this._dontReact = false;
-  },
-  paramsObjectChanged: function() {
-    if (this._dontReact) {
-      return;
-    }
-    this.paramsString = this._encodeParams(this.paramsObject);
-  },
-  _encodeParams: function(params) {
-    var encodedParams = [];
-    for (var key in params) {
-      var value = params[key];
-      if (value === '') {
-        encodedParams.push(encodeURIComponent(key));
-      } else if (value) {
-        encodedParams.push(encodeURIComponent(key) + '=' + encodeURIComponent(value.toString()));
-      }
-    }
-    return encodedParams.join('&');
-  },
-  _decodeParams: function(paramString) {
-    var params = {};
-    paramString = (paramString || '').replace(/\+/g, '%20');
-    var paramList = paramString.split('&');
-    for (var i = 0; i < paramList.length; i++) {
-      var param = paramList[i].split('=');
-      if (param[0]) {
-        params[decodeURIComponent(param[0])] = decodeURIComponent(param[1] || '');
-      }
-    }
-    return params;
-  }
-});
-
+Polymer({is:"history-list-container",properties:{selectedPage_:String,grouped:Boolean,groupedRange:{type:Number,observer:"groupedRangeChanged_"},queryState:Object,queryResult:Object},observers:["searchTermChanged_(queryState.searchTerm)"],listeners:{"history-list-scrolled":"closeMenu_","load-more-history":"loadMoreHistory_","toggle-menu":"toggleMenu_"},historyResult:function(info,results){this.initializeResults_(info,results);this.closeMenu_();if(this.selectedPage_=="grouped-list"){this.$$("#grouped-list").historyData=results;return}var list=this.$["infinite-list"];list.addNewResults(results,this.queryState.incremental);if(info.finished)list.disableResultLoading()},queryHistory:function(incremental){var queryState=this.queryState;var noResults=!this.queryResult||this.queryResult.results==null;if(queryState.queryingDisabled||!this.queryState.searchTerm&&noResults){return}var dialog=this.$.dialog.getIfExists();if(!incremental&&dialog&&dialog.open)dialog.close();this.set("queryState.querying",true);this.set("queryState.incremental",incremental);var lastVisitTime=0;if(incremental){var lastVisit=this.queryResult.results.slice(-1)[0];lastVisitTime=lastVisit?lastVisit.time:0}var maxResults=this.groupedRange==HistoryRange.ALL_TIME?RESULTS_PER_PAGE:0;chrome.send("queryHistory",[queryState.searchTerm,queryState.groupedOffset,queryState.range,lastVisitTime,maxResults])},historyDeleted:function(){if(this.getSelectedItemCount()>0)return;this.queryHistory(false)},getContentScrollTarget:function(){return this.getSelectedList_()},getSelectedItemCount:function(){return this.getSelectedList_().selectedPaths.size},unselectAllItems:function(count){var selectedList=this.getSelectedList_();if(selectedList)selectedList.unselectAllItems(count)},deleteSelectedWithPrompt:function(){if(!loadTimeData.getBoolean("allowDeletingHistory"))return;var browserService=md_history.BrowserService.getInstance();browserService.recordAction("RemoveSelected");if(this.queryState.searchTerm!="")browserService.recordAction("SearchResultRemove");this.$.dialog.get().showModal()},groupedRangeChanged_:function(range,oldRange){this.selectedPage_=range==HistoryRange.ALL_TIME?"infinite-list":"grouped-list";if(oldRange==undefined)return;this.queryHistory(false);this.fire("history-view-changed")},searchTermChanged_:function(){this.queryHistory(false);if(this.queryState.searchTerm)md_history.BrowserService.getInstance().recordAction("Search")},loadMoreHistory_:function(){this.queryHistory(true)},initializeResults_:function(info,results){if(results.length==0)return;var currentDate=results[0].dateRelativeDay;for(var i=0;i<results.length;i++){results[i].selected=false;results[i].readableTimestamp=info.term==""?results[i].dateTimeOfDay:results[i].dateShort;if(results[i].dateRelativeDay!=currentDate){currentDate=results[i].dateRelativeDay}}},onDialogConfirmTap_:function(){md_history.BrowserService.getInstance().recordAction("ConfirmRemoveSelected");this.getSelectedList_().deleteSelected();var dialog=assert(this.$.dialog.getIfExists());dialog.close()},onDialogCancelTap_:function(){md_history.BrowserService.getInstance().recordAction("CancelRemoveSelected");var dialog=assert(this.$.dialog.getIfExists());dialog.close()},closeMenu_:function(){var menu=this.$.sharedMenu.getIfExists();if(menu)menu.closeMenu()},toggleMenu_:function(e){var target=e.detail.target;var menu=this.$.sharedMenu.get();menu.toggleMenu(target,e.detail)},onMoreFromSiteTap_:function(){md_history.BrowserService.getInstance().recordAction("EntryMenuShowMoreFromSite");var menu=assert(this.$.sharedMenu.getIfExists());this.set("queryState.searchTerm",menu.itemData.item.domain);menu.closeMenu()},onRemoveFromHistoryTap_:function(){var browserService=md_history.BrowserService.getInstance();browserService.recordAction("EntryMenuRemoveFromHistory");var menu=assert(this.$.sharedMenu.getIfExists());var itemData=menu.itemData;browserService.deleteItems([itemData.item]).then(function(items){this.fire("unselect-all");this.getSelectedList_().removeItemsByPath([itemData.path]);var index=itemData.index;if(index==undefined)return;var browserService=md_history.BrowserService.getInstance();browserService.recordHistogram("HistoryPage.RemoveEntryPosition",index,UMA_MAX_BUCKET_VALUE);if(index<=UMA_MAX_SUBSET_BUCKET_VALUE){browserService.recordHistogram("HistoryPage.RemoveEntryPositionSubset",index,UMA_MAX_SUBSET_BUCKET_VALUE)}}.bind(this));menu.closeMenu()},getSelectedList_:function(){return this.$.content.selectedItem}});(function(){"use strict";Polymer({is:"iron-location",properties:{path:{type:String,notify:true,value:function(){return window.decodeURIComponent(window.location.pathname)}},query:{type:String,notify:true,value:function(){return window.decodeURIComponent(window.location.search.slice(1))}},hash:{type:String,notify:true,value:function(){return window.decodeURIComponent(window.location.hash.slice(1))}},dwellTime:{type:Number,value:2e3},urlSpaceRegex:{type:String,value:""},_urlSpaceRegExp:{computed:"_makeRegExp(urlSpaceRegex)"},_lastChangedAt:{type:Number},_initialized:{type:Boolean,value:false}},hostAttributes:{hidden:true},observers:["_updateUrl(path, query, hash)"],attached:function(){this.listen(window,"hashchange","_hashChanged");this.listen(window,"location-changed","_urlChanged");this.listen(window,"popstate","_urlChanged");this.listen(document.body,"click","_globalOnClick");this._lastChangedAt=window.performance.now()-(this.dwellTime-200);this._initialized=true;this._urlChanged()},detached:function(){this.unlisten(window,"hashchange","_hashChanged");this.unlisten(window,"location-changed","_urlChanged");this.unlisten(window,"popstate","_urlChanged");this.unlisten(document.body,"click","_globalOnClick");this._initialized=false},_hashChanged:function(){this.hash=window.decodeURIComponent(window.location.hash.substring(1))},_urlChanged:function(){this._dontUpdateUrl=true;this._hashChanged();this.path=window.decodeURIComponent(window.location.pathname);this.query=window.decodeURIComponent(window.location.search.substring(1));this._dontUpdateUrl=false;this._updateUrl()},_getUrl:function(){var partiallyEncodedPath=window.encodeURI(this.path).replace(/\#/g,"%23").replace(/\?/g,"%3F");var partiallyEncodedQuery="";if(this.query){partiallyEncodedQuery="?"+window.encodeURI(this.query).replace(/\#/g,"%23")}var partiallyEncodedHash="";if(this.hash){partiallyEncodedHash="#"+window.encodeURI(this.hash)}return partiallyEncodedPath+partiallyEncodedQuery+partiallyEncodedHash},_updateUrl:function(){if(this._dontUpdateUrl||!this._initialized){return}if(this.path===window.decodeURIComponent(window.location.pathname)&&this.query===window.decodeURIComponent(window.location.search.substring(1))&&this.hash===window.decodeURIComponent(window.location.hash.substring(1))){return}var newUrl=this._getUrl();var fullNewUrl=new URL(newUrl,window.location.protocol+"//"+window.location.host).href;var now=window.performance.now();var shouldReplace=this._lastChangedAt+this.dwellTime>now;this._lastChangedAt=now;if(shouldReplace){window.history.replaceState({},"",fullNewUrl)}else{window.history.pushState({},"",fullNewUrl)}this.fire("location-changed",{},{node:window})},_globalOnClick:function(event){if(event.defaultPrevented){return}var href=this._getSameOriginLinkHref(event);if(!href){return}event.preventDefault();if(href===window.location.href){return}window.history.pushState({},"",href);this.fire("location-changed",{},{node:window})},_getSameOriginLinkHref:function(event){if(event.button!==0){return null}if(event.metaKey||event.ctrlKey){return null}var eventPath=Polymer.dom(event).path;var anchor=null;for(var i=0;i<eventPath.length;i++){var element=eventPath[i];if(element.tagName==="A"&&element.href){anchor=element;break}}if(!anchor){return null}if(anchor.target==="_blank"){return null}if((anchor.target==="_top"||anchor.target==="_parent")&&window.top!==window){return null}var href=anchor.href;var url;if(document.baseURI!=null){url=new URL(href,document.baseURI)}else{url=new URL(href)}var origin;if(window.location.origin){origin=window.location.origin}else{origin=window.location.protocol+"//"+window.location.hostname;if(window.location.port){origin+=":"+window.location.port}}if(url.origin!==origin){return null}var normalizedHref=url.pathname+url.search+url.hash;if(this._urlSpaceRegExp&&!this._urlSpaceRegExp.test(normalizedHref)){return null}var fullNormalizedHref=new URL(normalizedHref,window.location.href).href;return fullNormalizedHref},_makeRegExp:function(urlSpaceRegex){return RegExp(urlSpaceRegex)}})})();"use strict";Polymer({is:"iron-query-params",properties:{paramsString:{type:String,notify:true,observer:"paramsStringChanged"},paramsObject:{type:Object,notify:true,value:function(){return{}}},_dontReact:{type:Boolean,value:false}},hostAttributes:{hidden:true},observers:["paramsObjectChanged(paramsObject.*)"],paramsStringChanged:function(){this._dontReact=true;this.paramsObject=this._decodeParams(this.paramsString);this._dontReact=false},paramsObjectChanged:function(){if(this._dontReact){return}this.paramsString=this._encodeParams(this.paramsObject)},_encodeParams:function(params){var encodedParams=[];for(var key in params){var value=params[key];if(value===""){encodedParams.push(encodeURIComponent(key))}else if(value){encodedParams.push(encodeURIComponent(key)+"="+encodeURIComponent(value.toString()))}}return encodedParams.join("&")},_decodeParams:function(paramString){var params={};paramString=(paramString||"").replace(/\+/g,"%20");var paramList=paramString.split("&");for(var i=0;i<paramList.length;i++){var param=paramList[i].split("=");if(param[0]){params[decodeURIComponent(param[0])]=decodeURIComponent(param[1]||"")}}return params}});
 // 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.
-Polymer({
-  is: 'history-router',
-  properties: {
-    selectedPage: {
-      type: String,
-      observer: 'serializePath_',
-      notify: true
-    },
-    queryState: {
-      type: Object,
-      notify: true
-    },
-    path_: {
-      type: String,
-      observer: 'pathChanged_'
-    },
-    queryParams_: Object
-  },
-  observers: [ 'queryParamsChanged_(queryParams_.*)', 'searchTermChanged_(queryState.searchTerm)' ],
-  attached: function() {
-    if (window.location.hash) {
-      window.location.href = window.location.href.split('#')[0] + '?' + window.location.hash.substr(1);
-    }
-  },
-  serializePath_: function() {
-    var page = this.selectedPage == 'history' ? '' : this.selectedPage;
-    this.path_ = '/' + page;
-  },
-  pathChanged_: function() {
-    var sections = this.path_.substr(1).split('/');
-    this.selectedPage = sections[0] || 'history';
-  },
-  queryParamsChanged_: function() {
-    this.set('queryState.searchTerm', this.queryParams_.q || '');
-  },
-  searchTermChanged_: function() {
-    this.set('queryParams_.q', this.queryState.searchTerm || null);
-  }
-});
-
-Polymer.IronMultiSelectableBehaviorImpl = {
-  properties: {
-    multi: {
-      type: Boolean,
-      value: false,
-      observer: 'multiChanged'
-    },
-    selectedValues: {
-      type: Array,
-      notify: true
-    },
-    selectedItems: {
-      type: Array,
-      readOnly: true,
-      notify: true
-    }
-  },
-  observers: [ '_updateSelected(selectedValues.splices)' ],
-  select: function(value) {
-    if (this.multi) {
-      if (this.selectedValues) {
-        this._toggleSelected(value);
-      } else {
-        this.selectedValues = [ value ];
-      }
-    } else {
-      this.selected = value;
-    }
-  },
-  multiChanged: function(multi) {
-    this._selection.multi = multi;
-  },
-  get _shouldUpdateSelection() {
-    return this.selected != null || this.selectedValues != null && this.selectedValues.length;
-  },
-  _updateAttrForSelected: function() {
-    if (!this.multi) {
-      Polymer.IronSelectableBehavior._updateAttrForSelected.apply(this);
-    } else if (this._shouldUpdateSelection) {
-      this.selectedValues = this.selectedItems.map(function(selectedItem) {
-        return this._indexToValue(this.indexOf(selectedItem));
-      }, this).filter(function(unfilteredValue) {
-        return unfilteredValue != null;
-      }, this);
-    }
-  },
-  _updateSelected: function() {
-    if (this.multi) {
-      this._selectMulti(this.selectedValues);
-    } else {
-      this._selectSelected(this.selected);
-    }
-  },
-  _selectMulti: function(values) {
-    if (values) {
-      var selectedItems = this._valuesToItems(values);
-      this._selection.clear(selectedItems);
-      for (var i = 0; i < selectedItems.length; i++) {
-        this._selection.setItemSelected(selectedItems[i], true);
-      }
-      if (this.fallbackSelection && this.items.length && !this._selection.get().length) {
-        var fallback = this._valueToItem(this.fallbackSelection);
-        if (fallback) {
-          this.selectedValues = [ this.fallbackSelection ];
-        }
-      }
-    } else {
-      this._selection.clear();
-    }
-  },
-  _selectionChange: function() {
-    var s = this._selection.get();
-    if (this.multi) {
-      this._setSelectedItems(s);
-    } else {
-      this._setSelectedItems([ s ]);
-      this._setSelectedItem(s);
-    }
-  },
-  _toggleSelected: function(value) {
-    var i = this.selectedValues.indexOf(value);
-    var unselected = i < 0;
-    if (unselected) {
-      this.push('selectedValues', value);
-    } else {
-      this.splice('selectedValues', i, 1);
-    }
-  },
-  _valuesToItems: function(values) {
-    return values == null ? null : values.map(function(value) {
-      return this._valueToItem(value);
-    }, this);
-  }
-};
-
-Polymer.IronMultiSelectableBehavior = [ Polymer.IronSelectableBehavior, Polymer.IronMultiSelectableBehaviorImpl ];
-
-Polymer({
-  is: 'iron-selector',
-  behaviors: [ Polymer.IronMultiSelectableBehavior ]
-});
-
+Polymer({is:"history-router",properties:{selectedPage:{type:String,observer:"serializePath_",notify:true},queryState:{type:Object,notify:true},path_:{type:String,observer:"pathChanged_"},queryParams_:Object},observers:["queryParamsChanged_(queryParams_.*)","searchTermChanged_(queryState.searchTerm)"],attached:function(){if(window.location.hash){window.location.href=window.location.href.split("#")[0]+"?"+window.location.hash.substr(1)}},serializePath_:function(){var page=this.selectedPage=="history"?"":this.selectedPage;this.path_="/"+page},pathChanged_:function(){var sections=this.path_.substr(1).split("/");this.selectedPage=sections[0]||"history"},queryParamsChanged_:function(){this.set("queryState.searchTerm",this.queryParams_.q||"")},searchTermChanged_:function(){this.set("queryParams_.q",this.queryState.searchTerm||null)}});Polymer.IronMultiSelectableBehaviorImpl={properties:{multi:{type:Boolean,value:false,observer:"multiChanged"},selectedValues:{type:Array,notify:true},selectedItems:{type:Array,readOnly:true,notify:true}},observers:["_updateSelected(selectedValues.splices)"],select:function(value){if(this.multi){if(this.selectedValues){this._toggleSelected(value)}else{this.selectedValues=[value]}}else{this.selected=value}},multiChanged:function(multi){this._selection.multi=multi},get _shouldUpdateSelection(){return this.selected!=null||this.selectedValues!=null&&this.selectedValues.length},_updateAttrForSelected:function(){if(!this.multi){Polymer.IronSelectableBehavior._updateAttrForSelected.apply(this)}else if(this._shouldUpdateSelection){this.selectedValues=this.selectedItems.map(function(selectedItem){return this._indexToValue(this.indexOf(selectedItem))},this).filter(function(unfilteredValue){return unfilteredValue!=null},this)}},_updateSelected:function(){if(this.multi){this._selectMulti(this.selectedValues)}else{this._selectSelected(this.selected)}},_selectMulti:function(values){if(values){var selectedItems=this._valuesToItems(values);this._selection.clear(selectedItems);for(var i=0;i<selectedItems.length;i++){this._selection.setItemSelected(selectedItems[i],true)}if(this.fallbackSelection&&this.items.length&&!this._selection.get().length){var fallback=this._valueToItem(this.fallbackSelection);if(fallback){this.selectedValues=[this.fallbackSelection]}}}else{this._selection.clear()}},_selectionChange:function(){var s=this._selection.get();if(this.multi){this._setSelectedItems(s)}else{this._setSelectedItems([s]);this._setSelectedItem(s)}},_toggleSelected:function(value){var i=this.selectedValues.indexOf(value);var unselected=i<0;if(unselected){this.push("selectedValues",value)}else{this.splice("selectedValues",i,1)}},_valuesToItems:function(values){return values==null?null:values.map(function(value){return this._valueToItem(value)},this)}};Polymer.IronMultiSelectableBehavior=[Polymer.IronSelectableBehavior,Polymer.IronMultiSelectableBehaviorImpl];Polymer({is:"iron-selector",behaviors:[Polymer.IronMultiSelectableBehavior]});
 // 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.
-Polymer({
-  is: 'history-side-bar',
-  behaviors: [ Polymer.IronA11yKeysBehavior ],
-  properties: {
-    selectedPage: {
-      type: String,
-      notify: true
-    },
-    showFooter: Boolean,
-    drawer: {
-      type: Boolean,
-      reflectToAttribute: true
-    }
-  },
-  keyBindings: {
-    'space:keydown': 'onSpacePressed_'
-  },
-  onSpacePressed_: function(e) {
-    e.detail.keyboardEvent.path[0].click();
-  },
-  onSelectorActivate_: function() {
-    this.fire('history-close-drawer');
-  },
-  onClearBrowsingDataTap_: function(e) {
-    var browserService = md_history.BrowserService.getInstance();
-    browserService.recordAction('InitClearBrowsingData');
-    browserService.openClearBrowsingData();
-    this.$['cbd-ripple'].upAction();
-    e.preventDefault();
-  },
-  onItemClick_: function(e) {
-    e.preventDefault();
-  }
-});
-
+Polymer({is:"history-side-bar",behaviors:[Polymer.IronA11yKeysBehavior],properties:{selectedPage:{type:String,notify:true},showFooter:Boolean,drawer:{type:Boolean,reflectToAttribute:true}},keyBindings:{"space:keydown":"onSpacePressed_"},onSpacePressed_:function(e){e.detail.keyboardEvent.path[0].click()},onSelectorActivate_:function(){this.fire("history-close-drawer")},onClearBrowsingDataTap_:function(e){var browserService=md_history.BrowserService.getInstance();browserService.recordAction("InitClearBrowsingData");browserService.openClearBrowsingData();this.$["cbd-ripple"].upAction();e.preventDefault()},onItemClick_:function(e){e.preventDefault()}});
 // 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.
-cr.define('md_history', function() {
-  var lazyLoadPromise = null;
-  function ensureLazyLoaded() {
-    if (!lazyLoadPromise) {
-      lazyLoadPromise = new Promise(function(resolve, reject) {
-        Polymer.Base.importHref('chrome://history/lazy_load.html', resolve, reject, true);
-      });
-    }
-    return lazyLoadPromise;
-  }
-  return {
-    ensureLazyLoaded: ensureLazyLoaded
-  };
-});
-
-Polymer({
-  is: 'history-app',
-  behaviors: [ Polymer.IronScrollTargetBehavior ],
-  properties: {
-    showSidebarFooter: Boolean,
-    hasSyncedResults: Boolean,
-    selectedPage_: {
-      type: String,
-      observer: 'selectedPageChanged_'
-    },
-    grouped_: {
-      type: Boolean,
-      reflectToAttribute: true
-    },
-    queryState_: {
-      type: Object,
-      value: function() {
-        return {
-          incremental: false,
-          querying: true,
-          queryingDisabled: false,
-          _range: HistoryRange.ALL_TIME,
-          searchTerm: '',
-          groupedOffset: 0,
-          set range(val) {
-            this._range = Number(val);
-          },
-          get range() {
-            return this._range;
-          }
-        };
-      }
-    },
-    queryResult_: {
-      type: Object,
-      value: function() {
-        return {
-          info: null,
-          results: null,
-          sessionList: null
-        };
-      }
-    },
-    hasDrawer_: Boolean,
-    isUserSignedIn_: {
-      type: Boolean,
-      value: loadTimeData.getBoolean('isUserSignedIn')
-    },
-    toolbarShadow_: {
-      type: Boolean,
-      reflectToAttribute: true,
-      notify: true
-    }
-  },
-  listeners: {
-    'cr-menu-tap': 'onMenuTap_',
-    'history-checkbox-select': 'checkboxSelected',
-    'unselect-all': 'unselectAll',
-    'delete-selected': 'deleteSelected',
-    'history-close-drawer': 'closeDrawer_',
-    'history-view-changed': 'historyViewChanged_'
-  },
-  ready: function() {
-    this.grouped_ = loadTimeData.getBoolean('groupByDomain');
-    cr.ui.decorate('command', cr.ui.Command);
-    document.addEventListener('canExecute', this.onCanExecute_.bind(this));
-    document.addEventListener('command', this.onCommand_.bind(this));
-  },
-  onFirstRender: function() {
-    setTimeout(function() {
-      chrome.send('metricsHandler:recordTime', [ 'History.ResultsRenderedTime', window.performance.now() ]);
-    });
-    var searchField = this.$.toolbar.searchField;
-    if (!searchField.narrow) {
-      searchField.getSearchInput().focus();
-    }
-    md_history.ensureLazyLoaded();
-  },
-  _scrollHandler: function() {
-    if (this.scrollTarget) this.toolbarShadow_ = this.scrollTarget.scrollTop != 0;
-  },
-  onMenuTap_: function() {
-    var drawer = this.$$('#drawer');
-    if (drawer) drawer.toggle();
-  },
-  checkboxSelected: function(e) {
-    var toolbar = this.$.toolbar;
-    toolbar.count = this.$.history.getSelectedItemCount();
-  },
-  unselectAll: function() {
-    var listContainer = this.$.history;
-    var toolbar = this.$.toolbar;
-    listContainer.unselectAllItems(toolbar.count);
-    toolbar.count = 0;
-  },
-  deleteSelected: function() {
-    this.$.history.deleteSelectedWithPrompt();
-  },
-  historyResult: function(info, results) {
-    this.set('queryState_.querying', false);
-    this.set('queryResult_.info', info);
-    this.set('queryResult_.results', results);
-    var listContainer = this.$['history'];
-    listContainer.historyResult(info, results);
-  },
-  focusToolbarSearchField: function() {
-    this.$.toolbar.showSearchField();
-  },
-  onCanExecute_: function(e) {
-    e = e;
-    switch (e.command.id) {
-     case 'find-command':
-      e.canExecute = true;
-      break;
-
-     case 'slash-command':
-      e.canExecute = !this.$.toolbar.searchField.isSearchFocused();
-      break;
-
-     case 'delete-command':
-      e.canExecute = this.$.toolbar.count > 0;
-      break;
-    }
-  },
-  onCommand_: function(e) {
-    if (e.command.id == 'find-command' || e.command.id == 'slash-command') this.focusToolbarSearchField();
-    if (e.command.id == 'delete-command') this.deleteSelected();
-  },
-  setForeignSessions: function(sessionList, isTabSyncEnabled) {
-    if (!isTabSyncEnabled) {
-      var syncedDeviceManagerElem = this.$$('history-synced-device-manager');
-      if (syncedDeviceManagerElem) syncedDeviceManagerElem.tabSyncDisabled();
-      return;
-    }
-    this.set('queryResult_.sessionList', sessionList);
-  },
-  historyDeleted: function() {
-    this.$.history.historyDeleted();
-  },
-  updateSignInState: function(isUserSignedIn) {
-    this.isUserSignedIn_ = isUserSignedIn;
-  },
-  syncedTabsSelected_: function(selectedPage) {
-    return selectedPage == 'syncedTabs';
-  },
-  shouldShowSpinner_: function(querying, incremental, searchTerm) {
-    return querying && !incremental && searchTerm != '';
-  },
-  showSyncNotice_: function(hasSyncedResults, selectedPage) {
-    return hasSyncedResults && selectedPage != 'syncedTabs';
-  },
-  selectedPageChanged_: function() {
-    this.unselectAll();
-    this.historyViewChanged_();
-  },
-  historyViewChanged_: function() {
-    requestAnimationFrame(function() {
-      if (!this.$.content.selectedItem) return;
-      this.scrollTarget = this.$.content.selectedItem.getContentScrollTarget();
-      this._scrollHandler();
-    }.bind(this));
-    this.recordHistoryPageView_();
-  },
-  getSelectedPage_: function(selectedPage, items) {
-    return selectedPage;
-  },
-  closeDrawer_: function() {
-    var drawer = this.$$('#drawer');
-    if (drawer) drawer.close();
-  },
-  recordHistoryPageView_: function() {
-    var histogramValue = HistoryPageViewHistogram.END;
-    switch (this.selectedPage_) {
-     case 'syncedTabs':
-      histogramValue = this.isUserSignedIn_ ? HistoryPageViewHistogram.SYNCED_TABS : HistoryPageViewHistogram.SIGNIN_PROMO;
-      break;
-
-     default:
-      switch (this.queryState_.range) {
-       case HistoryRange.ALL_TIME:
-        histogramValue = HistoryPageViewHistogram.HISTORY;
-        break;
-
-       case HistoryRange.WEEK:
-        histogramValue = HistoryPageViewHistogram.GROUPED_WEEK;
-        break;
-
-       case HistoryRange.MONTH:
-        histogramValue = HistoryPageViewHistogram.GROUPED_MONTH;
-        break;
-      }
-      break;
-    }
-    md_history.BrowserService.getInstance().recordHistogram('History.HistoryPageView', histogramValue, HistoryPageViewHistogram.END);
-  }
-});
\ No newline at end of file
+cr.define("md_history",function(){var lazyLoadPromise=null;function ensureLazyLoaded(){if(!lazyLoadPromise){lazyLoadPromise=new Promise(function(resolve,reject){Polymer.Base.importHref("chrome://history/lazy_load.html",resolve,reject,true)})}return lazyLoadPromise}return{ensureLazyLoaded:ensureLazyLoaded}});Polymer({is:"history-app",behaviors:[Polymer.IronScrollTargetBehavior],properties:{showSidebarFooter:Boolean,hasSyncedResults:Boolean,selectedPage_:{type:String,observer:"selectedPageChanged_"},grouped_:{type:Boolean,reflectToAttribute:true},queryState_:{type:Object,value:function(){return{incremental:false,querying:true,queryingDisabled:false,_range:HistoryRange.ALL_TIME,searchTerm:"",groupedOffset:0,set range(val){this._range=Number(val)},get range(){return this._range}}}},queryResult_:{type:Object,value:function(){return{info:null,results:null,sessionList:null}}},hasDrawer_:Boolean,isUserSignedIn_:{type:Boolean,value:loadTimeData.getBoolean("isUserSignedIn")},toolbarShadow_:{type:Boolean,reflectToAttribute:true,notify:true}},listeners:{"cr-menu-tap":"onMenuTap_","history-checkbox-select":"checkboxSelected","unselect-all":"unselectAll","delete-selected":"deleteSelected","history-close-drawer":"closeDrawer_","history-view-changed":"historyViewChanged_"},ready:function(){this.grouped_=loadTimeData.getBoolean("groupByDomain");cr.ui.decorate("command",cr.ui.Command);document.addEventListener("canExecute",this.onCanExecute_.bind(this));document.addEventListener("command",this.onCommand_.bind(this))},onFirstRender:function(){setTimeout(function(){chrome.send("metricsHandler:recordTime",["History.ResultsRenderedTime",window.performance.now()])});var searchField=this.$.toolbar.searchField;if(!searchField.narrow){searchField.getSearchInput().focus()}md_history.ensureLazyLoaded()},_scrollHandler:function(){if(this.scrollTarget)this.toolbarShadow_=this.scrollTarget.scrollTop!=0},onMenuTap_:function(){var drawer=this.$$("#drawer");if(drawer)drawer.toggle()},checkboxSelected:function(e){var toolbar=this.$.toolbar;toolbar.count=this.$.history.getSelectedItemCount()},unselectAll:function(){var listContainer=this.$.history;var toolbar=this.$.toolbar;listContainer.unselectAllItems(toolbar.count);toolbar.count=0},deleteSelected:function(){this.$.history.deleteSelectedWithPrompt()},historyResult:function(info,results){this.set("queryState_.querying",false);this.set("queryResult_.info",info);this.set("queryResult_.results",results);var listContainer=this.$["history"];listContainer.historyResult(info,results)},focusToolbarSearchField:function(){this.$.toolbar.showSearchField()},onCanExecute_:function(e){e=e;switch(e.command.id){case"find-command":e.canExecute=true;break;case"slash-command":e.canExecute=!this.$.toolbar.searchField.isSearchFocused();break;case"delete-command":e.canExecute=this.$.toolbar.count>0;break}},onCommand_:function(e){if(e.command.id=="find-command"||e.command.id=="slash-command")this.focusToolbarSearchField();if(e.command.id=="delete-command")this.deleteSelected()},setForeignSessions:function(sessionList,isTabSyncEnabled){if(!isTabSyncEnabled){var syncedDeviceManagerElem=this.$$("history-synced-device-manager");if(syncedDeviceManagerElem)syncedDeviceManagerElem.tabSyncDisabled();return}this.set("queryResult_.sessionList",sessionList)},historyDeleted:function(){this.$.history.historyDeleted()},updateSignInState:function(isUserSignedIn){this.isUserSignedIn_=isUserSignedIn},syncedTabsSelected_:function(selectedPage){return selectedPage=="syncedTabs"},shouldShowSpinner_:function(querying,incremental,searchTerm){return querying&&!incremental&&searchTerm!=""},showSyncNotice_:function(hasSyncedResults,selectedPage){return hasSyncedResults&&selectedPage!="syncedTabs"},selectedPageChanged_:function(){this.unselectAll();this.historyViewChanged_()},historyViewChanged_:function(){requestAnimationFrame(function(){if(!this.$.content.selectedItem)return;this.scrollTarget=this.$.content.selectedItem.getContentScrollTarget();this._scrollHandler()}.bind(this));this.recordHistoryPageView_()},getSelectedPage_:function(selectedPage,items){return selectedPage},closeDrawer_:function(){var drawer=this.$$("#drawer");if(drawer)drawer.close()},recordHistoryPageView_:function(){var histogramValue=HistoryPageViewHistogram.END;switch(this.selectedPage_){case"syncedTabs":histogramValue=this.isUserSignedIn_?HistoryPageViewHistogram.SYNCED_TABS:HistoryPageViewHistogram.SIGNIN_PROMO;break;default:switch(this.queryState_.range){case HistoryRange.ALL_TIME:histogramValue=HistoryPageViewHistogram.HISTORY;break;case HistoryRange.WEEK:histogramValue=HistoryPageViewHistogram.GROUPED_WEEK;break;case HistoryRange.MONTH:histogramValue=HistoryPageViewHistogram.GROUPED_MONTH;break}break}md_history.BrowserService.getInstance().recordHistogram("History.HistoryPageView",histogramValue,HistoryPageViewHistogram.END)}});
\ No newline at end of file
diff --git a/chrome/browser/resources/md_history/app.vulcanized.html b/chrome/browser/resources/md_history/app.vulcanized.html
index 43040c9..2500f4a5 100644
--- a/chrome/browser/resources/md_history/app.vulcanized.html
+++ b/chrome/browser/resources/md_history/app.vulcanized.html
@@ -2836,6 +2836,12 @@
   cursor: var(--cr-actionable_-_cursor);
 }
 
+.scroll-container {
+  display: flex;
+        flex-direction: column;
+        min-height: 1px;
+}
+
 [selectable]:focus, [selectable] > :focus {
   background-color: var(--cr-selectable-focus_-_background-color); outline: var(--cr-selectable-focus_-_outline);
 }
@@ -3508,6 +3514,12 @@
   cursor: var(--cr-actionable_-_cursor);
 }
 
+.scroll-container {
+  display: flex;
+        flex-direction: column;
+        min-height: 1px;
+}
+
 [selectable]:focus, [selectable] > :focus {
   background-color: var(--cr-selectable-focus_-_background-color); outline: var(--cr-selectable-focus_-_outline);
 }
diff --git a/chrome/browser/resources/md_history/lazy_load.crisper.js b/chrome/browser/resources/md_history/lazy_load.crisper.js
index cc06fa30..de8173f 100644
--- a/chrome/browser/resources/md_history/lazy_load.crisper.js
+++ b/chrome/browser/resources/md_history/lazy_load.crisper.js
@@ -1,3295 +1,23 @@
-Polymer({
-  is: 'iron-collapse',
-  behaviors: [ Polymer.IronResizableBehavior ],
-  properties: {
-    horizontal: {
-      type: Boolean,
-      value: false,
-      observer: '_horizontalChanged'
-    },
-    opened: {
-      type: Boolean,
-      value: false,
-      notify: true,
-      observer: '_openedChanged'
-    },
-    noAnimation: {
-      type: Boolean
-    },
-    _desiredSize: {
-      type: String,
-      value: ''
-    }
-  },
-  get dimension() {
-    return this.horizontal ? 'width' : 'height';
-  },
-  get _dimensionMax() {
-    return this.horizontal ? 'maxWidth' : 'maxHeight';
-  },
-  get _dimensionMaxCss() {
-    return this.horizontal ? 'max-width' : 'max-height';
-  },
-  hostAttributes: {
-    role: 'group',
-    'aria-hidden': 'true',
-    'aria-expanded': 'false'
-  },
-  listeners: {
-    transitionend: '_transitionEnd'
-  },
-  attached: function() {
-    this._transitionEnd();
-  },
-  toggle: function() {
-    this.opened = !this.opened;
-  },
-  show: function() {
-    this.opened = true;
-  },
-  hide: function() {
-    this.opened = false;
-  },
-  updateSize: function(size, animated) {
-    size = size === 'auto' ? '' : size;
-    if (this._desiredSize === size) {
-      return;
-    }
-    this._desiredSize = size;
-    this._updateTransition(false);
-    var willAnimate = animated && !this.noAnimation && this._isDisplayed;
-    if (willAnimate) {
-      var startSize = this._calcSize();
-      if (size === '') {
-        this.style[this._dimensionMax] = '';
-        size = this._calcSize();
-      }
-      this.style[this._dimensionMax] = startSize;
-      this.scrollTop = this.scrollTop;
-      this._updateTransition(true);
-      willAnimate = size !== startSize;
-    }
-    this.style[this._dimensionMax] = size;
-    if (!willAnimate) {
-      this._transitionEnd();
-    }
-  },
-  enableTransition: function(enabled) {
-    Polymer.Base._warn('`enableTransition()` is deprecated, use `noAnimation` instead.');
-    this.noAnimation = !enabled;
-  },
-  _updateTransition: function(enabled) {
-    this.style.transitionDuration = enabled && !this.noAnimation ? '' : '0s';
-  },
-  _horizontalChanged: function() {
-    this.style.transitionProperty = this._dimensionMaxCss;
-    var otherDimension = this._dimensionMax === 'maxWidth' ? 'maxHeight' : 'maxWidth';
-    this.style[otherDimension] = '';
-    this.updateSize(this.opened ? 'auto' : '0px', false);
-  },
-  _openedChanged: function() {
-    this.setAttribute('aria-expanded', this.opened);
-    this.setAttribute('aria-hidden', !this.opened);
-    this.toggleClass('iron-collapse-closed', false);
-    this.toggleClass('iron-collapse-opened', false);
-    this.updateSize(this.opened ? 'auto' : '0px', true);
-    if (this.opened) {
-      this.focus();
-    }
-  },
-  _transitionEnd: function() {
-    this.style[this._dimensionMax] = this._desiredSize;
-    this.toggleClass('iron-collapse-closed', !this.opened);
-    this.toggleClass('iron-collapse-opened', this.opened);
-    this._updateTransition(false);
-    this.notifyResize();
-  },
-  get _isDisplayed() {
-    var rect = this.getBoundingClientRect();
-    for (var prop in rect) {
-      if (rect[prop] !== 0) return true;
-    }
-    return false;
-  },
-  _calcSize: function() {
-    return this.getBoundingClientRect()[this.dimension] + 'px';
-  }
-});
-
+Polymer({is:"iron-collapse",behaviors:[Polymer.IronResizableBehavior],properties:{horizontal:{type:Boolean,value:false,observer:"_horizontalChanged"},opened:{type:Boolean,value:false,notify:true,observer:"_openedChanged"},noAnimation:{type:Boolean},_desiredSize:{type:String,value:""}},get dimension(){return this.horizontal?"width":"height"},get _dimensionMax(){return this.horizontal?"maxWidth":"maxHeight"},get _dimensionMaxCss(){return this.horizontal?"max-width":"max-height"},hostAttributes:{role:"group","aria-hidden":"true","aria-expanded":"false"},listeners:{transitionend:"_transitionEnd"},attached:function(){this._transitionEnd()},toggle:function(){this.opened=!this.opened},show:function(){this.opened=true},hide:function(){this.opened=false},updateSize:function(size,animated){size=size==="auto"?"":size;if(this._desiredSize===size){return}this._desiredSize=size;this._updateTransition(false);var willAnimate=animated&&!this.noAnimation&&this._isDisplayed;if(willAnimate){var startSize=this._calcSize();if(size===""){this.style[this._dimensionMax]="";size=this._calcSize()}this.style[this._dimensionMax]=startSize;this.scrollTop=this.scrollTop;this._updateTransition(true);willAnimate=size!==startSize}this.style[this._dimensionMax]=size;if(!willAnimate){this._transitionEnd()}},enableTransition:function(enabled){Polymer.Base._warn("`enableTransition()` is deprecated, use `noAnimation` instead.");this.noAnimation=!enabled},_updateTransition:function(enabled){this.style.transitionDuration=enabled&&!this.noAnimation?"":"0s"},_horizontalChanged:function(){this.style.transitionProperty=this._dimensionMaxCss;var otherDimension=this._dimensionMax==="maxWidth"?"maxHeight":"maxWidth";this.style[otherDimension]="";this.updateSize(this.opened?"auto":"0px",false)},_openedChanged:function(){this.setAttribute("aria-expanded",this.opened);this.setAttribute("aria-hidden",!this.opened);this.toggleClass("iron-collapse-closed",false);this.toggleClass("iron-collapse-opened",false);this.updateSize(this.opened?"auto":"0px",true);if(this.opened){this.focus()}},_transitionEnd:function(){this.style[this._dimensionMax]=this._desiredSize;this.toggleClass("iron-collapse-closed",!this.opened);this.toggleClass("iron-collapse-opened",this.opened);this._updateTransition(false);this.notifyResize()},get _isDisplayed(){var rect=this.getBoundingClientRect();for(var prop in rect){if(rect[prop]!==0)return true}return false},_calcSize:function(){return this.getBoundingClientRect()[this.dimension]+"px"}});
 // 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.
-var HistoryDomain;
+var HistoryDomain;var HistoryGroup;Polymer({is:"history-grouped-list",behaviors:[HistoryListBehavior],properties:{historyData:{type:Array},groupedHistoryData_:{type:Array},searchedTerm:{type:String,value:""},range:{type:Number},queryStartTime:String,queryEndTime:String},observers:["updateGroupedHistoryData_(range, historyData)"],createHistoryDomains_:function(visits){var domainIndexes={};var domains=[];for(var i=0,visit;visit=visits[i];i++){var domain=visit.domain;if(domainIndexes[domain]==undefined){domainIndexes[domain]=domains.length;domains.push({domain:domain,visits:[],expanded:false,rendered:false})}domains[domainIndexes[domain]].visits.push(visit)}var sortByVisits=function(a,b){return b.visits.length-a.visits.length};domains.sort(sortByVisits);return domains},updateGroupedHistoryData_:function(){if(this.historyData.length==0){this.groupedHistoryData_=[];return}if(this.range==HistoryRange.WEEK){var days=[];var currentDayVisits=[this.historyData[0]];var pushCurrentDay=function(){days.push({title:this.searchedTerm?currentDayVisits[0].dateShort:currentDayVisits[0].dateRelativeDay,domains:this.createHistoryDomains_(currentDayVisits)})}.bind(this);var visitsSameDay=function(a,b){if(this.searchedTerm)return a.dateShort==b.dateShort;return a.dateRelativeDay==b.dateRelativeDay}.bind(this);for(var i=1;i<this.historyData.length;i++){var visit=this.historyData[i];if(!visitsSameDay(visit,currentDayVisits[0])){pushCurrentDay();currentDayVisits=[]}currentDayVisits.push(visit)}pushCurrentDay();this.groupedHistoryData_=days}else if(this.range==HistoryRange.MONTH){this.groupedHistoryData_=[{title:this.queryStartTime+" – "+this.queryEndTime,domains:this.createHistoryDomains_(this.historyData)}]}},toggleDomainExpanded_:function(e){var collapse=e.currentTarget.parentNode.querySelector("iron-collapse");e.model.set("domain.rendered",true);setTimeout(function(){collapse.toggle()},0)},needsTimeGap_:function(groupIndex,domainIndex,itemIndex){var visits=this.groupedHistoryData_[groupIndex].domains[domainIndex].visits;return md_history.HistoryItem.needsTimeGap(visits,itemIndex,this.searchedTerm)},pathForItem_:function(groupIndex,domainIndex,itemIndex){return["groupedHistoryData_",groupIndex,"domains",domainIndex,"visits",itemIndex].join(".")},getWebsiteIconStyle_:function(domain){return"background-image: "+cr.icon.getFavicon(domain.visits[0].url)},getDropdownIcon_:function(expanded){return expanded?"cr:expand-less":"cr:expand-more"}});Polymer.PaperButtonBehaviorImpl={properties:{elevation:{type:Number,reflectToAttribute:true,readOnly:true}},observers:["_calculateElevation(focused, disabled, active, pressed, receivedFocusFromKeyboard)","_computeKeyboardClass(receivedFocusFromKeyboard)"],hostAttributes:{role:"button",tabindex:"0",animated:true},_calculateElevation:function(){var e=1;if(this.disabled){e=0}else if(this.active||this.pressed){e=4}else if(this.receivedFocusFromKeyboard){e=3}this._setElevation(e)},_computeKeyboardClass:function(receivedFocusFromKeyboard){this.toggleClass("keyboard-focus",receivedFocusFromKeyboard)},_spaceKeyDownHandler:function(event){Polymer.IronButtonStateImpl._spaceKeyDownHandler.call(this,event);if(this.hasRipple()&&this.getRipple().ripples.length<1){this._ripple.uiDownAction()}},_spaceKeyUpHandler:function(event){Polymer.IronButtonStateImpl._spaceKeyUpHandler.call(this,event);if(this.hasRipple()){this._ripple.uiUpAction()}}};Polymer.PaperButtonBehavior=[Polymer.IronButtonState,Polymer.IronControlState,Polymer.PaperRippleBehavior,Polymer.PaperButtonBehaviorImpl];Polymer({is:"paper-button",behaviors:[Polymer.PaperButtonBehavior],properties:{raised:{type:Boolean,reflectToAttribute:true,value:false,observer:"_calculateElevation"}},_calculateElevation:function(){if(!this.raised){this._setElevation(0)}else{Polymer.PaperButtonBehaviorImpl._calculateElevation.apply(this)}}});Polymer.PaperItemBehaviorImpl={hostAttributes:{role:"option",tabindex:"0"}};Polymer.PaperItemBehavior=[Polymer.IronButtonState,Polymer.IronControlState,Polymer.PaperItemBehaviorImpl];Polymer({is:"paper-item",behaviors:[Polymer.PaperItemBehavior]});Polymer.IronFitBehavior={properties:{sizingTarget:{type:Object,value:function(){return this}},fitInto:{type:Object,value:window},noOverlap:{type:Boolean},positionTarget:{type:Element},horizontalAlign:{type:String},verticalAlign:{type:String},dynamicAlign:{type:Boolean},horizontalOffset:{type:Number,value:0,notify:true},verticalOffset:{type:Number,value:0,notify:true},autoFitOnAttach:{type:Boolean,value:false},_fitInfo:{type:Object}},get _fitWidth(){var fitWidth;if(this.fitInto===window){fitWidth=this.fitInto.innerWidth}else{fitWidth=this.fitInto.getBoundingClientRect().width}return fitWidth},get _fitHeight(){var fitHeight;if(this.fitInto===window){fitHeight=this.fitInto.innerHeight}else{fitHeight=this.fitInto.getBoundingClientRect().height}return fitHeight},get _fitLeft(){var fitLeft;if(this.fitInto===window){fitLeft=0}else{fitLeft=this.fitInto.getBoundingClientRect().left}return fitLeft},get _fitTop(){var fitTop;if(this.fitInto===window){fitTop=0}else{fitTop=this.fitInto.getBoundingClientRect().top}return fitTop},get _defaultPositionTarget(){var parent=Polymer.dom(this).parentNode;if(parent&&parent.nodeType===Node.DOCUMENT_FRAGMENT_NODE){parent=parent.host}return parent},get _localeHorizontalAlign(){if(this._isRTL){if(this.horizontalAlign==="right"){return"left"}if(this.horizontalAlign==="left"){return"right"}}return this.horizontalAlign},attached:function(){this._isRTL=window.getComputedStyle(this).direction=="rtl";this.positionTarget=this.positionTarget||this._defaultPositionTarget;if(this.autoFitOnAttach){if(window.getComputedStyle(this).display==="none"){setTimeout(function(){this.fit()}.bind(this))}else{this.fit()}}},fit:function(){this.position();this.constrain();this.center()},_discoverInfo:function(){if(this._fitInfo){return}var target=window.getComputedStyle(this);var sizer=window.getComputedStyle(this.sizingTarget);this._fitInfo={inlineStyle:{top:this.style.top||"",left:this.style.left||"",position:this.style.position||""},sizerInlineStyle:{maxWidth:this.sizingTarget.style.maxWidth||"",maxHeight:this.sizingTarget.style.maxHeight||"",boxSizing:this.sizingTarget.style.boxSizing||""},positionedBy:{vertically:target.top!=="auto"?"top":target.bottom!=="auto"?"bottom":null,horizontally:target.left!=="auto"?"left":target.right!=="auto"?"right":null},sizedBy:{height:sizer.maxHeight!=="none",width:sizer.maxWidth!=="none",minWidth:parseInt(sizer.minWidth,10)||0,minHeight:parseInt(sizer.minHeight,10)||0},margin:{top:parseInt(target.marginTop,10)||0,right:parseInt(target.marginRight,10)||0,bottom:parseInt(target.marginBottom,10)||0,left:parseInt(target.marginLeft,10)||0}};if(this.verticalOffset){this._fitInfo.margin.top=this._fitInfo.margin.bottom=this.verticalOffset;this._fitInfo.inlineStyle.marginTop=this.style.marginTop||"";this._fitInfo.inlineStyle.marginBottom=this.style.marginBottom||"";this.style.marginTop=this.style.marginBottom=this.verticalOffset+"px"}if(this.horizontalOffset){this._fitInfo.margin.left=this._fitInfo.margin.right=this.horizontalOffset;this._fitInfo.inlineStyle.marginLeft=this.style.marginLeft||"";this._fitInfo.inlineStyle.marginRight=this.style.marginRight||"";this.style.marginLeft=this.style.marginRight=this.horizontalOffset+"px"}},resetFit:function(){var info=this._fitInfo||{};for(var property in info.sizerInlineStyle){this.sizingTarget.style[property]=info.sizerInlineStyle[property]}for(var property in info.inlineStyle){this.style[property]=info.inlineStyle[property]}this._fitInfo=null},refit:function(){var scrollLeft=this.sizingTarget.scrollLeft;var scrollTop=this.sizingTarget.scrollTop;this.resetFit();this.fit();this.sizingTarget.scrollLeft=scrollLeft;this.sizingTarget.scrollTop=scrollTop},position:function(){if(!this.horizontalAlign&&!this.verticalAlign){return}this._discoverInfo();this.style.position="fixed";this.sizingTarget.style.boxSizing="border-box";this.style.left="0px";this.style.top="0px";var rect=this.getBoundingClientRect();var positionRect=this.__getNormalizedRect(this.positionTarget);var fitRect=this.__getNormalizedRect(this.fitInto);var margin=this._fitInfo.margin;var size={width:rect.width+margin.left+margin.right,height:rect.height+margin.top+margin.bottom};var position=this.__getPosition(this._localeHorizontalAlign,this.verticalAlign,size,positionRect,fitRect);var left=position.left+margin.left;var top=position.top+margin.top;var right=Math.min(fitRect.right-margin.right,left+rect.width);var bottom=Math.min(fitRect.bottom-margin.bottom,top+rect.height);var minWidth=this._fitInfo.sizedBy.minWidth;var minHeight=this._fitInfo.sizedBy.minHeight;if(left<margin.left){left=margin.left;if(right-left<minWidth){left=right-minWidth}}if(top<margin.top){top=margin.top;if(bottom-top<minHeight){top=bottom-minHeight}}this.sizingTarget.style.maxWidth=right-left+"px";this.sizingTarget.style.maxHeight=bottom-top+"px";this.style.left=left-rect.left+"px";this.style.top=top-rect.top+"px"},constrain:function(){if(this.horizontalAlign||this.verticalAlign){return}this._discoverInfo();var info=this._fitInfo;if(!info.positionedBy.vertically){this.style.position="fixed";this.style.top="0px"}if(!info.positionedBy.horizontally){this.style.position="fixed";this.style.left="0px"}this.sizingTarget.style.boxSizing="border-box";var rect=this.getBoundingClientRect();if(!info.sizedBy.height){this.__sizeDimension(rect,info.positionedBy.vertically,"top","bottom","Height")}if(!info.sizedBy.width){this.__sizeDimension(rect,info.positionedBy.horizontally,"left","right","Width")}},_sizeDimension:function(rect,positionedBy,start,end,extent){this.__sizeDimension(rect,positionedBy,start,end,extent)},__sizeDimension:function(rect,positionedBy,start,end,extent){var info=this._fitInfo;var fitRect=this.__getNormalizedRect(this.fitInto);var max=extent==="Width"?fitRect.width:fitRect.height;var flip=positionedBy===end;var offset=flip?max-rect[end]:rect[start];var margin=info.margin[flip?start:end];var offsetExtent="offset"+extent;var sizingOffset=this[offsetExtent]-this.sizingTarget[offsetExtent];this.sizingTarget.style["max"+extent]=max-margin-offset-sizingOffset+"px"},center:function(){if(this.horizontalAlign||this.verticalAlign){return}this._discoverInfo();var positionedBy=this._fitInfo.positionedBy;if(positionedBy.vertically&&positionedBy.horizontally){return}this.style.position="fixed";if(!positionedBy.vertically){this.style.top="0px"}if(!positionedBy.horizontally){this.style.left="0px"}var rect=this.getBoundingClientRect();var fitRect=this.__getNormalizedRect(this.fitInto);if(!positionedBy.vertically){var top=fitRect.top-rect.top+(fitRect.height-rect.height)/2;this.style.top=top+"px"}if(!positionedBy.horizontally){var left=fitRect.left-rect.left+(fitRect.width-rect.width)/2;this.style.left=left+"px"}},__getNormalizedRect:function(target){if(target===document.documentElement||target===window){return{top:0,left:0,width:window.innerWidth,height:window.innerHeight,right:window.innerWidth,bottom:window.innerHeight}}return target.getBoundingClientRect()},__getCroppedArea:function(position,size,fitRect){var verticalCrop=Math.min(0,position.top)+Math.min(0,fitRect.bottom-(position.top+size.height));var horizontalCrop=Math.min(0,position.left)+Math.min(0,fitRect.right-(position.left+size.width));return Math.abs(verticalCrop)*size.width+Math.abs(horizontalCrop)*size.height},__getPosition:function(hAlign,vAlign,size,positionRect,fitRect){var positions=[{verticalAlign:"top",horizontalAlign:"left",top:positionRect.top,left:positionRect.left},{verticalAlign:"top",horizontalAlign:"right",top:positionRect.top,left:positionRect.right-size.width},{verticalAlign:"bottom",horizontalAlign:"left",top:positionRect.bottom-size.height,left:positionRect.left},{verticalAlign:"bottom",horizontalAlign:"right",top:positionRect.bottom-size.height,left:positionRect.right-size.width}];if(this.noOverlap){for(var i=0,l=positions.length;i<l;i++){var copy={};for(var key in positions[i]){copy[key]=positions[i][key]}positions.push(copy)}positions[0].top=positions[1].top+=positionRect.height;positions[2].top=positions[3].top-=positionRect.height;positions[4].left=positions[6].left+=positionRect.width;positions[5].left=positions[7].left-=positionRect.width}vAlign=vAlign==="auto"?null:vAlign;hAlign=hAlign==="auto"?null:hAlign;var position;for(var i=0;i<positions.length;i++){var pos=positions[i];if(!this.dynamicAlign&&!this.noOverlap&&pos.verticalAlign===vAlign&&pos.horizontalAlign===hAlign){position=pos;break}var alignOk=(!vAlign||pos.verticalAlign===vAlign)&&(!hAlign||pos.horizontalAlign===hAlign);if(!this.dynamicAlign&&!alignOk){continue}position=position||pos;pos.croppedArea=this.__getCroppedArea(pos,size,fitRect);var diff=pos.croppedArea-position.croppedArea;if(diff<0||diff===0&&alignOk){position=pos}if(position.croppedArea===0&&alignOk){break}}return position}};(function(){"use strict";Polymer({is:"iron-overlay-backdrop",properties:{opened:{reflectToAttribute:true,type:Boolean,value:false,observer:"_openedChanged"}},listeners:{transitionend:"_onTransitionend"},created:function(){this.__openedRaf=null},attached:function(){this.opened&&this._openedChanged(this.opened)},prepare:function(){if(this.opened&&!this.parentNode){Polymer.dom(document.body).appendChild(this)}},open:function(){this.opened=true},close:function(){this.opened=false},complete:function(){if(!this.opened&&this.parentNode===document.body){Polymer.dom(this.parentNode).removeChild(this)}},_onTransitionend:function(event){if(event&&event.target===this){this.complete()}},_openedChanged:function(opened){if(opened){this.prepare()}else{var cs=window.getComputedStyle(this);if(cs.transitionDuration==="0s"||cs.opacity==0){this.complete()}}if(!this.isAttached){return}if(this.__openedRaf){window.cancelAnimationFrame(this.__openedRaf);this.__openedRaf=null}this.scrollTop=this.scrollTop;this.__openedRaf=window.requestAnimationFrame(function(){this.__openedRaf=null;this.toggleClass("opened",this.opened)}.bind(this))}})})();Polymer.IronOverlayManagerClass=function(){this._overlays=[];this._minimumZ=101;this._backdropElement=null;Polymer.Gestures.add(document,"tap",this._onCaptureClick.bind(this));document.addEventListener("focus",this._onCaptureFocus.bind(this),true);document.addEventListener("keydown",this._onCaptureKeyDown.bind(this),true)};Polymer.IronOverlayManagerClass.prototype={constructor:Polymer.IronOverlayManagerClass,get backdropElement(){if(!this._backdropElement){this._backdropElement=document.createElement("iron-overlay-backdrop")}return this._backdropElement},get deepActiveElement(){var active=document.activeElement||document.body;while(active.root&&Polymer.dom(active.root).activeElement){active=Polymer.dom(active.root).activeElement}return active},_bringOverlayAtIndexToFront:function(i){var overlay=this._overlays[i];if(!overlay){return}var lastI=this._overlays.length-1;var currentOverlay=this._overlays[lastI];if(currentOverlay&&this._shouldBeBehindOverlay(overlay,currentOverlay)){lastI--}if(i>=lastI){return}var minimumZ=Math.max(this.currentOverlayZ(),this._minimumZ);if(this._getZ(overlay)<=minimumZ){this._applyOverlayZ(overlay,minimumZ)}while(i<lastI){this._overlays[i]=this._overlays[i+1];i++}this._overlays[lastI]=overlay},addOrRemoveOverlay:function(overlay){if(overlay.opened){this.addOverlay(overlay)}else{this.removeOverlay(overlay)}},addOverlay:function(overlay){var i=this._overlays.indexOf(overlay);if(i>=0){this._bringOverlayAtIndexToFront(i);this.trackBackdrop();return}var insertionIndex=this._overlays.length;var currentOverlay=this._overlays[insertionIndex-1];var minimumZ=Math.max(this._getZ(currentOverlay),this._minimumZ);var newZ=this._getZ(overlay);if(currentOverlay&&this._shouldBeBehindOverlay(overlay,currentOverlay)){this._applyOverlayZ(currentOverlay,minimumZ);insertionIndex--;var previousOverlay=this._overlays[insertionIndex-1];minimumZ=Math.max(this._getZ(previousOverlay),this._minimumZ)}if(newZ<=minimumZ){this._applyOverlayZ(overlay,minimumZ)}this._overlays.splice(insertionIndex,0,overlay);this.trackBackdrop()},removeOverlay:function(overlay){var i=this._overlays.indexOf(overlay);if(i===-1){return}this._overlays.splice(i,1);this.trackBackdrop()},currentOverlay:function(){var i=this._overlays.length-1;return this._overlays[i]},currentOverlayZ:function(){return this._getZ(this.currentOverlay())},ensureMinimumZ:function(minimumZ){this._minimumZ=Math.max(this._minimumZ,minimumZ)},focusOverlay:function(){var current=this.currentOverlay();if(current){current._applyFocus()}},trackBackdrop:function(){var overlay=this._overlayWithBackdrop();if(!overlay&&!this._backdropElement){return}this.backdropElement.style.zIndex=this._getZ(overlay)-1;this.backdropElement.opened=!!overlay},getBackdrops:function(){var backdrops=[];for(var i=0;i<this._overlays.length;i++){if(this._overlays[i].withBackdrop){backdrops.push(this._overlays[i])}}return backdrops},backdropZ:function(){return this._getZ(this._overlayWithBackdrop())-1},_overlayWithBackdrop:function(){for(var i=0;i<this._overlays.length;i++){if(this._overlays[i].withBackdrop){return this._overlays[i]}}},_getZ:function(overlay){var z=this._minimumZ;if(overlay){var z1=Number(overlay.style.zIndex||window.getComputedStyle(overlay).zIndex);if(z1===z1){z=z1}}return z},_setZ:function(element,z){element.style.zIndex=z},_applyOverlayZ:function(overlay,aboveZ){this._setZ(overlay,aboveZ+2)},_overlayInPath:function(path){path=path||[];for(var i=0;i<path.length;i++){if(path[i]._manager===this){return path[i]}}},_onCaptureClick:function(event){var overlay=this.currentOverlay();if(overlay&&this._overlayInPath(Polymer.dom(event).path)!==overlay){overlay._onCaptureClick(event)}},_onCaptureFocus:function(event){var overlay=this.currentOverlay();if(overlay){overlay._onCaptureFocus(event)}},_onCaptureKeyDown:function(event){var overlay=this.currentOverlay();if(overlay){if(Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event,"esc")){overlay._onCaptureEsc(event)}else if(Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event,"tab")){overlay._onCaptureTab(event)}}},_shouldBeBehindOverlay:function(overlay1,overlay2){return!overlay1.alwaysOnTop&&overlay2.alwaysOnTop}};Polymer.IronOverlayManager=new Polymer.IronOverlayManagerClass;(function(){"use strict";Polymer.IronOverlayBehaviorImpl={properties:{opened:{observer:"_openedChanged",type:Boolean,value:false,notify:true},canceled:{observer:"_canceledChanged",readOnly:true,type:Boolean,value:false},withBackdrop:{observer:"_withBackdropChanged",type:Boolean},noAutoFocus:{type:Boolean,value:false},noCancelOnEscKey:{type:Boolean,value:false},noCancelOnOutsideClick:{type:Boolean,value:false},closingReason:{type:Object},restoreFocusOnClose:{type:Boolean,value:false},alwaysOnTop:{type:Boolean},_manager:{type:Object,value:Polymer.IronOverlayManager},_focusedChild:{type:Object}},listeners:{"iron-resize":"_onIronResize"},get backdropElement(){return this._manager.backdropElement},get _focusNode(){return this._focusedChild||Polymer.dom(this).querySelector("[autofocus]")||this},get _focusableNodes(){var FOCUSABLE_WITH_DISABLED=["a[href]","area[href]","iframe","[tabindex]","[contentEditable=true]"];var FOCUSABLE_WITHOUT_DISABLED=["input","select","textarea","button"];var selector=FOCUSABLE_WITH_DISABLED.join(':not([tabindex="-1"]),')+':not([tabindex="-1"]),'+FOCUSABLE_WITHOUT_DISABLED.join(':not([disabled]):not([tabindex="-1"]),')+':not([disabled]):not([tabindex="-1"])';var focusables=Polymer.dom(this).querySelectorAll(selector);if(this.tabIndex>=0){focusables.splice(0,0,this)}return focusables.sort(function(a,b){if(a.tabIndex===b.tabIndex){return 0}if(a.tabIndex===0||a.tabIndex>b.tabIndex){return 1}return-1})},ready:function(){this.__isAnimating=false;this.__shouldRemoveTabIndex=false;this.__firstFocusableNode=this.__lastFocusableNode=null;this.__raf=null;this.__restoreFocusNode=null;this._ensureSetup()},attached:function(){if(this.opened){this._openedChanged(this.opened)}this._observer=Polymer.dom(this).observeNodes(this._onNodesChange)},detached:function(){Polymer.dom(this).unobserveNodes(this._observer);this._observer=null;if(this.__raf){window.cancelAnimationFrame(this.__raf);this.__raf=null}this._manager.removeOverlay(this)},toggle:function(){this._setCanceled(false);this.opened=!this.opened},open:function(){this._setCanceled(false);this.opened=true},close:function(){this._setCanceled(false);this.opened=false},cancel:function(event){var cancelEvent=this.fire("iron-overlay-canceled",event,{cancelable:true});if(cancelEvent.defaultPrevented){return}this._setCanceled(true);this.opened=false},_ensureSetup:function(){if(this._overlaySetup){return}this._overlaySetup=true;this.style.outline="none";this.style.display="none"},_openedChanged:function(opened){if(opened){this.removeAttribute("aria-hidden")}else{this.setAttribute("aria-hidden","true")}if(!this.isAttached){return}this.__isAnimating=true;this.__onNextAnimationFrame(this.__openedChanged)},_canceledChanged:function(){this.closingReason=this.closingReason||{};this.closingReason.canceled=this.canceled},_withBackdropChanged:function(){if(this.withBackdrop&&!this.hasAttribute("tabindex")){this.setAttribute("tabindex","-1");this.__shouldRemoveTabIndex=true}else if(this.__shouldRemoveTabIndex){this.removeAttribute("tabindex");this.__shouldRemoveTabIndex=false}if(this.opened&&this.isAttached){this._manager.trackBackdrop()}},_prepareRenderOpened:function(){this.__restoreFocusNode=this._manager.deepActiveElement;this._preparePositioning();this.refit();this._finishPositioning();if(this.noAutoFocus&&document.activeElement===this._focusNode){this._focusNode.blur();this.__restoreFocusNode.focus()}},_renderOpened:function(){this._finishRenderOpened()},_renderClosed:function(){this._finishRenderClosed()},_finishRenderOpened:function(){this.notifyResize();this.__isAnimating=false;var focusableNodes=this._focusableNodes;this.__firstFocusableNode=focusableNodes[0];this.__lastFocusableNode=focusableNodes[focusableNodes.length-1];this.fire("iron-overlay-opened")},_finishRenderClosed:function(){this.style.display="none";this.style.zIndex="";this.notifyResize();this.__isAnimating=false;this.fire("iron-overlay-closed",this.closingReason)},_preparePositioning:function(){this.style.transition=this.style.webkitTransition="none";this.style.transform=this.style.webkitTransform="none";this.style.display=""},_finishPositioning:function(){this.style.display="none";this.scrollTop=this.scrollTop;this.style.transition=this.style.webkitTransition="";this.style.transform=this.style.webkitTransform="";this.style.display="";this.scrollTop=this.scrollTop},_applyFocus:function(){if(this.opened){if(!this.noAutoFocus){this._focusNode.focus()}}else{this._focusNode.blur();this._focusedChild=null;if(this.restoreFocusOnClose&&this.__restoreFocusNode){this.__restoreFocusNode.focus()}this.__restoreFocusNode=null;var currentOverlay=this._manager.currentOverlay();if(currentOverlay&&this!==currentOverlay){currentOverlay._applyFocus()}}},_onCaptureClick:function(event){if(!this.noCancelOnOutsideClick){this.cancel(event)}},_onCaptureFocus:function(event){if(!this.withBackdrop){return}var path=Polymer.dom(event).path;if(path.indexOf(this)===-1){event.stopPropagation();this._applyFocus()}else{this._focusedChild=path[0]}},_onCaptureEsc:function(event){if(!this.noCancelOnEscKey){this.cancel(event)}},_onCaptureTab:function(event){if(!this.withBackdrop){return}var shift=event.shiftKey;var nodeToCheck=shift?this.__firstFocusableNode:this.__lastFocusableNode;var nodeToSet=shift?this.__lastFocusableNode:this.__firstFocusableNode;var shouldWrap=false;if(nodeToCheck===nodeToSet){shouldWrap=true}else{var focusedNode=this._manager.deepActiveElement;shouldWrap=focusedNode===nodeToCheck||focusedNode===this}if(shouldWrap){event.preventDefault();this._focusedChild=nodeToSet;this._applyFocus()}},_onIronResize:function(){if(this.opened&&!this.__isAnimating){this.__onNextAnimationFrame(this.refit)}},_onNodesChange:function(){if(this.opened&&!this.__isAnimating){this.notifyResize()}},__openedChanged:function(){if(this.opened){this._prepareRenderOpened();this._manager.addOverlay(this);this._applyFocus();this._renderOpened()}else{this._manager.removeOverlay(this);this._applyFocus();this._renderClosed()}},__onNextAnimationFrame:function(callback){if(this.__raf){window.cancelAnimationFrame(this.__raf)}var self=this;this.__raf=window.requestAnimationFrame(function nextAnimationFrame(){self.__raf=null;callback.call(self)})}};Polymer.IronOverlayBehavior=[Polymer.IronFitBehavior,Polymer.IronResizableBehavior,Polymer.IronOverlayBehaviorImpl]})();Polymer.NeonAnimatableBehavior={properties:{animationConfig:{type:Object},entryAnimation:{observer:"_entryAnimationChanged",type:String},exitAnimation:{observer:"_exitAnimationChanged",type:String}},_entryAnimationChanged:function(){this.animationConfig=this.animationConfig||{};this.animationConfig["entry"]=[{name:this.entryAnimation,node:this}]},_exitAnimationChanged:function(){this.animationConfig=this.animationConfig||{};this.animationConfig["exit"]=[{name:this.exitAnimation,node:this}]},_copyProperties:function(config1,config2){for(var property in config2){config1[property]=config2[property]}},_cloneConfig:function(config){var clone={isClone:true};this._copyProperties(clone,config);return clone},_getAnimationConfigRecursive:function(type,map,allConfigs){if(!this.animationConfig){return}if(this.animationConfig.value&&typeof this.animationConfig.value==="function"){this._warn(this._logf("playAnimation","Please put 'animationConfig' inside of your components 'properties' object instead of outside of it."));return}var thisConfig;if(type){thisConfig=this.animationConfig[type]}else{thisConfig=this.animationConfig}if(!Array.isArray(thisConfig)){thisConfig=[thisConfig]}if(thisConfig){for(var config,index=0;config=thisConfig[index];index++){if(config.animatable){config.animatable._getAnimationConfigRecursive(config.type||type,map,allConfigs)}else{if(config.id){var cachedConfig=map[config.id];if(cachedConfig){if(!cachedConfig.isClone){map[config.id]=this._cloneConfig(cachedConfig);cachedConfig=map[config.id]}this._copyProperties(cachedConfig,config)}else{map[config.id]=config}}else{allConfigs.push(config)}}}}},getAnimationConfig:function(type){var map={};var allConfigs=[];this._getAnimationConfigRecursive(type,map,allConfigs);for(var key in map){allConfigs.push(map[key])}return allConfigs}};Polymer.NeonAnimationRunnerBehaviorImpl={_configureAnimations:function(configs){var results=[];if(configs.length>0){for(var config,index=0;config=configs[index];index++){var neonAnimation=document.createElement(config.name);if(neonAnimation.isNeonAnimation){var result=null;try{result=neonAnimation.configure(config);if(typeof result.cancel!="function"){result=document.timeline.play(result)}}catch(e){result=null;console.warn("Couldnt play","(",config.name,").",e)}if(result){results.push({neonAnimation:neonAnimation,config:config,animation:result})}}else{console.warn(this.is+":",config.name,"not found!")}}}return results},_shouldComplete:function(activeEntries){var finished=true;for(var i=0;i<activeEntries.length;i++){if(activeEntries[i].animation.playState!="finished"){finished=false;break}}return finished},_complete:function(activeEntries){for(var i=0;i<activeEntries.length;i++){activeEntries[i].neonAnimation.complete(activeEntries[i].config)}for(var i=0;i<activeEntries.length;i++){activeEntries[i].animation.cancel()}},playAnimation:function(type,cookie){var configs=this.getAnimationConfig(type);if(!configs){return}this._active=this._active||{};if(this._active[type]){this._complete(this._active[type]);delete this._active[type]}var activeEntries=this._configureAnimations(configs);if(activeEntries.length==0){this.fire("neon-animation-finish",cookie,{bubbles:false});return}this._active[type]=activeEntries;for(var i=0;i<activeEntries.length;i++){activeEntries[i].animation.onfinish=function(){if(this._shouldComplete(activeEntries)){this._complete(activeEntries);delete this._active[type];this.fire("neon-animation-finish",cookie,{bubbles:false})}}.bind(this)}},cancelAnimation:function(){for(var k in this._animations){this._animations[k].cancel()}this._animations={}}};Polymer.NeonAnimationRunnerBehavior=[Polymer.NeonAnimatableBehavior,Polymer.NeonAnimationRunnerBehaviorImpl];Polymer.NeonAnimationBehavior={properties:{animationTiming:{type:Object,value:function(){return{duration:500,easing:"cubic-bezier(0.4, 0, 0.2, 1)",fill:"both"}}}},isNeonAnimation:true,timingFromConfig:function(config){if(config.timing){for(var property in config.timing){this.animationTiming[property]=config.timing[property]}}return this.animationTiming},setPrefixedProperty:function(node,property,value){var map={transform:["webkitTransform"],transformOrigin:["mozTransformOrigin","webkitTransformOrigin"]};var prefixes=map[property];for(var prefix,index=0;prefix=prefixes[index];index++){node.style[prefix]=value}node.style[property]=value},complete:function(){}};Polymer({is:"opaque-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;this._effect=new KeyframeEffect(node,[{opacity:"1"},{opacity:"1"}],this.timingFromConfig(config));node.style.opacity="0";return this._effect},complete:function(config){config.node.style.opacity=""}});(function(){"use strict";var LAST_TOUCH_POSITION={pageX:0,pageY:0};var ROOT_TARGET=null;var SCROLLABLE_NODES=[];Polymer.IronDropdownScrollManager={get currentLockingElement(){return this._lockingElements[this._lockingElements.length-1]},elementIsScrollLocked:function(element){var currentLockingElement=this.currentLockingElement;if(currentLockingElement===undefined)return false;var scrollLocked;if(this._hasCachedLockedElement(element)){return true}if(this._hasCachedUnlockedElement(element)){return false}scrollLocked=!!currentLockingElement&&currentLockingElement!==element&&!this._composedTreeContains(currentLockingElement,element);if(scrollLocked){this._lockedElementCache.push(element)}else{this._unlockedElementCache.push(element)}return scrollLocked},pushScrollLock:function(element){if(this._lockingElements.indexOf(element)>=0){return}if(this._lockingElements.length===0){this._lockScrollInteractions()}this._lockingElements.push(element);this._lockedElementCache=[];this._unlockedElementCache=[]},removeScrollLock:function(element){var index=this._lockingElements.indexOf(element);if(index===-1){return}this._lockingElements.splice(index,1);this._lockedElementCache=[];this._unlockedElementCache=[];if(this._lockingElements.length===0){this._unlockScrollInteractions()}},_lockingElements:[],_lockedElementCache:null,_unlockedElementCache:null,_hasCachedLockedElement:function(element){return this._lockedElementCache.indexOf(element)>-1},_hasCachedUnlockedElement:function(element){return this._unlockedElementCache.indexOf(element)>-1},_composedTreeContains:function(element,child){var contentElements;var distributedNodes;var contentIndex;var nodeIndex;if(element.contains(child)){return true}contentElements=Polymer.dom(element).querySelectorAll("content");for(contentIndex=0;contentIndex<contentElements.length;++contentIndex){distributedNodes=Polymer.dom(contentElements[contentIndex]).getDistributedNodes();for(nodeIndex=0;nodeIndex<distributedNodes.length;++nodeIndex){if(this._composedTreeContains(distributedNodes[nodeIndex],child)){return true}}}return false},_scrollInteractionHandler:function(event){if(event.cancelable&&this._shouldPreventScrolling(event)){event.preventDefault()}if(event.targetTouches){var touch=event.targetTouches[0];LAST_TOUCH_POSITION.pageX=touch.pageX;LAST_TOUCH_POSITION.pageY=touch.pageY}},_lockScrollInteractions:function(){this._boundScrollHandler=this._boundScrollHandler||this._scrollInteractionHandler.bind(this);document.addEventListener("wheel",this._boundScrollHandler,true);document.addEventListener("mousewheel",this._boundScrollHandler,true);document.addEventListener("DOMMouseScroll",this._boundScrollHandler,true);document.addEventListener("touchstart",this._boundScrollHandler,true);
 
-var HistoryGroup;
-
-Polymer({
-  is: 'history-grouped-list',
-  behaviors: [ HistoryListBehavior ],
-  properties: {
-    historyData: {
-      type: Array
-    },
-    groupedHistoryData_: {
-      type: Array
-    },
-    searchedTerm: {
-      type: String,
-      value: ''
-    },
-    range: {
-      type: Number
-    },
-    queryStartTime: String,
-    queryEndTime: String
-  },
-  observers: [ 'updateGroupedHistoryData_(range, historyData)' ],
-  createHistoryDomains_: function(visits) {
-    var domainIndexes = {};
-    var domains = [];
-    for (var i = 0, visit; visit = visits[i]; i++) {
-      var domain = visit.domain;
-      if (domainIndexes[domain] == undefined) {
-        domainIndexes[domain] = domains.length;
-        domains.push({
-          domain: domain,
-          visits: [],
-          expanded: false,
-          rendered: false
-        });
-      }
-      domains[domainIndexes[domain]].visits.push(visit);
-    }
-    var sortByVisits = function(a, b) {
-      return b.visits.length - a.visits.length;
-    };
-    domains.sort(sortByVisits);
-    return domains;
-  },
-  updateGroupedHistoryData_: function() {
-    if (this.historyData.length == 0) {
-      this.groupedHistoryData_ = [];
-      return;
-    }
-    if (this.range == HistoryRange.WEEK) {
-      var days = [];
-      var currentDayVisits = [ this.historyData[0] ];
-      var pushCurrentDay = function() {
-        days.push({
-          title: this.searchedTerm ? currentDayVisits[0].dateShort : currentDayVisits[0].dateRelativeDay,
-          domains: this.createHistoryDomains_(currentDayVisits)
-        });
-      }.bind(this);
-      var visitsSameDay = function(a, b) {
-        if (this.searchedTerm) return a.dateShort == b.dateShort;
-        return a.dateRelativeDay == b.dateRelativeDay;
-      }.bind(this);
-      for (var i = 1; i < this.historyData.length; i++) {
-        var visit = this.historyData[i];
-        if (!visitsSameDay(visit, currentDayVisits[0])) {
-          pushCurrentDay();
-          currentDayVisits = [];
-        }
-        currentDayVisits.push(visit);
-      }
-      pushCurrentDay();
-      this.groupedHistoryData_ = days;
-    } else if (this.range == HistoryRange.MONTH) {
-      this.groupedHistoryData_ = [ {
-        title: this.queryStartTime + ' – ' + this.queryEndTime,
-        domains: this.createHistoryDomains_(this.historyData)
-      } ];
-    }
-  },
-  toggleDomainExpanded_: function(e) {
-    var collapse = e.currentTarget.parentNode.querySelector('iron-collapse');
-    e.model.set('domain.rendered', true);
-    setTimeout(function() {
-      collapse.toggle();
-    }, 0);
-  },
-  needsTimeGap_: function(groupIndex, domainIndex, itemIndex) {
-    var visits = this.groupedHistoryData_[groupIndex].domains[domainIndex].visits;
-    return md_history.HistoryItem.needsTimeGap(visits, itemIndex, this.searchedTerm);
-  },
-  pathForItem_: function(groupIndex, domainIndex, itemIndex) {
-    return [ 'groupedHistoryData_', groupIndex, 'domains', domainIndex, 'visits', itemIndex ].join('.');
-  },
-  getWebsiteIconStyle_: function(domain) {
-    return 'background-image: ' + cr.icon.getFavicon(domain.visits[0].url);
-  },
-  getDropdownIcon_: function(expanded) {
-    return expanded ? 'cr:expand-less' : 'cr:expand-more';
-  }
-});
-
-Polymer.PaperButtonBehaviorImpl = {
-  properties: {
-    elevation: {
-      type: Number,
-      reflectToAttribute: true,
-      readOnly: true
-    }
-  },
-  observers: [ '_calculateElevation(focused, disabled, active, pressed, receivedFocusFromKeyboard)', '_computeKeyboardClass(receivedFocusFromKeyboard)' ],
-  hostAttributes: {
-    role: 'button',
-    tabindex: '0',
-    animated: true
-  },
-  _calculateElevation: function() {
-    var e = 1;
-    if (this.disabled) {
-      e = 0;
-    } else if (this.active || this.pressed) {
-      e = 4;
-    } else if (this.receivedFocusFromKeyboard) {
-      e = 3;
-    }
-    this._setElevation(e);
-  },
-  _computeKeyboardClass: function(receivedFocusFromKeyboard) {
-    this.toggleClass('keyboard-focus', receivedFocusFromKeyboard);
-  },
-  _spaceKeyDownHandler: function(event) {
-    Polymer.IronButtonStateImpl._spaceKeyDownHandler.call(this, event);
-    if (this.hasRipple() && this.getRipple().ripples.length < 1) {
-      this._ripple.uiDownAction();
-    }
-  },
-  _spaceKeyUpHandler: function(event) {
-    Polymer.IronButtonStateImpl._spaceKeyUpHandler.call(this, event);
-    if (this.hasRipple()) {
-      this._ripple.uiUpAction();
-    }
-  }
-};
-
-Polymer.PaperButtonBehavior = [ Polymer.IronButtonState, Polymer.IronControlState, Polymer.PaperRippleBehavior, Polymer.PaperButtonBehaviorImpl ];
-
-Polymer({
-  is: 'paper-button',
-  behaviors: [ Polymer.PaperButtonBehavior ],
-  properties: {
-    raised: {
-      type: Boolean,
-      reflectToAttribute: true,
-      value: false,
-      observer: '_calculateElevation'
-    }
-  },
-  _calculateElevation: function() {
-    if (!this.raised) {
-      this._setElevation(0);
-    } else {
-      Polymer.PaperButtonBehaviorImpl._calculateElevation.apply(this);
-    }
-  }
-});
-
-Polymer.PaperItemBehaviorImpl = {
-  hostAttributes: {
-    role: 'option',
-    tabindex: '0'
-  }
-};
-
-Polymer.PaperItemBehavior = [ Polymer.IronButtonState, Polymer.IronControlState, Polymer.PaperItemBehaviorImpl ];
-
-Polymer({
-  is: 'paper-item',
-  behaviors: [ Polymer.PaperItemBehavior ]
-});
-
-Polymer.IronFitBehavior = {
-  properties: {
-    sizingTarget: {
-      type: Object,
-      value: function() {
-        return this;
-      }
-    },
-    fitInto: {
-      type: Object,
-      value: window
-    },
-    noOverlap: {
-      type: Boolean
-    },
-    positionTarget: {
-      type: Element
-    },
-    horizontalAlign: {
-      type: String
-    },
-    verticalAlign: {
-      type: String
-    },
-    dynamicAlign: {
-      type: Boolean
-    },
-    horizontalOffset: {
-      type: Number,
-      value: 0,
-      notify: true
-    },
-    verticalOffset: {
-      type: Number,
-      value: 0,
-      notify: true
-    },
-    autoFitOnAttach: {
-      type: Boolean,
-      value: false
-    },
-    _fitInfo: {
-      type: Object
-    }
-  },
-  get _fitWidth() {
-    var fitWidth;
-    if (this.fitInto === window) {
-      fitWidth = this.fitInto.innerWidth;
-    } else {
-      fitWidth = this.fitInto.getBoundingClientRect().width;
-    }
-    return fitWidth;
-  },
-  get _fitHeight() {
-    var fitHeight;
-    if (this.fitInto === window) {
-      fitHeight = this.fitInto.innerHeight;
-    } else {
-      fitHeight = this.fitInto.getBoundingClientRect().height;
-    }
-    return fitHeight;
-  },
-  get _fitLeft() {
-    var fitLeft;
-    if (this.fitInto === window) {
-      fitLeft = 0;
-    } else {
-      fitLeft = this.fitInto.getBoundingClientRect().left;
-    }
-    return fitLeft;
-  },
-  get _fitTop() {
-    var fitTop;
-    if (this.fitInto === window) {
-      fitTop = 0;
-    } else {
-      fitTop = this.fitInto.getBoundingClientRect().top;
-    }
-    return fitTop;
-  },
-  get _defaultPositionTarget() {
-    var parent = Polymer.dom(this).parentNode;
-    if (parent && parent.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
-      parent = parent.host;
-    }
-    return parent;
-  },
-  get _localeHorizontalAlign() {
-    if (this._isRTL) {
-      if (this.horizontalAlign === 'right') {
-        return 'left';
-      }
-      if (this.horizontalAlign === 'left') {
-        return 'right';
-      }
-    }
-    return this.horizontalAlign;
-  },
-  attached: function() {
-    this._isRTL = window.getComputedStyle(this).direction == 'rtl';
-    this.positionTarget = this.positionTarget || this._defaultPositionTarget;
-    if (this.autoFitOnAttach) {
-      if (window.getComputedStyle(this).display === 'none') {
-        setTimeout(function() {
-          this.fit();
-        }.bind(this));
-      } else {
-        this.fit();
-      }
-    }
-  },
-  fit: function() {
-    this.position();
-    this.constrain();
-    this.center();
-  },
-  _discoverInfo: function() {
-    if (this._fitInfo) {
-      return;
-    }
-    var target = window.getComputedStyle(this);
-    var sizer = window.getComputedStyle(this.sizingTarget);
-    this._fitInfo = {
-      inlineStyle: {
-        top: this.style.top || '',
-        left: this.style.left || '',
-        position: this.style.position || ''
-      },
-      sizerInlineStyle: {
-        maxWidth: this.sizingTarget.style.maxWidth || '',
-        maxHeight: this.sizingTarget.style.maxHeight || '',
-        boxSizing: this.sizingTarget.style.boxSizing || ''
-      },
-      positionedBy: {
-        vertically: target.top !== 'auto' ? 'top' : target.bottom !== 'auto' ? 'bottom' : null,
-        horizontally: target.left !== 'auto' ? 'left' : target.right !== 'auto' ? 'right' : null
-      },
-      sizedBy: {
-        height: sizer.maxHeight !== 'none',
-        width: sizer.maxWidth !== 'none',
-        minWidth: parseInt(sizer.minWidth, 10) || 0,
-        minHeight: parseInt(sizer.minHeight, 10) || 0
-      },
-      margin: {
-        top: parseInt(target.marginTop, 10) || 0,
-        right: parseInt(target.marginRight, 10) || 0,
-        bottom: parseInt(target.marginBottom, 10) || 0,
-        left: parseInt(target.marginLeft, 10) || 0
-      }
-    };
-    if (this.verticalOffset) {
-      this._fitInfo.margin.top = this._fitInfo.margin.bottom = this.verticalOffset;
-      this._fitInfo.inlineStyle.marginTop = this.style.marginTop || '';
-      this._fitInfo.inlineStyle.marginBottom = this.style.marginBottom || '';
-      this.style.marginTop = this.style.marginBottom = this.verticalOffset + 'px';
-    }
-    if (this.horizontalOffset) {
-      this._fitInfo.margin.left = this._fitInfo.margin.right = this.horizontalOffset;
-      this._fitInfo.inlineStyle.marginLeft = this.style.marginLeft || '';
-      this._fitInfo.inlineStyle.marginRight = this.style.marginRight || '';
-      this.style.marginLeft = this.style.marginRight = this.horizontalOffset + 'px';
-    }
-  },
-  resetFit: function() {
-    var info = this._fitInfo || {};
-    for (var property in info.sizerInlineStyle) {
-      this.sizingTarget.style[property] = info.sizerInlineStyle[property];
-    }
-    for (var property in info.inlineStyle) {
-      this.style[property] = info.inlineStyle[property];
-    }
-    this._fitInfo = null;
-  },
-  refit: function() {
-    var scrollLeft = this.sizingTarget.scrollLeft;
-    var scrollTop = this.sizingTarget.scrollTop;
-    this.resetFit();
-    this.fit();
-    this.sizingTarget.scrollLeft = scrollLeft;
-    this.sizingTarget.scrollTop = scrollTop;
-  },
-  position: function() {
-    if (!this.horizontalAlign && !this.verticalAlign) {
-      return;
-    }
-    this._discoverInfo();
-    this.style.position = 'fixed';
-    this.sizingTarget.style.boxSizing = 'border-box';
-    this.style.left = '0px';
-    this.style.top = '0px';
-    var rect = this.getBoundingClientRect();
-    var positionRect = this.__getNormalizedRect(this.positionTarget);
-    var fitRect = this.__getNormalizedRect(this.fitInto);
-    var margin = this._fitInfo.margin;
-    var size = {
-      width: rect.width + margin.left + margin.right,
-      height: rect.height + margin.top + margin.bottom
-    };
-    var position = this.__getPosition(this._localeHorizontalAlign, this.verticalAlign, size, positionRect, fitRect);
-    var left = position.left + margin.left;
-    var top = position.top + margin.top;
-    var right = Math.min(fitRect.right - margin.right, left + rect.width);
-    var bottom = Math.min(fitRect.bottom - margin.bottom, top + rect.height);
-    var minWidth = this._fitInfo.sizedBy.minWidth;
-    var minHeight = this._fitInfo.sizedBy.minHeight;
-    if (left < margin.left) {
-      left = margin.left;
-      if (right - left < minWidth) {
-        left = right - minWidth;
-      }
-    }
-    if (top < margin.top) {
-      top = margin.top;
-      if (bottom - top < minHeight) {
-        top = bottom - minHeight;
-      }
-    }
-    this.sizingTarget.style.maxWidth = right - left + 'px';
-    this.sizingTarget.style.maxHeight = bottom - top + 'px';
-    this.style.left = left - rect.left + 'px';
-    this.style.top = top - rect.top + 'px';
-  },
-  constrain: function() {
-    if (this.horizontalAlign || this.verticalAlign) {
-      return;
-    }
-    this._discoverInfo();
-    var info = this._fitInfo;
-    if (!info.positionedBy.vertically) {
-      this.style.position = 'fixed';
-      this.style.top = '0px';
-    }
-    if (!info.positionedBy.horizontally) {
-      this.style.position = 'fixed';
-      this.style.left = '0px';
-    }
-    this.sizingTarget.style.boxSizing = 'border-box';
-    var rect = this.getBoundingClientRect();
-    if (!info.sizedBy.height) {
-      this.__sizeDimension(rect, info.positionedBy.vertically, 'top', 'bottom', 'Height');
-    }
-    if (!info.sizedBy.width) {
-      this.__sizeDimension(rect, info.positionedBy.horizontally, 'left', 'right', 'Width');
-    }
-  },
-  _sizeDimension: function(rect, positionedBy, start, end, extent) {
-    this.__sizeDimension(rect, positionedBy, start, end, extent);
-  },
-  __sizeDimension: function(rect, positionedBy, start, end, extent) {
-    var info = this._fitInfo;
-    var fitRect = this.__getNormalizedRect(this.fitInto);
-    var max = extent === 'Width' ? fitRect.width : fitRect.height;
-    var flip = positionedBy === end;
-    var offset = flip ? max - rect[end] : rect[start];
-    var margin = info.margin[flip ? start : end];
-    var offsetExtent = 'offset' + extent;
-    var sizingOffset = this[offsetExtent] - this.sizingTarget[offsetExtent];
-    this.sizingTarget.style['max' + extent] = max - margin - offset - sizingOffset + 'px';
-  },
-  center: function() {
-    if (this.horizontalAlign || this.verticalAlign) {
-      return;
-    }
-    this._discoverInfo();
-    var positionedBy = this._fitInfo.positionedBy;
-    if (positionedBy.vertically && positionedBy.horizontally) {
-      return;
-    }
-    this.style.position = 'fixed';
-    if (!positionedBy.vertically) {
-      this.style.top = '0px';
-    }
-    if (!positionedBy.horizontally) {
-      this.style.left = '0px';
-    }
-    var rect = this.getBoundingClientRect();
-    var fitRect = this.__getNormalizedRect(this.fitInto);
-    if (!positionedBy.vertically) {
-      var top = fitRect.top - rect.top + (fitRect.height - rect.height) / 2;
-      this.style.top = top + 'px';
-    }
-    if (!positionedBy.horizontally) {
-      var left = fitRect.left - rect.left + (fitRect.width - rect.width) / 2;
-      this.style.left = left + 'px';
-    }
-  },
-  __getNormalizedRect: function(target) {
-    if (target === document.documentElement || target === window) {
-      return {
-        top: 0,
-        left: 0,
-        width: window.innerWidth,
-        height: window.innerHeight,
-        right: window.innerWidth,
-        bottom: window.innerHeight
-      };
-    }
-    return target.getBoundingClientRect();
-  },
-  __getCroppedArea: function(position, size, fitRect) {
-    var verticalCrop = Math.min(0, position.top) + Math.min(0, fitRect.bottom - (position.top + size.height));
-    var horizontalCrop = Math.min(0, position.left) + Math.min(0, fitRect.right - (position.left + size.width));
-    return Math.abs(verticalCrop) * size.width + Math.abs(horizontalCrop) * size.height;
-  },
-  __getPosition: function(hAlign, vAlign, size, positionRect, fitRect) {
-    var positions = [ {
-      verticalAlign: 'top',
-      horizontalAlign: 'left',
-      top: positionRect.top,
-      left: positionRect.left
-    }, {
-      verticalAlign: 'top',
-      horizontalAlign: 'right',
-      top: positionRect.top,
-      left: positionRect.right - size.width
-    }, {
-      verticalAlign: 'bottom',
-      horizontalAlign: 'left',
-      top: positionRect.bottom - size.height,
-      left: positionRect.left
-    }, {
-      verticalAlign: 'bottom',
-      horizontalAlign: 'right',
-      top: positionRect.bottom - size.height,
-      left: positionRect.right - size.width
-    } ];
-    if (this.noOverlap) {
-      for (var i = 0, l = positions.length; i < l; i++) {
-        var copy = {};
-        for (var key in positions[i]) {
-          copy[key] = positions[i][key];
-        }
-        positions.push(copy);
-      }
-      positions[0].top = positions[1].top += positionRect.height;
-      positions[2].top = positions[3].top -= positionRect.height;
-      positions[4].left = positions[6].left += positionRect.width;
-      positions[5].left = positions[7].left -= positionRect.width;
-    }
-    vAlign = vAlign === 'auto' ? null : vAlign;
-    hAlign = hAlign === 'auto' ? null : hAlign;
-    var position;
-    for (var i = 0; i < positions.length; i++) {
-      var pos = positions[i];
-      if (!this.dynamicAlign && !this.noOverlap && pos.verticalAlign === vAlign && pos.horizontalAlign === hAlign) {
-        position = pos;
-        break;
-      }
-      var alignOk = (!vAlign || pos.verticalAlign === vAlign) && (!hAlign || pos.horizontalAlign === hAlign);
-      if (!this.dynamicAlign && !alignOk) {
-        continue;
-      }
-      position = position || pos;
-      pos.croppedArea = this.__getCroppedArea(pos, size, fitRect);
-      var diff = pos.croppedArea - position.croppedArea;
-      if (diff < 0 || diff === 0 && alignOk) {
-        position = pos;
-      }
-      if (position.croppedArea === 0 && alignOk) {
-        break;
-      }
-    }
-    return position;
-  }
-};
-
-(function() {
-  'use strict';
-  Polymer({
-    is: 'iron-overlay-backdrop',
-    properties: {
-      opened: {
-        reflectToAttribute: true,
-        type: Boolean,
-        value: false,
-        observer: '_openedChanged'
-      }
-    },
-    listeners: {
-      transitionend: '_onTransitionend'
-    },
-    created: function() {
-      this.__openedRaf = null;
-    },
-    attached: function() {
-      this.opened && this._openedChanged(this.opened);
-    },
-    prepare: function() {
-      if (this.opened && !this.parentNode) {
-        Polymer.dom(document.body).appendChild(this);
-      }
-    },
-    open: function() {
-      this.opened = true;
-    },
-    close: function() {
-      this.opened = false;
-    },
-    complete: function() {
-      if (!this.opened && this.parentNode === document.body) {
-        Polymer.dom(this.parentNode).removeChild(this);
-      }
-    },
-    _onTransitionend: function(event) {
-      if (event && event.target === this) {
-        this.complete();
-      }
-    },
-    _openedChanged: function(opened) {
-      if (opened) {
-        this.prepare();
-      } else {
-        var cs = window.getComputedStyle(this);
-        if (cs.transitionDuration === '0s' || cs.opacity == 0) {
-          this.complete();
-        }
-      }
-      if (!this.isAttached) {
-        return;
-      }
-      if (this.__openedRaf) {
-        window.cancelAnimationFrame(this.__openedRaf);
-        this.__openedRaf = null;
-      }
-      this.scrollTop = this.scrollTop;
-      this.__openedRaf = window.requestAnimationFrame(function() {
-        this.__openedRaf = null;
-        this.toggleClass('opened', this.opened);
-      }.bind(this));
-    }
-  });
-})();
-
-Polymer.IronOverlayManagerClass = function() {
-  this._overlays = [];
-  this._minimumZ = 101;
-  this._backdropElement = null;
-  Polymer.Gestures.add(document, 'tap', this._onCaptureClick.bind(this));
-  document.addEventListener('focus', this._onCaptureFocus.bind(this), true);
-  document.addEventListener('keydown', this._onCaptureKeyDown.bind(this), true);
-};
-
-Polymer.IronOverlayManagerClass.prototype = {
-  constructor: Polymer.IronOverlayManagerClass,
-  get backdropElement() {
-    if (!this._backdropElement) {
-      this._backdropElement = document.createElement('iron-overlay-backdrop');
-    }
-    return this._backdropElement;
-  },
-  get deepActiveElement() {
-    var active = document.activeElement || document.body;
-    while (active.root && Polymer.dom(active.root).activeElement) {
-      active = Polymer.dom(active.root).activeElement;
-    }
-    return active;
-  },
-  _bringOverlayAtIndexToFront: function(i) {
-    var overlay = this._overlays[i];
-    if (!overlay) {
-      return;
-    }
-    var lastI = this._overlays.length - 1;
-    var currentOverlay = this._overlays[lastI];
-    if (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay)) {
-      lastI--;
-    }
-    if (i >= lastI) {
-      return;
-    }
-    var minimumZ = Math.max(this.currentOverlayZ(), this._minimumZ);
-    if (this._getZ(overlay) <= minimumZ) {
-      this._applyOverlayZ(overlay, minimumZ);
-    }
-    while (i < lastI) {
-      this._overlays[i] = this._overlays[i + 1];
-      i++;
-    }
-    this._overlays[lastI] = overlay;
-  },
-  addOrRemoveOverlay: function(overlay) {
-    if (overlay.opened) {
-      this.addOverlay(overlay);
-    } else {
-      this.removeOverlay(overlay);
-    }
-  },
-  addOverlay: function(overlay) {
-    var i = this._overlays.indexOf(overlay);
-    if (i >= 0) {
-      this._bringOverlayAtIndexToFront(i);
-      this.trackBackdrop();
-      return;
-    }
-    var insertionIndex = this._overlays.length;
-    var currentOverlay = this._overlays[insertionIndex - 1];
-    var minimumZ = Math.max(this._getZ(currentOverlay), this._minimumZ);
-    var newZ = this._getZ(overlay);
-    if (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay)) {
-      this._applyOverlayZ(currentOverlay, minimumZ);
-      insertionIndex--;
-      var previousOverlay = this._overlays[insertionIndex - 1];
-      minimumZ = Math.max(this._getZ(previousOverlay), this._minimumZ);
-    }
-    if (newZ <= minimumZ) {
-      this._applyOverlayZ(overlay, minimumZ);
-    }
-    this._overlays.splice(insertionIndex, 0, overlay);
-    this.trackBackdrop();
-  },
-  removeOverlay: function(overlay) {
-    var i = this._overlays.indexOf(overlay);
-    if (i === -1) {
-      return;
-    }
-    this._overlays.splice(i, 1);
-    this.trackBackdrop();
-  },
-  currentOverlay: function() {
-    var i = this._overlays.length - 1;
-    return this._overlays[i];
-  },
-  currentOverlayZ: function() {
-    return this._getZ(this.currentOverlay());
-  },
-  ensureMinimumZ: function(minimumZ) {
-    this._minimumZ = Math.max(this._minimumZ, minimumZ);
-  },
-  focusOverlay: function() {
-    var current = this.currentOverlay();
-    if (current) {
-      current._applyFocus();
-    }
-  },
-  trackBackdrop: function() {
-    var overlay = this._overlayWithBackdrop();
-    if (!overlay && !this._backdropElement) {
-      return;
-    }
-    this.backdropElement.style.zIndex = this._getZ(overlay) - 1;
-    this.backdropElement.opened = !!overlay;
-  },
-  getBackdrops: function() {
-    var backdrops = [];
-    for (var i = 0; i < this._overlays.length; i++) {
-      if (this._overlays[i].withBackdrop) {
-        backdrops.push(this._overlays[i]);
-      }
-    }
-    return backdrops;
-  },
-  backdropZ: function() {
-    return this._getZ(this._overlayWithBackdrop()) - 1;
-  },
-  _overlayWithBackdrop: function() {
-    for (var i = 0; i < this._overlays.length; i++) {
-      if (this._overlays[i].withBackdrop) {
-        return this._overlays[i];
-      }
-    }
-  },
-  _getZ: function(overlay) {
-    var z = this._minimumZ;
-    if (overlay) {
-      var z1 = Number(overlay.style.zIndex || window.getComputedStyle(overlay).zIndex);
-      if (z1 === z1) {
-        z = z1;
-      }
-    }
-    return z;
-  },
-  _setZ: function(element, z) {
-    element.style.zIndex = z;
-  },
-  _applyOverlayZ: function(overlay, aboveZ) {
-    this._setZ(overlay, aboveZ + 2);
-  },
-  _overlayInPath: function(path) {
-    path = path || [];
-    for (var i = 0; i < path.length; i++) {
-      if (path[i]._manager === this) {
-        return path[i];
-      }
-    }
-  },
-  _onCaptureClick: function(event) {
-    var overlay = this.currentOverlay();
-    if (overlay && this._overlayInPath(Polymer.dom(event).path) !== overlay) {
-      overlay._onCaptureClick(event);
-    }
-  },
-  _onCaptureFocus: function(event) {
-    var overlay = this.currentOverlay();
-    if (overlay) {
-      overlay._onCaptureFocus(event);
-    }
-  },
-  _onCaptureKeyDown: function(event) {
-    var overlay = this.currentOverlay();
-    if (overlay) {
-      if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 'esc')) {
-        overlay._onCaptureEsc(event);
-      } else if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 'tab')) {
-        overlay._onCaptureTab(event);
-      }
-    }
-  },
-  _shouldBeBehindOverlay: function(overlay1, overlay2) {
-    return !overlay1.alwaysOnTop && overlay2.alwaysOnTop;
-  }
-};
-
-Polymer.IronOverlayManager = new Polymer.IronOverlayManagerClass();
-
-(function() {
-  'use strict';
-  Polymer.IronOverlayBehaviorImpl = {
-    properties: {
-      opened: {
-        observer: '_openedChanged',
-        type: Boolean,
-        value: false,
-        notify: true
-      },
-      canceled: {
-        observer: '_canceledChanged',
-        readOnly: true,
-        type: Boolean,
-        value: false
-      },
-      withBackdrop: {
-        observer: '_withBackdropChanged',
-        type: Boolean
-      },
-      noAutoFocus: {
-        type: Boolean,
-        value: false
-      },
-      noCancelOnEscKey: {
-        type: Boolean,
-        value: false
-      },
-      noCancelOnOutsideClick: {
-        type: Boolean,
-        value: false
-      },
-      closingReason: {
-        type: Object
-      },
-      restoreFocusOnClose: {
-        type: Boolean,
-        value: false
-      },
-      alwaysOnTop: {
-        type: Boolean
-      },
-      _manager: {
-        type: Object,
-        value: Polymer.IronOverlayManager
-      },
-      _focusedChild: {
-        type: Object
-      }
-    },
-    listeners: {
-      'iron-resize': '_onIronResize'
-    },
-    get backdropElement() {
-      return this._manager.backdropElement;
-    },
-    get _focusNode() {
-      return this._focusedChild || Polymer.dom(this).querySelector('[autofocus]') || this;
-    },
-    get _focusableNodes() {
-      var FOCUSABLE_WITH_DISABLED = [ 'a[href]', 'area[href]', 'iframe', '[tabindex]', '[contentEditable=true]' ];
-      var FOCUSABLE_WITHOUT_DISABLED = [ 'input', 'select', 'textarea', 'button' ];
-      var selector = FOCUSABLE_WITH_DISABLED.join(':not([tabindex="-1"]),') + ':not([tabindex="-1"]),' + FOCUSABLE_WITHOUT_DISABLED.join(':not([disabled]):not([tabindex="-1"]),') + ':not([disabled]):not([tabindex="-1"])';
-      var focusables = Polymer.dom(this).querySelectorAll(selector);
-      if (this.tabIndex >= 0) {
-        focusables.splice(0, 0, this);
-      }
-      return focusables.sort(function(a, b) {
-        if (a.tabIndex === b.tabIndex) {
-          return 0;
-        }
-        if (a.tabIndex === 0 || a.tabIndex > b.tabIndex) {
-          return 1;
-        }
-        return -1;
-      });
-    },
-    ready: function() {
-      this.__isAnimating = false;
-      this.__shouldRemoveTabIndex = false;
-      this.__firstFocusableNode = this.__lastFocusableNode = null;
-      this.__raf = null;
-      this.__restoreFocusNode = null;
-      this._ensureSetup();
-    },
-    attached: function() {
-      if (this.opened) {
-        this._openedChanged(this.opened);
-      }
-      this._observer = Polymer.dom(this).observeNodes(this._onNodesChange);
-    },
-    detached: function() {
-      Polymer.dom(this).unobserveNodes(this._observer);
-      this._observer = null;
-      if (this.__raf) {
-        window.cancelAnimationFrame(this.__raf);
-        this.__raf = null;
-      }
-      this._manager.removeOverlay(this);
-    },
-    toggle: function() {
-      this._setCanceled(false);
-      this.opened = !this.opened;
-    },
-    open: function() {
-      this._setCanceled(false);
-      this.opened = true;
-    },
-    close: function() {
-      this._setCanceled(false);
-      this.opened = false;
-    },
-    cancel: function(event) {
-      var cancelEvent = this.fire('iron-overlay-canceled', event, {
-        cancelable: true
-      });
-      if (cancelEvent.defaultPrevented) {
-        return;
-      }
-      this._setCanceled(true);
-      this.opened = false;
-    },
-    _ensureSetup: function() {
-      if (this._overlaySetup) {
-        return;
-      }
-      this._overlaySetup = true;
-      this.style.outline = 'none';
-      this.style.display = 'none';
-    },
-    _openedChanged: function(opened) {
-      if (opened) {
-        this.removeAttribute('aria-hidden');
-      } else {
-        this.setAttribute('aria-hidden', 'true');
-      }
-      if (!this.isAttached) {
-        return;
-      }
-      this.__isAnimating = true;
-      this.__onNextAnimationFrame(this.__openedChanged);
-    },
-    _canceledChanged: function() {
-      this.closingReason = this.closingReason || {};
-      this.closingReason.canceled = this.canceled;
-    },
-    _withBackdropChanged: function() {
-      if (this.withBackdrop && !this.hasAttribute('tabindex')) {
-        this.setAttribute('tabindex', '-1');
-        this.__shouldRemoveTabIndex = true;
-      } else if (this.__shouldRemoveTabIndex) {
-        this.removeAttribute('tabindex');
-        this.__shouldRemoveTabIndex = false;
-      }
-      if (this.opened && this.isAttached) {
-        this._manager.trackBackdrop();
-      }
-    },
-    _prepareRenderOpened: function() {
-      this.__restoreFocusNode = this._manager.deepActiveElement;
-      this._preparePositioning();
-      this.refit();
-      this._finishPositioning();
-      if (this.noAutoFocus && document.activeElement === this._focusNode) {
-        this._focusNode.blur();
-        this.__restoreFocusNode.focus();
-      }
-    },
-    _renderOpened: function() {
-      this._finishRenderOpened();
-    },
-    _renderClosed: function() {
-      this._finishRenderClosed();
-    },
-    _finishRenderOpened: function() {
-      this.notifyResize();
-      this.__isAnimating = false;
-      var focusableNodes = this._focusableNodes;
-      this.__firstFocusableNode = focusableNodes[0];
-      this.__lastFocusableNode = focusableNodes[focusableNodes.length - 1];
-      this.fire('iron-overlay-opened');
-    },
-    _finishRenderClosed: function() {
-      this.style.display = 'none';
-      this.style.zIndex = '';
-      this.notifyResize();
-      this.__isAnimating = false;
-      this.fire('iron-overlay-closed', this.closingReason);
-    },
-    _preparePositioning: function() {
-      this.style.transition = this.style.webkitTransition = 'none';
-      this.style.transform = this.style.webkitTransform = 'none';
-      this.style.display = '';
-    },
-    _finishPositioning: function() {
-      this.style.display = 'none';
-      this.scrollTop = this.scrollTop;
-      this.style.transition = this.style.webkitTransition = '';
-      this.style.transform = this.style.webkitTransform = '';
-      this.style.display = '';
-      this.scrollTop = this.scrollTop;
-    },
-    _applyFocus: function() {
-      if (this.opened) {
-        if (!this.noAutoFocus) {
-          this._focusNode.focus();
-        }
-      } else {
-        this._focusNode.blur();
-        this._focusedChild = null;
-        if (this.restoreFocusOnClose && this.__restoreFocusNode) {
-          this.__restoreFocusNode.focus();
-        }
-        this.__restoreFocusNode = null;
-        var currentOverlay = this._manager.currentOverlay();
-        if (currentOverlay && this !== currentOverlay) {
-          currentOverlay._applyFocus();
-        }
-      }
-    },
-    _onCaptureClick: function(event) {
-      if (!this.noCancelOnOutsideClick) {
-        this.cancel(event);
-      }
-    },
-    _onCaptureFocus: function(event) {
-      if (!this.withBackdrop) {
-        return;
-      }
-      var path = Polymer.dom(event).path;
-      if (path.indexOf(this) === -1) {
-        event.stopPropagation();
-        this._applyFocus();
-      } else {
-        this._focusedChild = path[0];
-      }
-    },
-    _onCaptureEsc: function(event) {
-      if (!this.noCancelOnEscKey) {
-        this.cancel(event);
-      }
-    },
-    _onCaptureTab: function(event) {
-      if (!this.withBackdrop) {
-        return;
-      }
-      var shift = event.shiftKey;
-      var nodeToCheck = shift ? this.__firstFocusableNode : this.__lastFocusableNode;
-      var nodeToSet = shift ? this.__lastFocusableNode : this.__firstFocusableNode;
-      var shouldWrap = false;
-      if (nodeToCheck === nodeToSet) {
-        shouldWrap = true;
-      } else {
-        var focusedNode = this._manager.deepActiveElement;
-        shouldWrap = focusedNode === nodeToCheck || focusedNode === this;
-      }
-      if (shouldWrap) {
-        event.preventDefault();
-        this._focusedChild = nodeToSet;
-        this._applyFocus();
-      }
-    },
-    _onIronResize: function() {
-      if (this.opened && !this.__isAnimating) {
-        this.__onNextAnimationFrame(this.refit);
-      }
-    },
-    _onNodesChange: function() {
-      if (this.opened && !this.__isAnimating) {
-        this.notifyResize();
-      }
-    },
-    __openedChanged: function() {
-      if (this.opened) {
-        this._prepareRenderOpened();
-        this._manager.addOverlay(this);
-        this._applyFocus();
-        this._renderOpened();
-      } else {
-        this._manager.removeOverlay(this);
-        this._applyFocus();
-        this._renderClosed();
-      }
-    },
-    __onNextAnimationFrame: function(callback) {
-      if (this.__raf) {
-        window.cancelAnimationFrame(this.__raf);
-      }
-      var self = this;
-      this.__raf = window.requestAnimationFrame(function nextAnimationFrame() {
-        self.__raf = null;
-        callback.call(self);
-      });
-    }
-  };
-  Polymer.IronOverlayBehavior = [ Polymer.IronFitBehavior, Polymer.IronResizableBehavior, Polymer.IronOverlayBehaviorImpl ];
-})();
-
-Polymer.NeonAnimatableBehavior = {
-  properties: {
-    animationConfig: {
-      type: Object
-    },
-    entryAnimation: {
-      observer: '_entryAnimationChanged',
-      type: String
-    },
-    exitAnimation: {
-      observer: '_exitAnimationChanged',
-      type: String
-    }
-  },
-  _entryAnimationChanged: function() {
-    this.animationConfig = this.animationConfig || {};
-    this.animationConfig['entry'] = [ {
-      name: this.entryAnimation,
-      node: this
-    } ];
-  },
-  _exitAnimationChanged: function() {
-    this.animationConfig = this.animationConfig || {};
-    this.animationConfig['exit'] = [ {
-      name: this.exitAnimation,
-      node: this
-    } ];
-  },
-  _copyProperties: function(config1, config2) {
-    for (var property in config2) {
-      config1[property] = config2[property];
-    }
-  },
-  _cloneConfig: function(config) {
-    var clone = {
-      isClone: true
-    };
-    this._copyProperties(clone, config);
-    return clone;
-  },
-  _getAnimationConfigRecursive: function(type, map, allConfigs) {
-    if (!this.animationConfig) {
-      return;
-    }
-    if (this.animationConfig.value && typeof this.animationConfig.value === 'function') {
-      this._warn(this._logf('playAnimation', "Please put 'animationConfig' inside of your components 'properties' object instead of outside of it."));
-      return;
-    }
-    var thisConfig;
-    if (type) {
-      thisConfig = this.animationConfig[type];
-    } else {
-      thisConfig = this.animationConfig;
-    }
-    if (!Array.isArray(thisConfig)) {
-      thisConfig = [ thisConfig ];
-    }
-    if (thisConfig) {
-      for (var config, index = 0; config = thisConfig[index]; index++) {
-        if (config.animatable) {
-          config.animatable._getAnimationConfigRecursive(config.type || type, map, allConfigs);
-        } else {
-          if (config.id) {
-            var cachedConfig = map[config.id];
-            if (cachedConfig) {
-              if (!cachedConfig.isClone) {
-                map[config.id] = this._cloneConfig(cachedConfig);
-                cachedConfig = map[config.id];
-              }
-              this._copyProperties(cachedConfig, config);
-            } else {
-              map[config.id] = config;
-            }
-          } else {
-            allConfigs.push(config);
-          }
-        }
-      }
-    }
-  },
-  getAnimationConfig: function(type) {
-    var map = {};
-    var allConfigs = [];
-    this._getAnimationConfigRecursive(type, map, allConfigs);
-    for (var key in map) {
-      allConfigs.push(map[key]);
-    }
-    return allConfigs;
-  }
-};
-
-Polymer.NeonAnimationRunnerBehaviorImpl = {
-  _configureAnimations: function(configs) {
-    var results = [];
-    if (configs.length > 0) {
-      for (var config, index = 0; config = configs[index]; index++) {
-        var neonAnimation = document.createElement(config.name);
-        if (neonAnimation.isNeonAnimation) {
-          var result = null;
-          try {
-            result = neonAnimation.configure(config);
-            if (typeof result.cancel != 'function') {
-              result = document.timeline.play(result);
-            }
-          } catch (e) {
-            result = null;
-            console.warn('Couldnt play', '(', config.name, ').', e);
-          }
-          if (result) {
-            results.push({
-              neonAnimation: neonAnimation,
-              config: config,
-              animation: result
-            });
-          }
-        } else {
-          console.warn(this.is + ':', config.name, 'not found!');
-        }
-      }
-    }
-    return results;
-  },
-  _shouldComplete: function(activeEntries) {
-    var finished = true;
-    for (var i = 0; i < activeEntries.length; i++) {
-      if (activeEntries[i].animation.playState != 'finished') {
-        finished = false;
-        break;
-      }
-    }
-    return finished;
-  },
-  _complete: function(activeEntries) {
-    for (var i = 0; i < activeEntries.length; i++) {
-      activeEntries[i].neonAnimation.complete(activeEntries[i].config);
-    }
-    for (var i = 0; i < activeEntries.length; i++) {
-      activeEntries[i].animation.cancel();
-    }
-  },
-  playAnimation: function(type, cookie) {
-    var configs = this.getAnimationConfig(type);
-    if (!configs) {
-      return;
-    }
-    this._active = this._active || {};
-    if (this._active[type]) {
-      this._complete(this._active[type]);
-      delete this._active[type];
-    }
-    var activeEntries = this._configureAnimations(configs);
-    if (activeEntries.length == 0) {
-      this.fire('neon-animation-finish', cookie, {
-        bubbles: false
-      });
-      return;
-    }
-    this._active[type] = activeEntries;
-    for (var i = 0; i < activeEntries.length; i++) {
-      activeEntries[i].animation.onfinish = function() {
-        if (this._shouldComplete(activeEntries)) {
-          this._complete(activeEntries);
-          delete this._active[type];
-          this.fire('neon-animation-finish', cookie, {
-            bubbles: false
-          });
-        }
-      }.bind(this);
-    }
-  },
-  cancelAnimation: function() {
-    for (var k in this._animations) {
-      this._animations[k].cancel();
-    }
-    this._animations = {};
-  }
-};
-
-Polymer.NeonAnimationRunnerBehavior = [ Polymer.NeonAnimatableBehavior, Polymer.NeonAnimationRunnerBehaviorImpl ];
-
-Polymer.NeonAnimationBehavior = {
-  properties: {
-    animationTiming: {
-      type: Object,
-      value: function() {
-        return {
-          duration: 500,
-          easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
-          fill: 'both'
-        };
-      }
-    }
-  },
-  isNeonAnimation: true,
-  timingFromConfig: function(config) {
-    if (config.timing) {
-      for (var property in config.timing) {
-        this.animationTiming[property] = config.timing[property];
-      }
-    }
-    return this.animationTiming;
-  },
-  setPrefixedProperty: function(node, property, value) {
-    var map = {
-      transform: [ 'webkitTransform' ],
-      transformOrigin: [ 'mozTransformOrigin', 'webkitTransformOrigin' ]
-    };
-    var prefixes = map[property];
-    for (var prefix, index = 0; prefix = prefixes[index]; index++) {
-      node.style[prefix] = value;
-    }
-    node.style[property] = value;
-  },
-  complete: function() {}
-};
-
-Polymer({
-  is: 'opaque-animation',
-  behaviors: [ Polymer.NeonAnimationBehavior ],
-  configure: function(config) {
-    var node = config.node;
-    this._effect = new KeyframeEffect(node, [ {
-      opacity: '1'
-    }, {
-      opacity: '1'
-    } ], this.timingFromConfig(config));
-    node.style.opacity = '0';
-    return this._effect;
-  },
-  complete: function(config) {
-    config.node.style.opacity = '';
-  }
-});
-
-(function() {
-  'use strict';
-  var LAST_TOUCH_POSITION = {
-    pageX: 0,
-    pageY: 0
-  };
-  var ROOT_TARGET = null;
-  var SCROLLABLE_NODES = [];
-  Polymer.IronDropdownScrollManager = {
-    get currentLockingElement() {
-      return this._lockingElements[this._lockingElements.length - 1];
-    },
-    elementIsScrollLocked: function(element) {
-      var currentLockingElement = this.currentLockingElement;
-      if (currentLockingElement === undefined) return false;
-      var scrollLocked;
-      if (this._hasCachedLockedElement(element)) {
-        return true;
-      }
-      if (this._hasCachedUnlockedElement(element)) {
-        return false;
-      }
-      scrollLocked = !!currentLockingElement && currentLockingElement !== element && !this._composedTreeContains(currentLockingElement, element);
-      if (scrollLocked) {
-        this._lockedElementCache.push(element);
-      } else {
-        this._unlockedElementCache.push(element);
-      }
-      return scrollLocked;
-    },
-    pushScrollLock: function(element) {
-      if (this._lockingElements.indexOf(element) >= 0) {
-        return;
-      }
-      if (this._lockingElements.length === 0) {
-        this._lockScrollInteractions();
-      }
-      this._lockingElements.push(element);
-      this._lockedElementCache = [];
-      this._unlockedElementCache = [];
-    },
-    removeScrollLock: function(element) {
-      var index = this._lockingElements.indexOf(element);
-      if (index === -1) {
-        return;
-      }
-      this._lockingElements.splice(index, 1);
-      this._lockedElementCache = [];
-      this._unlockedElementCache = [];
-      if (this._lockingElements.length === 0) {
-        this._unlockScrollInteractions();
-      }
-    },
-    _lockingElements: [],
-    _lockedElementCache: null,
-    _unlockedElementCache: null,
-    _hasCachedLockedElement: function(element) {
-      return this._lockedElementCache.indexOf(element) > -1;
-    },
-    _hasCachedUnlockedElement: function(element) {
-      return this._unlockedElementCache.indexOf(element) > -1;
-    },
-    _composedTreeContains: function(element, child) {
-      var contentElements;
-      var distributedNodes;
-      var contentIndex;
-      var nodeIndex;
-      if (element.contains(child)) {
-        return true;
-      }
-      contentElements = Polymer.dom(element).querySelectorAll('content');
-      for (contentIndex = 0; contentIndex < contentElements.length; ++contentIndex) {
-        distributedNodes = Polymer.dom(contentElements[contentIndex]).getDistributedNodes();
-        for (nodeIndex = 0; nodeIndex < distributedNodes.length; ++nodeIndex) {
-          if (this._composedTreeContains(distributedNodes[nodeIndex], child)) {
-            return true;
-          }
-        }
-      }
-      return false;
-    },
-    _scrollInteractionHandler: function(event) {
-      if (event.cancelable && this._shouldPreventScrolling(event)) {
-        event.preventDefault();
-      }
-      if (event.targetTouches) {
-        var touch = event.targetTouches[0];
-        LAST_TOUCH_POSITION.pageX = touch.pageX;
-        LAST_TOUCH_POSITION.pageY = touch.pageY;
-      }
-    },
-    _lockScrollInteractions: function() {
-      this._boundScrollHandler = this._boundScrollHandler || this._scrollInteractionHandler.bind(this);
-      document.addEventListener('wheel', this._boundScrollHandler, true);
-      document.addEventListener('mousewheel', this._boundScrollHandler, true);
-      document.addEventListener('DOMMouseScroll', this._boundScrollHandler, true);
-      document.addEventListener('touchstart', this._boundScrollHandler, true);
-      document.addEventListener('touchmove', this._boundScrollHandler, true);
-    },
-    _unlockScrollInteractions: function() {
-      document.removeEventListener('wheel', this._boundScrollHandler, true);
-      document.removeEventListener('mousewheel', this._boundScrollHandler, true);
-      document.removeEventListener('DOMMouseScroll', this._boundScrollHandler, true);
-      document.removeEventListener('touchstart', this._boundScrollHandler, true);
-      document.removeEventListener('touchmove', this._boundScrollHandler, true);
-    },
-    _shouldPreventScrolling: function(event) {
-      var target = Polymer.dom(event).rootTarget;
-      if (event.type !== 'touchmove' && ROOT_TARGET !== target) {
-        ROOT_TARGET = target;
-        SCROLLABLE_NODES = this._getScrollableNodes(Polymer.dom(event).path);
-      }
-      if (!SCROLLABLE_NODES.length) {
-        return true;
-      }
-      if (event.type === 'touchstart') {
-        return false;
-      }
-      var info = this._getScrollInfo(event);
-      return !this._getScrollingNode(SCROLLABLE_NODES, info.deltaX, info.deltaY);
-    },
-    _getScrollableNodes: function(nodes) {
-      var scrollables = [];
-      var lockingIndex = nodes.indexOf(this.currentLockingElement);
-      for (var i = 0; i <= lockingIndex; i++) {
-        var node = nodes[i];
-        if (node.nodeType === 11) {
-          continue;
-        }
-        var style = node.style;
-        if (style.overflow !== 'scroll' && style.overflow !== 'auto') {
-          style = window.getComputedStyle(node);
-        }
-        if (style.overflow === 'scroll' || style.overflow === 'auto') {
-          scrollables.push(node);
-        }
-      }
-      return scrollables;
-    },
-    _getScrollingNode: function(nodes, deltaX, deltaY) {
-      if (!deltaX && !deltaY) {
-        return;
-      }
-      var verticalScroll = Math.abs(deltaY) >= Math.abs(deltaX);
-      for (var i = 0; i < nodes.length; i++) {
-        var node = nodes[i];
-        var canScroll = false;
-        if (verticalScroll) {
-          canScroll = deltaY < 0 ? node.scrollTop > 0 : node.scrollTop < node.scrollHeight - node.clientHeight;
-        } else {
-          canScroll = deltaX < 0 ? node.scrollLeft > 0 : node.scrollLeft < node.scrollWidth - node.clientWidth;
-        }
-        if (canScroll) {
-          return node;
-        }
-      }
-    },
-    _getScrollInfo: function(event) {
-      var info = {
-        deltaX: event.deltaX,
-        deltaY: event.deltaY
-      };
-      if ('deltaX' in event) {} else if ('wheelDeltaX' in event) {
-        info.deltaX = -event.wheelDeltaX;
-        info.deltaY = -event.wheelDeltaY;
-      } else if ('axis' in event) {
-        info.deltaX = event.axis === 1 ? event.detail : 0;
-        info.deltaY = event.axis === 2 ? event.detail : 0;
-      } else if (event.targetTouches) {
-        var touch = event.targetTouches[0];
-        info.deltaX = LAST_TOUCH_POSITION.pageX - touch.pageX;
-        info.deltaY = LAST_TOUCH_POSITION.pageY - touch.pageY;
-      }
-      return info;
-    }
-  };
-})();
-
-(function() {
-  'use strict';
-  Polymer({
-    is: 'iron-dropdown',
-    behaviors: [ Polymer.IronControlState, Polymer.IronA11yKeysBehavior, Polymer.IronOverlayBehavior, Polymer.NeonAnimationRunnerBehavior ],
-    properties: {
-      horizontalAlign: {
-        type: String,
-        value: 'left',
-        reflectToAttribute: true
-      },
-      verticalAlign: {
-        type: String,
-        value: 'top',
-        reflectToAttribute: true
-      },
-      openAnimationConfig: {
-        type: Object
-      },
-      closeAnimationConfig: {
-        type: Object
-      },
-      focusTarget: {
-        type: Object
-      },
-      noAnimations: {
-        type: Boolean,
-        value: false
-      },
-      allowOutsideScroll: {
-        type: Boolean,
-        value: false
-      },
-      _boundOnCaptureScroll: {
-        type: Function,
-        value: function() {
-          return this._onCaptureScroll.bind(this);
-        }
-      }
-    },
-    listeners: {
-      'neon-animation-finish': '_onNeonAnimationFinish'
-    },
-    observers: [ '_updateOverlayPosition(positionTarget, verticalAlign, horizontalAlign, verticalOffset, horizontalOffset)' ],
-    get containedElement() {
-      return Polymer.dom(this.$.content).getDistributedNodes()[0];
-    },
-    get _focusTarget() {
-      return this.focusTarget || this.containedElement;
-    },
-    ready: function() {
-      this._scrollTop = 0;
-      this._scrollLeft = 0;
-      this._refitOnScrollRAF = null;
-    },
-    attached: function() {
-      if (!this.sizingTarget || this.sizingTarget === this) {
-        this.sizingTarget = this.containedElement;
-      }
-    },
-    detached: function() {
-      this.cancelAnimation();
-      document.removeEventListener('scroll', this._boundOnCaptureScroll);
-      Polymer.IronDropdownScrollManager.removeScrollLock(this);
-    },
-    _openedChanged: function() {
-      if (this.opened && this.disabled) {
-        this.cancel();
-      } else {
-        this.cancelAnimation();
-        this._updateAnimationConfig();
-        this._saveScrollPosition();
-        if (this.opened) {
-          document.addEventListener('scroll', this._boundOnCaptureScroll);
-          !this.allowOutsideScroll && Polymer.IronDropdownScrollManager.pushScrollLock(this);
-        } else {
-          document.removeEventListener('scroll', this._boundOnCaptureScroll);
-          Polymer.IronDropdownScrollManager.removeScrollLock(this);
-        }
-        Polymer.IronOverlayBehaviorImpl._openedChanged.apply(this, arguments);
-      }
-    },
-    _renderOpened: function() {
-      if (!this.noAnimations && this.animationConfig.open) {
-        this.$.contentWrapper.classList.add('animating');
-        this.playAnimation('open');
-      } else {
-        Polymer.IronOverlayBehaviorImpl._renderOpened.apply(this, arguments);
-      }
-    },
-    _renderClosed: function() {
-      if (!this.noAnimations && this.animationConfig.close) {
-        this.$.contentWrapper.classList.add('animating');
-        this.playAnimation('close');
-      } else {
-        Polymer.IronOverlayBehaviorImpl._renderClosed.apply(this, arguments);
-      }
-    },
-    _onNeonAnimationFinish: function() {
-      this.$.contentWrapper.classList.remove('animating');
-      if (this.opened) {
-        this._finishRenderOpened();
-      } else {
-        this._finishRenderClosed();
-      }
-    },
-    _onCaptureScroll: function() {
-      if (!this.allowOutsideScroll) {
-        this._restoreScrollPosition();
-      } else {
-        this._refitOnScrollRAF && window.cancelAnimationFrame(this._refitOnScrollRAF);
-        this._refitOnScrollRAF = window.requestAnimationFrame(this.refit.bind(this));
-      }
-    },
-    _saveScrollPosition: function() {
-      if (document.scrollingElement) {
-        this._scrollTop = document.scrollingElement.scrollTop;
-        this._scrollLeft = document.scrollingElement.scrollLeft;
-      } else {
-        this._scrollTop = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
-        this._scrollLeft = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft);
-      }
-    },
-    _restoreScrollPosition: function() {
-      if (document.scrollingElement) {
-        document.scrollingElement.scrollTop = this._scrollTop;
-        document.scrollingElement.scrollLeft = this._scrollLeft;
-      } else {
-        document.documentElement.scrollTop = this._scrollTop;
-        document.documentElement.scrollLeft = this._scrollLeft;
-        document.body.scrollTop = this._scrollTop;
-        document.body.scrollLeft = this._scrollLeft;
-      }
-    },
-    _updateAnimationConfig: function() {
-      var animations = (this.openAnimationConfig || []).concat(this.closeAnimationConfig || []);
-      for (var i = 0; i < animations.length; i++) {
-        animations[i].node = this.containedElement;
-      }
-      this.animationConfig = {
-        open: this.openAnimationConfig,
-        close: this.closeAnimationConfig
-      };
-    },
-    _updateOverlayPosition: function() {
-      if (this.isAttached) {
-        this.notifyResize();
-      }
-    },
-    _applyFocus: function() {
-      var focusTarget = this.focusTarget || this.containedElement;
-      if (focusTarget && this.opened && !this.noAutoFocus) {
-        focusTarget.focus();
-      } else {
-        Polymer.IronOverlayBehaviorImpl._applyFocus.apply(this, arguments);
-      }
-    }
-  });
-})();
-
-Polymer({
-  is: 'fade-in-animation',
-  behaviors: [ Polymer.NeonAnimationBehavior ],
-  configure: function(config) {
-    var node = config.node;
-    this._effect = new KeyframeEffect(node, [ {
-      opacity: '0'
-    }, {
-      opacity: '1'
-    } ], this.timingFromConfig(config));
-    return this._effect;
-  }
-});
-
-Polymer({
-  is: 'fade-out-animation',
-  behaviors: [ Polymer.NeonAnimationBehavior ],
-  configure: function(config) {
-    var node = config.node;
-    this._effect = new KeyframeEffect(node, [ {
-      opacity: '1'
-    }, {
-      opacity: '0'
-    } ], this.timingFromConfig(config));
-    return this._effect;
-  }
-});
-
-Polymer({
-  is: 'paper-menu-grow-height-animation',
-  behaviors: [ Polymer.NeonAnimationBehavior ],
-  configure: function(config) {
-    var node = config.node;
-    var rect = node.getBoundingClientRect();
-    var height = rect.height;
-    this._effect = new KeyframeEffect(node, [ {
-      height: height / 2 + 'px'
-    }, {
-      height: height + 'px'
-    } ], this.timingFromConfig(config));
-    return this._effect;
-  }
-});
-
-Polymer({
-  is: 'paper-menu-grow-width-animation',
-  behaviors: [ Polymer.NeonAnimationBehavior ],
-  configure: function(config) {
-    var node = config.node;
-    var rect = node.getBoundingClientRect();
-    var width = rect.width;
-    this._effect = new KeyframeEffect(node, [ {
-      width: width / 2 + 'px'
-    }, {
-      width: width + 'px'
-    } ], this.timingFromConfig(config));
-    return this._effect;
-  }
-});
-
-Polymer({
-  is: 'paper-menu-shrink-width-animation',
-  behaviors: [ Polymer.NeonAnimationBehavior ],
-  configure: function(config) {
-    var node = config.node;
-    var rect = node.getBoundingClientRect();
-    var width = rect.width;
-    this._effect = new KeyframeEffect(node, [ {
-      width: width + 'px'
-    }, {
-      width: width - width / 20 + 'px'
-    } ], this.timingFromConfig(config));
-    return this._effect;
-  }
-});
-
-Polymer({
-  is: 'paper-menu-shrink-height-animation',
-  behaviors: [ Polymer.NeonAnimationBehavior ],
-  configure: function(config) {
-    var node = config.node;
-    var rect = node.getBoundingClientRect();
-    var height = rect.height;
-    var top = rect.top;
-    this.setPrefixedProperty(node, 'transformOrigin', '0 0');
-    this._effect = new KeyframeEffect(node, [ {
-      height: height + 'px',
-      transform: 'translateY(0)'
-    }, {
-      height: height / 2 + 'px',
-      transform: 'translateY(-20px)'
-    } ], this.timingFromConfig(config));
-    return this._effect;
-  }
-});
-
+document.addEventListener("touchmove",this._boundScrollHandler,true)},_unlockScrollInteractions:function(){document.removeEventListener("wheel",this._boundScrollHandler,true);document.removeEventListener("mousewheel",this._boundScrollHandler,true);document.removeEventListener("DOMMouseScroll",this._boundScrollHandler,true);document.removeEventListener("touchstart",this._boundScrollHandler,true);document.removeEventListener("touchmove",this._boundScrollHandler,true)},_shouldPreventScrolling:function(event){var target=Polymer.dom(event).rootTarget;if(event.type!=="touchmove"&&ROOT_TARGET!==target){ROOT_TARGET=target;SCROLLABLE_NODES=this._getScrollableNodes(Polymer.dom(event).path)}if(!SCROLLABLE_NODES.length){return true}if(event.type==="touchstart"){return false}var info=this._getScrollInfo(event);return!this._getScrollingNode(SCROLLABLE_NODES,info.deltaX,info.deltaY)},_getScrollableNodes:function(nodes){var scrollables=[];var lockingIndex=nodes.indexOf(this.currentLockingElement);for(var i=0;i<=lockingIndex;i++){var node=nodes[i];if(node.nodeType===11){continue}var style=node.style;if(style.overflow!=="scroll"&&style.overflow!=="auto"){style=window.getComputedStyle(node)}if(style.overflow==="scroll"||style.overflow==="auto"){scrollables.push(node)}}return scrollables},_getScrollingNode:function(nodes,deltaX,deltaY){if(!deltaX&&!deltaY){return}var verticalScroll=Math.abs(deltaY)>=Math.abs(deltaX);for(var i=0;i<nodes.length;i++){var node=nodes[i];var canScroll=false;if(verticalScroll){canScroll=deltaY<0?node.scrollTop>0:node.scrollTop<node.scrollHeight-node.clientHeight}else{canScroll=deltaX<0?node.scrollLeft>0:node.scrollLeft<node.scrollWidth-node.clientWidth}if(canScroll){return node}}},_getScrollInfo:function(event){var info={deltaX:event.deltaX,deltaY:event.deltaY};if("deltaX"in event){}else if("wheelDeltaX"in event){info.deltaX=-event.wheelDeltaX;info.deltaY=-event.wheelDeltaY}else if("axis"in event){info.deltaX=event.axis===1?event.detail:0;info.deltaY=event.axis===2?event.detail:0}else if(event.targetTouches){var touch=event.targetTouches[0];info.deltaX=LAST_TOUCH_POSITION.pageX-touch.pageX;info.deltaY=LAST_TOUCH_POSITION.pageY-touch.pageY}return info}}})();(function(){"use strict";Polymer({is:"iron-dropdown",behaviors:[Polymer.IronControlState,Polymer.IronA11yKeysBehavior,Polymer.IronOverlayBehavior,Polymer.NeonAnimationRunnerBehavior],properties:{horizontalAlign:{type:String,value:"left",reflectToAttribute:true},verticalAlign:{type:String,value:"top",reflectToAttribute:true},openAnimationConfig:{type:Object},closeAnimationConfig:{type:Object},focusTarget:{type:Object},noAnimations:{type:Boolean,value:false},allowOutsideScroll:{type:Boolean,value:false},_boundOnCaptureScroll:{type:Function,value:function(){return this._onCaptureScroll.bind(this)}}},listeners:{"neon-animation-finish":"_onNeonAnimationFinish"},observers:["_updateOverlayPosition(positionTarget, verticalAlign, horizontalAlign, verticalOffset, horizontalOffset)"],get containedElement(){return Polymer.dom(this.$.content).getDistributedNodes()[0]},get _focusTarget(){return this.focusTarget||this.containedElement},ready:function(){this._scrollTop=0;this._scrollLeft=0;this._refitOnScrollRAF=null},attached:function(){if(!this.sizingTarget||this.sizingTarget===this){this.sizingTarget=this.containedElement}},detached:function(){this.cancelAnimation();document.removeEventListener("scroll",this._boundOnCaptureScroll);Polymer.IronDropdownScrollManager.removeScrollLock(this)},_openedChanged:function(){if(this.opened&&this.disabled){this.cancel()}else{this.cancelAnimation();this._updateAnimationConfig();this._saveScrollPosition();if(this.opened){document.addEventListener("scroll",this._boundOnCaptureScroll);!this.allowOutsideScroll&&Polymer.IronDropdownScrollManager.pushScrollLock(this)}else{document.removeEventListener("scroll",this._boundOnCaptureScroll);Polymer.IronDropdownScrollManager.removeScrollLock(this)}Polymer.IronOverlayBehaviorImpl._openedChanged.apply(this,arguments)}},_renderOpened:function(){if(!this.noAnimations&&this.animationConfig.open){this.$.contentWrapper.classList.add("animating");this.playAnimation("open")}else{Polymer.IronOverlayBehaviorImpl._renderOpened.apply(this,arguments)}},_renderClosed:function(){if(!this.noAnimations&&this.animationConfig.close){this.$.contentWrapper.classList.add("animating");this.playAnimation("close")}else{Polymer.IronOverlayBehaviorImpl._renderClosed.apply(this,arguments)}},_onNeonAnimationFinish:function(){this.$.contentWrapper.classList.remove("animating");if(this.opened){this._finishRenderOpened()}else{this._finishRenderClosed()}},_onCaptureScroll:function(){if(!this.allowOutsideScroll){this._restoreScrollPosition()}else{this._refitOnScrollRAF&&window.cancelAnimationFrame(this._refitOnScrollRAF);this._refitOnScrollRAF=window.requestAnimationFrame(this.refit.bind(this))}},_saveScrollPosition:function(){if(document.scrollingElement){this._scrollTop=document.scrollingElement.scrollTop;this._scrollLeft=document.scrollingElement.scrollLeft}else{this._scrollTop=Math.max(document.documentElement.scrollTop,document.body.scrollTop);this._scrollLeft=Math.max(document.documentElement.scrollLeft,document.body.scrollLeft)}},_restoreScrollPosition:function(){if(document.scrollingElement){document.scrollingElement.scrollTop=this._scrollTop;document.scrollingElement.scrollLeft=this._scrollLeft}else{document.documentElement.scrollTop=this._scrollTop;document.documentElement.scrollLeft=this._scrollLeft;document.body.scrollTop=this._scrollTop;document.body.scrollLeft=this._scrollLeft}},_updateAnimationConfig:function(){var animations=(this.openAnimationConfig||[]).concat(this.closeAnimationConfig||[]);for(var i=0;i<animations.length;i++){animations[i].node=this.containedElement}this.animationConfig={open:this.openAnimationConfig,close:this.closeAnimationConfig}},_updateOverlayPosition:function(){if(this.isAttached){this.notifyResize()}},_applyFocus:function(){var focusTarget=this.focusTarget||this.containedElement;if(focusTarget&&this.opened&&!this.noAutoFocus){focusTarget.focus()}else{Polymer.IronOverlayBehaviorImpl._applyFocus.apply(this,arguments)}}})})();Polymer({is:"fade-in-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;this._effect=new KeyframeEffect(node,[{opacity:"0"},{opacity:"1"}],this.timingFromConfig(config));return this._effect}});Polymer({is:"fade-out-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;this._effect=new KeyframeEffect(node,[{opacity:"1"},{opacity:"0"}],this.timingFromConfig(config));return this._effect}});Polymer.IronMenuBehaviorImpl={properties:{focusedItem:{observer:"_focusedItemChanged",readOnly:true,type:Object},attrForItemTitle:{type:String}},hostAttributes:{role:"menu",tabindex:"0"},observers:["_updateMultiselectable(multi)"],listeners:{focus:"_onFocus",keydown:"_onKeydown","iron-items-changed":"_onIronItemsChanged"},keyBindings:{up:"_onUpKey",down:"_onDownKey",esc:"_onEscKey","shift+tab:keydown":"_onShiftTabDown"},attached:function(){this._resetTabindices()},select:function(value){if(this._defaultFocusAsync){this.cancelAsync(this._defaultFocusAsync);this._defaultFocusAsync=null}var item=this._valueToItem(value);if(item&&item.hasAttribute("disabled"))return;this._setFocusedItem(item);Polymer.IronMultiSelectableBehaviorImpl.select.apply(this,arguments)},_resetTabindices:function(){var selectedItem=this.multi?this.selectedItems&&this.selectedItems[0]:this.selectedItem;this.items.forEach(function(item){item.setAttribute("tabindex",item===selectedItem?"0":"-1")},this)},_updateMultiselectable:function(multi){if(multi){this.setAttribute("aria-multiselectable","true")}else{this.removeAttribute("aria-multiselectable")}},_focusWithKeyboardEvent:function(event){for(var i=0,item;item=this.items[i];i++){var attr=this.attrForItemTitle||"textContent";var title=item[attr]||item.getAttribute(attr);if(!item.hasAttribute("disabled")&&title&&title.trim().charAt(0).toLowerCase()===String.fromCharCode(event.keyCode).toLowerCase()){this._setFocusedItem(item);break}}},_focusPrevious:function(){var length=this.items.length;var curFocusIndex=Number(this.indexOf(this.focusedItem));for(var i=1;i<length+1;i++){var item=this.items[(curFocusIndex-i+length)%length];if(!item.hasAttribute("disabled")){var owner=Polymer.dom(item).getOwnerRoot()||document;this._setFocusedItem(item);if(Polymer.dom(owner).activeElement==item){return}}}},_focusNext:function(){var length=this.items.length;var curFocusIndex=Number(this.indexOf(this.focusedItem));for(var i=1;i<length+1;i++){var item=this.items[(curFocusIndex+i)%length];if(!item.hasAttribute("disabled")){var owner=Polymer.dom(item).getOwnerRoot()||document;this._setFocusedItem(item);if(Polymer.dom(owner).activeElement==item){return}}}},_applySelection:function(item,isSelected){if(isSelected){item.setAttribute("aria-selected","true")}else{item.removeAttribute("aria-selected")}Polymer.IronSelectableBehavior._applySelection.apply(this,arguments)},_focusedItemChanged:function(focusedItem,old){old&&old.setAttribute("tabindex","-1");if(focusedItem){focusedItem.setAttribute("tabindex","0");focusedItem.focus()}},_onIronItemsChanged:function(event){if(event.detail.addedNodes.length){this._resetTabindices()}},_onShiftTabDown:function(event){var oldTabIndex=this.getAttribute("tabindex");Polymer.IronMenuBehaviorImpl._shiftTabPressed=true;this._setFocusedItem(null);this.setAttribute("tabindex","-1");this.async(function(){this.setAttribute("tabindex",oldTabIndex);Polymer.IronMenuBehaviorImpl._shiftTabPressed=false},1)},_onFocus:function(event){if(Polymer.IronMenuBehaviorImpl._shiftTabPressed){return}var rootTarget=Polymer.dom(event).rootTarget;if(rootTarget!==this&&typeof rootTarget.tabIndex!=="undefined"&&!this.isLightDescendant(rootTarget)){return}this._defaultFocusAsync=this.async(function(){var selectedItem=this.multi?this.selectedItems&&this.selectedItems[0]:this.selectedItem;this._setFocusedItem(null);if(selectedItem){this._setFocusedItem(selectedItem)}else if(this.items[0]){this._focusNext()}})},_onUpKey:function(event){this._focusPrevious();event.detail.keyboardEvent.preventDefault()},_onDownKey:function(event){this._focusNext();event.detail.keyboardEvent.preventDefault()},_onEscKey:function(event){this.focusedItem.blur()},_onKeydown:function(event){if(!this.keyboardEventMatchesKeys(event,"up down esc")){this._focusWithKeyboardEvent(event)}event.stopPropagation()},_activateHandler:function(event){Polymer.IronSelectableBehavior._activateHandler.call(this,event);event.stopPropagation()}};Polymer.IronMenuBehaviorImpl._shiftTabPressed=false;Polymer.IronMenuBehavior=[Polymer.IronMultiSelectableBehavior,Polymer.IronA11yKeysBehavior,Polymer.IronMenuBehaviorImpl];(function(){Polymer({is:"paper-listbox",behaviors:[Polymer.IronMenuBehavior],hostAttributes:{role:"listbox"}})})();Polymer({is:"paper-menu-grow-height-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;var rect=node.getBoundingClientRect();var height=rect.height;this._effect=new KeyframeEffect(node,[{height:height/2+"px"},{height:height+"px"}],this.timingFromConfig(config));return this._effect}});Polymer({is:"paper-menu-grow-width-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;var rect=node.getBoundingClientRect();var width=rect.width;this._effect=new KeyframeEffect(node,[{width:width/2+"px"},{width:width+"px"}],this.timingFromConfig(config));return this._effect}});Polymer({is:"paper-menu-shrink-width-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;var rect=node.getBoundingClientRect();var width=rect.width;this._effect=new KeyframeEffect(node,[{width:width+"px"},{width:width-width/20+"px"}],this.timingFromConfig(config));return this._effect}});Polymer({is:"paper-menu-shrink-height-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;var rect=node.getBoundingClientRect();var height=rect.height;var top=rect.top;this.setPrefixedProperty(node,"transformOrigin","0 0");this._effect=new KeyframeEffect(node,[{height:height+"px",transform:"translateY(0)"},{height:height/2+"px",transform:"translateY(-20px)"}],this.timingFromConfig(config));return this._effect}});
 // 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.
-var SLIDE_CUBIC_BEZIER = 'cubic-bezier(0.3, 0.95, 0.5, 1)';
-
-Polymer({
-  is: 'cr-shared-menu',
-  behaviors: [ Polymer.IronA11yKeysBehavior ],
-  properties: {
-    menuOpen: {
-      type: Boolean,
-      observer: 'menuOpenChanged_',
-      value: false,
-      notify: true
-    },
-    itemData: {
-      type: Object,
-      value: null
-    },
-    keyEventTarget: {
-      type: Object,
-      value: function() {
-        return this.$.menu;
-      }
-    },
-    openAnimationConfig: {
-      type: Object,
-      value: function() {
-        return [ {
-          name: 'fade-in-animation',
-          timing: {
-            delay: 50,
-            duration: 200
-          }
-        }, {
-          name: 'paper-menu-grow-width-animation',
-          timing: {
-            delay: 50,
-            duration: 150,
-            easing: SLIDE_CUBIC_BEZIER
-          }
-        }, {
-          name: 'paper-menu-grow-height-animation',
-          timing: {
-            delay: 100,
-            duration: 275,
-            easing: SLIDE_CUBIC_BEZIER
-          }
-        } ];
-      }
-    },
-    closeAnimationConfig: {
-      type: Object,
-      value: function() {
-        return [ {
-          name: 'fade-out-animation',
-          timing: {
-            duration: 150
-          }
-        } ];
-      }
-    }
-  },
-  keyBindings: {
-    tab: 'onTabPressed_'
-  },
-  listeners: {
-    'dropdown.iron-overlay-canceled': 'onOverlayCanceled_'
-  },
-  lastAnchor_: null,
-  firstFocus_: null,
-  lastFocus_: null,
-  attached: function() {
-    window.addEventListener('resize', this.closeMenu.bind(this));
-  },
-  closeMenu: function() {
-    if (this.root.activeElement == null) {
-      this.$.dropdown.restoreFocusOnClose = false;
-    }
-    this.menuOpen = false;
-  },
-  openMenu: function(anchor, opt_itemData) {
-    if (this.lastAnchor_ == anchor && this.menuOpen) return;
-    if (this.menuOpen) this.closeMenu();
-    this.itemData = opt_itemData || null;
-    this.lastAnchor_ = anchor;
-    this.$.dropdown.restoreFocusOnClose = true;
-    var focusableChildren = Polymer.dom(this).querySelectorAll('[tabindex]:not([disabled]):not([hidden]),' + 'button:not([disabled]):not([hidden])');
-    if (focusableChildren.length > 0) {
-      this.$.dropdown.focusTarget = focusableChildren[0];
-      this.firstFocus_ = focusableChildren[0];
-      this.lastFocus_ = focusableChildren[focusableChildren.length - 1];
-    }
-    this.$.dropdown.positionTarget = anchor;
-    this.menuOpen = true;
-  },
-  toggleMenu: function(anchor, opt_itemData) {
-    if (anchor == this.lastAnchor_ && this.menuOpen) this.closeMenu(); else this.openMenu(anchor, opt_itemData);
-  },
-  onTabPressed_: function(e) {
-    if (!this.firstFocus_ || !this.lastFocus_) return;
-    var toFocus;
-    var keyEvent = e.detail.keyboardEvent;
-    if (keyEvent.shiftKey && keyEvent.target == this.firstFocus_) toFocus = this.lastFocus_; else if (!keyEvent.shiftKey && keyEvent.target == this.lastFocus_) toFocus = this.firstFocus_;
-    if (!toFocus) return;
-    e.preventDefault();
-    toFocus.focus();
-  },
-  menuOpenChanged_: function() {
-    if (!this.menuOpen) {
-      this.itemData = null;
-      this.lastAnchor_ = null;
-    }
-  },
-  onOverlayCanceled_: function(e) {
-    if (e.detail.type == 'tap') this.$.dropdown.restoreFocusOnClose = false;
-  }
-});
-
-Polymer({
-  is: 'paper-icon-button-light',
-  "extends": 'button',
-  behaviors: [ Polymer.PaperRippleBehavior ],
-  listeners: {
-    down: '_rippleDown',
-    up: '_rippleUp',
-    focus: '_rippleDown',
-    blur: '_rippleUp'
-  },
-  _rippleDown: function() {
-    this.getRipple().downAction();
-  },
-  _rippleUp: function() {
-    this.getRipple().upAction();
-  },
-  ensureRipple: function(var_args) {
-    var lastRipple = this._ripple;
-    Polymer.PaperRippleBehavior.ensureRipple.apply(this, arguments);
-    if (this._ripple && this._ripple !== lastRipple) {
-      this._ripple.center = true;
-      this._ripple.classList.add('circle');
-    }
-  }
-});
-
+var SLIDE_CUBIC_BEZIER="cubic-bezier(0.3, 0.95, 0.5, 1)";Polymer({is:"cr-shared-menu",properties:{menuOpen:{type:Boolean,observer:"menuOpenChanged_",value:false,notify:true},itemData:{type:Object,value:null},openAnimationConfig:{type:Object,value:function(){return[{name:"fade-in-animation",timing:{delay:50,duration:200}},{name:"paper-menu-grow-width-animation",timing:{delay:50,duration:150,easing:SLIDE_CUBIC_BEZIER}},{name:"paper-menu-grow-height-animation",timing:{delay:100,duration:275,easing:SLIDE_CUBIC_BEZIER}}]}},closeAnimationConfig:{type:Object,value:function(){return[{name:"fade-out-animation",timing:{duration:150}}]}}},listeners:{"dropdown.iron-overlay-canceled":"onOverlayCanceled_"},lastAnchor_:null,keyHandler_:null,attached:function(){window.addEventListener("resize",this.closeMenu.bind(this));this.keyHandler_=this.onCaptureKeyDown_.bind(this);this.$.menu.addEventListener("keydown",this.keyHandler_,true)},detached:function(){this.$.menu.removeEventListener("keydown",this.keyHandler_,true)},closeMenu:function(){if(this.root.activeElement==null){this.$.dropdown.restoreFocusOnClose=false}this.menuOpen=false},openMenu:function(anchor,opt_itemData){if(this.lastAnchor_==anchor&&this.menuOpen)return;if(this.menuOpen)this.closeMenu();this.itemData=opt_itemData||null;this.lastAnchor_=anchor;this.$.dropdown.restoreFocusOnClose=true;this.$.menu.selected=-1;this.$.dropdown.positionTarget=anchor;this.menuOpen=true},toggleMenu:function(anchor,opt_itemData){if(anchor==this.lastAnchor_&&this.menuOpen)this.closeMenu();else this.openMenu(anchor,opt_itemData)},onCaptureKeyDown_:function(e){if(Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(e,"tab")){this.$.dropdown.restoreFocusOnClose=false;this.lastAnchor_.focus();this.closeMenu()}},menuOpenChanged_:function(){if(!this.menuOpen){this.itemData=null;this.lastAnchor_=null}},onOverlayCanceled_:function(e){if(e.detail.type=="tap")this.$.dropdown.restoreFocusOnClose=false}});Polymer({is:"paper-icon-button-light","extends":"button",behaviors:[Polymer.PaperRippleBehavior],listeners:{down:"_rippleDown",up:"_rippleUp",focus:"_rippleDown",blur:"_rippleUp"},_rippleDown:function(){this.getRipple().downAction()},_rippleUp:function(){this.getRipple().upAction()},ensureRipple:function(var_args){var lastRipple=this._ripple;Polymer.PaperRippleBehavior.ensureRipple.apply(this,arguments);if(this._ripple&&this._ripple!==lastRipple){this._ripple.center=true;this._ripple.classList.add("circle")}}});
 // 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.
-Polymer({
-  is: 'history-synced-device-card',
-  properties: {
-    device: String,
-    lastUpdateTime: String,
-    tabs: {
-      type: Array,
-      value: function() {
-        return [];
-      },
-      observer: 'updateIcons_'
-    },
-    separatorIndexes: Array,
-    opened: Boolean,
-    searchTerm: String,
-    sessionTag: String
-  },
-  openTab_: function(e) {
-    var tab = e.model.tab;
-    var browserService = md_history.BrowserService.getInstance();
-    browserService.recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogram.LINK_CLICKED, SyncedTabsHistogram.LIMIT);
-    browserService.openForeignSessionTab(this.sessionTag, tab.windowId, tab.sessionId, e);
-    e.preventDefault();
-  },
-  toggleTabCard: function() {
-    var histogramValue = this.$.collapse.opened ? SyncedTabsHistogram.COLLAPSE_SESSION : SyncedTabsHistogram.EXPAND_SESSION;
-    md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, histogramValue, SyncedTabsHistogram.LIMIT);
-    this.$.collapse.toggle();
-    this.$['dropdown-indicator'].icon = this.$.collapse.opened ? 'cr:expand-less' : 'cr:expand-more';
-  },
-  updateIcons_: function() {
-    this.async(function() {
-      var icons = Polymer.dom(this.root).querySelectorAll('.website-icon');
-      for (var i = 0; i < this.tabs.length; i++) {
-        icons[i].style.backgroundImage = cr.icon.getFavicon(this.tabs[i].url);
-      }
-    });
-  },
-  isWindowSeparatorIndex_: function(index, separatorIndexes) {
-    return this.separatorIndexes.indexOf(index) != -1;
-  },
-  getCollapseIcon_: function(opened) {
-    return opened ? 'cr:expand-less' : 'cr:expand-more';
-  },
-  getCollapseTitle_: function(opened) {
-    return opened ? loadTimeData.getString('collapseSessionButton') : loadTimeData.getString('expandSessionButton');
-  },
-  onMenuButtonTap_: function(e) {
-    this.fire('toggle-menu', {
-      target: Polymer.dom(e).localTarget,
-      tag: this.sessionTag
-    });
-    e.stopPropagation();
-  },
-  onLinkRightClick_: function() {
-    md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogram.LINK_RIGHT_CLICKED, SyncedTabsHistogram.LIMIT);
-  }
-});
-
+Polymer({is:"history-synced-device-card",properties:{device:String,lastUpdateTime:String,tabs:{type:Array,value:function(){return[]},observer:"updateIcons_"},separatorIndexes:Array,opened:Boolean,searchTerm:String,sessionTag:String},openTab_:function(e){var tab=e.model.tab;var browserService=md_history.BrowserService.getInstance();browserService.recordHistogram(SYNCED_TABS_HISTOGRAM_NAME,SyncedTabsHistogram.LINK_CLICKED,SyncedTabsHistogram.LIMIT);browserService.openForeignSessionTab(this.sessionTag,tab.windowId,tab.sessionId,e);e.preventDefault()},toggleTabCard:function(){var histogramValue=this.$.collapse.opened?SyncedTabsHistogram.COLLAPSE_SESSION:SyncedTabsHistogram.EXPAND_SESSION;md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME,histogramValue,SyncedTabsHistogram.LIMIT);this.$.collapse.toggle();this.$["dropdown-indicator"].icon=this.$.collapse.opened?"cr:expand-less":"cr:expand-more"},updateIcons_:function(){this.async(function(){var icons=Polymer.dom(this.root).querySelectorAll(".website-icon");for(var i=0;i<this.tabs.length;i++){icons[i].style.backgroundImage=cr.icon.getFavicon(this.tabs[i].url)}})},isWindowSeparatorIndex_:function(index,separatorIndexes){return this.separatorIndexes.indexOf(index)!=-1},getCollapseIcon_:function(opened){return opened?"cr:expand-less":"cr:expand-more"},getCollapseTitle_:function(opened){return opened?loadTimeData.getString("collapseSessionButton"):loadTimeData.getString("expandSessionButton")},onMenuButtonTap_:function(e){this.fire("toggle-menu",{target:Polymer.dom(e).localTarget,tag:this.sessionTag});e.stopPropagation()},onLinkRightClick_:function(){md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME,SyncedTabsHistogram.LINK_RIGHT_CLICKED,SyncedTabsHistogram.LIMIT)}});
 // 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.
-var ForeignDeviceInternal;
-
-Polymer({
-  is: 'history-synced-device-manager',
-  properties: {
-    sessionList: {
-      type: Array,
-      observer: 'updateSyncedDevices'
-    },
-    searchTerm: {
-      type: String,
-      observer: 'searchTermChanged'
-    },
-    syncedDevices_: {
-      type: Array,
-      value: function() {
-        return [];
-      }
-    },
-    signInState: {
-      type: Boolean,
-      observer: 'signInStateChanged_'
-    },
-    guestSession_: {
-      type: Boolean,
-      value: loadTimeData.getBoolean('isGuestSession')
-    },
-    fetchingSyncedTabs_: {
-      type: Boolean,
-      value: false
-    },
-    hasSeenForeignData_: Boolean
-  },
-  listeners: {
-    'toggle-menu': 'onToggleMenu_',
-    scroll: 'onListScroll_'
-  },
-  attached: function() {
-    chrome.send('otherDevicesInitialized');
-    md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogram.INITIALIZED, SyncedTabsHistogram.LIMIT);
-  },
-  getContentScrollTarget: function() {
-    return this;
-  },
-  createInternalDevice_: function(session) {
-    var tabs = [];
-    var separatorIndexes = [];
-    for (var i = 0; i < session.windows.length; i++) {
-      var windowId = session.windows[i].sessionId;
-      var newTabs = session.windows[i].tabs;
-      if (newTabs.length == 0) continue;
-      newTabs.forEach(function(tab) {
-        tab.windowId = windowId;
-      });
-      var windowAdded = false;
-      if (!this.searchTerm) {
-        tabs = tabs.concat(newTabs);
-        windowAdded = true;
-      } else {
-        var searchText = this.searchTerm.toLowerCase();
-        for (var j = 0; j < newTabs.length; j++) {
-          var tab = newTabs[j];
-          if (tab.title.toLowerCase().indexOf(searchText) != -1) {
-            tabs.push(tab);
-            windowAdded = true;
-          }
-        }
-      }
-      if (windowAdded && i != session.windows.length - 1) separatorIndexes.push(tabs.length - 1);
-    }
-    return {
-      device: session.name,
-      lastUpdateTime: '– ' + session.modifiedTime,
-      opened: true,
-      separatorIndexes: separatorIndexes,
-      timestamp: session.timestamp,
-      tabs: tabs,
-      tag: session.tag
-    };
-  },
-  onSignInTap_: function() {
-    chrome.send('startSignInFlow');
-  },
-  onListScroll_: function() {
-    var menu = this.$.menu.getIfExists();
-    if (menu) menu.closeMenu();
-  },
-  onToggleMenu_: function(e) {
-    var menu = this.$.menu.get();
-    menu.toggleMenu(e.detail.target, e.detail.tag);
-    if (menu.menuOpen) {
-      md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogram.SHOW_SESSION_MENU, SyncedTabsHistogram.LIMIT);
-    }
-  },
-  onOpenAllTap_: function() {
-    var menu = assert(this.$.menu.getIfExists());
-    var browserService = md_history.BrowserService.getInstance();
-    browserService.recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogram.OPEN_ALL, SyncedTabsHistogram.LIMIT);
-    browserService.openForeignSessionAllTabs(menu.itemData);
-    menu.closeMenu();
-  },
-  onDeleteSessionTap_: function() {
-    var menu = assert(this.$.menu.getIfExists());
-    var browserService = md_history.BrowserService.getInstance();
-    browserService.recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogram.HIDE_FOR_NOW, SyncedTabsHistogram.LIMIT);
-    browserService.deleteForeignSession(menu.itemData);
-    menu.closeMenu();
-  },
-  clearDisplayedSyncedDevices_: function() {
-    this.syncedDevices_ = [];
-  },
-  showNoSyncedMessage: function(signInState, syncedDevicesLength, guestSession) {
-    if (guestSession) return true;
-    return signInState && syncedDevicesLength == 0;
-  },
-  showSignInGuide: function(signInState, guestSession) {
-    var show = !signInState && !guestSession;
-    if (show) {
-      md_history.BrowserService.getInstance().recordAction('Signin_Impression_FromRecentTabs');
-    }
-    return show;
-  },
-  noSyncedTabsMessage: function() {
-    var stringName = this.fetchingSyncedTabs_ ? 'loading' : 'noSyncedResults';
-    if (this.searchTerm !== '') stringName = 'noSearchResults';
-    return loadTimeData.getString(stringName);
-  },
-  updateSyncedDevices: function(sessionList) {
-    this.fetchingSyncedTabs_ = false;
-    if (!sessionList) return;
-    if (sessionList.length > 0 && !this.hasSeenForeignData_) {
-      this.hasSeenForeignData_ = true;
-      md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogram.HAS_FOREIGN_DATA, SyncedTabsHistogram.LIMIT);
-    }
-    var updateCount = Math.min(sessionList.length, this.syncedDevices_.length);
-    for (var i = 0; i < updateCount; i++) {
-      var oldDevice = this.syncedDevices_[i];
-      if (oldDevice.tag != sessionList[i].tag || oldDevice.timestamp != sessionList[i].timestamp) {
-        var device = this.createInternalDevice_(sessionList[i]);
-        if (device.tabs.length != 0) this.splice('syncedDevices_', i, 1, device);
-      }
-    }
-    if (sessionList.length >= this.syncedDevices_.length) {
-      for (var i = updateCount; i < sessionList.length; i++) {
-        var device = this.createInternalDevice_(sessionList[i]);
-        if (device.tabs.length != 0) this.push('syncedDevices_', device);
-      }
-    } else {
-      this.splice('syncedDevices_', updateCount, this.syncedDevices_.length - updateCount);
-    }
-  },
-  tabSyncDisabled: function() {
-    this.fetchingSyncedTabs_ = false;
-    this.clearDisplayedSyncedDevices_();
-  },
-  signInStateChanged_: function() {
-    this.fire('history-view-changed');
-    if (!this.signInState) {
-      this.clearDisplayedSyncedDevices_();
-      return;
-    }
-    this.fetchingSyncedTabs_ = true;
-  },
-  searchTermChanged: function(searchTerm) {
-    this.clearDisplayedSyncedDevices_();
-    this.updateSyncedDevices(this.sessionList);
-  }
-});
-
+var ForeignDeviceInternal;Polymer({is:"history-synced-device-manager",properties:{sessionList:{type:Array,observer:"updateSyncedDevices"},searchTerm:{type:String,observer:"searchTermChanged"},syncedDevices_:{type:Array,value:function(){return[]}},signInState:{type:Boolean,observer:"signInStateChanged_"},guestSession_:{type:Boolean,value:loadTimeData.getBoolean("isGuestSession")},fetchingSyncedTabs_:{type:Boolean,value:false},hasSeenForeignData_:Boolean},listeners:{"toggle-menu":"onToggleMenu_",scroll:"onListScroll_"},attached:function(){chrome.send("otherDevicesInitialized");md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME,SyncedTabsHistogram.INITIALIZED,SyncedTabsHistogram.LIMIT)},getContentScrollTarget:function(){return this},createInternalDevice_:function(session){var tabs=[];var separatorIndexes=[];for(var i=0;i<session.windows.length;i++){var windowId=session.windows[i].sessionId;var newTabs=session.windows[i].tabs;if(newTabs.length==0)continue;newTabs.forEach(function(tab){tab.windowId=windowId});var windowAdded=false;if(!this.searchTerm){tabs=tabs.concat(newTabs);windowAdded=true}else{var searchText=this.searchTerm.toLowerCase();for(var j=0;j<newTabs.length;j++){var tab=newTabs[j];if(tab.title.toLowerCase().indexOf(searchText)!=-1){tabs.push(tab);windowAdded=true}}}if(windowAdded&&i!=session.windows.length-1)separatorIndexes.push(tabs.length-1)}return{device:session.name,lastUpdateTime:"– "+session.modifiedTime,opened:true,separatorIndexes:separatorIndexes,timestamp:session.timestamp,tabs:tabs,tag:session.tag}},onSignInTap_:function(){chrome.send("startSignInFlow")},onListScroll_:function(){var menu=this.$.menu.getIfExists();if(menu)menu.closeMenu()},onToggleMenu_:function(e){var menu=this.$.menu.get();menu.toggleMenu(e.detail.target,e.detail.tag);if(menu.menuOpen){md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME,SyncedTabsHistogram.SHOW_SESSION_MENU,SyncedTabsHistogram.LIMIT)}},onOpenAllTap_:function(){var menu=assert(this.$.menu.getIfExists());var browserService=md_history.BrowserService.getInstance();browserService.recordHistogram(SYNCED_TABS_HISTOGRAM_NAME,SyncedTabsHistogram.OPEN_ALL,SyncedTabsHistogram.LIMIT);browserService.openForeignSessionAllTabs(menu.itemData);menu.closeMenu()},onDeleteSessionTap_:function(){var menu=assert(this.$.menu.getIfExists());var browserService=md_history.BrowserService.getInstance();browserService.recordHistogram(SYNCED_TABS_HISTOGRAM_NAME,SyncedTabsHistogram.HIDE_FOR_NOW,SyncedTabsHistogram.LIMIT);browserService.deleteForeignSession(menu.itemData);menu.closeMenu()},clearDisplayedSyncedDevices_:function(){this.syncedDevices_=[]},showNoSyncedMessage:function(signInState,syncedDevicesLength,guestSession){if(guestSession)return true;return signInState&&syncedDevicesLength==0},showSignInGuide:function(signInState,guestSession){var show=!signInState&&!guestSession;if(show){md_history.BrowserService.getInstance().recordAction("Signin_Impression_FromRecentTabs")}return show},noSyncedTabsMessage:function(){var stringName=this.fetchingSyncedTabs_?"loading":"noSyncedResults";if(this.searchTerm!=="")stringName="noSearchResults";return loadTimeData.getString(stringName)},updateSyncedDevices:function(sessionList){this.fetchingSyncedTabs_=false;if(!sessionList)return;if(sessionList.length>0&&!this.hasSeenForeignData_){this.hasSeenForeignData_=true;md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME,SyncedTabsHistogram.HAS_FOREIGN_DATA,SyncedTabsHistogram.LIMIT)}var updateCount=Math.min(sessionList.length,this.syncedDevices_.length);for(var i=0;i<updateCount;i++){var oldDevice=this.syncedDevices_[i];if(oldDevice.tag!=sessionList[i].tag||oldDevice.timestamp!=sessionList[i].timestamp){var device=this.createInternalDevice_(sessionList[i]);if(device.tabs.length!=0)this.splice("syncedDevices_",i,1,device)}}if(sessionList.length>=this.syncedDevices_.length){for(var i=updateCount;i<sessionList.length;i++){var device=this.createInternalDevice_(sessionList[i]);if(device.tabs.length!=0)this.push("syncedDevices_",device)}}else{this.splice("syncedDevices_",updateCount,this.syncedDevices_.length-updateCount)}},tabSyncDisabled:function(){this.fetchingSyncedTabs_=false;this.clearDisplayedSyncedDevices_()},signInStateChanged_:function(){this.fire("history-view-changed");if(!this.signInState){this.clearDisplayedSyncedDevices_();return}this.fetchingSyncedTabs_=true},searchTermChanged:function(searchTerm){this.clearDisplayedSyncedDevices_();this.updateSyncedDevices(this.sessionList)}});
 // 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.
-Polymer({
-  is: 'cr-dialog',
-  "extends": 'dialog',
-  created: function() {
-    window.addEventListener('popstate', function() {
-      if (this.open) this.cancel();
-    }.bind(this));
-  },
-  cancel: function() {
-    this.fire('cancel');
-    HTMLDialogElement.prototype.close.call(this, '');
-  },
-  close: function(opt_returnValue) {
-    HTMLDialogElement.prototype.close.call(this, 'success');
-  },
-  getCloseButton: function() {
-    return this.$.close;
-  }
-});
-
-Polymer({
-  is: 'app-drawer',
-  properties: {
-    opened: {
-      type: Boolean,
-      value: false,
-      notify: true,
-      reflectToAttribute: true
-    },
-    persistent: {
-      type: Boolean,
-      value: false,
-      reflectToAttribute: true
-    },
-    align: {
-      type: String,
-      value: 'left'
-    },
-    position: {
-      type: String,
-      readOnly: true,
-      value: 'left',
-      reflectToAttribute: true
-    },
-    swipeOpen: {
-      type: Boolean,
-      value: false,
-      reflectToAttribute: true
-    },
-    noFocusTrap: {
-      type: Boolean,
-      value: false
-    }
-  },
-  observers: [ 'resetLayout(position)', '_resetPosition(align, isAttached)' ],
-  _translateOffset: 0,
-  _trackDetails: null,
-  _drawerState: 0,
-  _boundEscKeydownHandler: null,
-  _firstTabStop: null,
-  _lastTabStop: null,
-  ready: function() {
-    this.setScrollDirection('y');
-    this._setTransitionDuration('0s');
-  },
-  attached: function() {
-    Polymer.RenderStatus.afterNextRender(this, function() {
-      this._setTransitionDuration('');
-      this._boundEscKeydownHandler = this._escKeydownHandler.bind(this);
-      this._resetDrawerState();
-      this.listen(this, 'track', '_track');
-      this.addEventListener('transitionend', this._transitionend.bind(this));
-      this.addEventListener('keydown', this._tabKeydownHandler.bind(this));
-    });
-  },
-  detached: function() {
-    document.removeEventListener('keydown', this._boundEscKeydownHandler);
-  },
-  open: function() {
-    this.opened = true;
-  },
-  close: function() {
-    this.opened = false;
-  },
-  toggle: function() {
-    this.opened = !this.opened;
-  },
-  getWidth: function() {
-    return this.$.contentContainer.offsetWidth;
-  },
-  resetLayout: function() {
-    this.debounce('_resetLayout', function() {
-      this.fire('app-drawer-reset-layout');
-    }, 1);
-  },
-  _isRTL: function() {
-    return window.getComputedStyle(this).direction === 'rtl';
-  },
-  _resetPosition: function() {
-    switch (this.align) {
-     case 'start':
-      this._setPosition(this._isRTL() ? 'right' : 'left');
-      return;
-
-     case 'end':
-      this._setPosition(this._isRTL() ? 'left' : 'right');
-      return;
-    }
-    this._setPosition(this.align);
-  },
-  _escKeydownHandler: function(event) {
-    var ESC_KEYCODE = 27;
-    if (event.keyCode === ESC_KEYCODE) {
-      event.preventDefault();
-      this.close();
-    }
-  },
-  _track: function(event) {
-    if (this.persistent) {
-      return;
-    }
-    event.preventDefault();
-    switch (event.detail.state) {
-     case 'start':
-      this._trackStart(event);
-      break;
-
-     case 'track':
-      this._trackMove(event);
-      break;
-
-     case 'end':
-      this._trackEnd(event);
-      break;
-    }
-  },
-  _trackStart: function(event) {
-    this._drawerState = this._DRAWER_STATE.TRACKING;
-    this._setTransitionDuration('0s');
-    this.style.visibility = 'visible';
-    var rect = this.$.contentContainer.getBoundingClientRect();
-    if (this.position === 'left') {
-      this._translateOffset = rect.left;
-    } else {
-      this._translateOffset = rect.right - window.innerWidth;
-    }
-    this._trackDetails = [];
-  },
-  _trackMove: function(event) {
-    this._translateDrawer(event.detail.dx + this._translateOffset);
-    this._trackDetails.push({
-      dx: event.detail.dx,
-      timeStamp: Date.now()
-    });
-  },
-  _trackEnd: function(event) {
-    var x = event.detail.dx + this._translateOffset;
-    var drawerWidth = this.getWidth();
-    var isPositionLeft = this.position === 'left';
-    var isInEndState = isPositionLeft ? x >= 0 || x <= -drawerWidth : x <= 0 || x >= drawerWidth;
-    if (!isInEndState) {
-      var trackDetails = this._trackDetails;
-      this._trackDetails = null;
-      this._flingDrawer(event, trackDetails);
-      if (this._drawerState === this._DRAWER_STATE.FLINGING) {
-        return;
-      }
-    }
-    var halfWidth = drawerWidth / 2;
-    if (event.detail.dx < -halfWidth) {
-      this.opened = this.position === 'right';
-    } else if (event.detail.dx > halfWidth) {
-      this.opened = this.position === 'left';
-    }
-    if (isInEndState) {
-      this._resetDrawerState();
-    }
-    this._setTransitionDuration('');
-    this._resetDrawerTranslate();
-    this.style.visibility = '';
-  },
-  _calculateVelocity: function(event, trackDetails) {
-    var now = Date.now();
-    var timeLowerBound = now - 100;
-    var trackDetail;
-    var min = 0;
-    var max = trackDetails.length - 1;
-    while (min <= max) {
-      var mid = min + max >> 1;
-      var d = trackDetails[mid];
-      if (d.timeStamp >= timeLowerBound) {
-        trackDetail = d;
-        max = mid - 1;
-      } else {
-        min = mid + 1;
-      }
-    }
-    if (trackDetail) {
-      var dx = event.detail.dx - trackDetail.dx;
-      var dt = now - trackDetail.timeStamp || 1;
-      return dx / dt;
-    }
-    return 0;
-  },
-  _flingDrawer: function(event, trackDetails) {
-    var velocity = this._calculateVelocity(event, trackDetails);
-    if (Math.abs(velocity) < this._MIN_FLING_THRESHOLD) {
-      return;
-    }
-    this._drawerState = this._DRAWER_STATE.FLINGING;
-    var x = event.detail.dx + this._translateOffset;
-    var drawerWidth = this.getWidth();
-    var isPositionLeft = this.position === 'left';
-    var isVelocityPositive = velocity > 0;
-    var isClosingLeft = !isVelocityPositive && isPositionLeft;
-    var isClosingRight = isVelocityPositive && !isPositionLeft;
-    var dx;
-    if (isClosingLeft) {
-      dx = -(x + drawerWidth);
-    } else if (isClosingRight) {
-      dx = drawerWidth - x;
-    } else {
-      dx = -x;
-    }
-    if (isVelocityPositive) {
-      velocity = Math.max(velocity, this._MIN_TRANSITION_VELOCITY);
-      this.opened = this.position === 'left';
-    } else {
-      velocity = Math.min(velocity, -this._MIN_TRANSITION_VELOCITY);
-      this.opened = this.position === 'right';
-    }
-    this._setTransitionDuration(this._FLING_INITIAL_SLOPE * dx / velocity + 'ms');
-    this._setTransitionTimingFunction(this._FLING_TIMING_FUNCTION);
-    this._resetDrawerTranslate();
-  },
-  _transitionend: function(event) {
-    var target = Polymer.dom(event).rootTarget;
-    if (target === this.$.contentContainer || target === this.$.scrim) {
-      if (this._drawerState === this._DRAWER_STATE.FLINGING) {
-        this._setTransitionDuration('');
-        this._setTransitionTimingFunction('');
-        this.style.visibility = '';
-      }
-      this._resetDrawerState();
-    }
-  },
-  _setTransitionDuration: function(duration) {
-    this.$.contentContainer.style.transitionDuration = duration;
-    this.$.scrim.style.transitionDuration = duration;
-  },
-  _setTransitionTimingFunction: function(timingFunction) {
-    this.$.contentContainer.style.transitionTimingFunction = timingFunction;
-    this.$.scrim.style.transitionTimingFunction = timingFunction;
-  },
-  _translateDrawer: function(x) {
-    var drawerWidth = this.getWidth();
-    if (this.position === 'left') {
-      x = Math.max(-drawerWidth, Math.min(x, 0));
-      this.$.scrim.style.opacity = 1 + x / drawerWidth;
-    } else {
-      x = Math.max(0, Math.min(x, drawerWidth));
-      this.$.scrim.style.opacity = 1 - x / drawerWidth;
-    }
-    this.translate3d(x + 'px', '0', '0', this.$.contentContainer);
-  },
-  _resetDrawerTranslate: function() {
-    this.$.scrim.style.opacity = '';
-    this.transform('', this.$.contentContainer);
-  },
-  _resetDrawerState: function() {
-    var oldState = this._drawerState;
-    if (this.opened) {
-      this._drawerState = this.persistent ? this._DRAWER_STATE.OPENED_PERSISTENT : this._DRAWER_STATE.OPENED;
-    } else {
-      this._drawerState = this._DRAWER_STATE.CLOSED;
-    }
-    if (oldState !== this._drawerState) {
-      if (this._drawerState === this._DRAWER_STATE.OPENED) {
-        this._setKeyboardFocusTrap();
-        document.addEventListener('keydown', this._boundEscKeydownHandler);
-        document.body.style.overflow = 'hidden';
-      } else {
-        document.removeEventListener('keydown', this._boundEscKeydownHandler);
-        document.body.style.overflow = '';
-      }
-      if (oldState !== this._DRAWER_STATE.INIT) {
-        this.fire('app-drawer-transitioned');
-      }
-    }
-  },
-  _setKeyboardFocusTrap: function() {
-    if (this.noFocusTrap) {
-      return;
-    }
-    var focusableElementsSelector = [ 'a[href]:not([tabindex="-1"])', 'area[href]:not([tabindex="-1"])', 'input:not([disabled]):not([tabindex="-1"])', 'select:not([disabled]):not([tabindex="-1"])', 'textarea:not([disabled]):not([tabindex="-1"])', 'button:not([disabled]):not([tabindex="-1"])', 'iframe:not([tabindex="-1"])', '[tabindex]:not([tabindex="-1"])', '[contentEditable=true]:not([tabindex="-1"])' ].join(',');
-    var focusableElements = Polymer.dom(this).querySelectorAll(focusableElementsSelector);
-    if (focusableElements.length > 0) {
-      this._firstTabStop = focusableElements[0];
-      this._lastTabStop = focusableElements[focusableElements.length - 1];
-    } else {
-      this._firstTabStop = null;
-      this._lastTabStop = null;
-    }
-    var tabindex = this.getAttribute('tabindex');
-    if (tabindex && parseInt(tabindex, 10) > -1) {
-      this.focus();
-    } else if (this._firstTabStop) {
-      this._firstTabStop.focus();
-    }
-  },
-  _tabKeydownHandler: function(event) {
-    if (this.noFocusTrap) {
-      return;
-    }
-    var TAB_KEYCODE = 9;
-    if (this._drawerState === this._DRAWER_STATE.OPENED && event.keyCode === TAB_KEYCODE) {
-      if (event.shiftKey) {
-        if (this._firstTabStop && Polymer.dom(event).localTarget === this._firstTabStop) {
-          event.preventDefault();
-          this._lastTabStop.focus();
-        }
-      } else {
-        if (this._lastTabStop && Polymer.dom(event).localTarget === this._lastTabStop) {
-          event.preventDefault();
-          this._firstTabStop.focus();
-        }
-      }
-    }
-  },
-  _MIN_FLING_THRESHOLD: .2,
-  _MIN_TRANSITION_VELOCITY: 1.2,
-  _FLING_TIMING_FUNCTION: 'cubic-bezier(0.667, 1, 0.667, 1)',
-  _FLING_INITIAL_SLOPE: 1.5,
-  _DRAWER_STATE: {
-    INIT: 0,
-    OPENED: 1,
-    OPENED_PERSISTENT: 2,
-    CLOSED: 3,
-    TRACKING: 4,
-    FLINGING: 5
-  }
-});
-
-Polymer.IronFormElementBehavior = {
-  properties: {
-    name: {
-      type: String
-    },
-    value: {
-      notify: true,
-      type: String
-    },
-    required: {
-      type: Boolean,
-      value: false
-    },
-    _parentForm: {
-      type: Object
-    }
-  },
-  attached: function() {
-    this.fire('iron-form-element-register');
-  },
-  detached: function() {
-    if (this._parentForm) {
-      this._parentForm.fire('iron-form-element-unregister', {
-        target: this
-      });
-    }
-  }
-};
-
-Polymer.IronCheckedElementBehaviorImpl = {
-  properties: {
-    checked: {
-      type: Boolean,
-      value: false,
-      reflectToAttribute: true,
-      notify: true,
-      observer: '_checkedChanged'
-    },
-    toggles: {
-      type: Boolean,
-      value: true,
-      reflectToAttribute: true
-    },
-    value: {
-      type: String,
-      value: 'on',
-      observer: '_valueChanged'
-    }
-  },
-  observers: [ '_requiredChanged(required)' ],
-  created: function() {
-    this._hasIronCheckedElementBehavior = true;
-  },
-  _getValidity: function(_value) {
-    return this.disabled || !this.required || this.checked;
-  },
-  _requiredChanged: function() {
-    if (this.required) {
-      this.setAttribute('aria-required', 'true');
-    } else {
-      this.removeAttribute('aria-required');
-    }
-  },
-  _checkedChanged: function() {
-    this.active = this.checked;
-    this.fire('iron-change');
-  },
-  _valueChanged: function() {
-    if (this.value === undefined || this.value === null) {
-      this.value = 'on';
-    }
-  }
-};
-
-Polymer.IronCheckedElementBehavior = [ Polymer.IronFormElementBehavior, Polymer.IronValidatableBehavior, Polymer.IronCheckedElementBehaviorImpl ];
-
-Polymer.PaperCheckedElementBehaviorImpl = {
-  _checkedChanged: function() {
-    Polymer.IronCheckedElementBehaviorImpl._checkedChanged.call(this);
-    if (this.hasRipple()) {
-      if (this.checked) {
-        this._ripple.setAttribute('checked', '');
-      } else {
-        this._ripple.removeAttribute('checked');
-      }
-    }
-  },
-  _buttonStateChanged: function() {
-    Polymer.PaperRippleBehavior._buttonStateChanged.call(this);
-    if (this.disabled) {
-      return;
-    }
-    if (this.isAttached) {
-      this.checked = this.active;
-    }
-  }
-};
-
-Polymer.PaperCheckedElementBehavior = [ Polymer.PaperInkyFocusBehavior, Polymer.IronCheckedElementBehavior, Polymer.PaperCheckedElementBehaviorImpl ];
-
-Polymer({
-  is: 'paper-checkbox',
-  behaviors: [ Polymer.PaperCheckedElementBehavior ],
-  hostAttributes: {
-    role: 'checkbox',
-    'aria-checked': false,
-    tabindex: 0
-  },
-  properties: {
-    ariaActiveAttribute: {
-      type: String,
-      value: 'aria-checked'
-    }
-  },
-  attached: function() {
-    var inkSize = this.getComputedStyleValue('--calculated-paper-checkbox-ink-size');
-    if (inkSize === '-1px') {
-      var checkboxSize = parseFloat(this.getComputedStyleValue('--calculated-paper-checkbox-size'));
-      var defaultInkSize = Math.floor(8 / 3 * checkboxSize);
-      if (defaultInkSize % 2 !== checkboxSize % 2) {
-        defaultInkSize++;
-      }
-      this.customStyle['--paper-checkbox-ink-size'] = defaultInkSize + 'px';
-      this.updateStyles();
-    }
-  },
-  _computeCheckboxClass: function(checked, invalid) {
-    var className = '';
-    if (checked) {
-      className += 'checked ';
-    }
-    if (invalid) {
-      className += 'invalid';
-    }
-    return className;
-  },
-  _computeCheckmarkClass: function(checked) {
-    return checked ? '' : 'hidden';
-  },
-  _createRipple: function() {
-    this._rippleContainer = this.$.checkboxContainer;
-    return Polymer.PaperInkyFocusBehaviorImpl._createRipple.call(this);
-  }
-});
-
-Polymer({
-  is: 'paper-tab',
-  behaviors: [ Polymer.IronControlState, Polymer.IronButtonState, Polymer.PaperRippleBehavior ],
-  properties: {
-    link: {
-      type: Boolean,
-      value: false,
-      reflectToAttribute: true
-    }
-  },
-  hostAttributes: {
-    role: 'tab'
-  },
-  listeners: {
-    down: '_updateNoink',
-    tap: '_onTap'
-  },
-  attached: function() {
-    this._updateNoink();
-  },
-  get _parentNoink() {
-    var parent = Polymer.dom(this).parentNode;
-    return !!parent && !!parent.noink;
-  },
-  _updateNoink: function() {
-    this.noink = !!this.noink || !!this._parentNoink;
-  },
-  _onTap: function(event) {
-    if (this.link) {
-      var anchor = this.queryEffectiveChildren('a');
-      if (!anchor) {
-        return;
-      }
-      if (event.target === anchor) {
-        return;
-      }
-      anchor.click();
-    }
-  }
-});
-
-Polymer.IronMenuBehaviorImpl = {
-  properties: {
-    focusedItem: {
-      observer: '_focusedItemChanged',
-      readOnly: true,
-      type: Object
-    },
-    attrForItemTitle: {
-      type: String
-    }
-  },
-  hostAttributes: {
-    role: 'menu',
-    tabindex: '0'
-  },
-  observers: [ '_updateMultiselectable(multi)' ],
-  listeners: {
-    focus: '_onFocus',
-    keydown: '_onKeydown',
-    'iron-items-changed': '_onIronItemsChanged'
-  },
-  keyBindings: {
-    up: '_onUpKey',
-    down: '_onDownKey',
-    esc: '_onEscKey',
-    'shift+tab:keydown': '_onShiftTabDown'
-  },
-  attached: function() {
-    this._resetTabindices();
-  },
-  select: function(value) {
-    if (this._defaultFocusAsync) {
-      this.cancelAsync(this._defaultFocusAsync);
-      this._defaultFocusAsync = null;
-    }
-    var item = this._valueToItem(value);
-    if (item && item.hasAttribute('disabled')) return;
-    this._setFocusedItem(item);
-    Polymer.IronMultiSelectableBehaviorImpl.select.apply(this, arguments);
-  },
-  _resetTabindices: function() {
-    var selectedItem = this.multi ? this.selectedItems && this.selectedItems[0] : this.selectedItem;
-    this.items.forEach(function(item) {
-      item.setAttribute('tabindex', item === selectedItem ? '0' : '-1');
-    }, this);
-  },
-  _updateMultiselectable: function(multi) {
-    if (multi) {
-      this.setAttribute('aria-multiselectable', 'true');
-    } else {
-      this.removeAttribute('aria-multiselectable');
-    }
-  },
-  _focusWithKeyboardEvent: function(event) {
-    for (var i = 0, item; item = this.items[i]; i++) {
-      var attr = this.attrForItemTitle || 'textContent';
-      var title = item[attr] || item.getAttribute(attr);
-      if (!item.hasAttribute('disabled') && title && title.trim().charAt(0).toLowerCase() === String.fromCharCode(event.keyCode).toLowerCase()) {
-        this._setFocusedItem(item);
-        break;
-      }
-    }
-  },
-  _focusPrevious: function() {
-    var length = this.items.length;
-    var curFocusIndex = Number(this.indexOf(this.focusedItem));
-    for (var i = 1; i < length + 1; i++) {
-      var item = this.items[(curFocusIndex - i + length) % length];
-      if (!item.hasAttribute('disabled')) {
-        var owner = Polymer.dom(item).getOwnerRoot() || document;
-        this._setFocusedItem(item);
-        if (Polymer.dom(owner).activeElement == item) {
-          return;
-        }
-      }
-    }
-  },
-  _focusNext: function() {
-    var length = this.items.length;
-    var curFocusIndex = Number(this.indexOf(this.focusedItem));
-    for (var i = 1; i < length + 1; i++) {
-      var item = this.items[(curFocusIndex + i) % length];
-      if (!item.hasAttribute('disabled')) {
-        var owner = Polymer.dom(item).getOwnerRoot() || document;
-        this._setFocusedItem(item);
-        if (Polymer.dom(owner).activeElement == item) {
-          return;
-        }
-      }
-    }
-  },
-  _applySelection: function(item, isSelected) {
-    if (isSelected) {
-      item.setAttribute('aria-selected', 'true');
-    } else {
-      item.removeAttribute('aria-selected');
-    }
-    Polymer.IronSelectableBehavior._applySelection.apply(this, arguments);
-  },
-  _focusedItemChanged: function(focusedItem, old) {
-    old && old.setAttribute('tabindex', '-1');
-    if (focusedItem) {
-      focusedItem.setAttribute('tabindex', '0');
-      focusedItem.focus();
-    }
-  },
-  _onIronItemsChanged: function(event) {
-    if (event.detail.addedNodes.length) {
-      this._resetTabindices();
-    }
-  },
-  _onShiftTabDown: function(event) {
-    var oldTabIndex = this.getAttribute('tabindex');
-    Polymer.IronMenuBehaviorImpl._shiftTabPressed = true;
-    this._setFocusedItem(null);
-    this.setAttribute('tabindex', '-1');
-    this.async(function() {
-      this.setAttribute('tabindex', oldTabIndex);
-      Polymer.IronMenuBehaviorImpl._shiftTabPressed = false;
-    }, 1);
-  },
-  _onFocus: function(event) {
-    if (Polymer.IronMenuBehaviorImpl._shiftTabPressed) {
-      return;
-    }
-    var rootTarget = Polymer.dom(event).rootTarget;
-    if (rootTarget !== this && typeof rootTarget.tabIndex !== "undefined" && !this.isLightDescendant(rootTarget)) {
-      return;
-    }
-    this._defaultFocusAsync = this.async(function() {
-      var selectedItem = this.multi ? this.selectedItems && this.selectedItems[0] : this.selectedItem;
-      this._setFocusedItem(null);
-      if (selectedItem) {
-        this._setFocusedItem(selectedItem);
-      } else if (this.items[0]) {
-        this._focusNext();
-      }
-    });
-  },
-  _onUpKey: function(event) {
-    this._focusPrevious();
-    event.detail.keyboardEvent.preventDefault();
-  },
-  _onDownKey: function(event) {
-    this._focusNext();
-    event.detail.keyboardEvent.preventDefault();
-  },
-  _onEscKey: function(event) {
-    this.focusedItem.blur();
-  },
-  _onKeydown: function(event) {
-    if (!this.keyboardEventMatchesKeys(event, 'up down esc')) {
-      this._focusWithKeyboardEvent(event);
-    }
-    event.stopPropagation();
-  },
-  _activateHandler: function(event) {
-    Polymer.IronSelectableBehavior._activateHandler.call(this, event);
-    event.stopPropagation();
-  }
-};
-
-Polymer.IronMenuBehaviorImpl._shiftTabPressed = false;
-
-Polymer.IronMenuBehavior = [ Polymer.IronMultiSelectableBehavior, Polymer.IronA11yKeysBehavior, Polymer.IronMenuBehaviorImpl ];
-
-Polymer.IronMenubarBehaviorImpl = {
-  hostAttributes: {
-    role: 'menubar'
-  },
-  keyBindings: {
-    left: '_onLeftKey',
-    right: '_onRightKey'
-  },
-  _onUpKey: function(event) {
-    this.focusedItem.click();
-    event.detail.keyboardEvent.preventDefault();
-  },
-  _onDownKey: function(event) {
-    this.focusedItem.click();
-    event.detail.keyboardEvent.preventDefault();
-  },
-  get _isRTL() {
-    return window.getComputedStyle(this)['direction'] === 'rtl';
-  },
-  _onLeftKey: function(event) {
-    if (this._isRTL) {
-      this._focusNext();
-    } else {
-      this._focusPrevious();
-    }
-    event.detail.keyboardEvent.preventDefault();
-  },
-  _onRightKey: function(event) {
-    if (this._isRTL) {
-      this._focusPrevious();
-    } else {
-      this._focusNext();
-    }
-    event.detail.keyboardEvent.preventDefault();
-  },
-  _onKeydown: function(event) {
-    if (this.keyboardEventMatchesKeys(event, 'up down left right esc')) {
-      return;
-    }
-    this._focusWithKeyboardEvent(event);
-  }
-};
-
-Polymer.IronMenubarBehavior = [ Polymer.IronMenuBehavior, Polymer.IronMenubarBehaviorImpl ];
-
-Polymer({
-  is: 'paper-tabs',
-  behaviors: [ Polymer.IronResizableBehavior, Polymer.IronMenubarBehavior ],
-  properties: {
-    noink: {
-      type: Boolean,
-      value: false,
-      observer: '_noinkChanged'
-    },
-    noBar: {
-      type: Boolean,
-      value: false
-    },
-    noSlide: {
-      type: Boolean,
-      value: false
-    },
-    scrollable: {
-      type: Boolean,
-      value: false
-    },
-    fitContainer: {
-      type: Boolean,
-      value: false
-    },
-    disableDrag: {
-      type: Boolean,
-      value: false
-    },
-    hideScrollButtons: {
-      type: Boolean,
-      value: false
-    },
-    alignBottom: {
-      type: Boolean,
-      value: false
-    },
-    selectable: {
-      type: String,
-      value: 'paper-tab'
-    },
-    autoselect: {
-      type: Boolean,
-      value: false
-    },
-    autoselectDelay: {
-      type: Number,
-      value: 0
-    },
-    _step: {
-      type: Number,
-      value: 10
-    },
-    _holdDelay: {
-      type: Number,
-      value: 1
-    },
-    _leftHidden: {
-      type: Boolean,
-      value: false
-    },
-    _rightHidden: {
-      type: Boolean,
-      value: false
-    },
-    _previousTab: {
-      type: Object
-    }
-  },
-  hostAttributes: {
-    role: 'tablist'
-  },
-  listeners: {
-    'iron-resize': '_onTabSizingChanged',
-    'iron-items-changed': '_onTabSizingChanged',
-    'iron-select': '_onIronSelect',
-    'iron-deselect': '_onIronDeselect'
-  },
-  keyBindings: {
-    'left:keyup right:keyup': '_onArrowKeyup'
-  },
-  created: function() {
-    this._holdJob = null;
-    this._pendingActivationItem = undefined;
-    this._pendingActivationTimeout = undefined;
-    this._bindDelayedActivationHandler = this._delayedActivationHandler.bind(this);
-    this.addEventListener('blur', this._onBlurCapture.bind(this), true);
-  },
-  ready: function() {
-    this.setScrollDirection('y', this.$.tabsContainer);
-  },
-  detached: function() {
-    this._cancelPendingActivation();
-  },
-  _noinkChanged: function(noink) {
-    var childTabs = Polymer.dom(this).querySelectorAll('paper-tab');
-    childTabs.forEach(noink ? this._setNoinkAttribute : this._removeNoinkAttribute);
-  },
-  _setNoinkAttribute: function(element) {
-    element.setAttribute('noink', '');
-  },
-  _removeNoinkAttribute: function(element) {
-    element.removeAttribute('noink');
-  },
-  _computeScrollButtonClass: function(hideThisButton, scrollable, hideScrollButtons) {
-    if (!scrollable || hideScrollButtons) {
-      return 'hidden';
-    }
-    if (hideThisButton) {
-      return 'not-visible';
-    }
-    return '';
-  },
-  _computeTabsContentClass: function(scrollable, fitContainer) {
-    return scrollable ? 'scrollable' + (fitContainer ? ' fit-container' : '') : ' fit-container';
-  },
-  _computeSelectionBarClass: function(noBar, alignBottom) {
-    if (noBar) {
-      return 'hidden';
-    } else if (alignBottom) {
-      return 'align-bottom';
-    }
-    return '';
-  },
-  _onTabSizingChanged: function() {
-    this.debounce('_onTabSizingChanged', function() {
-      this._scroll();
-      this._tabChanged(this.selectedItem);
-    }, 10);
-  },
-  _onIronSelect: function(event) {
-    this._tabChanged(event.detail.item, this._previousTab);
-    this._previousTab = event.detail.item;
-    this.cancelDebouncer('tab-changed');
-  },
-  _onIronDeselect: function(event) {
-    this.debounce('tab-changed', function() {
-      this._tabChanged(null, this._previousTab);
-      this._previousTab = null;
-    }, 1);
-  },
-  _activateHandler: function() {
-    this._cancelPendingActivation();
-    Polymer.IronMenuBehaviorImpl._activateHandler.apply(this, arguments);
-  },
-  _scheduleActivation: function(item, delay) {
-    this._pendingActivationItem = item;
-    this._pendingActivationTimeout = this.async(this._bindDelayedActivationHandler, delay);
-  },
-  _delayedActivationHandler: function() {
-    var item = this._pendingActivationItem;
-    this._pendingActivationItem = undefined;
-    this._pendingActivationTimeout = undefined;
-    item.fire(this.activateEvent, null, {
-      bubbles: true,
-      cancelable: true
-    });
-  },
-  _cancelPendingActivation: function() {
-    if (this._pendingActivationTimeout !== undefined) {
-      this.cancelAsync(this._pendingActivationTimeout);
-      this._pendingActivationItem = undefined;
-      this._pendingActivationTimeout = undefined;
-    }
-  },
-  _onArrowKeyup: function(event) {
-    if (this.autoselect) {
-      this._scheduleActivation(this.focusedItem, this.autoselectDelay);
-    }
-  },
-  _onBlurCapture: function(event) {
-    if (event.target === this._pendingActivationItem) {
-      this._cancelPendingActivation();
-    }
-  },
-  get _tabContainerScrollSize() {
-    return Math.max(0, this.$.tabsContainer.scrollWidth - this.$.tabsContainer.offsetWidth);
-  },
-  _scroll: function(e, detail) {
-    if (!this.scrollable) {
-      return;
-    }
-    var ddx = detail && -detail.ddx || 0;
-    this._affectScroll(ddx);
-  },
-  _down: function(e) {
-    this.async(function() {
-      if (this._defaultFocusAsync) {
-        this.cancelAsync(this._defaultFocusAsync);
-        this._defaultFocusAsync = null;
-      }
-    }, 1);
-  },
-  _affectScroll: function(dx) {
-    this.$.tabsContainer.scrollLeft += dx;
-    var scrollLeft = this.$.tabsContainer.scrollLeft;
-    this._leftHidden = scrollLeft === 0;
-    this._rightHidden = scrollLeft === this._tabContainerScrollSize;
-  },
-  _onLeftScrollButtonDown: function() {
-    this._scrollToLeft();
-    this._holdJob = setInterval(this._scrollToLeft.bind(this), this._holdDelay);
-  },
-  _onRightScrollButtonDown: function() {
-    this._scrollToRight();
-    this._holdJob = setInterval(this._scrollToRight.bind(this), this._holdDelay);
-  },
-  _onScrollButtonUp: function() {
-    clearInterval(this._holdJob);
-    this._holdJob = null;
-  },
-  _scrollToLeft: function() {
-    this._affectScroll(-this._step);
-  },
-  _scrollToRight: function() {
-    this._affectScroll(this._step);
-  },
-  _tabChanged: function(tab, old) {
-    if (!tab) {
-      this.$.selectionBar.classList.remove('expand');
-      this.$.selectionBar.classList.remove('contract');
-      this._positionBar(0, 0);
-      return;
-    }
-    var r = this.$.tabsContent.getBoundingClientRect();
-    var w = r.width;
-    var tabRect = tab.getBoundingClientRect();
-    var tabOffsetLeft = tabRect.left - r.left;
-    this._pos = {
-      width: this._calcPercent(tabRect.width, w),
-      left: this._calcPercent(tabOffsetLeft, w)
-    };
-    if (this.noSlide || old == null) {
-      this.$.selectionBar.classList.remove('expand');
-      this.$.selectionBar.classList.remove('contract');
-      this._positionBar(this._pos.width, this._pos.left);
-      return;
-    }
-    var oldRect = old.getBoundingClientRect();
-    var oldIndex = this.items.indexOf(old);
-    var index = this.items.indexOf(tab);
-    var m = 5;
-    this.$.selectionBar.classList.add('expand');
-    var moveRight = oldIndex < index;
-    var isRTL = this._isRTL;
-    if (isRTL) {
-      moveRight = !moveRight;
-    }
-    if (moveRight) {
-      this._positionBar(this._calcPercent(tabRect.left + tabRect.width - oldRect.left, w) - m, this._left);
-    } else {
-      this._positionBar(this._calcPercent(oldRect.left + oldRect.width - tabRect.left, w) - m, this._calcPercent(tabOffsetLeft, w) + m);
-    }
-    if (this.scrollable) {
-      this._scrollToSelectedIfNeeded(tabRect.width, tabOffsetLeft);
-    }
-  },
-  _scrollToSelectedIfNeeded: function(tabWidth, tabOffsetLeft) {
-    var l = tabOffsetLeft - this.$.tabsContainer.scrollLeft;
-    if (l < 0) {
-      this.$.tabsContainer.scrollLeft += l;
-    } else {
-      l += tabWidth - this.$.tabsContainer.offsetWidth;
-      if (l > 0) {
-        this.$.tabsContainer.scrollLeft += l;
-      }
-    }
-  },
-  _calcPercent: function(w, w0) {
-    return 100 * w / w0;
-  },
-  _positionBar: function(width, left) {
-    width = width || 0;
-    left = left || 0;
-    this._width = width;
-    this._left = left;
-    this.transform('translateX(' + left + '%) scaleX(' + width / 100 + ')', this.$.selectionBar);
-  },
-  _onBarTransitionEnd: function(e) {
-    var cl = this.$.selectionBar.classList;
-    if (cl.contains('expand')) {
-      cl.remove('expand');
-      cl.add('contract');
-      this._positionBar(this._pos.width, this._pos.left);
-    } else if (cl.contains('contract')) {
-      cl.remove('contract');
-    }
-  }
-});
\ No newline at end of file
+Polymer({is:"cr-dialog","extends":"dialog",created:function(){window.addEventListener("popstate",function(){if(this.open)this.cancel()}.bind(this))},cancel:function(){this.fire("cancel");HTMLDialogElement.prototype.close.call(this,"")},close:function(opt_returnValue){HTMLDialogElement.prototype.close.call(this,"success")},getCloseButton:function(){return this.$.close}});Polymer({is:"app-drawer",properties:{opened:{type:Boolean,value:false,notify:true,reflectToAttribute:true},persistent:{type:Boolean,value:false,reflectToAttribute:true},align:{type:String,value:"left"},position:{type:String,readOnly:true,value:"left",reflectToAttribute:true},swipeOpen:{type:Boolean,value:false,reflectToAttribute:true},noFocusTrap:{type:Boolean,value:false}},observers:["resetLayout(position)","_resetPosition(align, isAttached)"],_translateOffset:0,_trackDetails:null,_drawerState:0,_boundEscKeydownHandler:null,_firstTabStop:null,_lastTabStop:null,ready:function(){this.setScrollDirection("y");this._setTransitionDuration("0s")},attached:function(){Polymer.RenderStatus.afterNextRender(this,function(){this._setTransitionDuration("");this._boundEscKeydownHandler=this._escKeydownHandler.bind(this);this._resetDrawerState();this.listen(this,"track","_track");this.addEventListener("transitionend",this._transitionend.bind(this));this.addEventListener("keydown",this._tabKeydownHandler.bind(this))})},detached:function(){document.removeEventListener("keydown",this._boundEscKeydownHandler)},open:function(){this.opened=true},close:function(){this.opened=false},toggle:function(){this.opened=!this.opened},getWidth:function(){return this.$.contentContainer.offsetWidth},resetLayout:function(){this.debounce("_resetLayout",function(){this.fire("app-drawer-reset-layout")},1)},_isRTL:function(){return window.getComputedStyle(this).direction==="rtl"},_resetPosition:function(){switch(this.align){case"start":this._setPosition(this._isRTL()?"right":"left");return;case"end":this._setPosition(this._isRTL()?"left":"right");return}this._setPosition(this.align)},_escKeydownHandler:function(event){var ESC_KEYCODE=27;if(event.keyCode===ESC_KEYCODE){event.preventDefault();this.close()}},_track:function(event){if(this.persistent){return}event.preventDefault();switch(event.detail.state){case"start":this._trackStart(event);break;case"track":this._trackMove(event);break;case"end":this._trackEnd(event);break}},_trackStart:function(event){this._drawerState=this._DRAWER_STATE.TRACKING;this._setTransitionDuration("0s");this.style.visibility="visible";var rect=this.$.contentContainer.getBoundingClientRect();if(this.position==="left"){this._translateOffset=rect.left}else{this._translateOffset=rect.right-window.innerWidth}this._trackDetails=[]},_trackMove:function(event){this._translateDrawer(event.detail.dx+this._translateOffset);this._trackDetails.push({dx:event.detail.dx,timeStamp:Date.now()})},_trackEnd:function(event){var x=event.detail.dx+this._translateOffset;var drawerWidth=this.getWidth();var isPositionLeft=this.position==="left";var isInEndState=isPositionLeft?x>=0||x<=-drawerWidth:x<=0||x>=drawerWidth;if(!isInEndState){var trackDetails=this._trackDetails;this._trackDetails=null;this._flingDrawer(event,trackDetails);if(this._drawerState===this._DRAWER_STATE.FLINGING){return}}var halfWidth=drawerWidth/2;if(event.detail.dx<-halfWidth){this.opened=this.position==="right"}else if(event.detail.dx>halfWidth){this.opened=this.position==="left"}if(isInEndState){this._resetDrawerState()}this._setTransitionDuration("");this._resetDrawerTranslate();this.style.visibility=""},_calculateVelocity:function(event,trackDetails){var now=Date.now();var timeLowerBound=now-100;var trackDetail;var min=0;var max=trackDetails.length-1;while(min<=max){var mid=min+max>>1;var d=trackDetails[mid];if(d.timeStamp>=timeLowerBound){trackDetail=d;max=mid-1}else{min=mid+1}}if(trackDetail){var dx=event.detail.dx-trackDetail.dx;var dt=now-trackDetail.timeStamp||1;return dx/dt}return 0},_flingDrawer:function(event,trackDetails){var velocity=this._calculateVelocity(event,trackDetails);if(Math.abs(velocity)<this._MIN_FLING_THRESHOLD){return}this._drawerState=this._DRAWER_STATE.FLINGING;var x=event.detail.dx+this._translateOffset;var drawerWidth=this.getWidth();var isPositionLeft=this.position==="left";var isVelocityPositive=velocity>0;var isClosingLeft=!isVelocityPositive&&isPositionLeft;var isClosingRight=isVelocityPositive&&!isPositionLeft;var dx;if(isClosingLeft){dx=-(x+drawerWidth)}else if(isClosingRight){dx=drawerWidth-x}else{dx=-x}if(isVelocityPositive){velocity=Math.max(velocity,this._MIN_TRANSITION_VELOCITY);this.opened=this.position==="left"}else{velocity=Math.min(velocity,-this._MIN_TRANSITION_VELOCITY);this.opened=this.position==="right"}this._setTransitionDuration(this._FLING_INITIAL_SLOPE*dx/velocity+"ms");this._setTransitionTimingFunction(this._FLING_TIMING_FUNCTION);this._resetDrawerTranslate()},_transitionend:function(event){var target=Polymer.dom(event).rootTarget;if(target===this.$.contentContainer||target===this.$.scrim){if(this._drawerState===this._DRAWER_STATE.FLINGING){this._setTransitionDuration("");this._setTransitionTimingFunction("");this.style.visibility=""}this._resetDrawerState()}},_setTransitionDuration:function(duration){this.$.contentContainer.style.transitionDuration=duration;this.$.scrim.style.transitionDuration=duration},_setTransitionTimingFunction:function(timingFunction){this.$.contentContainer.style.transitionTimingFunction=timingFunction;this.$.scrim.style.transitionTimingFunction=timingFunction},_translateDrawer:function(x){var drawerWidth=this.getWidth();if(this.position==="left"){x=Math.max(-drawerWidth,Math.min(x,0));this.$.scrim.style.opacity=1+x/drawerWidth}else{x=Math.max(0,Math.min(x,drawerWidth));this.$.scrim.style.opacity=1-x/drawerWidth}this.translate3d(x+"px","0","0",this.$.contentContainer)},_resetDrawerTranslate:function(){this.$.scrim.style.opacity="";this.transform("",this.$.contentContainer)},_resetDrawerState:function(){var oldState=this._drawerState;if(this.opened){this._drawerState=this.persistent?this._DRAWER_STATE.OPENED_PERSISTENT:this._DRAWER_STATE.OPENED}else{this._drawerState=this._DRAWER_STATE.CLOSED}if(oldState!==this._drawerState){if(this._drawerState===this._DRAWER_STATE.OPENED){this._setKeyboardFocusTrap();document.addEventListener("keydown",this._boundEscKeydownHandler);document.body.style.overflow="hidden"}else{document.removeEventListener("keydown",this._boundEscKeydownHandler);document.body.style.overflow=""}if(oldState!==this._DRAWER_STATE.INIT){this.fire("app-drawer-transitioned")}}},_setKeyboardFocusTrap:function(){if(this.noFocusTrap){return}var focusableElementsSelector=['a[href]:not([tabindex="-1"])','area[href]:not([tabindex="-1"])','input:not([disabled]):not([tabindex="-1"])','select:not([disabled]):not([tabindex="-1"])','textarea:not([disabled]):not([tabindex="-1"])','button:not([disabled]):not([tabindex="-1"])','iframe:not([tabindex="-1"])','[tabindex]:not([tabindex="-1"])','[contentEditable=true]:not([tabindex="-1"])'].join(",");var focusableElements=Polymer.dom(this).querySelectorAll(focusableElementsSelector);if(focusableElements.length>0){this._firstTabStop=focusableElements[0];this._lastTabStop=focusableElements[focusableElements.length-1]}else{this._firstTabStop=null;this._lastTabStop=null}var tabindex=this.getAttribute("tabindex");if(tabindex&&parseInt(tabindex,10)>-1){this.focus()}else if(this._firstTabStop){this._firstTabStop.focus()}},_tabKeydownHandler:function(event){if(this.noFocusTrap){return}var TAB_KEYCODE=9;if(this._drawerState===this._DRAWER_STATE.OPENED&&event.keyCode===TAB_KEYCODE){if(event.shiftKey){if(this._firstTabStop&&Polymer.dom(event).localTarget===this._firstTabStop){event.preventDefault();this._lastTabStop.focus()}}else{if(this._lastTabStop&&Polymer.dom(event).localTarget===this._lastTabStop){event.preventDefault();this._firstTabStop.focus()}}}},_MIN_FLING_THRESHOLD:.2,_MIN_TRANSITION_VELOCITY:1.2,_FLING_TIMING_FUNCTION:"cubic-bezier(0.667, 1, 0.667, 1)",_FLING_INITIAL_SLOPE:1.5,_DRAWER_STATE:{INIT:0,OPENED:1,OPENED_PERSISTENT:2,CLOSED:3,TRACKING:4,FLINGING:5}});Polymer.IronFormElementBehavior={properties:{name:{type:String},value:{notify:true,type:String},required:{type:Boolean,value:false},_parentForm:{type:Object}},attached:function(){this.fire("iron-form-element-register")},detached:function(){if(this._parentForm){this._parentForm.fire("iron-form-element-unregister",{target:this})}}};Polymer.IronCheckedElementBehaviorImpl={properties:{checked:{type:Boolean,value:false,reflectToAttribute:true,notify:true,observer:"_checkedChanged"},toggles:{type:Boolean,value:true,reflectToAttribute:true},value:{type:String,value:"on",observer:"_valueChanged"}},observers:["_requiredChanged(required)"],created:function(){this._hasIronCheckedElementBehavior=true},_getValidity:function(_value){return this.disabled||!this.required||this.checked},_requiredChanged:function(){if(this.required){this.setAttribute("aria-required","true")}else{this.removeAttribute("aria-required")}},_checkedChanged:function(){this.active=this.checked;this.fire("iron-change")},_valueChanged:function(){if(this.value===undefined||this.value===null){this.value="on"}}};Polymer.IronCheckedElementBehavior=[Polymer.IronFormElementBehavior,Polymer.IronValidatableBehavior,Polymer.IronCheckedElementBehaviorImpl];Polymer.PaperCheckedElementBehaviorImpl={_checkedChanged:function(){Polymer.IronCheckedElementBehaviorImpl._checkedChanged.call(this);if(this.hasRipple()){if(this.checked){this._ripple.setAttribute("checked","")}else{this._ripple.removeAttribute("checked")}}},_buttonStateChanged:function(){Polymer.PaperRippleBehavior._buttonStateChanged.call(this);if(this.disabled){return}if(this.isAttached){this.checked=this.active}}};Polymer.PaperCheckedElementBehavior=[Polymer.PaperInkyFocusBehavior,Polymer.IronCheckedElementBehavior,Polymer.PaperCheckedElementBehaviorImpl];Polymer({is:"paper-checkbox",behaviors:[Polymer.PaperCheckedElementBehavior],hostAttributes:{role:"checkbox","aria-checked":false,tabindex:0},properties:{ariaActiveAttribute:{type:String,value:"aria-checked"}},attached:function(){var inkSize=this.getComputedStyleValue("--calculated-paper-checkbox-ink-size");if(inkSize==="-1px"){var checkboxSize=parseFloat(this.getComputedStyleValue("--calculated-paper-checkbox-size"));var defaultInkSize=Math.floor(8/3*checkboxSize);if(defaultInkSize%2!==checkboxSize%2){defaultInkSize++}this.customStyle["--paper-checkbox-ink-size"]=defaultInkSize+"px";this.updateStyles()}},_computeCheckboxClass:function(checked,invalid){var className="";if(checked){className+="checked "}if(invalid){className+="invalid"}return className},_computeCheckmarkClass:function(checked){return checked?"":"hidden"},_createRipple:function(){this._rippleContainer=this.$.checkboxContainer;return Polymer.PaperInkyFocusBehaviorImpl._createRipple.call(this)}});Polymer({is:"paper-tab",behaviors:[Polymer.IronControlState,Polymer.IronButtonState,Polymer.PaperRippleBehavior],properties:{link:{type:Boolean,value:false,reflectToAttribute:true}},hostAttributes:{role:"tab"},listeners:{down:"_updateNoink",tap:"_onTap"},attached:function(){this._updateNoink()},get _parentNoink(){var parent=Polymer.dom(this).parentNode;return!!parent&&!!parent.noink},_updateNoink:function(){this.noink=!!this.noink||!!this._parentNoink},_onTap:function(event){if(this.link){var anchor=this.queryEffectiveChildren("a");if(!anchor){return}if(event.target===anchor){return}anchor.click()}}});Polymer.IronMenubarBehaviorImpl={hostAttributes:{role:"menubar"},keyBindings:{left:"_onLeftKey",right:"_onRightKey"},_onUpKey:function(event){this.focusedItem.click();event.detail.keyboardEvent.preventDefault()},_onDownKey:function(event){this.focusedItem.click();event.detail.keyboardEvent.preventDefault()},get _isRTL(){return window.getComputedStyle(this)["direction"]==="rtl"},_onLeftKey:function(event){if(this._isRTL){this._focusNext()}else{this._focusPrevious()}event.detail.keyboardEvent.preventDefault()},_onRightKey:function(event){if(this._isRTL){this._focusPrevious()}else{this._focusNext()}event.detail.keyboardEvent.preventDefault()},_onKeydown:function(event){if(this.keyboardEventMatchesKeys(event,"up down left right esc")){return}this._focusWithKeyboardEvent(event)}};Polymer.IronMenubarBehavior=[Polymer.IronMenuBehavior,Polymer.IronMenubarBehaviorImpl];Polymer({is:"paper-tabs",behaviors:[Polymer.IronResizableBehavior,Polymer.IronMenubarBehavior],properties:{noink:{type:Boolean,value:false,observer:"_noinkChanged"},noBar:{type:Boolean,value:false},noSlide:{type:Boolean,value:false},scrollable:{type:Boolean,value:false},fitContainer:{type:Boolean,value:false},disableDrag:{type:Boolean,value:false},hideScrollButtons:{type:Boolean,value:false},alignBottom:{type:Boolean,value:false},selectable:{type:String,value:"paper-tab"},autoselect:{type:Boolean,value:false},autoselectDelay:{type:Number,value:0},_step:{type:Number,value:10},_holdDelay:{type:Number,value:1},_leftHidden:{type:Boolean,value:false},_rightHidden:{type:Boolean,value:false},_previousTab:{type:Object}},hostAttributes:{role:"tablist"},listeners:{"iron-resize":"_onTabSizingChanged","iron-items-changed":"_onTabSizingChanged","iron-select":"_onIronSelect","iron-deselect":"_onIronDeselect"},keyBindings:{"left:keyup right:keyup":"_onArrowKeyup"},created:function(){this._holdJob=null;this._pendingActivationItem=undefined;this._pendingActivationTimeout=undefined;this._bindDelayedActivationHandler=this._delayedActivationHandler.bind(this);this.addEventListener("blur",this._onBlurCapture.bind(this),true)},ready:function(){this.setScrollDirection("y",this.$.tabsContainer)},detached:function(){this._cancelPendingActivation()},_noinkChanged:function(noink){var childTabs=Polymer.dom(this).querySelectorAll("paper-tab");childTabs.forEach(noink?this._setNoinkAttribute:this._removeNoinkAttribute)},_setNoinkAttribute:function(element){element.setAttribute("noink","")},_removeNoinkAttribute:function(element){element.removeAttribute("noink")},_computeScrollButtonClass:function(hideThisButton,scrollable,hideScrollButtons){if(!scrollable||hideScrollButtons){return"hidden"}if(hideThisButton){return"not-visible"}return""},_computeTabsContentClass:function(scrollable,fitContainer){return scrollable?"scrollable"+(fitContainer?" fit-container":""):" fit-container"},_computeSelectionBarClass:function(noBar,alignBottom){if(noBar){return"hidden"}else if(alignBottom){return"align-bottom"}return""},_onTabSizingChanged:function(){this.debounce("_onTabSizingChanged",function(){this._scroll();this._tabChanged(this.selectedItem)},10)},_onIronSelect:function(event){this._tabChanged(event.detail.item,this._previousTab);this._previousTab=event.detail.item;this.cancelDebouncer("tab-changed")},_onIronDeselect:function(event){this.debounce("tab-changed",function(){this._tabChanged(null,this._previousTab);this._previousTab=null},1)},_activateHandler:function(){this._cancelPendingActivation();Polymer.IronMenuBehaviorImpl._activateHandler.apply(this,arguments)},_scheduleActivation:function(item,delay){this._pendingActivationItem=item;this._pendingActivationTimeout=this.async(this._bindDelayedActivationHandler,delay)},_delayedActivationHandler:function(){var item=this._pendingActivationItem;this._pendingActivationItem=undefined;this._pendingActivationTimeout=undefined;item.fire(this.activateEvent,null,{bubbles:true,cancelable:true})},_cancelPendingActivation:function(){if(this._pendingActivationTimeout!==undefined){this.cancelAsync(this._pendingActivationTimeout);this._pendingActivationItem=undefined;this._pendingActivationTimeout=undefined}},_onArrowKeyup:function(event){if(this.autoselect){this._scheduleActivation(this.focusedItem,this.autoselectDelay)}},_onBlurCapture:function(event){if(event.target===this._pendingActivationItem){this._cancelPendingActivation()}},get _tabContainerScrollSize(){return Math.max(0,this.$.tabsContainer.scrollWidth-this.$.tabsContainer.offsetWidth)},_scroll:function(e,detail){if(!this.scrollable){return}var ddx=detail&&-detail.ddx||0;this._affectScroll(ddx)},_down:function(e){this.async(function(){if(this._defaultFocusAsync){this.cancelAsync(this._defaultFocusAsync);this._defaultFocusAsync=null}},1)},_affectScroll:function(dx){this.$.tabsContainer.scrollLeft+=dx;var scrollLeft=this.$.tabsContainer.scrollLeft;this._leftHidden=scrollLeft===0;this._rightHidden=scrollLeft===this._tabContainerScrollSize},_onLeftScrollButtonDown:function(){this._scrollToLeft();this._holdJob=setInterval(this._scrollToLeft.bind(this),this._holdDelay)},_onRightScrollButtonDown:function(){this._scrollToRight();this._holdJob=setInterval(this._scrollToRight.bind(this),this._holdDelay)},_onScrollButtonUp:function(){clearInterval(this._holdJob);this._holdJob=null},_scrollToLeft:function(){this._affectScroll(-this._step)},_scrollToRight:function(){this._affectScroll(this._step)},_tabChanged:function(tab,old){if(!tab){this.$.selectionBar.classList.remove("expand");this.$.selectionBar.classList.remove("contract");this._positionBar(0,0);return}var r=this.$.tabsContent.getBoundingClientRect();var w=r.width;var tabRect=tab.getBoundingClientRect();var tabOffsetLeft=tabRect.left-r.left;this._pos={width:this._calcPercent(tabRect.width,w),left:this._calcPercent(tabOffsetLeft,w)};if(this.noSlide||old==null){this.$.selectionBar.classList.remove("expand");this.$.selectionBar.classList.remove("contract");this._positionBar(this._pos.width,this._pos.left);return}var oldRect=old.getBoundingClientRect();var oldIndex=this.items.indexOf(old);var index=this.items.indexOf(tab);var m=5;this.$.selectionBar.classList.add("expand");var moveRight=oldIndex<index;var isRTL=this._isRTL;if(isRTL){moveRight=!moveRight}if(moveRight){this._positionBar(this._calcPercent(tabRect.left+tabRect.width-oldRect.left,w)-m,this._left)}else{this._positionBar(this._calcPercent(oldRect.left+oldRect.width-tabRect.left,w)-m,this._calcPercent(tabOffsetLeft,w)+m)}if(this.scrollable){this._scrollToSelectedIfNeeded(tabRect.width,tabOffsetLeft)}},_scrollToSelectedIfNeeded:function(tabWidth,tabOffsetLeft){var l=tabOffsetLeft-this.$.tabsContainer.scrollLeft;if(l<0){this.$.tabsContainer.scrollLeft+=l}else{l+=tabWidth-this.$.tabsContainer.offsetWidth;if(l>0){this.$.tabsContainer.scrollLeft+=l}}},_calcPercent:function(w,w0){return 100*w/w0},_positionBar:function(width,left){width=width||0;left=left||0;this._width=width;this._left=left;this.transform("translateX("+left+"%) scaleX("+width/100+")",this.$.selectionBar)},_onBarTransitionEnd:function(e){var cl=this.$.selectionBar.classList;if(cl.contains("expand")){cl.remove("expand");cl.add("contract");this._positionBar(this._pos.width,this._pos.left)}else if(cl.contains("contract")){cl.remove("contract")}}});
\ No newline at end of file
diff --git a/chrome/browser/resources/md_history/lazy_load.vulcanized.html b/chrome/browser/resources/md_history/lazy_load.vulcanized.html
index b36ec21..9478fc3 100644
--- a/chrome/browser/resources/md_history/lazy_load.vulcanized.html
+++ b/chrome/browser/resources/md_history/lazy_load.vulcanized.html
@@ -520,21 +520,38 @@
   </template>
 
   </dom-module>
+<dom-module id="paper-listbox" assetpath="chrome://resources/polymer/v1_0/paper-listbox/" css-build="shadow">
+  <template>
+    <style scope="paper-listbox">:host {
+  display: block;
+        padding: 8px 0;
+
+        background: var(--paper-listbox-background-color,var(--primary-background-color));;
+        color: var(--paper-listbox-color,var(--primary-text-color));;
+
+        ;
+}
+
+</style>
+
+    <content></content>
+  </template>
+
+  </dom-module>
 <dom-module id="cr-shared-menu" assetpath="chrome://resources/cr_elements/cr_shared_menu/" css-build="shadow">
   <template>
-    <style scope="cr-shared-menu">#menu {
+    <style scope="cr-shared-menu">paper-listbox {
   box-shadow: var(--shadow-elevation-2dp_-_box-shadow);
-        background-color: white;
         overflow: hidden;
-        padding: 8px 0;
         position: relative;
+        width: var(--cr-shared-menu-width);
 }
 
 </style>
     <iron-dropdown id="dropdown" allow-outside-scroll="" restore-focus-on-close="" vertical-align="auto" horizontal-align="right" opened="{{menuOpen}}" open-animation-config="[[openAnimationConfig]]" close-animation-config="[[closeAnimationConfig]]">
-      <div id="menu" class="dropdown-content" role="menu">
+      <paper-listbox id="menu" class="dropdown-content">
         <content></content>
-      </div>
+      </paper-listbox>
     </iron-dropdown>
   </template>
   </dom-module>
@@ -898,6 +915,12 @@
   cursor: var(--cr-actionable_-_cursor);
 }
 
+.scroll-container {
+  display: flex;
+        flex-direction: column;
+        min-height: 1px;
+}
+
 [selectable]:focus, [selectable] > :focus {
   background-color: var(--cr-selectable-focus_-_background-color); outline: var(--cr-selectable-focus_-_outline);
 }
diff --git a/chrome/browser/resources/md_history/list_container.js b/chrome/browser/resources/md_history/list_container.js
index 72aaa61d..5028965 100644
--- a/chrome/browser/resources/md_history/list_container.js
+++ b/chrome/browser/resources/md_history/list_container.js
@@ -238,11 +238,13 @@
     var itemData = menu.itemData;
     browserService.deleteItems([itemData.item])
         .then(function(items) {
-          this.getSelectedList_().removeItemsByPath([itemData.path]);
-          // This unselect-all is to reset the toolbar when deleting a selected
-          // item. TODO(tsergeant): Make this automatic based on observing list
+          // This unselect-all resets the toolbar when deleting a selected item
+          // and clears selection state which can be invalid if items move
+          // around during deletion.
+          // TODO(tsergeant): Make this automatic based on observing list
           // modifications.
           this.fire('unselect-all');
+          this.getSelectedList_().removeItemsByPath([itemData.path]);
 
           var index = itemData.index;
           if (index == undefined)
diff --git a/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.html b/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.html
index de948ff6a..6234156c 100644
--- a/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.html
+++ b/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.html
@@ -57,7 +57,8 @@
     </media-router-header>
     <div id="content">
       <template is="dom-if" if="[[!computeCastModeListHidden_(currentView_)]]">
-        <paper-menu id="cast-mode-list" role="presentation">
+        <paper-menu id="cast-mode-list" role="presentation"
+            selectable="paper-item">
           <template is="dom-repeat" id="defaultCastModeList"
               items="[[computeDefaultCastModeList_(castModeList)]]">
             <paper-item on-tap="onCastModeClick_">
diff --git a/chrome/browser/resources/settings/a11y_page/manage_a11y_page.html b/chrome/browser/resources/settings/a11y_page/manage_a11y_page.html
index c55a60d..a3d94c88 100644
--- a/chrome/browser/resources/settings/a11y_page/manage_a11y_page.html
+++ b/chrome/browser/resources/settings/a11y_page/manage_a11y_page.html
@@ -16,11 +16,6 @@
         border-top: none;
       }
 
-      h3 {
-        color: var(--settings-nav-grey);
-        font-weight: 500;
-      }
-
       .settings-box iron-icon {
         -webkit-margin-end: var(--iron-icon-spacing);
       }
@@ -28,6 +23,10 @@
       .settings-box settings-checkbox {
         flex-grow: 1;
       }
+
+      .list-item settings-dropdown-menu {
+        -webkit-margin-start: 16px;
+      }
     </style>
     <div class="settings-box row first">
       <span>
@@ -39,7 +38,7 @@
     </div>
 
     <div class="settings-box block">
-      <h3>$i18n{textToSpeechHeading}</h3>
+      <h2>$i18n{textToSpeechHeading}</h2>
       <div class="settings-box first indented">
         <settings-checkbox pref="{{prefs.settings.accessibility}}"
             label="$i18n{chromeVoxLabel}">
@@ -56,7 +55,7 @@
         </div>
       </template>
 
-      <h3>$i18n{displayHeading}</h3>
+      <h2>$i18n{displayHeading}</h2>
       <div class="settings-box block first indented">
         <settings-checkbox label="$i18n{highContrastLabel}"
             pref="{{prefs.settings.a11y.high_contrast_enabled}}">
@@ -82,7 +81,7 @@
         </div>
       </div>
 
-      <h3>$i18n{keyboardHeading}</h3>
+      <h2>$i18n{keyboardHeading}</h2>
       <div class="settings-box block first indented">
         <settings-checkbox
             pref="{{prefs.settings.a11y.sticky_keys_enabled}}"
@@ -112,7 +111,7 @@
         </div>
       </div>
 
-      <h3>$i18n{mouseAndTouchpadHeading}</h3>
+      <h2>$i18n{mouseAndTouchpadHeading}</h2>
       <div class="settings-box block first indented">
         <settings-checkbox label="$i18n{clickOnStopLabel}"
             pref="{{prefs.settings.a11y.autoclick}}">
@@ -143,7 +142,7 @@
         </div>
       </div>
 
-      <h3>$i18n{audioHeading}</h3>
+      <h2>$i18n{audioHeading}</h2>
       <div class="settings-box block first indented">
         <settings-checkbox pref="{{prefs.settings.a11y.mono_audio}}"
             label="$i18n{monoAudioLabel}">
diff --git a/chrome/browser/resources/settings/compiled_resources2.gyp b/chrome/browser/resources/settings/compiled_resources2.gyp
index 3626edf..09caa83 100644
--- a/chrome/browser/resources/settings/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/compiled_resources2.gyp
@@ -72,15 +72,5 @@
       ],
       'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
-    {
-      'target_name': 'settings',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-        'direction_delegate',
-        'route',
-      ],
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
   ],
 }
diff --git a/chrome/browser/resources/settings/device_page/display_overscan_dialog.js b/chrome/browser/resources/settings/device_page/display_overscan_dialog.js
index 4cb019fc..109301b 100644
--- a/chrome/browser/resources/settings/device_page/display_overscan_dialog.js
+++ b/chrome/browser/resources/settings/device_page/display_overscan_dialog.js
@@ -30,23 +30,16 @@
    */
   keyHandler_: null,
 
-  /** @override */
-  attached: function() {
-    this.keyHandler_ = this.handleKeyEvent_.bind(this);
-    window.addEventListener('keydown', this.keyHandler_);
-  },
-
-  /** @override */
-  detached: function() {
-    window.removeEventListener('keydown', this.keyHandler_);
-  },
-
   open: function() {
+    this.keyHandler_ = this.handleKeyEvent_.bind(this);
+    this.addEventListener('keydown', this.keyHandler_);
     this.comitted_ = false;
     this.$.dialog.showModal();
   },
 
   close: function() {
+    this.removeEventListener('keydown', this.keyHandler_);
+
     this.displayId = '';  // Will trigger displayIdChanged_.
 
     if (this.$.dialog.open)
@@ -83,6 +76,8 @@
    * @private
    */
   handleKeyEvent_: function(event) {
+    if (event.altKey || event.ctrlKey || event.metaKey)
+      return;
     switch (event.keyCode) {
       case 37:  // left arrow
         if (event.shiftKey)
@@ -109,6 +104,7 @@
           this.resize_(0, 1);
         break;
       default:
+        // Allow unhandled key events to propagate.
         return;
     }
     event.preventDefault();
diff --git a/chrome/browser/resources/settings/languages_page/add_languages_dialog.js b/chrome/browser/resources/settings/languages_page/add_languages_dialog.js
index 14674400..43457ca 100644
--- a/chrome/browser/resources/settings/languages_page/add_languages_dialog.js
+++ b/chrome/browser/resources/settings/languages_page/add_languages_dialog.js
@@ -34,6 +34,10 @@
 
   attached: function() {
     this.$.dialog.showModal();
+    // Fire iron-resize after the list initially displays to prevent flickering.
+    setTimeout(function() {
+      this.$$('iron-list').fire('iron-resize');
+    }.bind(this));
   },
 
   /**
diff --git a/chrome/browser/resources/settings/languages_page/languages.js b/chrome/browser/resources/settings/languages_page/languages.js
index ff56be8f..ee4c8166 100644
--- a/chrome/browser/resources/settings/languages_page/languages.js
+++ b/chrome/browser/resources/settings/languages_page/languages.js
@@ -576,6 +576,25 @@
   },
 
   /**
+   * Moves the language directly to the front of the list of enabled languages.
+   * @param {string} languageCode
+   */
+  moveLanguageToFront: function(languageCode) {
+    if (!CrSettingsPrefs.isInitialized)
+      return;
+
+    var languageCodes =
+        this.getPref(preferredLanguagesPrefName).value.split(',');
+    var originalIndex = languageCodes.indexOf(languageCode);
+    assert(originalIndex != -1);
+
+    languageCodes.splice(originalIndex, 1);
+    languageCodes.unshift(languageCode);
+
+    this.setPrefValue(preferredLanguagesPrefName, languageCodes.join(','));
+  },
+
+  /**
    * Enables translate for the given language by removing the translate
    * language from the blocked languages preference.
    * @param {string} languageCode
diff --git a/chrome/browser/resources/settings/languages_page/languages_page.html b/chrome/browser/resources/settings/languages_page/languages_page.html
index e07cdcb6..27b4bc4 100644
--- a/chrome/browser/resources/settings/languages_page/languages_page.html
+++ b/chrome/browser/resources/settings/languages_page/languages_page.html
@@ -6,7 +6,6 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-checkbox/paper-checkbox.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-toggle-button/paper-toggle-button.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_expand_button/cr_expand_button.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_shared_menu/cr_shared_menu.html">
@@ -42,10 +41,29 @@
         margin-top: 4px;
       }
 
+      cr-shared-menu {
+        --cr-shared-menu-width: 320px;
+      }
+
+      cr-shared-menu.complex .dropdown-item {
+        min-height: 36px;
+      }
+
+      cr-shared-menu:not(.complex) hr {
+        display: none;
+      }
+
+      cr-shared-menu.complex hr {
+        /* Override user-agent border and margin. */
+        border: none;
+        /* TODO(michaelpg): Update to whatever variable is used for the darker,
+         * full-width separators: crbug.com/649547. */
+        border-top: var(--settings-separator-line);
+        margin: 6px 0 0 0;
+      }
+
       paper-checkbox.dropdown-item {
         --checkbox-margin-start: 0;
-        /* Allow for the ripple height. */
-        min-height: var(--paper-checkbox-ink-size);
       }
     </style>
     <settings-languages languages="{{languages}}" prefs="{{prefs}}"
@@ -129,12 +147,13 @@
               <div class$="list-item [[getInputMethodItemClass_(
                       item.id, languages.inputMethods.currentId)]]"
                   on-tap="onInputMethodTap_" actionable>
-                <div>[[item.displayName]]</div>
-                <div class="middle">
-                  <iron-icon icon="settings:done"
+                <div class="start">
+                  <div>[[item.displayName]]</div>
+                  <div class="explain-selected"
                       hidden="[[!isCurrentInputMethod_(
                           item.id, languages.inputMethods.currentId)]]">
-                  </iron-icon>
+                    $i18n{inputMethodEnabled}
+                  </div>
                 </div>
                 <paper-icon-button icon="cr:settings"
                     on-tap="onInputMethodOptionsTap_"
@@ -165,19 +184,12 @@
           <div class="list-frame vertical-list">
             <template is="dom-repeat" items="[[languages.enabled]]">
               <div class="list-item">
-                <label class="start"
-                    id="supportsSpellCheckLabel-[[item.language.code]]">
-                  <span disabled$="[[!item.language.supportsSpellcheck]]">
-                    [[item.language.displayName]]
-                  </span>
-                </label>
-                <paper-toggle-button
+                <paper-checkbox
                     checked="[[item.spellCheckEnabled]]"
                     on-change="onSpellCheckChange_"
-                    disabled$="[[!item.language.supportsSpellcheck]]"
-                    aria-labelledby=
-                        "supportsSpellCheckLabel-[[item.language.code]]">
-                </paper-toggle-button>
+                    disabled$="[[!item.language.supportsSpellcheck]]">
+                  [[item.language.displayName]]
+                </paper-checkbox>
               </label>
             </template>
             <div class="list-item list-button" on-tap="onEditDictionaryTap_">
@@ -187,7 +199,8 @@
         </iron-collapse>
 </if>
         <template is="cr-lazy-render" id="menu">
-          <cr-shared-menu>
+          <cr-shared-menu
+              class$="[[getMenuClass_(prefs.translate.enabled.value)]]">
 <if expr="chromeos or is_win">
             <paper-checkbox id="uiLanguageItem" class="dropdown-item"
                 checked="[[isProspectiveUILanguage_(
@@ -207,9 +220,16 @@
                     detailLanguage_.language, languages.translateTarget)]]">
               $i18n{offerToTranslateInThisLanguage}
             </paper-checkbox>
+            <hr>
+            <button class="dropdown-item" role="menuitem"
+                on-tap="onMoveToTopTap_"
+                hidden="[[isFirstLanguage_(
+                    detailLanguage_, languages.enabled.*)]]">
+              $i18n{moveToTop}
+            </button>
             <button class="dropdown-item" role="menuitem"
                 on-tap="onMoveUpTap_"
-                hidden="[[isFirstLanguage_(
+                hidden="[[isFirstOrSecondLanguage_(
                     detailLanguage_, languages.enabled.*)]]">
               $i18n{moveUp}
             </button>
diff --git a/chrome/browser/resources/settings/languages_page/languages_page.js b/chrome/browser/resources/settings/languages_page/languages_page.js
index 93817af..19a0538 100644
--- a/chrome/browser/resources/settings/languages_page/languages_page.js
+++ b/chrome/browser/resources/settings/languages_page/languages_page.js
@@ -108,6 +108,16 @@
 
   /**
    * @param {!LanguageState} language
+   * @return {boolean} True if |language| is first or second in the list of
+   *     enabled languages. Used to hide the "Move to top" option.
+   * @private
+   */
+  isFirstOrSecondLanguage_: function(language) {
+    return this.languages.enabled.slice(0, 2).includes(language);
+  },
+
+  /**
+   * @param {!LanguageState} language
    * @return {boolean} True if |language| is last in the list of enabled
    *     languages. Used to hide the "Move down" option.
    * @private
@@ -175,6 +185,7 @@
       // Reset the chosen UI language to the actual UI language.
       this.languageHelper.resetUILanguage();
     }
+    /** @type {!CrSharedMenuElement} */(this.$.menu.get()).closeMenu();
   },
 
    /**
@@ -204,6 +215,28 @@
       this.languageHelper.disableTranslateLanguage(
           this.detailLanguage_.language.code);
     }
+    /** @type {!CrSharedMenuElement} */(this.$.menu.get()).closeMenu();
+  },
+
+  /**
+   * Returns "complex" if the menu includes checkboxes, which should change the
+   * spacing of items and show a separator in the menu.
+   * @param {boolean} translateEnabled
+   * @return {string}
+   */
+  getMenuClass_: function(translateEnabled) {
+    if (translateEnabled || cr.isChromeOS || cr.isWindows)
+      return 'complex';
+    return '';
+  },
+
+  /**
+   * Moves the language to the top of the list.
+   * @private
+   */
+  onMoveToTopTap_: function() {
+    /** @type {!CrSharedMenuElement} */(this.$.menu.get()).closeMenu();
+    this.languageHelper.moveLanguageToFront(this.detailLanguage_.language.code);
   },
 
   /**
diff --git a/chrome/browser/resources/settings/languages_page/languages_types.js b/chrome/browser/resources/settings/languages_page/languages_types.js
index 417ad28..4ee060f 100644
--- a/chrome/browser/resources/settings/languages_page/languages_types.js
+++ b/chrome/browser/resources/settings/languages_page/languages_types.js
@@ -109,6 +109,12 @@
   moveLanguage: assertNotReached,
 
   /**
+   * Moves the language directly to the front of the list of enabled languages.
+   * @param {string} languageCode
+   */
+  moveLanguageToFront: assertNotReached,
+
+  /**
    * Enables translate for the given language by removing the translate
    * language from the blocked languages preference.
    * @param {string} languageCode
diff --git a/chrome/browser/resources/settings/settings.html b/chrome/browser/resources/settings/settings.html
index 86370a0..6efcfe3 100644
--- a/chrome/browser/resources/settings/settings.html
+++ b/chrome/browser/resources/settings/settings.html
@@ -4,30 +4,11 @@
   <meta charset="utf-8">
   <title>$i18n{settings}</title>
   <link rel="import" href="chrome://resources/html/polymer.html">
-  <link rel="import" href="/i18n_setup.html">
-  <link rel="import" href="/direction_delegate.html">
   <link rel="import" href="/settings_ui/settings_ui.html">
-  <link rel="import" href="/prefs/prefs.html">
-  <link rel="import" href="/route.html">
-  <link rel="import" href="/settings_vars_css.html">
   <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
 </head>
 <body>
-
-  <dom-module id="cr-settings">
-    <template>
-      <style>
-        :host {
-          color: var(--paper-grey-800);
-        }
-      </style>
-      <settings-prefs id="prefs" prefs="{{prefs_}}"></settings-prefs>
-      <settings-ui id="ui" prefs="{{prefs_}}"></settings-ui>
-    </template>
-    <script src="/settings.js"></script>
-  </dom-module>
-
-  <cr-settings></cr-settings>
+  <settings-ui></settings-ui>
   <link rel="import" href="chrome://resources/html/i18n_template.html">
 </body>
 </html>
diff --git a/chrome/browser/resources/settings/settings.js b/chrome/browser/resources/settings/settings.js
deleted file mode 100644
index bb59abb..0000000
--- a/chrome/browser/resources/settings/settings.js
+++ /dev/null
@@ -1,31 +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.
-
-cr.exportPath('settings');
-assert(!settings.defaultResourceLoaded,
-       'settings.js run twice. You probably have an invalid import.');
-/** Global defined when the main Settings script runs. */
-settings.defaultResourceLoaded = true;
-
-/**
- * @fileoverview
- * 'cr-settings' is the main MD-Settings element, combining the UI and models.
- *
- * Example:
- *
- *    <cr-settings></cr-settings>
- */
-Polymer({
-  is: 'cr-settings',
-
-  /** @override */
-  created: function() {
-    settings.initializeRouteFromUrl();
-  },
-
-  /** @override */
-  ready: function() {
-    this.$.ui.directionDelegate = new settings.DirectionDelegateImpl;
-  },
-});
diff --git a/chrome/browser/resources/settings/settings_page/settings_subpage.html b/chrome/browser/resources/settings/settings_page/settings_subpage.html
index d55220b..0a4c36f 100644
--- a/chrome/browser/resources/settings/settings_page/settings_subpage.html
+++ b/chrome/browser/resources/settings/settings_page/settings_subpage.html
@@ -22,10 +22,11 @@
       }
 
       paper-icon-button {
+        /* Centers the ripple on the icon with appropriate margin on right. */
+        -webkit-margin-end: 8px;
+        -webkit-margin-start: -8px;
         /* The inner icon is 20px in size. paper-icon-button has 8px padding. */
         height: 36px;
-        /* Centers the ripple on the icon with appropriate margin on right. */
-        margin: 0 8px 0 -8px;
         width: 36px;
       }
 
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd
index 0371670..cfd1d04 100644
--- a/chrome/browser/resources/settings/settings_resources.grd
+++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -882,9 +882,6 @@
       <structure name="IDR_SETTINGS_SETTINGS_HTML"
                  file="settings.html"
                  type="chrome_html" />
-      <structure name="IDR_SETTINGS_SETTINGS_JS"
-                 file="settings.js"
-                 type="chrome_html" />
       <structure name="IDR_SETTINGS_USB_DEVICES_HTML"
                  file="site_settings/usb_devices.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 a3974fb0..35039d9 100644
--- a/chrome/browser/resources/settings/settings_shared_css.html
+++ b/chrome/browser/resources/settings/settings_shared_css.html
@@ -102,7 +102,8 @@
       [is='action-link']:hover,
       [is='action-link']:visited,
       .primary-button,
-      .tertiary-button {
+      .tertiary-button,
+      a[href] {
         color: var(--google-blue-700);
       }
 
@@ -113,6 +114,7 @@
         };
       }
 
+      a[href],
       [is='action-link']:hover {
         text-decoration: none;
       }
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.html b/chrome/browser/resources/settings/settings_ui/settings_ui.html
index 4153d77..baafd39c 100644
--- a/chrome/browser/resources/settings/settings_ui/settings_ui.html
+++ b/chrome/browser/resources/settings/settings_ui/settings_ui.html
@@ -10,6 +10,9 @@
 <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="/prefs/prefs.html">
+<link rel="import" href="/route.html">
+<link rel="import" href="/settings_vars_css.html">
 
 <dom-module id="settings-ui">
   <template>
@@ -21,6 +24,7 @@
         };
         -webkit-user-select: none;
         background-color: var(--settings-background-color);
+        color: var(--paper-grey-800);
         display: flex;
         flex-direction: column;
         overflow: hidden;  /* Prevent double scroll bar bugs. */
@@ -78,6 +82,7 @@
         overflow: auto;
       }
     </style>
+    <settings-prefs id="prefs" prefs="{{prefs}}"></settings-prefs>
     <cr-toolbar page-name="$i18n{settings}" clear-label="$i18n{clearSearch}"
         search-prompt="$i18n{searchPrompt}" on-cr-menu-tap="onMenuButtonTap_"
         spinner-active="[[toolbarSpinnerActive_]]" show-menu
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.js b/chrome/browser/resources/settings/settings_ui/settings_ui.js
index 910bddc..52307933 100644
--- a/chrome/browser/resources/settings/settings_ui/settings_ui.js
+++ b/chrome/browser/resources/settings/settings_ui/settings_ui.js
@@ -10,6 +10,12 @@
  *
  *    <settings-ui prefs="{{prefs}}"></settings-ui>
  */
+cr.exportPath('settings');
+assert(!settings.defaultResourceLoaded,
+       'settings_ui.js run twice. You probably have an invalid import.');
+/** Global defined when the main Settings script runs. */
+settings.defaultResourceLoaded = true;
+
 Polymer({
   is: 'settings-ui',
 
@@ -23,6 +29,7 @@
     directionDelegate: {
       observer: 'directionDelegateChanged_',
       type: Object,
+      value: new settings.DirectionDelegateImpl(),
     },
 
     /** @private {boolean} */
@@ -38,6 +45,11 @@
     pageVisibility_: Object,
   },
 
+  /** @override */
+  created: function() {
+    settings.initializeRouteFromUrl();
+  },
+
   /**
    * @override
    * @suppress {es5Strict} Object literals cannot contain duplicate keys in ES5
diff --git a/chrome/browser/resources/settings/site_settings/site_list.html b/chrome/browser/resources/settings/site_settings/site_list.html
index 0ce69c7c..40c7829 100644
--- a/chrome/browser/resources/settings/site_settings/site_list.html
+++ b/chrome/browser/resources/settings/site_settings/site_list.html
@@ -59,7 +59,7 @@
               <iron-icon icon="[[computeIconControlledBy_(item)]]"></iron-icon>
             </template>
 
-            <paper-menu-button hidden="[[isExceptionControlled_(item.source)]]"
+            <paper-menu-button hidden="[[!shouldShowMenu_(item.source)]]"
                 horizontal-align="right">
               <paper-icon-button icon="cr:more-vert" class="dropdown-trigger">
               </paper-icon-button>
diff --git a/chrome/browser/resources/settings/site_settings/site_list.js b/chrome/browser/resources/settings/site_settings/site_list.js
index b38743e..4c4b38f 100644
--- a/chrome/browser/resources/settings/site_settings/site_list.js
+++ b/chrome/browser/resources/settings/site_settings/site_list.js
@@ -130,7 +130,7 @@
    * @private
    */
   siteWithinCategoryChanged_: function(category, site) {
-    if (category == this.category || this.category == settings.ALL_SITES)
+    if (category == this.category || this.allSites)
       this.configureWidget_();
   },
 
@@ -205,6 +205,8 @@
    * @return {string} The icon to show (or blank, if none).
    */
   computeIconControlledBy_: function(item) {
+    if (this.allSites)
+      return '';
     return iconControlledBy[item.source] || '';
   },
 
@@ -320,7 +322,7 @@
    */
   appendSiteList_: function(sites, exceptionList) {
     for (var i = 0; i < exceptionList.length; ++i) {
-      if (this.category != settings.ALL_SITES) {
+      if (!this.allSites) {
         if (exceptionList[i].setting == settings.PermissionValues.DEFAULT)
           continue;
 
diff --git a/chrome/browser/resources/settings/site_settings/site_settings_behavior.js b/chrome/browser/resources/settings/site_settings/site_settings_behavior.js
index f1a9dcb..3e77511 100644
--- a/chrome/browser/resources/settings/site_settings/site_settings_behavior.js
+++ b/chrome/browser/resources/settings/site_settings/site_settings_behavior.js
@@ -381,6 +381,8 @@
       return pattern.replace('http://', 'http://[*.]');
     else if (pattern.startsWith('https://'))
       return pattern.replace('https://', 'https://[*.]');
+    else if (pattern.startsWith('chrome-extension://'))
+      return pattern;  // No need for a wildcard for this.
     else
       return '[*.]' + pattern;
   },
@@ -481,7 +483,8 @@
    */
   expandSiteException: function(exception) {
     var origin = exception.origin;
-    var originForDisplay = this.sanitizePort(this.toUrl(origin).origin);
+    var url = this.toUrl(origin);
+    var originForDisplay = url ? this.sanitizePort(url.origin) : origin;
 
     var embeddingOrigin = exception.embeddingOrigin;
     var embeddingOriginForDisplay = '';
diff --git a/chrome/browser/resources/snippets_internals.html b/chrome/browser/resources/snippets_internals.html
index f8251e9..eab56bb3 100644
--- a/chrome/browser/resources/snippets_internals.html
+++ b/chrome/browser/resources/snippets_internals.html
@@ -137,7 +137,7 @@
               <table>
                 <tr>
                   <td>ID
-                  <td jscontent="suggestionId">
+                  <td jscontent="idWithinCategory">
                 <tr>
                   <td>URL
                   <td><a class="url" jsvalues="href:url" jscontent="url"></a>
diff --git a/chrome/browser/resources/vulcanize.py b/chrome/browser/resources/vulcanize.py
index 66f7fa4..3752c965 100755
--- a/chrome/browser/resources/vulcanize.py
+++ b/chrome/browser/resources/vulcanize.py
@@ -88,7 +88,6 @@
     # TODO(tsergeant): Remove when JS resources are minified by default:
     # crbug.com/619091.
     _run_cmd(['uglifyjs', js_out_path,
-                         '--beautify', 'indent-level=2,quote_style=3',
                          '--comments', '/Copyright|license|LICENSE|\<\/?if/',
                          '--output', js_out_path])
   finally:
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
index e944af9..9c78afa9 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
@@ -131,57 +131,23 @@
     WebContents* web_contents,
     const GURL& main_frame_url,
     const UnsafeResourceList& unsafe_resources)
-    : SecurityInterstitialPage(web_contents, unsafe_resources[0].url),
+    : SecurityInterstitialPage(
+          web_contents,
+          unsafe_resources[0].url,
+          CreateMetricsHelper(web_contents, unsafe_resources)),
       threat_details_proceed_delay_ms_(kThreatDetailsProceedDelayMilliSeconds),
       ui_manager_(ui_manager),
       is_main_frame_load_blocked_(IsMainPageLoadBlocked(unsafe_resources)),
       main_frame_url_(main_frame_url),
       unsafe_resources_(unsafe_resources),
-      proceeded_(false) {
-  bool malware = false;
-  bool harmful = false;
-  bool phishing = false;
-  for (UnsafeResourceList::const_iterator iter = unsafe_resources_.begin();
-       iter != unsafe_resources_.end(); ++iter) {
-    const UnsafeResource& resource = *iter;
-    SBThreatType threat_type = resource.threat_type;
-    if (threat_type == SB_THREAT_TYPE_URL_MALWARE ||
-        threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL) {
-      malware = true;
-    } else if (threat_type == SB_THREAT_TYPE_URL_UNWANTED) {
-      harmful = true;
-    } else {
-      DCHECK(threat_type == SB_THREAT_TYPE_URL_PHISHING ||
-             threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL);
-      phishing = true;
-    }
-  }
-  DCHECK(phishing || malware || harmful);
-  if (malware)
-    interstitial_reason_ = SB_REASON_MALWARE;
-  else if (harmful)
-    interstitial_reason_ = SB_REASON_HARMFUL;
-  else
-    interstitial_reason_ = SB_REASON_PHISHING;
-
-  // This must be done after calculating |interstitial_reason_| above.
-  security_interstitials::MetricsHelper::ReportDetails reporting_info;
-  reporting_info.metric_prefix = GetMetricPrefix();
-  reporting_info.extra_suffix = GetExtraMetricsSuffix();
-  reporting_info.rappor_prefix = GetRapporPrefix();
-  reporting_info.deprecated_rappor_prefix = GetDeprecatedRapporPrefix();
-  reporting_info.rappor_report_type =
-      rappor::LOW_FREQUENCY_SAFEBROWSING_RAPPOR_TYPE;
-  reporting_info.deprecated_rappor_report_type =
-      rappor::SAFEBROWSING_RAPPOR_TYPE;
-  set_metrics_helper(base::MakeUnique<ChromeMetricsHelper>(
-      web_contents, request_url(), reporting_info, GetSamplingEventName()));
-  metrics_helper()->RecordUserDecision(
+      proceeded_(false),
+      interstitial_reason_(GetInterstitialReason(unsafe_resources)) {
+  controller()->metrics_helper()->RecordUserDecision(
       security_interstitials::MetricsHelper::SHOW);
-  metrics_helper()->RecordUserInteraction(
+  controller()->metrics_helper()->RecordUserInteraction(
       security_interstitials::MetricsHelper::TOTAL_VISITS);
   if (IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled)) {
-    metrics_helper()->RecordUserDecision(
+    controller()->metrics_helper()->RecordUserDecision(
         security_interstitials::MetricsHelper::PROCEEDING_DISABLED);
   }
 
@@ -355,7 +321,7 @@
   proceeded_ = true;
   // Send the threat details, if we opted to.
   FinishThreatDetails(threat_details_proceed_delay_ms_, true, /* did_proceed */
-                      metrics_helper()->NumVisits());
+                      controller()->metrics_helper()->NumVisits());
 
   ui_manager_->OnBlockingPageDone(unsafe_resources_, true);
 
@@ -398,13 +364,13 @@
     return;
 
   if (!IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled)) {
-    metrics_helper()->RecordUserDecision(
+    controller()->metrics_helper()->RecordUserDecision(
         security_interstitials::MetricsHelper::DONT_PROCEED);
   }
 
   // Send the malware details, if we opted to.
   FinishThreatDetails(0, false /* did_proceed */,
-                      metrics_helper()->NumVisits());  // No delay
+                      controller()->metrics_helper()->NumVisits());  // No delay
 
   ui_manager_->OnBlockingPageDone(unsafe_resources_, false);
 
@@ -445,7 +411,7 @@
   if (!enabled)
     return;
 
-  metrics_helper()->RecordUserInteraction(
+  controller()->metrics_helper()->RecordUserInteraction(
       security_interstitials::MetricsHelper::EXTENDED_REPORTING_IS_ENABLED);
   // Finish the malware details collection, send it over.
   BrowserThread::PostDelayedTask(
@@ -520,16 +486,19 @@
          unsafe_resources[0].IsMainPageLoadBlocked();
 }
 
-std::string SafeBrowsingBlockingPage::GetMetricPrefix() const {
-  bool primary_subresource = unsafe_resources_[0].is_subresource;
-  switch (interstitial_reason_) {
+// static
+std::string SafeBrowsingBlockingPage::GetMetricPrefix(
+    const UnsafeResourceList& unsafe_resources,
+    SBInterstitialReason interstitial_reason) {
+  bool primary_subresource = unsafe_resources[0].is_subresource;
+  switch (interstitial_reason) {
     case SB_REASON_MALWARE:
       return primary_subresource ? "malware_subresource" : "malware";
     case SB_REASON_HARMFUL:
       return primary_subresource ? "harmful_subresource" : "harmful";
     case SB_REASON_PHISHING:
       ThreatPatternType threat_pattern_type =
-          unsafe_resources_[0].threat_metadata.threat_pattern_type;
+          unsafe_resources[0].threat_metadata.threat_pattern_type;
       if (threat_pattern_type == ThreatPatternType::PHISHING ||
           threat_pattern_type == ThreatPatternType::NONE)
         return primary_subresource ? "phishing_subresource" : "phishing";
@@ -546,8 +515,10 @@
 }
 
 // We populate a parallel set of metrics to differentiate some threat sources.
-std::string SafeBrowsingBlockingPage::GetExtraMetricsSuffix() const {
-  switch (unsafe_resources_[0].threat_source) {
+// static
+std::string SafeBrowsingBlockingPage::GetExtraMetricsSuffix(
+    const UnsafeResourceList& unsafe_resources) {
+  switch (unsafe_resources[0].threat_source) {
     case safe_browsing::ThreatSource::DATA_SAVER:
       return "from_data_saver";
     case safe_browsing::ThreatSource::REMOTE:
@@ -566,8 +537,10 @@
   return std::string();
 }
 
-std::string SafeBrowsingBlockingPage::GetRapporPrefix() const {
-  switch (interstitial_reason_) {
+// static
+std::string SafeBrowsingBlockingPage::GetRapporPrefix(
+    SBInterstitialReason interstitial_reason) {
+  switch (interstitial_reason) {
     case SB_REASON_MALWARE:
       return "malware2";
     case SB_REASON_HARMFUL:
@@ -579,8 +552,10 @@
   return std::string();
 }
 
-std::string SafeBrowsingBlockingPage::GetDeprecatedRapporPrefix() const {
-  switch (interstitial_reason_) {
+// static
+std::string SafeBrowsingBlockingPage::GetDeprecatedRapporPrefix(
+    SBInterstitialReason interstitial_reason) {
+  switch (interstitial_reason) {
     case SB_REASON_MALWARE:
       return "malware";
     case SB_REASON_HARMFUL:
@@ -592,8 +567,10 @@
   return std::string();
 }
 
-std::string SafeBrowsingBlockingPage::GetSamplingEventName() const {
-  switch (interstitial_reason_) {
+// static
+std::string SafeBrowsingBlockingPage::GetSamplingEventName(
+    SBInterstitialReason interstitial_reason) {
+  switch (interstitial_reason) {
     case SB_REASON_MALWARE:
       return kEventNameMalware;
     case SB_REASON_HARMFUL:
@@ -605,6 +582,60 @@
   }
 }
 
+// static
+SafeBrowsingBlockingPage::SBInterstitialReason
+SafeBrowsingBlockingPage::GetInterstitialReason(
+    const UnsafeResourceList& unsafe_resources) {
+  bool malware = false;
+  bool harmful = false;
+  bool phishing = false;
+  for (UnsafeResourceList::const_iterator iter = unsafe_resources.begin();
+       iter != unsafe_resources.end(); ++iter) {
+    const SafeBrowsingUIManager::UnsafeResource& resource = *iter;
+    safe_browsing::SBThreatType threat_type = resource.threat_type;
+    if (threat_type == SB_THREAT_TYPE_URL_MALWARE ||
+        threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL) {
+      malware = true;
+    } else if (threat_type == SB_THREAT_TYPE_URL_UNWANTED) {
+      harmful = true;
+    } else {
+      DCHECK(threat_type == SB_THREAT_TYPE_URL_PHISHING ||
+             threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL);
+      phishing = true;
+    }
+  }
+  DCHECK(phishing || malware || harmful);
+  if (malware)
+    return SB_REASON_MALWARE;
+  else if (harmful)
+    return SB_REASON_HARMFUL;
+  return SB_REASON_PHISHING;
+}
+
+// static
+std::unique_ptr<ChromeMetricsHelper>
+SafeBrowsingBlockingPage::CreateMetricsHelper(
+    WebContents* web_contents,
+    const UnsafeResourceList& unsafe_resources) {
+  SBInterstitialReason interstitial_reason =
+      GetInterstitialReason(unsafe_resources);
+  GURL request_url(unsafe_resources[0].url);
+  security_interstitials::MetricsHelper::ReportDetails reporting_info;
+  reporting_info.metric_prefix =
+      GetMetricPrefix(unsafe_resources, interstitial_reason);
+  reporting_info.extra_suffix = GetExtraMetricsSuffix(unsafe_resources);
+  reporting_info.rappor_prefix = GetRapporPrefix(interstitial_reason);
+  reporting_info.deprecated_rappor_prefix =
+      GetDeprecatedRapporPrefix(interstitial_reason);
+  reporting_info.rappor_report_type =
+      rappor::LOW_FREQUENCY_SAFEBROWSING_RAPPOR_TYPE;
+  reporting_info.deprecated_rappor_report_type =
+      rappor::SAFEBROWSING_RAPPOR_TYPE;
+  return std::unique_ptr<ChromeMetricsHelper>(
+      new ChromeMetricsHelper(web_contents, request_url, reporting_info,
+                              GetSamplingEventName(interstitial_reason)));
+}
+
 void SafeBrowsingBlockingPage::PopulateInterstitialStrings(
     base::DictionaryValue* load_time_data) {
   CHECK(load_time_data);
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.h b/chrome/browser/safe_browsing/safe_browsing_blocking_page.h
index 13779f1..0b2e2340 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.h
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.h
@@ -193,7 +193,8 @@
     SB_REASON_MALWARE,
     SB_REASON_HARMFUL,
     SB_REASON_PHISHING,
-  } interstitial_reason_;
+  };
+  SBInterstitialReason interstitial_reason_;
 
   // The factory used to instantiate SafeBrowsingBlockingPage objects.
   // Useful for tests, so they can provide their own implementation of
@@ -208,11 +209,22 @@
   void PopulateHarmfulLoadTimeData(base::DictionaryValue* load_time_data);
   void PopulatePhishingLoadTimeData(base::DictionaryValue* load_time_data);
 
-  std::string GetMetricPrefix() const;
-  std::string GetExtraMetricsSuffix() const;
-  std::string GetRapporPrefix() const;
-  std::string GetDeprecatedRapporPrefix() const;
-  std::string GetSamplingEventName() const;
+  static std::string GetMetricPrefix(const UnsafeResourceList& unsafe_resources,
+                                     SBInterstitialReason interstitial_reason);
+  static std::string GetExtraMetricsSuffix(
+      const UnsafeResourceList& unsafe_resources);
+  static std::string GetRapporPrefix(SBInterstitialReason interstitial_reason);
+  static std::string GetDeprecatedRapporPrefix(
+      SBInterstitialReason interstitial_reason);
+  static std::string GetSamplingEventName(
+      SBInterstitialReason interstitial_reason);
+
+  static SBInterstitialReason GetInterstitialReason(
+      const UnsafeResourceList& unsafe_resources);
+
+  static std::unique_ptr<ChromeMetricsHelper> CreateMetricsHelper(
+      content::WebContents* web_contents,
+      const UnsafeResourceList& unsafe_resources);
 
   DISALLOW_COPY_AND_ASSIGN(SafeBrowsingBlockingPage);
 };
diff --git a/chrome/browser/safe_browsing/srt_fetcher_win.cc b/chrome/browser/safe_browsing/srt_fetcher_win.cc
index cde5190..dc765da 100644
--- a/chrome/browser/safe_browsing/srt_fetcher_win.cc
+++ b/chrome/browser/safe_browsing/srt_fetcher_win.cc
@@ -145,6 +145,7 @@
 const wchar_t kFoundUwsValueName[] = L"FoundUws";
 const wchar_t kMemoryUsedValueName[] = L"MemoryUsed";
 const wchar_t kLogsUploadResultValueName[] = L"LogsUploadResult";
+const wchar_t kExitCodeValueName[] = L"ExitCode";
 
 const char kFoundUwsMetricName[] = "SoftwareReporter.FoundUwS";
 const char kFoundUwsReadErrorMetricName[] =
@@ -157,6 +158,7 @@
 const char kLogsUploadResultMetricName[] = "SoftwareReporter.LogsUploadResult";
 const char kLogsUploadResultRegistryErrorMetricName[] =
     "SoftwareReporter.LogsUploadResultRegistryError";
+const char kExitCodeMetricName[] = "SoftwareReporter.ExitCodeFromRegistry";
 
 // The max value for histogram SoftwareReporter.LogsUploadResult, which is used
 // to send UMA information about the result of Software Reporter's attempt to
@@ -208,6 +210,19 @@
 
   void ReportExitCode(int exit_code) const {
     RecordSparseHistogram("SoftwareReporter.ExitCode", exit_code);
+
+    // Also report the exit code that the reporter writes to the registry.
+    base::win::RegKey reporter_key;
+    DWORD exit_code_in_registry;
+    if (reporter_key.Open(HKEY_CURRENT_USER, registry_key_.c_str(),
+                          KEY_QUERY_VALUE | KEY_SET_VALUE) != ERROR_SUCCESS ||
+        reporter_key.ReadValueDW(kExitCodeValueName, &exit_code_in_registry) !=
+            ERROR_SUCCESS) {
+      return;
+    }
+
+    RecordSparseHistogram(kExitCodeMetricName, exit_code_in_registry);
+    reporter_key.DeleteValue(kExitCodeValueName);
   }
 
   // Reports UwS found by the software reporter tool via UMA and RAPPOR.
diff --git a/chrome/browser/ssl/bad_clock_blocking_page.cc b/chrome/browser/ssl/bad_clock_blocking_page.cc
index 028dc6e..1ee6156 100644
--- a/chrome/browser/ssl/bad_clock_blocking_page.cc
+++ b/chrome/browser/ssl/bad_clock_blocking_page.cc
@@ -35,6 +35,19 @@
 
 const char kMetricsName[] = "bad_clock";
 
+std::unique_ptr<ChromeMetricsHelper> CreateMetricsHelper(
+    content::WebContents* web_contents,
+    const GURL& request_url) {
+  // Set up the metrics helper for the BadClockUI.
+  security_interstitials::MetricsHelper::ReportDetails reporting_info;
+  reporting_info.metric_prefix = kMetricsName;
+  std::unique_ptr<ChromeMetricsHelper> metrics_helper =
+      base::MakeUnique<ChromeMetricsHelper>(web_contents, request_url,
+                                            reporting_info, kMetricsName);
+  metrics_helper.get()->StartRecordingCaptivePortalMetrics(false);
+  return metrics_helper;
+}
+
 }  // namespace
 
 // static
@@ -54,20 +67,12 @@
     ssl_errors::ClockState clock_state,
     std::unique_ptr<SSLCertReporter> ssl_cert_reporter,
     const base::Callback<void(content::CertificateRequestResultType)>& callback)
-    : SecurityInterstitialPage(web_contents, request_url),
+    : SecurityInterstitialPage(web_contents,
+                               request_url,
+                               CreateMetricsHelper(web_contents, request_url)),
       callback_(callback),
       ssl_info_(ssl_info),
       time_triggered_(time_triggered) {
-  // Set up the metrics helper for the BadClockUI.
-  security_interstitials::MetricsHelper::ReportDetails reporting_info;
-  reporting_info.metric_prefix = kMetricsName;
-  ChromeMetricsHelper* chrome_metrics_helper = new ChromeMetricsHelper(
-      web_contents, request_url, reporting_info, kMetricsName);
-  chrome_metrics_helper->StartRecordingCaptivePortalMetrics(false);
-  std::unique_ptr<security_interstitials::MetricsHelper> metrics_helper(
-      chrome_metrics_helper);
-  controller()->set_metrics_helper(std::move(metrics_helper));
-
   cert_report_helper_.reset(new CertReportHelper(
       std::move(ssl_cert_reporter), web_contents, request_url, ssl_info,
       certificate_reporting::ErrorReport::INTERSTITIAL_CLOCK,
diff --git a/chrome/browser/ssl/captive_portal_blocking_page.cc b/chrome/browser/ssl/captive_portal_blocking_page.cc
index e1e7a4f..828c160 100644
--- a/chrome/browser/ssl/captive_portal_blocking_page.cc
+++ b/chrome/browser/ssl/captive_portal_blocking_page.cc
@@ -21,6 +21,7 @@
 #include "components/certificate_reporting/error_reporter.h"
 #include "components/security_interstitials/core/common_string_util.h"
 #include "components/security_interstitials/core/controller_client.h"
+#include "components/security_interstitials/core/metrics_helper.h"
 #include "components/url_formatter/url_formatter.h"
 #include "components/wifi/wifi_service.h"
 #include "content/public/browser/web_contents.h"
@@ -56,7 +57,7 @@
     std::unique_ptr<SSLCertReporter> ssl_cert_reporter,
     const net::SSLInfo& ssl_info,
     const base::Callback<void(content::CertificateRequestResultType)>& callback)
-    : SecurityInterstitialPage(web_contents, request_url),
+    : SecurityInterstitialPage(web_contents, request_url, nullptr),
       login_url_(login_url),
       callback_(callback) {
   DCHECK(login_url_.is_valid());
diff --git a/chrome/browser/ssl/ssl_blocking_page.cc b/chrome/browser/ssl/ssl_blocking_page.cc
index db70bbbc..72ada1b6 100644
--- a/chrome/browser/ssl/ssl_blocking_page.cc
+++ b/chrome/browser/ssl/ssl_blocking_page.cc
@@ -98,15 +98,32 @@
   }
 }
 
+std::unique_ptr<ChromeMetricsHelper> CreateMetricsHelper(
+    content::WebContents* web_contents,
+    int cert_error,
+    const GURL& request_url,
+    bool overridable) {
+  // Set up the metrics helper for the SSLErrorUI.
+  security_interstitials::MetricsHelper::ReportDetails reporting_info;
+  reporting_info.metric_prefix =
+      overridable ? "ssl_overridable" : "ssl_nonoverridable";
+  reporting_info.rappor_prefix = kSSLRapporPrefix;
+  reporting_info.deprecated_rappor_prefix = kDeprecatedSSLRapporPrefix;
+  reporting_info.rappor_report_type = rappor::LOW_FREQUENCY_UMA_RAPPOR_TYPE;
+  reporting_info.deprecated_rappor_report_type = rappor::UMA_RAPPOR_TYPE;
+  return base::MakeUnique<ChromeMetricsHelper>(
+      web_contents, request_url, reporting_info,
+      GetSamplingEventName(overridable, cert_error));
+}
+
 }  // namespace
 
 // static
 InterstitialPageDelegate::TypeID SSLBlockingPage::kTypeForTesting =
     &SSLBlockingPage::kTypeForTesting;
 
-// Note that we always create a navigation entry with SSL errors.
-// No error happening loading a sub-resource triggers an interstitial so far.
-SSLBlockingPage::SSLBlockingPage(
+// static
+SSLBlockingPage* SSLBlockingPage::Create(
     content::WebContents* web_contents,
     int cert_error,
     const net::SSLInfo& ssl_info,
@@ -114,52 +131,18 @@
     int options_mask,
     const base::Time& time_triggered,
     std::unique_ptr<SSLCertReporter> ssl_cert_reporter,
-    const base::Callback<void(content::CertificateRequestResultType)>& callback)
-    : SecurityInterstitialPage(web_contents, request_url),
-      callback_(callback),
-      ssl_info_(ssl_info),
-      overridable_(IsOverridable(
-          options_mask,
-          Profile::FromBrowserContext(web_contents->GetBrowserContext()))),
-      expired_but_previously_allowed_(
-          (options_mask & SSLErrorUI::EXPIRED_BUT_PREVIOUSLY_ALLOWED) != 0) {
-  // Override prefs for the SSLErrorUI.
-  Profile* profile =
-      Profile::FromBrowserContext(web_contents->GetBrowserContext());
-  if (profile &&
-      !profile->GetPrefs()->GetBoolean(prefs::kSSLErrorOverrideAllowed)) {
-    options_mask |= SSLErrorUI::HARD_OVERRIDE_DISABLED;
-  }
-  if (overridable_)
-    options_mask |= SSLErrorUI::SOFT_OVERRIDE_ENABLED;
-  else
-    options_mask &= ~SSLErrorUI::SOFT_OVERRIDE_ENABLED;
-
-  // Set up the metrics helper for the SSLErrorUI.
-  security_interstitials::MetricsHelper::ReportDetails reporting_info;
-  reporting_info.metric_prefix =
-      overridable_ ? "ssl_overridable" : "ssl_nonoverridable";
-  reporting_info.rappor_prefix = kSSLRapporPrefix;
-  reporting_info.deprecated_rappor_prefix = kDeprecatedSSLRapporPrefix;
-  reporting_info.rappor_report_type = rappor::LOW_FREQUENCY_UMA_RAPPOR_TYPE;
-  reporting_info.deprecated_rappor_report_type = rappor::UMA_RAPPOR_TYPE;
-  ChromeMetricsHelper* chrome_metrics_helper =
-      new ChromeMetricsHelper(web_contents, request_url, reporting_info,
-                              GetSamplingEventName(overridable_, cert_error));
-  chrome_metrics_helper->StartRecordingCaptivePortalMetrics(overridable_);
-  controller()->set_metrics_helper(base::WrapUnique(chrome_metrics_helper));
-
-  cert_report_helper_.reset(new CertReportHelper(
-      std::move(ssl_cert_reporter), web_contents, request_url, ssl_info,
-      certificate_reporting::ErrorReport::INTERSTITIAL_SSL, overridable_,
-      controller()->metrics_helper()));
-
-  ssl_error_ui_.reset(new SSLErrorUI(request_url, cert_error, ssl_info,
-                                     options_mask, time_triggered,
-                                     controller()));
-
-  // Creating an interstitial without showing (e.g. from chrome://interstitials)
-  // it leaks memory, so don't create it here.
+    const base::Callback<void(content::CertificateRequestResultType)>&
+        callback) {
+  bool overridable = IsOverridable(
+      options_mask,
+      Profile::FromBrowserContext(web_contents->GetBrowserContext()));
+  std::unique_ptr<ChromeMetricsHelper> metrics_helper(
+      CreateMetricsHelper(web_contents, cert_error, request_url, overridable));
+  metrics_helper.get()->StartRecordingCaptivePortalMetrics(overridable);
+  return new SSLBlockingPage(web_contents, cert_error, ssl_info, request_url,
+                             options_mask, time_triggered,
+                             std::move(ssl_cert_reporter), overridable,
+                             std::move(metrics_helper), callback);
 }
 
 bool SSLBlockingPage::ShouldCreateNewNavigation() const {
@@ -174,8 +157,8 @@
   if (!callback_.is_null()) {
     // The page is closed without the user having chosen what to do, default to
     // deny.
-    RecordSSLExpirationPageEventState(
-        expired_but_previously_allowed_, false, overridable_);
+    RecordSSLExpirationPageEventState(expired_but_previously_allowed_, false,
+                                      overridable_);
     NotifyDenyCertificate();
   }
 }
@@ -186,6 +169,51 @@
   cert_report_helper_->PopulateExtendedReportingOption(load_time_data);
 }
 
+// Note that we always create a navigation entry with SSL errors.
+// No error happening loading a sub-resource triggers an interstitial so far.
+SSLBlockingPage::SSLBlockingPage(
+    content::WebContents* web_contents,
+    int cert_error,
+    const net::SSLInfo& ssl_info,
+    const GURL& request_url,
+    int options_mask,
+    const base::Time& time_triggered,
+    std::unique_ptr<SSLCertReporter> ssl_cert_reporter,
+    bool overridable,
+    std::unique_ptr<ChromeMetricsHelper> metrics_helper,
+    const base::Callback<void(content::CertificateRequestResultType)>& callback)
+    : SecurityInterstitialPage(web_contents,
+                               request_url,
+                               std::move(metrics_helper)),
+      callback_(callback),
+      ssl_info_(ssl_info),
+      overridable_(overridable),
+      expired_but_previously_allowed_(
+          (options_mask & SSLErrorUI::EXPIRED_BUT_PREVIOUSLY_ALLOWED) != 0) {
+  // Override prefs for the SSLErrorUI.
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents->GetBrowserContext());
+  if (profile &&
+      !profile->GetPrefs()->GetBoolean(prefs::kSSLErrorOverrideAllowed)) {
+    options_mask |= SSLErrorUI::HARD_OVERRIDE_DISABLED;
+  }
+  if (overridable_)
+    options_mask |= SSLErrorUI::SOFT_OVERRIDE_ENABLED;
+  else
+    options_mask &= ~SSLErrorUI::SOFT_OVERRIDE_ENABLED;
+
+  cert_report_helper_.reset(new CertReportHelper(
+      std::move(ssl_cert_reporter), web_contents, request_url, ssl_info,
+      certificate_reporting::ErrorReport::INTERSTITIAL_SSL, overridable_,
+      controller()->metrics_helper()));
+
+  ssl_error_ui_.reset(new SSLErrorUI(request_url, cert_error, ssl_info,
+                                     options_mask, time_triggered,
+                                     controller()));
+  // Creating an interstitial without showing (e.g. from chrome://interstitials)
+  // it leaks memory, so don't create it here.
+}
+
 void SSLBlockingPage::OverrideEntry(NavigationEntry* entry) {
   entry->GetSSL() = content::SSLStatus(
       content::SECURITY_STYLE_AUTHENTICATION_BROKEN, ssl_info_.cert, ssl_info_);
diff --git a/chrome/browser/ssl/ssl_blocking_page.h b/chrome/browser/ssl/ssl_blocking_page.h
index feb7966..084343c 100644
--- a/chrome/browser/ssl/ssl_blocking_page.h
+++ b/chrome/browser/ssl/ssl_blocking_page.h
@@ -37,6 +37,7 @@
 
 class CertReportHelper;
 class SSLUITest;
+class ChromeMetricsHelper;
 
 // This class is responsible for showing/hiding the interstitial page that is
 // shown when a certificate error happens.
@@ -52,15 +53,18 @@
   // is responsible for cleaning up the blocking page, otherwise the
   // interstitial takes ownership when shown. |options_mask| must be a bitwise
   // mask of SSLErrorUI::SSLErrorOptionsMask values.
-  SSLBlockingPage(content::WebContents* web_contents,
-                  int cert_error,
-                  const net::SSLInfo& ssl_info,
-                  const GURL& request_url,
-                  int options_mask,
-                  const base::Time& time_triggered,
-                  std::unique_ptr<SSLCertReporter> ssl_cert_reporter,
-                  const base::Callback<
-                      void(content::CertificateRequestResultType)>& callback);
+  // This is static because the constructor uses expensive to compute parameters
+  // more than once (e.g. overrideable).
+  static SSLBlockingPage* Create(
+      content::WebContents* web_contents,
+      int cert_error,
+      const net::SSLInfo& ssl_info,
+      const GURL& request_url,
+      int options_mask,
+      const base::Time& time_triggered,
+      std::unique_ptr<SSLCertReporter> ssl_cert_reporter,
+      const base::Callback<void(content::CertificateRequestResultType)>&
+          callback);
 
   // InterstitialPageDelegate method:
   InterstitialPageDelegate::TypeID GetTypeForTesting() const override;
@@ -89,6 +93,19 @@
       base::DictionaryValue* load_time_data) override;
 
  private:
+  SSLBlockingPage(
+      content::WebContents* web_contents,
+      int cert_error,
+      const net::SSLInfo& ssl_info,
+      const GURL& request_url,
+      int options_mask,
+      const base::Time& time_triggered,
+      std::unique_ptr<SSLCertReporter> ssl_cert_reporter,
+      bool overrideable,
+      std::unique_ptr<ChromeMetricsHelper> metrics_helper,
+      const base::Callback<void(content::CertificateRequestResultType)>&
+          callback);
+
   void NotifyDenyCertificate();
 
   base::Callback<void(content::CertificateRequestResultType)> callback_;
diff --git a/chrome/browser/ssl/ssl_browser_tests.cc b/chrome/browser/ssl/ssl_browser_tests.cc
index 61d20c5..6d6db23 100644
--- a/chrome/browser/ssl/ssl_browser_tests.cc
+++ b/chrome/browser/ssl/ssl_browser_tests.cc
@@ -3077,7 +3077,7 @@
     net::SSLInfo ssl_info;
     ssl_info.cert =
         net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
-    return new SSLBlockingPage(
+    return SSLBlockingPage::Create(
         contents, net::ERR_CERT_CONTAINS_ERRORS, ssl_info, request_url, 0,
         base::Time::NowFromSystemTime(), nullptr,
         base::Callback<void(content::CertificateRequestResultType)>());
diff --git a/chrome/browser/ssl/ssl_error_handler.cc b/chrome/browser/ssl/ssl_error_handler.cc
index 74907fd..4eefa85 100644
--- a/chrome/browser/ssl/ssl_error_handler.cc
+++ b/chrome/browser/ssl/ssl_error_handler.cc
@@ -337,9 +337,9 @@
   RecordUMA(IsErrorOverridable() ? SHOW_SSL_INTERSTITIAL_OVERRIDABLE
                                  : SHOW_SSL_INTERSTITIAL_NONOVERRIDABLE);
 
-  (new SSLBlockingPage(web_contents_, cert_error_, ssl_info_, request_url_,
-                       options_mask_, base::Time::NowFromSystemTime(),
-                       std::move(ssl_cert_reporter_), callback_))
+  (SSLBlockingPage::Create(web_contents_, cert_error_, ssl_info_, request_url_,
+                           options_mask_, base::Time::NowFromSystemTime(),
+                           std::move(ssl_cert_reporter_), callback_))
       ->Show();
   // Once an interstitial is displayed, no need to keep the handler around.
   // This is the equivalent of "delete this".
diff --git a/chrome/browser/sync/sessions/sessions_sync_manager_unittest.cc b/chrome/browser/sync/sessions/sessions_sync_manager_unittest.cc
index b8c0766e..734e4d5 100644
--- a/chrome/browser/sync/sessions/sessions_sync_manager_unittest.cc
+++ b/chrome/browser/sync/sessions/sessions_sync_manager_unittest.cc
@@ -180,6 +180,10 @@
     return sync_data_to_return_;
   }
 
+  void AddLocalChangeObserver(syncer::LocalChangeObserver* observer) override {}
+  void RemoveLocalChangeObserver(
+      syncer::LocalChangeObserver* observer) override {}
+
   void FailProcessSyncChangesWith(const syncer::SyncError& error) {
     error_ = error;
   }
diff --git a/chrome/browser/sync/test/integration/two_client_uss_sync_test.cc b/chrome/browser/sync/test/integration/two_client_uss_sync_test.cc
index b9df953..977df4b 100644
--- a/chrome/browser/sync/test/integration/two_client_uss_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_uss_sync_test.cc
@@ -8,6 +8,7 @@
 #include "chrome/browser/sync/chrome_sync_client.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.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_integration_test_util.h"
 #include "chrome/browser/sync/test/integration/sync_test.h"
@@ -23,6 +24,7 @@
 using syncer_v2::SharedModelTypeProcessor;
 
 const char kKey1[] = "key1";
+const char kKey2[] = "key2";
 const char kValue1[] = "value1";
 const char kValue2[] = "value2";
 const char kValue3[] = "value3";
@@ -90,7 +92,6 @@
  public:
   KeyChecker(TestModelTypeService* service, const std::string& key)
       : service_(service), key_(key) {}
-  ~KeyChecker() override {}
 
   void OnApplySyncChanges() override { CheckExitCondition(); }
 
@@ -118,7 +119,6 @@
               const std::string& key,
               const std::string& value)
       : KeyChecker(service, key), value_(value) {}
-  ~DataChecker() override {}
 
   bool IsExitConditionSatisfied() override {
     const auto& db = service_->db();
@@ -138,7 +138,6 @@
  public:
   DataAbsentChecker(TestModelTypeService* service, const std::string& key)
       : KeyChecker(service, key) {}
-  ~DataAbsentChecker() override {}
 
   bool IsExitConditionSatisfied() override {
     return !service_->db().HasData(key_);
@@ -154,7 +153,6 @@
  public:
   MetadataPresentChecker(TestModelTypeService* service, const std::string& key)
       : KeyChecker(service, key) {}
-  ~MetadataPresentChecker() override {}
 
   bool IsExitConditionSatisfied() override {
     return service_->db().HasMetadata(key_);
@@ -170,7 +168,6 @@
  public:
   MetadataAbsentChecker(TestModelTypeService* service, const std::string& key)
       : KeyChecker(service, key) {}
-  ~MetadataAbsentChecker() override {}
 
   bool IsExitConditionSatisfied() override {
     return !service_->db().HasMetadata(key_);
@@ -181,6 +178,26 @@
   }
 };
 
+// Wait for PREFERENCES to no longer be running.
+class PrefsNotRunningChecker : public SingleClientStatusChangeChecker {
+ public:
+  explicit PrefsNotRunningChecker(browser_sync::ProfileSyncService* service)
+      : SingleClientStatusChangeChecker(service) {}
+
+  bool Wait() {
+    SingleClientStatusChangeChecker::Wait();
+    return !TimedOut();
+  }
+
+  bool IsExitConditionSatisfied() override {
+    return !service()->IsDataTypeControllerRunning(syncer::PREFERENCES);
+  }
+
+  std::string GetDebugMessage() const override {
+    return "Waiting for prefs to be not running.";
+  }
+};
+
 class TwoClientUssSyncTest : public SyncTest {
  public:
   TwoClientUssSyncTest() : SyncTest(TWO_CLIENT) {
@@ -301,3 +318,24 @@
   ASSERT_TRUE(DataChecker(model1, kKey1, kValue3).Wait());
   ASSERT_TRUE(DataChecker(model2, kKey1, kValue3).Wait());
 }
+
+IN_PROC_BROWSER_TEST_F(TwoClientUssSyncTest, Error) {
+  ASSERT_TRUE(SetupSync());
+  TestModelTypeService* model1 = GetModelTypeService(0);
+  TestModelTypeService* model2 = GetModelTypeService(1);
+
+  // Add an entity.
+  model1->WriteItem(kKey1, kValue1);
+  ASSERT_TRUE(DataChecker(model2, kKey1, kValue1).Wait());
+
+  // Set an error in model 2 to trigger in the next GetUpdates.
+  model2->SetServiceError(syncer::SyncError::DATATYPE_ERROR);
+  // Write an item on model 1 to trigger a GetUpdates in model 2.
+  model1->WriteItem(kKey1, kValue2);
+
+  // The type should stop syncing but keep tracking metadata.
+  ASSERT_TRUE(PrefsNotRunningChecker(GetSyncService(1)).Wait());
+  ASSERT_EQ(1U, model2->db().metadata_count());
+  model2->WriteItem(kKey2, kValue2);
+  ASSERT_EQ(2U, model2->db().metadata_count());
+}
diff --git a/chrome/browser/task_manager/providers/arc/arc_process_task.cc b/chrome/browser/task_manager/providers/arc/arc_process_task.cc
index 3929c3a8..1f0b4fe 100644
--- a/chrome/browser/task_manager/providers/arc/arc_process_task.cc
+++ b/chrome/browser/task_manager/providers/arc/arc_process_task.cc
@@ -89,13 +89,14 @@
 void ArcProcessTask::StartIconLoading() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  if (package_name_.empty())
-    return;
-
   scoped_refptr<arc::ActivityIconLoader> icon_loader = GetIconLoader();
   arc::ActivityIconLoader::GetResult result =
       arc::ActivityIconLoader::GetResult::FAILED_ARC_NOT_READY;
   if (icon_loader) {
+    // In some case, the package_name_ does not exists, it would be expected to
+    // get default process icon. For example, daemon processes in android
+    // container such like surfaceflinger, debuggerd or installd. Each of them
+    // would be shown on task manager but does not have a package name.
     std::vector<arc::ActivityIconLoader::ActivityName> activities = {
         {package_name_, kEmptyActivityName}};
     result = icon_loader->GetActivityIcons(
diff --git a/chrome/browser/ui/android/infobars/grouped_permission_infobar.cc b/chrome/browser/ui/android/infobars/grouped_permission_infobar.cc
index 8f3065532..5c8afd1 100644
--- a/chrome/browser/ui/android/infobars/grouped_permission_infobar.cc
+++ b/chrome/browser/ui/android/infobars/grouped_permission_infobar.cc
@@ -8,7 +8,7 @@
 #include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
 #include "chrome/browser/android/resource_mapper.h"
-#include "chrome/browser/permissions/grouped_permission_infobar_delegate.h"
+#include "chrome/browser/permissions/grouped_permission_infobar_delegate_android.h"
 #include "jni/GroupedPermissionInfoBar_jni.h"
 
 GroupedPermissionInfoBar::GroupedPermissionInfoBar(
@@ -26,11 +26,10 @@
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& obj,
     const base::android::JavaParamRef<jbooleanArray>& permissions) {
-
-  for (int i = 0; i < GetDelegate()->GetPermissionCount(); i++) {
-      jboolean value;
-      env->GetBooleanArrayRegion(permissions.obj(), i, 1, &value);
-      GetDelegate()->ToggleAccept(i, value);
+  for (size_t i = 0; i < GetDelegate()->permission_count(); i++) {
+    jboolean value;
+    env->GetBooleanArrayRegion(permissions.obj(), i, 1, &value);
+    GetDelegate()->ToggleAccept(i, value);
   }
 }
 
@@ -64,7 +63,7 @@
   std::vector<int> permission_icons;
   std::vector<int> content_settings_types;
 
-  for (int i = 0; i < delegate->GetPermissionCount(); i++) {
+  for (size_t i = 0; i < delegate->permission_count(); i++) {
     permission_strings.push_back(delegate->GetMessageTextFragment(i));
     permission_icons.push_back(
         ResourceMapper::MapFromChromiumId(delegate->GetIconIdForPermission(i)));
@@ -91,11 +90,3 @@
 GroupedPermissionInfoBarDelegate* GroupedPermissionInfoBar::GetDelegate() {
   return static_cast<GroupedPermissionInfoBarDelegate*>(delegate());
 }
-
-std::unique_ptr<infobars::InfoBar>
-GroupedPermissionInfoBarDelegate::CreateInfoBar(
-    infobars::InfoBarManager* infobar_manager,
-    std::unique_ptr<GroupedPermissionInfoBarDelegate> delegate) {
-  return std::unique_ptr<infobars::InfoBar>(
-      new GroupedPermissionInfoBar(std::move(delegate)));
-}
diff --git a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc
index 025640f..eb5a600 100644
--- a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc
@@ -134,7 +134,7 @@
 
   ArcAppWindowLauncherItemController* controller() { return controller_; }
 
-  const std::string app_id() { return app_id_; }
+  const std::string& app_id() { return app_id_; }
 
   // ui::BaseWindow:
   bool IsActive() const override {
@@ -275,6 +275,12 @@
   if (user_email == primary_user_email) {
     // Restore existing Arc window and create controllers for them.
     AttachControllerToWindowsIfNeeded();
+
+    // Make sure that we created items for all apps, not only which have a
+    // window.
+    for (const auto& it : task_id_to_shelf_app_id_)
+      AttachControllerToTask(it.second, it.first);
+
     // Update active status.
     OnTaskSetActive(active_task_id_);
   } else {
@@ -285,6 +291,12 @@
       UnregisterApp(app_window, true);
     }
     task_id_to_app_window_.clear();
+
+    // Some controllers might have no windows attached, for example background
+    // task when foreground tasks is in full screen.
+    for (const auto& it : app_controller_map_)
+      owner()->CloseLauncherItem(it.second->shelf_id());
+    app_controller_map_.clear();
   }
 }
 
@@ -429,14 +441,20 @@
     const std::string& package_name,
     const std::string& activity_name) {
   DCHECK(!GetAppWindowForTask(task_id));
-  task_id_to_shelf_app_id_[task_id] = GetShelfAppIdFromArcAppId(
+  const std::string shelf_app_id = GetShelfAppIdFromArcAppId(
       ArcAppListPrefs::GetAppId(package_name, activity_name));
+  task_id_to_shelf_app_id_[task_id] = shelf_app_id;
 
   // Don't create shelf icon for non-primary user.
   if (observed_profile_ != owner()->GetProfile())
     return;
 
   AttachControllerToWindowsIfNeeded();
+
+  // Some tasks can be started in background and might have no window until
+  // pushed to the front. We need its representation on the shelf to give a user
+  // control over it.
+  AttachControllerToTask(shelf_app_id, task_id);
 }
 
 void ArcAppWindowLauncherController::OnTaskDestroyed(int task_id) {
@@ -577,31 +595,45 @@
     env->RemoveObserver(this);
 }
 
+ArcAppWindowLauncherItemController*
+ArcAppWindowLauncherController::AttachControllerToTask(
+    const std::string& shelf_app_id,
+    int task_id) {
+  AppControllerMap::const_iterator it = app_controller_map_.find(shelf_app_id);
+  if (it != app_controller_map_.end()) {
+    DCHECK_EQ(it->second->app_id(), shelf_app_id);
+    it->second->AddTaskId(task_id);
+    return it->second;
+  }
+
+  ArcAppWindowLauncherItemController* controller =
+      new ArcAppWindowLauncherItemController(shelf_app_id, owner());
+  const ash::ShelfID shelf_id =
+      shelf_delegate_->GetShelfIDForAppID(shelf_app_id);
+  if (!shelf_id) {
+    owner()->CreateAppLauncherItem(controller, shelf_app_id,
+                                   ash::STATUS_RUNNING);
+  } else {
+    owner()->SetItemController(shelf_id, controller);
+    owner()->SetItemStatus(shelf_id, ash::STATUS_RUNNING);
+  }
+  controller->AddTaskId(task_id);
+  app_controller_map_[shelf_app_id] = controller;
+  return controller;
+}
+
 void ArcAppWindowLauncherController::RegisterApp(AppWindow* app_window) {
   const std::string app_id = app_window->app_id();
   DCHECK(!app_id.empty());
 
-  ArcAppWindowLauncherItemController* controller;
-  AppControllerMap::iterator it = app_controller_map_.find(app_id);
-  ash::ShelfID shelf_id = 0;
-  if (it != app_controller_map_.end()) {
-    controller = it->second;
-    DCHECK_EQ(controller->app_id(), app_id);
-    shelf_id = controller->shelf_id();
-  } else {
-    controller = new ArcAppWindowLauncherItemController(app_id, owner());
-    shelf_id = shelf_delegate_->GetShelfIDForAppID(app_id);
-    if (shelf_id == 0) {
-      // Map Play Store shelf icon to Arc Support host, to share one entry.
-      shelf_id = owner()->CreateAppLauncherItem(controller, app_id,
-                                                ash::STATUS_RUNNING);
-    } else {
-      owner()->SetItemController(shelf_id, controller);
-    }
-    app_controller_map_[app_id] = controller;
-  }
+  ArcAppWindowLauncherItemController* controller =
+      AttachControllerToTask(app_id, app_window->task_id());
+  DCHECK(controller);
+
+  const ash::ShelfID shelf_id = shelf_delegate_->GetShelfIDForAppID(app_id);
+  DCHECK(shelf_id);
+
   controller->AddWindow(app_window);
-  controller->AddTaskId(app_window->task_id());
   owner()->SetItemStatus(shelf_id, ash::STATUS_RUNNING);
   app_window->SetController(controller);
   app_window->set_shelf_id(shelf_id);
diff --git a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h
index 30a1793..e6acc26 100644
--- a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h
+++ b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h
@@ -101,6 +101,9 @@
 
   void AttachControllerToWindowIfNeeded(aura::Window* window);
   void AttachControllerToWindowsIfNeeded();
+  ArcAppWindowLauncherItemController* AttachControllerToTask(
+      const std::string& shelf_app_id,
+      int taskId);
 
   void SetOrientationLockForAppWindow(AppWindow* app_window);
 
diff --git a/chrome/browser/ui/ash/launcher/browser_status_monitor.cc b/chrome/browser/ui/ash/launcher/browser_status_monitor.cc
index 6e1bafbd..df94be6 100644
--- a/chrome/browser/ui/ash/launcher/browser_status_monitor.cc
+++ b/chrome/browser/ui/ash/launcher/browser_status_monitor.cc
@@ -7,6 +7,7 @@
 #include "ash/aura/wm_window_aura.h"
 #include "ash/common/shelf/shelf_item_types.h"
 #include "ash/common/wm_window_property.h"
+#include "ash/common/wm_window_tracker.h"
 #include "ash/resources/grit/ash_resources.h"
 #include "ash/shell.h"
 #include "ash/wm/window_util.h"
@@ -23,7 +24,6 @@
 #include "chrome/browser/ui/settings_window_manager_observer.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/web_applications/web_app.h"
-#include "chrome/grit/generated_resources.h"
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
@@ -85,19 +85,29 @@
 // Observes any new settings windows and sets their shelf icon (since they
 // are excluded from BrowserShortcutLauncherItem).
 class BrowserStatusMonitor::SettingsWindowObserver
-    : public chrome::SettingsWindowManagerObserver {
+    : public chrome::SettingsWindowManagerObserver,
+      public ash::WmWindowTracker {
  public:
   SettingsWindowObserver() {}
   ~SettingsWindowObserver() override {}
 
-  // SettingsWindowManagerObserver
+  // SettingsWindowManagerObserver:
   void OnNewSettingsWindow(Browser* settings_browser) override {
-    ash::ShelfItemDetails item_details;
-    item_details.type = ash::TYPE_DIALOG;
-    item_details.image_resource_id = IDR_ASH_SHELF_ICON_SETTINGS;
-    item_details.title = l10n_util::GetStringUTF16(IDS_SETTINGS_TITLE);
     aura::Window* aura_window = settings_browser->window()->GetNativeWindow();
-    ash::WmWindowAura::Get(aura_window)->SetShelfItemDetails(item_details);
+    ash::WmWindow* window = ash::WmWindowAura::Get(aura_window);
+    window->SetTitle(l10n_util::GetStringUTF16(IDS_SETTINGS_TITLE));
+    window->SetIntProperty(ash::WmWindowProperty::SHELF_ITEM_TYPE,
+                           ash::TYPE_DIALOG);
+    window->SetIntProperty(ash::WmWindowProperty::SHELF_ICON_RESOURCE_ID,
+                           IDR_ASH_SHELF_ICON_SETTINGS);
+    Add(window);
+  }
+
+  // ash::WmWindowTracker:
+  void OnWindowTitleChanged(ash::WmWindow* window) override {
+    // Name the window "Settings" instead of "Google Chrome - Settings".
+    if (window->GetTitle() != l10n_util::GetStringUTF16(IDS_SETTINGS_TITLE))
+      window->SetTitle(l10n_util::GetStringUTF16(IDS_SETTINGS_TITLE));
   }
 
  private:
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.cc
index 67762c1..f3cbb73 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.cc
@@ -1133,8 +1133,9 @@
     UnpinAndUpdatePrefs(shelf_id, update_prefs);
 }
 
-int ChromeLauncherControllerImpl::PinRunningAppInternal(int index,
-                                                        ash::ShelfID shelf_id) {
+void ChromeLauncherControllerImpl::PinRunningAppInternal(
+    int index,
+    ash::ShelfID shelf_id) {
   int running_index = model_->ItemIndexByID(shelf_id);
   ash::ShelfItem item = model_->items()[running_index];
   DCHECK(item.type == ash::TYPE_WINDOWED_APP ||
@@ -1148,7 +1149,6 @@
     --index;
   if (running_index != index)
     model_->Move(running_index, index);
-  return index;
 }
 
 void ChromeLauncherControllerImpl::UnpinRunningAppInternal(int index) {
@@ -1220,119 +1220,79 @@
   // into the pref state. Therefore we tell |persistPinnedState| to ignore any
   // invocations while we are running.
   base::AutoReset<bool> auto_reset(&ignore_persist_pinned_state_change_, true);
-  std::vector<std::string> pinned_apps = ash::launcher::GetPinnedAppsFromPrefs(
-      profile_->GetPrefs(), launcher_controller_helper_.get());
+  const std::vector<std::string> pinned_apps =
+      ash::launcher::GetPinnedAppsFromPrefs(profile_->GetPrefs(),
+                                            launcher_controller_helper_.get());
 
   int index = 0;
-  int max_index = model_->item_count();
-  int seen_chrome_index = -1;
-
-  // At least chrome browser shortcut should exist.
-  DCHECK_GT(max_index, 0);
-
   // Skip app list items if it exists.
   if (model_->items()[0].type == ash::TYPE_APP_LIST)
     ++index;
 
-  // Walk the model and |pinned_apps| from the pref lockstep, adding and
-  // removing items as necessary. NB: This code uses plain old indexing instead
-  // of iterators because of model mutations as part of the loop.
-  std::vector<std::string>::const_iterator pref_app_id(pinned_apps.begin());
-  for (; index < max_index && pref_app_id != pinned_apps.end(); ++index) {
+  // Apply pins in two steps. At the first step, go through the list of apps to
+  // pin, move existing pin to current position specified by |index| or create
+  // the new pin at that position.
+  for (const auto& pref_app_id : pinned_apps) {
+    // Filter out apps that may be mapped wrongly.
+    // TODO(khmel):  b/31703859 is to refactore shelf mapping.
+    const std::string shelf_app_id =
+        ArcAppWindowLauncherController::GetShelfAppIdFromArcAppId(pref_app_id);
+    if (shelf_app_id != pref_app_id)
+      continue;
+
     // Update apps icon if applicable.
-    OnAppUpdated(profile_, *pref_app_id);
-    // Check if we have an item which we need to handle.
-    if (IsAppPinned(*pref_app_id)) {
-      if (seen_chrome_index >= 0 &&
-          *pref_app_id == extension_misc::kChromeAppId) {
-        // Current item is Chrome browser and we saw it before.
-        model_->Move(seen_chrome_index, index);
-        ++pref_app_id;
-        --index;
-        continue;
+    OnAppUpdated(profile_, pref_app_id);
+
+    // Find existing pin or app from the right of current |index|.
+    int app_index = index;
+    for (; app_index < model_->item_count(); ++app_index) {
+      const ash::ShelfItem& item = model_->items()[app_index];
+      const IDToItemControllerMap::iterator it =
+          id_to_item_controller_map_.find(item.id);
+      if (it != id_to_item_controller_map_.end() &&
+          it->second->app_id() == pref_app_id) {
+        break;
       }
-      for (; index < max_index; ++index) {
-        const ash::ShelfItem& item(model_->items()[index]);
-        if (item.type != ash::TYPE_APP_SHORTCUT &&
-            item.type != ash::TYPE_BROWSER_SHORTCUT) {
-          continue;
-        }
-        LauncherItemController* controller = GetLauncherItemController(item.id);
-        if (controller && controller->app_id() == *pref_app_id) {
-          ++pref_app_id;
-          break;
-        } else if (item.type == ash::TYPE_BROWSER_SHORTCUT) {
-          // We cannot close browser shortcut. Remember its position.
-          seen_chrome_index = index;
-        } else {
-          // Check if this is a platform or a windowed app.
-          if (item.type == ash::TYPE_APP_SHORTCUT && controller &&
-              (controller->locked() ||
-               controller->type() == LauncherItemController::TYPE_APP)) {
-            // Note: This will not change the amount of items (|max_index|).
-            // Even changes to the actual |index| due to item weighting
-            // changes should be fine.
-            UnpinRunningAppInternal(index);
-          } else {
-            if (controller)
-              LauncherItemClosed(item.id);
-            --max_index;
-          }
-          --index;
-        }
-      }
-      // If the item wasn't found, that means id_to_item_controller_map_
-      // is out of sync.
-      DCHECK(index <= max_index);
-    } else {
-      // Check if the item was already running but not yet pinned.
-      ash::ShelfID shelf_id = GetShelfIDForAppID(*pref_app_id);
-      if (shelf_id) {
-        // This app is running but not yet pinned. So pin and move it.
-        index = PinRunningAppInternal(index, shelf_id);
+    }
+    if (app_index < model_->item_count()) {
+      // Found existing pin or running app.
+      const ash::ShelfItem item = model_->items()[app_index];
+      if (item.type == ash::TYPE_APP_SHORTCUT ||
+          item.type == ash::TYPE_BROWSER_SHORTCUT) {
+        // Just move to required position or keep it inplace.
+        model_->Move(app_index, index);
       } else {
-        // This app wasn't pinned before, insert a new entry.
-        shelf_id = CreateAppShortcutLauncherItem(*pref_app_id, index);
-        ++max_index;
-        index = model_->ItemIndexByID(shelf_id);
+        PinRunningAppInternal(index, item.id);
       }
-      ++pref_app_id;
+      DCHECK_EQ(model_->ItemIndexByID(item.id), index);
+    } else {
+      // This is fresh pin. Create new one.
+      DCHECK_NE(pref_app_id, extension_misc::kChromeAppId);
+      CreateAppShortcutLauncherItem(pref_app_id, index);
     }
+    ++index;
   }
 
-  // Remove any trailing existing items.
+  // At second step remove any pin to the right from the current index.
   while (index < model_->item_count()) {
-    const ash::ShelfItem& item(model_->items()[index]);
-    if (item.type == ash::TYPE_APP_SHORTCUT) {
-      LauncherItemController* controller = GetLauncherItemController(item.id);
-      if (controller) {
-        if (controller->locked() ||
-            controller->type() == LauncherItemController::TYPE_APP) {
-          UnpinRunningAppInternal(index);
-        } else {
-          LauncherItemClosed(item.id);
-        }
-      }
-    } else {
+    const ash::ShelfItem item = model_->items()[index];
+    if (item.type != ash::TYPE_APP_SHORTCUT) {
       ++index;
+      continue;
     }
-  }
 
-  // Append unprocessed items from the pref to the end of the model.
-  for (; pref_app_id != pinned_apps.end(); ++pref_app_id) {
-    // Update apps icon if applicable.
-    OnAppUpdated(profile_, *pref_app_id);
-    if (*pref_app_id == extension_misc::kChromeAppId) {
-      int target_index = FindInsertionPoint();
-      DCHECK(seen_chrome_index >= 0 && seen_chrome_index < target_index);
-      model_->Move(seen_chrome_index, target_index);
+    const LauncherItemController* controller =
+        GetLauncherItemController(item.id);
+    DCHECK(controller);
+    DCHECK_NE(controller->app_id(), extension_misc::kChromeAppId);
+
+    if (controller->locked() ||
+        controller->type() == LauncherItemController::TYPE_APP) {
+      UnpinRunningAppInternal(index);
+      // Note, item can be moved to the right due weighting in shelf model.
+      DCHECK_GE(model_->ItemIndexByID(item.id), index);
     } else {
-      DoPinAppWithID(*pref_app_id);
-      int target_index = FindInsertionPoint();
-      ash::ShelfID id = GetShelfIDForAppID(*pref_app_id);
-      int source_index = model_->ItemIndexByID(id);
-      if (source_index != target_index)
-        model_->Move(source_index, target_index);
+      LauncherItemClosed(item.id);
     }
   }
 }
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.h
index 61a76aa..8504e64 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.h
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.h
@@ -219,9 +219,8 @@
   void DoPinAppWithID(const std::string& app_id);
   void DoUnpinAppWithID(const std::string& app_id, bool update_prefs);
 
-  // Pin a running app with |shelf_id| internally to |index|. It returns
-  // the index where the item was pinned.
-  int PinRunningAppInternal(int index, ash::ShelfID shelf_id);
+  // Pin a running app with |shelf_id| internally to |index|.
+  void PinRunningAppInternal(int index, ash::ShelfID shelf_id);
 
   // Unpin a locked application. This is an internal call which converts the
   // model type of the given app index from a shortcut into an unpinned running
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc
index 9753e12..9810416 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc
@@ -1966,7 +1966,7 @@
   // Arc window created after and closed before mojom notification.
   std::string window_app_id2("org.chromium.arc.2");
   arc_test_.app_instance()->SendTaskCreated(2, arc_test_.fake_apps()[1]);
-  EXPECT_EQ(0, launcher_controller_->GetShelfIDForAppID(arc_app_id2));
+  EXPECT_NE(0, launcher_controller_->GetShelfIDForAppID(arc_app_id2));
   arc_window = CreateArcWindow(window_app_id2);
   ASSERT_TRUE(arc_window);
   EXPECT_NE(0, launcher_controller_->GetShelfIDForAppID(arc_app_id2));
diff --git a/chrome/browser/ui/ash/launcher/launcher_item_controller.h b/chrome/browser/ui/ash/launcher/launcher_item_controller.h
index b45ffde..42b55b8 100644
--- a/chrome/browser/ui/ash/launcher/launcher_item_controller.h
+++ b/chrome/browser/ui/ash/launcher/launcher_item_controller.h
@@ -61,7 +61,7 @@
     DCHECK(locked_);
     locked_--;
   }
-  bool locked() { return locked_ > 0; }
+  bool locked() const { return locked_ > 0; }
 
   bool image_set_by_controller() const { return image_set_by_controller_; }
   void set_image_set_by_controller(bool image_set_by_controller) {
diff --git a/chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.cc b/chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.cc
index ab3fb69..b75862a 100644
--- a/chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.cc
+++ b/chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.cc
@@ -6,8 +6,8 @@
 
 #include "ash/aura/wm_window_aura.h"
 #include "ash/common/shelf/shelf_item_types.h"
+#include "ash/common/wm_window_observer.h"
 #include "ash/common/wm_window_property.h"
-#include "ash/resources/grit/ash_resources.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
@@ -18,9 +18,6 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/settings_window_manager.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/grit/generated_resources.h"
-#include "components/strings/grit/components_strings.h"
-#include "ui/base/l10n/l10n_util.h"
 
 MultiProfileBrowserStatusMonitor::MultiProfileBrowserStatusMonitor(
     ChromeLauncherController* launcher_controller)
@@ -47,9 +44,7 @@
   BrowserList* browser_list = BrowserList::GetInstance();
 
   // Remove old (tabbed V1) applications.
-  for (BrowserList::const_iterator it = browser_list->begin();
-       it != browser_list->end(); ++it) {
-    Browser* browser = *it;
+  for (Browser* browser : *browser_list) {
     if (!browser->is_app() &&
         browser->is_type_tabbed() &&
         !multi_user_util::IsProfileFromActiveUser(browser->profile())) {
@@ -62,9 +57,7 @@
   }
 
   // Handle apps in browser tabs: Add new (tabbed V1) applications.
-  for (BrowserList::const_iterator it = browser_list->begin();
-       it != browser_list->end(); ++it) {
-    Browser* browser = *it;
+  for (Browser* browser : *browser_list) {
     if (!browser->is_app() &&
         browser->is_type_tabbed() &&
         multi_user_util::IsProfileFromActiveUser(browser->profile())) {
@@ -79,24 +72,18 @@
     }
   }
 
-  // Remove settings window icons not associated with this profile and create
-  // icons for windows associated with the current profile.
-  for (BrowserList::const_iterator it = browser_list->begin();
-       it != browser_list->end(); ++it) {
-    Browser* browser = *it;
-    if (!chrome::SettingsWindowManager::GetInstance()->IsSettingsBrowser(
+  // Hide settings window shelf items not associated with this profile and
+  // restore items for windows associated with the current profile.
+  for (Browser* browser : *browser_list) {
+    if (chrome::SettingsWindowManager::GetInstance()->IsSettingsBrowser(
             browser)) {
-      continue;
-    }
-    aura::Window* aura_window = browser->window()->GetNativeWindow();
-    if (multi_user_util::IsProfileFromActiveUser(browser->profile())) {
-      ash::ShelfItemDetails item_details;
-      item_details.type = ash::TYPE_DIALOG;
-      item_details.image_resource_id = IDR_ASH_SHELF_ICON_SETTINGS;
-      item_details.title = l10n_util::GetStringUTF16(IDS_SETTINGS_TITLE);
-      ash::WmWindowAura::Get(aura_window)->SetShelfItemDetails(item_details);
-    } else {
-      ash::WmWindowAura::Get(aura_window)->ClearShelfItemDetails();
+      aura::Window* aura_window = browser->window()->GetNativeWindow();
+      ash::WmWindowAura::Get(aura_window)
+          ->SetIntProperty(
+              ash::WmWindowProperty::SHELF_ITEM_TYPE,
+              multi_user_util::IsProfileFromActiveUser(browser->profile())
+                  ? ash::TYPE_DIALOG
+                  : ash::TYPE_UNDEFINED);
     }
   }
 
diff --git a/chrome/browser/ui/cocoa/chooser_content_view_cocoa.h b/chrome/browser/ui/cocoa/chooser_content_view_cocoa.h
index a7c5b33..34dff6f 100644
--- a/chrome/browser/ui/cocoa/chooser_content_view_cocoa.h
+++ b/chrome/browser/ui/cocoa/chooser_content_view_cocoa.h
@@ -155,13 +155,17 @@
 // Called when the "Get help" button is pressed.
 - (void)onHelpPressed:(id)sender;
 
-// Gets the image from table row view. For testing only.
+// Update the color of the image and text in the table row view.
+- (void)updateContentRowColor;
+
+// Gets the image from table row view. For testing and internal use only.
 - (NSImageView*)tableRowViewImage:(NSInteger)row;
 
-// Gets the text from table row view. For testing only.
+// Gets the text from table row view. For testing and internal use only.
 - (NSTextField*)tableRowViewText:(NSInteger)row;
 
-// Gets the paired status from table row view. For testing only.
+// Gets the paired status from table row view. For testing and internal use
+// only.
 - (NSTextField*)tableRowViewPairedStatus:(NSInteger)row;
 
 @end
diff --git a/chrome/browser/ui/cocoa/chooser_content_view_cocoa.mm b/chrome/browser/ui/cocoa/chooser_content_view_cocoa.mm
index 567c9fe..c0030750 100644
--- a/chrome/browser/ui/cocoa/chooser_content_view_cocoa.mm
+++ b/chrome/browser/ui/cocoa/chooser_content_view_cocoa.mm
@@ -64,6 +64,10 @@
 const int kSignalStrengthLevelImageIds[5] = {IDR_SIGNAL_0_BAR, IDR_SIGNAL_1_BAR,
                                              IDR_SIGNAL_2_BAR, IDR_SIGNAL_3_BAR,
                                              IDR_SIGNAL_4_BAR};
+const int kSignalStrengthLevelImageSelectedIds[5] = {
+    IDR_SIGNAL_0_BAR_SELECTED, IDR_SIGNAL_1_BAR_SELECTED,
+    IDR_SIGNAL_2_BAR_SELECTED, IDR_SIGNAL_3_BAR_SELECTED,
+    IDR_SIGNAL_4_BAR_SELECTED};
 
 // Creates a label with |text|.
 base::scoped_nsobject<NSTextField> CreateLabel(NSString* text) {
@@ -75,6 +79,7 @@
   [label setSelectable:NO];
   [label setStringValue:text];
   [label setFont:[NSFont systemFontOfSize:[NSFont systemFontSize]]];
+  [label setTextColor:[NSColor blackColor]];
   [label sizeToFit];
   return label;
 }
@@ -298,12 +303,13 @@
   // be adjusted by one.
   NSInteger idx = static_cast<NSInteger>(index);
   NSInteger selected_row = [table_view_ selectedRow];
-  if (selected_row == idx)
+  if (selected_row == idx) {
     [table_view_ deselectRow:idx];
-  else if (selected_row > idx)
+  } else if (selected_row > idx) {
     [table_view_
             selectRowIndexes:[NSIndexSet indexSetWithIndex:selected_row - 1]
         byExtendingSelection:NO];
+  }
 
   UpdateTableView();
 }
@@ -805,6 +811,50 @@
   chooserController_->OpenHelpCenterUrl();
 }
 
+- (void)updateContentRowColor {
+  NSInteger selectedRow = [tableView_ selectedRow];
+  NSInteger numOptions =
+      base::checked_cast<NSInteger>(chooserController_->NumOptions());
+  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+  for (NSInteger rowIndex = 0; rowIndex < numOptions; ++rowIndex) {
+    // Update the color of the text.
+    [[self tableRowViewText:rowIndex]
+        setTextColor:(rowIndex == selectedRow ? [NSColor whiteColor]
+                                              : [NSColor blackColor])];
+
+    // Update the color of the image.
+    if (chooserController_->ShouldShowIconBeforeText()) {
+      if (chooserController_->IsConnected(rowIndex)) {
+        [[self tableRowViewImage:rowIndex]
+            setImage:gfx::NSImageFromImageSkia(gfx::CreateVectorIcon(
+                         gfx::VectorIconId::BLUETOOTH_CONNECTED,
+                         rowIndex == selectedRow ? SK_ColorWHITE
+                                                 : gfx::kChromeIconGrey))];
+      } else {
+        int signalStrengthLevel =
+            chooserController_->GetSignalStrengthLevel(rowIndex);
+        if (signalStrengthLevel != -1) {
+          int imageId =
+              rowIndex == selectedRow
+                  ? kSignalStrengthLevelImageSelectedIds[signalStrengthLevel]
+                  : kSignalStrengthLevelImageIds[signalStrengthLevel];
+          [[self tableRowViewImage:rowIndex]
+              setImage:rb.GetNativeImageNamed(imageId).ToNSImage()];
+        }
+      }
+    }
+
+    // Update the color of paired status.
+    NSTextField* pairedStatusText = [self tableRowViewPairedStatus:rowIndex];
+    if (pairedStatusText) {
+      [pairedStatusText
+          setTextColor:(skia::SkColorToCalibratedNSColor(
+                           rowIndex == selectedRow ? gfx::kGoogleGreen300
+                                                   : gfx::kGoogleGreen700))];
+    }
+  }
+}
+
 - (NSImageView*)tableRowViewImage:(NSInteger)row {
   ChooserContentTableRowView* tableRowView =
       [tableView_ viewAtColumn:0 row:row makeIfNecessary:YES];
diff --git a/chrome/browser/ui/cocoa/extensions/chooser_dialog_cocoa_controller.mm b/chrome/browser/ui/cocoa/extensions/chooser_dialog_cocoa_controller.mm
index 535dc76..4b26f17 100644
--- a/chrome/browser/ui/cocoa/extensions/chooser_dialog_cocoa_controller.mm
+++ b/chrome/browser/ui/cocoa/extensions/chooser_dialog_cocoa_controller.mm
@@ -62,6 +62,7 @@
 }
 
 - (void)tableViewSelectionDidChange:(NSNotification*)aNotification {
+  [chooserContentView_ updateContentRowColor];
   [connectButton_ setEnabled:[tableView_ numberOfSelectedRows] > 0];
 }
 
diff --git a/chrome/browser/ui/cocoa/extensions/chooser_dialog_cocoa_controller_unittest.mm b/chrome/browser/ui/cocoa/extensions/chooser_dialog_cocoa_controller_unittest.mm
index 683a744..a4ccce7 100644
--- a/chrome/browser/ui/cocoa/extensions/chooser_dialog_cocoa_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/extensions/chooser_dialog_cocoa_controller_unittest.mm
@@ -17,6 +17,7 @@
 #import "chrome/browser/ui/cocoa/extensions/chooser_dialog_cocoa.h"
 #include "chrome/browser/ui/cocoa/spinner_view.h"
 #include "chrome/grit/generated_resources.h"
+#include "skia/ext/skia_utils_mac.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
@@ -35,6 +36,10 @@
 const int kSignalStrengthLevelImageIds[5] = {IDR_SIGNAL_0_BAR, IDR_SIGNAL_1_BAR,
                                              IDR_SIGNAL_2_BAR, IDR_SIGNAL_3_BAR,
                                              IDR_SIGNAL_4_BAR};
+const int kSignalStrengthLevelImageSelectedIds[5] = {
+    IDR_SIGNAL_0_BAR_SELECTED, IDR_SIGNAL_1_BAR_SELECTED,
+    IDR_SIGNAL_2_BAR_SELECTED, IDR_SIGNAL_3_BAR_SELECTED,
+    IDR_SIGNAL_4_BAR_SELECTED};
 
 }  // namespace
 
@@ -89,24 +94,27 @@
   }
 
   void ExpectSignalStrengthLevelImageIs(int row,
-                                        int expected_signal_strength_level) {
+                                        int expected_signal_strength_level,
+                                        int expected_color) {
     NSImageView* image_view =
         [chooser_content_view_ tableRowViewImage:static_cast<NSInteger>(row)];
     ASSERT_TRUE(image_view);
-    EXPECT_NSEQ(
-        rb_.GetNativeImageNamed(
-               kSignalStrengthLevelImageIds[expected_signal_strength_level])
-            .ToNSImage(),
-        [image_view image]);
+    int image_id =
+        expected_color == MockChooserController::kImageColorUnselected
+            ? kSignalStrengthLevelImageIds[expected_signal_strength_level]
+            : kSignalStrengthLevelImageSelectedIds
+                  [expected_signal_strength_level];
+    EXPECT_NSEQ(rb_.GetNativeImageNamed(image_id).ToNSImage(),
+                [image_view image]);
   }
 
-  void ExpectRowImageIsConnectedImage(int row) {
+  void ExpectRowImageIsConnectedImage(int row, SkColor expected_color) {
     NSImageView* image_view =
         [chooser_content_view_ tableRowViewImage:static_cast<NSInteger>(row)];
     ASSERT_TRUE(image_view);
     EXPECT_TRUE(gfx::test::AreImagesEqual(
         gfx::Image(gfx::CreateVectorIcon(gfx::VectorIconId::BLUETOOTH_CONNECTED,
-                                         gfx::kChromeIconGrey)),
+                                         expected_color)),
         gfx::Image([[image_view image] copy])));
   }
 
@@ -116,6 +124,12 @@
                     tableRowViewText:static_cast<NSInteger>(row)] stringValue]);
   }
 
+  void ExpectRowTextColorIs(int row, NSColor* expected_color) {
+    EXPECT_NSEQ(expected_color,
+                [[chooser_content_view_
+                    tableRowViewText:static_cast<NSInteger>(row)] textColor]);
+  }
+
   bool IsRowPaired(int row) {
     NSTextField* paired_status = [chooser_content_view_
         tableRowViewPairedStatus:static_cast<NSInteger>(row)];
@@ -128,6 +142,13 @@
     }
   }
 
+  void ExpectPairedTextColorIs(int row, NSColor* expected_color) {
+    EXPECT_NSEQ(
+        expected_color,
+        [[chooser_content_view_
+            tableRowViewPairedStatus:static_cast<NSInteger>(row)] textColor]);
+  }
+
   ui::ResourceBundle& rb_;
 
   std::unique_ptr<ChooserDialogCocoa> chooser_dialog_;
@@ -182,7 +203,7 @@
   // |table_view_| should be enabled since there is an option.
   EXPECT_TRUE(table_view_.enabled);
   EXPECT_EQ(-1, table_view_.selectedRow);
-  ExpectRowImageIsConnectedImage(0);
+  ExpectRowImageIsConnectedImage(0, gfx::kChromeIconGrey);
   ExpectRowTextIs(0, @"a");
   EXPECT_TRUE(IsRowPaired(0));
   EXPECT_FALSE(connect_button_.enabled);
@@ -197,7 +218,8 @@
   EXPECT_TRUE(table_view_.enabled);
   EXPECT_EQ(-1, table_view_.selectedRow);
   ExpectSignalStrengthLevelImageIs(
-      1, MockChooserController::kSignalStrengthLevel0Bar);
+      1, MockChooserController::kSignalStrengthLevel0Bar,
+      MockChooserController::kImageColorUnselected);
   ExpectRowTextIs(1, @"b");
   EXPECT_FALSE(IsRowPaired(1));
 
@@ -209,7 +231,8 @@
   EXPECT_TRUE(table_view_.enabled);
   EXPECT_EQ(-1, table_view_.selectedRow);
   ExpectSignalStrengthLevelImageIs(
-      2, MockChooserController::kSignalStrengthLevel1Bar);
+      2, MockChooserController::kSignalStrengthLevel1Bar,
+      MockChooserController::kImageColorUnselected);
   ExpectRowTextIs(2, @"c");
   EXPECT_FALSE(IsRowPaired(2));
 
@@ -217,7 +240,8 @@
       base::ASCIIToUTF16("d"), MockChooserController::kSignalStrengthLevel2Bar,
       MockChooserController::ConnectedPairedStatus::NONE);
   ExpectSignalStrengthLevelImageIs(
-      3, MockChooserController::kSignalStrengthLevel2Bar);
+      3, MockChooserController::kSignalStrengthLevel2Bar,
+      MockChooserController::kImageColorUnselected);
   ExpectRowTextIs(3, @"d");
   EXPECT_FALSE(IsRowPaired(3));
 
@@ -225,7 +249,8 @@
       base::ASCIIToUTF16("e"), MockChooserController::kSignalStrengthLevel3Bar,
       MockChooserController::ConnectedPairedStatus::NONE);
   ExpectSignalStrengthLevelImageIs(
-      4, MockChooserController::kSignalStrengthLevel3Bar);
+      4, MockChooserController::kSignalStrengthLevel3Bar,
+      MockChooserController::kImageColorUnselected);
   ExpectRowTextIs(4, @"e");
   EXPECT_FALSE(IsRowPaired(4));
 
@@ -233,7 +258,8 @@
       base::ASCIIToUTF16("f"), MockChooserController::kSignalStrengthLevel4Bar,
       MockChooserController::ConnectedPairedStatus::NONE);
   ExpectSignalStrengthLevelImageIs(
-      5, MockChooserController::kSignalStrengthLevel4Bar);
+      5, MockChooserController::kSignalStrengthLevel4Bar,
+      MockChooserController::kImageColorUnselected);
   ExpectRowTextIs(5, @"f");
   EXPECT_FALSE(IsRowPaired(5));
 }
@@ -258,11 +284,12 @@
   EXPECT_EQ(1, table_view_.numberOfColumns);
   EXPECT_TRUE(table_view_.enabled);
   EXPECT_EQ(-1, table_view_.selectedRow);
-  ExpectRowImageIsConnectedImage(0);
+  ExpectRowImageIsConnectedImage(0, gfx::kChromeIconGrey);
   ExpectRowTextIs(0, @"a");
   EXPECT_TRUE(IsRowPaired(0));
   ExpectSignalStrengthLevelImageIs(
-      1, MockChooserController::kSignalStrengthLevel1Bar);
+      1, MockChooserController::kSignalStrengthLevel1Bar,
+      MockChooserController::kImageColorUnselected);
   ExpectRowTextIs(1, @"c");
   EXPECT_FALSE(IsRowPaired(1));
 
@@ -321,14 +348,15 @@
   EXPECT_EQ(1, table_view_.numberOfColumns);
   EXPECT_TRUE(table_view_.enabled);
   EXPECT_EQ(-1, table_view_.selectedRow);
-  ExpectRowImageIsConnectedImage(0);
+  ExpectRowImageIsConnectedImage(0, gfx::kChromeIconGrey);
   ExpectRowTextIs(0, @"a");
   EXPECT_TRUE(IsRowPaired(0));
-  ExpectRowImageIsConnectedImage(1);
+  ExpectRowImageIsConnectedImage(1, gfx::kChromeIconGrey);
   ExpectRowTextIs(1, @"d");
   EXPECT_TRUE(IsRowPaired(1));
   ExpectSignalStrengthLevelImageIs(
-      2, MockChooserController::kSignalStrengthLevel1Bar);
+      2, MockChooserController::kSignalStrengthLevel1Bar,
+      MockChooserController::kImageColorUnselected);
   ExpectRowTextIs(2, @"c");
   EXPECT_FALSE(IsRowPaired(2));
 }
@@ -389,15 +417,173 @@
   EXPECT_EQ(1, table_view_.numberOfColumns);
   EXPECT_TRUE(table_view_.enabled);
   EXPECT_EQ(-1, table_view_.selectedRow);
-  ExpectRowImageIsConnectedImage(0);
+  ExpectRowImageIsConnectedImage(0, gfx::kChromeIconGrey);
   ExpectRowTextIs(0, @"a");
   EXPECT_TRUE(IsRowPaired(0));
   ExpectSignalStrengthLevelImageIs(
-      1, MockChooserController::kSignalStrengthLevel1Bar);
+      1, MockChooserController::kSignalStrengthLevel1Bar,
+      MockChooserController::kImageColorUnselected);
   ExpectRowTextIs(1, @"c");
   EXPECT_FALSE(IsRowPaired(1));
 }
 
+TEST_F(ChooserDialogCocoaControllerTest,
+       RowImageAndTextChangeColorWhenSelectionChanges) {
+  CreateChooserDialog();
+
+  mock_chooser_controller_->OptionAdded(
+      base::ASCIIToUTF16("a"),
+      MockChooserController::kNoSignalStrengthLevelImage,
+      MockChooserController::ConnectedPairedStatus::CONNECTED |
+          MockChooserController::ConnectedPairedStatus::PAIRED);
+  mock_chooser_controller_->OptionAdded(
+      base::ASCIIToUTF16("b"), MockChooserController::kSignalStrengthLevel0Bar,
+      MockChooserController::ConnectedPairedStatus::NONE);
+  mock_chooser_controller_->OptionAdded(
+      base::ASCIIToUTF16("c"), MockChooserController::kSignalStrengthLevel1Bar,
+      MockChooserController::ConnectedPairedStatus::NONE);
+
+  ExpectRowImageIsConnectedImage(0, gfx::kChromeIconGrey);
+  ExpectSignalStrengthLevelImageIs(
+      1, MockChooserController::kSignalStrengthLevel0Bar,
+      MockChooserController::kImageColorUnselected);
+  ExpectSignalStrengthLevelImageIs(
+      2, MockChooserController::kSignalStrengthLevel1Bar,
+      MockChooserController::kImageColorUnselected);
+  ExpectRowTextColorIs(0, [NSColor blackColor]);
+  ExpectRowTextColorIs(1, [NSColor blackColor]);
+  ExpectRowTextColorIs(2, [NSColor blackColor]);
+  ExpectPairedTextColorIs(
+      0, skia::SkColorToCalibratedNSColor(gfx::kGoogleGreen700));
+
+  // Option 0 shows a Bluetooth connected image, the following code tests the
+  // color of that image and text change when the option is selected or
+  // deselected.
+  // Select option 0.
+  [table_view_ selectRowIndexes:[NSIndexSet indexSetWithIndex:0]
+           byExtendingSelection:NO];
+  EXPECT_EQ(0, table_view_.selectedRow);
+  ExpectRowImageIsConnectedImage(0, SK_ColorWHITE);
+  ExpectSignalStrengthLevelImageIs(
+      1, MockChooserController::kSignalStrengthLevel0Bar,
+      MockChooserController::kImageColorUnselected);
+  ExpectSignalStrengthLevelImageIs(
+      2, MockChooserController::kSignalStrengthLevel1Bar,
+      MockChooserController::kImageColorUnselected);
+  ExpectRowTextColorIs(0, [NSColor whiteColor]);
+  ExpectRowTextColorIs(1, [NSColor blackColor]);
+  ExpectRowTextColorIs(2, [NSColor blackColor]);
+  ExpectPairedTextColorIs(
+      0, skia::SkColorToCalibratedNSColor(gfx::kGoogleGreen300));
+
+  // Deselect option 0.
+  [table_view_ deselectRow:0];
+  EXPECT_EQ(-1, table_view_.selectedRow);
+  ExpectRowImageIsConnectedImage(0, gfx::kChromeIconGrey);
+  ExpectSignalStrengthLevelImageIs(
+      1, MockChooserController::kSignalStrengthLevel0Bar,
+      MockChooserController::kImageColorUnselected);
+  ExpectSignalStrengthLevelImageIs(
+      2, MockChooserController::kSignalStrengthLevel1Bar,
+      MockChooserController::kImageColorUnselected);
+  ExpectRowTextColorIs(0, [NSColor blackColor]);
+  ExpectRowTextColorIs(1, [NSColor blackColor]);
+  ExpectRowTextColorIs(2, [NSColor blackColor]);
+  ExpectPairedTextColorIs(
+      0, skia::SkColorToCalibratedNSColor(gfx::kGoogleGreen700));
+
+  // Option 1 shows a signal strengh level image, the following code tests the
+  // color of that image and text change when the option is selected or
+  // deselected.
+  // Select option 1.
+  [table_view_ selectRowIndexes:[NSIndexSet indexSetWithIndex:1]
+           byExtendingSelection:NO];
+  EXPECT_EQ(1, table_view_.selectedRow);
+  ExpectRowImageIsConnectedImage(0, gfx::kChromeIconGrey);
+  ExpectSignalStrengthLevelImageIs(
+      1, MockChooserController::kSignalStrengthLevel0Bar,
+      MockChooserController::kImageColorSelected);
+  ExpectSignalStrengthLevelImageIs(
+      2, MockChooserController::kSignalStrengthLevel1Bar,
+      MockChooserController::kImageColorUnselected);
+  ExpectRowTextColorIs(0, [NSColor blackColor]);
+  ExpectRowTextColorIs(1, [NSColor whiteColor]);
+  ExpectRowTextColorIs(2, [NSColor blackColor]);
+  ExpectPairedTextColorIs(
+      0, skia::SkColorToCalibratedNSColor(gfx::kGoogleGreen700));
+
+  // Deselect option 1.
+  [table_view_ deselectRow:1];
+  EXPECT_EQ(-1, table_view_.selectedRow);
+  ExpectRowImageIsConnectedImage(0, gfx::kChromeIconGrey);
+  ExpectSignalStrengthLevelImageIs(
+      1, MockChooserController::kSignalStrengthLevel0Bar,
+      MockChooserController::kImageColorUnselected);
+  ExpectSignalStrengthLevelImageIs(
+      2, MockChooserController::kSignalStrengthLevel1Bar,
+      MockChooserController::kImageColorUnselected);
+  ExpectRowTextColorIs(0, [NSColor blackColor]);
+  ExpectRowTextColorIs(1, [NSColor blackColor]);
+  ExpectRowTextColorIs(2, [NSColor blackColor]);
+  ExpectPairedTextColorIs(
+      0, skia::SkColorToCalibratedNSColor(gfx::kGoogleGreen700));
+
+  // The following code tests the color of the image and text change when
+  // selecting another option without deselecting the first.
+  // Select option 0.
+  [table_view_ selectRowIndexes:[NSIndexSet indexSetWithIndex:0]
+           byExtendingSelection:NO];
+
+  // Select option 1.
+  [table_view_ selectRowIndexes:[NSIndexSet indexSetWithIndex:1]
+           byExtendingSelection:NO];
+  EXPECT_EQ(1, table_view_.selectedRow);
+  ExpectRowImageIsConnectedImage(0, gfx::kChromeIconGrey);
+  ExpectSignalStrengthLevelImageIs(
+      1, MockChooserController::kSignalStrengthLevel0Bar,
+      MockChooserController::kImageColorSelected);
+  ExpectSignalStrengthLevelImageIs(
+      2, MockChooserController::kSignalStrengthLevel1Bar,
+      MockChooserController::kImageColorUnselected);
+  ExpectRowTextColorIs(0, [NSColor blackColor]);
+  ExpectRowTextColorIs(1, [NSColor whiteColor]);
+  ExpectRowTextColorIs(2, [NSColor blackColor]);
+  ExpectPairedTextColorIs(
+      0, skia::SkColorToCalibratedNSColor(gfx::kGoogleGreen700));
+
+  // The following code tests the color of the image and text of a selected
+  // option when it is updated.
+  // Select option 2.
+  [table_view_ selectRowIndexes:[NSIndexSet indexSetWithIndex:2]
+           byExtendingSelection:NO];
+
+  // Update option 2 from one signal strength to another.
+  mock_chooser_controller_->OptionUpdated(
+      base::ASCIIToUTF16("c"), base::ASCIIToUTF16("e"),
+      MockChooserController::kSignalStrengthLevel2Bar,
+      MockChooserController::ConnectedPairedStatus::NONE);
+  ExpectSignalStrengthLevelImageIs(
+      2, MockChooserController::kSignalStrengthLevel2Bar,
+      MockChooserController::kImageColorSelected);
+  ExpectRowTextColorIs(0, [NSColor blackColor]);
+  ExpectRowTextColorIs(1, [NSColor blackColor]);
+  ExpectRowTextColorIs(2, [NSColor whiteColor]);
+
+  // Update option 2 again from non-connected and non-paired to connected
+  // and paired.
+  mock_chooser_controller_->OptionUpdated(
+      base::ASCIIToUTF16("e"), base::ASCIIToUTF16("f"),
+      MockChooserController::kNoSignalStrengthLevelImage,
+      MockChooserController::ConnectedPairedStatus::CONNECTED |
+          MockChooserController::ConnectedPairedStatus::PAIRED);
+  ExpectRowImageIsConnectedImage(2, SK_ColorWHITE);
+  ExpectRowTextColorIs(0, [NSColor blackColor]);
+  ExpectRowTextColorIs(1, [NSColor blackColor]);
+  ExpectRowTextColorIs(2, [NSColor whiteColor]);
+  ExpectPairedTextColorIs(
+      2, skia::SkColorToCalibratedNSColor(gfx::kGoogleGreen300));
+}
+
 TEST_F(ChooserDialogCocoaControllerTest, SelectAndDeselectAnOption) {
   CreateChooserDialog();
 
@@ -567,14 +753,15 @@
           MockChooserController::ConnectedPairedStatus::PAIRED);
 
   EXPECT_EQ(1, table_view_.selectedRow);
-  ExpectRowImageIsConnectedImage(0);
+  ExpectRowImageIsConnectedImage(0, gfx::kChromeIconGrey);
   ExpectRowTextIs(0, @"a");
   EXPECT_TRUE(IsRowPaired(0));
-  ExpectRowImageIsConnectedImage(1);
+  ExpectRowImageIsConnectedImage(1, SK_ColorWHITE);
   ExpectRowTextIs(1, @"d");
   EXPECT_TRUE(IsRowPaired(1));
   ExpectSignalStrengthLevelImageIs(
-      2, MockChooserController::kSignalStrengthLevel1Bar);
+      2, MockChooserController::kSignalStrengthLevel1Bar,
+      MockChooserController::kImageColorUnselected);
   ExpectRowTextIs(2, @"c");
   EXPECT_FALSE(IsRowPaired(2));
   EXPECT_TRUE(connect_button_.enabled);
@@ -855,7 +1042,8 @@
   // No option selected.
   EXPECT_EQ(-1, table_view_.selectedRow);
   ExpectSignalStrengthLevelImageIs(
-      0, MockChooserController::kSignalStrengthLevel2Bar);
+      0, MockChooserController::kSignalStrengthLevel2Bar,
+      MockChooserController::kImageColorUnselected);
   ExpectRowTextIs(0, @"d");
   EXPECT_FALSE(IsRowPaired(0));
   EXPECT_TRUE(spinner_.hidden);
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm
index 2b68af5..13df962 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm
@@ -400,13 +400,11 @@
 
   // Allow the ToolbarController to take action upon the
   // AutocompleteTextField being added to the window.
-  if (ui::MaterialDesignController::IsModeMaterial()) {
-    BrowserWindowController* browserWindowController =
-        [BrowserWindowController browserWindowControllerForView:self];
-    [[browserWindowController toolbarController] locationBarWasAddedToWindow];
+  BrowserWindowController* browserWindowController =
+      [BrowserWindowController browserWindowControllerForView:self];
+  [[browserWindowController toolbarController] locationBarWasAddedToWindow];
 
-    [self updateColorsToMatchTheme];
-  }
+  [self updateColorsToMatchTheme];
 
   NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
   [nc addObserver:self
@@ -552,10 +550,6 @@
 // ThemedWindowDrawing implementation.
 
 - (void)windowDidChangeTheme {
-  if (!ui::MaterialDesignController::IsModeMaterial()) {
-    return;
-  }
-
   [self updateColorsToMatchTheme];
 }
 
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm
index c3f1902..9a1a707f 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm
@@ -32,28 +32,11 @@
 // How far to inset the left- and right-hand decorations from the field's
 // bounds.
 const CGFloat kRightDecorationXOffset = 5.0;
-CGFloat LeftDecorationXOffset() {
-  const CGFloat kLeftDecorationXOffset = 5.0;
-  const CGFloat kLeftMaterialDecorationXOffset = 6.0;
-  return ui::MaterialDesignController::IsModeMaterial()
-             ? kLeftMaterialDecorationXOffset
-             : kLeftDecorationXOffset;
-}
+const CGFloat kLeftDecorationXOffset = 6.0;
 
 // The amount of padding on either side reserved for drawing
 // decorations.  [Views has |kItemPadding| == 3.]
-CGFloat DecorationsHorizontalPad() {
-  const CGFloat kDecorationHorizontalPad = 3.0;
-  const CGFloat kMaterialDecorationHorizontalPad = 4.0;
-  return ui::MaterialDesignController::IsModeMaterial()
-      ? kMaterialDecorationHorizontalPad
-      : kDecorationHorizontalPad;
-}
-
-const ui::NinePartImageIds kPopupBorderImageIds =
-    IMAGE_GRID(IDR_OMNIBOX_POPUP_BORDER_AND_SHADOW);
-
-const ui::NinePartImageIds kNormalBorderImageIds = IMAGE_GRID(IDR_TEXTFIELD);
+const CGFloat kDecorationHorizontalPad = 4.0;
 
 // How long to wait for mouse-up on the location icon before assuming
 // that the user wants to drag.
@@ -83,7 +66,6 @@
   // The initial padding depends on whether the first visible decoration is
   // a button or not.
   bool is_first_visible_decoration = true;
-  const CGFloat kDecorationHorizontalPad = DecorationsHorizontalPad();
 
   for (size_t i = 0; i < all_decorations.size(); ++i) {
     if (all_decorations[i]->IsVisible()) {
@@ -147,7 +129,7 @@
 
   // Layout |left_decorations| against the LHS.
   CalculatePositionsHelper(frame, left_decorations, NSMinXEdge,
-                           LeftDecorationXOffset(), decorations,
+                           kLeftDecorationXOffset, decorations,
                            decoration_frames, &frame);
   DCHECK_EQ(decorations->size(), decoration_frames->size());
 
@@ -263,11 +245,9 @@
   // after computing decoration positions because the decorations are already
   // correctly positioned. The spec also calls for positioning the text 1pt to
   // the right of its default position.
-  if (ui::MaterialDesignController::IsModeMaterial()) {
-    textFrame.origin.x += 1;
-    textFrame.size.width -= 1;
-    textFrame.origin.y -= singlePixelLineWidth_;
-  }
+  textFrame.origin.x += 1;
+  textFrame.size.width -= 1;
+  textFrame.origin.y -= singlePixelLineWidth_;
 
   // NOTE: This function must closely match the logic in
   // |-drawInteriorWithFrame:inView:|.
@@ -285,7 +265,6 @@
 
   // Determine the left-most extent for the i-beam cursor.
   CGFloat minX = NSMinX(textFrame);
-  const CGFloat kDecorationHorizontalPad = DecorationsHorizontalPad();
   for (size_t index = left_count; index--; ) {
     if (decorations[index]->AcceptsMousePress())
       break;
@@ -317,16 +296,13 @@
 }
 
 - (void)drawWithFrame:(NSRect)frame inView:(NSView*)controlView {
-  BOOL isModeMaterial = ui::MaterialDesignController::IsModeMaterial();
   BOOL inDarkMode = [[controlView window] inIncognitoModeWithSystemTheme];
   BOOL showingFirstResponder = [self showsFirstResponder];
   // Adjust the inset by 1/2 the line width to get a crisp line (screen pixels
   // lay between cooridnate space lines).
   CGFloat insetSize = 1 - singlePixelLineWidth_ / 2.;
-  if (isModeMaterial && showingFirstResponder && !inDarkMode) {
+  if (showingFirstResponder && !inDarkMode) {
     insetSize++;
-  } else if (!isModeMaterial) {
-    insetSize = singlePixelLineWidth_ == 0.5 ? 1.5 : 2.0;
   }
 
   // Compute the border's bezier path.
@@ -335,10 +311,8 @@
       [NSBezierPath bezierPathWithRoundedRect:pathRect
                                       xRadius:kCornerRadius
                                       yRadius:kCornerRadius];
-  if (isModeMaterial) {
-    [path setLineWidth:showingFirstResponder ? singlePixelLineWidth_ * 2
-                                             : singlePixelLineWidth_];
-  }
+  [path setLineWidth:showingFirstResponder ? singlePixelLineWidth_ * 2
+                                           : singlePixelLineWidth_];
 
   // Fill the background.
   [[self backgroundColor] set];
@@ -349,23 +323,14 @@
   }
 
   // Draw the border.
-  if (isModeMaterial) {
-    if (!inDarkMode) {
-      const CGFloat kNormalStrokeGray = 168 / 255.;
-      [[NSColor colorWithCalibratedWhite:kNormalStrokeGray alpha:1] set];
-    } else {
-      const CGFloat k30PercentAlpha = 0.3;
-      [[NSColor colorWithCalibratedWhite:0 alpha:k30PercentAlpha] set];
-    }
-    [path stroke];
+  if (!inDarkMode) {
+    const CGFloat kNormalStrokeGray = 168 / 255.;
+    [[NSColor colorWithCalibratedWhite:kNormalStrokeGray alpha:1] set];
   } else {
-    ui::DrawNinePartImage(frame,
-                          isPopupMode_ ? kPopupBorderImageIds
-                                       : kNormalBorderImageIds,
-                          NSCompositeSourceOver,
-                          1.0,
-                          true);
+    const CGFloat k30PercentAlpha = 0.3;
+    [[NSColor colorWithCalibratedWhite:0 alpha:k30PercentAlpha] set];
   }
+  [path stroke];
 
   // Draw the interior contents. We do this after drawing the border as some
   // of the interior controls draw over it.
@@ -373,17 +338,8 @@
 
   // Draw the focus ring.
   if (showingFirstResponder) {
-    if (!isModeMaterial) {
-      NSRect focusRingRect =
-          NSInsetRect(frame, singlePixelLineWidth_, singlePixelLineWidth_);
-      path = [NSBezierPath bezierPathWithRoundedRect:focusRingRect
-                                             xRadius:kCornerRadius
-                                             yRadius:kCornerRadius];
-      [path setLineWidth:singlePixelLineWidth_ * 2.0];
-    }
-
     CGFloat alphaComponent = 0.5 / singlePixelLineWidth_;
-    if (isModeMaterial && inDarkMode) {
+    if (inDarkMode) {
       // Special focus color for Material Incognito.
       [[NSColor colorWithSRGBRed:123 / 255.
                            green:170 / 255.
@@ -406,7 +362,6 @@
                             &decorations, &decorationFrames, &workingFrame);
 
   // Draw the decorations.
-  const CGFloat kDecorationHorizontalPad = DecorationsHorizontalPad();
   for (size_t i = 0; i < decorations.size(); ++i) {
     if (decorations[i]) {
       NSRect background_frame = NSInsetRect(
@@ -431,7 +386,7 @@
       [controlView convertPoint:location fromView:nil];
 
   // If we have decorations, the drop can't occur at their horizontal padding.
-  if (!leftDecorations_.empty() && locationInView.x < LeftDecorationXOffset())
+  if (!leftDecorations_.empty() && locationInView.x < kLeftDecorationXOffset)
     return false;
 
   if (!rightDecorations_.empty() &&
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm
index 2edcbce..5d7520e 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm
@@ -165,11 +165,7 @@
   textFrame = [cell textFrameForFrame:bounds];
   EXPECT_FALSE(NSIsEmptyRect(textFrame));
   EXPECT_TRUE(NSContainsRect(bounds, textFrame));
-  if (ui::MaterialDesignController::IsModeMaterial()) {
-    EXPECT_EQ(1, NSMinX(textFrame));
-  } else {
-    EXPECT_EQ(NSMinX(bounds), NSMinX(textFrame));
-  }
+  EXPECT_EQ(1, NSMinX(textFrame));
   EXPECT_EQ(NSMaxX(bounds), NSMaxX(textFrame));
   EXPECT_TRUE(NSContainsRect(cursorFrame, textFrame));
 
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.mm
index b4f6d71e..83126cf 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.mm
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.mm
@@ -107,8 +107,8 @@
 }
 
 - (void)viewDidMoveToWindow {
-  // Only care about landing in a window when in Material Design mode.
-  if ([self window] && ui::MaterialDesignController::IsModeMaterial()) {
+  // Only care about landing in a window.
+  if ([self window]) {
     [self updateColorsToMatchTheme];
   }
 }
@@ -604,9 +604,6 @@
 // ThemedWindowDrawing implementation.
 
 - (void)windowDidChangeTheme {
-  if (!ui::MaterialDesignController::IsModeMaterial()) {
-    return;
-  }
   [self updateColorsToMatchTheme];
 }
 
diff --git a/chrome/browser/ui/cocoa/location_bar/bubble_decoration.mm b/chrome/browser/ui/cocoa/location_bar/bubble_decoration.mm
index dbc6c5b..ed332a3 100644
--- a/chrome/browser/ui/cocoa/location_bar/bubble_decoration.mm
+++ b/chrome/browser/ui/cocoa/location_bar/bubble_decoration.mm
@@ -20,15 +20,13 @@
 const CGFloat kRightSideMargin = 1.0;
 
 // Padding between the icon/label and bubble edges.
-CGFloat BubblePadding() {
-  return ui::MaterialDesignController::IsModeMaterial() ? 8.0 : 3.0;
-}
+const CGFloat kBubblePadding = 8.0;
 
 // Additional padding between the divider and the label.
 const CGFloat kDividerPadding = 2.0;
 
 // Padding between the icon and label.
-CGFloat kIconLabelPadding = 4.0;
+const CGFloat kIconLabelPadding = 4.0;
 
 // Inset for the background.
 const CGFloat kBackgroundYInset = 4.0;
@@ -45,7 +43,7 @@
 }
 
 CGFloat BubbleDecoration::DividerPadding() const {
-  return ui::MaterialDesignController::IsModeMaterial() ? kDividerPadding : 0.0;
+  return kDividerPadding;
 }
 
 CGFloat BubbleDecoration::GetWidthForImageAndLabel(NSImage* image,
@@ -55,14 +53,14 @@
 
   const CGFloat image_width = image ? [image size].width : 0.0;
   if (!label)
-    return BubblePadding() + image_width;
+    return kBubblePadding + image_width;
 
   // The bubble needs to take up an integral number of pixels.
   // Generally -sizeWithAttributes: seems to overestimate rather than
   // underestimate, so floor() seems to work better.
   const CGFloat label_width =
       std::floor([label sizeWithAttributes:attributes_].width);
-  return BubblePadding() + image_width + kIconLabelPadding + label_width +
+  return kBubblePadding + image_width + kIconLabelPadding + label_width +
          DividerPadding();
 }
 
@@ -115,22 +113,20 @@
   }
 
   // Draw the divider and set the text color.
-  if (ui::MaterialDesignController::IsModeMaterial()) {
-    NSBezierPath* line = [NSBezierPath bezierPath];
-    [line setLineWidth:1];
-    [line moveToPoint:NSMakePoint(NSMaxX(decoration_frame) - DividerPadding(),
-                                  NSMinY(decoration_frame))];
-    [line lineToPoint:NSMakePoint(NSMaxX(decoration_frame) - DividerPadding(),
-                                  NSMaxY(decoration_frame))];
+  NSBezierPath* line = [NSBezierPath bezierPath];
+  [line setLineWidth:1];
+  [line moveToPoint:NSMakePoint(NSMaxX(decoration_frame) - DividerPadding(),
+                                NSMinY(decoration_frame))];
+  [line lineToPoint:NSMakePoint(NSMaxX(decoration_frame) - DividerPadding(),
+                                NSMaxY(decoration_frame))];
 
-    bool in_dark_mode = [[control_view window] inIncognitoModeWithSystemTheme];
-    [GetDividerColor(in_dark_mode) set];
-    [line stroke];
+  bool in_dark_mode = [[control_view window] inIncognitoModeWithSystemTheme];
+  [GetDividerColor(in_dark_mode) set];
+  [line stroke];
 
-    NSColor* text_color =
-        in_dark_mode ? GetDarkModeTextColor() : GetBackgroundBorderColor();
-    SetTextColor(text_color);
-  }
+  NSColor* text_color =
+      in_dark_mode ? GetDarkModeTextColor() : GetBackgroundBorderColor();
+  SetTextColor(text_color);
 
   if (label_) {
     NSRect text_rect = frame;
@@ -154,11 +150,6 @@
                                                  NSView* control_view) {
   NSRect rect = NSInsetRect(background_frame, 0, 1);
   rect.size.width -= kRightSideMargin;
-  if (!ui::MaterialDesignController::IsModeMaterial()) {
-    ui::DrawNinePartImage(
-        rect, GetBubbleImageIds(), NSCompositeSourceOver, 1.0, true);
-  }
-
   DrawInFrame(frame, control_view);
 }
 
diff --git a/chrome/browser/ui/cocoa/location_bar/content_setting_decoration.mm b/chrome/browser/ui/cocoa/location_bar/content_setting_decoration.mm
index 725668f..fd005bf7 100644
--- a/chrome/browser/ui/cocoa/location_bar/content_setting_decoration.mm
+++ b/chrome/browser/ui/cocoa/location_bar/content_setting_decoration.mm
@@ -67,11 +67,7 @@
 // subtracting kBorderPadding from 8px.
 const CGFloat kRightDividerPadding = 8.0;
 const CGFloat kLeftDividerPadding = 5.0;
-CGFloat DividerPadding() {
-  return ui::MaterialDesignController::IsModeMaterial()
-             ? kLeftDividerPadding + kRightDividerPadding
-             : 0.0;
-}
+const CGFloat kDividerPadding = kLeftDividerPadding + kRightDividerPadding;
 
 // Color of the vector graphic icons. Used when the location is not dark.
 // SkColorSetARGB(0xCC, 0xFF, 0xFF 0xFF);
@@ -343,7 +339,7 @@
       preferred_width += kIconMarginPadding + kTextMarginPadding;
 
       // Add the width of the text based on the state of the animation.
-      CGFloat text_width = text_width_ + DividerPadding();
+      CGFloat text_width = text_width_ + kDividerPadding;
       switch (state) {
         case kOpening:
           preferred_width += text_width * kInMotionMultiplier * progress;
@@ -375,13 +371,6 @@
     // this ContentSettingDecoration's DrawInFrame() also draws the background.
     // In short, moving this code upstream to a common parent requires a non-
     // trivial bit of refactoring.
-    if (!ui::MaterialDesignController::IsModeMaterial()) {
-      const ui::NinePartImageIds image_ids =
-          IMAGE_GRID(IDR_OMNIBOX_CONTENT_SETTING_BUBBLE);
-      ui::DrawNinePartImage(
-          background_rect, image_ids, NSCompositeSourceOver, 1.0, true);
-    }
-
     // Draw the icon.
     NSImage* icon = GetImage();
     NSRect icon_rect = background_rect;
@@ -397,18 +386,14 @@
         NSMaxX(background_rect) - NSMinX(remainder) - kLeftDividerPadding;
     DrawAttributedString(animated_text_, remainder);
 
-    if (ui::MaterialDesignController::IsModeMaterial()) {
-      NSBezierPath* line = [NSBezierPath bezierPath];
-      [line setLineWidth:1];
-      [line
-          moveToPoint:NSMakePoint(NSMaxX(background_rect) - kLeftDividerPadding,
+    NSBezierPath* line = [NSBezierPath bezierPath];
+    [line setLineWidth:1];
+    [line moveToPoint:NSMakePoint(NSMaxX(background_rect) - kLeftDividerPadding,
                                   NSMinY(background_rect))];
-      [line
-          lineToPoint:NSMakePoint(NSMaxX(background_rect) - kLeftDividerPadding,
+    [line lineToPoint:NSMakePoint(NSMaxX(background_rect) - kLeftDividerPadding,
                                   NSMaxY(background_rect))];
-      [GetDividerColor(owner_->IsLocationBarDark()) set];
-      [line stroke];
-    }
+    [GetDividerColor(owner_->IsLocationBarDark()) set];
+    [line stroke];
   } else {
     // No animation, draw the image as normal.
     ImageDecoration::DrawInFrame(frame, control_view);
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
index 57617956..15b7d2f 100644
--- a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
+++ b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
@@ -633,11 +633,6 @@
 }
 
 void LocationBarViewMac::UpdateColorsToMatchTheme() {
-  if (!ui::MaterialDesignController::IsModeMaterial() ||
-      ![[field_ window] inIncognitoMode]) {
-    return;
-  }
-
   // Update the location-bar icon.
   UpdateLocationIcon();
 
@@ -660,14 +655,6 @@
 }
 
 void LocationBarViewMac::OnChanged() {
-  if (!ui::MaterialDesignController::IsModeMaterial()) {
-    const int resource_id = omnibox_view_->GetIcon();
-    NSImage* image = OmniboxViewMac::ImageForResource(resource_id);
-    location_icon_decoration_->SetImage(image);
-    security_state_bubble_decoration_->SetImage(image);
-    Layout();
-    return;
-  }
   UpdateSecurityState(false);
   UpdateLocationIcon();
 }
@@ -697,8 +684,7 @@
       security == security_state::SecurityStateModel::DANGEROUS ||
       (IsSecureConnection(security) && should_show_secure_verbose_);
 
-  return ui::MaterialDesignController::IsModeMaterial() &&
-         has_verbose_for_security && !omnibox_view_->IsEditingOrEmpty() &&
+  return has_verbose_for_security && !omnibox_view_->IsEditingOrEmpty() &&
          !omnibox_view_->model()->is_keyword_hint();
 }
 
@@ -715,16 +701,12 @@
         GetOmniboxIcon(template_url->GetExtensionId()).AsNSImage();
   }
 
-  if (ui::MaterialDesignController::IsModeMaterial()) {
-    SkColor icon_color = IsLocationBarDark() ? kMaterialDarkVectorIconColor
-                                             : gfx::kGoogleBlue700;
-    return NSImageFromImageSkiaWithColorSpace(
-        gfx::CreateVectorIcon(gfx::VectorIconId::OMNIBOX_SEARCH,
-                              kDefaultIconSize, icon_color),
-        base::mac::GetSRGBColorSpace());
-  }
-
-  return OmniboxViewMac::ImageForResource(IDR_OMNIBOX_SEARCH);
+  SkColor icon_color =
+      IsLocationBarDark() ? kMaterialDarkVectorIconColor : gfx::kGoogleBlue700;
+  return NSImageFromImageSkiaWithColorSpace(
+      gfx::CreateVectorIcon(gfx::VectorIconId::OMNIBOX_SEARCH, kDefaultIconSize,
+                            icon_color),
+      base::mac::GetSRGBColorSpace());
 }
 
 SkColor LocationBarViewMac::GetLocationBarIconColor() const {
diff --git a/chrome/browser/ui/cocoa/location_bar/manage_passwords_decoration.mm b/chrome/browser/ui/cocoa/location_bar/manage_passwords_decoration.mm
index e29bbbe..76789901 100644
--- a/chrome/browser/ui/cocoa/location_bar/manage_passwords_decoration.mm
+++ b/chrome/browser/ui/cocoa/location_bar/manage_passwords_decoration.mm
@@ -87,10 +87,6 @@
     return;
   }
   SetVisible(true);
-  if (!ui::MaterialDesignController::IsModeMaterial()) {
-    SetImage(OmniboxViewMac::ImageForResource(icon_->icon_id()));
-    return;
-  }
   // |location_bar_| can be NULL in tests.
   bool location_bar_is_dark = location_bar_ &&
       [[location_bar_->GetAutocompleteTextField() window]
diff --git a/chrome/browser/ui/cocoa/location_bar/manage_passwords_decoration_unittest.mm b/chrome/browser/ui/cocoa/location_bar/manage_passwords_decoration_unittest.mm
index b2f8ea4..9b4894bf 100644
--- a/chrome/browser/ui/cocoa/location_bar/manage_passwords_decoration_unittest.mm
+++ b/chrome/browser/ui/cocoa/location_bar/manage_passwords_decoration_unittest.mm
@@ -103,20 +103,14 @@
   EXPECT_EQ(GetParam().visible, decoration()->IsVisible());
   NSImage* expected_image = nil;
   if (GetParam().image) {
-    if (ui::MaterialDesignController::IsModeMaterial()) {
-      // IDR_SAVE_PASSWORD_ACTIVE and IDR_SAVE_PASSWORD_INACTIVE map to
-      // gfx::VectorIconId::AUTOLOGIN in Material Design - fail the test if
-      // somehow some other value is present.
-      EXPECT_TRUE(GetParam().image == IDR_SAVE_PASSWORD_ACTIVE ||
-                  GetParam().image == IDR_SAVE_PASSWORD_INACTIVE);
-      const int kIconSize = 16;
-      expected_image = NSImageFromImageSkia(
-          gfx::CreateVectorIcon(gfx::VectorIconId::AUTOLOGIN,
-                                kIconSize,
-                                gfx::kChromeIconGrey));
-    } else {
-      expected_image = OmniboxViewMac::ImageForResource(GetParam().image);
-    }
+    // IDR_SAVE_PASSWORD_ACTIVE and IDR_SAVE_PASSWORD_INACTIVE map to
+    // gfx::VectorIconId::AUTOLOGIN in Material Design; fail the test if
+    // somehow some other value is present.
+    EXPECT_TRUE(GetParam().image == IDR_SAVE_PASSWORD_ACTIVE ||
+                GetParam().image == IDR_SAVE_PASSWORD_INACTIVE);
+    const int kIconSize = 16;
+    expected_image = NSImageFromImageSkia(gfx::CreateVectorIcon(
+        gfx::VectorIconId::AUTOLOGIN, kIconSize, gfx::kChromeIconGrey));
   }
   EXPECT_TRUE(ImagesEqual(expected_image, decoration()->GetImage()));
   EXPECT_NSEQ(GetParam().toolTip
diff --git a/chrome/browser/ui/cocoa/location_bar/save_credit_card_decoration.mm b/chrome/browser/ui/cocoa/location_bar/save_credit_card_decoration.mm
index 8e31c08c..dbd5b11 100644
--- a/chrome/browser/ui/cocoa/location_bar/save_credit_card_decoration.mm
+++ b/chrome/browser/ui/cocoa/location_bar/save_credit_card_decoration.mm
@@ -22,12 +22,8 @@
 SaveCreditCardDecoration::~SaveCreditCardDecoration() {}
 
 void SaveCreditCardDecoration::SetIcon(bool locationBarIsDark) {
-  SkColor theColor = gfx::kPlaceholderColor;
-  if (ui::MaterialDesignController::IsModeMaterial()) {
-    theColor = locationBarIsDark ? SK_ColorWHITE : gfx::kChromeIconGrey;
-  } else {
-    theColor = SkColorSetRGB(0x96, 0x96, 0x96);
-  }
+  SkColor theColor = theColor =
+      locationBarIsDark ? SK_ColorWHITE : gfx::kChromeIconGrey;
 
   SetImage(NSImageFromImageSkia(gfx::CreateVectorIcon(
         gfx::VectorIconId::CREDIT_CARD, 16, theColor)));
diff --git a/chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration.mm b/chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration.mm
index 5cf77aa..6a5f597 100644
--- a/chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration.mm
+++ b/chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration.mm
@@ -50,10 +50,6 @@
 // |kMinElidedBubbleWidth|.
 const float kMaxBubbleFraction = 0.5;
 
-// The base text color used for non-MD. The color tuples are stolen from
-// location_bar_view_gtk.cc.
-const SkColor kBaseTextColor = SkColorSetRGB(0x07, 0x95, 0x00);
-
 // Duration of animation in ms.
 const NSTimeInterval kInAnimationDuration = 330;
 const NSTimeInterval kOutAnimationDuration = 250;
@@ -76,20 +72,16 @@
       animation_(this),
       owner_(owner),
       disable_animations_during_testing_(false) {
-  if (ui::MaterialDesignController::IsModeMaterial()) {
-    // On Retina the text label is 1px above the Omnibox textfield's text
-    // baseline. If the Omnibox textfield also drew the label the baselines
-    // would align.
-    SetRetinaBaselineOffset(kRetinaBaselineOffset);
+  // On Retina the text label is 1px above the Omnibox textfield's text
+  // baseline. If the Omnibox textfield also drew the label the baselines
+  // would align.
+  SetRetinaBaselineOffset(kRetinaBaselineOffset);
 
-    base::scoped_nsobject<NSMutableParagraphStyle> style(
-        [[NSMutableParagraphStyle alloc] init]);
-    [style setLineBreakMode:NSLineBreakByClipping];
-    [attributes_ setObject:style forKey:NSParagraphStyleAttributeName];
-    animation_.SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN);
-  } else {
-    SetTextColor(skia::SkColorToSRGBNSColor(kBaseTextColor));
-  }
+  base::scoped_nsobject<NSMutableParagraphStyle> style(
+      [[NSMutableParagraphStyle alloc] init]);
+  [style setLineBreakMode:NSLineBreakByClipping];
+  [attributes_ setObject:style forKey:NSParagraphStyleAttributeName];
+  animation_.SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN);
 }
 
 SecurityStateBubbleDecoration::~SecurityStateBubbleDecoration() {
@@ -143,9 +135,6 @@
 // SecurityStateBubbleDecoration::LocationBarDecoration:
 
 CGFloat SecurityStateBubbleDecoration::GetWidthForSpace(CGFloat width) {
-  if (!ui::MaterialDesignController::IsModeMaterial())
-    return GetWidthForText(width);
-
   CGFloat location_icon_width = location_icon_->GetWidthForSpace(width);
   CGFloat text_width = GetWidthForText(width) - location_icon_width;
   return (text_width * GetAnimationProgress()) + location_icon_width;
@@ -255,12 +244,6 @@
     NSRect background_frame,
     NSRect frame,
     NSView* control_view) {
-  if (!ui::MaterialDesignController::IsModeMaterial()) {
-    BubbleDecoration::DrawWithBackgroundInFrame(background_frame, frame,
-                                                control_view);
-    return;
-  }
-
   NSRect rect = NSInsetRect(background_frame, 0, 3);
   rect.size.width -= kRightSideMargin;
 
@@ -335,9 +318,6 @@
 // SecurityStateBubbleDecoration, private:
 
 CGFloat SecurityStateBubbleDecoration::GetAnimationProgress() const {
-  if (!ui::MaterialDesignController::IsModeMaterial())
-    return 1.0;
-
   if (disable_animations_during_testing_)
     return 1.0;
 
diff --git a/chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.mm b/chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.mm
index a209a2e..426c4d1 100644
--- a/chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.mm
+++ b/chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.mm
@@ -15,12 +15,6 @@
 #include "ui/gfx/color_palette.h"
 
 SelectedKeywordDecoration::SelectedKeywordDecoration() {
-  if (!ui::MaterialDesignController::IsModeMaterial()) {
-    search_image_.reset([OmniboxViewMac::ImageForResource(
-        IDR_KEYWORD_SEARCH_MAGNIFIER) retain]);
-    SetTextColor([NSColor blackColor]);
-    return;
-  }
   // Note: the unit test
   // SelectedKeywordDecorationTest.UsesPartialKeywordIfNarrow expects to work
   // with a fully-initialized SelectedKeywordDecoration (i.e. one that has a
@@ -35,9 +29,6 @@
 SelectedKeywordDecoration::~SelectedKeywordDecoration() {}
 
 NSColor* SelectedKeywordDecoration::GetBackgroundBorderColor() {
-  if (!ui::MaterialDesignController::IsModeMaterial()) {
-    return skia::SkColorToCalibratedNSColor(gfx::kGoogleBlue700);
-  }
   return skia::SkColorToSRGBNSColor(gfx::kGoogleBlue700);
 }
 
@@ -69,9 +60,7 @@
                                            bool is_extension_keyword) {
   const base::string16 min_name(
       location_bar_util::CalculateMinString(short_name));
-  const int keyword_text_id = ui::MaterialDesignController::IsModeMaterial()
-                                  ? IDS_OMNIBOX_KEYWORD_TEXT_MD
-                                  : IDS_OMNIBOX_KEYWORD_TEXT;
+  const int keyword_text_id = IDS_OMNIBOX_KEYWORD_TEXT_MD;
 
   NSString* full_string =
       is_extension_keyword
diff --git a/chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration_unittest.mm b/chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration_unittest.mm
index a8a1ae84..5f46266f6 100644
--- a/chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration_unittest.mm
+++ b/chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration_unittest.mm
@@ -30,13 +30,9 @@
     // With Material Design vector images the image isn't set at creation time
     // but later by the LocationBar. The unit tests fail with a nil image, so
     // initialize it now.
-    if (ui::MaterialDesignController::IsModeMaterial()) {
-      const int kDefaultIconSize = 16;
-      decoration_.SetImage(NSImageFromImageSkia(
-            gfx::CreateVectorIcon(gfx::VectorIconId::OMNIBOX_SEARCH,
-                                  kDefaultIconSize,
-                                  SK_ColorBLACK)));
-    }
+    const int kDefaultIconSize = 16;
+    decoration_.SetImage(NSImageFromImageSkia(gfx::CreateVectorIcon(
+        gfx::VectorIconId::OMNIBOX_SEARCH, kDefaultIconSize, SK_ColorBLACK)));
   }
 
   SelectedKeywordDecoration decoration_;
@@ -47,13 +43,8 @@
 TEST_F(SelectedKeywordDecorationTest, UsesPartialKeywordIfNarrow) {
 
   const base::string16 kKeyword = base::ASCIIToUTF16("Engine");
-  NSString* const kFullString = ui::MaterialDesignController::IsModeMaterial()
-                                    ? @"Search Engine"
-                                    : @"Search Engine:";
-  NSString* const kPartialString =
-      ui::MaterialDesignController::IsModeMaterial()
-          ? @"Search En\u2026"
-          : @"Search En\u2026:";  // ellipses
+  NSString* const kFullString = @"Search Engine";
+  NSString* const kPartialString = @"Search En\u2026";
 
   decoration_.SetKeyword(kKeyword, false);
 
diff --git a/chrome/browser/ui/cocoa/location_bar/star_decoration.mm b/chrome/browser/ui/cocoa/location_bar/star_decoration.mm
index eb08fb1..8703ebbf 100644
--- a/chrome/browser/ui/cocoa/location_bar/star_decoration.mm
+++ b/chrome/browser/ui/cocoa/location_bar/star_decoration.mm
@@ -37,12 +37,6 @@
 void StarDecoration::SetStarred(bool starred, bool location_bar_is_dark) {
   starred_ = starred;
   const int tip_id = starred ? IDS_TOOLTIP_STARRED : IDS_TOOLTIP_STAR;
-  if (!ui::MaterialDesignController::IsModeMaterial()) {
-    const int image_id = starred ? IDR_STAR_LIT : IDR_STAR;
-    SetImage(OmniboxViewMac::ImageForResource(image_id));
-    tooltip_.reset([l10n_util::GetNSStringWithFixup(tip_id) retain]);
-    return;
-  }
   SetImage(GetMaterialIcon(location_bar_is_dark));
   tooltip_.reset([l10n_util::GetNSStringWithFixup(tip_id) retain]);
 }
diff --git a/chrome/browser/ui/cocoa/location_bar/translate_decoration.mm b/chrome/browser/ui/cocoa/location_bar/translate_decoration.mm
index 455ca6c3..983ad820 100644
--- a/chrome/browser/ui/cocoa/location_bar/translate_decoration.mm
+++ b/chrome/browser/ui/cocoa/location_bar/translate_decoration.mm
@@ -20,11 +20,6 @@
 TranslateDecoration::~TranslateDecoration() {}
 
 void TranslateDecoration::SetLit(bool on, bool location_bar_is_dark) {
-  if (!ui::MaterialDesignController::IsModeMaterial()) {
-    const int image_id = on ? IDR_TRANSLATE_ACTIVE : IDR_TRANSLATE;
-    SetImage(OmniboxViewMac::ImageForResource(image_id));
-    return;
-  }
   SetImage(GetMaterialIcon(location_bar_is_dark));
 }
 
diff --git a/chrome/browser/ui/cocoa/location_bar/zoom_decoration.mm b/chrome/browser/ui/cocoa/location_bar/zoom_decoration.mm
index 9c69127..992baaeb 100644
--- a/chrome/browser/ui/cocoa/location_bar/zoom_decoration.mm
+++ b/chrome/browser/ui/cocoa/location_bar/zoom_decoration.mm
@@ -93,29 +93,17 @@
 void ZoomDecoration::ShowAndUpdateUI(zoom::ZoomController* zoom_controller,
                                      NSString* tooltip_string,
                                      bool location_bar_is_dark) {
-  if (ui::MaterialDesignController::IsModeMaterial()) {
-    vector_icon_id_ = gfx::VectorIconId::VECTOR_ICON_NONE;
-    zoom::ZoomController::RelativeZoom relative_zoom =
-        zoom_controller->GetZoomRelativeToDefault();
-    if (relative_zoom == zoom::ZoomController::ZOOM_BELOW_DEFAULT_ZOOM) {
-      vector_icon_id_ = gfx::VectorIconId::ZOOM_MINUS;
-    } else if (relative_zoom == zoom::ZoomController::ZOOM_ABOVE_DEFAULT_ZOOM) {
-      vector_icon_id_ = gfx::VectorIconId::ZOOM_PLUS;
-    }
-
-    SetImage(GetMaterialIcon(location_bar_is_dark));
-  } else {
-    int image_id = IDR_ZOOM_NORMAL;
-    zoom::ZoomController::RelativeZoom relative_zoom =
-        zoom_controller->GetZoomRelativeToDefault();
-    if (relative_zoom == zoom::ZoomController::ZOOM_BELOW_DEFAULT_ZOOM)
-      image_id = IDR_ZOOM_MINUS;
-    else if (relative_zoom == zoom::ZoomController::ZOOM_ABOVE_DEFAULT_ZOOM)
-      image_id = IDR_ZOOM_PLUS;
-
-    SetImage(OmniboxViewMac::ImageForResource(image_id));
+  vector_icon_id_ = gfx::VectorIconId::VECTOR_ICON_NONE;
+  zoom::ZoomController::RelativeZoom relative_zoom =
+      zoom_controller->GetZoomRelativeToDefault();
+  if (relative_zoom == zoom::ZoomController::ZOOM_BELOW_DEFAULT_ZOOM) {
+    vector_icon_id_ = gfx::VectorIconId::ZOOM_MINUS;
+  } else if (relative_zoom == zoom::ZoomController::ZOOM_ABOVE_DEFAULT_ZOOM) {
+    vector_icon_id_ = gfx::VectorIconId::ZOOM_PLUS;
   }
 
+  SetImage(GetMaterialIcon(location_bar_is_dark));
+
   tooltip_.reset([tooltip_string retain]);
 
   SetVisible(true);
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
index 32e28585c..0577af2 100644
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
+++ b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
@@ -79,22 +79,22 @@
 // Duration of the toolbar animation.
 const NSTimeInterval kToolBarAnimationDuration = 0.12;
 
-// The height of the location bar in Material Design.
-const CGFloat kMaterialDesignLocationBarHeight = 28;
+// The height of the location bar.
+const CGFloat kLocationBarHeight = 28;
 
 // The padding between the top of the toolbar and the top of the
 // location bar.
-const CGFloat kMaterialDesignLocationBarPadding = 2;
+const CGFloat kLocationBarPadding = 2;
 
-// The padding between Material Design elements and the edges of the toolbar.
-const CGFloat kMaterialDesignElementPadding = 4;
+// The padding between elements and the edges of the toolbar.
+const CGFloat kElementPadding = 4;
 
 // Toolbar buttons are 24x24 and centered in a 28x28 space, so there is a 2pt-
 // wide inset.
-const CGFloat kMaterialDesignButtonInset = 2;
+const CGFloat kButtonInset = 2;
 
 // The y-offset of the browser actions container from the location bar.
-const CGFloat kMaterialDesignContainerYOffset = 2;
+const CGFloat kContainerYOffset = 2;
 
 // The minimum width of the location bar in pixels.
 const CGFloat kMinimumLocationBarWidth = 100.0;
@@ -230,15 +230,15 @@
 @synthesize browser = browser_;
 
 + (CGFloat)locationBarHeight {
-  return kMaterialDesignLocationBarHeight;
+  return kLocationBarHeight;
 }
 
 + (CGFloat)appMenuLeftPadding {
-  return kMaterialDesignElementPadding;
+  return kElementPadding;
 }
 
 + (CGFloat)materialDesignButtonInset {
-  return kMaterialDesignButtonInset;
+  return kButtonInset;
 }
 
 - (id)initWithCommands:(CommandUpdater*)commands
@@ -304,30 +304,26 @@
   [toolbarView setFrame:frame];
 
   NSRect backButtonFrame = [backButton_ frame];
-  backButtonFrame.origin.x =
-      kMaterialDesignElementPadding + kMaterialDesignButtonInset;
-  backButtonFrame.origin.y = NSMaxY(toolbarBounds) -
-      kMaterialDesignElementPadding - toolbarButtonSize.height;
+  backButtonFrame.origin.x = kElementPadding + kButtonInset;
+  backButtonFrame.origin.y =
+      NSMaxY(toolbarBounds) - kElementPadding - toolbarButtonSize.height;
   backButtonFrame.size = toolbarButtonSize;
   [backButton_ setFrame:backButtonFrame];
 
   NSRect forwardButtonFrame = [forwardButton_ frame];
-  forwardButtonFrame.origin.x =
-      NSMaxX(backButtonFrame) + 2 * kMaterialDesignButtonInset;
+  forwardButtonFrame.origin.x = NSMaxX(backButtonFrame) + 2 * kButtonInset;
   forwardButtonFrame.origin.y = backButtonFrame.origin.y;
   forwardButtonFrame.size = toolbarButtonSize;
   [forwardButton_ setFrame:forwardButtonFrame];
 
   NSRect reloadButtonFrame = [reloadButton_ frame];
-  reloadButtonFrame.origin.x =
-      NSMaxX(forwardButtonFrame) + 2 * kMaterialDesignButtonInset;
+  reloadButtonFrame.origin.x = NSMaxX(forwardButtonFrame) + 2 * kButtonInset;
   reloadButtonFrame.origin.y = forwardButtonFrame.origin.y;
   reloadButtonFrame.size = toolbarButtonSize;
   [reloadButton_ setFrame:reloadButtonFrame];
 
   NSRect homeButtonFrame = [homeButton_ frame];
-  homeButtonFrame.origin.x =
-      NSMaxX(reloadButtonFrame) + 2 * kMaterialDesignButtonInset;
+  homeButtonFrame.origin.x = NSMaxX(reloadButtonFrame) + 2 * kButtonInset;
   homeButtonFrame.origin.y = reloadButtonFrame.origin.y;
   homeButtonFrame.size = toolbarButtonSize;
   [homeButton_ setFrame:homeButtonFrame];
@@ -347,8 +343,7 @@
   CGFloat menuButtonFrameMaxX =
       NSMaxX(toolbarBounds) - [ToolbarController appMenuLeftPadding];
   menuButtonFrame.origin.x =
-      menuButtonFrameMaxX - kMaterialDesignButtonInset -
-          toolbarButtonSize.width;
+      menuButtonFrameMaxX - kButtonInset - toolbarButtonSize.width;
   menuButtonFrame.origin.y = homeButtonFrame.origin.y;
   menuButtonFrame.size = toolbarButtonSize;
   [appMenuButton_ setFrame:menuButtonFrame];
@@ -356,25 +351,23 @@
   // Adjust the size and location on the location bar to take up the
   // space between the reload and menu buttons.
   NSRect locationBarFrame = [locationBar_ frame];
-  locationBarFrame.origin.x = NSMaxX(homeButtonFrame) +
-      kMaterialDesignButtonInset;
+  locationBarFrame.origin.x = NSMaxX(homeButtonFrame) + kButtonInset;
   if (![homeButton_ isHidden]) {
     // Ensure proper spacing between the home button and the location bar.
-    locationBarFrame.origin.x += kMaterialDesignElementPadding;
+    locationBarFrame.origin.x += kElementPadding;
   }
-  locationBarFrame.origin.y = NSMaxY(toolbarBounds) -
-      kMaterialDesignLocationBarPadding - kMaterialDesignLocationBarHeight;
+  locationBarFrame.origin.y =
+      NSMaxY(toolbarBounds) - kLocationBarPadding - kLocationBarHeight;
   locationBarFrame.size.width =
       menuButtonFrame.origin.x -
           locationBarFrame.origin.x;
-  locationBarFrame.size.height = kMaterialDesignLocationBarHeight;
+  locationBarFrame.size.height = kLocationBarHeight;
   [locationBar_ setFrame:locationBarFrame];
 
   // Correctly position the extension buttons' container view.
   NSRect containerFrame = [browserActionsContainerView_ frame];
-  containerFrame.size.width += kMaterialDesignButtonInset;
-  containerFrame.origin.y =
-      locationBarFrame.origin.y + kMaterialDesignContainerYOffset;
+  containerFrame.size.width += kButtonInset;
+  containerFrame.origin.y = locationBarFrame.origin.y + kContainerYOffset;
   containerFrame.size.height = toolbarButtonSize.height;
   [browserActionsContainerView_ setFrame:containerFrame];
 
@@ -737,7 +730,7 @@
   // hiding the button, reverse the direction of the movement (to the left).
   CGFloat moveX = [homeButton_ frame].size.width;
   // Ensure proper spacing between the home button and the location bar.
-  moveX += kMaterialDesignElementPadding;
+  moveX += kElementPadding;
   if (hide)
     moveX *= -1;  // Reverse the direction of the move.
 
@@ -853,7 +846,7 @@
         locationBarXPos;
     // Equalize the distance between the location bar and the first extension
     // button, and the distance between the location bar and home/reload button.
-    leftDistance -= kMaterialDesignButtonInset;
+    leftDistance -= kButtonInset;
   }
   if (leftDistance != 0.0)
     [self adjustLocationSizeBy:leftDistance animate:animate];
@@ -884,8 +877,7 @@
     // it afterwards.
     [browserActionsContainerView_ stopAnimation];
     NSRect containerFrame = [browserActionsContainerView_ frame];
-    containerFrame.origin.y =
-        [locationBar_ frame].origin.y + kMaterialDesignContainerYOffset;
+    containerFrame.origin.y = [locationBar_ frame].origin.y + kContainerYOffset;
     [browserActionsContainerView_ setFrame:containerFrame];
     [self pinLocationBarToLeftOfBrowserActionsContainerAndAnimate:NO];
   }
diff --git a/chrome/browser/ui/cocoa/website_settings/chooser_bubble_ui_cocoa.mm b/chrome/browser/ui/cocoa/website_settings/chooser_bubble_ui_cocoa.mm
index 127699d9..edcaef5 100644
--- a/chrome/browser/ui/cocoa/website_settings/chooser_bubble_ui_cocoa.mm
+++ b/chrome/browser/ui/cocoa/website_settings/chooser_bubble_ui_cocoa.mm
@@ -209,6 +209,7 @@
 }
 
 - (void)tableViewSelectionDidChange:(NSNotification*)aNotification {
+  [chooserContentView_ updateContentRowColor];
   [connectButton_ setEnabled:[tableView_ numberOfSelectedRows] > 0];
 }
 
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
index ab7c0bc..04d2a6d 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
@@ -186,11 +186,6 @@
     exclusive_access_context->UpdateUIForTabFullscreen(
         ExclusiveAccessContext::STATE_EXIT_TAB_FULLSCREEN);
 
-#if defined(OS_MACOSX)
-  // Clear the bubble URL, which forces the Mac UI to redraw.
-  exclusive_access_manager()->UpdateExclusiveAccessExitBubbleContent();
-#endif  // defined(OS_MACOSX)
-
   // If currently there is a tab in "tab fullscreen" mode and fullscreen
   // was not caused by it (i.e., previously it was in "browser fullscreen"
   // mode), we need to switch back to "browser fullscreen" mode. In this
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
index c5f41c6..3da2242 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
@@ -30,7 +30,7 @@
 
 namespace {
 
-const base::FilePath::CharType* kSimpleFile = FILE_PATH_LITERAL("/simple.html");
+const base::FilePath::CharType* kSimpleFile = FILE_PATH_LITERAL("simple.html");
 
 }  // namespace
 
@@ -703,6 +703,7 @@
   // FullscreenControllerTest::ToggleTabFullscreen. This test verifies that
   // when running serially there is no flakiness.
 
+  EXPECT_TRUE(embedded_test_server()->Start());
   GURL url = embedded_test_server()->GetURL("/simple.html");
   AddTabAtIndex(0, url, PAGE_TRANSITION_TYPED);
 
diff --git a/chrome/browser/ui/login/login_handler_browsertest.cc b/chrome/browser/ui/login/login_handler_browsertest.cc
index 532374d..d3e1ca5 100644
--- a/chrome/browser/ui/login/login_handler_browsertest.cc
+++ b/chrome/browser/ui/login/login_handler_browsertest.cc
@@ -361,8 +361,9 @@
   observer.Register(content::Source<NavigationController>(controller));
 
   // One LOAD_STOP event for LoginInterstitial, second for kAuthURL and third
-  // for kNoAuthURL.
-  const int kLoadStopEvents = 3;
+  // for kNoAuthURL, unless PlzNavigate is active, in which case the
+  // interrupted ongoing navigation does not receive LOAD_STOP.
+  const int kLoadStopEvents = content::IsBrowserSideNavigationEnabled() ? 2 : 3;
   WindowedLoadStopObserver load_stop_waiter(controller, kLoadStopEvents);
   WindowedAuthNeededObserver auth_needed_waiter(controller);
   browser()->OpenURL(OpenURLParams(kAuthURL, Referrer(),
diff --git a/chrome/browser/ui/omnibox/alternate_nav_infobar_delegate.cc b/chrome/browser/ui/omnibox/alternate_nav_infobar_delegate.cc
index 96fb8c8..70f4e105 100644
--- a/chrome/browser/ui/omnibox/alternate_nav_infobar_delegate.cc
+++ b/chrome/browser/ui/omnibox/alternate_nav_infobar_delegate.cc
@@ -11,7 +11,6 @@
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/grit/generated_resources.h"
-#include "chrome/grit/theme_resources.h"
 #include "components/history/core/browser/history_service.h"
 #include "components/infobars/core/infobar.h"
 #include "components/omnibox/browser/shortcuts_backend.h"
@@ -109,14 +108,6 @@
   return ALTERNATE_NAV_INFOBAR_DELEGATE;
 }
 
-int AlternateNavInfoBarDelegate::GetIconId() const {
-  return IDR_INFOBAR_ALT_NAV_URL;
-}
-
 gfx::VectorIconId AlternateNavInfoBarDelegate::GetVectorIconId() const {
-#if defined(OS_MACOSX)
-  return gfx::VectorIconId::VECTOR_ICON_NONE;
-#else
   return gfx::VectorIconId::GLOBE;
-#endif
 }
diff --git a/chrome/browser/ui/omnibox/alternate_nav_infobar_delegate.h b/chrome/browser/ui/omnibox/alternate_nav_infobar_delegate.h
index 3f61521..9a70b3b 100644
--- a/chrome/browser/ui/omnibox/alternate_nav_infobar_delegate.h
+++ b/chrome/browser/ui/omnibox/alternate_nav_infobar_delegate.h
@@ -48,7 +48,6 @@
   // InfoBarDelegate:
   Type GetInfoBarType() const override;
   infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
-  int GetIconId() const override;
   gfx::VectorIconId GetVectorIconId() const override;
 
   Profile* profile_;
diff --git a/chrome/browser/ui/task_manager/task_manager_table_model.cc b/chrome/browser/ui/task_manager/task_manager_table_model.cc
index 1ce189b8..97478c3 100644
--- a/chrome/browser/ui/task_manager/task_manager_table_model.cc
+++ b/chrome/browser/ui/task_manager/task_manager_table_model.cc
@@ -33,16 +33,13 @@
 
 namespace {
 
+const char kCpuTextFormatString[] = "%.1f";
+
 #if defined(OS_MACOSX)
 // Match Activity Monitor's default refresh rate.
 const int64_t kRefreshTimeMS = 2000;
-
-// Activity Monitor shows %cpu with one decimal digit -- be consistent with
-// that.
-const char kCpuTextFormatString[] = "%.1f";
 #else
 const int64_t kRefreshTimeMS = 1000;
-const char kCpuTextFormatString[] = "%.0f";
 #endif  // defined(OS_MACOSX)
 
 // The columns that are shared by a group will show the value of the column
diff --git a/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views.cc b/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views.cc
index 169f9ab..0a86b3e 100644
--- a/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views.cc
+++ b/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views.cc
@@ -8,7 +8,6 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
-#include "base/metrics/histogram_macros.h"
 #include "build/build_config.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/profiles/profile.h"
@@ -77,13 +76,6 @@
                           Profile* profile,
                           const extensions::Extension* app,
                           const base::Closure& close_callback) {
-  UMA_HISTOGRAM_ENUMERATION("Apps.AppInfoDialogOpenedForType",
-                            app->GetType(),
-                            extensions::Manifest::NUM_LOAD_TYPES);
-  UMA_HISTOGRAM_ENUMERATION("Apps.AppInfoDialogOpenedForLocation",
-                            app->location(),
-                            extensions::Manifest::NUM_LOCATIONS);
-
   views::View* app_info_view = new AppInfoDialog(parent, profile, app);
   views::DialogDelegate* dialog =
       CreateAppListContainerForView(app_info_view, close_callback);
@@ -123,13 +115,6 @@
       profile_(profile),
       app_id_(app->id()),
       extension_registry_(NULL) {
-  UMA_HISTOGRAM_ENUMERATION("Apps.AppInfoDialogOpenedForType",
-                            app->GetType(),
-                            extensions::Manifest::NUM_LOAD_TYPES);
-  UMA_HISTOGRAM_ENUMERATION("Apps.AppInfoDialogOpenedForLocation",
-                            app->location(),
-                            extensions::Manifest::NUM_LOCATIONS);
-
   views::BoxLayout* layout =
       new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0);
   SetLayoutManager(layout);
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index d0fb9bc..8bfec3d 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -44,7 +44,6 @@
 #include "ui/base/default_theme_provider.h"
 #include "ui/base/dragdrop/drag_drop_types.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/models/list_selection_model.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/compositor/compositing_recorder.h"
@@ -369,111 +368,60 @@
   const bool pressed = state() == views::CustomButton::STATE_PRESSED;
   const float scale = canvas->image_scale();
 
+  // Fill.
   SkPath fill;
-  const ui::ThemeProvider* tp = GetThemeProvider();
-  if (ui::MaterialDesignController::IsModeMaterial()) {
-    // Fill.
-    const float fill_bottom = (visible_height - 2) * scale;
-    const float diag_height = fill_bottom - 3.5 * scale;
-    const float diag_width = diag_height * Tab::GetInverseDiagonalSlope();
-    fill.moveTo(diag_width + 4 * scale, fill_bottom);
-    fill.rCubicTo(-0.75 * scale, 0, -1.625 * scale, -0.5 * scale, -2 * scale,
-                  -1.5 * scale);
-    fill.rLineTo(-diag_width, -diag_height);
-    fill.rCubicTo(0, -0.5 * scale, 0.25 * scale, -scale, scale, -scale);
-    fill.lineTo((width() - 4) * scale - diag_width, scale);
-    fill.rCubicTo(0.75 * scale, 0, 1.625 * scale, 0.5 * scale, 2 * scale,
-                  1.5 * scale);
-    fill.rLineTo(diag_width, diag_height);
-    fill.rCubicTo(0, 0.5 * scale, -0.25 * scale, scale, -scale, scale);
-    fill.close();
-    PaintFill(pressed, scale, fill, canvas);
+  const float fill_bottom = (visible_height - 2) * scale;
+  const float diag_height = fill_bottom - 3.5 * scale;
+  const float diag_width = diag_height * Tab::GetInverseDiagonalSlope();
+  fill.moveTo(diag_width + 4 * scale, fill_bottom);
+  fill.rCubicTo(-0.75 * scale, 0, -1.625 * scale, -0.5 * scale, -2 * scale,
+                -1.5 * scale);
+  fill.rLineTo(-diag_width, -diag_height);
+  fill.rCubicTo(0, -0.5 * scale, 0.25 * scale, -scale, scale, -scale);
+  fill.lineTo((width() - 4) * scale - diag_width, scale);
+  fill.rCubicTo(0.75 * scale, 0, 1.625 * scale, 0.5 * scale, 2 * scale,
+                1.5 * scale);
+  fill.rLineTo(diag_width, diag_height);
+  fill.rCubicTo(0, 0.5 * scale, -0.25 * scale, scale, -scale, scale);
+  fill.close();
+  PaintFill(pressed, scale, fill, canvas);
 
-    // Stroke.
-    gfx::ScopedCanvas scoped_canvas(canvas);
-    canvas->UndoDeviceScaleFactor();
-    SkPath stroke;
-    GetBorderPath(0, scale, false, &stroke);
-    // We want to draw a drop shadow either inside or outside the stroke,
-    // depending on whether we're pressed; so, either clip out what's outside
-    // the stroke, or clip out the fill inside it.
-    if (pressed)
-      canvas->ClipPath(stroke, true);
-    Op(stroke, fill, kDifference_SkPathOp, &stroke);
-    if (!pressed)
-      canvas->sk_canvas()->clipPath(fill, SkRegion::kDifference_Op, true);
-    // Now draw the stroke and shadow; the stroke will always be visible, while
-    // the shadow will be affected by the clip we set above.
-    SkPaint paint;
-    paint.setAntiAlias(true);
-    const SkColor stroke_color = tab_strip_->GetToolbarTopSeparatorColor();
-    const float alpha = SkColorGetA(stroke_color);
-    const SkAlpha shadow_alpha =
-        base::saturated_cast<SkAlpha>(std::round(2.1875f * alpha));
-    paint.setLooper(
-        CreateShadowDrawLooper(SkColorSetA(stroke_color, shadow_alpha)));
-    const SkAlpha path_alpha = static_cast<SkAlpha>(
-        std::round((pressed ? 0.875f : 0.609375f) * alpha));
-    paint.setColor(SkColorSetA(stroke_color, path_alpha));
-    canvas->DrawPath(stroke, paint);
-  } else {
-    // Fill.
-    gfx::ImageSkia* mask = tp->GetImageSkiaNamed(IDR_NEWTAB_BUTTON_MASK);
-    // The canvas and mask have to use the same scale factor.
-    const float fill_canvas_scale = mask->HasRepresentation(scale) ?
-        scale : ui::GetScaleForScaleFactor(ui::SCALE_FACTOR_100P);
-    gfx::Canvas fill_canvas(GetLayoutSize(NEW_TAB_BUTTON), fill_canvas_scale,
-                            false);
-    PaintFill(pressed, fill_canvas_scale, fill, &fill_canvas);
-    gfx::ImageSkia image(fill_canvas.ExtractImageRep());
-    canvas->DrawImageInt(
-        gfx::ImageSkiaOperations::CreateMaskedImage(image, *mask), 0, 0);
-
-    // Stroke.  Draw the button border with a slight alpha.
-    static const SkAlpha kGlassFrameOverlayAlpha = 178;
-    static const SkAlpha kOpaqueFrameOverlayAlpha = 230;
-    const SkAlpha alpha = GetWidget()->ShouldWindowContentsBeTransparent() ?
-        kGlassFrameOverlayAlpha : kOpaqueFrameOverlayAlpha;
-    const int overlay_id = pressed ? IDR_NEWTAB_BUTTON_P : IDR_NEWTAB_BUTTON;
-    canvas->DrawImageInt(*tp->GetImageSkiaNamed(overlay_id), 0, 0, alpha);
-  }
+  // Stroke.
+  canvas->UndoDeviceScaleFactor();
+  SkPath stroke;
+  GetBorderPath(0, scale, false, &stroke);
+  // We want to draw a drop shadow either inside or outside the stroke,
+  // depending on whether we're pressed; so, either clip out what's outside
+  // the stroke, or clip out the fill inside it.
+  if (pressed)
+    canvas->ClipPath(stroke, true);
+  Op(stroke, fill, kDifference_SkPathOp, &stroke);
+  if (!pressed)
+    canvas->sk_canvas()->clipPath(fill, SkRegion::kDifference_Op, true);
+  // Now draw the stroke and shadow; the stroke will always be visible, while
+  // the shadow will be affected by the clip we set above.
+  SkPaint paint;
+  paint.setAntiAlias(true);
+  const SkColor stroke_color = tab_strip_->GetToolbarTopSeparatorColor();
+  const float alpha = SkColorGetA(stroke_color);
+  const SkAlpha shadow_alpha =
+      base::saturated_cast<SkAlpha>(std::round(2.1875f * alpha));
+  paint.setLooper(
+      CreateShadowDrawLooper(SkColorSetA(stroke_color, shadow_alpha)));
+  const SkAlpha path_alpha = static_cast<SkAlpha>(
+      std::round((pressed ? 0.875f : 0.609375f) * alpha));
+  paint.setColor(SkColorSetA(stroke_color, path_alpha));
+  canvas->DrawPath(stroke, paint);
 }
 
 bool NewTabButton::GetHitTestMask(gfx::Path* mask) const {
   DCHECK(mask);
 
-  if (ui::MaterialDesignController::IsModeMaterial()) {
-    SkPath border;
-    const float scale = GetWidget()->GetCompositor()->device_scale_factor();
-    GetBorderPath(GetNewTabButtonTopOffset() * scale, scale,
-                  tab_strip_->SizeTabButtonToTopOfTabStrip(), &border);
-    mask->addPath(border, SkMatrix::MakeScale(1 / scale));
-  } else if (tab_strip_->SizeTabButtonToTopOfTabStrip()) {
-    // When the button is sized to the top of the tab strip, we want the hit
-    // test mask to be defined as the complete (rectangular) bounds of the
-    // button.
-    gfx::Rect button_bounds(GetContentsBounds());
-    button_bounds.set_x(GetMirroredXForRect(button_bounds));
-    mask->addRect(RectToSkRect(button_bounds));
-  } else {
-    SkScalar w = SkIntToScalar(width());
-    SkScalar v_offset = SkIntToScalar(GetNewTabButtonTopOffset());
-
-    // These values are defined by the shape of the new tab image. Should that
-    // image ever change, these values will need to be updated. They're so
-    // custom it's not really worth defining constants for.
-    // These values are correct for regular and USE_ASH versions of the image.
-    mask->moveTo(0, v_offset + 1);
-    mask->lineTo(w - 7, v_offset + 1);
-    mask->lineTo(w - 4, v_offset + 4);
-    mask->lineTo(w, v_offset + 16);
-    mask->lineTo(w - 1, v_offset + 17);
-    mask->lineTo(7, v_offset + 17);
-    mask->lineTo(4, v_offset + 13);
-    mask->lineTo(0, v_offset + 1);
-    mask->close();
-  }
-
+  SkPath border;
+  const float scale = GetWidget()->GetCompositor()->device_scale_factor();
+  GetBorderPath(GetNewTabButtonTopOffset() * scale, scale,
+                tab_strip_->SizeTabButtonToTopOfTabStrip(), &border);
+  mask->addPath(border, SkMatrix::MakeScale(1 / scale));
   return true;
 }
 
@@ -520,99 +468,67 @@
                              float scale,
                              const SkPath& fill,
                              gfx::Canvas* canvas) const {
-  // First we compute the background image coordinates and scale, in case we
-  // need to draw a custom background image.
-  const ui::ThemeProvider* tp = GetThemeProvider();
-  bool custom_image;
-  const int bg_id = tab_strip_->GetBackgroundResourceId(&custom_image);
-  // For custom tab backgrounds the background starts at the top of the tab
-  // strip. Otherwise the background starts at the top of the frame.
-  const int offset_y = tp->HasCustomImage(bg_id) ? 0 : background_offset_.y();
-  // The new tab background is mirrored in RTL mode, but the theme background
-  // should never be mirrored. Mirror it here to compensate.
-  float x_scale = 1.0f;
-  int x = GetMirroredX() + background_offset_.x();
-  const gfx::Size size(GetLayoutSize(NEW_TAB_BUTTON));
-  if (base::i18n::IsRTL()) {
-    x_scale = -1.0f;
-    // Offset by |width| such that the same region is painted as if there was no
-    // flip.
-    x += size.width();
-  }
-  const int y = GetNewTabButtonTopOffset() + offset_y;
+  gfx::ScopedCanvas scoped_canvas(canvas);
+  canvas->UndoDeviceScaleFactor();
+  SkPaint paint;
+  paint.setAntiAlias(true);
 
-  if (ui::MaterialDesignController::IsModeMaterial()) {
-    gfx::ScopedCanvas scoped_canvas(canvas);
-    canvas->UndoDeviceScaleFactor();
-
-    // For unpressed buttons, draw the fill and its shadow.
-    if (!pressed) {
-      SkPaint paint;
-      paint.setAntiAlias(true);
-      if (custom_image) {
-        const bool succeeded = canvas->InitSkPaintForTiling(
-            *tp->GetImageSkiaNamed(bg_id), x, y, x_scale * scale, scale, 0, 0,
-            &paint);
-        DCHECK(succeeded);
-      } else {
-        paint.setColor(tp->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB));
+  // For unpressed buttons, draw the fill and its shadow.
+  if (!pressed) {
+    // First we compute the background image coordinates and scale, in case we
+    // need to draw a custom background image.
+    const ui::ThemeProvider* tp = GetThemeProvider();
+    bool custom_image;
+    const int bg_id = tab_strip_->GetBackgroundResourceId(&custom_image);
+    if (custom_image) {
+      // For custom tab backgrounds the background starts at the top of the tab
+      // strip. Otherwise the background starts at the top of the frame.
+      const int offset_y =
+          tp->HasCustomImage(bg_id) ? 0 : background_offset_.y();
+      // The new tab background is mirrored in RTL mode, but the theme
+      // background should never be mirrored. Mirror it here to compensate.
+      float x_scale = 1.0f;
+      int x = GetMirroredX() + background_offset_.x();
+      const gfx::Size size(GetLayoutSize(NEW_TAB_BUTTON));
+      if (base::i18n::IsRTL()) {
+        x_scale = -1.0f;
+        // Offset by |width| such that the same region is painted as if there
+        // was no flip.
+        x += size.width();
       }
-      const SkColor stroke_color = tab_strip_->GetToolbarTopSeparatorColor();
-      const SkAlpha alpha = static_cast<SkAlpha>(
-          std::round(SkColorGetA(stroke_color) * 0.59375f));
-      paint.setLooper(
-          CreateShadowDrawLooper(SkColorSetA(stroke_color, alpha)));
-      canvas->DrawPath(fill, paint);
-    }
 
-    // Draw a white highlight on hover.
-    SkPaint paint;
-    paint.setAntiAlias(true);
-    const SkAlpha hover_alpha = static_cast<SkAlpha>(
-        hover_animation().CurrentValueBetween(0x00, 0x4D));
-    if (hover_alpha != SK_AlphaTRANSPARENT) {
-      paint.setColor(SkColorSetA(SK_ColorWHITE, hover_alpha));
-      canvas->DrawPath(fill, paint);
+      const bool succeeded =
+          canvas->InitSkPaintForTiling(*tp->GetImageSkiaNamed(bg_id), x,
+                                       GetNewTabButtonTopOffset() + offset_y,
+                                       x_scale * scale, scale, 0, 0, &paint);
+      DCHECK(succeeded);
+    } else {
+      paint.setColor(tp->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB));
     }
+    const SkColor stroke_color = tab_strip_->GetToolbarTopSeparatorColor();
+    const SkAlpha alpha = static_cast<SkAlpha>(
+        std::round(SkColorGetA(stroke_color) * 0.59375f));
+    SkPaint shadow_paint = paint;
+    shadow_paint.setLooper(
+        CreateShadowDrawLooper(SkColorSetA(stroke_color, alpha)));
+    canvas->DrawPath(fill, shadow_paint);
+  }
 
-    // Most states' opacities are adjusted using an opacity recorder in
-    // TabStrip::PaintChildren(), but the pressed state is excluded there and
-    // instead rendered using a dark overlay here.  This produces a different
-    // effect than for non-MD, and avoiding the use of the opacity recorder
-    // keeps the stroke more visible in this state.
-    if (pressed) {
-      paint.setColor(SkColorSetA(SK_ColorBLACK, 0x14));
-      canvas->DrawPath(fill, paint);
-    }
-  } else {
-    // Draw the fill image.
-    canvas->TileImageInt(*tp->GetImageSkiaNamed(bg_id), x, y, x_scale, 1.0f,
-                         0, 0, size.width(), size.height());
+  // Draw a white highlight on hover.
+  const SkAlpha hover_alpha = static_cast<SkAlpha>(
+      hover_animation().CurrentValueBetween(0x00, 0x4D));
+  if (hover_alpha != SK_AlphaTRANSPARENT) {
+    paint.setColor(SkColorSetA(SK_ColorWHITE, hover_alpha));
+    canvas->DrawPath(fill, paint);
+  }
 
-    // Adjust the alpha of the fill to match that of inactive tabs (except for
-    // pressed buttons, which get a different value).  For MD, we do this with
-    // an opacity recorder in TabStrip::PaintChildren() so the fill and stroke
-    // are both affected, to better match how tabs are handled, but in non-MD,
-    // the button stroke is already lighter than the tab stroke, and using the
-    // opacity recorder washes it out too much.
-    static const SkAlpha kPressedAlpha = 145;
-    const SkAlpha fill_alpha =
-        pressed ? kPressedAlpha : tab_strip_->GetInactiveAlpha(true);
-    if (fill_alpha != 255) {
-      SkPaint paint;
-      paint.setAlpha(fill_alpha);
-      paint.setXfermodeMode(SkXfermode::kDstIn_Mode);
-      paint.setStyle(SkPaint::kFill_Style);
-      canvas->DrawRect(gfx::Rect(size), paint);
-    }
-
-    // Draw a white highlight on hover.
-    const SkAlpha hover_alpha = static_cast<SkAlpha>(
-        hover_animation().CurrentValueBetween(0x00, 0x40));
-    if (hover_alpha != SK_AlphaTRANSPARENT) {
-      canvas->FillRect(GetLocalBounds(),
-                       SkColorSetA(SK_ColorWHITE, hover_alpha));
-    }
+  // Most states' opacities are adjusted using an opacity recorder in
+  // TabStrip::PaintChildren(), but the pressed state is excluded there and
+  // instead rendered using a dark overlay here.  Avoiding the use of the
+  // opacity recorder keeps the stroke more visible in this state.
+  if (pressed) {
+    paint.setColor(SkColorSetA(SK_ColorBLACK, 0x14));
+    canvas->DrawPath(fill, paint);
   }
 }
 
@@ -1526,8 +1442,7 @@
     active_tab->Paint(context);
 
   // Paint the New Tab button.
-  const bool md = ui::MaterialDesignController::IsModeMaterial();
-  if (md && (newtab_button_->state() != views::CustomButton::STATE_PRESSED)) {
+  if (newtab_button_->state() != views::CustomButton::STATE_PRESSED) {
     // Match the inactive tab opacity for non-pressed states.  See comments in
     // NewTabButton::PaintFill() for why we don't do this for the pressed state.
     // This call doesn't need to set |lcd_text_requires_opaque_layer| to false
@@ -1535,8 +1450,6 @@
     ui::CompositingRecorder opacity_recorder(context, GetInactiveAlpha(true),
                                              true);
     newtab_button_->Paint(context);
-  } else {
-    newtab_button_->Paint(context);
   }
 
   // And the dragged tabs.
@@ -1547,17 +1460,15 @@
   if (active_tab && is_dragging)
     active_tab->Paint(context);
 
-  if (md) {
-    ui::PaintRecorder recorder(context, size());
-    gfx::Canvas* canvas = recorder.canvas();
-    if (active_tab) {
-      canvas->sk_canvas()->clipRect(
-          gfx::RectToSkRect(active_tab->GetMirroredBounds()),
-          SkRegion::kDifference_Op);
-    }
-    BrowserView::Paint1pxHorizontalLine(canvas, GetToolbarTopSeparatorColor(),
-                                        GetLocalBounds(), true);
+  ui::PaintRecorder recorder(context, size());
+  gfx::Canvas* canvas = recorder.canvas();
+  if (active_tab) {
+    canvas->sk_canvas()->clipRect(
+        gfx::RectToSkRect(active_tab->GetMirroredBounds()),
+        SkRegion::kDifference_Op);
   }
+  BrowserView::Paint1pxHorizontalLine(canvas, GetToolbarTopSeparatorColor(),
+                                      GetLocalBounds(), true);
 }
 
 const char* TabStrip::GetClassName() const {
diff --git a/chrome/browser/ui/views/task_manager_view.cc b/chrome/browser/ui/views/task_manager_view.cc
index 513934e..ba09251 100644
--- a/chrome/browser/ui/views/task_manager_view.cc
+++ b/chrome/browser/ui/views/task_manager_view.cc
@@ -105,11 +105,10 @@
 #if defined(USE_ASH)
   ash::WmWindow* wm_window = ash::WmLookup::Get()->GetWindowForWidget(
       g_task_manager_view->GetWidget());
-  ash::ShelfItemDetails item_details;
-  item_details.type = ash::TYPE_DIALOG;
-  item_details.image_resource_id = IDR_ASH_SHELF_ICON_TASK_MANAGER;
-  item_details.title = wm_window->GetTitle();
-  wm_window->SetShelfItemDetails(item_details);
+  wm_window->SetIntProperty(ash::WmWindowProperty::SHELF_ITEM_TYPE,
+                            ash::TYPE_DIALOG);
+  wm_window->SetIntProperty(ash::WmWindowProperty::SHELF_ICON_RESOURCE_ID,
+                            IDR_ASH_SHELF_ICON_TASK_MANAGER);
 #endif
   return g_task_manager_view->table_model_.get();
 }
diff --git a/chrome/browser/ui/website_settings/website_settings_infobar_delegate.cc b/chrome/browser/ui/website_settings/website_settings_infobar_delegate.cc
index a5799d7..ea53376 100644
--- a/chrome/browser/ui/website_settings/website_settings_infobar_delegate.cc
+++ b/chrome/browser/ui/website_settings/website_settings_infobar_delegate.cc
@@ -39,16 +39,8 @@
   return WEBSITE_SETTINGS_INFOBAR_DELEGATE;
 }
 
-int WebsiteSettingsInfoBarDelegate::GetIconId() const {
-  return IDR_INFOBAR_ALT_NAV_URL;
-}
-
 gfx::VectorIconId WebsiteSettingsInfoBarDelegate::GetVectorIconId() const {
-#if defined(OS_MACOSX)
-  return gfx::VectorIconId::VECTOR_ICON_NONE;
-#else
   return gfx::VectorIconId::GLOBE;
-#endif
 }
 
 base::string16 WebsiteSettingsInfoBarDelegate::GetMessageText() const {
diff --git a/chrome/browser/ui/website_settings/website_settings_infobar_delegate.h b/chrome/browser/ui/website_settings/website_settings_infobar_delegate.h
index f57e7a6..d94e2fc 100644
--- a/chrome/browser/ui/website_settings/website_settings_infobar_delegate.h
+++ b/chrome/browser/ui/website_settings/website_settings_infobar_delegate.h
@@ -28,7 +28,6 @@
   // ConfirmInfoBarDelegate:
   Type GetInfoBarType() const override;
   infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
-  int GetIconId() const override;
   gfx::VectorIconId GetVectorIconId() const override;
   base::string16 GetMessageText() const override;
   int GetButtons() const override;
diff --git a/chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.cc b/chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.cc
index 6d2bf4c..817448ce 100644
--- a/chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.cc
@@ -259,6 +259,8 @@
   { "keyboardOverlayDisableCapsLock", IDS_KEYBOARD_OVERLAY_DISABLE_CAPS_LOCK },
   { "keyboardOverlayToggleChromevoxSpokenFeedback",
     IDS_KEYBOARD_OVERLAY_TOGGLE_CHROMEVOX_SPOKEN_FEEDBACK },
+  { "keyboardOverlayToggleHighContrastMode",
+    IDS_KEYBOARD_OVERLAY_TOGGLE_HIGH_CONTRAST_MODE},
   { "keyboardOverlayToggleProjectionTouchHud",
     IDS_KEYBOARD_OVERLAY_TOGGLE_PROJECTION_TOUCH_HUD },
   { "keyboardOverlayUndo", IDS_KEYBOARD_OVERLAY_UNDO },
diff --git a/chrome/browser/ui/webui/interstitials/interstitial_ui.cc b/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
index f02d0ca8..f92b1f12 100644
--- a/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
+++ b/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
@@ -152,7 +152,7 @@
     options_mask |= security_interstitials::SSLErrorUI::SOFT_OVERRIDE_ENABLED;
   if (strict_enforcement)
     options_mask |= security_interstitials::SSLErrorUI::STRICT_ENFORCEMENT;
-  return new SSLBlockingPage(
+  return SSLBlockingPage::Create(
       web_contents, cert_error, ssl_info, request_url, options_mask,
       time_triggered_, nullptr,
       base::Callback<void(content::CertificateRequestResultType)>());
diff --git a/chrome/browser/ui/webui/md_history_ui.cc b/chrome/browser/ui/webui/md_history_ui.cc
index bd1e358b0..56bbf9b 100644
--- a/chrome/browser/ui/webui/md_history_ui.cc
+++ b/chrome/browser/ui/webui/md_history_ui.cc
@@ -35,6 +35,8 @@
 
 namespace {
 
+constexpr char kShowMenuPromoKey[] = "showMenuPromo";
+
 content::WebUIDataSource* CreateMdHistoryUIHTMLSource(Profile* profile,
                                                       bool use_test_title) {
   content::WebUIDataSource* source =
@@ -117,7 +119,7 @@
       prefs->GetBoolean(prefs::kAllowDeletingBrowserHistory);
   source->AddBoolean("allowDeletingHistory", allow_deleting_history);
 
-  source->AddBoolean("showMenuPromo",
+  source->AddBoolean(kShowMenuPromoKey,
       !prefs->GetBoolean(prefs::kMdHistoryMenuPromoShown));
 
   bool group_by_domain = base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -267,5 +269,5 @@
 void MdHistoryUI::HandleMenuPromoShown(const base::ListValue* args) {
   Profile::FromWebUI(web_ui())->GetPrefs()->SetBoolean(
       prefs::kMdHistoryMenuPromoShown, true);
-  data_source_->AddBoolean("showMenuPromo", false);
+  data_source_->AddBoolean(kShowMenuPromoKey, false);
 }
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index 6058ed50..56881784 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -769,6 +769,7 @@
        IDS_SETTINGS_LANGUAGES_EXPAND_ACCESSIBILITY_LABEL},
       {"orderLanguagesInstructions",
        IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_ORDERING_INSTRUCTIONS},
+      {"moveToTop", IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_MOVE_TO_TOP},
       {"moveUp", IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_MOVE_UP},
       {"moveDown", IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_MOVE_DOWN},
       {"removeLanguage", IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_REMOVE},
@@ -776,6 +777,7 @@
 #if defined(OS_CHROMEOS)
       {"inputMethodsListTitle",
        IDS_SETTINGS_LANGUAGES_INPUT_METHODS_LIST_TITLE},
+      {"inputMethodEnabled", IDS_SETTINGS_LANGUAGES_INPUT_METHOD_ENABLED},
       {"inputMethodsExpandA11yLabel",
        IDS_SETTINGS_LANGUAGES_INPUT_METHODS_EXPAND_ACCESSIBILITY_LABEL},
       {"manageInputMethods", IDS_SETTINGS_LANGUAGES_INPUT_METHODS_MANAGE},
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui_browsertest.cc b/chrome/browser/ui/webui/settings/md_settings_ui_browsertest.cc
index 8ab348e..8614ed94 100644
--- a/chrome/browser/ui/webui/settings/md_settings_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_ui_browsertest.cc
@@ -29,9 +29,10 @@
            chrome::kChromeUIMdSettingsURL));
 }
 
-// May not complete on memory bots. TODO(dbeam): investigate and fix.
-// See https://crbug.com/558434 and https://crbug.com/620370.
-#if defined(MEMORY_SANITIZER)
+// May not complete on memory and Windows debug bots. TODO(dbeam): investigate
+// and fix. See https://crbug.com/558434, https://crbug.com/620370 and
+// https://crbug.com/651296.
+#if defined(MEMORY_SANITIZER) || defined(OS_WIN)
 #define MAYBE_BackForwardDoesntCrash DISABLED_BackForwardDoesntCrash
 #else
 #define MAYBE_BackForwardDoesntCrash BackForwardDoesntCrash
diff --git a/chrome/browser/ui/webui/snippets_internals_message_handler.cc b/chrome/browser/ui/webui/snippets_internals_message_handler.cc
index 761bad9..ce04ff3c 100644
--- a/chrome/browser/ui/webui/snippets_internals_message_handler.cc
+++ b/chrome/browser/ui/webui/snippets_internals_message_handler.cc
@@ -24,7 +24,6 @@
 #include "chrome/browser/profiles/profile.h"
 #include "components/ntp_snippets/category_info.h"
 #include "components/ntp_snippets/features.h"
-#include "components/ntp_snippets/ntp_snippet.h"
 #include "components/ntp_snippets/switches.h"
 #include "content/public/browser/web_ui.h"
 
@@ -41,7 +40,7 @@
     const ContentSuggestion& suggestion,
     int index) {
   auto entry = base::MakeUnique<base::DictionaryValue>();
-  entry->SetString("suggestionId", suggestion.id());
+  entry->SetString("idWithinCategory", suggestion.id().id_within_category());
   entry->SetString("url", suggestion.url().spec());
   entry->SetString("ampUrl", suggestion.amp_url().spec());
   entry->SetString("title", suggestion.title());
@@ -144,8 +143,7 @@
 }
 
 void SnippetsInternalsMessageHandler::OnSuggestionInvalidated(
-    ntp_snippets::Category category,
-    const std::string& suggestion_id) {
+    const ntp_snippets::ContentSuggestion::ID& suggestion_id) {
   if (!dom_loaded_)
     return;
   SendContentSuggestions();
diff --git a/chrome/browser/ui/webui/snippets_internals_message_handler.h b/chrome/browser/ui/webui/snippets_internals_message_handler.h
index 6b423bc..e5d7a10 100644
--- a/chrome/browser/ui/webui/snippets_internals_message_handler.h
+++ b/chrome/browser/ui/webui/snippets_internals_message_handler.h
@@ -15,7 +15,7 @@
 #include "components/ntp_snippets/category.h"
 #include "components/ntp_snippets/category_status.h"
 #include "components/ntp_snippets/content_suggestions_service.h"
-#include "components/ntp_snippets/ntp_snippets_service.h"
+#include "components/ntp_snippets/remote/ntp_snippets_service.h"
 #include "content/public/browser/web_ui_message_handler.h"
 
 namespace base {
@@ -41,8 +41,8 @@
   void OnCategoryStatusChanged(
       ntp_snippets::Category category,
       ntp_snippets::CategoryStatus new_status) override;
-  void OnSuggestionInvalidated(ntp_snippets::Category category,
-                               const std::string& suggestion_id) override;
+  void OnSuggestionInvalidated(
+      const ntp_snippets::ContentSuggestion::ID& suggestion_id) override;
   void ContentSuggestionsServiceShutdown() override;
 
   void HandleRefreshContent(const base::ListValue* args);
diff --git a/chrome/browser/usb/usb_chooser_controller.cc b/chrome/browser/usb/usb_chooser_controller.cc
index 7b2c6d3a..59a6e16 100644
--- a/chrome/browser/usb/usb_chooser_controller.cc
+++ b/chrome/browser/usb/usb_chooser_controller.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/usb/usb_chooser_context.h"
 #include "chrome/browser/usb/usb_chooser_context_factory.h"
 #include "chrome/browser/usb/web_usb_histograms.h"
+#include "chrome/browser/usb/web_usb_permission_provider.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
@@ -97,6 +98,11 @@
                    devices_[index].first->serial_number());
 }
 
+bool UsbChooserController::IsPaired(size_t index) const {
+  return WebUSBPermissionProvider::HasDevicePermission(render_frame_host_,
+                                                       devices_[index].first);
+}
+
 void UsbChooserController::RefreshOptions() {}
 
 base::string16 UsbChooserController::GetStatus() const {
diff --git a/chrome/browser/usb/usb_chooser_controller.h b/chrome/browser/usb/usb_chooser_controller.h
index c713112..6811172 100644
--- a/chrome/browser/usb/usb_chooser_controller.h
+++ b/chrome/browser/usb/usb_chooser_controller.h
@@ -44,6 +44,7 @@
   base::string16 GetOkButtonLabel() const override;
   size_t NumOptions() const override;
   base::string16 GetOption(size_t index) const override;
+  bool IsPaired(size_t index) const override;
   void RefreshOptions() override;
   base::string16 GetStatus() const override;
   void Select(size_t index) override;
diff --git a/chrome/browser/usb/web_usb_permission_provider.cc b/chrome/browser/usb/web_usb_permission_provider.cc
index a6a9bc6..fe27011 100644
--- a/chrome/browser/usb/web_usb_permission_provider.cc
+++ b/chrome/browser/usb/web_usb_permission_provider.cc
@@ -54,29 +54,16 @@
 
 }  // namespace
 
-WebUSBPermissionProvider::WebUSBPermissionProvider(
-    content::RenderFrameHost* render_frame_host)
-    : render_frame_host_(render_frame_host), weak_factory_(this) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  DCHECK(render_frame_host_);
-}
-
-WebUSBPermissionProvider::~WebUSBPermissionProvider() {}
-
-base::WeakPtr<device::usb::PermissionProvider>
-WebUSBPermissionProvider::GetWeakPtr() {
-  return weak_factory_.GetWeakPtr();
-}
-
+// static
 bool WebUSBPermissionProvider::HasDevicePermission(
-    scoped_refptr<const device::UsbDevice> device) const {
+    content::RenderFrameHost* render_frame_host,
+    scoped_refptr<const device::UsbDevice> device) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   WebContents* web_contents =
-      WebContents::FromRenderFrameHost(render_frame_host_);
+      WebContents::FromRenderFrameHost(render_frame_host);
   GURL embedding_origin =
       web_contents->GetMainFrame()->GetLastCommittedURL().GetOrigin();
-  GURL requesting_origin =
-      render_frame_host_->GetLastCommittedURL().GetOrigin();
+  GURL requesting_origin = render_frame_host->GetLastCommittedURL().GetOrigin();
   Profile* profile =
       Profile::FromBrowserContext(web_contents->GetBrowserContext());
   UsbChooserContext* chooser_context =
@@ -98,6 +85,25 @@
                                    requesting_origin, nullptr, nullptr);
 }
 
+WebUSBPermissionProvider::WebUSBPermissionProvider(
+    content::RenderFrameHost* render_frame_host)
+    : render_frame_host_(render_frame_host), weak_factory_(this) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  DCHECK(render_frame_host_);
+}
+
+WebUSBPermissionProvider::~WebUSBPermissionProvider() {}
+
+base::WeakPtr<device::usb::PermissionProvider>
+WebUSBPermissionProvider::GetWeakPtr() {
+  return weak_factory_.GetWeakPtr();
+}
+
+bool WebUSBPermissionProvider::HasDevicePermission(
+    scoped_refptr<const device::UsbDevice> device) const {
+  return HasDevicePermission(render_frame_host_, device);
+}
+
 bool WebUSBPermissionProvider::HasConfigurationPermission(
     uint8_t requested_configuration_value,
     scoped_refptr<const device::UsbDevice> device) const {
diff --git a/chrome/browser/usb/web_usb_permission_provider.h b/chrome/browser/usb/web_usb_permission_provider.h
index dee8323..5668ee3 100644
--- a/chrome/browser/usb/web_usb_permission_provider.h
+++ b/chrome/browser/usb/web_usb_permission_provider.h
@@ -20,6 +20,10 @@
 // granted by the user through a device chooser UI.
 class WebUSBPermissionProvider : public device::usb::PermissionProvider {
  public:
+  static bool HasDevicePermission(
+      content::RenderFrameHost* render_frame_host,
+      scoped_refptr<const device::UsbDevice> device);
+
   explicit WebUSBPermissionProvider(
       content::RenderFrameHost* render_frame_host);
   ~WebUSBPermissionProvider() override;
diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni
index 48f5104..3e93269 100644
--- a/chrome/chrome_paks.gni
+++ b/chrome/chrome_paks.gni
@@ -169,6 +169,8 @@
 #   output_dir [required]: Directory to output .pak files. Locale .pak files
 #       will always be place in $output_dir/locales
 #   additional_extra_paks: List of extra .pak sources for resources.pak.
+#   additional_locale_source_patterns: additional_source_patterns for
+#       chrome_repack_locales().
 #   copy_data_to_bundle:
 #   deps:
 #   output_dir:
@@ -227,6 +229,9 @@
                              "visibility",
                            ])
 
+    if (defined(invoker.additional_locale_source_patterns)) {
+      additional_source_patterns = invoker.additional_locale_source_patterns
+    }
     input_locales = locales
     output_dir = "${invoker.output_dir}/locales"
 
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 90879c4..14d9ffd 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -108,10 +108,12 @@
 const base::Feature kMaterialDesignSettings{
     "MaterialDesignSettings", base::FEATURE_DISABLED_BY_DEFAULT};
 
+#if defined(ENABLE_PLUGINS)
 // Prefer HTML content by hiding Flash from the list of plugins.
 // https://crbug.com/626728
 const base::Feature kPreferHtmlOverPlugins{"PreferHtmlOverPlugins",
                                            base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
 
 #if defined(OS_CHROMEOS)
 // Runtime flag that indicates whether this leak detector should be enabled in
@@ -120,6 +122,12 @@
     "RuntimeMemoryLeakDetector", base::FEATURE_DISABLED_BY_DEFAULT};
 #endif  // defined(OS_CHROMEOS)
 
+#if defined(ENABLE_PLUGINS)
+// Disables Plugin Power Saver when Flash is in ALLOW mode.
+const base::Feature kRunAllFlashInAllowMode{"RunAllFlashInAllowMode",
+                                            base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
 const base::Feature kSafeSearchUrlReporting{"SafeSearchUrlReporting",
                                             base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 47384ff6..887f422 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -61,7 +61,9 @@
 
 extern const base::Feature kMaterialDesignSettings;
 
+#if defined(ENABLE_PLUGINS)
 extern const base::Feature kPreferHtmlOverPlugins;
+#endif
 
 extern const base::Feature kOverrideYouTubeFlashEmbed;
 
@@ -71,6 +73,10 @@
 extern const base::Feature kRuntimeMemoryLeakDetector;
 #endif  // defined(OS_CHROMEOS)
 
+#if defined(ENABLE_PLUGINS)
+extern const base::Feature kRunAllFlashInAllowMode;
+#endif
+
 extern const base::Feature kSafeSearchUrlReporting;
 
 extern const base::Feature kSimplifiedFullscreenUI;
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 9e456c6..61fdcde83e 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -649,11 +649,6 @@
 // Enables Media Router.
 const char kMediaRouter[]                   = "media-router";
 
-// Enables histograming of tasks served by MessageLoop. See
-// about:histograms/Loop for results, which show frequency of messages on each
-// thread, including APC count, object signalling count, etc.
-const char kMessageLoopHistogrammer[]       = "message-loop-histogrammer";
-
 // Enables the recording of metrics reports but disables reporting. In contrast
 // to kDisableMetrics, this executes all the code that a normal client would
 // use for reporting, except the report is dropped rather than sent to the
@@ -1095,14 +1090,6 @@
 const char kProgressBarAnimation[]          = "progress-bar-animation";
 
 // Specifies a particular tab management experiment to enable.
-const char kTabManagementExperimentTypeAnise[] =
-    "tab-management-experiment-type-anise";
-const char kTabManagementExperimentTypeBasil[] =
-    "tab-management-experiment-type-basil";
-const char kTabManagementExperimentTypeChive[] =
-    "tab-management-experiment-type-chive";
-const char kTabManagementExperimentTypeDill[] =
-    "tab-management-experiment-type-dill";
 const char kTabManagementExperimentTypeDisabled[] =
     "tab-management-experiment-type-disabled";
 const char kTabManagementExperimentTypeElderberry[] =
@@ -1345,7 +1332,7 @@
 #endif
 
 // -----------------------------------------------------------------------------
-// DO NOT ADD YOUR CRAP TO THE BOTTOM OF THIS FILE.
+// DO NOT ADD YOUR VERY NICE FLAGS TO THE BOTTOM OF THIS FILE.
 //
 // You were going to just dump your switches here, weren't you? Instead, please
 // put them in alphabetical order above, or in order inside the appropriate
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 68b641c..993633d 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -190,7 +190,6 @@
 extern const char kMaterialSecurityVerboseShowNonSecureNonAnimated[];
 extern const char kMediaCacheSize[];
 extern const char kMediaRouter[];
-extern const char kMessageLoopHistogrammer[];
 extern const char kMetricsRecordingOnly[];
 extern const char kMonitoringDestinationID[];
 extern const char kNetLogCaptureMode[];
@@ -310,10 +309,6 @@
 extern const char kMarketUrlForTesting[];
 extern const char kNtpSwitchToExistingTab[];
 extern const char kProgressBarAnimation[];
-extern const char kTabManagementExperimentTypeAnise[];
-extern const char kTabManagementExperimentTypeBasil[];
-extern const char kTabManagementExperimentTypeChive[];
-extern const char kTabManagementExperimentTypeDill[];
 extern const char kTabManagementExperimentTypeDisabled[];
 extern const char kTabManagementExperimentTypeElderberry[];
 extern const char kWebApkServerUrl[];
diff --git a/chrome/common/extensions/api/BUILD.gn b/chrome/common/extensions/api/BUILD.gn
index b7e17cd..96db7d8 100644
--- a/chrome/common/extensions/api/BUILD.gn
+++ b/chrome/common/extensions/api/BUILD.gn
@@ -17,7 +17,6 @@
   "automation.idl",
   "automation_internal.idl",
   "autotest_private.idl",
-  "bluetooth_low_energy.idl",
   "bookmark_manager_private.json",
   "bookmarks.json",
   "braille_display_private.idl",
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json
index cfd0aa8..af7d9e2 100644
--- a/chrome/common/extensions/api/_api_features.json
+++ b/chrome/common/extensions/api/_api_features.json
@@ -676,7 +676,7 @@
   },
   "imageWriterPrivate": {
     "dependencies": ["permission:imageWriterPrivate"],
-    "extension_types": ["platform_app"],
+    "extension_types": ["extension", "platform_app"],
     "contexts": ["blessed_extension"]
   },
   "quickUnlockPrivate": {
diff --git a/chrome/common/extensions/api/file_manager_private.idl b/chrome/common/extensions/api/file_manager_private.idl
index 51d428a50..a7f4fb0 100644
--- a/chrome/common/extensions/api/file_manager_private.idl
+++ b/chrome/common/extensions/api/file_manager_private.idl
@@ -167,6 +167,7 @@
   contentMimeType,
   sharedWithMe,
   shared,
+  starred,
   externalFileUrl
 };
 
@@ -275,6 +276,9 @@
   // by others.)
   boolean? shared;
 
+  // True if the entry is starred by the user.
+  boolean? starred;
+
   // External file URL to open the file in browser.
   DOMString? externalFileUrl;
 };
diff --git a/chrome/common/extensions/docs/templates/json/chrome_sidenav.json b/chrome/common/extensions/docs/templates/json/chrome_sidenav.json
index 623d05b..fb54e07 100644
--- a/chrome/common/extensions/docs/templates/json/chrome_sidenav.json
+++ b/chrome/common/extensions/docs/templates/json/chrome_sidenav.json
@@ -266,38 +266,6 @@
             "href": "/multidevice/webview/tipsandtricks"
           }
         ]
-      },
-      {
-        "title": "Chrome for iOS",
-        "href": "/multidevice/ios/overview",
-        "items": [
-          {
-            "title": "Overview",
-            "href": "/multidevice/ios/overview"
-          },
-          {
-            "title": "Opening Links in Chrome",
-            "href": "/multidevice/ios/links"
-          },
-          {
-            "title": "Case Studies",
-            "href": "/multidevice/ios/case-studies",
-            "items": [
-              {
-                "title": "Case Studies",
-                "href": "/multidevice/ios/case-studies"
-              },
-              {
-                "title": "Pocket",
-                "href": "/multidevice/ios/pocket"
-              },
-              {
-                "title": "Feedly",
-                "href": "/multidevice/ios/feedly"
-              }
-            ]
-          }
-        ]
       }
     ]
   },
diff --git a/chrome/gpu/arc_gpu_video_decode_accelerator.cc b/chrome/gpu/arc_gpu_video_decode_accelerator.cc
index 27e0a9e..dc194db3 100644
--- a/chrome/gpu/arc_gpu_video_decode_accelerator.cc
+++ b/chrome/gpu/arc_gpu_video_decode_accelerator.cc
@@ -299,8 +299,8 @@
         handle.native_pixmap_handle.fds.emplace_back(
             base::FileDescriptor(info.handle.release(), true));
         for (const auto& plane : info.planes) {
-          handle.native_pixmap_handle.planes.emplace_back(
-              plane.stride, plane.offset, 0);
+          handle.native_pixmap_handle.planes.emplace_back(plane.stride,
+                                                          plane.offset, 0, 0);
         }
 #endif
         vda_->ImportBufferForPicture(index, handle);
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
index 087e254a..840a53be 100644
--- a/chrome/renderer/chrome_content_renderer_client.cc
+++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -1076,6 +1076,16 @@
     return true;
   }
 
+  // TODO(lukasza): https://crbug.com/650694: For now, we skip the rest for POST
+  // submissions.  This is because 1) in M54 there are some remaining issues
+  // with POST in OpenURL path (e.g. https://crbug.com/648648) and 2) OpenURL
+  // path regresses (blocks) navigations that result in downloads
+  // (https://crbug.com/646261).  In the long-term we should avoid forking for
+  // extensions (not hosted apps though) altogether and rely on transfers logic
+  // instead.
+  if (http_method != "GET")
+    return false;
+
   // If |url| matches one of the prerendered URLs, stop this navigation and try
   // to swap in the prerendered page on the browser process. If the prerendered
   // page no longer exists by the time the OpenURL IPC is handled, a normal
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index b01586da..88ac0e95 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -227,7 +227,8 @@
 
     public_deps += [
       "//ash",
-      "//ash:test_support_without_content",
+      "//ash:ash_with_aura_test_support",
+      "//ash:test_support_with_content",
       "//ui/aura",
       "//ui/aura:test_support",
     ]
@@ -2066,7 +2067,10 @@
         "../browser/ui/ash/volume_controller_browsertest_chromeos.cc",
         "../browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc",
       ]
-      deps += [ "//ash:test_support_without_content" ]
+      deps += [
+        "//ash:ash_with_aura_test_support",
+        "//ash:test_support_with_content",
+      ]
 
       if (enable_app_list) {
         deps += [ ":test_support_applist_ash" ]
@@ -4037,6 +4041,7 @@
       "../browser/ui/window_sizer/window_sizer_ash_unittest.cc",
     ]
     deps += [
+      "//ash:ash_with_aura_test_support",
       "//ash:test_support_with_content",
       "//ash/common/strings",
       "//ash/resources",
diff --git a/chrome/test/data/downloads/tiny_binary.bin b/chrome/test/data/downloads/tiny_binary.bin
new file mode 100644
index 0000000..593f470
--- /dev/null
+++ b/chrome/test/data/downloads/tiny_binary.bin
Binary files differ
diff --git a/chrome/test/data/extensions/api_test/browser_action/popup_with_form/manifest.json b/chrome/test/data/extensions/api_test/browser_action/popup_with_form/manifest.json
new file mode 100644
index 0000000..ff856f8
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/browser_action/popup_with_form/manifest.json
@@ -0,0 +1,9 @@
+{
+  "name": "Popup with form",
+  "version": "0.1",
+  "manifest_version": 2,
+  "description": "Test for navigating a browser action popup via POST",
+  "browser_action": {
+    "default_popup": "popup.html"
+  }
+}
diff --git a/chrome/test/data/extensions/api_test/browser_action/popup_with_form/other_page.html b/chrome/test/data/extensions/api_test/browser_action/popup_with_form/other_page.html
new file mode 100644
index 0000000..ceec3a6
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/browser_action/popup_with_form/other_page.html
@@ -0,0 +1,6 @@
+<html>
+<body>
+  <div>Another page within the same extension.</div>
+</body>
+</html>
+
diff --git a/chrome/test/data/extensions/api_test/browser_action/popup_with_form/popup.html b/chrome/test/data/extensions/api_test/browser_action/popup_with_form/popup.html
new file mode 100644
index 0000000..062c8d3b
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/browser_action/popup_with_form/popup.html
@@ -0,0 +1,14 @@
+<html>
+<head>
+  <script src="popup.js"></script>
+</head>
+<body>
+  <div>This popup contains a frame that triggers a POST navigation.</div>
+  <form id="form" method="POST" action="other_page.html">
+      Test field:
+      <input name="test-field" type="text" value="test-value">
+      <input type="submit" value="Submit">
+  </form>
+</body>
+</html>
+
diff --git a/chrome/test/data/extensions/api_test/browser_action/popup_with_form/popup.js b/chrome/test/data/extensions/api_test/browser_action/popup_with_form/popup.js
new file mode 100644
index 0000000..ecba7c80
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/browser_action/popup_with_form/popup.js
@@ -0,0 +1,7 @@
+// 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.
+
+window.addEventListener('load', function() {
+  chrome.test.notifyPass();
+}, false);
diff --git a/chrome/test/data/extensions/api_test/tab_capture/end_to_end.js b/chrome/test/data/extensions/api_test/tab_capture/end_to_end.js
index ba449bdf..087eddf 100644
--- a/chrome/test/data/extensions/api_test/tab_capture/end_to_end.js
+++ b/chrome/test/data/extensions/api_test/tab_capture/end_to_end.js
@@ -5,7 +5,7 @@
 // The tests here cover the end-to-end functionality of tab capturing and
 // playback as video.  The page generates video test patterns that rotate
 // cyclicly, and the rendering output of the tab is captured into a
-// LocalMediaStream.  This stream is then piped into a video element for
+// local MediaStream.  This stream is then piped into a video element for
 // playback, and a canvas is used to examine the frames of the video for
 // expected content.  The stream may be plumbed one of two ways, depending on
 // the 'method' query param:
@@ -13,6 +13,12 @@
 //   local:  LocalMediaStream --> DOM Video Element
 //   webrtc: LocalMediaStream --> PeerConnection (sender)
 //             --> PeerConnection (receiver) --> DOM Video Element
+//
+// There are two rounds of testing: In each round, video frames are received and
+// monitored, and the round successfully completes once each of the expected
+// patterns is observed. Between the two rounds, the MediaStream is disconnected
+// from its consumer, which places the tab capture "device" into a suspend mode.
+var testRoundNumber = 0;
 
 // The test pattern cycles as a color fill of red, then green, then blue.
 var colors = [ [ 255, 0, 0 ], [ 0, 255, 0 ], [ 0, 0, 255 ] ];
@@ -78,16 +84,19 @@
     if (curIdx >= colors.length) {  // Completed a cycle.
       curIdx = 0;
       // Increase the wait time between switching test patterns for overloaded
-      // bots that aren't capturing all the frames of video.
-      this.stepTimeMillis *= 1.25;
+      // bots that aren't capturing all the frames of video. Only do this for
+      // the first test phase, since increases shouldn't be needed after that.
+      if (testRoundNumber == 0) {
+        this.stepTimeMillis *= 1.25;
+      }
     }
     this.nextSteppingAt = now + this.stepTimeMillis;
   }
 }
 
 function waitForExpectedColors(colorDeviation) {
-  // If needed, create the video and canvas elements, but no need to append them
-  // to the DOM.
+  // At the start of a round of testing, create the video and canvas elements,
+  // but no need to append them to the DOM.
   if (!this.video) {
     this.video = document.createElement("video");
     this.video.width = width;
@@ -119,15 +128,39 @@
       if (Math.abs(pixel[0] - curColor[0]) <= colorDeviation &&
           Math.abs(pixel[1] - curColor[1]) <= colorDeviation &&
           Math.abs(pixel[2] - curColor[2]) <= colorDeviation) {
-        console.debug("Observed expected color RGB(" + curColor +
-            ") in the video as RGB(" + pixel + ")");
+        console.debug(`${testRoundNumber == 0 ? 'First' : 'Second'} round: ` +
+            `Observed expected color RGB(${curColor}) in the video as ` +
+            `RGB(${pixel})`);
         expectedColors.splice(i, 1);
       }
     }
   }
 
   if (expectedColors.length == 0) {
-    chrome.test.succeed();
+    // Successful end of the current test round. If the first round, sleep, then
+    // execute the second round. If the second round, then the whole test has
+    // succeeded.
+    if (testRoundNumber == 0) {
+      // Destroy the video, which will disconnect the consumer of the
+      // MediaStream.
+      this.video.removeEventListener("error", chrome.test.fail);
+      this.video.src = '';
+      this.video = null;
+
+      // Wait one second, then execute the second round of testing. This tests
+      // the suspend/resume functionality of tab capture (w.r.t. a MediaStream
+      // having no consumers, and then being re-used with a new consumer).
+      console.debug('First round succeeded! Now testing suspend/resume...');
+      setTimeout(function() {
+        ++testRoundNumber;
+        for (const color of colors) {
+          expectedColors.push(color);
+        }
+        waitForExpectedColors(colorDeviation);
+      }, 1000);
+    } else {
+      chrome.test.succeed();
+    }
   } else {
     setTimeout(function () { waitForExpectedColors(colorDeviation); },
                1000 / frameRate);
diff --git a/chrome/test/data/extensions/theme_with_extension.crx b/chrome/test/data/extensions/theme_with_extension.crx
index bd0d312..77e395f 100644
--- a/chrome/test/data/extensions/theme_with_extension.crx
+++ b/chrome/test/data/extensions/theme_with_extension.crx
Binary files differ
diff --git a/chrome/test/data/webui/cr_elements/cr_shared_menu_tests.js b/chrome/test/data/webui/cr_elements/cr_shared_menu_tests.js
index b5ac54a..7b18a7a 100644
--- a/chrome/test/data/webui/cr_elements/cr_shared_menu_tests.js
+++ b/chrome/test/data/webui/cr_elements/cr_shared_menu_tests.js
@@ -12,17 +12,15 @@
   var items = [];
 
   function afterOpen(callback) {
-    menu.addEventListener('iron-overlay-opened', function f() {
-      menu.removeEventListener('iron-overlay-opened', f);
-      callback();
+    listenOnce(menu, 'iron-overlay-opened', function () {
+      // paper-listbox applies focus after opening with microtask timing.
+      // Delay until that has happened:
+      setTimeout(callback, 0);
     });
   }
 
   function afterClose(callback) {
-    menu.addEventListener('iron-overlay-closed', function f() {
-      menu.removeEventListener('iron-overlay-closed', f);
-      callback();
-    });
+    listenOnce(menu, 'iron-overlay-closed', () => callback());
   }
 
   suiteSetup(function() {
@@ -146,32 +144,48 @@
       });
     });
 
-    test('focus is trapped inside the menu', function(done) {
+    test('tab closes menu', function(done) {
       button.focus();
       MockInteractions.tap(button);
 
       afterOpen(function() {
-        // Simulate shift-tab on first element.
-        assertEquals(items[0], menu.shadowRoot.activeElement);
+        MockInteractions.pressAndReleaseKeyOn(items[0], 9);
+        afterClose(function() {
+          // Focus should move to a different element, but we can't simulate
+          // the right events to test this.
+          done();
+        });
+      });
+    });
+
+    test('shift-tab closes menu', function(done) {
+      button.focus();
+      MockInteractions.tap(button);
+
+      afterOpen(function() {
         MockInteractions.pressAndReleaseKeyOn(items[0], 9, ['shift']);
-        assertEquals(items[2], menu.shadowRoot.activeElement);
+        afterClose(done);
+      });
+    });
 
-        // Simulate tab on last element.
-        MockInteractions.pressAndReleaseKeyOn(items[2], 9);
-        assertEquals(items[0], menu.shadowRoot.activeElement);
+    test('up and down change focus', function(done) {
+      button.focus();
+      MockInteractions.tap(button);
 
-        // Simulate shift-tab on first element.
-        assertEquals(items[0], menu.shadowRoot.activeElement);
-        MockInteractions.pressAndReleaseKeyOn(items[0], 9, ['shift']);
-        assertEquals(items[2], menu.shadowRoot.activeElement);
+      afterOpen(function() {
+        // Pressing down on first item goes to second item.
+        assertEquals(items[0], document.activeElement);
+        MockInteractions.pressAndReleaseKeyOn(items[0], 40);
+        assertEquals(items[1], document.activeElement);
 
-        // Simulate shift-tab on last element. This should simply cause the
-        // browser to focus the previous item in the tab order, since
-        // cr-shared-menu should not wrap in this case. However, we can't mimic
-        // native events from JS, so the focus won't actually move unless
-        // cr-shared--menu misbehaves.
-        MockInteractions.pressAndReleaseKeyOn(items[2], 9, ['shift']);
-        assertEquals(items[2], menu.shadowRoot.activeElement);
+        // Pressing down twice more cycles back to first item.
+        MockInteractions.pressAndReleaseKeyOn(items[1], 40);
+        MockInteractions.pressAndReleaseKeyOn(items[2], 40);
+        assertEquals(items[0], document.activeElement);
+
+        // Pressing up cycles to last item.
+        MockInteractions.pressAndReleaseKeyOn(items[0], 38);
+        assertEquals(items[2], document.activeElement);
 
         done();
       });
@@ -193,6 +207,7 @@
 
       items[3] = document.createElement('button');
       items[3].disabled = true;
+      menu.appendChild(items[3]);
 
       items[4] = document.createElement('paper-item');
       items[4].hidden = true;
@@ -209,13 +224,13 @@
         assertEquals(items[1], menu.shadowRoot.activeElement);
 
         // The last two items are disabled or hidden, so they should be skipped
-        // too.
-        MockInteractions.pressAndReleaseKeyOn(items[1], 9, ['shift']);
+        // when pressing up.
+        MockInteractions.pressAndReleaseKeyOn(items[1], 38);
         assertEquals(items[2], menu.shadowRoot.activeElement);
 
-        // Simulate tab on last tabbable element to wrap to the first tabbable
-        // element again.
-        MockInteractions.pressAndReleaseKeyOn(items[2], 9);
+        // Simulate pressing down on last focusable element to wrap to first
+        // focusable element.
+        MockInteractions.pressAndReleaseKeyOn(items[2], 40);
         assertEquals(items[1], menu.shadowRoot.activeElement);
 
         done();
diff --git a/chrome/test/data/webui/md_history/history_list_test.js b/chrome/test/data/webui/md_history/history_list_test.js
index 2df6533..6bf4ebc 100644
--- a/chrome/test/data/webui/md_history/history_list_test.js
+++ b/chrome/test/data/webui/md_history/history_list_test.js
@@ -410,9 +410,18 @@
                 'https://www.google.com',
                 'https://en.wikipedia.org',
               ], element.historyData_.map(item => item.title));
+
+              // Deletion should deselect all.
+              assertDeepEquals(
+                  [false, false, false],
+                  items.slice(0, 3).map(i => i.selected));
+
               done();
             });
           });
+
+          MockInteractions.tap(items[1].$.checkbox);
+          MockInteractions.tap(items[3].$.checkbox);
           MockInteractions.tap(items[1].$['menu-button']);
           app.$.history.$.sharedMenu.get();
           MockInteractions.tap(app.$.history.$$('#menuRemoveButton'));
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js
index 2f4e928..8664769 100644
--- a/chrome/test/data/webui/settings/cr_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -768,6 +768,13 @@
   mocha.run();
 });
 
+// Times out on Windows Tests (dbg). See https://crbug.com/651296.
+GEN('#if defined(OS_WIN)');
+GEN('#define MAYBE_MainPage_All DISABLED_All');
+GEN('#else');
+GEN('#define MAYBE_MainPage_All All');
+GEN('#endif');
+
 /**
  * Test fixture for chrome/browser/resources/settings/settings_main/.
  * @constructor
@@ -787,7 +794,7 @@
   ]),
 };
 
-TEST_F('CrSettingsMainPageTest', 'All', function() {
+TEST_F('CrSettingsMainPageTest', 'MAYBE_MainPage_All', function() {
   settings_main_page.registerTests();
   mocha.run();
 });
diff --git a/chrome/test/data/webui/settings/easy_unlock_browsertest_chromeos.js b/chrome/test/data/webui/settings/easy_unlock_browsertest_chromeos.js
index d6214712..b3c1f4bb 100644
--- a/chrome/test/data/webui/settings/easy_unlock_browsertest_chromeos.js
+++ b/chrome/test/data/webui/settings/easy_unlock_browsertest_chromeos.js
@@ -134,7 +134,7 @@
 
       // Before clearing the body, save a copy of the real prefs so we can
       // cleanly re-create the People page element.
-      prefs = document.querySelector('cr-settings').$$('settings-prefs').prefs;
+      prefs = document.querySelector('settings-ui').$$('settings-prefs').prefs;
     });
 
     setup(function() {
diff --git a/chrome/test/data/webui/settings/languages_page_browsertest.js b/chrome/test/data/webui/settings/languages_page_browsertest.js
index d03d93da..ad427df1 100644
--- a/chrome/test/data/webui/settings/languages_page_browsertest.js
+++ b/chrome/test/data/webui/settings/languages_page_browsertest.js
@@ -87,6 +87,7 @@
       languagesPage = assert(
           languagesSection.querySelector('settings-languages-page'));
       languagesCollapse = languagesPage.$.languagesCollapse;
+      languagesCollapse.opened = true;
 
       languageHelper = languagesPage.languageHelper;
       return languageHelper.whenReady();
@@ -193,56 +194,88 @@
       });
     });
 
-    test('should not set UI language', function() {
-      var languageOptionsDropdownTrigger = languagesCollapse.querySelector(
-          'paper-icon-button');
-      assertTrue(!!languageOptionsDropdownTrigger);
+    suite('language menu', function() {
+      var origTranslateEnabled;
 
-      // This shouldn't get called.
-      languageHelper.setUILanguage = assertNotReached;
+      suiteSetup(function() {
+        // Cache the value of Translate to avoid side effects.
+        origTranslateEnabled = languageHelper.prefs.translate.enabled.value;
+      });
 
-      // Tap the menu trigger twice to open and close the menu.
-      MockInteractions.tap(languageOptionsDropdownTrigger);
-      MockInteractions.tap(languageOptionsDropdownTrigger);
+      suiteTeardown(function() {
+        var cur = languageHelper.prefs.translate.enabled.value;
+        // Restore the value of Translate.
+        languageHelper.setPrefValue('translate.enabled', origTranslateEnabled);
+        cur = languageHelper.prefs.translate.enabled.value;
+      });
 
-      languageHelper.setUILanguage = languageHelper.__proto__.setUILanguage;
-    });
-
-    test('remove language', function() {
-      var numEnabled = languagesPage.languages.enabled.length;
-
-      // Enabled a language which we can then disable.
-      var newLanguage = getAvailableLanguage();
-      languageHelper.enableLanguage(newLanguage.code);
-
-      // Wait for the language to be enabled.
-      return whenNumEnabledLanguagesBecomes(numEnabled + 1).then(function() {
-        // Populate the dom-repeat.
-        Polymer.dom.flush();
-
-        // Find the new language item.
-        var items = languagesCollapse.querySelectorAll('.list-item');
-        var domRepeat = assert(
-            languagesCollapse.querySelector('template[is="dom-repeat"]'));
-        var item = Array.from(items).find(function(el) {
-          return domRepeat.itemForElement(el) &&
-              domRepeat.itemForElement(el).language == newLanguage;
-        });
-
-        // Open the menu and select Remove.
-        MockInteractions.tap(item.querySelector('paper-icon-button'));
-
+      test('structure', function(done) {
+        var languageOptionsDropdownTrigger = languagesCollapse.querySelector(
+            'paper-icon-button');
+        assertTrue(!!languageOptionsDropdownTrigger);
+        MockInteractions.tap(languageOptionsDropdownTrigger);
         var languageMenu = assert(languagesPage.$$('cr-shared-menu'));
-        assertTrue(languageMenu.menuOpen);
-        var removeMenuItem = assert(languageMenu.querySelector(
-            '.dropdown-item:last-child'));
-        assertFalse(removeMenuItem.disabled);
-        MockInteractions.tap(removeMenuItem);
-        assertFalse(languageMenu.menuOpen);
 
-        // We should go back down to the original number of enabled languages.
-        return whenNumEnabledLanguagesBecomes(numEnabled).then(function() {
-          assertFalse(languageHelper.isLanguageEnabled(newLanguage.code));
+        listenOnce(languageMenu, 'iron-overlay-opened', function() {
+          assertTrue(languageMenu.menuOpen);
+
+          // Enable Translate so the menu always shows the Translate checkbox.
+          languageHelper.setPrefValue('translate.enabled', true);
+
+          var separator = languageMenu.querySelector('hr');
+          assertEquals(1, separator.offsetHeight);
+
+          // Disable Translate. On platforms that can't change the UI language,
+          // this hides all the checkboxes, so the separator isn't needed.
+          // Chrome OS and Windows still show a checkbox and thus the separator.
+          languageHelper.setPrefValue('translate.enabled', false);
+          if (cr.isChromeOS || cr.isWindows)
+            assertEquals(1, separator.offsetHeight);
+          else
+            assertEquals(0, separator.offsetHeight);
+
+          MockInteractions.tap(languageOptionsDropdownTrigger);
+          assertFalse(languageMenu.menuOpen);
+          done();
+        });
+      });
+
+      test('remove language', function() {
+        var numEnabled = languagesPage.languages.enabled.length;
+
+        // Enabled a language which we can then disable.
+        var newLanguage = getAvailableLanguage();
+        languageHelper.enableLanguage(newLanguage.code);
+
+        // Wait for the language to be enabled.
+        return whenNumEnabledLanguagesBecomes(numEnabled + 1).then(function() {
+          // Populate the dom-repeat.
+          Polymer.dom.flush();
+
+          // Find the new language item.
+          var items = languagesCollapse.querySelectorAll('.list-item');
+          var domRepeat = assert(
+              languagesCollapse.querySelector('template[is="dom-repeat"]'));
+          var item = Array.from(items).find(function(el) {
+            return domRepeat.itemForElement(el) &&
+                domRepeat.itemForElement(el).language == newLanguage;
+          });
+
+          // Open the menu and select Remove.
+          MockInteractions.tap(item.querySelector('paper-icon-button'));
+
+          var languageMenu = assert(languagesPage.$$('cr-shared-menu'));
+          assertTrue(languageMenu.menuOpen);
+          var removeMenuItem = assert(languageMenu.querySelector(
+              '.dropdown-item:last-child'));
+          assertFalse(removeMenuItem.disabled);
+          MockInteractions.tap(removeMenuItem);
+          assertFalse(languageMenu.menuOpen);
+
+          // We should go back down to the original number of enabled languages.
+          return whenNumEnabledLanguagesBecomes(numEnabled).then(function() {
+            assertFalse(languageHelper.isLanguageEnabled(newLanguage.code));
+          });
         });
       });
     });
diff --git a/chrome/test/data/webui/settings/languages_tests.js b/chrome/test/data/webui/settings/languages_tests.js
index d1d98ac..f3341262 100644
--- a/chrome/test/data/webui/settings/languages_tests.js
+++ b/chrome/test/data/webui/settings/languages_tests.js
@@ -63,6 +63,17 @@
       return fakePrefs;
     }
 
+    /**
+     * @param {!Array<string>} expected
+     */
+    function assertLanguageOrder(expected) {
+      assertEquals(expected.length, languageHelper.languages.enabled.length);
+      for (var i = 0; i < expected.length; i++) {
+        assertEquals(
+            expected[i], languageHelper.languages.enabled[i].language.code);
+      }
+    }
+
     var languageHelper;
     var languageSettingsPrivate;
 
@@ -93,11 +104,7 @@
         assertEquals(languageSettingsPrivate.languages[i].code,
                      languageHelper.languages.supported[i].code);
       }
-      assertEquals(2, languageHelper.languages.enabled.length);
-      assertEquals('en-US',
-                   languageHelper.languages.enabled[0].language.code);
-      assertEquals('sw',
-                   languageHelper.languages.enabled[1].language.code);
+      assertLanguageOrder(['en-US', 'sw']);
       assertEquals('en', languageHelper.languages.translateTarget);
 
       // TODO(michaelpg): Test other aspects of the model.
@@ -117,34 +124,34 @@
     });
 
     test('reorder languages', function() {
+      // New language is added at the end.
       languageHelper.enableLanguage('en-CA');
-      assertEquals('en-US', languageHelper.languages.enabled[0].language.code);
-      assertEquals('sw', languageHelper.languages.enabled[1].language.code);
-      assertEquals('en-CA', languageHelper.languages.enabled[2].language.code);
+      assertLanguageOrder(['en-US', 'sw', 'en-CA']);
 
       // Can move a language up.
       languageHelper.moveLanguage('en-CA', -1);
-      assertEquals('en-US', languageHelper.languages.enabled[0].language.code);
-      assertEquals('en-CA', languageHelper.languages.enabled[1].language.code);
-      assertEquals('sw', languageHelper.languages.enabled[2].language.code);
+      assertLanguageOrder(['en-US', 'en-CA', 'sw']);
 
       // Can move a language down.
       languageHelper.moveLanguage('en-US', 1);
-      assertEquals('en-CA', languageHelper.languages.enabled[0].language.code);
-      assertEquals('en-US', languageHelper.languages.enabled[1].language.code);
-      assertEquals('sw', languageHelper.languages.enabled[2].language.code);
+      assertLanguageOrder(['en-CA', 'en-US', 'sw']);
+
+      // Can move a language to the front.
+      languageHelper.moveLanguageToFront('sw');
+      var expectedOrder = ['sw', 'en-CA', 'en-US'];
+      assertLanguageOrder(expectedOrder);
 
       // Moving the first language up has no effect.
-      languageHelper.moveLanguage('en-CA', -1);
-      assertEquals('en-CA', languageHelper.languages.enabled[0].language.code);
-      assertEquals('en-US', languageHelper.languages.enabled[1].language.code);
-      assertEquals('sw', languageHelper.languages.enabled[2].language.code);
+      languageHelper.moveLanguage('sw', -1);
+      assertLanguageOrder(expectedOrder);
+
+      // Moving the first language to top has no effect.
+      languageHelper.moveLanguageToFront('sw');
+      assertLanguageOrder(expectedOrder);
 
       // Moving the last language down has no effect.
-      languageHelper.moveLanguage('sw', 1);
-      assertEquals('en-CA', languageHelper.languages.enabled[0].language.code);
-      assertEquals('en-US', languageHelper.languages.enabled[1].language.code);
-      assertEquals('sw', languageHelper.languages.enabled[2].language.code);
+      languageHelper.moveLanguage('en-US', 1);
+      assertLanguageOrder(expectedOrder);
     });
 
     if (cr.isChromeOS) {
diff --git a/chrome/test/data/webui/settings/on_startup_browsertest.js b/chrome/test/data/webui/settings/on_startup_browsertest.js
index f6c0db2..5c9e7aa3 100644
--- a/chrome/test/data/webui/settings/on_startup_browsertest.js
+++ b/chrome/test/data/webui/settings/on_startup_browsertest.js
@@ -62,7 +62,7 @@
       self.getPage('basic').set('pageVisibility.onStartup', true);
       Polymer.dom.flush();
 
-      settingsPrefs = document.querySelector('cr-settings').$$(
+      settingsPrefs = document.querySelector('settings-ui').$$(
           'settings-prefs');
       assertTrue(!!settingsPrefs);
       return CrSettingsPrefs.initialized;
diff --git a/chrome/test/data/webui/settings/settings_page_browsertest.js b/chrome/test/data/webui/settings/settings_page_browsertest.js
index a3a2fb1..afd3351 100644
--- a/chrome/test/data/webui/settings/settings_page_browsertest.js
+++ b/chrome/test/data/webui/settings/settings_page_browsertest.js
@@ -55,9 +55,7 @@
    * @return {!PolymerElement} The PolymerElement for the page.
    */
   getPage: function(type) {
-    var settings = document.querySelector('cr-settings');
-    assertTrue(!!settings);
-    var settingsUi = settings.$$('settings-ui');
+    var settingsUi = document.querySelector('settings-ui');
     assertTrue(!!settingsUi);
     var settingsMain = settingsUi.$$('settings-main');
     assertTrue(!!settingsMain);
diff --git a/chrome/test/data/webui/settings/settings_ui_browsertest.js b/chrome/test/data/webui/settings/settings_ui_browsertest.js
index 5e08ca8..bc44014 100644
--- a/chrome/test/data/webui/settings/settings_ui_browsertest.js
+++ b/chrome/test/data/webui/settings/settings_ui_browsertest.js
@@ -31,8 +31,7 @@
     var ui;
 
     suiteSetup(function() {
-      var settings = assert(document.querySelector('cr-settings'));
-      ui = assert(settings.$$('settings-ui'));
+      ui = assert(document.querySelector('settings-ui'));
     });
 
     test('basic', function() {
diff --git a/chrome/test/data/webui/settings/site_list_tests.js b/chrome/test/data/webui/settings/site_list_tests.js
index bb260e5..57962f0 100644
--- a/chrome/test/data/webui/settings/site_list_tests.js
+++ b/chrome/test/data/webui/settings/site_list_tests.js
@@ -282,6 +282,23 @@
         }
       };
 
+      /**
+       * An example Javascript pref with a chrome-extension:// scheme.
+       * @type {SiteSettingsPref}
+       */
+      var prefsChromeExtension = {
+        exceptions: {
+          javascript: [
+            {
+              embeddingOrigin: '',
+              origin: 'chrome-extension://cfhgfbfpcbnnbibfphagcjmgjfjmojfa/',
+              setting: 'block',
+              source: 'preference',
+            },
+          ]
+        }
+      };
+
       // Import necessary html before running suite.
       suiteSetup(function() {
         CrSettingsPrefs.setInitialized();
@@ -499,11 +516,11 @@
               MockInteractions.tap(menuItems[2]);
               return browserProxy.whenCalled(
                   'resetCategoryPermissionForOrigin');
-            }).then(function(arguments) {
-              assertEquals('http://foo.com', arguments[0]);
-              assertEquals('http://foo.com', arguments[1]);
-              assertEquals(settings.ContentSettingsTypes.COOKIES, arguments[2]);
-              assertFalse(arguments[3]);  // Incognito.
+            }).then(function(args) {
+              assertEquals('http://foo.com', args[0]);
+              assertEquals('http://foo.com', args[1]);
+              assertEquals(settings.ContentSettingsTypes.COOKIES, args[2]);
+              assertFalse(args[3]);  // Incognito.
             });
       });
 
@@ -535,11 +552,11 @@
               MockInteractions.tap(menuItems[1]);
               return browserProxy.whenCalled(
                   'resetCategoryPermissionForOrigin');
-            }).then(function(arguments) {
-              assertEquals('http://foo.com', arguments[0]);
-              assertEquals('http://foo.com', arguments[1]);
-              assertEquals(settings.ContentSettingsTypes.COOKIES, arguments[2]);
-              assertTrue(arguments[3]);  // Incognito.
+            }).then(function(args) {
+              assertEquals('http://foo.com', args[0]);
+              assertEquals('http://foo.com', args[1]);
+              assertEquals(settings.ContentSettingsTypes.COOKIES, args[2]);
+              assertTrue(args[3]);  // Incognito.
             });
       });
 
@@ -768,6 +785,27 @@
           return browserProxy.whenCalled('setCategoryPermissionForOrigin');
         });
       });
+
+      test('Chrome Extension scheme', function() {
+        setupCategory(settings.ContentSettingsTypes.JAVASCRIPT,
+            settings.PermissionValues.BLOCK, prefsChromeExtension);
+        return browserProxy.whenCalled('getExceptionList').then(function(
+            contentType) {
+          Polymer.dom.flush();
+          assertMenu(['Allow', 'Remove'], testElement);
+
+          var menuItems = getMenuItems(testElement.$.listContainer, 0);
+          assertTrue(!!menuItems);
+          MockInteractions.tap(menuItems[0]);  // Action: Allow.
+          return browserProxy.whenCalled('setCategoryPermissionForOrigin');
+        }).then(function(args) {
+          assertEquals('chrome-extension://cfhgfbfpcbnnbibfphagcjmgjfjmojfa/',
+              args[0]);
+          assertEquals('', args[1]);
+          assertEquals(settings.ContentSettingsTypes.JAVASCRIPT, args[2]);
+          assertEquals('allow', args[3]);
+        });
+      });
     });
   }
   return {
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastShellActivity.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastShellActivity.java
index 6c576f5..311fc4e 100644
--- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastShellActivity.java
+++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastShellActivity.java
@@ -20,9 +20,6 @@
 import android.widget.Toast;
 
 import org.chromium.base.Log;
-import org.chromium.content.browser.ActivityContentVideoViewEmbedder;
-import org.chromium.content.browser.ContentVideoViewEmbedder;
-import org.chromium.content.browser.ContentViewClient;
 import org.chromium.content.browser.ContentViewCore;
 import org.chromium.ui.base.WindowAndroid;
 
@@ -114,13 +111,6 @@
         String url = getIntent().getDataString();
         Log.d(TAG, "onCreate startupUrl: %s", url);
         mNativeCastWindow = mCastWindowManager.launchCastWindow(url);
-
-        getActiveContentViewCore().setContentViewClient(new ContentViewClient() {
-            @Override
-            public ContentVideoViewEmbedder getContentVideoViewEmbedder() {
-                return new ActivityContentVideoViewEmbedder(CastShellActivity.this);
-            }
-        });
     }
 
     @Override
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWindowAndroid.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWindowAndroid.java
index 1769e37..7dbe284 100644
--- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWindowAndroid.java
+++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWindowAndroid.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chromecast.shell;
 
+import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
@@ -17,6 +18,8 @@
 
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
+import org.chromium.content.browser.ActivityContentVideoViewEmbedder;
+import org.chromium.content.browser.ContentVideoViewEmbedder;
 import org.chromium.content.browser.ContentView;
 import org.chromium.content.browser.ContentViewCore;
 import org.chromium.content.browser.ContentViewRenderView;
@@ -122,12 +125,15 @@
     /**
      * Initializes the ContentView based on the native tab contents pointer passed in.
      * @param nativeWebContents The pointer to the native tab contents object.
+     * @param renderProcessId ID of the corresponding render process host.
+     * @param productVersion String containing version description.
      */
     @SuppressWarnings("unused")
     @CalledByNative
-    private void initFromNativeWebContents(WebContents webContents, int renderProcessId) {
+    private void initFromNativeWebContents(WebContents webContents, int renderProcessId,
+            String productVersion) {
         Context context = getContext();
-        mContentViewCore = new ContentViewCore(context);
+        mContentViewCore = new ContentViewCore(context, productVersion);
         ContentView view = ContentView.createContentView(context, mContentViewCore);
         mContentViewCore.initialize(ViewAndroidDelegate.createBasicDelegate(view), view,
                 webContents, mWindow);
@@ -156,6 +162,11 @@
         };
     }
 
+    @CalledByNative
+    private ContentVideoViewEmbedder getContentVideoViewEmbedder() {
+        return new ActivityContentVideoViewEmbedder((Activity) getContext());
+    }
+
     /**
      * @return The {@link ViewGroup} currently shown by this Shell.
      */
diff --git a/chromecast/browser/android/cast_window_android.cc b/chromecast/browser/android/cast_window_android.cc
index f21a05f..015f30d 100644
--- a/chromecast/browser/android/cast_window_android.cc
+++ b/chromecast/browser/android/cast_window_android.cc
@@ -6,6 +6,7 @@
 
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "chromecast/base/version.h"
 #include "chromecast/browser/android/cast_window_manager.h"
 #include "chromecast/browser/cast_content_window.h"
 #include "content/public/browser/devtools_agent_host.h"
@@ -64,8 +65,9 @@
   window_java_.Reset(CreateCastWindowView(this));
 
   Java_CastWindowAndroid_initFromNativeWebContents(
-      env, window_java_.obj(), web_contents_->GetJavaWebContents().obj(),
-      web_contents_->GetRenderProcessHost()->GetID());
+      env, window_java_, web_contents_->GetJavaWebContents(),
+      web_contents_->GetRenderProcessHost()->GetID(),
+      base::android::ConvertUTF8ToJavaString(env, PRODUCT_VERSION));
 
   // Enabling hole-punching also requires runtime renderer preference
   content::RendererPreferences* prefs =
@@ -143,6 +145,12 @@
   contents->GetRenderViewHost()->GetWidget()->Focus();
 }
 
+base::android::ScopedJavaLocalRef<jobject>
+CastWindowAndroid::GetContentVideoViewEmbedder() {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  return Java_CastWindowAndroid_getContentVideoViewEmbedder(env, window_java_);
+}
+
 void CastWindowAndroid::RenderProcessGone(base::TerminationStatus status) {
   LOG(ERROR) << "Render process gone: status=" << status;
   Destroy();
diff --git a/chromecast/browser/android/cast_window_android.h b/chromecast/browser/android/cast_window_android.h
index 3cb45ef..5a01cca 100644
--- a/chromecast/browser/android/cast_window_android.h
+++ b/chromecast/browser/android/cast_window_android.h
@@ -69,6 +69,8 @@
                            int32_t line_no,
                            const base::string16& source_id) override;
   void ActivateContents(content::WebContents* contents) override;
+  base::android::ScopedJavaLocalRef<jobject>
+      GetContentVideoViewEmbedder() override;
 
   // content::WebContentsObserver implementation:
   void RenderProcessGone(base::TerminationStatus status) override;
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index f7a6eee..18aa346b 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-8843.0.0
\ No newline at end of file
+8845.0.0
\ No newline at end of file
diff --git a/components/arc/BUILD.gn b/components/arc/BUILD.gn
index a99b329..804fdd0 100644
--- a/components/arc/BUILD.gn
+++ b/components/arc/BUILD.gn
@@ -116,21 +116,6 @@
   ]
 }
 
-static_library("arc_bitmap") {
-  sources = [
-    "bitmap/bitmap_type_converters.cc",
-    "bitmap/bitmap_type_converters.h",
-  ]
-
-  deps = [
-    "//skia",
-  ]
-
-  public_deps = [
-    ":arc_bindings",
-  ]
-}
-
 mojom("arc_bindings") {
   sources = [
     "common/app.mojom",
diff --git a/components/arc/bitmap/OWNERS b/components/arc/bitmap/OWNERS
new file mode 100644
index 0000000..bb65116
--- /dev/null
+++ b/components/arc/bitmap/OWNERS
@@ -0,0 +1,2 @@
+per-file *_struct_traits*.*=set noparent
+per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/components/arc/bitmap/bitmap_struct_traits.cc b/components/arc/bitmap/bitmap_struct_traits.cc
new file mode 100644
index 0000000..51aa30f
--- /dev/null
+++ b/components/arc/bitmap/bitmap_struct_traits.cc
@@ -0,0 +1,36 @@
+// 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.
+
+#include "components/arc/bitmap/bitmap_struct_traits.h"
+
+namespace mojo {
+
+bool StructTraits<arc::mojom::ArcBitmapDataView, SkBitmap>::
+    Read(arc::mojom::ArcBitmapDataView data, SkBitmap* out) {
+  mojo::ArrayDataView<uint8_t> pixel_data;
+  data.GetPixelDataDataView(&pixel_data);
+
+  SkImageInfo info = SkImageInfo::Make(
+      data.width(), data.height(),
+      kRGBA_8888_SkColorType, kPremul_SkAlphaType);
+  if (info.getSafeSize(info.minRowBytes()) > pixel_data.size()) {
+    // Insufficient buffer size.
+    return false;
+  }
+
+  // Create the SkBitmap object which wraps the arc bitmap pixels. This
+  // doesn't copy and |data| and |bitmap| share the buffer.
+  SkBitmap bitmap;
+  if (!bitmap.installPixels(info,
+          const_cast<uint8_t*>(pixel_data.data()),
+          info.minRowBytes())) {
+    // Error in installing pixels.
+    return false;
+  }
+
+  // Copy the pixels with converting color type.
+  return bitmap.copyTo(out, kN32_SkColorType);
+}
+
+}  // namespace mojo
diff --git a/components/arc/bitmap/bitmap_struct_traits.h b/components/arc/bitmap/bitmap_struct_traits.h
new file mode 100644
index 0000000..e4e61e3
--- /dev/null
+++ b/components/arc/bitmap/bitmap_struct_traits.h
@@ -0,0 +1,30 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENT_ARC_BITMAP_BITMAP_STRUCT_TRAITS_H_
+#define COMPONENT_ARC_BITMAP_BITMAP_STRUCT_TRAITS_H_
+
+#include "components/arc/common/bitmap.mojom.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+namespace mojo {
+
+template <>
+struct StructTraits<arc::mojom::ArcBitmapDataView, SkBitmap> {
+  static const mojo::CArray<uint8_t> pixel_data(const SkBitmap& r) {
+    const SkImageInfo& info = r.info();
+    DCHECK_EQ(info.colorType(), kRGBA_8888_SkColorType);
+
+    return mojo::CArray<uint8_t>(
+        r.getSize(), r.getSize(), static_cast<uint8_t*>(r.getPixels()));
+  }
+  static uint32_t width(const SkBitmap& r) { return r.width(); }
+  static uint32_t height(const SkBitmap& r) { return r.height(); }
+
+  static bool Read(arc::mojom::ArcBitmapDataView data, SkBitmap* out);
+};
+
+}
+
+#endif  // COMPONENT_ARC_BITMAP_BITMAP_STRUCT_TRAITS_H_
diff --git a/components/arc/bitmap/bitmap_type_converters.cc b/components/arc/bitmap/bitmap_type_converters.cc
deleted file mode 100644
index ab9e58b..0000000
--- a/components/arc/bitmap/bitmap_type_converters.cc
+++ /dev/null
@@ -1,36 +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.
-
-#include "components/arc/bitmap/bitmap_type_converters.h"
-
-namespace mojo {
-
-SkBitmap TypeConverter<SkBitmap, arc::mojom::ArcBitmapPtr>::Convert(
-    const arc::mojom::ArcBitmapPtr& arcBitmap) {
-  if (arcBitmap.is_null())
-    return SkBitmap();
-
-  SkImageInfo info = SkImageInfo::Make(
-      arcBitmap->width, arcBitmap->height,
-      kRGBA_8888_SkColorType, kPremul_SkAlphaType);
-  if (info.getSafeSize(info.minRowBytes()) > arcBitmap->pixel_data.size())
-      return SkBitmap();
-
-  // Create the SkBitmap object which wraps the arc bitmap pixels.
-  SkBitmap bitmap;
-  if (!bitmap.installPixels(info,
-          const_cast<uint8_t*>(arcBitmap->pixel_data.storage().data()),
-          info.minRowBytes())) {
-    return SkBitmap();
-  }
-
-  // Copy the pixels with converting color type.
-  SkBitmap nativeColorBitmap;
-  if (!bitmap.copyTo(&nativeColorBitmap, kN32_SkColorType))
-    return SkBitmap();
-
-  return nativeColorBitmap;
-}
-
-}  // namespace mojo
diff --git a/components/arc/bitmap/bitmap_type_converters.h b/components/arc/bitmap/bitmap_type_converters.h
deleted file mode 100644
index 815b965..0000000
--- a/components/arc/bitmap/bitmap_type_converters.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_ARC_BITMAP_BITMAP_TYPE_CONVERTERS_H_
-#define COMPONENTS_ARC_BITMAP_BITMAP_TYPE_CONVERTERS_H_
-
-#include "components/arc/common/bitmap.mojom.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-
-namespace mojo {
-
-template <>
-struct TypeConverter<SkBitmap, arc::mojom::ArcBitmapPtr> {
-  static SkBitmap Convert(const arc::mojom::ArcBitmapPtr& bitmap);
-};
-
-}  // namespace mojo
-
-#endif  // COMPONENTS_ARC_BITMAP_BITMAP_TYPE_CONVERTERS_H_
diff --git a/components/arc/common/bitmap.typemap b/components/arc/common/bitmap.typemap
new file mode 100644
index 0000000..73529dc
--- /dev/null
+++ b/components/arc/common/bitmap.typemap
@@ -0,0 +1,13 @@
+mojom = "//components/arc/common/bitmap.mojom"
+public_headers = [ "//third_party/skia/include/core/SkBitmap.h" ]
+traits_headers = [ "//components/arc/bitmap/bitmap_struct_traits.h" ]
+sources = [
+  "//components/arc/bitmap/bitmap_struct_traits.cc",
+]
+deps = [
+  "//skia",
+]
+public_deps = [
+  "//skia",
+]
+type_mappings = [ "arc.mojom.ArcBitmap=SkBitmap" ]
diff --git a/components/arc/common/typemaps.gni b/components/arc/common/typemaps.gni
index edd6aee7..4359362f 100644
--- a/components/arc/common/typemaps.gni
+++ b/components/arc/common/typemaps.gni
@@ -4,5 +4,6 @@
 
 typemaps = [
   "//components/arc/common/app.typemap",
+  "//components/arc/common/bitmap.typemap",
   "//components/arc/common/bluetooth.typemap",
 ]
diff --git a/components/cronet/android/cronet_url_request_context_adapter.cc b/components/cronet/android/cronet_url_request_context_adapter.cc
index 7ced1be..ffe6089 100644
--- a/components/cronet/android/cronet_url_request_context_adapter.cc
+++ b/components/cronet/android/cronet_url_request_context_adapter.cc
@@ -775,7 +775,7 @@
   return network_thread_->task_runner();
 }
 
-void CronetURLRequestContextAdapter::StartNetLogToFile(
+bool CronetURLRequestContextAdapter::StartNetLogToFile(
     JNIEnv* env,
     const JavaParamRef<jobject>& jcaller,
     const JavaParamRef<jstring>& jfile_name,
@@ -783,14 +783,14 @@
   base::AutoLock lock(write_to_file_observer_lock_);
   // Do nothing if already logging to a file.
   if (write_to_file_observer_)
-    return;
+    return true;
   std::string file_name =
       base::android::ConvertJavaStringToUTF8(env, jfile_name);
   base::FilePath file_path(file_name);
   base::ScopedFILE file(base::OpenFile(file_path, "w"));
   if (!file) {
     LOG(ERROR) << "Failed to open NetLog file for writing.";
-    return;
+    return false;
   }
 
   write_to_file_observer_.reset(new net::WriteToFileNetLogObserver());
@@ -801,6 +801,8 @@
   write_to_file_observer_->StartObserving(
       g_net_log.Get().net_log(), std::move(file),
       /*constants=*/nullptr, /*url_request_context=*/nullptr);
+
+  return true;
 }
 
 void CronetURLRequestContextAdapter::StartNetLogToDisk(
diff --git a/components/cronet/android/cronet_url_request_context_adapter.h b/components/cronet/android/cronet_url_request_context_adapter.h
index 901f26c6..647cc06 100644
--- a/components/cronet/android/cronet_url_request_context_adapter.h
+++ b/components/cronet/android/cronet_url_request_context_adapter.h
@@ -79,8 +79,9 @@
 
   net::URLRequestContext* GetURLRequestContext();
 
-  // Starts NetLog logging to file. This can be called on any thread.
-  void StartNetLogToFile(JNIEnv* env,
+  // Starts NetLog logging to file. This can be called on any thread.  Returns
+  // false if it fails to open log file.
+  bool StartNetLogToFile(JNIEnv* env,
                          const base::android::JavaParamRef<jobject>& jcaller,
                          const base::android::JavaParamRef<jstring>& jfile_name,
                          jboolean jlog_all);
diff --git a/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequestContext.java b/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequestContext.java
index 2c2df1a7..f9656fa 100644
--- a/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequestContext.java
+++ b/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequestContext.java
@@ -260,7 +260,9 @@
     public void startNetLogToFile(String fileName, boolean logAll) {
         synchronized (mLock) {
             checkHaveAdapter();
-            nativeStartNetLogToFile(mUrlRequestContextAdapter, fileName, logAll);
+            if (!nativeStartNetLogToFile(mUrlRequestContextAdapter, fileName, logAll)) {
+                throw new RuntimeException("Unable to start NetLog");
+            }
             mIsLogging = true;
         }
     }
@@ -612,7 +614,7 @@
     private native void nativeDestroy(long nativePtr);
 
     @NativeClassQualifiedName("CronetURLRequestContextAdapter")
-    private native void nativeStartNetLogToFile(long nativePtr, String fileName, boolean logAll);
+    private native boolean nativeStartNetLogToFile(long nativePtr, String fileName, boolean logAll);
 
     @NativeClassQualifiedName("CronetURLRequestContextAdapter")
     private native void nativeStartNetLogToDisk(
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc
index 97898ae4..7eab12e0 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc
@@ -895,6 +895,10 @@
     CreateAndExecuteRequest(
         GURL("http://foo.com"), test_case.initial_response_headers,
         kErrorBody.c_str(), "HTTP/1.1 200 OK\r\n\r\n", kBody.c_str());
+
+    histogram_tester.ExpectUniqueSample(
+        "DataReductionProxy.ConfigService.HTTPRequests", 1, 1);
+
     // The first request caused the proxy to be marked as bad, so this second
     // request should not come through the proxy.
     CreateAndExecuteRequest(GURL("http://bar.com"), "HTTP/1.1 200 OK\r\n\r\n",
@@ -907,6 +911,11 @@
                                        kNextBody.size(), 1);
     ExpectOtherBypassedBytesHistogramsEmpty(histogram_tester,
                                             test_case.histogram_name);
+
+    // "DataReductionProxy.ConfigService.HTTPRequests" should not be recorded
+    // for bypassed requests.
+    histogram_tester.ExpectUniqueSample(
+        "DataReductionProxy.ConfigService.HTTPRequests", 1, 1);
   }
 }
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
index 69c9bd7..26bab64 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
@@ -114,7 +114,7 @@
                                         : AUTH_EXPIRED_SESSION_KEY_MISMATCH;
 
   UMA_HISTOGRAM_ENUMERATION(
-      "DataReductionProxy.ClientConfig.AuthExpiredSessionKey", state,
+      "DataReductionProxy.ConfigService.AuthExpiredSessionKey", state,
       AUTH_EXPIRED_SESSION_KEY_BOUNDARY);
 }
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc
index cd8633d3..76b998a 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc
@@ -448,10 +448,12 @@
   Init(true);
   AddMockSuccess();
   SetDataReductionProxyEnabled(true, true);
+  EXPECT_FALSE(configurator()->GetProxyConfig().is_valid());
   EXPECT_EQ(std::vector<net::ProxyServer>(), GetConfiguredProxiesForHttp());
   config_client()->RetrieveConfig();
   RunUntilIdle();
   VerifyRemoteSuccess(true);
+  EXPECT_TRUE(configurator()->GetProxyConfig().is_valid());
 #if defined(OS_ANDROID)
   EXPECT_FALSE(config_client()->foreground_fetch_pending());
 #endif
@@ -672,12 +674,14 @@
   AddMockPreviousSuccess();
 
   SetDataReductionProxyEnabled(true, true);
+  EXPECT_FALSE(configurator()->GetProxyConfig().is_valid());
   histogram_tester.ExpectTotalCount(
       "DataReductionProxy.ConfigService.AuthExpired", 0);
   config_client()->RetrieveConfig();
   RunUntilIdle();
   // First remote config should be fetched.
   VerifyRemoteSuccessWithOldConfig();
+  EXPECT_TRUE(configurator()->GetProxyConfig().is_valid());
   EXPECT_EQ(kOldSuccessSessionKey, request_options()->GetSecureSession());
   EXPECT_EQ(0, config_client()->GetBackoffErrorCount());
   histogram_tester.ExpectUniqueSample(
@@ -698,6 +702,8 @@
       request_headers, parsed.get(), origin.host_port_pair(),
       load_timing_info));
   EXPECT_EQ(1, config_client()->GetBackoffErrorCount());
+  EXPECT_FALSE(configurator()->GetProxyConfig().is_valid());
+
   // Persisted config on pref should be cleared.
   EXPECT_TRUE(persisted_config().empty());
   histogram_tester.ExpectBucketCount(
@@ -736,7 +742,7 @@
   VerifyRemoteSuccessWithOldConfig();
 
   histogram_tester.ExpectUniqueSample(
-      "DataReductionProxy.ClientConfig.AuthExpiredSessionKey",
+      "DataReductionProxy.ConfigService.AuthExpiredSessionKey",
       1 /* AUTH_EXPIRED_SESSION_KEY_MATCH */, 2);
 }
 
@@ -793,7 +799,7 @@
   EXPECT_EQ(kOldSuccessSessionKey, request_options()->GetSecureSession());
 
   histogram_tester.ExpectUniqueSample(
-      "DataReductionProxy.ClientConfig.AuthExpiredSessionKey",
+      "DataReductionProxy.ConfigService.AuthExpiredSessionKey",
       0 /* AUTH_EXPIRED_SESSION_KEY_MISMATCH */, 1);
 }
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc
index bfa1f06..ed2397f 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc
@@ -180,8 +180,14 @@
       &data_reduction_proxy_info);
   if (data_saver_proxy_used)
     result->OverrideProxyList(data_reduction_proxy_info.proxy_list());
+
+  // The |data_reduction_proxy_config| must be valid otherwise the proxy
+  // cannot be used.
+  DCHECK(data_reduction_proxy_config.is_valid() || !data_saver_proxy_used);
+
   if (config->enabled_by_user_and_reachable() && url.SchemeIsHTTPOrHTTPS() &&
-      !url.SchemeIsCryptographic() && !net::IsLocalhost(url.host())) {
+      !url.SchemeIsCryptographic() && !net::IsLocalhost(url.host()) &&
+      (!data_reduction_proxy_config.is_valid() || data_saver_proxy_used)) {
     UMA_HISTOGRAM_BOOLEAN("DataReductionProxy.ConfigService.HTTPRequests",
                           data_saver_proxy_used);
   }
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc
index fd0e764..6d99189 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc
@@ -726,6 +726,7 @@
           "http=" + data_reduction_proxy + ",direct://;");
       data_reduction_proxy_config.set_id(1);
     }
+    EXPECT_NE(test.use_direct_proxy, data_reduction_proxy_config.is_valid());
     config()->SetStateForTest(test.enabled_by_user /* enabled */,
                               false /* at_startup */);
 
@@ -752,6 +753,7 @@
 }
 
 TEST_F(DataReductionProxyDelegateTest, OnCompletedSizeFor200) {
+  base::HistogramTester histogram_tester;
   int64_t baseline_received_bytes = total_received_bytes();
   int64_t baseline_original_received_bytes = total_original_received_bytes();
 
@@ -778,6 +780,9 @@
   EXPECT_EQ(static_cast<int64_t>(raw_headers.size() +
                                  10000 /* original_response_body */),
             total_original_received_bytes() - baseline_original_received_bytes);
+
+  histogram_tester.ExpectUniqueSample(
+      "DataReductionProxy.ConfigService.HTTPRequests", 1, 1);
 }
 
 TEST_F(DataReductionProxyDelegateTest, OnCompletedSizeFor304) {
@@ -912,6 +917,7 @@
   };
 
   for (const auto& test : test_cases) {
+    base::HistogramTester histogram_tester;
     int64_t baseline_received_bytes = total_received_bytes();
     int64_t baseline_original_received_bytes = total_original_received_bytes();
 
@@ -944,6 +950,8 @@
     EXPECT_EQ(expected_original_size, total_original_received_bytes() -
                                           baseline_original_received_bytes)
         << (&test - test_cases);
+    histogram_tester.ExpectUniqueSample(
+        "DataReductionProxy.ConfigService.HTTPRequests", 1, 1);
   }
 }
 
diff --git a/components/domain_reliability/quic_error_mapping.cc b/components/domain_reliability/quic_error_mapping.cc
index 853f49f..3b247e8 100644
--- a/components/domain_reliability/quic_error_mapping.cc
+++ b/components/domain_reliability/quic_error_mapping.cc
@@ -242,6 +242,10 @@
   // has too many gaps.
   { net::QUIC_TOO_MANY_FRAME_GAPS,
     "quic.too_many_frame_gaps" },
+  // Sequencer buffer get into weird state where continuing read/write
+  // will lead to crash.
+  { net::QUIC_STREAM_SEQUENCER_INVALID_STATE,
+    "quic.stream_sequencer_invalid_state" },
 
   // No error. Used as bound while iterating.
   { net::QUIC_LAST_ERROR, "quic.last_error"}
diff --git a/components/drive/drive.proto b/components/drive/drive.proto
index 7a99598c..54e29640 100644
--- a/components/drive/drive.proto
+++ b/components/drive/drive.proto
@@ -109,6 +109,9 @@
   // server. Deleted entries won't be stored in ResourceMetadata.
   optional bool deleted = 11;
 
+  // True if the entry is labeled "starred".
+  optional bool starred = 20;
+
   // True if the entry is labeled with "shared-with-me", i.e., owned by someone
   // else initially and later shared to the current user.
   optional bool shared_with_me = 14;
@@ -149,6 +152,10 @@
   // drive_resource_metadata_storage.h defines the current version.
   optional int32 version = 1;
   optional int64 largest_changestamp = 2;
+
+  // True if resources already have been updated after 'starred' property added.
+  // Otherwise, we have to load them from server.
+  optional bool starred_property_initialized = 3;
 }
 
 // Message to store information of an existing cache file.
diff --git a/components/drive/resource_entry_conversion.cc b/components/drive/resource_entry_conversion.cc
index 608a2fe..52eda29b 100644
--- a/components/drive/resource_entry_conversion.cc
+++ b/components/drive/resource_entry_conversion.cc
@@ -65,6 +65,7 @@
     parent_resource_id = input.parents()[0].file_id();
 
   converted.set_deleted(input.labels().is_trashed());
+  converted.set_starred(input.labels().is_starred());
   converted.set_shared_with_me(!input.shared_with_me_date().is_null());
   converted.set_shared(input.shared());
 
diff --git a/components/drive/resource_entry_conversion_unittest.cc b/components/drive/resource_entry_conversion_unittest.cc
index 5891d91671..e4d159f 100644
--- a/components/drive/resource_entry_conversion_unittest.cc
+++ b/components/drive/resource_entry_conversion_unittest.cc
@@ -56,6 +56,7 @@
   EXPECT_EQ("", parent_resource_id);
 
   EXPECT_FALSE(entry.deleted());
+  EXPECT_FALSE(entry.starred());
   EXPECT_FALSE(entry.shared_with_me());
   EXPECT_FALSE(entry.shared());
 
@@ -105,6 +106,7 @@
   EXPECT_EQ("", parent_resource_id);
 
   EXPECT_FALSE(entry.deleted());
+  EXPECT_FALSE(entry.starred());
   EXPECT_FALSE(entry.shared_with_me());
   EXPECT_FALSE(entry.shared());
 
@@ -155,6 +157,7 @@
   EXPECT_EQ(parent.file_id(), parent_resource_id);
 
   EXPECT_FALSE(entry.deleted());
+  EXPECT_FALSE(entry.starred());
   EXPECT_FALSE(entry.shared_with_me());
   EXPECT_FALSE(entry.shared());
 
@@ -193,6 +196,7 @@
   EXPECT_EQ("", parent_resource_id);
 
   EXPECT_TRUE(entry.deleted());  // The document was deleted.
+  EXPECT_FALSE(entry.starred());
   EXPECT_FALSE(entry.shared_with_me());
   EXPECT_FALSE(entry.shared());
 
@@ -293,6 +297,18 @@
 }
 
 TEST(ResourceEntryConversionTest,
+     ConvertFileResourceToResourceEntry_StarredEntry) {
+  google_apis::FileResource file_resource;
+  file_resource.mutable_labels()->set_starred(true);
+
+  ResourceEntry entry;
+  std::string parent_resource_id;
+  EXPECT_TRUE(ConvertFileResourceToResourceEntry(
+      file_resource, &entry, &parent_resource_id));
+  EXPECT_TRUE(entry.starred());
+}
+
+TEST(ResourceEntryConversionTest,
      ConvertFileResourceToResourceEntry_SharedWithMeEntry) {
   google_apis::FileResource file_resource;
   file_resource.set_shared(true);
diff --git a/components/drive/resource_metadata_storage.cc b/components/drive/resource_metadata_storage.cc
index 8a0eb35b..4974809 100644
--- a/components/drive/resource_metadata_storage.cc
+++ b/components/drive/resource_metadata_storage.cc
@@ -630,6 +630,24 @@
     }
   }
 
+  // Update local resouces if 'starred' property has not been initialized.
+  if (resource_map_) {
+    ResourceMetadataHeader header;
+    if (GetHeader(&header) != FILE_ERROR_OK)
+      return false;
+
+    if (!header.starred_property_initialized()) {
+      // largest changestamp == 0 means data in DB is obsolete.
+      // So data for all entries will be reloaded.
+      header.set_largest_changestamp(0);
+      header.set_starred_property_initialized(true);
+      FileError error = PutHeader(header);
+
+      if (error != FILE_ERROR_OK)
+        return false;
+    }
+  }
+
   UMA_HISTOGRAM_ENUMERATION("Drive.MetadataDBInitResult",
                             init_result,
                             DB_INIT_MAX_VALUE);
diff --git a/components/drive/resource_metadata_storage_unittest.cc b/components/drive/resource_metadata_storage_unittest.cc
index 5f4a0fa0..e4d15ace 100644
--- a/components/drive/resource_metadata_storage_unittest.cc
+++ b/components/drive/resource_metadata_storage_unittest.cc
@@ -43,6 +43,21 @@
     EXPECT_EQ(FILE_ERROR_OK, storage_->PutHeader(header));
   }
 
+  // Overwrites |storage_|'s starred_property_initialized.
+  void SetStarredPropertyInitialized(bool value) {
+    ResourceMetadataHeader header;
+    ASSERT_EQ(FILE_ERROR_OK, storage_->GetHeader(&header));
+    header.set_starred_property_initialized(value);
+    EXPECT_EQ(FILE_ERROR_OK, storage_->PutHeader(header));
+  }
+
+  // Returns |storage_|'s starred_property_initialized.
+  bool GetStarredPropertyInitialized() {
+    ResourceMetadataHeader header;
+    EXPECT_EQ(FILE_ERROR_OK, storage_->GetHeader(&header));
+    return header.starred_property_initialized();
+  }
+
   bool CheckValidity() {
     return storage_->CheckValidity();
   }
@@ -634,5 +649,28 @@
   EXPECT_TRUE(CheckValidity());
 }
 
+TEST_F(ResourceMetadataStorageTest, ChangeStarredPropertyInitialized) {
+  // Suppose 'Starred' property has not loaded.
+  bool starred_property_initialized = false;
+  SetStarredPropertyInitialized(starred_property_initialized);
+
+  const int64_t kLargestChangestamp = 1234567890;
+  EXPECT_EQ(FILE_ERROR_OK,
+            storage_->SetLargestChangestamp(kLargestChangestamp));
+
+  // Close DB and reopen.
+  storage_.reset(new ResourceMetadataStorage(
+      temp_dir_.GetPath(), base::ThreadTaskRunnerHandle::Get().get()));
+  ASSERT_TRUE(storage_->Initialize());
+
+  starred_property_initialized = GetStarredPropertyInitialized();
+  EXPECT_TRUE(starred_property_initialized);
+
+  int64_t largest_changestamp = 0;
+  EXPECT_EQ(FILE_ERROR_OK,
+            storage_->GetLargestChangestamp(&largest_changestamp));
+  EXPECT_EQ(0, largest_changestamp);
+}
+
 }  // namespace internal
 }  // namespace drive
diff --git a/components/drive/service/drive_api_service.cc b/components/drive/service/drive_api_service.cc
index e11962c..59558fc 100644
--- a/components/drive/service/drive_api_service.cc
+++ b/components/drive/service/drive_api_service.cc
@@ -100,7 +100,8 @@
     "kind,quotaBytesTotal,quotaBytesUsedAggregate,largestChangeId,rootFolderId";
 const char kFileResourceFields[] =
     "kind,id,title,createdDate,sharedWithMeDate,mimeType,"
-    "md5Checksum,fileSize,labels/trashed,imageMediaMetadata/width,"
+    "md5Checksum,fileSize,labels/trashed,labels/starred,"
+    "imageMediaMetadata/width,"
     "imageMediaMetadata/height,imageMediaMetadata/rotation,etag,"
     "parents(id,parentLink),alternateLink,"
     "modifiedDate,lastViewedByMeDate,shared";
@@ -110,13 +111,15 @@
     "kind,id,shareLink";
 const char kFileListFields[] =
     "kind,items(kind,id,title,createdDate,sharedWithMeDate,"
-    "mimeType,md5Checksum,fileSize,labels/trashed,imageMediaMetadata/width,"
+    "mimeType,md5Checksum,fileSize,labels/trashed,labels/starred,"
+    "imageMediaMetadata/width,"
     "imageMediaMetadata/height,imageMediaMetadata/rotation,etag,"
     "parents(id,parentLink),alternateLink,"
     "modifiedDate,lastViewedByMeDate,shared),nextLink";
 const char kChangeListFields[] =
     "kind,items(file(kind,id,title,createdDate,sharedWithMeDate,"
-    "mimeType,md5Checksum,fileSize,labels/trashed,imageMediaMetadata/width,"
+    "mimeType,md5Checksum,fileSize,labels/trashed,labels/starred,"
+    "imageMediaMetadata/width,"
     "imageMediaMetadata/height,imageMediaMetadata/rotation,etag,"
     "parents(id,parentLink),alternateLink,modifiedDate,"
     "lastViewedByMeDate,shared),deleted,id,fileId,modificationDate),nextLink,"
diff --git a/components/error_page/OWNERS b/components/error_page/OWNERS
index 44a878b..2b70a4c 100644
--- a/components/error_page/OWNERS
+++ b/components/error_page/OWNERS
@@ -1,2 +1,6 @@
 mmenke@chromium.org
 juliatuttle@chromium.org
+
+# If changing network error strings, please visit go/chrome-neterror-strings
+# (Google internal) or contact edwardjung@chromium.org and rachelis@chromium.org
+per-file error_page_strings.grdp=edwardjung@chromium.org
\ No newline at end of file
diff --git a/components/error_page/common/OWNERS b/components/error_page/common/OWNERS
new file mode 100644
index 0000000..ec20b61
--- /dev/null
+++ b/components/error_page/common/OWNERS
@@ -0,0 +1 @@
+per-file localized_error.cc=edwardjung@chromium.org
\ No newline at end of file
diff --git a/components/exo/BUILD.gn b/components/exo/BUILD.gn
index e43eab93..779e42a4 100644
--- a/components/exo/BUILD.gn
+++ b/components/exo/BUILD.gn
@@ -77,6 +77,7 @@
 
   deps = [
     ":exo",
+    "//ash:ash_with_aura_test_support",
     "//ash:test_support_without_content",
     "//base",
     "//gpu",
@@ -141,6 +142,7 @@
 
   deps = [
     ":unit_tests",
+    "//ash:ash_with_aura_test_support",
     "//ash:test_support_without_content",
     "//base",
     "//base/test:test_support",
diff --git a/components/exo/wayland/server.cc b/components/exo/wayland/server.cc
index de1df93..53b20f9 100644
--- a/components/exo/wayland/server.cc
+++ b/components/exo/wayland/server.cc
@@ -536,9 +536,9 @@
   }
 
   std::vector<gfx::NativePixmapPlane> planes;
-  planes.emplace_back(stride0, offset0, 0);
-  planes.emplace_back(stride1, offset1, 0);
-  planes.emplace_back(stride2, offset2, 0);
+  planes.emplace_back(stride0, offset0, 0, 0);
+  planes.emplace_back(stride1, offset1, 0, 0);
+  planes.emplace_back(stride2, offset2, 0, 0);
   std::vector<base::ScopedFD> fds;
 
   size_t num_planes =
@@ -694,7 +694,7 @@
       return;
     }
     LinuxBufferParams::Plane& plane = plane_it->second;
-    planes.emplace_back(plane.stride, plane.offset, 0);
+    planes.emplace_back(plane.stride, plane.offset, 0, 0);
     if (plane.fd.is_valid())
       fds.push_back(std::move(plane.fd));
   }
diff --git a/components/gcm_driver/gcm_stats_recorder_impl.cc b/components/gcm_driver/gcm_stats_recorder_impl.cc
index d632bd3..719f25383 100644
--- a/components/gcm_driver/gcm_stats_recorder_impl.cc
+++ b/components/gcm_driver/gcm_stats_recorder_impl.cc
@@ -400,6 +400,8 @@
     int message_byte_size,
     bool to_registered_app,
     ReceivedMessageType message_type) {
+  UMA_HISTOGRAM_BOOLEAN("GCM.DataMessageReceivedHasRegisteredApp",
+                        to_registered_app);
   if (to_registered_app)
     UMA_HISTOGRAM_COUNTS("GCM.DataMessageReceived", 1);
 
diff --git a/components/history/core/browser/download_database.cc b/components/history/core/browser/download_database.cc
index e226af38..5994bf5e 100644
--- a/components/history/core/browser/download_database.cc
+++ b/components/history/core/browser/download_database.cc
@@ -29,7 +29,7 @@
 
 namespace {
 
-// Reason for dropping a particular record.
+// Reason for dropping a particular record. Used for UMA.
 enum DroppedReason {
   DROPPED_REASON_BAD_STATE = 0,
   DROPPED_REASON_BAD_DANGER_TYPE = 1,
@@ -624,7 +624,6 @@
     count_urls.BindInt(0, info.id);
     if (count_urls.Step()) {
       bool corrupt_urls = count_urls.ColumnInt(0) > 0;
-      UMA_HISTOGRAM_BOOLEAN("Download.DatabaseCorruptUrls", corrupt_urls);
       if (corrupt_urls) {
         // There should not be any URLs in downloads_url_chains for this
         // info.id.  If there are, we don't want them to interfere with
diff --git a/components/history/core/browser/history_backend.cc b/components/history/core/browser/history_backend.cc
index 9b17ed6..166921d3 100644
--- a/components/history/core/browser/history_backend.cc
+++ b/components/history/core/browser/history_backend.cc
@@ -1221,10 +1221,6 @@
                         (1000 * micros) / num_downloads_deleted);
   }
   DCHECK_GE(ids.size(), num_downloads_deleted);
-  if (ids.size() < num_downloads_deleted)
-    return;
-  UMA_HISTOGRAM_COUNTS("Download.DatabaseRemoveDownloadsCountNotRemoved",
-                       ids.size() - num_downloads_deleted);
 }
 
 void HistoryBackend::QueryHistory(const base::string16& text_query,
diff --git a/components/history_strings.grdp b/components/history_strings.grdp
index f73f49e7..9dca8554 100644
--- a/components/history_strings.grdp
+++ b/components/history_strings.grdp
@@ -50,13 +50,13 @@
     Blocked
   </message>
   <message name="IDS_HISTORY_FOUND_SEARCH_RESULTS" desc="Message shown when zero or multiple search results are found.">
-    Found <ph name="NUMBER_OF_RESULTS">$1</ph> <ph name="SEARCH_RESULTS"><ex>search results</ex>$2</ph> for '<ph name="SEARCH_STRING">$3</ph>'.
+    Found <ph name="NUMBER_OF_RESULTS">$1</ph> <ph name="SEARCH_RESULTS"><ex>search results</ex>$2</ph> for '<ph name="SEARCH_STRING">$3</ph>'
   </message>
   <message name="IDS_HISTORY_HAS_SYNCED_RESULTS" desc="The notification at the top of the history page indicating that it is showing visits synced from other devices.">
     Showing history from your signed-in devices. <ph name="BEGIN_LINK">&lt;a href="https://support.google.com/chrome/?p=sync_history&amp;hl=[GRITLANGCODE]"&gt;</ph>Learn more<ph name="END_LINK">&lt;/a&gt;<ex>&lt;/a&gt;</ex></ph>.
   </message>
   <message name="IDS_HISTORY_OTHER_FORMS_OF_HISTORY" desc="The notification at the top of the history page indicating that deleting Chrome browsing history will not delete other forms of history stored at Google My Activity.">
-    Your Google Account may have other forms of browsing history at <ph name="BEGIN_LINK">&lt;a target="_blank" href="$1"&gt;</ph>history.google.com<ph name="END_LINK">&lt;/a&gt;</ph>.
+    Your Google Account may have other forms of browsing history at <ph name="BEGIN_LINK">&lt;a target="_blank" href="$1"&gt;</ph>history.google.com<ph name="END_LINK">&lt;/a&gt;</ph>
   </message>
   <message name="IDS_HISTORY_INTERVAL" desc="A history interval shown in the title. The dates are already localized strings.">
     <ph name="START_DATE">$1<ex>Wednesday, Aug. 1, 2012</ex></ph> to <ph name="END_DATE">$2<ex>Thursday, Aug. 30, 2012</ex></ph>
@@ -74,10 +74,10 @@
     Newest
   </message>
   <message name="IDS_HISTORY_NO_RESULTS" desc="Text shown when no history entries are found.">
-    No history entries found.
+    No history entries found
   </message>
   <message name="IDS_HISTORY_NO_SEARCH_RESULTS" desc="Text shown when no history search results have been found">
-    No search results found.
+    No search results found
   </message>
   <message name="IDS_HISTORY_NO_SYNCED_RESULTS" desc="The notification at the top of the history page indicating that it does not include visits from other devices.">
     Showing history from this device. <ph name="BEGIN_LINK">&lt;a href="https://support.google.com/chrome/?p=sync_history&amp;hl=[GRITLANGCODE]"&gt;</ph>Learn more<ph name="END_LINK">&lt;/a&gt;<ex>&lt;/a&gt;</ex></ph>.
diff --git a/components/infobars/core/infobar_delegate.h b/components/infobars/core/infobar_delegate.h
index 9c49b2f..0e956f84 100644
--- a/components/infobars/core/infobar_delegate.h
+++ b/components/infobars/core/infobar_delegate.h
@@ -137,6 +137,7 @@
     INSTANT_APPS_INFOBAR_DELEGATE_ANDROID = 67,
     DATA_REDUCTION_PROXY_PREVIEW_INFOBAR_DELEGATE = 68,
     SCREEN_CAPTURE_INFOBAR_DELEGATE_ANDROID = 69,
+    GROUPED_PERMISSION_INFOBAR_DELEGATE_ANDROID = 70,
   };
 
   // Describes navigation events, used to decide whether infobars should be
diff --git a/components/neterror/OWNERS b/components/neterror/OWNERS
index fd1666b4..9f303e4e 100644
--- a/components/neterror/OWNERS
+++ b/components/neterror/OWNERS
@@ -1,3 +1,4 @@
 jar@chromium.org
 mmenke@chromium.org
 juliatuttle@chromium.org
+edwardjung@chromium.org
\ No newline at end of file
diff --git a/components/network_time/network_time_tracker.cc b/components/network_time/network_time_tracker.cc
index e299fb2..71223e0e7 100644
--- a/components/network_time/network_time_tracker.cc
+++ b/components/network_time/network_time_tracker.cc
@@ -8,7 +8,6 @@
 #include <string>
 #include <utility>
 
-#include "base/feature_list.h"
 #include "base/i18n/time_formatting.h"
 #include "base/json/json_reader.h"
 #include "base/logging.h"
@@ -34,6 +33,9 @@
 
 namespace network_time {
 
+const base::Feature kNetworkTimeServiceQuerying{
+    "NetworkTimeServiceQuerying", base::FEATURE_DISABLED_BY_DEFAULT};
+
 namespace {
 
 // Time updates happen in two ways. First, other components may call
@@ -94,10 +96,6 @@
 
 const char kTimeServiceURL[] = "http://clients2.google.com/time/1/current";
 
-// Variations Service feature that enables network time service querying.
-const base::Feature kNetworkTimeServiceQuerying{
-    "NetworkTimeServiceQuerying", base::FEATURE_DISABLED_BY_DEFAULT};
-
 const char kVariationsServiceCheckTimeIntervalSeconds[] =
     "CheckTimeIntervalSeconds";
 const char kVariationsServiceRandomQueryProbability[] =
diff --git a/components/network_time/network_time_tracker.h b/components/network_time/network_time_tracker.h
index 7faf1fd..ae1f268 100644
--- a/components/network_time/network_time_tracker.h
+++ b/components/network_time/network_time_tracker.h
@@ -8,6 +8,7 @@
 #include <stdint.h>
 #include <memory>
 
+#include "base/feature_list.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -44,6 +45,9 @@
 const int64_t kTicksResolutionMs = 1;  // Assume 1ms for non-windows platforms.
 #endif
 
+// Variations Service feature that enables network time service querying.
+extern const base::Feature kNetworkTimeServiceQuerying;
+
 // A class that receives network time updates and can provide the network time
 // for a corresponding local time. This class is not thread safe.
 class NetworkTimeTracker : public net::URLFetcherDelegate {
diff --git a/components/ntp_snippets/BUILD.gn b/components/ntp_snippets/BUILD.gn
index d8ffb41..bdb92ed0 100644
--- a/components/ntp_snippets/BUILD.gn
+++ b/components/ntp_snippets/BUILD.gn
@@ -33,19 +33,8 @@
     "content_suggestions_service.h",
     "features.cc",
     "features.h",
-    "ntp_snippet.cc",
-    "ntp_snippet.h",
     "ntp_snippets_constants.cc",
     "ntp_snippets_constants.h",
-    "ntp_snippets_database.cc",
-    "ntp_snippets_database.h",
-    "ntp_snippets_fetcher.cc",
-    "ntp_snippets_fetcher.h",
-    "ntp_snippets_scheduler.h",
-    "ntp_snippets_service.cc",
-    "ntp_snippets_service.h",
-    "ntp_snippets_status_service.cc",
-    "ntp_snippets_status_service.h",
     "offline_pages/offline_page_proxy.cc",
     "offline_pages/offline_page_proxy.h",
     "offline_pages/offline_page_suggestions_provider.cc",
@@ -56,8 +45,19 @@
     "pref_names.h",
     "pref_util.cc",
     "pref_util.h",
-    "request_throttler.cc",
-    "request_throttler.h",
+    "remote/ntp_snippet.cc",
+    "remote/ntp_snippet.h",
+    "remote/ntp_snippets_database.cc",
+    "remote/ntp_snippets_database.h",
+    "remote/ntp_snippets_fetcher.cc",
+    "remote/ntp_snippets_fetcher.h",
+    "remote/ntp_snippets_scheduler.h",
+    "remote/ntp_snippets_service.cc",
+    "remote/ntp_snippets_service.h",
+    "remote/ntp_snippets_status_service.cc",
+    "remote/ntp_snippets_status_service.h",
+    "remote/request_throttler.cc",
+    "remote/request_throttler.h",
     "sessions/foreign_sessions_suggestions_provider.cc",
     "sessions/foreign_sessions_suggestions_provider.h",
     "sessions/tab_delegate_sync_adapter.cc",
@@ -88,7 +88,7 @@
     "//components/history/core/browser",
     "//components/image_fetcher",
     "//components/metrics",
-    "//components/ntp_snippets/proto",
+    "//components/ntp_snippets/remote/proto",
     "//components/offline_pages",
     "//components/sessions",
     "//components/strings",
@@ -118,16 +118,16 @@
     "content_suggestions_service_unittest.cc",
     "mock_content_suggestions_provider_observer.cc",
     "mock_content_suggestions_provider_observer.h",
-    "ntp_snippet_unittest.cc",
-    "ntp_snippets_database_unittest.cc",
-    "ntp_snippets_fetcher_unittest.cc",
-    "ntp_snippets_service_unittest.cc",
-    "ntp_snippets_status_service_unittest.cc",
-    "ntp_snippets_test_utils.cc",
-    "ntp_snippets_test_utils.h",
     "offline_pages/offline_page_suggestions_provider_unittest.cc",
     "physical_web_pages/physical_web_page_suggestions_provider_unittest.cc",
-    "request_throttler_unittest.cc",
+    "remote/ntp_snippet_unittest.cc",
+    "remote/ntp_snippets_database_unittest.cc",
+    "remote/ntp_snippets_fetcher_unittest.cc",
+    "remote/ntp_snippets_service_unittest.cc",
+    "remote/ntp_snippets_status_service_unittest.cc",
+    "remote/ntp_snippets_test_utils.cc",
+    "remote/ntp_snippets_test_utils.h",
+    "remote/request_throttler_unittest.cc",
     "sessions/foreign_sessions_suggestions_provider_unittest.cc",
   ]
 
diff --git a/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc b/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc
index 27db5336..ca953b5 100644
--- a/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc
+++ b/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc
@@ -154,14 +154,14 @@
 }
 
 void BookmarkSuggestionsProvider::DismissSuggestion(
-    const std::string& suggestion_id) {
+    const ContentSuggestion::ID& suggestion_id) {
   DCHECK(bookmark_model_->loaded());
-  GURL url(GetWithinCategoryIDFromUniqueID(suggestion_id));
+  GURL url(suggestion_id.id_within_category());
   MarkBookmarksDismissed(bookmark_model_, url);
 }
 
 void BookmarkSuggestionsProvider::FetchSuggestionImage(
-    const std::string& suggestion_id,
+    const ContentSuggestion::ID& suggestion_id,
     const ImageFetchedCallback& callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(callback, gfx::Image()));
@@ -260,9 +260,8 @@
 
 ContentSuggestion BookmarkSuggestionsProvider::ConvertBookmark(
     const BookmarkNode* bookmark) {
-  ContentSuggestion suggestion(
-      MakeUniqueID(provided_category_, bookmark->url().spec()),
-      bookmark->url());
+  ContentSuggestion suggestion(provided_category_, bookmark->url().spec(),
+                               bookmark->url());
 
   suggestion.set_title(bookmark->GetTitle());
   suggestion.set_snippet_text(base::string16());
diff --git a/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h b/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h
index 79b8718..68ede9d 100644
--- a/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h
+++ b/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h
@@ -39,8 +39,8 @@
   // ContentSuggestionsProvider implementation.
   CategoryStatus GetCategoryStatus(Category category) override;
   CategoryInfo GetCategoryInfo(Category category) override;
-  void DismissSuggestion(const std::string& suggestion_id) override;
-  void FetchSuggestionImage(const std::string& suggestion_id,
+  void DismissSuggestion(const ContentSuggestion::ID& suggestion_id) override;
+  void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
                             const ImageFetchedCallback& callback) override;
   void ClearHistory(
       base::Time begin,
diff --git a/components/ntp_snippets/category_factory.cc b/components/ntp_snippets/category_factory.cc
index 9962f077..4da984e 100644
--- a/components/ntp_snippets/category_factory.cc
+++ b/components/ntp_snippets/category_factory.cc
@@ -12,13 +12,6 @@
 
 namespace ntp_snippets {
 
-namespace {
-
-const char kCombinedIDFormat[] = "%d|%s";
-const char kSeparator = '|';
-
-}  // namespace
-
 CategoryFactory::CategoryFactory() {
   // Add all local categories in a fixed order.
   AddKnownCategory(KnownCategories::DOWNLOADS);
@@ -66,32 +59,6 @@
                                      ordered_categories_.end(), right);
 }
 
-std::string CategoryFactory::MakeUniqueID(
-    Category category,
-    const std::string& within_category_id) const {
-  return base::StringPrintf(kCombinedIDFormat, category.id(),
-                            within_category_id.c_str());
-}
-
-Category CategoryFactory::GetCategoryFromUniqueID(
-    const std::string& unique_id) {
-  size_t colon_index = unique_id.find(kSeparator);
-  DCHECK_NE(std::string::npos, colon_index) << "Not a valid unique_id: "
-                                            << unique_id;
-  int category = -1;
-  bool ret = base::StringToInt(unique_id.substr(0, colon_index), &category);
-  DCHECK(ret) << "Non-numeric category part in unique_id: " << unique_id;
-  return FromIDValue(category);
-}
-
-std::string CategoryFactory::GetWithinCategoryIDFromUniqueID(
-    const std::string& unique_id) const {
-  size_t colon_index = unique_id.find(kSeparator);
-  DCHECK_NE(std::string::npos, colon_index) << "Not a valid unique_id: "
-                                            << unique_id;
-  return unique_id.substr(colon_index + 1);
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // Private methods
 
diff --git a/components/ntp_snippets/category_factory.h b/components/ntp_snippets/category_factory.h
index db134d2..c3941ea 100644
--- a/components/ntp_snippets/category_factory.h
+++ b/components/ntp_snippets/category_factory.h
@@ -44,23 +44,6 @@
   // |FromRemoteCategory|.
   bool CompareCategories(const Category& left, const Category& right) const;
 
-  // TODO(treib): Remove the following 3 functions from here once we move to a
-  // more structured identification than the unique_id string and thus once we
-  // eliminate these functions. See crbug.com/649048.
-
-  // Creates a unique ID. The given |within_category_id| must be unique among
-  // all suggestion IDs from this provider for the given |category|. This method
-  // combines it with the |category| to form an ID that is unique
-  // application-wide, because this provider is the only one that provides
-  // suggestions for that category.
-  std::string MakeUniqueID(Category category,
-                           const std::string& within_category_id) const;
-
-  // Reverse functions for MakeUniqueID()
-  Category GetCategoryFromUniqueID(const std::string& unique_id);
-  std::string GetWithinCategoryIDFromUniqueID(
-      const std::string& unique_id) const;
-
  private:
   bool CategoryExists(int id);
   void AddKnownCategory(KnownCategories known_category);
diff --git a/components/ntp_snippets/content_suggestion.cc b/components/ntp_snippets/content_suggestion.cc
index 0617f6e..44524cb 100644
--- a/components/ntp_snippets/content_suggestion.cc
+++ b/components/ntp_snippets/content_suggestion.cc
@@ -6,13 +6,32 @@
 
 namespace ntp_snippets {
 
-ContentSuggestion::ContentSuggestion(const std::string& id, const GURL& url)
+bool ContentSuggestion::ID::operator==(const ID& rhs) const {
+  return category_ == rhs.category_ &&
+         id_within_category_ == rhs.id_within_category_;
+}
+
+bool ContentSuggestion::ID::operator!=(const ID& rhs) const {
+  return !(*this == rhs);
+}
+
+ContentSuggestion::ContentSuggestion(ID id, const GURL& url)
     : id_(id), url_(url), score_(0) {}
 
+ContentSuggestion::ContentSuggestion(Category category,
+                                     const std::string& id_within_category,
+                                     const GURL& url)
+    : id_(category, id_within_category), url_(url), score_(0) {}
+
 ContentSuggestion::ContentSuggestion(ContentSuggestion&&) = default;
 
 ContentSuggestion& ContentSuggestion::operator=(ContentSuggestion&&) = default;
 
 ContentSuggestion::~ContentSuggestion() = default;
 
+std::ostream& operator<<(std::ostream& os, ContentSuggestion::ID id) {
+  os << id.category() << "|" << id.id_within_category();
+  return os;
+}
+
 }  // namespace ntp_snippets
diff --git a/components/ntp_snippets/content_suggestion.h b/components/ntp_snippets/content_suggestion.h
index f289706..bf8442c 100644
--- a/components/ntp_snippets/content_suggestion.h
+++ b/components/ntp_snippets/content_suggestion.h
@@ -5,13 +5,12 @@
 #ifndef COMPONENTS_NTP_SNIPPETS_CONTENT_SUGGESTION_H_
 #define COMPONENTS_NTP_SNIPPETS_CONTENT_SUGGESTION_H_
 
-#include <memory>
 #include <string>
-#include <vector>
 
 #include "base/macros.h"
 #include "base/strings/string16.h"
 #include "base/time/time.h"
+#include "components/ntp_snippets/category.h"
 #include "url/gurl.h"
 
 namespace ntp_snippets {
@@ -20,9 +19,32 @@
 // offline page, for example.
 class ContentSuggestion {
  public:
+  class ID {
+   public:
+    ID(Category category, const std::string& id_within_category)
+        : category_(category), id_within_category_(id_within_category) {}
+
+    Category category() const { return category_; }
+
+    const std::string& id_within_category() const {
+      return id_within_category_;
+    }
+
+    bool operator==(const ID& rhs) const;
+    bool operator!=(const ID& rhs) const;
+
+   private:
+    Category category_;
+    std::string id_within_category_;
+
+    // Allow copy and assignment.
+  };
+
   // Creates a new ContentSuggestion. The caller must ensure that the |id|
   // passed in here is unique application-wide.
-  ContentSuggestion(const std::string& id,
+  ContentSuggestion(ID id, const GURL& url);
+  ContentSuggestion(Category category,
+                    const std::string& id_within_category,
                     const GURL& url);
   ContentSuggestion(ContentSuggestion&&);
   ContentSuggestion& operator=(ContentSuggestion&&);
@@ -30,7 +52,7 @@
   ~ContentSuggestion();
 
   // An ID for identifying the suggestion. The ID is unique application-wide.
-  const std::string& id() const { return id_; }
+  const ID& id() const { return id_; }
 
   // The normal content URL where the content referenced by the suggestion can
   // be accessed.
@@ -72,7 +94,7 @@
   void set_score(float score) { score_ = score; }
 
  private:
-  std::string id_;
+  ID id_;
   GURL url_;
   GURL amp_url_;
   base::string16 title_;
@@ -84,6 +106,8 @@
   DISALLOW_COPY_AND_ASSIGN(ContentSuggestion);
 };
 
+std::ostream& operator<<(std::ostream& os, ContentSuggestion::ID id);
+
 }  // namespace ntp_snippets
 
 #endif  // COMPONENTS_NTP_SNIPPETS_CONTENT_SUGGESTION_H_
diff --git a/components/ntp_snippets/content_suggestions_provider.cc b/components/ntp_snippets/content_suggestions_provider.cc
index de3c759..3489657 100644
--- a/components/ntp_snippets/content_suggestions_provider.cc
+++ b/components/ntp_snippets/content_suggestions_provider.cc
@@ -15,20 +15,4 @@
 
 ContentSuggestionsProvider::~ContentSuggestionsProvider() = default;
 
-std::string ContentSuggestionsProvider::MakeUniqueID(
-    Category category,
-    const std::string& within_category_id) const {
-  return category_factory()->MakeUniqueID(category, within_category_id);
-}
-
-Category ContentSuggestionsProvider::GetCategoryFromUniqueID(
-    const std::string& unique_id) const {
-  return category_factory()->GetCategoryFromUniqueID(unique_id);
-}
-
-std::string ContentSuggestionsProvider::GetWithinCategoryIDFromUniqueID(
-    const std::string& unique_id) const {
-  return category_factory()->GetWithinCategoryIDFromUniqueID(unique_id);
-}
-
 }  // namespace ntp_snippets
diff --git a/components/ntp_snippets/content_suggestions_provider.h b/components/ntp_snippets/content_suggestions_provider.h
index bc568f5..b3119669 100644
--- a/components/ntp_snippets/content_suggestions_provider.h
+++ b/components/ntp_snippets/content_suggestions_provider.h
@@ -70,13 +70,13 @@
     // |FetchSuggestionImage| or |DismissSuggestion| anymore, and should
     // immediately be cleared from the UI and caches. This happens, for example,
     // when the content that the suggestion refers to is gone.
-    // Note that this event may be fired even if the corresponding |category| is
+    // Note that this event may be fired even if the corresponding category is
     // not currently AVAILABLE, because open UIs may still be showing the
     // suggestion that is to be removed. This event may also be fired for
     // |suggestion_id|s that never existed and should be ignored in that case.
-    virtual void OnSuggestionInvalidated(ContentSuggestionsProvider* provider,
-                                         Category category,
-                                         const std::string& suggestion_id) = 0;
+    virtual void OnSuggestionInvalidated(
+        ContentSuggestionsProvider* provider,
+        const ContentSuggestion::ID& suggestion_id) = 0;
   };
 
   virtual ~ContentSuggestionsProvider();
@@ -91,14 +91,15 @@
   // a once-dismissed suggestion is never delivered again (through the
   // Observer). The provider must not call Observer::OnSuggestionsChanged if the
   // removal of the dismissed suggestion is the only change.
-  virtual void DismissSuggestion(const std::string& suggestion_id) = 0;
+  virtual void DismissSuggestion(
+      const ContentSuggestion::ID& suggestion_id) = 0;
 
   // Fetches the image for the suggestion with the given ID and returns it
   // through the callback. This fetch may occur locally or from the internet.
   // If that suggestion doesn't exist, doesn't have an image or if the fetch
   // fails, the callback gets a null image. The callback will not be called
   // synchronously.
-  virtual void FetchSuggestionImage(const std::string& suggestion_id,
+  virtual void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
                                     const ImageFetchedCallback& callback) = 0;
 
   // Removes history from the specified time range where the URL matches the
@@ -136,19 +137,6 @@
   ContentSuggestionsProvider(Observer* observer,
                              CategoryFactory* category_factory);
 
-  // Creates a unique ID. The given |within_category_id| must be unique among
-  // all suggestion IDs from this provider for the given |category|. This method
-  // combines it with the |category| to form an ID that is unique
-  // application-wide, because this provider is the only one that provides
-  // suggestions for that category.
-  std::string MakeUniqueID(Category category,
-                           const std::string& within_category_id) const;
-
-  // Reverse functions for MakeUniqueID()
-  Category GetCategoryFromUniqueID(const std::string& unique_id) const;
-  std::string GetWithinCategoryIDFromUniqueID(
-      const std::string& unique_id) const;
-
   Observer* observer() const { return observer_; }
   CategoryFactory* category_factory() const { return category_factory_; }
 
diff --git a/components/ntp_snippets/content_suggestions_service.cc b/components/ntp_snippets/content_suggestions_service.cc
index f141eab..f52a980 100644
--- a/components/ntp_snippets/content_suggestions_service.cc
+++ b/components/ntp_snippets/content_suggestions_service.cc
@@ -72,18 +72,17 @@
 }
 
 void ContentSuggestionsService::FetchSuggestionImage(
-    const std::string& suggestion_id,
+    const ContentSuggestion::ID& suggestion_id,
     const ImageFetchedCallback& callback) {
-  Category category = category_factory_.GetCategoryFromUniqueID(suggestion_id);
-  if (!providers_by_category_.count(category)) {
+  if (!providers_by_category_.count(suggestion_id.category())) {
     LOG(WARNING) << "Requested image for suggestion " << suggestion_id
-                 << " for unavailable category " << category;
+                 << " for unavailable category " << suggestion_id.category();
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(callback, gfx::Image()));
     return;
   }
-  providers_by_category_[category]->FetchSuggestionImage(suggestion_id,
-                                                         callback);
+  providers_by_category_[suggestion_id.category()]->FetchSuggestionImage(
+      suggestion_id, callback);
 }
 
 void ContentSuggestionsService::ClearHistory(
@@ -130,17 +129,17 @@
 }
 
 void ContentSuggestionsService::DismissSuggestion(
-    const std::string& suggestion_id) {
-  Category category = category_factory_.GetCategoryFromUniqueID(suggestion_id);
-  if (!providers_by_category_.count(category)) {
+    const ContentSuggestion::ID& suggestion_id) {
+  if (!providers_by_category_.count(suggestion_id.category())) {
     LOG(WARNING) << "Dismissed suggestion " << suggestion_id
-                 << " for unavailable category " << category;
+                 << " for unavailable category " << suggestion_id.category();
     return;
   }
-  providers_by_category_[category]->DismissSuggestion(suggestion_id);
+  providers_by_category_[suggestion_id.category()]->DismissSuggestion(
+      suggestion_id);
 
   // Remove the suggestion locally.
-  bool removed = RemoveSuggestionByID(category, suggestion_id);
+  bool removed = RemoveSuggestionByID(suggestion_id);
   DCHECK(removed) << "The dismissed suggestion " << suggestion_id
                   << " has already been removed. Providers must not call"
                   << " OnNewSuggestions in response to DismissSuggestion.";
@@ -214,11 +213,10 @@
 
 void ContentSuggestionsService::OnSuggestionInvalidated(
     ContentSuggestionsProvider* provider,
-    Category category,
-    const std::string& suggestion_id) {
-  RemoveSuggestionByID(category, suggestion_id);
+    const ContentSuggestion::ID& suggestion_id) {
+  RemoveSuggestionByID(suggestion_id);
   FOR_EACH_OBSERVER(Observer, observers_,
-                    OnSuggestionInvalidated(category, suggestion_id));
+                    OnSuggestionInvalidated(suggestion_id));
 }
 
 // history::HistoryServiceObserver implementation.
@@ -287,10 +285,9 @@
 }
 
 bool ContentSuggestionsService::RemoveSuggestionByID(
-    Category category,
-    const std::string& suggestion_id) {
+    const ContentSuggestion::ID& suggestion_id) {
   std::vector<ContentSuggestion>* suggestions =
-      &suggestions_by_category_[category];
+      &suggestions_by_category_[suggestion_id.category()];
   auto position =
       std::find_if(suggestions->begin(), suggestions->end(),
                    [&suggestion_id](const ContentSuggestion& suggestion) {
@@ -302,7 +299,7 @@
 
   // The positioning of the bookmarks category depends on whether it's empty.
   // TODO(treib): Remove this temporary hack, crbug.com/640568.
-  if (category.IsKnownCategory(KnownCategories::BOOKMARKS))
+  if (suggestion_id.category().IsKnownCategory(KnownCategories::BOOKMARKS))
     SortCategories();
 
   return true;
diff --git a/components/ntp_snippets/content_suggestions_service.h b/components/ntp_snippets/content_suggestions_service.h
index 8c4a4f7..045785f0 100644
--- a/components/ntp_snippets/content_suggestions_service.h
+++ b/components/ntp_snippets/content_suggestions_service.h
@@ -63,12 +63,12 @@
     // Fired when a suggestion has been invalidated. The UI must immediately
     // clear the suggestion even from open NTPs. Invalidation happens, for
     // example, when the content that the suggestion refers to is gone.
-    // Note that this event may be fired even if the corresponding |category| is
+    // Note that this event may be fired even if the corresponding category is
     // not currently AVAILABLE, because open UIs may still be showing the
     // suggestion that is to be removed. This event may also be fired for
     // |suggestion_id|s that never existed and should be ignored in that case.
-    virtual void OnSuggestionInvalidated(Category category,
-                                         const std::string& suggestion_id) = 0;
+    virtual void OnSuggestionInvalidated(
+        const ContentSuggestion::ID& suggestion_id) = 0;
 
     // Sent when the service is shutting down. After the service has shut down,
     // it will not provide any data anymore, though calling the getters is still
@@ -114,12 +114,12 @@
   // runs the |callback|. If that suggestion doesn't exist or the fetch fails,
   // the callback gets an empty image. The callback will not be called
   // synchronously.
-  void FetchSuggestionImage(const std::string& suggestion_id,
+  void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
                             const ImageFetchedCallback& callback);
 
   // Dismisses the suggestion with the given |suggestion_id|, if it exists.
   // This will not trigger an update through the observers.
-  void DismissSuggestion(const std::string& suggestion_id);
+  void DismissSuggestion(const ContentSuggestion::ID& suggestion_id);
 
   // Dismisses the given |category|, if it exists.
   // This will not trigger an update through the observers.
@@ -193,9 +193,9 @@
   void OnCategoryStatusChanged(ContentSuggestionsProvider* provider,
                                Category category,
                                CategoryStatus new_status) override;
-  void OnSuggestionInvalidated(ContentSuggestionsProvider* provider,
-                               Category category,
-                               const std::string& suggestion_id) override;
+  void OnSuggestionInvalidated(
+      ContentSuggestionsProvider* provider,
+      const ContentSuggestion::ID& suggestion_id) override;
 
   // history::HistoryServiceObserver implementation.
   void OnURLsDeleted(history::HistoryService* history_service,
@@ -214,8 +214,7 @@
 
   // Removes a suggestion from the local store |suggestions_by_category_|, if it
   // exists. Returns true if a suggestion was removed.
-  bool RemoveSuggestionByID(Category category,
-                            const std::string& suggestion_id);
+  bool RemoveSuggestionByID(const ContentSuggestion::ID& suggestion_id);
 
   // Fires the OnCategoryStatusChanged event for the given |category|.
   void NotifyCategoryStatusChanged(Category category);
diff --git a/components/ntp_snippets/content_suggestions_service_unittest.cc b/components/ntp_snippets/content_suggestions_service_unittest.cc
index d0629cb..a2245bf 100644
--- a/components/ntp_snippets/content_suggestions_service_unittest.cc
+++ b/components/ntp_snippets/content_suggestions_service_unittest.cc
@@ -77,9 +77,8 @@
                                         statuses_[category.id()]);
   }
 
-  void FireSuggestionInvalidated(Category category,
-                                 const std::string& suggestion_id) {
-    observer()->OnSuggestionInvalidated(this, category, suggestion_id);
+  void FireSuggestionInvalidated(const ContentSuggestion::ID& suggestion_id) {
+    observer()->OnSuggestionInvalidated(this, suggestion_id);
   }
 
   MOCK_METHOD3(ClearHistory,
@@ -91,9 +90,10 @@
                void(Category category,
                     const DismissedSuggestionsCallback& callback));
   MOCK_METHOD1(ClearDismissedSuggestionsForDebugging, void(Category category));
-  MOCK_METHOD1(DismissSuggestion, void(const std::string& suggestion_id));
+  MOCK_METHOD1(DismissSuggestion,
+               void(const ContentSuggestion::ID& suggestion_id));
   MOCK_METHOD2(FetchSuggestionImage,
-               void(const std::string& suggestion_id,
+               void(const ContentSuggestion::ID& suggestion_id,
                     const ImageFetchedCallback& callback));
 
  private:
@@ -109,8 +109,8 @@
   MOCK_METHOD1(OnNewSuggestions, void(Category category));
   MOCK_METHOD2(OnCategoryStatusChanged,
                void(Category changed_category, CategoryStatus new_status));
-  MOCK_METHOD2(OnSuggestionInvalidated,
-               void(Category category, const std::string& suggestion_id));
+  MOCK_METHOD1(OnSuggestionInvalidated,
+               void(const ContentSuggestion::ID& suggestion_id));
   MOCK_METHOD0(ContentSuggestionsServiceShutdown, void());
 
  private:
@@ -143,11 +143,9 @@
 
     for (const auto& suggestion :
          service()->GetSuggestionsForCategory(category)) {
-      std::string within_category_id =
-          service()->category_factory()->GetWithinCategoryIDFromUniqueID(
-              suggestion.id());
+      std::string id_within_category = suggestion.id().id_within_category();
       int id;
-      ASSERT_TRUE(base::StringToInt(within_category_id, &id));
+      ASSERT_TRUE(base::StringToInt(id_within_category, &id));
       auto position = std::find(numbers.begin(), numbers.end(), id);
       if (position == numbers.end()) {
         ADD_FAILURE() << "Unexpected suggestion with ID " << id;
@@ -205,8 +203,7 @@
   // Returns a suggestion instance for testing.
   ContentSuggestion CreateSuggestion(Category category, int number) {
     return ContentSuggestion(
-        service()->category_factory()->MakeUniqueID(category,
-                                                    base::IntToString(number)),
+        category, base::IntToString(number),
         GURL("http://testsuggestion/" + base::IntToString(number)));
   }
 
@@ -299,7 +296,7 @@
 
   provider1->FireSuggestionsChanged(articles_category,
                                     CreateSuggestions(articles_category, {1}));
-  std::string suggestion_id = CreateSuggestion(articles_category, 1).id();
+  ContentSuggestion::ID suggestion_id(articles_category, "1");
 
   EXPECT_CALL(*provider1, FetchSuggestionImage(suggestion_id, _));
   EXPECT_CALL(*provider2, FetchSuggestionImage(_, _)).Times(0);
@@ -315,7 +312,8 @@
 
   base::RunLoop run_loop;
   // Assuming there will never be a category with the id below.
-  std::string suggestion_id = "21563|TestID";
+  ContentSuggestion::ID suggestion_id(category_factory()->FromIDValue(21563),
+                                      "TestID");
   EXPECT_CALL(*this, OnImageFetched(Property(&gfx::Image::IsEmpty, Eq(true))))
       .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
   service()->FetchSuggestionImage(
@@ -333,7 +331,7 @@
 
   provider2->FireSuggestionsChanged(
       offline_pages_category, CreateSuggestions(offline_pages_category, {11}));
-  std::string suggestion_id = CreateSuggestion(offline_pages_category, 11).id();
+  ContentSuggestion::ID suggestion_id(offline_pages_category, "11");
 
   EXPECT_CALL(*provider1, DismissSuggestion(_)).Times(0);
   EXPECT_CALL(*provider2, DismissSuggestion(suggestion_id));
@@ -351,19 +349,18 @@
       articles_category, CreateSuggestions(articles_category, {11, 12, 13}));
   ExpectThatSuggestionsAre(articles_category, {11, 12, 13});
 
-  std::string suggestion_id = CreateSuggestion(articles_category, 12).id();
-  EXPECT_CALL(observer,
-              OnSuggestionInvalidated(articles_category, suggestion_id));
-  provider->FireSuggestionInvalidated(articles_category, suggestion_id);
+  ContentSuggestion::ID suggestion_id(articles_category, "12");
+  EXPECT_CALL(observer, OnSuggestionInvalidated(suggestion_id));
+  provider->FireSuggestionInvalidated(suggestion_id);
   ExpectThatSuggestionsAre(articles_category, {11, 13});
   Mock::VerifyAndClearExpectations(&observer);
 
   // Unknown IDs must be forwarded (though no change happens to the service's
   // internal data structures) because previously opened UIs, which can still
   // show the invalidated suggestion, must be notified.
-  std::string unknown_id = CreateSuggestion(articles_category, 1234).id();
-  EXPECT_CALL(observer, OnSuggestionInvalidated(articles_category, unknown_id));
-  provider->FireSuggestionInvalidated(articles_category, unknown_id);
+  ContentSuggestion::ID unknown_id(articles_category, "1234");
+  EXPECT_CALL(observer, OnSuggestionInvalidated(unknown_id));
+  provider->FireSuggestionInvalidated(unknown_id);
   ExpectThatSuggestionsAre(articles_category, {11, 13});
   Mock::VerifyAndClearExpectations(&observer);
 
@@ -576,10 +573,10 @@
       bookmarks, CreateSuggestions(bookmarks, {1, 2}));
   EXPECT_THAT(service()->GetCategories(), ElementsAre(bookmarks, remote));
   bookmarks_provider->FireSuggestionInvalidated(
-      bookmarks, CreateSuggestion(bookmarks, 1).id());
+      ContentSuggestion::ID(bookmarks, "1"));
   EXPECT_THAT(service()->GetCategories(), ElementsAre(bookmarks, remote));
   bookmarks_provider->FireSuggestionInvalidated(
-      bookmarks, CreateSuggestion(bookmarks, 2).id());
+      ContentSuggestion::ID(bookmarks, "2"));
   EXPECT_THAT(service()->GetCategories(), ElementsAre(remote, bookmarks));
 
   // Same thing, but now the bookmarks category updates "naturally".
diff --git a/components/ntp_snippets/mock_content_suggestions_provider_observer.h b/components/ntp_snippets/mock_content_suggestions_provider_observer.h
index 01e273d..12bb1fd 100644
--- a/components/ntp_snippets/mock_content_suggestions_provider_observer.h
+++ b/components/ntp_snippets/mock_content_suggestions_provider_observer.h
@@ -37,10 +37,9 @@
                void(ContentSuggestionsProvider* provider,
                     Category category,
                     CategoryStatus new_status));
-  MOCK_METHOD3(OnSuggestionInvalidated,
+  MOCK_METHOD2(OnSuggestionInvalidated,
                void(ContentSuggestionsProvider* provider,
-                    Category category,
-                    const std::string& suggestion_id));
+                    const ContentSuggestion::ID& suggestion_id));
 };
 
 }  // namespace ntp_snippets
diff --git a/components/ntp_snippets/offline_pages/offline_page_suggestions_provider.cc b/components/ntp_snippets/offline_pages/offline_page_suggestions_provider.cc
index 8d489a65..d1525ba4f 100644
--- a/components/ntp_snippets/offline_pages/offline_page_suggestions_provider.cc
+++ b/components/ntp_snippets/offline_pages/offline_page_suggestions_provider.cc
@@ -135,16 +135,15 @@
 }
 
 void OfflinePageSuggestionsProvider::DismissSuggestion(
-    const std::string& suggestion_id) {
-  Category category = GetCategoryFromUniqueID(suggestion_id);
-  std::string offline_page_id = GetWithinCategoryIDFromUniqueID(suggestion_id);
-  std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs(category);
-  dismissed_ids.insert(offline_page_id);
-  StoreDismissedIDsToPrefs(category, dismissed_ids);
+    const ContentSuggestion::ID& suggestion_id) {
+  std::set<std::string> dismissed_ids =
+      ReadDismissedIDsFromPrefs(suggestion_id.category());
+  dismissed_ids.insert(suggestion_id.id_within_category());
+  StoreDismissedIDsToPrefs(suggestion_id.category(), dismissed_ids);
 }
 
 void OfflinePageSuggestionsProvider::FetchSuggestionImage(
-    const std::string& suggestion_id,
+    const ContentSuggestion::ID& suggestion_id,
     const ImageFetchedCallback& callback) {
   // TODO(pke): Fetch proper thumbnail from OfflinePageModel once it's available
   // there.
@@ -314,9 +313,9 @@
   // TODO(pke): Make sure the URL is actually opened as an offline URL.
   // Currently, the browser opens the offline URL and then immediately
   // redirects to the online URL if the device is online.
-  ContentSuggestion suggestion(
-      MakeUniqueID(category, base::IntToString(offline_page.offline_id)),
-      offline_page.GetOfflineURL());
+  ContentSuggestion suggestion(category,
+                               base::IntToString(offline_page.offline_id),
+                               offline_page.GetOfflineURL());
 
   if (offline_page.title.empty()) {
     // TODO(pke): Remove this fallback once the OfflinePageModel provides titles
@@ -348,8 +347,8 @@
 void OfflinePageSuggestionsProvider::InvalidateSuggestion(Category category,
                                                           int64_t offline_id) {
   std::string offline_page_id = base::IntToString(offline_id);
-  observer()->OnSuggestionInvalidated(this, category,
-                                      MakeUniqueID(category, offline_page_id));
+  observer()->OnSuggestionInvalidated(
+      this, ContentSuggestion::ID(category, offline_page_id));
 
   std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs(category);
   auto it = dismissed_ids.find(offline_page_id);
diff --git a/components/ntp_snippets/offline_pages/offline_page_suggestions_provider.h b/components/ntp_snippets/offline_pages/offline_page_suggestions_provider.h
index 19a058a5..41d421e 100644
--- a/components/ntp_snippets/offline_pages/offline_page_suggestions_provider.h
+++ b/components/ntp_snippets/offline_pages/offline_page_suggestions_provider.h
@@ -52,8 +52,8 @@
   // ContentSuggestionsProvider implementation.
   CategoryStatus GetCategoryStatus(Category category) override;
   CategoryInfo GetCategoryInfo(Category category) override;
-  void DismissSuggestion(const std::string& suggestion_id) override;
-  void FetchSuggestionImage(const std::string& suggestion_id,
+  void DismissSuggestion(const ContentSuggestion::ID& suggestion_id) override;
+  void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
                             const ImageFetchedCallback& callback) override;
   void ClearHistory(
       base::Time begin,
diff --git a/components/ntp_snippets/offline_pages/offline_page_suggestions_provider_unittest.cc b/components/ntp_snippets/offline_pages/offline_page_suggestions_provider_unittest.cc
index 039ac5b..4ad0254f 100644
--- a/components/ntp_snippets/offline_pages/offline_page_suggestions_provider_unittest.cc
+++ b/components/ntp_snippets/offline_pages/offline_page_suggestions_provider_unittest.cc
@@ -134,8 +134,8 @@
     return category_factory_.FromKnownCategory(KnownCategories::DOWNLOADS);
   }
 
-  std::string GetDummySuggestionId(Category category, int id) {
-    return provider_->MakeUniqueID(category, base::IntToString(id));
+  ContentSuggestion::ID GetDummySuggestionId(Category category, int id) {
+    return ContentSuggestion::ID(category, base::IntToString(id));
   }
 
   ContentSuggestion CreateDummySuggestion(Category category, int id) {
@@ -348,10 +348,9 @@
   FireOfflinePageModelChanged();
 
   // Invalidation of suggestion 2 should be forwarded.
-  EXPECT_CALL(
-      *observer(),
-      OnSuggestionInvalidated(_, recent_tabs_category(),
-                              GetDummySuggestionId(recent_tabs_category(), 2)));
+  EXPECT_CALL(*observer(),
+              OnSuggestionInvalidated(
+                  _, GetDummySuggestionId(recent_tabs_category(), 2)));
   FireOfflinePageDeleted(model()->items().at(1));
 }
 
diff --git a/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc b/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc
index 22dd7ed..b87f20e 100644
--- a/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc
+++ b/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc
@@ -45,9 +45,8 @@
   for (const UrlInfo& url_info : urls) {
     if (suggestions.size() >= kMaxSuggestionsCount) break;
 
-    ContentSuggestion suggestion(
-        MakeUniqueID(provided_category_, url_info.site_url.spec()),
-        url_info.site_url);
+    ContentSuggestion suggestion(provided_category_, url_info.site_url.spec(),
+                                 url_info.site_url);
 
     suggestion.set_title(base::UTF8ToUTF16(url_info.title));
     suggestion.set_snippet_text(base::UTF8ToUTF16(url_info.description));
@@ -75,13 +74,14 @@
 }
 
 void PhysicalWebPageSuggestionsProvider::DismissSuggestion(
-    const std::string& suggestion_id) {
+    const ContentSuggestion::ID& suggestion_id) {
   // TODO(vitaliii): Implement this and then
   // ClearDismissedSuggestionsForDebugging.
 }
 
 void PhysicalWebPageSuggestionsProvider::FetchSuggestionImage(
-    const std::string& suggestion_id, const ImageFetchedCallback& callback) {
+    const ContentSuggestion::ID& suggestion_id,
+    const ImageFetchedCallback& callback) {
   // TODO(vitaliii): Implement.
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(callback, gfx::Image()));
diff --git a/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.h b/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.h
index b2c7431a..934dd74 100644
--- a/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.h
+++ b/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.h
@@ -45,8 +45,8 @@
   // ContentSuggestionsProvider implementation.
   CategoryStatus GetCategoryStatus(Category category) override;
   CategoryInfo GetCategoryInfo(Category category) override;
-  void DismissSuggestion(const std::string& suggestion_id) override;
-  void FetchSuggestionImage(const std::string& suggestion_id,
+  void DismissSuggestion(const ContentSuggestion::ID& suggestion_id) override;
+  void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
                             const ImageFetchedCallback& callback) override;
   void ClearHistory(
       base::Time begin,
diff --git a/components/ntp_snippets/ntp_snippet.cc b/components/ntp_snippets/remote/ntp_snippet.cc
similarity index 98%
rename from components/ntp_snippets/ntp_snippet.cc
rename to components/ntp_snippets/remote/ntp_snippet.cc
index 57f9526..496e1fa 100644
--- a/components/ntp_snippets/ntp_snippet.cc
+++ b/components/ntp_snippets/remote/ntp_snippet.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/ntp_snippets/ntp_snippet.h"
+#include "components/ntp_snippets/remote/ntp_snippet.h"
 
 #include "base/memory/ptr_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
 
-#include "components/ntp_snippets/proto/ntp_snippets.pb.h"
+#include "components/ntp_snippets/remote/proto/ntp_snippets.pb.h"
 
 namespace {
 
diff --git a/components/ntp_snippets/ntp_snippet.h b/components/ntp_snippets/remote/ntp_snippet.h
similarity index 96%
rename from components/ntp_snippets/ntp_snippet.h
rename to components/ntp_snippets/remote/ntp_snippet.h
index def1b88..f14d3ad6 100644
--- a/components/ntp_snippets/ntp_snippet.h
+++ b/components/ntp_snippets/remote/ntp_snippet.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_NTP_SNIPPETS_NTP_SNIPPET_H_
-#define COMPONENTS_NTP_SNIPPETS_NTP_SNIPPET_H_
+#ifndef COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPET_H_
+#define COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPET_H_
 
 #include <map>
 #include <memory>
@@ -152,4 +152,4 @@
 
 }  // namespace ntp_snippets
 
-#endif  // COMPONENTS_NTP_SNIPPETS_NTP_SNIPPET_H_
+#endif  // COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPET_H_
diff --git a/components/ntp_snippets/ntp_snippet_unittest.cc b/components/ntp_snippets/remote/ntp_snippet_unittest.cc
similarity index 99%
rename from components/ntp_snippets/ntp_snippet_unittest.cc
rename to components/ntp_snippets/remote/ntp_snippet_unittest.cc
index 825a6f2..2c6c95e 100644
--- a/components/ntp_snippets/ntp_snippet_unittest.cc
+++ b/components/ntp_snippets/remote/ntp_snippet_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 "components/ntp_snippets/ntp_snippet.h"
+#include "components/ntp_snippets/remote/ntp_snippet.h"
 
 #include "base/json/json_reader.h"
 #include "base/values.h"
diff --git a/components/ntp_snippets/ntp_snippets_database.cc b/components/ntp_snippets/remote/ntp_snippets_database.cc
similarity index 98%
rename from components/ntp_snippets/ntp_snippets_database.cc
rename to components/ntp_snippets/remote/ntp_snippets_database.cc
index 0a52f76f..5ded341 100644
--- a/components/ntp_snippets/ntp_snippets_database.cc
+++ b/components/ntp_snippets/remote/ntp_snippets_database.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/ntp_snippets/ntp_snippets_database.h"
+#include "components/ntp_snippets/remote/ntp_snippets_database.h"
 
 #include <utility>
 
 #include "base/files/file_path.h"
 #include "components/leveldb_proto/proto_database_impl.h"
-#include "components/ntp_snippets/proto/ntp_snippets.pb.h"
+#include "components/ntp_snippets/remote/proto/ntp_snippets.pb.h"
 
 using leveldb_proto::ProtoDatabaseImpl;
 
diff --git a/components/ntp_snippets/ntp_snippets_database.h b/components/ntp_snippets/remote/ntp_snippets_database.h
similarity index 94%
rename from components/ntp_snippets/ntp_snippets_database.h
rename to components/ntp_snippets/remote/ntp_snippets_database.h
index dc5131c..9c903f0a 100644
--- a/components/ntp_snippets/ntp_snippets_database.h
+++ b/components/ntp_snippets/remote/ntp_snippets_database.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_DATABASE_H_
-#define COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_DATABASE_H_
+#ifndef COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_DATABASE_H_
+#define COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_DATABASE_H_
 
 #include <memory>
 #include <string>
@@ -16,7 +16,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/sequenced_task_runner.h"
 #include "components/leveldb_proto/proto_database.h"
-#include "components/ntp_snippets/ntp_snippet.h"
+#include "components/ntp_snippets/remote/ntp_snippet.h"
 
 namespace base {
 class FilePath;
@@ -131,4 +131,4 @@
 
 }  // namespace ntp_snippets
 
-#endif  // COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_DATABASE_H_
+#endif  // COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_DATABASE_H_
diff --git a/components/ntp_snippets/ntp_snippets_database_unittest.cc b/components/ntp_snippets/remote/ntp_snippets_database_unittest.cc
similarity index 99%
rename from components/ntp_snippets/ntp_snippets_database_unittest.cc
rename to components/ntp_snippets/remote/ntp_snippets_database_unittest.cc
index 1c7c8f8..1bd31b86c 100644
--- a/components/ntp_snippets/ntp_snippets_database_unittest.cc
+++ b/components/ntp_snippets/remote/ntp_snippets_database_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 "components/ntp_snippets/ntp_snippets_database.h"
+#include "components/ntp_snippets/remote/ntp_snippets_database.h"
 
 #include <memory>
 
diff --git a/components/ntp_snippets/ntp_snippets_fetcher.cc b/components/ntp_snippets/remote/ntp_snippets_fetcher.cc
similarity index 99%
rename from components/ntp_snippets/ntp_snippets_fetcher.cc
rename to components/ntp_snippets/remote/ntp_snippets_fetcher.cc
index f494a97..b447572 100644
--- a/components/ntp_snippets/ntp_snippets_fetcher.cc
+++ b/components/ntp_snippets/remote/ntp_snippets_fetcher.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 "components/ntp_snippets/ntp_snippets_fetcher.h"
+#include "components/ntp_snippets/remote/ntp_snippets_fetcher.h"
 
 #include <cstdlib>
 
diff --git a/components/ntp_snippets/ntp_snippets_fetcher.h b/components/ntp_snippets/remote/ntp_snippets_fetcher.h
similarity index 96%
rename from components/ntp_snippets/ntp_snippets_fetcher.h
rename to components/ntp_snippets/remote/ntp_snippets_fetcher.h
index 03276c8..2d801ac 100644
--- a/components/ntp_snippets/ntp_snippets_fetcher.h
+++ b/components/ntp_snippets/remote/ntp_snippets_fetcher.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_FETCHER_H_
-#define COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_FETCHER_H_
+#ifndef COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_FETCHER_H_
+#define COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_FETCHER_H_
 
 #include <memory>
 #include <set>
@@ -16,8 +16,8 @@
 #include "base/optional.h"
 #include "base/time/tick_clock.h"
 #include "base/time/time.h"
-#include "components/ntp_snippets/ntp_snippet.h"
-#include "components/ntp_snippets/request_throttler.h"
+#include "components/ntp_snippets/remote/ntp_snippet.h"
+#include "components/ntp_snippets/remote/request_throttler.h"
 #include "google_apis/gaia/oauth2_token_service.h"
 #include "net/url_request/url_fetcher_delegate.h"
 #include "net/url_request/url_request_context_getter.h"
@@ -265,4 +265,4 @@
 };
 }  // namespace ntp_snippets
 
-#endif  // COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_FETCHER_H_
+#endif  // COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_FETCHER_H_
diff --git a/components/ntp_snippets/ntp_snippets_fetcher_unittest.cc b/components/ntp_snippets/remote/ntp_snippets_fetcher_unittest.cc
similarity index 99%
rename from components/ntp_snippets/ntp_snippets_fetcher_unittest.cc
rename to components/ntp_snippets/remote/ntp_snippets_fetcher_unittest.cc
index d688b47..b5934c7 100644
--- a/components/ntp_snippets/ntp_snippets_fetcher_unittest.cc
+++ b/components/ntp_snippets/remote/ntp_snippets_fetcher_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 "components/ntp_snippets/ntp_snippets_fetcher.h"
+#include "components/ntp_snippets/remote/ntp_snippets_fetcher.h"
 
 #include <map>
 #include <utility>
@@ -16,8 +16,8 @@
 #include "base/time/time.h"
 #include "base/values.h"
 #include "components/ntp_snippets/category_factory.h"
-#include "components/ntp_snippets/ntp_snippet.h"
 #include "components/ntp_snippets/ntp_snippets_constants.h"
+#include "components/ntp_snippets/remote/ntp_snippet.h"
 #include "components/prefs/testing_pref_service.h"
 #include "components/signin/core/browser/account_tracker_service.h"
 #include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
diff --git a/components/ntp_snippets/ntp_snippets_scheduler.h b/components/ntp_snippets/remote/ntp_snippets_scheduler.h
similarity index 82%
rename from components/ntp_snippets/ntp_snippets_scheduler.h
rename to components/ntp_snippets/remote/ntp_snippets_scheduler.h
index 1b9517c..7a4fc1ef 100644
--- a/components/ntp_snippets/ntp_snippets_scheduler.h
+++ b/components/ntp_snippets/remote/ntp_snippets_scheduler.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_SCHEDULER_H_
-#define COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_SCHEDULER_H_
+#ifndef COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_SCHEDULER_H_
+#define COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_SCHEDULER_H_
 
 #include "base/macros.h"
 #include "base/time/time.h"
@@ -33,4 +33,4 @@
 
 }  // namespace ntp_snippets
 
-#endif  // COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_SCHEDULER_H_
+#endif  // COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_SCHEDULER_H_
diff --git a/components/ntp_snippets/ntp_snippets_service.cc b/components/ntp_snippets/remote/ntp_snippets_service.cc
similarity index 92%
rename from components/ntp_snippets/ntp_snippets_service.cc
rename to components/ntp_snippets/remote/ntp_snippets_service.cc
index c59770b..dbf472b 100644
--- a/components/ntp_snippets/ntp_snippets_service.cc
+++ b/components/ntp_snippets/remote/ntp_snippets_service.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 "components/ntp_snippets/ntp_snippets_service.h"
+#include "components/ntp_snippets/remote/ntp_snippets_service.h"
 
 #include <algorithm>
 #include <iterator>
@@ -15,6 +15,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/sparse_histogram.h"
 #include "base/path_service.h"
+#include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task_runner_util.h"
@@ -25,8 +26,8 @@
 #include "components/image_fetcher/image_decoder.h"
 #include "components/image_fetcher/image_fetcher.h"
 #include "components/ntp_snippets/ntp_snippets_constants.h"
-#include "components/ntp_snippets/ntp_snippets_database.h"
 #include "components/ntp_snippets/pref_names.h"
+#include "components/ntp_snippets/remote/ntp_snippets_database.h"
 #include "components/ntp_snippets/switches.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
@@ -321,39 +322,36 @@
                       /* show_if_empty */ true);
 }
 
-void NTPSnippetsService::DismissSuggestion(const std::string& suggestion_id) {
+void NTPSnippetsService::DismissSuggestion(
+    const ContentSuggestion::ID& suggestion_id) {
   if (!ready())
     return;
 
-  Category category = GetCategoryFromUniqueID(suggestion_id);
-  std::string snippet_id = GetWithinCategoryIDFromUniqueID(suggestion_id);
+  DCHECK(base::ContainsKey(categories_, suggestion_id.category()));
 
-  DCHECK(categories_.find(category) != categories_.end());
-
-  CategoryContent* content = &categories_[category];
-  auto it =
-      std::find_if(content->snippets.begin(), content->snippets.end(),
-                   [&snippet_id](const std::unique_ptr<NTPSnippet>& snippet) {
-                     return snippet->id() == snippet_id;
-                   });
+  CategoryContent* content = &categories_[suggestion_id.category()];
+  auto it = std::find_if(
+      content->snippets.begin(), content->snippets.end(),
+      [&suggestion_id](const std::unique_ptr<NTPSnippet>& snippet) {
+        return snippet->id() == suggestion_id.id_within_category();
+      });
   if (it == content->snippets.end())
     return;
 
   (*it)->set_dismissed(true);
 
   database_->SaveSnippet(**it);
-  database_->DeleteImage(snippet_id);
+  database_->DeleteImage(suggestion_id.id_within_category());
 
   content->dismissed.push_back(std::move(*it));
   content->snippets.erase(it);
 }
 
 void NTPSnippetsService::FetchSuggestionImage(
-    const std::string& suggestion_id,
+    const ContentSuggestion::ID& suggestion_id,
     const ImageFetchedCallback& callback) {
-  std::string snippet_id = GetWithinCategoryIDFromUniqueID(suggestion_id);
   database_->LoadImage(
-      snippet_id,
+      suggestion_id.id_within_category(),
       base::Bind(&NTPSnippetsService::OnSnippetImageFetchedFromDatabase,
                  base::Unretained(this), callback, suggestion_id));
 }
@@ -400,7 +398,7 @@
   for (const std::unique_ptr<NTPSnippet>& snippet : content.dismissed) {
     if (!snippet->is_complete())
       continue;
-    ContentSuggestion suggestion(MakeUniqueID(category, snippet->id()),
+    ContentSuggestion suggestion(category, snippet->id(),
                                  snippet->best_source().url);
     suggestion.set_amp_url(snippet->best_source().amp_url);
     suggestion.set_title(base::UTF8ToUTF16(snippet->title()));
@@ -451,49 +449,38 @@
 // Private methods
 
 GURL NTPSnippetsService::FindSnippetImageUrl(
-    Category category,
-    const std::string& snippet_id) const {
-  DCHECK(categories_.find(category) != categories_.end());
+    const ContentSuggestion::ID& suggestion_id) const {
+  DCHECK(categories_.find(suggestion_id.category()) != categories_.end());
 
-  const CategoryContent& content = categories_.at(category);
-  // Search for the snippet in current and archived snippets.
-  auto it =
-      std::find_if(content.snippets.begin(), content.snippets.end(),
-                   [&snippet_id](const std::unique_ptr<NTPSnippet>& snippet) {
-                     return snippet->id() == snippet_id;
-                   });
-  if (it != content.snippets.end())
-    return (*it)->salient_image_url();
-
-  it = std::find_if(content.archived.begin(), content.archived.end(),
-                    [&snippet_id](const std::unique_ptr<NTPSnippet>& snippet) {
-                      return snippet->id() == snippet_id;
-                    });
-  if (it != content.archived.end())
-    return (*it)->salient_image_url();
-
-  return GURL();
+  const CategoryContent& content = categories_.at(suggestion_id.category());
+  const NTPSnippet* snippet =
+      content.FindSnippet(suggestion_id.id_within_category());
+  if (!snippet)
+    return GURL();
+  return snippet->salient_image_url();
 }
 
 // image_fetcher::ImageFetcherDelegate implementation.
-void NTPSnippetsService::OnImageDataFetched(const std::string& suggestion_id,
-                                            const std::string& image_data) {
+void NTPSnippetsService::OnImageDataFetched(
+    const std::string& id_within_category,
+    const std::string& image_data) {
   if (image_data.empty())
     return;
 
-  Category category = GetCategoryFromUniqueID(suggestion_id);
-  std::string snippet_id = GetWithinCategoryIDFromUniqueID(suggestion_id);
-
-  if (categories_.find(category) == categories_.end())
-    return;
-
   // Only save the image if the corresponding snippet still exists.
-  if (FindSnippetImageUrl(category, snippet_id).is_empty())
+  bool found = false;
+  for (const std::pair<const Category, CategoryContent>& entry : categories_) {
+    if (entry.second.FindSnippet(id_within_category)) {
+      found = true;
+      break;
+    }
+  }
+  if (!found)
     return;
 
   // Only cache the data in the DB, the actual serving is done in the callback
   // provided to |image_fetcher_| (OnSnippetImageDecodedFromNetwork()).
-  database_->SaveImage(snippet_id, image_data);
+  database_->SaveImage(id_within_category, image_data);
 }
 
 void NTPSnippetsService::OnDatabaseLoaded(NTPSnippet::PtrVector snippets) {
@@ -819,7 +806,7 @@
 
 void NTPSnippetsService::OnSnippetImageFetchedFromDatabase(
     const ImageFetchedCallback& callback,
-    const std::string& suggestion_id,
+    const ContentSuggestion::ID& suggestion_id,
     std::string data) {
   // |image_decoder_| is null in tests.
   if (image_decoder_ && !data.empty()) {
@@ -835,7 +822,7 @@
 
 void NTPSnippetsService::OnSnippetImageDecodedFromDatabase(
     const ImageFetchedCallback& callback,
-    const std::string& suggestion_id,
+    const ContentSuggestion::ID& suggestion_id,
     const gfx::Image& image) {
   if (!image.IsEmpty()) {
     callback.Run(image);
@@ -843,24 +830,21 @@
   }
 
   // If decoding the image failed, delete the DB entry.
-  std::string snippet_id = GetWithinCategoryIDFromUniqueID(suggestion_id);
-  database_->DeleteImage(snippet_id);
+  database_->DeleteImage(suggestion_id.id_within_category());
 
   FetchSnippetImageFromNetwork(suggestion_id, callback);
 }
 
 void NTPSnippetsService::FetchSnippetImageFromNetwork(
-    const std::string& suggestion_id,
+    const ContentSuggestion::ID& suggestion_id,
     const ImageFetchedCallback& callback) {
-  Category category = GetCategoryFromUniqueID(suggestion_id);
-  std::string snippet_id = GetWithinCategoryIDFromUniqueID(suggestion_id);
-
-  if (categories_.find(category) == categories_.end()) {
-    OnSnippetImageDecodedFromNetwork(callback, suggestion_id, gfx::Image());
+  if (categories_.find(suggestion_id.category()) == categories_.end()) {
+    OnSnippetImageDecodedFromNetwork(
+        callback, suggestion_id.id_within_category(), gfx::Image());
     return;
   }
 
-  GURL image_url = FindSnippetImageUrl(category, snippet_id);
+  GURL image_url = FindSnippetImageUrl(suggestion_id);
 
   if (image_url.is_empty() ||
       !thumbnail_requests_throttler_.DemandQuotaForRequest(
@@ -868,19 +852,20 @@
     // Return an empty image. Directly, this is never synchronous with the
     // original FetchSuggestionImage() call - an asynchronous database query has
     // happened in the meantime.
-    OnSnippetImageDecodedFromNetwork(callback, suggestion_id, gfx::Image());
+    OnSnippetImageDecodedFromNetwork(
+        callback, suggestion_id.id_within_category(), gfx::Image());
     return;
   }
 
   image_fetcher_->StartOrQueueNetworkRequest(
-      suggestion_id, image_url,
+      suggestion_id.id_within_category(), image_url,
       base::Bind(&NTPSnippetsService::OnSnippetImageDecodedFromNetwork,
                  base::Unretained(this), callback));
 }
 
 void NTPSnippetsService::OnSnippetImageDecodedFromNetwork(
     const ImageFetchedCallback& callback,
-    const std::string& suggestion_id,
+    const std::string& id_within_category,
     const gfx::Image& image) {
   callback.Run(image);
 }
@@ -1026,7 +1011,7 @@
       // incomplete ones we kept.
       if (!snippet->is_complete())
         continue;
-      ContentSuggestion suggestion(MakeUniqueID(category, snippet->id()),
+      ContentSuggestion suggestion(category, snippet->id(),
                                    snippet->best_source().url);
       suggestion.set_amp_url(snippet->best_source().amp_url);
       suggestion.set_title(base::UTF8ToUTF16(snippet->title()));
@@ -1064,6 +1049,28 @@
   }
 }
 
+const NTPSnippet* NTPSnippetsService::CategoryContent::FindSnippet(
+    const std::string& id_within_category) const {
+  // Search for the snippet in current and archived snippets.
+  auto it = std::find_if(
+      snippets.begin(), snippets.end(),
+      [&id_within_category](const std::unique_ptr<NTPSnippet>& snippet) {
+        return snippet->id() == id_within_category;
+      });
+  if (it != snippets.end())
+    return it->get();
+
+  it = std::find_if(
+      archived.begin(), archived.end(),
+      [&id_within_category](const std::unique_ptr<NTPSnippet>& snippet) {
+        return snippet->id() == id_within_category;
+      });
+  if (it != archived.end())
+    return it->get();
+
+  return nullptr;
+}
+
 NTPSnippetsService::CategoryContent::CategoryContent() = default;
 NTPSnippetsService::CategoryContent::CategoryContent(CategoryContent&&) =
     default;
diff --git a/components/ntp_snippets/ntp_snippets_service.h b/components/ntp_snippets/remote/ntp_snippets_service.h
similarity index 89%
rename from components/ntp_snippets/ntp_snippets_service.h
rename to components/ntp_snippets/remote/ntp_snippets_service.h
index 1aac5ec6..43ed996 100644
--- a/components/ntp_snippets/ntp_snippets_service.h
+++ b/components/ntp_snippets/remote/ntp_snippets_service.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_SERVICE_H_
-#define COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_SERVICE_H_
+#ifndef COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_SERVICE_H_
+#define COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_SERVICE_H_
 
 #include <cstddef>
 #include <map>
@@ -21,11 +21,11 @@
 #include "components/ntp_snippets/category_status.h"
 #include "components/ntp_snippets/content_suggestion.h"
 #include "components/ntp_snippets/content_suggestions_provider.h"
-#include "components/ntp_snippets/ntp_snippet.h"
-#include "components/ntp_snippets/ntp_snippets_fetcher.h"
-#include "components/ntp_snippets/ntp_snippets_scheduler.h"
-#include "components/ntp_snippets/ntp_snippets_status_service.h"
-#include "components/ntp_snippets/request_throttler.h"
+#include "components/ntp_snippets/remote/ntp_snippet.h"
+#include "components/ntp_snippets/remote/ntp_snippets_fetcher.h"
+#include "components/ntp_snippets/remote/ntp_snippets_scheduler.h"
+#include "components/ntp_snippets/remote/ntp_snippets_status_service.h"
+#include "components/ntp_snippets/remote/request_throttler.h"
 #include "components/suggestions/suggestions_service.h"
 
 class PrefRegistrySimple;
@@ -118,8 +118,8 @@
   // ContentSuggestionsProvider implementation
   CategoryStatus GetCategoryStatus(Category category) override;
   CategoryInfo GetCategoryInfo(Category category) override;
-  void DismissSuggestion(const std::string& suggestion_id) override;
-  void FetchSuggestionImage(const std::string& suggestion_id,
+  void DismissSuggestion(const ContentSuggestion::ID& suggestion_id) override;
+  void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
                             const ImageFetchedCallback& callback) override;
   void ClearHistory(
       base::Time begin,
@@ -199,12 +199,12 @@
   };
 
   // Returns the URL of the image of a snippet if it is among the current or
-  // among the archived snippets in |category|. Returns an empty URL, otherwise.
-  GURL FindSnippetImageUrl(Category category,
-                           const std::string& snippet_id) const;
+  // among the archived snippets in the matching category. Returns an empty URL
+  // otherwise.
+  GURL FindSnippetImageUrl(const ContentSuggestion::ID& suggestion_id) const;
 
   // image_fetcher::ImageFetcherDelegate implementation.
-  void OnImageDataFetched(const std::string& suggestion_id,
+  void OnImageDataFetched(const std::string& id_within_category,
                           const std::string& image_data) override;
 
   // Callbacks for the NTPSnippetsDatabase.
@@ -242,19 +242,21 @@
   // observers. This is done after construction, once the database is loaded.
   void FinishInitialization();
 
-  void OnSnippetImageFetchedFromDatabase(const ImageFetchedCallback& callback,
-                                         const std::string& suggestion_id,
-                                         std::string data);
+  void OnSnippetImageFetchedFromDatabase(
+      const ImageFetchedCallback& callback,
+      const ContentSuggestion::ID& suggestion_id,
+      std::string data);
 
-  void OnSnippetImageDecodedFromDatabase(const ImageFetchedCallback& callback,
-                                         const std::string& suggestion_id,
-                                         const gfx::Image& image);
+  void OnSnippetImageDecodedFromDatabase(
+      const ImageFetchedCallback& callback,
+      const ContentSuggestion::ID& suggestion_id,
+      const gfx::Image& image);
 
-  void FetchSnippetImageFromNetwork(const std::string& suggestion_id,
+  void FetchSnippetImageFromNetwork(const ContentSuggestion::ID& suggestion_id,
                                     const ImageFetchedCallback& callback);
 
   void OnSnippetImageDecodedFromNetwork(const ImageFetchedCallback& callback,
-                                        const std::string& suggestion_id,
+                                        const std::string& id_within_category,
                                         const gfx::Image& image);
 
   // Triggers a state transition depending on the provided reason to be
@@ -320,6 +322,10 @@
     // expire so we won't re-add them to |snippets| on the next fetch.
     NTPSnippet::PtrVector dismissed;
 
+    // Returns a non-dismissed snippet with the given |id_within_category|, or
+    // null if none exist.
+    const NTPSnippet* FindSnippet(const std::string& id_within_category) const;
+
     CategoryContent();
     CategoryContent(CategoryContent&&);
     ~CategoryContent();
@@ -369,4 +375,4 @@
 
 }  // namespace ntp_snippets
 
-#endif  // COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_SERVICE_H_
+#endif  // COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_SERVICE_H_
diff --git a/components/ntp_snippets/ntp_snippets_service_unittest.cc b/components/ntp_snippets/remote/ntp_snippets_service_unittest.cc
similarity index 93%
rename from components/ntp_snippets/ntp_snippets_service_unittest.cc
rename to components/ntp_snippets/remote/ntp_snippets_service_unittest.cc
index d9708da..6c263b1 100644
--- a/components/ntp_snippets/ntp_snippets_service_unittest.cc
+++ b/components/ntp_snippets/remote/ntp_snippets_service_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 "components/ntp_snippets/ntp_snippets_service.h"
+#include "components/ntp_snippets/remote/ntp_snippets_service.h"
 
 #include <memory>
 #include <utility>
@@ -26,12 +26,12 @@
 #include "components/image_fetcher/image_fetcher.h"
 #include "components/image_fetcher/image_fetcher_delegate.h"
 #include "components/ntp_snippets/category_factory.h"
-#include "components/ntp_snippets/ntp_snippet.h"
 #include "components/ntp_snippets/ntp_snippets_constants.h"
-#include "components/ntp_snippets/ntp_snippets_database.h"
-#include "components/ntp_snippets/ntp_snippets_fetcher.h"
-#include "components/ntp_snippets/ntp_snippets_scheduler.h"
-#include "components/ntp_snippets/ntp_snippets_test_utils.h"
+#include "components/ntp_snippets/remote/ntp_snippet.h"
+#include "components/ntp_snippets/remote/ntp_snippets_database.h"
+#include "components/ntp_snippets/remote/ntp_snippets_fetcher.h"
+#include "components/ntp_snippets/remote/ntp_snippets_scheduler.h"
+#include "components/ntp_snippets/remote/ntp_snippets_test_utils.h"
 #include "components/ntp_snippets/switches.h"
 #include "components/prefs/testing_pref_service.h"
 #include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
@@ -299,9 +299,9 @@
     statuses_[category] = new_status;
   }
 
-  void OnSuggestionInvalidated(ContentSuggestionsProvider* provider,
-                               Category category,
-                               const std::string& suggestion_id) override {}
+  void OnSuggestionInvalidated(
+      ContentSuggestionsProvider* provider,
+      const ContentSuggestion::ID& suggestion_id) override {}
 
   const std::map<Category, CategoryStatus, Category::CompareByID>& statuses()
       const {
@@ -367,9 +367,10 @@
     base::RunLoop().RunUntilIdle();
   }
 
-  std::unique_ptr<NTPSnippetsService> MakeSnippetsService() {
+  std::unique_ptr<NTPSnippetsService> MakeSnippetsService(
+      bool set_empty_response = true) {
     auto service = MakeSnippetsServiceWithoutInitialization();
-    WaitForSnippetsServiceInitialization();
+    WaitForSnippetsServiceInitialization(set_empty_response);
     return service;
   }
 
@@ -405,13 +406,14 @@
                                                    utils_.pref_service()));
   }
 
-  void WaitForSnippetsServiceInitialization() {
+  void WaitForSnippetsServiceInitialization(bool set_empty_response = true) {
     EXPECT_TRUE(observer_);
     EXPECT_FALSE(observer_->Loaded());
 
     // Add an initial fetch response, as the service tries to fetch when there
     // is nothing in the DB.
-    SetUpFetchResponse(GetTestJson(std::vector<std::string>()));
+    if (set_empty_response)
+      SetUpFetchResponse(GetTestJson(std::vector<std::string>()));
 
     base::RunLoop().RunUntilIdle();
     observer_->WaitForLoad();
@@ -423,18 +425,16 @@
     *service = MakeSnippetsService();
   }
 
-  std::string MakeArticleID(const NTPSnippetsService& service,
-                            const std::string& within_category_id) {
-    return service.MakeUniqueID(articles_category(), within_category_id);
+  ContentSuggestion::ID MakeArticleID(const std::string& id_within_category) {
+    return ContentSuggestion::ID(articles_category(), id_within_category);
   }
 
   Category articles_category() {
     return category_factory_.FromKnownCategory(KnownCategories::ARTICLES);
   }
 
-  std::string MakeOtherID(const NTPSnippetsService& service,
-                          const std::string& within_category_id) {
-    return service.MakeUniqueID(other_category(), within_category_id);
+  ContentSuggestion::ID MakeOtherID(const std::string& id_within_category) {
+    return ContentSuggestion::ID(other_category(), id_within_category);
   }
 
   Category other_category() { return category_factory_.FromRemoteCategory(2); }
@@ -486,25 +486,23 @@
   auto service = MakeSnippetsService();
 
   // When we have no snippets are all, loading the service initiates a fetch.
-  base::RunLoop().RunUntilIdle();
   EXPECT_EQ("OK", service->snippets_fetcher()->last_status());
 }
 
 TEST_F(NTPSnippetsServiceTest, DontRescheduleOnStart) {
   EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(2);
   EXPECT_CALL(mock_scheduler(), Unschedule()).Times(0);
-  auto service = MakeSnippetsService();
-  base::RunLoop().RunUntilIdle();
+  SetUpFetchResponse(GetTestJson({GetSnippet()}));
+  auto service = MakeSnippetsService(/*set_empty_response=*/false);
 
-  // When recreating the service, we should not get a single |Schedule| call:
+  // When recreating the service, we should not get any |Schedule| calls:
   // The tasks are already scheduled with the correct intervals, so nothing on
-  // initialization, but the service still has no data, so one |Schedule|
-  // happens after the automatic fetch.
+  // initialization, and the service has data from the DB, so no automatic fetch
+  // should happen.
   Mock::VerifyAndClearExpectations(&mock_scheduler());
-  EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(1);
+  EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(0);
   EXPECT_CALL(mock_scheduler(), Unschedule()).Times(0);
   ResetSnippetsService(&service);
-  base::RunLoop().RunUntilIdle();
 }
 
 TEST_F(NTPSnippetsServiceTest, RescheduleAfterSuccessfulFetch) {
@@ -513,7 +511,6 @@
   // have any data yet) fetch finishes.
   EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(2);
   auto service = MakeSnippetsService();
-  base::RunLoop().RunUntilIdle();
 
   // A successful fetch should trigger another |Schedule|.
   EXPECT_CALL(mock_scheduler(), Schedule(_, _));
@@ -526,7 +523,6 @@
   // have any data yet) fetch finishes.
   EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(2);
   auto service = MakeSnippetsService();
-  base::RunLoop().RunUntilIdle();
 
   // A failed fetch should NOT trigger another |Schedule|.
   EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(0);
@@ -574,7 +570,6 @@
   }
   auto service = MakeSnippetsService();
   ASSERT_TRUE(service->ready());
-  base::RunLoop().RunUntilIdle();
 
   service->OnDisabledReasonChanged(DisabledReason::EXPLICITLY_DISABLED);
   ASSERT_FALSE(service->ready());
@@ -590,7 +585,6 @@
   EXPECT_CALL(mock_scheduler(), Unschedule()).Times(0);
 
   auto service = MakeSnippetsService();
-  base::RunLoop().RunUntilIdle();
 
   service.reset();
   base::RunLoop().RunUntilIdle();
@@ -610,7 +604,7 @@
   const ContentSuggestion& suggestion =
       observer().SuggestionsForCategory(articles_category()).front();
 
-  EXPECT_EQ(MakeArticleID(*service, kSnippetUrl), suggestion.id());
+  EXPECT_EQ(MakeArticleID(kSnippetUrl), suggestion.id());
   EXPECT_EQ(kSnippetTitle, base::UTF16ToUTF8(suggestion.title()));
   EXPECT_EQ(kSnippetText, base::UTF16ToUTF8(suggestion.snippet_text()));
   EXPECT_EQ(GetDefaultCreationTime(), suggestion.publish_date());
@@ -644,8 +638,7 @@
   {
     const ContentSuggestion& suggestion =
         observer().SuggestionsForCategory(articles_category()).front();
-    EXPECT_EQ(MakeArticleID(*service, std::string(kSnippetUrl) + "/0"),
-              suggestion.id());
+    EXPECT_EQ(MakeArticleID(std::string(kSnippetUrl) + "/0"), suggestion.id());
     EXPECT_EQ(kSnippetTitle, base::UTF16ToUTF8(suggestion.title()));
     EXPECT_EQ(kSnippetText, base::UTF16ToUTF8(suggestion.snippet_text()));
     EXPECT_EQ(GetDefaultCreationTime(), suggestion.publish_date());
@@ -657,8 +650,7 @@
   {
     const ContentSuggestion& suggestion =
         observer().SuggestionsForCategory(other_category()).front();
-    EXPECT_EQ(MakeOtherID(*service, std::string(kSnippetUrl) + "/1"),
-              suggestion.id());
+    EXPECT_EQ(MakeOtherID(std::string(kSnippetUrl) + "/1"), suggestion.id());
     EXPECT_EQ(kSnippetTitle, base::UTF16ToUTF8(suggestion.title()));
     EXPECT_EQ(kSnippetText, base::UTF16ToUTF8(suggestion.snippet_text()));
     EXPECT_EQ(GetDefaultCreationTime(), suggestion.publish_date());
@@ -751,11 +743,11 @@
   ASSERT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1));
 
   // Dismissing a non-existent snippet shouldn't do anything.
-  service->DismissSuggestion(MakeArticleID(*service, "http://othersite.com"));
+  service->DismissSuggestion(MakeArticleID("http://othersite.com"));
   EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1));
 
   // Dismiss the snippet.
-  service->DismissSuggestion(MakeArticleID(*service, kSnippetUrl));
+  service->DismissSuggestion(MakeArticleID(kSnippetUrl));
   EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty());
 
   // Make sure that fetching the same snippet again does not re-add it.
@@ -779,7 +771,7 @@
 
   LoadFromJSONString(service.get(), GetTestJson({GetSnippet()}));
 
-  service->DismissSuggestion(MakeArticleID(*service, kSnippetUrl));
+  service->DismissSuggestion(MakeArticleID(kSnippetUrl));
 
   service->GetDismissedSuggestionsForDebugging(
       articles_category(),
@@ -788,8 +780,7 @@
              std::vector<ContentSuggestion> dismissed_suggestions) {
             EXPECT_EQ(1u, dismissed_suggestions.size());
             for (auto& suggestion : dismissed_suggestions) {
-              EXPECT_EQ(test->MakeArticleID(*service, kSnippetUrl),
-                        suggestion.id());
+              EXPECT_EQ(test->MakeArticleID(kSnippetUrl), suggestion.id());
             }
           },
           service.get(), this));
@@ -829,7 +820,7 @@
   LoadFromJSONString(service.get(), json_str1);
   // Dismiss the suggestion
   service->DismissSuggestion(
-      service->MakeUniqueID(service->articles_category_, kSnippetUrl));
+      ContentSuggestion::ID(articles_category(), kSnippetUrl));
 
   // Load a different snippet - this will clear the expired dismissed ones.
   std::string json_str2(GetTestJson({GetSnippetWithUrl(kSnippetUrl2)}));
@@ -928,7 +919,7 @@
 
   // Dismissing a snippet should decrease the list size. This will only be
   // logged after the next fetch.
-  service->DismissSuggestion(MakeArticleID(*service, kSnippetUrl));
+  service->DismissSuggestion(MakeArticleID(kSnippetUrl));
   LoadFromJSONString(service.get(), GetTestJson({GetSnippet()}));
   EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticles"),
               ElementsAre(base::Bucket(/*min=*/0, /*count=*/3),
@@ -982,7 +973,7 @@
                          publishers[0], amp_urls[0])}));
   ASSERT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1));
   // Dismiss the snippet via the mashable source corpus ID.
-  service->DismissSuggestion(MakeArticleID(*service, source_urls[0]));
+  service->DismissSuggestion(MakeArticleID(source_urls[0]));
   EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty());
 
   // The same article from the AOL domain should now be detected as dismissed.
@@ -1035,7 +1026,7 @@
   }
 
   service->FetchSuggestionImage(
-      MakeArticleID(*service, kSnippetUrl),
+      MakeArticleID(kSnippetUrl),
       base::Bind(&MockFunction<void(const gfx::Image&)>::Call,
                  base::Unretained(&image_fetched)));
   base::RunLoop().RunUntilIdle();
@@ -1052,7 +1043,7 @@
   EXPECT_CALL(image_fetched, Call(_)).WillOnce(SaveArg<0>(&image));
 
   service->FetchSuggestionImage(
-      MakeArticleID(*service, kSnippetUrl2),
+      MakeArticleID(kSnippetUrl2),
       base::Bind(&MockFunction<void(const gfx::Image&)>::Call,
                  base::Unretained(&image_fetched)));
 
@@ -1069,7 +1060,7 @@
   LoadFromJSONString(service.get(), json_str);
   ASSERT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(2));
 
-  service->DismissSuggestion(MakeArticleID(*service, "http://url1.com"));
+  service->DismissSuggestion(MakeArticleID("http://url1.com"));
   ASSERT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1));
   ASSERT_THAT(service->GetDismissedSnippetsForTesting(articles_category()),
               SizeIs(1));
diff --git a/components/ntp_snippets/ntp_snippets_status_service.cc b/components/ntp_snippets/remote/ntp_snippets_status_service.cc
similarity index 97%
rename from components/ntp_snippets/ntp_snippets_status_service.cc
rename to components/ntp_snippets/remote/ntp_snippets_status_service.cc
index 8f10283..a15bfdf 100644
--- a/components/ntp_snippets/ntp_snippets_status_service.cc
+++ b/components/ntp_snippets/remote/ntp_snippets_status_service.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 "components/ntp_snippets/ntp_snippets_status_service.h"
+#include "components/ntp_snippets/remote/ntp_snippets_status_service.h"
 
 #include <string>
 
diff --git a/components/ntp_snippets/ntp_snippets_status_service.h b/components/ntp_snippets/remote/ntp_snippets_status_service.h
similarity index 91%
rename from components/ntp_snippets/ntp_snippets_status_service.h
rename to components/ntp_snippets/remote/ntp_snippets_status_service.h
index bd52c136..c75bcf6 100644
--- a/components/ntp_snippets/ntp_snippets_status_service.h
+++ b/components/ntp_snippets/remote/ntp_snippets_status_service.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_STATUS_SERVICE_H_
-#define COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_STATUS_SERVICE_H_
+#ifndef COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_STATUS_SERVICE_H_
+#define COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_STATUS_SERVICE_H_
 
 #include "base/callback.h"
 #include "base/gtest_prod_util.h"
@@ -75,4 +75,4 @@
 
 }  // namespace ntp_snippets
 
-#endif  // COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_STATUS_SERVICE_H_
+#endif  // COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_STATUS_SERVICE_H_
diff --git a/components/ntp_snippets/ntp_snippets_status_service_unittest.cc b/components/ntp_snippets/remote/ntp_snippets_status_service_unittest.cc
similarity index 93%
rename from components/ntp_snippets/ntp_snippets_status_service_unittest.cc
rename to components/ntp_snippets/remote/ntp_snippets_status_service_unittest.cc
index 2be8659..3a555c6 100644
--- a/components/ntp_snippets/ntp_snippets_status_service_unittest.cc
+++ b/components/ntp_snippets/remote/ntp_snippets_status_service_unittest.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/ntp_snippets/ntp_snippets_status_service.h"
+#include "components/ntp_snippets/remote/ntp_snippets_status_service.h"
 
 #include <memory>
 
-#include "components/ntp_snippets/ntp_snippets_test_utils.h"
 #include "components/ntp_snippets/pref_names.h"
+#include "components/ntp_snippets/remote/ntp_snippets_test_utils.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/testing_pref_service.h"
 #include "components/signin/core/browser/account_tracker_service.h"
diff --git a/components/ntp_snippets/ntp_snippets_test_utils.cc b/components/ntp_snippets/remote/ntp_snippets_test_utils.cc
similarity index 96%
rename from components/ntp_snippets/ntp_snippets_test_utils.cc
rename to components/ntp_snippets/remote/ntp_snippets_test_utils.cc
index 2d770284..cdcb450 100644
--- a/components/ntp_snippets/ntp_snippets_test_utils.cc
+++ b/components/ntp_snippets/remote/ntp_snippets_test_utils.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 "components/ntp_snippets/ntp_snippets_test_utils.h"
+#include "components/ntp_snippets/remote/ntp_snippets_test_utils.h"
 
 #include <memory>
 
diff --git a/components/ntp_snippets/ntp_snippets_test_utils.h b/components/ntp_snippets/remote/ntp_snippets_test_utils.h
similarity index 89%
rename from components/ntp_snippets/ntp_snippets_test_utils.h
rename to components/ntp_snippets/remote/ntp_snippets_test_utils.h
index 272b692e3..511cbac 100644
--- a/components/ntp_snippets/ntp_snippets_test_utils.h
+++ b/components/ntp_snippets/remote/ntp_snippets_test_utils.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_TEST_UTILS_H_
-#define COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_TEST_UTILS_H_
+#ifndef COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_TEST_UTILS_H_
+#define COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_TEST_UTILS_H_
 
 #include <memory>
 
@@ -63,4 +63,4 @@
 }  // namespace test
 }  // namespace ntp_snippets
 
-#endif  // COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_TEST_UTILS_H_
+#endif  // COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_TEST_UTILS_H_
diff --git a/components/ntp_snippets/proto/BUILD.gn b/components/ntp_snippets/remote/proto/BUILD.gn
similarity index 100%
rename from components/ntp_snippets/proto/BUILD.gn
rename to components/ntp_snippets/remote/proto/BUILD.gn
diff --git a/components/ntp_snippets/proto/ntp_snippets.proto b/components/ntp_snippets/remote/proto/ntp_snippets.proto
similarity index 100%
rename from components/ntp_snippets/proto/ntp_snippets.proto
rename to components/ntp_snippets/remote/proto/ntp_snippets.proto
diff --git a/components/ntp_snippets/request_throttler.cc b/components/ntp_snippets/remote/request_throttler.cc
similarity index 98%
rename from components/ntp_snippets/request_throttler.cc
rename to components/ntp_snippets/remote/request_throttler.cc
index d921c80..4777f38 100644
--- a/components/ntp_snippets/request_throttler.cc
+++ b/components/ntp_snippets/remote/request_throttler.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 "components/ntp_snippets/request_throttler.h"
+#include "components/ntp_snippets/remote/request_throttler.h"
 
 #include <climits>
 #include <vector>
diff --git a/components/ntp_snippets/request_throttler.h b/components/ntp_snippets/remote/request_throttler.h
similarity index 94%
rename from components/ntp_snippets/request_throttler.h
rename to components/ntp_snippets/remote/request_throttler.h
index ee5065f1..30c2dd55 100644
--- a/components/ntp_snippets/request_throttler.h
+++ b/components/ntp_snippets/remote/request_throttler.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_NTP_SNIPPETS_REQUEST_THROTTLER_H_
-#define COMPONENTS_NTP_SNIPPETS_REQUEST_THROTTLER_H_
+#ifndef COMPONENTS_NTP_SNIPPETS_REMOTE_REQUEST_THROTTLER_H_
+#define COMPONENTS_NTP_SNIPPETS_REMOTE_REQUEST_THROTTLER_H_
 
 #include <string>
 
@@ -93,4 +93,4 @@
 
 }  // namespace ntp_snippets
 
-#endif  // COMPONENTS_NTP_SNIPPETS_REQUEST_THROTTLER_H_
+#endif  // COMPONENTS_NTP_SNIPPETS_REMOTE_REQUEST_THROTTLER_H_
diff --git a/components/ntp_snippets/request_throttler_unittest.cc b/components/ntp_snippets/remote/request_throttler_unittest.cc
similarity index 97%
rename from components/ntp_snippets/request_throttler_unittest.cc
rename to components/ntp_snippets/remote/request_throttler_unittest.cc
index 9c485ec..79eca3b 100644
--- a/components/ntp_snippets/request_throttler_unittest.cc
+++ b/components/ntp_snippets/remote/request_throttler_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 "components/ntp_snippets/request_throttler.h"
+#include "components/ntp_snippets/remote/request_throttler.h"
 
 #include <memory>
 
diff --git a/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.cc b/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.cc
index 0a6aaa7..f913d66 100644
--- a/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.cc
+++ b/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.cc
@@ -125,21 +125,21 @@
 }
 
 void ForeignSessionsSuggestionsProvider::DismissSuggestion(
-    const std::string& suggestion_id) {
+    const ContentSuggestion::ID& suggestion_id) {
   // TODO(skym): Right now this continuously grows, without clearing out old and
   // irrelevant entries. Could either use a timestamp and expire after a
   // threshold, or compare with current foreign tabs and remove anything that
   // isn't actively blockign a foreign_sessions tab.
   std::set<std::string> dismissed_ids = prefs::ReadDismissedIDsFromPrefs(
       *pref_service_, prefs::kDismissedForeignSessionsSuggestions);
-  dismissed_ids.insert(suggestion_id);
+  dismissed_ids.insert(suggestion_id.id_within_category());
   prefs::StoreDismissedIDsToPrefs(pref_service_,
                                   prefs::kDismissedForeignSessionsSuggestions,
                                   dismissed_ids);
 }
 
 void ForeignSessionsSuggestionsProvider::FetchSuggestionImage(
-    const std::string& suggestion_id,
+    const ContentSuggestion::ID& suggestion_id,
     const ImageFetchedCallback& callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(callback, gfx::Image()));
@@ -152,7 +152,7 @@
   std::set<std::string> dismissed_ids = prefs::ReadDismissedIDsFromPrefs(
       *pref_service_, prefs::kDismissedForeignSessionsSuggestions);
   for (auto iter = dismissed_ids.begin(); iter != dismissed_ids.end();) {
-    if (filter.Run(GURL(base::StringPiece(*iter)))) {
+    if (filter.Run(GURL(*iter))) {
       iter = dismissed_ids.erase(iter);
     } else {
       ++iter;
@@ -277,13 +277,12 @@
           continue;
 
         const SerializedNavigationEntry& navigation = tab->navigations.back();
-        const std::string unique_id =
-            MakeUniqueID(provided_category_, navigation.virtual_url().spec());
+        const std::string id = navigation.virtual_url().spec();
         // TODO(skym): Filter out internal pages. Tabs that contain only
         // non-syncable content should never reach the local client, but
         // sometimes the most recent navigation may be internal while one
         // of the previous ones was more valid.
-        if (dismissed_ids.find(unique_id) == dismissed_ids.end() &&
+        if (dismissed_ids.find(id) == dismissed_ids.end() &&
             (base::Time::Now() - tab->timestamp) < max_foreign_tab_age) {
           suggestion_candidates.push_back(
               SessionData{session, tab.get(), &navigation});
@@ -296,9 +295,9 @@
 
 ContentSuggestion ForeignSessionsSuggestionsProvider::BuildSuggestion(
     const SessionData& data) {
-  ContentSuggestion suggestion(
-      MakeUniqueID(provided_category_, data.navigation->virtual_url().spec()),
-      data.navigation->virtual_url());
+  ContentSuggestion suggestion(provided_category_,
+                               data.navigation->virtual_url().spec(),
+                               data.navigation->virtual_url());
   suggestion.set_title(data.navigation->title());
   suggestion.set_publish_date(data.tab->timestamp);
   // TODO(skym): It's unclear if this simple approach is sufficient for
diff --git a/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.h b/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.h
index bb9540b9..4d21a3f 100644
--- a/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.h
+++ b/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.h
@@ -54,8 +54,8 @@
   // ContentSuggestionsProvider implementation.
   CategoryStatus GetCategoryStatus(Category category) override;
   CategoryInfo GetCategoryInfo(Category category) override;
-  void DismissSuggestion(const std::string& suggestion_id) override;
-  void FetchSuggestionImage(const std::string& suggestion_id,
+  void DismissSuggestion(const ContentSuggestion::ID& suggestion_id) override;
+  void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
                             const ImageFetchedCallback& callback) override;
   void ClearHistory(
       base::Time begin,
diff --git a/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider_unittest.cc b/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider_unittest.cc
index 202c0398..e36cf23 100644
--- a/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider_unittest.cc
+++ b/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider_unittest.cc
@@ -149,8 +149,8 @@
   }
 
   void Dismiss(const std::string& url) {
-    // The url of a given suggestion is used as the |within_category_id|.
-    provider_->DismissSuggestion(provider_->MakeUniqueID(category(), url));
+    // The url of a given suggestion is used as the |id_within_category|.
+    provider_->DismissSuggestion(ContentSuggestion::ID(category(), url));
   }
 
   Category category() {
diff --git a/components/os_crypt/os_crypt_linux.cc b/components/os_crypt/os_crypt_linux.cc
index 8650338..496d971 100644
--- a/components/os_crypt/os_crypt_linux.cc
+++ b/components/os_crypt/os_crypt_linux.cc
@@ -72,6 +72,10 @@
   return g_cache.Get().key_storage_cache.get();
 }
 
+// Pointer to a function that creates and returns the |KeyStorage| instance to
+// be used. The function maintains ownership of the pointer.
+KeyStorageLinux* (*g_key_storage_provider)() = &GetKeyStorage;
+
 // Returns a cached string of "peanuts". Is thread-safe.
 std::string* GetPasswordV10() {
   base::AutoLock auto_lock(g_cache.Get().lock);
@@ -87,16 +91,14 @@
   base::AutoLock auto_lock(g_cache.Get().lock);
   if (!g_cache.Get().is_password_v11_cached) {
     g_cache.Get().password_v11_cache.reset(
-        GetKeyStorage() ? new std::string(GetKeyStorage()->GetKey()) : nullptr);
+        g_key_storage_provider()
+            ? new std::string(g_key_storage_provider()->GetKey())
+            : nullptr);
     g_cache.Get().is_password_v11_cached = true;
   }
   return g_cache.Get().password_v11_cache.get();
 }
 
-// Pointer to a function that creates and returns the |KeyStorage| instance to
-// be used. The function maintains ownership of the pointer.
-KeyStorageLinux* (*g_key_storage_provider)() = &GetKeyStorage;
-
 // Pointers to functions that return a password for deriving the encryption key.
 // One function for each supported password version (see Version enum).
 std::string* (*g_get_password[])() = {
@@ -150,12 +152,16 @@
     return true;
   }
 
-  // If a |KeyStorage| is available, use a password backed by the |KeyStorage|.
-  // Otherwise use the hardcoded password.
-  Version version = g_key_storage_provider() ? Version::V11 : Version::V10;
-
+  // If we are able to create a V11 key (i.e. a KeyStorage was available), then
+  // we'll use it. If not, we'll use V10.
+  Version version = Version::V11;
   std::unique_ptr<crypto::SymmetricKey> encryption_key(
       GetEncryptionKey(version));
+  if (!encryption_key) {
+    version = Version::V10;
+    encryption_key = GetEncryptionKey(version);
+  }
+
   if (!encryption_key)
     return false;
 
diff --git a/components/plugins/renderer/webview_plugin.cc b/components/plugins/renderer/webview_plugin.cc
index 506bc21..af1d919 100644
--- a/components/plugins/renderer/webview_plugin.cc
+++ b/components/plugins/renderer/webview_plugin.cc
@@ -62,13 +62,12 @@
   // ApplyWebPreferences before making a WebLocalFrame so that the frame sees a
   // consistent view of our preferences.
   content::RenderView::ApplyWebPreferences(preferences, web_view_);
-  WebLocalFrame* web_local_frame = WebLocalFrame::create(
+  WebLocalFrame* web_frame = WebLocalFrame::create(
       blink::WebTreeScopeType::Document, &web_frame_client_);
-  web_frame_ = web_local_frame;
-  web_view_->setMainFrame(web_frame_);
+  web_view_->setMainFrame(web_frame);
   // TODO(dcheng): The main frame widget currently has a special case.
   // Eliminate this once WebView is no longer a WebWidget.
-  web_frame_widget_ = WebFrameWidget::create(this, web_view_, web_local_frame);
+  WebFrameWidget::create(this, web_view_, web_frame);
 }
 
 // static
@@ -85,9 +84,7 @@
 
 WebViewPlugin::~WebViewPlugin() {
   DCHECK(!weak_factory_.HasWeakPtrs());
-  web_frame_widget_->close();
   web_view_->close();
-  web_frame_->close();
 }
 
 WebPluginContainer* WebViewPlugin::container() const { return container_; }
diff --git a/components/plugins/renderer/webview_plugin.h b/components/plugins/renderer/webview_plugin.h
index f351ff19..086fa6d 100644
--- a/components/plugins/renderer/webview_plugin.h
+++ b/components/plugins/renderer/webview_plugin.h
@@ -154,11 +154,6 @@
   // Owned by us, deleted via |close()|.
   blink::WebView* web_view_;
 
-  // Owned by us, deleted via |close()|.
-  blink::WebFrameWidget* web_frame_widget_;
-
-  // Owned by us, deleted via |close()|.
-  blink::WebFrame* web_frame_;
   gfx::Rect rect_;
 
   blink::WebString old_title_;
diff --git a/components/prefs/json_pref_store.cc b/components/prefs/json_pref_store.cc
index 884829a..e91a4063 100644
--- a/components/prefs/json_pref_store.cc
+++ b/components/prefs/json_pref_store.cc
@@ -173,7 +173,7 @@
       pending_lossy_write_(false),
       read_error_(PREF_READ_ERROR_NONE),
       has_pending_successful_write_reply_(false),
-      has_pending_write_callback_(false),
+      has_pending_write_callbacks_(false),
       write_count_histogram_(writer_.commit_interval(), path_) {
   DCHECK(!path_.empty());
 }
@@ -330,7 +330,7 @@
     bool write_success) {
   DCHECK(CalledOnValidThread());
 
-  has_pending_write_callback_ = false;
+  has_pending_write_callbacks_ = false;
   if (has_pending_successful_write_reply_) {
     has_pending_successful_write_reply_ = false;
     if (write_success) {
@@ -364,31 +364,35 @@
   has_pending_successful_write_reply_ = true;
   on_next_successful_write_reply_ = on_next_successful_write_reply;
 
-  // If there already is a pending callback, avoid erasing it; the reply will
-  // be used as we set |on_next_successful_write_reply_|. Otherwise, setup a
-  // reply with an  empty callback.
-  if (!has_pending_write_callback_) {
-    writer_.RegisterOnNextWriteCallback(base::Bind(
-        &PostWriteCallback,
-        base::Bind(&JsonPrefStore::RunOrScheduleNextSuccessfulWriteCallback,
-                   AsWeakPtr()),
-        base::Callback<void(bool success)>(),
-        base::SequencedTaskRunnerHandle::Get()));
+  // If there are pending callbacks, avoid erasing them; the reply will be used
+  // as we set |on_next_successful_write_reply_|. Otherwise, setup a reply with
+  // an empty callback.
+  if (!has_pending_write_callbacks_) {
+    writer_.RegisterOnNextWriteCallbacks(
+        base::Closure(),
+        base::Bind(
+            &PostWriteCallback,
+            base::Bind(&JsonPrefStore::RunOrScheduleNextSuccessfulWriteCallback,
+                       AsWeakPtr()),
+            base::Callback<void(bool success)>(),
+            base::SequencedTaskRunnerHandle::Get()));
   }
 }
 
-void JsonPrefStore::RegisterOnNextWriteSynchronousCallback(
-    const base::Callback<void(bool success)>& on_next_write_callback) {
+void JsonPrefStore::RegisterOnNextWriteSynchronousCallbacks(
+    OnWriteCallbackPair callbacks) {
   DCHECK(CalledOnValidThread());
-  DCHECK(!has_pending_write_callback_);
+  DCHECK(!has_pending_write_callbacks_);
 
-  has_pending_write_callback_ = true;
+  has_pending_write_callbacks_ = true;
 
-  writer_.RegisterOnNextWriteCallback(base::Bind(
-      &PostWriteCallback,
-      base::Bind(&JsonPrefStore::RunOrScheduleNextSuccessfulWriteCallback,
-                 AsWeakPtr()),
-      on_next_write_callback, base::SequencedTaskRunnerHandle::Get()));
+  writer_.RegisterOnNextWriteCallbacks(
+      callbacks.first,
+      base::Bind(
+          &PostWriteCallback,
+          base::Bind(&JsonPrefStore::RunOrScheduleNextSuccessfulWriteCallback,
+                     AsWeakPtr()),
+          callbacks.second, base::SequencedTaskRunnerHandle::Get()));
 }
 
 void JsonPrefStore::ClearMutableValues() {
@@ -462,8 +466,12 @@
 
   write_count_histogram_.RecordWriteOccured();
 
-  if (pref_filter_)
-    pref_filter_->FilterSerializeData(prefs_.get());
+  if (pref_filter_) {
+    OnWriteCallbackPair callbacks =
+        pref_filter_->FilterSerializeData(prefs_.get());
+    if (!callbacks.first.is_null() || !callbacks.second.is_null())
+      RegisterOnNextWriteSynchronousCallbacks(callbacks);
+  }
 
   JSONStringValueSerializer serializer(output);
   // Not pretty-printing prefs shrinks pref file size by ~30%. To obtain
diff --git a/components/prefs/json_pref_store.h b/components/prefs/json_pref_store.h
index 218b205..5b52360c 100644
--- a/components/prefs/json_pref_store.h
+++ b/components/prefs/json_pref_store.h
@@ -34,6 +34,7 @@
 class JsonPrefStoreLossyWriteTest;
 class SequencedTaskRunner;
 class SequencedWorkerPool;
+class WriteCallbacksObserver;
 class Value;
 FORWARD_DECLARE_TEST(JsonPrefStoreTest, WriteCountHistogramTestBasic);
 FORWARD_DECLARE_TEST(JsonPrefStoreTest, WriteCountHistogramTestSinglePeriod);
@@ -50,6 +51,11 @@
  public:
   struct ReadResult;
 
+  // A pair of callbacks to call before and after the preference file is written
+  // to disk.
+  using OnWriteCallbackPair =
+      std::pair<base::Closure, base::Callback<void(bool success)>>;
+
   // Returns instance of SequencedTaskRunner which guarantees that file
   // operations on the same file will be executed in sequenced order.
   static scoped_refptr<base::SequencedTaskRunner> GetTaskRunnerForFile(
@@ -114,12 +120,6 @@
   void RegisterOnNextSuccessfulWriteReply(
       const base::Closure& on_next_successful_write_reply);
 
-  // Registers |on_next_write_callback| to be called once synchronously, on the
-  // next write event of |writer_|.
-  // |on_next_write_callback| must be thread-safe.
-  void RegisterOnNextWriteSynchronousCallback(
-      const base::Callback<void(bool success)>& on_next_write_callback);
-
   void ClearMutableValues() override;
 
  private:
@@ -181,6 +181,7 @@
                            WriteCountHistogramTestPeriodWithGaps);
   friend class base::JsonPrefStoreCallbackTest;
   friend class base::JsonPrefStoreLossyWriteTest;
+  friend class base::WriteCallbacksObserver;
 
   ~JsonPrefStore() override;
 
@@ -197,6 +198,11 @@
       scoped_refptr<base::SequencedTaskRunner> reply_task_runner,
       bool write_success);
 
+  // Registers the |callbacks| pair to be called once synchronously before and
+  // after, respectively, the next write event of |writer_|.
+  // Both callbacks must be thread-safe.
+  void RegisterOnNextWriteSynchronousCallbacks(OnWriteCallbackPair callbacks);
+
   // This method is called after the JSON file has been read.  It then hands
   // |value| (or an empty dictionary in some read error cases) to the
   // |pref_filter| if one is set. It also gives a callback pointing at
@@ -247,7 +253,7 @@
   std::set<std::string> keys_need_empty_value_;
 
   bool has_pending_successful_write_reply_;
-  bool has_pending_write_callback_;
+  bool has_pending_write_callbacks_;
   base::Closure on_next_successful_write_reply_;
 
   WriteCountHistogram write_count_histogram_;
diff --git a/components/prefs/json_pref_store_unittest.cc b/components/prefs/json_pref_store_unittest.cc
index cf93e7ef..f6ce3ad 100644
--- a/components/prefs/json_pref_store_unittest.cc
+++ b/components/prefs/json_pref_store_unittest.cc
@@ -69,6 +69,7 @@
 class InterceptingPrefFilter : public PrefFilter {
  public:
   InterceptingPrefFilter();
+  InterceptingPrefFilter(OnWriteCallbackPair callback_pair);
   ~InterceptingPrefFilter() override;
 
   // PrefFilter implementation:
@@ -76,8 +77,10 @@
       const PostFilterOnLoadCallback& post_filter_on_load_callback,
       std::unique_ptr<base::DictionaryValue> pref_store_contents) override;
   void FilterUpdate(const std::string& path) override {}
-  void FilterSerializeData(
-      base::DictionaryValue* pref_store_contents) override {}
+  OnWriteCallbackPair FilterSerializeData(
+      base::DictionaryValue* pref_store_contents) override {
+    return on_write_callback_pair_;
+  }
 
   bool has_intercepted_prefs() const { return intercepted_prefs_ != NULL; }
 
@@ -88,11 +91,18 @@
  private:
   PostFilterOnLoadCallback post_filter_on_load_callback_;
   std::unique_ptr<base::DictionaryValue> intercepted_prefs_;
+  OnWriteCallbackPair on_write_callback_pair_;
 
   DISALLOW_COPY_AND_ASSIGN(InterceptingPrefFilter);
 };
 
 InterceptingPrefFilter::InterceptingPrefFilter() {}
+
+InterceptingPrefFilter::InterceptingPrefFilter(
+    OnWriteCallbackPair callback_pair) {
+  on_write_callback_pair_ = callback_pair;
+}
+
 InterceptingPrefFilter::~InterceptingPrefFilter() {}
 
 void InterceptingPrefFilter::FilterOnLoad(
@@ -1006,37 +1016,61 @@
   CALLED_WITH_SUCCESS,
 };
 
-class WriteCallbackObserver {
+class WriteCallbacksObserver {
  public:
-  WriteCallbackObserver() = default;
+  WriteCallbacksObserver() = default;
 
   // Register OnWrite() to be called on the next write of |json_pref_store|.
   void ObserveNextWriteCallback(JsonPrefStore* json_pref_store);
 
-  // Returns true if a write was observed via OnWrite()
-  // and resets the observation state to false regardless.
-  WriteCallbackObservationState GetAndResetObservationState();
+  // Returns whether OnPreWrite() was called, and resets the observation state
+  // to false.
+  bool GetAndResetPreWriteObservationState();
 
-  void OnWrite(bool success) {
-    EXPECT_EQ(NOT_CALLED, observation_state_);
-    observation_state_ = success ? CALLED_WITH_SUCCESS : CALLED_WITH_ERROR;
+  // Returns the |WriteCallbackObservationState| which was observed, then resets
+  // it to |NOT_CALLED|.
+  WriteCallbackObservationState GetAndResetPostWriteObservationState();
+
+  JsonPrefStore::OnWriteCallbackPair GetCallbackPair() {
+    return std::make_pair(
+        base::Bind(&WriteCallbacksObserver::OnPreWrite, base::Unretained(this)),
+        base::Bind(&WriteCallbacksObserver::OnPostWrite,
+                   base::Unretained(this)));
+  }
+
+  void OnPreWrite() {
+    EXPECT_FALSE(pre_write_called_);
+    pre_write_called_ = true;
+  }
+
+  void OnPostWrite(bool success) {
+    EXPECT_EQ(NOT_CALLED, post_write_observation_state_);
+    post_write_observation_state_ =
+        success ? CALLED_WITH_SUCCESS : CALLED_WITH_ERROR;
   }
 
  private:
-  WriteCallbackObservationState observation_state_ = NOT_CALLED;
+  bool pre_write_called_ = false;
+  WriteCallbackObservationState post_write_observation_state_ = NOT_CALLED;
 
-  DISALLOW_COPY_AND_ASSIGN(WriteCallbackObserver);
+  DISALLOW_COPY_AND_ASSIGN(WriteCallbacksObserver);
 };
 
-void WriteCallbackObserver::ObserveNextWriteCallback(JsonPrefStore* writer) {
-  writer->RegisterOnNextWriteSynchronousCallback(
-      base::Bind(&WriteCallbackObserver::OnWrite, base::Unretained(this)));
+void WriteCallbacksObserver::ObserveNextWriteCallback(JsonPrefStore* writer) {
+  writer->RegisterOnNextWriteSynchronousCallbacks(GetCallbackPair());
+}
+
+bool WriteCallbacksObserver::GetAndResetPreWriteObservationState() {
+  bool observation_state = pre_write_called_;
+  pre_write_called_ = false;
+  return observation_state;
 }
 
 WriteCallbackObservationState
-WriteCallbackObserver::GetAndResetObservationState() {
-  WriteCallbackObservationState state = observation_state_;
-  observation_state_ = NOT_CALLED;
+WriteCallbacksObserver::GetAndResetPostWriteObservationState() {
+  WriteCallbackObservationState state = post_write_observation_state_;
+  pre_write_called_ = false;
+  post_write_observation_state_ = NOT_CALLED;
   return state;
 }
 
@@ -1064,13 +1098,13 @@
     JsonPrefStore::PostWriteCallback(
         base::Bind(&JsonPrefStore::RunOrScheduleNextSuccessfulWriteCallback,
                    pref_store->AsWeakPtr()),
-        base::Bind(&WriteCallbackObserver::OnWrite,
+        base::Bind(&WriteCallbacksObserver::OnPostWrite,
                    base::Unretained(&write_callback_observer_)),
         base::SequencedTaskRunnerHandle::Get(), success);
   }
 
   SuccessfulWriteReplyObserver successful_write_reply_observer_;
-  WriteCallbackObserver write_callback_observer_;
+  WriteCallbacksObserver write_callback_observer_;
 
  private:
   base::FilePath test_file_;
@@ -1078,44 +1112,82 @@
   DISALLOW_COPY_AND_ASSIGN(JsonPrefStoreCallbackTest);
 };
 
-TEST_F(JsonPrefStoreCallbackTest, TestPostWriteCallback) {
+TEST_F(JsonPrefStoreCallbackTest, TestSerializeDataCallbacks) {
+  base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
+  ASSERT_LT(0,
+            base::WriteFile(input_file, kReadJson, arraysize(kReadJson) - 1));
+
+  std::unique_ptr<InterceptingPrefFilter> intercepting_pref_filter(
+      new InterceptingPrefFilter(write_callback_observer_.GetCallbackPair()));
+  scoped_refptr<JsonPrefStore> pref_store =
+      new JsonPrefStore(input_file, message_loop_.task_runner(),
+                        std::move(intercepting_pref_filter));
+  ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
+
+  EXPECT_EQ(NOT_CALLED,
+            write_callback_observer_.GetAndResetPostWriteObservationState());
+  pref_store->SetValue("normal", base::MakeUnique<base::StringValue>("normal"),
+                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  file_writer->DoScheduledWrite();
+
+  // The observer should not be invoked right away.
+  EXPECT_FALSE(write_callback_observer_.GetAndResetPreWriteObservationState());
+  EXPECT_EQ(NOT_CALLED,
+            write_callback_observer_.GetAndResetPostWriteObservationState());
+
+  RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(write_callback_observer_.GetAndResetPreWriteObservationState());
+  EXPECT_EQ(CALLED_WITH_SUCCESS,
+            write_callback_observer_.GetAndResetPostWriteObservationState());
+}
+
+TEST_F(JsonPrefStoreCallbackTest, TestPostWriteCallbacks) {
   scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
   ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
 
-  // Test RegisterOnNextWriteSynchronousCallback after
+  // Test RegisterOnNextWriteSynchronousCallbacks after
   // RegisterOnNextSuccessfulWriteReply.
   successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
   write_callback_observer_.ObserveNextWriteCallback(pref_store.get());
   file_writer->WriteNow(MakeUnique<std::string>("foo"));
   RunLoop().RunUntilIdle();
   EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
-  EXPECT_TRUE(write_callback_observer_.GetAndResetObservationState());
+  EXPECT_TRUE(write_callback_observer_.GetAndResetPreWriteObservationState());
+  EXPECT_EQ(CALLED_WITH_SUCCESS,
+            write_callback_observer_.GetAndResetPostWriteObservationState());
 
   // Test RegisterOnNextSuccessfulWriteReply after
-  // RegisterOnNextWriteSynchronousCallback.
+  // RegisterOnNextWriteSynchronousCallbacks.
   successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
   write_callback_observer_.ObserveNextWriteCallback(pref_store.get());
   file_writer->WriteNow(MakeUnique<std::string>("foo"));
   RunLoop().RunUntilIdle();
   EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
-  EXPECT_TRUE(write_callback_observer_.GetAndResetObservationState());
+  EXPECT_TRUE(write_callback_observer_.GetAndResetPreWriteObservationState());
+  EXPECT_EQ(CALLED_WITH_SUCCESS,
+            write_callback_observer_.GetAndResetPostWriteObservationState());
 
   // Test RegisterOnNextSuccessfulWriteReply only.
   successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
   file_writer->WriteNow(MakeUnique<std::string>("foo"));
   RunLoop().RunUntilIdle();
   EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
-  EXPECT_FALSE(write_callback_observer_.GetAndResetObservationState());
+  EXPECT_FALSE(write_callback_observer_.GetAndResetPreWriteObservationState());
+  EXPECT_EQ(NOT_CALLED,
+            write_callback_observer_.GetAndResetPostWriteObservationState());
 
-  // Test RegisterOnNextWriteSynchronousCallback only.
+  // Test RegisterOnNextWriteSynchronousCallbacks only.
   write_callback_observer_.ObserveNextWriteCallback(pref_store.get());
   file_writer->WriteNow(MakeUnique<std::string>("foo"));
   RunLoop().RunUntilIdle();
   EXPECT_FALSE(successful_write_reply_observer_.GetAndResetObservationState());
-  EXPECT_TRUE(write_callback_observer_.GetAndResetObservationState());
+  EXPECT_TRUE(write_callback_observer_.GetAndResetPreWriteObservationState());
+  EXPECT_EQ(CALLED_WITH_SUCCESS,
+            write_callback_observer_.GetAndResetPostWriteObservationState());
 }
 
-TEST_F(JsonPrefStoreCallbackTest, TestPostWriteCallbackWithFakeFailure) {
+TEST_F(JsonPrefStoreCallbackTest, TestPostWriteCallbacksWithFakeFailure) {
   scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
 
   // Confirm that the observers are invoked.
@@ -1124,11 +1196,12 @@
   RunLoop().RunUntilIdle();
   EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
   EXPECT_EQ(CALLED_WITH_SUCCESS,
-            write_callback_observer_.GetAndResetObservationState());
+            write_callback_observer_.GetAndResetPostWriteObservationState());
 
   // Confirm that the observation states were reset.
   EXPECT_FALSE(successful_write_reply_observer_.GetAndResetObservationState());
-  EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState());
+  EXPECT_EQ(NOT_CALLED,
+            write_callback_observer_.GetAndResetPostWriteObservationState());
 
   // Confirm that re-installing the observers works for another write.
   successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
@@ -1136,7 +1209,7 @@
   RunLoop().RunUntilIdle();
   EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
   EXPECT_EQ(CALLED_WITH_SUCCESS,
-            write_callback_observer_.GetAndResetObservationState());
+            write_callback_observer_.GetAndResetPostWriteObservationState());
 
   // Confirm that the successful observer is not invoked by an unsuccessful
   // write, and that the synchronous observer is invoked.
@@ -1145,7 +1218,7 @@
   RunLoop().RunUntilIdle();
   EXPECT_FALSE(successful_write_reply_observer_.GetAndResetObservationState());
   EXPECT_EQ(CALLED_WITH_ERROR,
-            write_callback_observer_.GetAndResetObservationState());
+            write_callback_observer_.GetAndResetPostWriteObservationState());
 
   // Do a real write, and confirm that the successful observer was invoked after
   // being set by |PostWriteCallback| by the last TriggerFakeWriteCallback.
@@ -1153,10 +1226,11 @@
   file_writer->WriteNow(MakeUnique<std::string>("foo"));
   RunLoop().RunUntilIdle();
   EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
-  EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState());
+  EXPECT_EQ(NOT_CALLED,
+            write_callback_observer_.GetAndResetPostWriteObservationState());
 }
 
-TEST_F(JsonPrefStoreCallbackTest, TestPostWriteCallbackDuringProfileDeath) {
+TEST_F(JsonPrefStoreCallbackTest, TestPostWriteCallbacksDuringProfileDeath) {
   // Create a JsonPrefStore and attach observers to it, then delete it by making
   // it go out of scope to simulate profile switch or Chrome shutdown.
   {
@@ -1172,8 +1246,9 @@
   }
   RunLoop().RunUntilIdle();
   EXPECT_FALSE(successful_write_reply_observer_.GetAndResetObservationState());
+  EXPECT_TRUE(write_callback_observer_.GetAndResetPreWriteObservationState());
   EXPECT_EQ(CALLED_WITH_SUCCESS,
-            write_callback_observer_.GetAndResetObservationState());
+            write_callback_observer_.GetAndResetPostWriteObservationState());
 }
 
 }  // namespace base
\ No newline at end of file
diff --git a/components/prefs/pref_filter.h b/components/prefs/pref_filter.h
index 6ca2197..82be63e 100644
--- a/components/prefs/pref_filter.h
+++ b/components/prefs/pref_filter.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 #include <string>
+#include <utility>
 
 #include "base/callback_forward.h"
 #include "components/prefs/base_prefs_export.h"
@@ -20,13 +21,17 @@
 // Currently supported only by JsonPrefStore.
 class COMPONENTS_PREFS_EXPORT PrefFilter {
  public:
+  // A pair of pre-write and post-write callbacks.
+  using OnWriteCallbackPair =
+      std::pair<base::Closure, base::Callback<void(bool success)>>;
+
   // A callback to be invoked when |prefs| have been read (and possibly
   // pre-modified) and are now ready to be handed back to this callback's
   // builder. |schedule_write| indicates whether a write should be immediately
   // scheduled (typically because the |prefs| were pre-modified).
-  typedef base::Callback<void(std::unique_ptr<base::DictionaryValue> prefs,
-                              bool schedule_write)>
-      PostFilterOnLoadCallback;
+  using PostFilterOnLoadCallback =
+      base::Callback<void(std::unique_ptr<base::DictionaryValue> prefs,
+                          bool schedule_write)>;
 
   virtual ~PrefFilter() {}
 
@@ -49,7 +54,10 @@
   // contained in |pref_store_contents| to a string. Modifications to
   // |pref_store_contents| will be persisted to disk and also affect the
   // in-memory state.
-  virtual void FilterSerializeData(
+  // If the returned callbacks are non-null, they will be registered to be
+  // invoked synchronously after the next write (from the I/O TaskRunner so they
+  // must not be bound to thread-unsafe member state).
+  virtual OnWriteCallbackPair FilterSerializeData(
       base::DictionaryValue* pref_store_contents) = 0;
 };
 
diff --git a/components/printing/renderer/print_web_view_helper.cc b/components/printing/renderer/print_web_view_helper.cc
index 7fa310f..7e9df81 100644
--- a/components/printing/renderer/print_web_view_helper.cc
+++ b/components/printing/renderer/print_web_view_helper.cc
@@ -527,11 +527,11 @@
       blink::WebView::create(nullptr, blink::WebPageVisibilityStateVisible);
   web_view->settings()->setJavaScriptEnabled(true);
 
-  blink::WebLocalFrame* frame =
-      blink::WebLocalFrame::create(blink::WebTreeScopeType::Document, NULL);
+  blink::WebFrameClient frame_client;
+  blink::WebLocalFrame* frame = blink::WebLocalFrame::create(
+      blink::WebTreeScopeType::Document, &frame_client);
   web_view->setMainFrame(frame);
-  blink::WebFrameWidget* widget =
-      blink::WebFrameWidget::create(nullptr, web_view, frame);
+  blink::WebFrameWidget::create(nullptr, web_view, frame);
 
   base::StringValue html(ResourceBundle::GetSharedInstance().GetLocalizedString(
       IDR_PRINT_PREVIEW_PAGE));
@@ -561,9 +561,7 @@
   frame->printPage(0, canvas);
   frame->printEnd();
 
-  widget->close();
   web_view->close();
-  frame->close();
 }
 #endif  // defined(ENABLE_PRINT_PREVIEW)
 
@@ -620,14 +618,13 @@
   bool allowsBrokenNullLayerTreeView() const override;
 
   // blink::WebFrameClient:
-  blink::WebFrame* createChildFrame(
+  blink::WebLocalFrame* createChildFrame(
       blink::WebLocalFrame* parent,
       blink::WebTreeScopeType scope,
       const blink::WebString& name,
       const blink::WebString& unique_name,
       blink::WebSandboxFlags sandbox_flags,
       const blink::WebFrameOwnerProperties& frame_owner_properties) override;
-  void frameDetached(blink::WebLocalFrame* frame, DetachType type) override;
 
   void CallOnReady();
   void ResizeForPrinting();
@@ -775,26 +772,18 @@
                             weak_ptr_factory_.GetWeakPtr()));
 }
 
-blink::WebFrame* PrepareFrameAndViewForPrint::createChildFrame(
+blink::WebLocalFrame* PrepareFrameAndViewForPrint::createChildFrame(
     blink::WebLocalFrame* parent,
     blink::WebTreeScopeType scope,
     const blink::WebString& name,
     const blink::WebString& unique_name,
     blink::WebSandboxFlags sandbox_flags,
     const blink::WebFrameOwnerProperties& frame_owner_properties) {
-  blink::WebFrame* frame = blink::WebLocalFrame::create(scope, this);
+  blink::WebLocalFrame* frame = blink::WebLocalFrame::create(scope, this);
   parent->appendChild(frame);
   return frame;
 }
 
-void PrepareFrameAndViewForPrint::frameDetached(blink::WebLocalFrame* frame,
-                                                DetachType type) {
-  DCHECK(type == DetachType::Remove);
-  if (frame->parent())
-    frame->parent()->removeChild(frame);
-  frame->close();
-}
-
 void PrepareFrameAndViewForPrint::CallOnReady() {
   return on_ready_.Run();  // Can delete |this|.
 }
diff --git a/components/safe_browsing_db/database_manager.cc b/components/safe_browsing_db/database_manager.cc
index a882409a..91e4d7b6 100644
--- a/components/safe_browsing_db/database_manager.cc
+++ b/components/safe_browsing_db/database_manager.cc
@@ -67,9 +67,8 @@
   return api_checks_.end();
 }
 
-std::unordered_set<ListIdentifier>
-SafeBrowsingDatabaseManager::GetStoresForFullHashRequests() {
-  return std::unordered_set<ListIdentifier>({GetChromeUrlApiId()});
+StoresToCheck SafeBrowsingDatabaseManager::GetStoresForFullHashRequests() {
+  return StoresToCheck({GetChromeUrlApiId()});
 }
 
 void SafeBrowsingDatabaseManager::OnThreatMetadataResponse(
diff --git a/components/safe_browsing_db/database_manager.h b/components/safe_browsing_db/database_manager.h
index 687c7be..0d24b8bf 100644
--- a/components/safe_browsing_db/database_manager.h
+++ b/components/safe_browsing_db/database_manager.h
@@ -172,7 +172,7 @@
   //
 
   // Returns the lists that this DatabaseManager should get full hashes for.
-  virtual std::unordered_set<ListIdentifier> GetStoresForFullHashRequests();
+  virtual StoresToCheck GetStoresForFullHashRequests();
 
   // Returns the ThreatSource for this implementation.
   virtual ThreatSource GetThreatSource() const = 0;
diff --git a/components/safe_browsing_db/v4_database.cc b/components/safe_browsing_db/v4_database.cc
index 532475b1..efcbe7b 100644
--- a/components/safe_browsing_db/v4_database.cc
+++ b/components/safe_browsing_db/v4_database.cc
@@ -174,11 +174,11 @@
 
 void V4Database::GetStoresMatchingFullHash(
     const FullHash& full_hash,
-    const std::unordered_set<ListIdentifier>& stores_to_look,
+    const StoresToCheck& stores_to_check,
     StoreAndHashPrefixes* matched_store_and_hash_prefixes) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   matched_store_and_hash_prefixes->clear();
-  for (const ListIdentifier& identifier : stores_to_look) {
+  for (const ListIdentifier& identifier : stores_to_check) {
     const auto& store_pair = store_map_->find(identifier);
     DCHECK(store_pair != store_map_->end());
     const std::unique_ptr<V4Store>& store = store_pair->second;
diff --git a/components/safe_browsing_db/v4_database.h b/components/safe_browsing_db/v4_database.h
index 6b41731..bddba598 100644
--- a/components/safe_browsing_db/v4_database.h
+++ b/components/safe_browsing_db/v4_database.h
@@ -109,11 +109,11 @@
   std::unique_ptr<StoreStateMap> GetStoreStateMap();
 
   // Searches for a hash prefix matching the |full_hash| in stores in the
-  // database, filtered by |stores_to_look|, and returns the identifier of the
+  // database, filtered by |stores_to_check|, and returns the identifier of the
   // store along with the matching hash prefix in |matched_hash_prefix_map|.
   virtual void GetStoresMatchingFullHash(
       const FullHash& full_hash,
-      const std::unordered_set<ListIdentifier>& stores_to_look,
+      const StoresToCheck& stores_to_check,
       StoreAndHashPrefixes* matched_store_and_full_hashes);
 
   // Deletes the current database and creates a new one.
diff --git a/components/safe_browsing_db/v4_database_unittest.cc b/components/safe_browsing_db/v4_database_unittest.cc
index e16f182..2ce05ee 100644
--- a/components/safe_browsing_db/v4_database_unittest.cc
+++ b/components/safe_browsing_db/v4_database_unittest.cc
@@ -380,17 +380,16 @@
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(true, created_and_called_back_);
 
-  std::unordered_set<ListIdentifier> stores_to_look(
-      {linux_malware_id_, win_malware_id_});
+  StoresToCheck stores_to_check({linux_malware_id_, win_malware_id_});
   StoreAndHashPrefixes store_and_hash_prefixes;
-  v4_database_->GetStoresMatchingFullHash("anything", stores_to_look,
+  v4_database_->GetStoresMatchingFullHash("anything", stores_to_check,
                                           &store_and_hash_prefixes);
   EXPECT_EQ(2u, store_and_hash_prefixes.size());
-  std::unordered_set<ListIdentifier> stores_found;
+  StoresToCheck stores_found;
   for (const auto& it : store_and_hash_prefixes) {
     stores_found.insert(it.list_id);
   }
-  EXPECT_EQ(stores_to_look, stores_found);
+  EXPECT_EQ(stores_to_check, stores_found);
 }
 
 // Test to ensure the case that no stores match a given full hash.
@@ -407,11 +406,10 @@
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(true, created_and_called_back_);
 
-  std::unordered_set<ListIdentifier> stores_to_look(
-      {linux_malware_id_, win_malware_id_});
   StoreAndHashPrefixes store_and_hash_prefixes;
-  v4_database_->GetStoresMatchingFullHash("anything", stores_to_look,
-                                          &store_and_hash_prefixes);
+  v4_database_->GetStoresMatchingFullHash(
+      "anything", StoresToCheck({linux_malware_id_, win_malware_id_}),
+      &store_and_hash_prefixes);
   EXPECT_TRUE(store_and_hash_prefixes.empty());
 }
 
@@ -435,18 +433,17 @@
       v4_database_->store_map_->at(win_malware_id_).get());
   store->set_hash_prefix_matches(true);
 
-  std::unordered_set<ListIdentifier> stores_to_look(
-      {linux_malware_id_, win_malware_id_});
   StoreAndHashPrefixes store_and_hash_prefixes;
-  v4_database_->GetStoresMatchingFullHash("anything", stores_to_look,
-                                          &store_and_hash_prefixes);
+  v4_database_->GetStoresMatchingFullHash(
+      "anything", StoresToCheck({linux_malware_id_, win_malware_id_}),
+      &store_and_hash_prefixes);
   EXPECT_EQ(1u, store_and_hash_prefixes.size());
   EXPECT_EQ(store_and_hash_prefixes.begin()->list_id, win_malware_id_);
   EXPECT_FALSE(store_and_hash_prefixes.begin()->hash_prefix.empty());
 }
 
 // Test to ensure the case that only some stores are reported to match a given
-// full hash because of stores_to_look.
+// full hash because of StoresToCheck.
 TEST_F(V4DatabaseTest, TestSomeStoresMatchFullHashBecauseOfStoresToMatch) {
   // Setup all stores to match the full hash.
   bool hash_prefix_matches = true;
@@ -461,11 +458,10 @@
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(true, created_and_called_back_);
 
-  std::unordered_set<ListIdentifier> stores_to_look({linux_malware_id_});
-  // Don't add win_malware_id_ to the stores_to_look.
+  // Don't add win_malware_id_ to the StoresToCheck.
   StoreAndHashPrefixes store_and_hash_prefixes;
-  v4_database_->GetStoresMatchingFullHash("anything", stores_to_look,
-                                          &store_and_hash_prefixes);
+  v4_database_->GetStoresMatchingFullHash(
+      "anything", StoresToCheck({linux_malware_id_}), &store_and_hash_prefixes);
   EXPECT_EQ(1u, store_and_hash_prefixes.size());
   EXPECT_EQ(store_and_hash_prefixes.begin()->list_id, linux_malware_id_);
   EXPECT_FALSE(store_and_hash_prefixes.begin()->hash_prefix.empty());
diff --git a/components/safe_browsing_db/v4_get_hash_protocol_manager.cc b/components/safe_browsing_db/v4_get_hash_protocol_manager.cc
index dcd03e7..5994c4f 100644
--- a/components/safe_browsing_db/v4_get_hash_protocol_manager.cc
+++ b/components/safe_browsing_db/v4_get_hash_protocol_manager.cc
@@ -142,10 +142,10 @@
   ~V4GetHashProtocolManagerFactoryImpl() override {}
   std::unique_ptr<V4GetHashProtocolManager> CreateProtocolManager(
       net::URLRequestContextGetter* request_context_getter,
-      const std::unordered_set<ListIdentifier>& stores_to_request,
+      const StoresToCheck& stores_to_check,
       const V4ProtocolConfig& config) override {
     return base::WrapUnique(new V4GetHashProtocolManager(
-        request_context_getter, stores_to_request, config));
+        request_context_getter, stores_to_check, config));
   }
 
  private:
@@ -211,12 +211,12 @@
 // static
 std::unique_ptr<V4GetHashProtocolManager> V4GetHashProtocolManager::Create(
     net::URLRequestContextGetter* request_context_getter,
-    const std::unordered_set<ListIdentifier>& stores_to_request,
+    const StoresToCheck& stores_to_check,
     const V4ProtocolConfig& config) {
   if (!factory_)
     factory_ = new V4GetHashProtocolManagerFactoryImpl();
   return factory_->CreateProtocolManager(request_context_getter,
-                                         stores_to_request, config);
+                                         stores_to_check, config);
 }
 
 // static
@@ -229,7 +229,7 @@
 
 V4GetHashProtocolManager::V4GetHashProtocolManager(
     net::URLRequestContextGetter* request_context_getter,
-    const std::unordered_set<ListIdentifier>& stores_to_request,
+    const StoresToCheck& stores_to_check,
     const V4ProtocolConfig& config)
     : gethash_error_count_(0),
       gethash_back_off_mult_(1),
@@ -238,8 +238,8 @@
       request_context_getter_(request_context_getter),
       url_fetcher_id_(0),
       clock_(new base::DefaultClock()) {
-  DCHECK(!stores_to_request.empty());
-  for (const ListIdentifier& store : stores_to_request) {
+  DCHECK(!stores_to_check.empty());
+  for (const ListIdentifier& store : stores_to_check) {
     platform_types_.insert(store.platform_type());
     threat_entry_types_.insert(store.threat_entry_type());
     threat_types_.insert(store.threat_type());
diff --git a/components/safe_browsing_db/v4_get_hash_protocol_manager.h b/components/safe_browsing_db/v4_get_hash_protocol_manager.h
index 29f49c1..44b05d7 100644
--- a/components/safe_browsing_db/v4_get_hash_protocol_manager.h
+++ b/components/safe_browsing_db/v4_get_hash_protocol_manager.h
@@ -147,7 +147,7 @@
   // Create an instance of the safe browsing v4 protocol manager.
   static std::unique_ptr<V4GetHashProtocolManager> Create(
       net::URLRequestContextGetter* request_context_getter,
-      const std::unordered_set<ListIdentifier>& stores_to_request,
+      const StoresToCheck& stores_to_check,
       const V4ProtocolConfig& config);
 
   // Makes the passed |factory| the factory used to instantiate
@@ -183,12 +183,11 @@
   void OnURLFetchComplete(const net::URLFetcher* source) override;
 
  protected:
-  // Constructs a V4GetHashProtocolManager that issues
-  // network requests using |request_context_getter|.
-  V4GetHashProtocolManager(
-      net::URLRequestContextGetter* request_context_getter,
-      const std::unordered_set<ListIdentifier>& stores_to_request,
-      const V4ProtocolConfig& config);
+  // Constructs a V4GetHashProtocolManager that issues network requests using
+  // |request_context_getter|.
+  V4GetHashProtocolManager(net::URLRequestContextGetter* request_context_getter,
+                           const StoresToCheck& stores_to_check,
+                           const V4ProtocolConfig& config);
 
  private:
   FRIEND_TEST_ALL_PREFIXES(V4GetHashProtocolManagerTest, TestGetHashRequest);
@@ -345,7 +344,7 @@
   virtual ~V4GetHashProtocolManagerFactory() {}
   virtual std::unique_ptr<V4GetHashProtocolManager> CreateProtocolManager(
       net::URLRequestContextGetter* request_context_getter,
-      const std::unordered_set<ListIdentifier>& stores_to_request,
+      const StoresToCheck& stores_to_check,
       const V4ProtocolConfig& config) = 0;
 
  private:
diff --git a/components/safe_browsing_db/v4_get_hash_protocol_manager_unittest.cc b/components/safe_browsing_db/v4_get_hash_protocol_manager_unittest.cc
index c8b0542e..bb89fd9 100644
--- a/components/safe_browsing_db/v4_get_hash_protocol_manager_unittest.cc
+++ b/components/safe_browsing_db/v4_get_hash_protocol_manager_unittest.cc
@@ -80,9 +80,8 @@
     config.client_name = kClient;
     config.version = kAppVer;
     config.key_param = kKeyParam;
-    std::unordered_set<ListIdentifier> stores_to_look(
-        {GetUrlMalwareId(), GetChromeUrlApiId()});
-    return V4GetHashProtocolManager::Create(NULL, stores_to_look, config);
+    StoresToCheck stores_to_check({GetUrlMalwareId(), GetChromeUrlApiId()});
+    return V4GetHashProtocolManager::Create(NULL, stores_to_check, config);
   }
 
   static void SetupFetcherToReturnOKResponse(
diff --git a/components/safe_browsing_db/v4_local_database_manager.cc b/components/safe_browsing_db/v4_local_database_manager.cc
index 6d46cde..9215dc7 100644
--- a/components/safe_browsing_db/v4_local_database_manager.cc
+++ b/components/safe_browsing_db/v4_local_database_manager.cc
@@ -52,11 +52,15 @@
 V4LocalDatabaseManager::PendingCheck::PendingCheck(
     Client* client,
     ClientCallbackType client_callback_type,
+    const StoresToCheck& stores_to_check,
     const GURL& url)
     : client(client),
       client_callback_type(client_callback_type),
       result_threat_type(SB_THREAT_TYPE_SAFE),
-      url(url) {}
+      stores_to_check(stores_to_check),
+      url(url) {
+  DCHECK_GT(ClientCallbackType::CHECK_MAX, client_callback_type);
+}
 
 V4LocalDatabaseManager::PendingCheck::~PendingCheck() {}
 
@@ -86,7 +90,14 @@
     pending_clients_.erase(it);
   }
 
-  // TODO(vakh): Handle the case of queued checks.
+  auto queued_it =
+      std::find_if(std::begin(queued_checks_), std::end(queued_checks_),
+                   [&client](const std::unique_ptr<PendingCheck>& check) {
+                     return check->client == client;
+                   });
+  if (queued_it != queued_checks_.end()) {
+    queued_checks_.erase(queued_it);
+  }
 }
 
 bool V4LocalDatabaseManager::CanCheckResourceType(
@@ -111,47 +122,21 @@
     return true;
   }
 
-  if (v4_database_) {
-    std::unordered_set<FullHash> full_hashes;
-    V4ProtocolManagerUtil::UrlToFullHashes(url, &full_hashes);
-
-    std::unordered_set<ListIdentifier> stores_to_look(
-        {GetUrlMalwareId(), GetUrlSocEngId()});
-    std::unordered_set<HashPrefix> matched_hash_prefixes;
-    std::unordered_set<ListIdentifier> matched_stores;
-    StoreAndHashPrefixes matched_store_and_hash_prefixes;
-    FullHashToStoreAndHashPrefixesMap full_hash_to_store_and_hash_prefixes;
-    for (const auto& full_hash : full_hashes) {
-      matched_store_and_hash_prefixes.clear();
-      v4_database_->GetStoresMatchingFullHash(full_hash, stores_to_look,
-                                              &matched_store_and_hash_prefixes);
-      if (!matched_store_and_hash_prefixes.empty()) {
-        full_hash_to_store_and_hash_prefixes[full_hash] =
-            matched_store_and_hash_prefixes;
-      }
-    }
-
-    if (full_hash_to_store_and_hash_prefixes.empty()) {
-      return true;
-    } else {
-      std::unique_ptr<PendingCheck> pending_check =
-          base::MakeUnique<PendingCheck>(
-              client, ClientCallbackType::CHECK_BROWSE_URL, url);
-
-      pending_clients_.insert(client);
-
-      v4_get_hash_protocol_manager_->GetFullHashes(
-          full_hash_to_store_and_hash_prefixes,
-          base::Bind(&V4LocalDatabaseManager::OnFullHashResponse,
-                     base::Unretained(this), base::Passed(&pending_check)));
-
-      return false;
-    }
-  } else {
-    // TODO(vakh): Queue the check and process it when the database becomes
-    // ready.
+  std::unique_ptr<PendingCheck> check = base::MakeUnique<PendingCheck>(
+      client, ClientCallbackType::CHECK_BROWSE_URL,
+      StoresToCheck({GetUrlMalwareId(), GetUrlSocEngId()}), url);
+  if (!v4_database_) {
+    queued_checks_.push_back(std::move(check));
     return false;
   }
+
+  FullHashToStoreAndHashPrefixesMap full_hash_to_store_and_hash_prefixes;
+  if (!GetPrefixMatches(check, &full_hash_to_store_and_hash_prefixes)) {
+    return true;
+  }
+
+  PerformFullHashCheck(std::move(check), full_hash_to_store_and_hash_prefixes);
+  return false;
 }
 
 bool V4LocalDatabaseManager::CheckDownloadUrl(
@@ -255,6 +240,8 @@
 
   pending_clients_.clear();
 
+  RespondSafeToQueuedChecks();
+
   // Delete the V4Database. Any pending writes to disk are completed.
   // This operation happens on the task_runner on which v4_database_ operates
   // and doesn't block the IO thread.
@@ -285,6 +272,8 @@
     // The database is in place. Start fetching updates now.
     v4_update_protocol_manager_->ScheduleNextUpdate(
         v4_database_->GetStoreStateMap());
+
+    ProcessQueuedChecks();
   } else {
     // Schedule the deletion of v4_database off IO thread.
     V4Database::Destroy(std::move(v4_database));
@@ -298,6 +287,39 @@
   }
 }
 
+bool V4LocalDatabaseManager::GetPrefixMatches(
+    const std::unique_ptr<PendingCheck>& check,
+    FullHashToStoreAndHashPrefixesMap* full_hash_to_store_and_hash_prefixes) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  DCHECK(enabled_);
+  DCHECK(v4_database_);
+  DCHECK_GT(ClientCallbackType::CHECK_MAX, check->client_callback_type);
+
+  if (check->client_callback_type == ClientCallbackType::CHECK_BROWSE_URL) {
+    std::unordered_set<FullHash> full_hashes;
+    V4ProtocolManagerUtil::UrlToFullHashes(check->url, &full_hashes);
+
+    StoreAndHashPrefixes matched_store_and_hash_prefixes;
+    for (const auto& full_hash : full_hashes) {
+      matched_store_and_hash_prefixes.clear();
+      v4_database_->GetStoresMatchingFullHash(full_hash, check->stores_to_check,
+                                              &matched_store_and_hash_prefixes);
+      if (!matched_store_and_hash_prefixes.empty()) {
+        (*full_hash_to_store_and_hash_prefixes)[full_hash] =
+            matched_store_and_hash_prefixes;
+      }
+    }
+
+    // No hash prefixes found in the local database so that resource must be
+    // safe.
+    return !full_hash_to_store_and_hash_prefixes->empty();
+  }
+
+  NOTREACHED() << "Unexpected client_callback_type encountered";
+  return false;
+}
+
 void V4LocalDatabaseManager::GetSeverestThreatTypeAndMetadata(
     SBThreatType* result_threat_type,
     ThreatMetadata* metadata,
@@ -316,6 +338,14 @@
   }
 }
 
+StoresToCheck V4LocalDatabaseManager::GetStoresForFullHashRequests() {
+  StoresToCheck stores_for_full_hash;
+  for (auto it : list_infos_) {
+    stores_for_full_hash.insert(it.list_id());
+  }
+  return stores_for_full_hash;
+}
+
 // Returns the SBThreatType corresponding to a given SafeBrowsing list.
 SBThreatType V4LocalDatabaseManager::GetSBThreatTypeForList(
     const ListIdentifier& list_id) {
@@ -327,15 +357,6 @@
   return it->sb_threat_type();
 }
 
-std::unordered_set<ListIdentifier>
-V4LocalDatabaseManager::GetStoresForFullHashRequests() {
-  std::unordered_set<ListIdentifier> stores_for_full_hash;
-  for (auto it : list_infos_) {
-    stores_for_full_hash.insert(it.list_id());
-  }
-  return stores_for_full_hash;
-}
-
 void V4LocalDatabaseManager::OnFullHashResponse(
     std::unique_ptr<PendingCheck> pending_check,
     const std::vector<FullHashInfo>& full_hash_infos) {
@@ -356,8 +377,46 @@
   GetSeverestThreatTypeAndMetadata(&pending_check->result_threat_type,
                                    &pending_check->url_metadata,
                                    full_hash_infos);
-  RespondToClient(std::move(pending_check));
   pending_clients_.erase(it);
+  RespondToClient(std::move(pending_check));
+}
+
+void V4LocalDatabaseManager::PerformFullHashCheck(
+    std::unique_ptr<PendingCheck> check,
+    const FullHashToStoreAndHashPrefixesMap&
+        full_hash_to_store_and_hash_prefixes) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  DCHECK(enabled_);
+  DCHECK(!full_hash_to_store_and_hash_prefixes.empty());
+
+  pending_clients_.insert(check->client);
+
+  v4_get_hash_protocol_manager_->GetFullHashes(
+      full_hash_to_store_and_hash_prefixes,
+      base::Bind(&V4LocalDatabaseManager::OnFullHashResponse,
+                 base::Unretained(this), base::Passed(std::move(check))));
+}
+
+void V4LocalDatabaseManager::ProcessQueuedChecks() {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  for (auto& it : queued_checks_) {
+    FullHashToStoreAndHashPrefixesMap full_hash_to_store_and_hash_prefixes;
+    if (!GetPrefixMatches(it, &full_hash_to_store_and_hash_prefixes)) {
+      RespondToClient(std::move(it));
+    } else {
+      PerformFullHashCheck(std::move(it), full_hash_to_store_and_hash_prefixes);
+    }
+  }
+  queued_checks_.clear();
+}
+
+void V4LocalDatabaseManager::RespondSafeToQueuedChecks() {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  for (std::unique_ptr<PendingCheck>& it : queued_checks_) {
+    RespondToClient(std::move(it));
+  }
+  queued_checks_.clear();
 }
 
 void V4LocalDatabaseManager::RespondToClient(
diff --git a/components/safe_browsing_db/v4_local_database_manager.h b/components/safe_browsing_db/v4_local_database_manager.h
index 4dd4707..f9510c4 100644
--- a/components/safe_browsing_db/v4_local_database_manager.h
+++ b/components/safe_browsing_db/v4_local_database_manager.h
@@ -37,36 +37,6 @@
     CHECK_MAX
   };
 
-  // The information we need to return the response to the SafeBrowsing client
-  // that asked for the safety reputation of a URL if we can't determine that
-  // synchronously.
-  // TODO(vakh): In its current form, it only includes information for
-  // |CheckBrowseUrl| method. Extend it to serve other methods on |client|.
-  struct PendingCheck {
-    PendingCheck(Client* client,
-                 ClientCallbackType client_callback_type,
-                 const GURL& url);
-
-    ~PendingCheck();
-
-    // The SafeBrowsing client that's waiting for the safe/unsafe verdict.
-    Client* client;
-
-    // Determines which funtion from the |client| needs to be called once we
-    // know whether the URL in |url| is safe or unsafe.
-    ClientCallbackType client_callback_type;
-
-    // The threat verdict for the URL being checked.
-    SBThreatType result_threat_type;
-
-    // The URL that is being checked for being unsafe.
-    GURL url;
-
-    // The metadata associated with the full hash of the severest match found
-    // for that URL.
-    ThreatMetadata url_metadata;
-  };
-
   // Construct V4LocalDatabaseManager.
   // Must be initialized by calling StartOnIOThread() before using.
   V4LocalDatabaseManager(const base::FilePath& base_path);
@@ -104,7 +74,44 @@
   //
 
  protected:
-  std::unordered_set<ListIdentifier> GetStoresForFullHashRequests() override;
+  // The information we need to process a URL safety reputation request and
+  // respond to the SafeBrowsing client that asked for it.
+  // TODO(vakh): In its current form, it only includes information for
+  // |CheckBrowseUrl| method. Extend it to serve other methods on |client|.
+  struct PendingCheck {
+    PendingCheck(Client* client,
+                 ClientCallbackType client_callback_type,
+                 const StoresToCheck& stores_to_check,
+                 const GURL& url);
+
+    ~PendingCheck();
+
+    // The SafeBrowsing client that's waiting for the safe/unsafe verdict.
+    Client* client;
+
+    // Determines which funtion from the |client| needs to be called once we
+    // know whether the URL in |url| is safe or unsafe.
+    ClientCallbackType client_callback_type;
+
+    // The threat verdict for the URL being checked.
+    SBThreatType result_threat_type;
+
+    // The SafeBrowsing lists to check hash prefixes in.
+    StoresToCheck stores_to_check;
+
+    // The URL that is being checked for being unsafe.
+    GURL url;
+
+    // The metadata associated with the full hash of the severest match found
+    // for that URL.
+    ThreatMetadata url_metadata;
+  };
+
+  typedef std::vector<std::unique_ptr<PendingCheck>> QueuedChecks;
+
+  // The stores/lists to always get full hashes for, regardless of which store
+  // the hash prefix matched.
+  StoresToCheck GetStoresForFullHashRequests() override;
 
  private:
   friend class V4LocalDatabaseManagerTest;
@@ -128,6 +135,12 @@
   // Called when the database has been updated and schedules the next update.
   void DatabaseUpdated();
 
+  // Return the prefixes and the store they matched in, for a given URL. Returns
+  // true if a hash prefix match is found; false otherwise.
+  bool GetPrefixMatches(
+      const std::unique_ptr<PendingCheck>& check,
+      FullHashToStoreAndHashPrefixesMap* full_hash_to_store_and_hash_prefixes);
+
   // Finds the most severe |SBThreatType| and the corresponding |metadata| from
   // |full_hash_infos|.
   void GetSeverestThreatTypeAndMetadata(
@@ -144,6 +157,19 @@
   void OnFullHashResponse(std::unique_ptr<PendingCheck> pending_check,
                           const std::vector<FullHashInfo>& full_hash_infos);
 
+  // Performs the full hash checking of the URL in |check|.
+  void PerformFullHashCheck(std::unique_ptr<PendingCheck> check,
+                            const FullHashToStoreAndHashPrefixesMap&
+                                full_hash_to_store_and_hash_prefixes);
+
+  // When the database is ready to use, process the checks that were queued
+  // while the database was loading from disk.
+  void ProcessQueuedChecks();
+
+  // Called on StopOnIOThread, it responds to the clients that are waiting for
+  // the database to become available with the verdict as SAFE.
+  void RespondSafeToQueuedChecks();
+
   // Calls the appopriate method on the |client| object, based on the contents
   // of |pending_check|.
   void RespondToClient(std::unique_ptr<PendingCheck> pending_check);
@@ -182,6 +208,10 @@
   // SafeBrowsing service.
   PendingClients pending_clients_;
 
+  // The checks that need to be scheduled when the database becomes ready for
+  // use.
+  QueuedChecks queued_checks_;
+
   // The sequenced task runner for running safe browsing database operations.
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
 
diff --git a/components/safe_browsing_db/v4_local_database_manager_unittest.cc b/components/safe_browsing_db/v4_local_database_manager_unittest.cc
index 580ed74..d3e75cb 100644
--- a/components/safe_browsing_db/v4_local_database_manager_unittest.cc
+++ b/components/safe_browsing_db/v4_local_database_manager_unittest.cc
@@ -25,7 +25,7 @@
 
   void GetStoresMatchingFullHash(
       const FullHash& full_hash,
-      const std::unordered_set<ListIdentifier>& stores_to_look,
+      const StoresToCheck& stores_to_check,
       StoreAndHashPrefixes* store_and_hash_prefixes) override {
     *store_and_hash_prefixes = store_and_hash_prefixes_;
   }
@@ -34,6 +34,22 @@
   const StoreAndHashPrefixes& store_and_hash_prefixes_;
 };
 
+class TestClient : public SafeBrowsingDatabaseManager::Client {
+ public:
+  TestClient(SBThreatType sb_threat_type, const GURL& url)
+      : expected_sb_threat_type(sb_threat_type), expected_url(url) {}
+
+  void OnCheckBrowseUrlResult(const GURL& url,
+                              SBThreatType threat_type,
+                              const ThreatMetadata& metadata) override {
+    DCHECK_EQ(expected_url, url);
+    DCHECK_EQ(expected_sb_threat_type, threat_type);
+  }
+
+  SBThreatType expected_sb_threat_type;
+  GURL expected_url;
+};
+
 class V4LocalDatabaseManagerTest : public PlatformTest {
  public:
   V4LocalDatabaseManagerTest() : task_runner_(new base::TestSimpleTaskRunner) {}
@@ -48,15 +64,11 @@
         make_scoped_refptr(new V4LocalDatabaseManager(base_dir_.GetPath()));
     v4_local_database_manager_->SetTaskRunnerForTest(task_runner_);
 
-    SetupLocalDatabaseManager();
+    StartLocalDatabaseManager();
   }
 
   void TearDown() override {
-    v4_local_database_manager_->StopOnIOThread(true);
-
-    // Force destruction of the database.
-    task_runner_->RunPendingTasks();
-    base::RunLoop().RunUntilIdle();
+    StopLocalDatabaseManager();
 
     PlatformTest::TearDown();
   }
@@ -65,18 +77,32 @@
     v4_local_database_manager_->enabled_ = false;
   }
 
+  const V4LocalDatabaseManager::QueuedChecks& GetQueuedChecks() {
+    return v4_local_database_manager_->queued_checks_;
+  }
+
   void ReplaceV4Database(const StoreAndHashPrefixes& store_and_hash_prefixes) {
     v4_local_database_manager_->v4_database_.reset(new FakeV4Database(
         task_runner_, base::MakeUnique<StoreMap>(), store_and_hash_prefixes));
   }
 
-  void SetupLocalDatabaseManager() {
+  void ResetV4Database() { v4_local_database_manager_->v4_database_.reset(); }
+
+  void StartLocalDatabaseManager() {
     v4_local_database_manager_->StartOnIOThread(NULL, V4ProtocolConfig());
 
     task_runner_->RunPendingTasks();
     base::RunLoop().RunUntilIdle();
   }
 
+  void StopLocalDatabaseManager() {
+    v4_local_database_manager_->StopOnIOThread(true);
+
+    // Force destruction of the database.
+    task_runner_->RunPendingTasks();
+    base::RunLoop().RunUntilIdle();
+  }
+
   base::ScopedTempDir base_dir_;
   scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
   content::TestBrowserThreadBundle thread_bundle_;
@@ -162,4 +188,31 @@
   EXPECT_EQ("malware_popid", metadata.population_id);
 }
 
+TEST_F(V4LocalDatabaseManagerTest, TestChecksAreQueued) {
+  const GURL url("https://www.example.com/");
+  TestClient client(SB_THREAT_TYPE_SAFE, url);
+  EXPECT_TRUE(GetQueuedChecks().empty());
+  v4_local_database_manager_->CheckBrowseUrl(url, &client);
+  // The database is available so the check shouldn't get queued.
+  EXPECT_TRUE(GetQueuedChecks().empty());
+
+  ResetV4Database();
+  v4_local_database_manager_->CheckBrowseUrl(url, &client);
+  // The database is unavailable so the check should get queued.
+  EXPECT_EQ(1ul, GetQueuedChecks().size());
+
+  // The following function calls StartOnIOThread which should load the
+  // database from disk and cause the queued check to be performed.
+  StartLocalDatabaseManager();
+  EXPECT_TRUE(GetQueuedChecks().empty());
+
+  ResetV4Database();
+  v4_local_database_manager_->CheckBrowseUrl(url, &client);
+  // The database is unavailable so the check should get queued.
+  EXPECT_EQ(1ul, GetQueuedChecks().size());
+
+  StopLocalDatabaseManager();
+  EXPECT_TRUE(GetQueuedChecks().empty());
+}
+
 }  // namespace safe_browsing
diff --git a/components/safe_browsing_db/v4_protocol_manager_util.h b/components/safe_browsing_db/v4_protocol_manager_util.h
index 9ca00849..34e2412 100644
--- a/components/safe_browsing_db/v4_protocol_manager_util.h
+++ b/components/safe_browsing_db/v4_protocol_manager_util.h
@@ -297,6 +297,8 @@
   DISALLOW_COPY_AND_ASSIGN(V4ProtocolManagerUtil);
 };
 
+typedef std::unordered_set<ListIdentifier> StoresToCheck;
+
 }  // namespace safe_browsing
 
 namespace std {
diff --git a/components/security_interstitials/core/controller_client.cc b/components/security_interstitials/core/controller_client.cc
index 1bf60ba..e38fc18 100644
--- a/components/security_interstitials/core/controller_client.cc
+++ b/components/security_interstitials/core/controller_client.cc
@@ -22,18 +22,16 @@
     "<a id=\"privacy-link\" href=\"\" onclick=\"sendCommand(%d); "
     "return false;\" onmousedown=\"return false;\">%s</a>";
 
-ControllerClient::ControllerClient() {}
+ControllerClient::ControllerClient(
+    std::unique_ptr<MetricsHelper> metrics_helper)
+    : metrics_helper_(std::move(metrics_helper)) {}
+
 ControllerClient::~ControllerClient() {}
 
 MetricsHelper* ControllerClient::metrics_helper() const {
   return metrics_helper_.get();
 }
 
-void ControllerClient::set_metrics_helper(
-    std::unique_ptr<MetricsHelper> metrics_helper) {
-  metrics_helper_ = std::move(metrics_helper);
-}
-
 void ControllerClient::SetReportingPreference(bool report) {
   GetPrefService()->SetBoolean(GetExtendedReportingPrefName(), report);
   metrics_helper_->RecordUserInteraction(
diff --git a/components/security_interstitials/core/controller_client.h b/components/security_interstitials/core/controller_client.h
index aebff2c..42f9990e 100644
--- a/components/security_interstitials/core/controller_client.h
+++ b/components/security_interstitials/core/controller_client.h
@@ -56,7 +56,7 @@
 // by the JavaScript error page.
 class ControllerClient {
  public:
-  ControllerClient();
+  explicit ControllerClient(std::unique_ptr<MetricsHelper> metrics_helper);
   virtual ~ControllerClient();
 
   // Handle the user's reporting preferences.
@@ -78,7 +78,6 @@
   virtual void Reload() = 0;
 
   MetricsHelper* metrics_helper() const;
-  void set_metrics_helper(std::unique_ptr<MetricsHelper> metrics_helper);
 
   virtual void OpenUrlInCurrentTab(const GURL& url) = 0;
 
diff --git a/components/sync/BUILD.gn b/components/sync/BUILD.gn
index 9569724..1ebece93 100644
--- a/components/sync/BUILD.gn
+++ b/components/sync/BUILD.gn
@@ -29,6 +29,7 @@
     "api/entity_change.h",
     "api/entity_data.cc",
     "api/entity_data.h",
+    "api/local_change_observer.h",
     "api/metadata_batch.cc",
     "api/metadata_batch.h",
     "api/metadata_change_list.h",
diff --git a/components/sync/api/fake_sync_change_processor.cc b/components/sync/api/fake_sync_change_processor.cc
index 0060cf0..a675151 100644
--- a/components/sync/api/fake_sync_change_processor.cc
+++ b/components/sync/api/fake_sync_change_processor.cc
@@ -33,6 +33,12 @@
   return syncer::SyncError();
 }
 
+void FakeSyncChangeProcessor::AddLocalChangeObserver(
+    syncer::LocalChangeObserver* observer) {}
+
+void FakeSyncChangeProcessor::RemoveLocalChangeObserver(
+    syncer::LocalChangeObserver* observer) {}
+
 const syncer::SyncChangeList& FakeSyncChangeProcessor::changes() const {
   return changes_;
 }
diff --git a/components/sync/api/fake_sync_change_processor.h b/components/sync/api/fake_sync_change_processor.h
index d599f55e..1498b2d 100644
--- a/components/sync/api/fake_sync_change_processor.h
+++ b/components/sync/api/fake_sync_change_processor.h
@@ -36,6 +36,9 @@
   syncer::SyncError UpdateDataTypeContext(ModelType type,
                                           ContextRefreshStatus refresh_status,
                                           const std::string& context) override;
+  void AddLocalChangeObserver(syncer::LocalChangeObserver* observer) override;
+  void RemoveLocalChangeObserver(
+      syncer::LocalChangeObserver* observer) override;
 
   virtual const syncer::SyncChangeList& changes() const;
   virtual syncer::SyncChangeList& changes();
diff --git a/components/sync/api/local_change_observer.h b/components/sync/api/local_change_observer.h
new file mode 100644
index 0000000..1c9f7d2
--- /dev/null
+++ b/components/sync/api/local_change_observer.h
@@ -0,0 +1,32 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SYNC_API_LOCAL_CHANGE_OBSERVER_H_
+#define COMPONENTS_SYNC_API_LOCAL_CHANGE_OBSERVER_H_
+
+namespace syncer {
+
+class SyncChange;
+namespace syncable {
+class Entry;
+}  // namespace syncable
+
+// Interface for observers that want to be notified of local sync changes.
+// The OnLocalChange function will be called when a local change made through
+// ProcessSyncChanges is about to be applied to the directory. This is useful
+// for inspecting the specifics of sync data being written locally and comparing
+// it against the current state of the directory. Registering a local change
+// observer is done by calling the AddLocalChangeObserver function on an
+// instance of SyncChangeProcessor.
+class LocalChangeObserver {
+ public:
+  virtual ~LocalChangeObserver() {}
+  // Function called to notify observer of the local change. current_entry
+  // should reflect the state of the entry *before* change is applied.
+  virtual void OnLocalChange(const syncable::Entry* current_entry,
+                             const SyncChange& change) = 0;
+};
+}  // namespace syncer
+
+#endif  // COMPONENTS_SYNC_API_LOCAL_CHANGE_OBSERVER_H_
diff --git a/components/sync/api/sync_change_processor.cc b/components/sync/api/sync_change_processor.cc
index f954a6ac..3a0b6a0 100644
--- a/components/sync/api/sync_change_processor.cc
+++ b/components/sync/api/sync_change_processor.cc
@@ -18,4 +18,14 @@
   return syncer::SyncError();
 }
 
+void SyncChangeProcessor::AddLocalChangeObserver(
+    LocalChangeObserver* observer) {
+  NOTREACHED();
+}
+
+void SyncChangeProcessor::RemoveLocalChangeObserver(
+    LocalChangeObserver* observer) {
+  NOTREACHED();
+}
+
 }  // namespace syncer
diff --git a/components/sync/api/sync_change_processor.h b/components/sync/api/sync_change_processor.h
index d5884a2..2d31b8a9 100644
--- a/components/sync/api/sync_change_processor.h
+++ b/components/sync/api/sync_change_processor.h
@@ -20,6 +20,8 @@
 
 class SyncChange;
 
+class LocalChangeObserver;
+
 typedef std::vector<SyncChange> SyncChangeList;
 
 // An interface for services that handle receiving SyncChanges.
@@ -75,6 +77,12 @@
       ModelType type,
       ContextRefreshStatus refresh_status,
       const std::string& context);
+
+  // Adds an observer of local sync changes. This observer is notified when
+  // local sync changes are applied by GenericChangeProcessor. observer is
+  // not owned by the SyncChangeProcessor.
+  virtual void AddLocalChangeObserver(LocalChangeObserver* observer);
+  virtual void RemoveLocalChangeObserver(LocalChangeObserver* observer);
 };
 
 }  // namespace syncer
diff --git a/components/sync/driver/data_type_manager_impl.cc b/components/sync/driver/data_type_manager_impl.cc
index 0f6b78b..4d9f1f00 100644
--- a/components/sync/driver/data_type_manager_impl.cc
+++ b/components/sync/driver/data_type_manager_impl.cc
@@ -15,6 +15,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/profiler/scoped_tracker.h"
 #include "base/strings/stringprintf.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
 #include "components/sync/core/data_type_debug_info_listener.h"
 #include "components/sync/driver/data_type_encryption_handler.h"
@@ -332,7 +333,10 @@
 }
 
 void DataTypeManagerImpl::ProcessReconfigure() {
-  DCHECK(needs_reconfigure_);
+  // This may have been called asynchronously; no-op if it is no longer needed.
+  if (!needs_reconfigure_) {
+    return;
+  }
 
   // Wait for current download and association to finish.
   if (!download_types_queue_.empty() ||
@@ -499,7 +503,12 @@
     if (error.error_type() != syncer::SyncError::UNRECOVERABLE_ERROR) {
       needs_reconfigure_ = true;
       last_configure_reason_ = syncer::CONFIGURE_REASON_PROGRAMMATIC;
-      ProcessReconfigure();
+      // Do this asynchronously so the ModelAssociationManager has a chance to
+      // finish stopping this type, otherwise DeactivateDataType() and Stop()
+      // end up getting called twice on the controller.
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::Bind(&DataTypeManagerImpl::ProcessReconfigure,
+                                weak_ptr_factory_.GetWeakPtr()));
     }
   }
 }
diff --git a/components/sync/driver/generic_change_processor.cc b/components/sync/driver/generic_change_processor.cc
index a54a6a75..0042c16 100644
--- a/components/sync/driver/generic_change_processor.cc
+++ b/components/sync/driver/generic_change_processor.cc
@@ -15,6 +15,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/sync/api/data_type_error_handler.h"
+#include "components/sync/api/local_change_observer.h"
 #include "components/sync/api/sync_change.h"
 #include "components/sync/api/sync_error.h"
 #include "components/sync/api/syncable_service.h"
@@ -244,6 +245,16 @@
   return syncer::SyncError();
 }
 
+void GenericChangeProcessor::AddLocalChangeObserver(
+    syncer::LocalChangeObserver* observer) {
+  local_change_observers_.AddObserver(observer);
+}
+
+void GenericChangeProcessor::RemoveLocalChangeObserver(
+    syncer::LocalChangeObserver* observer) {
+  local_change_observers_.RemoveObserver(observer);
+}
+
 void GenericChangeProcessor::OnAttachmentUploaded(
     const syncer::AttachmentId& attachment_id) {
   syncer::WriteTransaction trans(FROM_HERE, share_handle());
@@ -366,11 +377,14 @@
   }
 }
 
-syncer::SyncError AttemptDelete(const syncer::SyncChange& change,
-                                syncer::ModelType type,
-                                const std::string& type_str,
-                                syncer::WriteNode* node,
-                                syncer::DataTypeErrorHandler* error_handler) {
+}  // namespace
+
+syncer::SyncError GenericChangeProcessor::AttemptDelete(
+    const syncer::SyncChange& change,
+    syncer::ModelType type,
+    const std::string& type_str,
+    syncer::WriteNode* node,
+    syncer::DataTypeErrorHandler* error_handler) {
   DCHECK_EQ(change.change_type(), syncer::SyncChange::ACTION_DELETE);
   if (change.sync_data().IsLocal()) {
     const std::string& tag = syncer::SyncDataLocal(change.sync_data()).GetTag();
@@ -405,6 +419,7 @@
                               type, error_handler);
     }
   }
+  NotifyLocalChangeObservers(node->GetEntry(), change);
   if (IsActOnceDataType(type))
     node->Drop();
   else
@@ -412,8 +427,6 @@
   return syncer::SyncError();
 }
 
-}  // namespace
-
 syncer::SyncError GenericChangeProcessor::ProcessSyncChanges(
     const tracked_objects::Location& from_here,
     const syncer::SyncChangeList& list_of_changes) {
@@ -553,6 +566,8 @@
       }
     }
   }
+  NotifyLocalChangeObservers(sync_node->GetEntry(), change);
+
   sync_node->SetTitle(change.sync_data().GetTitle());
   SetNodeSpecifics(sync_data_local.GetSpecifics(), sync_node);
 
@@ -617,6 +632,8 @@
     }
   }
 
+  NotifyLocalChangeObservers(sync_node->GetEntry(), change);
+
   sync_node->SetTitle(change.sync_data().GetTitle());
   SetNodeSpecifics(sync_data_local.GetSpecifics(), sync_node);
   syncer::AttachmentIdList attachment_ids = sync_data_local.GetAttachmentIds();
@@ -683,6 +700,13 @@
   }
 }
 
+void GenericChangeProcessor::NotifyLocalChangeObservers(
+    const syncer::syncable::Entry* current_entry,
+    const syncer::SyncChange& change) {
+  FOR_EACH_OBSERVER(syncer::LocalChangeObserver, local_change_observers_,
+                    OnLocalChange(current_entry, change));
+}
+
 std::unique_ptr<syncer::AttachmentService>
 GenericChangeProcessor::GetAttachmentService() const {
   return std::unique_ptr<syncer::AttachmentService>(
diff --git a/components/sync/driver/generic_change_processor.h b/components/sync/driver/generic_change_processor.h
index 36c08aa2..18ba548 100644
--- a/components/sync/driver/generic_change_processor.h
+++ b/components/sync/driver/generic_change_processor.h
@@ -30,6 +30,10 @@
 class WriteTransaction;
 
 typedef std::vector<syncer::SyncData> SyncDataList;
+
+namespace syncable {
+class Entry;
+}  // namespace syncable
 }  // namespace syncer
 
 namespace sync_driver {
@@ -82,6 +86,9 @@
       syncer::ModelType type,
       syncer::SyncChangeProcessor::ContextRefreshStatus refresh_status,
       const std::string& context) override;
+  void AddLocalChangeObserver(syncer::LocalChangeObserver* observer) override;
+  void RemoveLocalChangeObserver(
+      syncer::LocalChangeObserver* observer) override;
 
   // syncer::AttachmentService::Delegate implementation.
   void OnAttachmentUploaded(const syncer::AttachmentId& attachment_id) override;
@@ -113,6 +120,11 @@
   syncer::UserShare* share_handle() const override;
 
  private:
+  syncer::SyncError AttemptDelete(const syncer::SyncChange& change,
+                                  syncer::ModelType type,
+                                  const std::string& type_str,
+                                  syncer::WriteNode* node,
+                                  syncer::DataTypeErrorHandler* error_handler);
   // Logically part of ProcessSyncChanges.
   //
   // |new_attachments| is an output parameter containing newly added attachments
@@ -138,6 +150,11 @@
   // server.
   void UploadAllAttachmentsNotOnServer();
 
+  // Notify every registered local change observer that |change| is about to be
+  // applied to |current_entry|.
+  void NotifyLocalChangeObservers(const syncer::syncable::Entry* current_entry,
+                                  const syncer::SyncChange& change);
+
   const syncer::ModelType type_;
 
   // The SyncableService this change processor will forward changes on to.
@@ -166,6 +183,9 @@
   // attachments.
   std::unique_ptr<syncer::AttachmentService> attachment_service_;
 
+  // List of observers that want to be notified of local changes being written.
+  base::ObserverList<syncer::LocalChangeObserver> local_change_observers_;
+
   // Must be destroyed before attachment_service_ to ensure WeakPtrs are
   // invalidated before attachment_service_ is destroyed.
   // Can be NULL if attachment_service_ is NULL;
diff --git a/components/sync/driver/non_blocking_data_type_controller.cc b/components/sync/driver/non_blocking_data_type_controller.cc
index c414de2..a01905d 100644
--- a/components/sync/driver/non_blocking_data_type_controller.cc
+++ b/components/sync/driver/non_blocking_data_type_controller.cc
@@ -217,10 +217,7 @@
 void NonBlockingDataTypeController::ReportLoadModelError(
     const syncer::SyncError& error) {
   DCHECK(CalledOnValidThread());
-  // Report the error only if the model is starting.
-  if (state_ == MODEL_STARTING) {
-    LoadModelsDone(UNRECOVERABLE_ERROR, error);
-  }
+  LoadModelsDone(UNRECOVERABLE_ERROR, error);
 }
 
 void NonBlockingDataTypeController::RecordStartFailure(
diff --git a/components/sync/driver/shared_change_processor.cc b/components/sync/driver/shared_change_processor.cc
index 60f010a..fc8eea8 100644
--- a/components/sync/driver/shared_change_processor.cc
+++ b/components/sync/driver/shared_change_processor.cc
@@ -21,7 +21,7 @@
 
 namespace syncer {
 class AttachmentService;
-}
+}  // namespace syncer
 
 namespace sync_driver {
 
@@ -259,6 +259,22 @@
                                                           context);
 }
 
+void SharedChangeProcessor::AddLocalChangeObserver(
+    syncer::LocalChangeObserver* observer) {
+  DCHECK(backend_task_runner_.get());
+  DCHECK(backend_task_runner_->BelongsToCurrentThread());
+
+  generic_change_processor_->AddLocalChangeObserver(observer);
+}
+
+void SharedChangeProcessor::RemoveLocalChangeObserver(
+    syncer::LocalChangeObserver* observer) {
+  DCHECK(backend_task_runner_.get());
+  DCHECK(backend_task_runner_->BelongsToCurrentThread());
+
+  generic_change_processor_->RemoveLocalChangeObserver(observer);
+}
+
 bool SharedChangeProcessor::SyncModelHasUserCreatedNodes(bool* has_nodes) {
   DCHECK(backend_task_runner_.get());
   DCHECK(backend_task_runner_->BelongsToCurrentThread());
diff --git a/components/sync/driver/shared_change_processor.h b/components/sync/driver/shared_change_processor.h
index 0edc3ac..5488ac3f 100644
--- a/components/sync/driver/shared_change_processor.h
+++ b/components/sync/driver/shared_change_processor.h
@@ -106,6 +106,8 @@
       syncer::ModelType type,
       syncer::SyncChangeProcessor::ContextRefreshStatus refresh_status,
       const std::string& context);
+  virtual void AddLocalChangeObserver(syncer::LocalChangeObserver* observer);
+  virtual void RemoveLocalChangeObserver(syncer::LocalChangeObserver* observer);
   virtual bool SyncModelHasUserCreatedNodes(bool* has_nodes);
   virtual bool CryptoReadyIfNecessary();
 
diff --git a/components/sync/driver/shared_change_processor_ref.cc b/components/sync/driver/shared_change_processor_ref.cc
index 49df65eb..a989e1c2 100644
--- a/components/sync/driver/shared_change_processor_ref.cc
+++ b/components/sync/driver/shared_change_processor_ref.cc
@@ -33,6 +33,16 @@
                                                   context);
 }
 
+void SharedChangeProcessorRef::AddLocalChangeObserver(
+    syncer::LocalChangeObserver* observer) {
+  change_processor_->AddLocalChangeObserver(observer);
+}
+
+void SharedChangeProcessorRef::RemoveLocalChangeObserver(
+    syncer::LocalChangeObserver* observer) {
+  change_processor_->RemoveLocalChangeObserver(observer);
+}
+
 syncer::SyncError SharedChangeProcessorRef::CreateAndUploadError(
     const tracked_objects::Location& from_here,
     const std::string& message) {
diff --git a/components/sync/driver/shared_change_processor_ref.h b/components/sync/driver/shared_change_processor_ref.h
index c0167b2..a8a9b9b 100644
--- a/components/sync/driver/shared_change_processor_ref.h
+++ b/components/sync/driver/shared_change_processor_ref.h
@@ -33,6 +33,9 @@
       syncer::ModelType type,
       syncer::SyncChangeProcessor::ContextRefreshStatus refresh_status,
       const std::string& context) override;
+  void AddLocalChangeObserver(syncer::LocalChangeObserver* observer) override;
+  void RemoveLocalChangeObserver(
+      syncer::LocalChangeObserver* observer) override;
 
   // syncer::SyncErrorFactory implementation.
   syncer::SyncError CreateAndUploadError(
diff --git a/components/sync_sessions/BUILD.gn b/components/sync_sessions/BUILD.gn
index b7ef585..1515037 100644
--- a/components/sync_sessions/BUILD.gn
+++ b/components/sync_sessions/BUILD.gn
@@ -7,6 +7,8 @@
     "favicon_cache.cc",
     "favicon_cache.h",
     "local_session_event_router.h",
+    "lost_navigations_recorder.cc",
+    "lost_navigations_recorder.h",
     "open_tabs_ui_delegate.cc",
     "open_tabs_ui_delegate.h",
     "revisit/bookmarks_by_url_provider_impl.cc",
@@ -90,6 +92,7 @@
   testonly = true
   sources = [
     "favicon_cache_unittest.cc",
+    "lost_navigations_recorder_unittest.cc",
     "revisit/bookmarks_page_revisit_observer_unittest.cc",
     "revisit/current_tab_matcher_unittest.cc",
     "revisit/offset_tab_matcher_unittest.cc",
@@ -112,6 +115,7 @@
     "//components/sessions:test_support",
     "//components/sync",
     "//components/sync:test_support_sync_api",
+    "//components/sync:test_support_sync_core",
     "//components/sync:test_support_sync_driver",
     "//testing/gmock",
     "//testing/gtest",
diff --git a/components/sync_sessions/lost_navigations_recorder.cc b/components/sync_sessions/lost_navigations_recorder.cc
new file mode 100644
index 0000000..5f9b1f9
--- /dev/null
+++ b/components/sync_sessions/lost_navigations_recorder.cc
@@ -0,0 +1,136 @@
+// 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.
+
+#include "base/metrics/histogram_macros.h"
+#include "base/stl_util.h"
+#include "components/sync/api/sync_change.h"
+#include "components/sync/syncable/entry.h"
+#include "components/sync_sessions/lost_navigations_recorder.h"
+
+namespace sync_sessions {
+
+LostNavigationsRecorder::LostNavigationsRecorder()
+    : recorder_state_(RECORDER_STATE_NOT_SYNCING) {}
+
+LostNavigationsRecorder::~LostNavigationsRecorder() {}
+
+void LostNavigationsRecorder::OnLocalChange(
+    const syncer::syncable::Entry* current_entry,
+    const syncer::SyncChange& change) {
+  if (change.sync_data().GetSpecifics().session().has_tab()) {
+    TransitionState(current_entry->GetSyncing(),
+                    current_entry->GetIsUnsynced());
+  }
+  RecordChange(change);
+}
+
+// Record a change either by adjusting our list of tabs or by recording the set
+// of navigations in the updated tab.
+void LostNavigationsRecorder::RecordChange(const syncer::SyncChange& change) {
+  sync_pb::SessionSpecifics session_specifics =
+      change.sync_data().GetSpecifics().session();
+  if (session_specifics.has_header()) {
+    DeleteTabs(session_specifics.header());
+    return;
+  } else if (!session_specifics.has_tab()) {
+    // There isn't any data we care about if neither a tab or window is
+    // modified.
+    return;
+  }
+  sync_pb::SessionTab tab = session_specifics.tab();
+  id_type tab_id = tab.tab_id();
+
+  IdSet& latest = latest_navigation_ids_[tab_id];
+  latest.clear();
+
+  for (sync_pb::TabNavigation nav : tab.navigation()) {
+    id_type uid = nav.unique_id();
+    // Only record an id if it's "new" i.e. larger than the largest seen for
+    // that tab. If the id is smaller than this, it's not new; ids are generated
+    // in increasing order.
+    if (uid > max_recorded_for_tab_[tab_id]) {
+      recorded_navigation_ids_[tab_id].insert(uid);
+      max_recorded_for_tab_[tab_id] = uid;
+    }
+    latest.insert(nav.unique_id());
+  }
+}
+
+void LostNavigationsRecorder::DeleteTabs(const sync_pb::SessionHeader& header) {
+  IdSet new_tab_ids;
+  IdSet current_tab_ids;
+  // Find the set of tab ids that are still there after the deletion.
+  for (sync_pb::SessionWindow window : header.window()) {
+    for (id_type tab_id : window.tab()) {
+      new_tab_ids.insert(tab_id);
+    }
+  }
+  for (auto pair : recorded_navigation_ids_) {
+    current_tab_ids.insert(pair.first);
+  }
+  // The set of deleted tabs is the difference between the set of tabs before
+  // the pending change and the set of tabs following the pending change.
+  IdSet deleted_tabs =
+      base::STLSetDifference<IdSet>(current_tab_ids, new_tab_ids);
+  for (id_type tab_id : deleted_tabs) {
+    recorded_navigation_ids_.erase(tab_id);
+    latest_navigation_ids_.erase(tab_id);
+    max_recorded_for_tab_.erase(tab_id);
+  }
+}
+
+// Change the current state of the recorder, possibly triggering reconciliation,
+// based on the status of the directory entry. Reconciliation triggers on the
+// observation of two conditions.
+// 1) The entry transitioning into the syncing state
+// 2) If we miss the transition to syncing state, the entry transitioning into
+// the synced state.
+void LostNavigationsRecorder::TransitionState(bool is_syncing,
+                                              bool is_unsynced) {
+  switch (recorder_state_) {
+    case RECORDER_STATE_NOT_SYNCING:
+      // If a sync cycle is happening or already finished, reconcile.
+      // It's possible that this will trigger reconciliation multiple times per
+      // sync cycle; once per tab that finishes the cycle in the synced state
+      // and the user performs a navigation in. In theory this will cause
+      // under-counting, since reconciliation clears each tab's remembered set
+      // of navigations. In practice the number of unique tabs written to in
+      // between two adjacent sync cycles should be pretty low,
+      // making the undercounting tolerable.
+      if (is_syncing || !is_unsynced) {
+        ReconcileLostNavs();
+      }
+      // If we're currently in a sync cycle, remember that.
+      if (is_syncing) {
+        recorder_state_ = RECORDER_STATE_SYNCING;
+      }
+      break;
+    case RECORDER_STATE_SYNCING:
+      if (!is_syncing) {
+        recorder_state_ = RECORDER_STATE_NOT_SYNCING;
+      }
+      break;
+  }
+}
+
+// Reconcile the number of "lost" navigations by checking all the unique ids we
+// recorded against what was actually synced.
+void LostNavigationsRecorder::ReconcileLostNavs() {
+  for (auto pair : recorded_navigation_ids_) {
+    id_type tab_id = pair.first;
+    IdSet& latest = latest_navigation_ids_[tab_id];
+    IdSet& recorded = recorded_navigation_ids_[tab_id];
+    if (recorded.size() < 1) {
+      continue;
+    }
+
+    // The set of lost navigations is anything we recorded as new that's not
+    // present in latest.
+    IdSet lost_navs = base::STLSetDifference<IdSet>(recorded, latest);
+    int quantity_lost = lost_navs.size();
+    UMA_HISTOGRAM_COUNTS("Sync.LostNavigationCount", quantity_lost);
+    recorded.clear();
+  }
+}
+}  // namespace sync_sessions
diff --git a/components/sync_sessions/lost_navigations_recorder.h b/components/sync_sessions/lost_navigations_recorder.h
new file mode 100644
index 0000000..10b264f
--- /dev/null
+++ b/components/sync_sessions/lost_navigations_recorder.h
@@ -0,0 +1,55 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SYNC_SESSIONS_LOST_NAVIGATIONS_RECORDER_H_
+#define COMPONENTS_SYNC_SESSIONS_LOST_NAVIGATIONS_RECORDER_H_
+
+#include "base/macros.h"
+#include "components/sessions/core/session_id.h"
+#include "components/sync/api/local_change_observer.h"
+#include "components/sync/api/sync_change.h"
+#include "components/sync/protocol/session_specifics.pb.h"
+
+namespace sync_sessions {
+
+// Recorder class that tracks the number of navigations written locally that
+// aren't synced. This is done by recording set of locally observed navigations
+// and  reconciling these sets against what was ultimately synced. These
+// navigations ultimately feed chrome history, so losing them prevents them from
+// being reflected in the history page.
+class LostNavigationsRecorder : public syncer::LocalChangeObserver {
+ public:
+  typedef SessionID::id_type id_type;
+  typedef std::set<id_type> IdSet;
+  enum RecorderState { RECORDER_STATE_NOT_SYNCING, RECORDER_STATE_SYNCING };
+
+  LostNavigationsRecorder();
+  ~LostNavigationsRecorder() override;
+
+  // syncer::LocalChangeObserver implementation.
+  void OnLocalChange(const syncer::syncable::Entry* current_entry,
+                     const syncer::SyncChange& change) override;
+
+ private:
+  void RecordChange(const syncer::SyncChange& change);
+  void DeleteTabs(const sync_pb::SessionHeader& header);
+  void TransitionState(bool is_syncing, bool is_unsynced);
+  void ReconcileLostNavs();
+
+  // State that records whether the most recently observed directory state was
+  // syncing or not syncing.
+  RecorderState recorder_state_;
+
+  // The set of all navigation ids we've observed for each tab_id since the last
+  // sync.
+  std::map<id_type, IdSet> recorded_navigation_ids_;
+  // The set of navigation ids most recently recorded for each tab_id.
+  std::map<id_type, IdSet> latest_navigation_ids_;
+  // The maximum navigation_id recorded for each tab_id.
+  std::map<id_type, id_type> max_recorded_for_tab_;
+  DISALLOW_COPY_AND_ASSIGN(LostNavigationsRecorder);
+};
+};  // namespace sync_sessions
+
+#endif  // COMPONENTS_SYNC_SESSIONS_LOST_NAVIGATIONS_RECORDER_H_
diff --git a/components/sync_sessions/lost_navigations_recorder_unittest.cc b/components/sync_sessions/lost_navigations_recorder_unittest.cc
new file mode 100644
index 0000000..bffb921
--- /dev/null
+++ b/components/sync_sessions/lost_navigations_recorder_unittest.cc
@@ -0,0 +1,398 @@
+// 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.
+
+#include <memory>
+
+#include "base/message_loop/message_loop.h"
+#include "base/test/histogram_tester.h"
+#include "components/sessions/core/session_id.h"
+#include "components/sync/core/attachments/attachment_service_proxy_for_test.h"
+#include "components/sync/syncable/entry.h"
+#include "components/sync/syncable/mutable_entry.h"
+#include "components/sync/syncable/syncable_base_transaction.h"
+#include "components/sync/syncable/syncable_read_transaction.h"
+#include "components/sync/syncable/syncable_write_transaction.h"
+#include "components/sync/test/engine/test_directory_setter_upper.h"
+#include "components/sync/test/engine/test_id_factory.h"
+#include "components/sync_sessions/lost_navigations_recorder.h"
+#include "components/sync_sessions/sessions_sync_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using syncer::syncable::Entry;
+using syncer::syncable::Id;
+using syncer::syncable::MutableEntry;
+using syncer::syncable::WriteTransaction;
+
+namespace sync_sessions {
+namespace {
+typedef SessionID::id_type id_type;
+
+const char kTab1SyncTag[] = "tab-YWRkcjHvv74=";
+const char kTab2SyncTag[] = "tab-2FyZDHvv74=";
+
+class LostNavigationsRecorderTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    dir_maker_.SetUp();
+    _id = 1;
+  }
+
+  void TearDown() override { dir_maker_.TearDown(); }
+
+  syncer::syncable::Directory* directory() { return dir_maker_.directory(); }
+
+  LostNavigationsRecorder* recorder() { return &recorder_; }
+
+  void AddNavigation(sync_pb::SessionSpecifics* tab_base,
+                     id_type id_override = -1) {
+    sync_pb::SessionTab* tab = tab_base->mutable_tab();
+    sync_pb::TabNavigation* navigation = tab->add_navigation();
+    navigation->set_page_transition(sync_pb::SyncEnums_PageTransition_TYPED);
+    navigation->set_unique_id(id_override > 0 ? id_override : _id++);
+  }
+
+  void BuildTabSpecifics(const std::string& tag,
+                         int tab_id,
+                         sync_pb::SessionSpecifics* tab_base,
+                         int num_unique_navs = 1) {
+    tab_base->set_session_tag(tag);
+    tab_base->set_tab_node_id(0);
+    sync_pb::SessionTab* tab = tab_base->mutable_tab();
+    tab->set_tab_id(tab_id);
+    tab->set_current_navigation_index(0);
+    for (int i = 0; i < num_unique_navs; ++i) {
+      AddNavigation(tab_base);
+    }
+  }
+
+  void BuildWindowSpecifics(int window_id,
+                            sync_pb::SessionSpecifics* window_base) {
+    sync_pb::SessionHeader* header = window_base->mutable_header();
+    sync_pb::SessionWindow* window = header->add_window();
+    window->set_window_id(window_id);
+  }
+
+  const Id& CreateEntry() {
+    WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+    MutableEntry mutable_entry(&wtrans, syncer::syncable::CREATE,
+                               syncer::SESSIONS, wtrans.root_id(),
+                               "entrynamutable_entry");
+    EXPECT_TRUE(mutable_entry.good());
+    return mutable_entry.GetId();
+  }
+
+  const syncer::SyncData CreateLocalData(
+      const sync_pb::SessionSpecifics& specifics,
+      const std::string& sync_tag) const {
+    sync_pb::EntitySpecifics entity;
+    entity.mutable_session()->CopyFrom(specifics);
+    return syncer::SyncData::CreateLocalData(sync_tag, sync_tag, entity);
+  }
+
+  syncer::SyncChange MakeChange(const std::string& sync_tag,
+                                const sync_pb::SessionSpecifics& specifics,
+                                syncer::SyncChange::SyncChangeType type) const {
+    return syncer::SyncChange(FROM_HERE, type,
+                              CreateLocalData(specifics, sync_tag));
+  }
+
+  void RecordChange(const Entry* entry, int num_unique_navs) {
+    sync_pb::EntitySpecifics specifics;
+    BuildTabSpecifics(kTab1SyncTag, 1, specifics.mutable_session(),
+                      num_unique_navs);
+    RecordChange(entry, specifics);
+  }
+
+  void RecordChange(const Entry* entry, sync_pb::EntitySpecifics specifics) {
+    syncer::SyncChange change = MakeChange(kTab1SyncTag, specifics.session(),
+                                           syncer::SyncChange::ACTION_UPDATE);
+    recorder()->OnLocalChange(entry, change);
+  }
+
+  void TriggerReconcile(MutableEntry* mutable_entry,
+                        bool trigger_by_syncing = true,
+                        sync_pb::EntitySpecifics* specifics = nullptr) {
+    mutable_entry->PutSyncing(trigger_by_syncing);
+    mutable_entry->PutIsUnsynced(trigger_by_syncing);
+    if (specifics == nullptr) {
+      RecordChange(mutable_entry, 0);
+    } else {
+      RecordChange(mutable_entry, *specifics);
+    }
+  }
+
+ private:
+  base::MessageLoop message_loop;
+  id_type _id;
+  LostNavigationsRecorder recorder_;
+  syncer::TestDirectorySetterUpper dir_maker_;
+};
+
+TEST_F(LostNavigationsRecorderTest, MultipleNavsNoneLost) {
+  base::HistogramTester histogram_tester;
+  const Id& id = CreateEntry();
+  WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+  MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+  mutable_entry.PutIsUnsynced(true);
+
+  RecordChange(&mutable_entry, 6);
+
+  TriggerReconcile(&mutable_entry);
+  histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 0, 1);
+}
+
+TEST_F(LostNavigationsRecorderTest, MultipleNavsOneLost) {
+  base::HistogramTester histogram_tester;
+  const Id& id = CreateEntry();
+  WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+  MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+  mutable_entry.PutIsUnsynced(true);
+
+  RecordChange(&mutable_entry, 1);
+  RecordChange(&mutable_entry, 1);
+
+  TriggerReconcile(&mutable_entry);
+
+  histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 1, 1);
+}
+
+TEST_F(LostNavigationsRecorderTest, MultipleNavsMultipleLost) {
+  base::HistogramTester histogram_tester;
+  const Id& id = CreateEntry();
+  WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+  MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+  mutable_entry.PutIsUnsynced(true);
+
+  RecordChange(&mutable_entry, 5);
+  RecordChange(&mutable_entry, 1);
+
+  TriggerReconcile(&mutable_entry);
+  histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 5, 1);
+}
+
+TEST_F(LostNavigationsRecorderTest, MultipleWritesWhileSyncing) {
+  base::HistogramTester histogram_tester;
+  const Id& id = CreateEntry();
+  WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+  MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+
+  sync_pb::EntitySpecifics specifics;
+  BuildTabSpecifics(kTab1SyncTag, 1, specifics.mutable_session(), 5);
+  mutable_entry.PutIsUnsynced(true);
+  RecordChange(&mutable_entry, specifics);
+
+  mutable_entry.PutSyncing(true);
+  RecordChange(&mutable_entry, specifics);
+
+  specifics.mutable_session()->mutable_tab()->clear_navigation();
+  for (int i = 0; i < 5; i++) {
+    AddNavigation(specifics.mutable_session());
+    RecordChange(&mutable_entry, specifics);
+  }
+
+  TriggerReconcile(&mutable_entry, false);
+  histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 0, 1);
+}
+
+TEST_F(LostNavigationsRecorderTest, MultipleWritesMultipleEntriesNoneLost) {
+  base::HistogramTester histogram_tester;
+  const Id& id = CreateEntry();
+  const Id& id2 = CreateEntry();
+  WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+  MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+  MutableEntry mutable_entry2(&wtrans, syncer::syncable::GET_BY_ID, id2);
+  mutable_entry.PutIsUnsynced(true);
+  mutable_entry2.PutIsUnsynced(true);
+
+  sync_pb::EntitySpecifics specifics;
+  sync_pb::EntitySpecifics specifics2;
+  BuildTabSpecifics(kTab1SyncTag, 1, specifics.mutable_session(), 5);
+  BuildTabSpecifics(kTab2SyncTag, 2, specifics2.mutable_session(), 5);
+  RecordChange(&mutable_entry, specifics);
+  RecordChange(&mutable_entry2, specifics2);
+
+  mutable_entry.PutSyncing(true);
+  mutable_entry2.PutSyncing(true);
+  RecordChange(&mutable_entry, specifics);
+  RecordChange(&mutable_entry2, specifics2);
+
+  specifics.mutable_session()->mutable_tab()->clear_navigation();
+  specifics2.mutable_session()->mutable_tab()->clear_navigation();
+  for (int i = 0; i < 5; i++) {
+    AddNavigation(specifics.mutable_session());
+    AddNavigation(specifics2.mutable_session());
+
+    RecordChange(&mutable_entry, specifics);
+    RecordChange(&mutable_entry2, specifics2);
+  }
+
+  TriggerReconcile(&mutable_entry, false, &specifics);
+  TriggerReconcile(&mutable_entry2, false, &specifics2);
+
+  histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 0, 4);
+}
+
+TEST_F(LostNavigationsRecorderTest, MultipleWritesMultipleEntriesMultipleLost) {
+  base::HistogramTester histogram_tester;
+  const Id& id = CreateEntry();
+  const Id& id2 = CreateEntry();
+  WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+  MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+  MutableEntry mutable_entry2(&wtrans, syncer::syncable::GET_BY_ID, id2);
+  mutable_entry.PutIsUnsynced(true);
+  mutable_entry2.PutIsUnsynced(true);
+
+  sync_pb::EntitySpecifics specifics;
+  sync_pb::EntitySpecifics specifics2;
+  BuildTabSpecifics(kTab1SyncTag, 1, specifics.mutable_session(), 5);
+  BuildTabSpecifics(kTab2SyncTag, 2, specifics2.mutable_session(), 5);
+  RecordChange(&mutable_entry, specifics);
+  RecordChange(&mutable_entry2, specifics2);
+
+  mutable_entry.PutSyncing(true);
+  mutable_entry2.PutSyncing(true);
+  RecordChange(&mutable_entry, specifics);
+  RecordChange(&mutable_entry2, specifics2);
+
+  specifics.mutable_session()->mutable_tab()->clear_navigation();
+  specifics2.mutable_session()->mutable_tab()->clear_navigation();
+  for (int i = 0; i < 5; i++) {
+    AddNavigation(specifics.mutable_session());
+    AddNavigation(specifics2.mutable_session());
+
+    RecordChange(&mutable_entry, specifics);
+    RecordChange(&mutable_entry2, specifics2);
+  }
+
+  specifics.mutable_session()
+      ->mutable_tab()
+      ->mutable_navigation()
+      ->DeleteSubrange(0, 2);
+  specifics2.mutable_session()
+      ->mutable_tab()
+      ->mutable_navigation()
+      ->DeleteSubrange(0, 2);
+  RecordChange(&mutable_entry, specifics);
+  RecordChange(&mutable_entry, specifics2);
+
+  TriggerReconcile(&mutable_entry, false, &specifics);
+  TriggerReconcile(&mutable_entry2, false, &specifics2);
+
+  histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 2, 2);
+}
+
+TEST_F(LostNavigationsRecorderTest, NoWritesWhileSyncingMultipleLost) {
+  base::HistogramTester histogram_tester;
+  const Id& id = CreateEntry();
+  WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+  MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+
+  sync_pb::EntitySpecifics specifics;
+  BuildTabSpecifics(kTab1SyncTag, 1, specifics.mutable_session(), 5);
+  syncer::SyncChange change = MakeChange(kTab1SyncTag, specifics.session(),
+                                         syncer::SyncChange::ACTION_UPDATE);
+  mutable_entry.PutIsUnsynced(true);
+  recorder()->OnLocalChange(&mutable_entry, change);
+
+  specifics.mutable_session()->mutable_tab()->clear_navigation();
+  AddNavigation(specifics.mutable_session());
+  change = MakeChange(kTab1SyncTag, specifics.session(),
+                      syncer::SyncChange::ACTION_UPDATE);
+  recorder()->OnLocalChange(&mutable_entry, change);
+
+  mutable_entry.PutIsUnsynced(false);
+  recorder()->OnLocalChange(&mutable_entry, change);
+  histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 5, 1);
+}
+
+TEST_F(LostNavigationsRecorderTest, WindowChangeDoesNotTriggerReconcile) {
+  base::HistogramTester histogram_tester;
+  const Id& id = CreateEntry();
+  const Id& id2 = CreateEntry();
+  WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+  MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+  MutableEntry mutable_entry2(&wtrans, syncer::syncable::GET_BY_ID, id2);
+  mutable_entry.PutIsUnsynced(true);
+
+  RecordChange(&mutable_entry, 1);
+
+  sync_pb::EntitySpecifics specifics;
+  BuildWindowSpecifics(1, specifics.mutable_session());
+  RecordChange(&mutable_entry2, specifics);
+
+  EXPECT_EQ(0ul,
+            histogram_tester.GetAllSamples("Sync.LostNavigationCount").size());
+}
+
+TEST_F(LostNavigationsRecorderTest, Samutable_entryNavigationSetAcrossStates) {
+  base::HistogramTester histogram_tester;
+  const Id& id = CreateEntry();
+  WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+  MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+
+  sync_pb::EntitySpecifics specifics;
+  BuildTabSpecifics(kTab1SyncTag, 1, specifics.mutable_session(), 5);
+  syncer::SyncChange change = MakeChange(kTab1SyncTag, specifics.session(),
+                                         syncer::SyncChange::ACTION_UPDATE);
+  mutable_entry.PutIsUnsynced(true);
+  recorder()->OnLocalChange(&mutable_entry, change);
+  recorder()->OnLocalChange(&mutable_entry, change);
+
+  mutable_entry.PutIsUnsynced(false);
+  recorder()->OnLocalChange(&mutable_entry, change);
+  histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 0, 1);
+}
+
+TEST_F(LostNavigationsRecorderTest, RevisitPreviousNavs) {
+  base::HistogramTester histogram_tester;
+  const Id& id = CreateEntry();
+  WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+  MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+  mutable_entry.PutIsUnsynced(true);
+
+  sync_pb::EntitySpecifics specifics;
+  BuildTabSpecifics(kTab1SyncTag, 1, specifics.mutable_session(), 3);
+  RecordChange(&mutable_entry, specifics);
+
+  AddNavigation(specifics.mutable_session());
+  RecordChange(&mutable_entry, specifics);
+
+  specifics.mutable_session()
+      ->mutable_tab()
+      ->mutable_navigation()
+      ->RemoveLast();
+  RecordChange(&mutable_entry, specifics);
+
+  TriggerReconcile(&mutable_entry, true, &specifics);
+
+  histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 1, 1);
+}
+
+TEST_F(LostNavigationsRecorderTest, MultipleNavsMultipleLostWithOverlap) {
+  base::HistogramTester histogram_tester;
+  const Id& id = CreateEntry();
+  WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+  MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+  mutable_entry.PutIsUnsynced(true);
+
+  sync_pb::EntitySpecifics specifics;
+  BuildTabSpecifics(kTab1SyncTag, 1, specifics.mutable_session(), 5);
+  RecordChange(&mutable_entry, specifics);
+
+  AddNavigation(specifics.mutable_session());
+  AddNavigation(specifics.mutable_session());
+
+  specifics.mutable_session()
+      ->mutable_tab()
+      ->mutable_navigation()
+      ->DeleteSubrange(0, 2);
+  RecordChange(&mutable_entry, specifics);
+
+  TriggerReconcile(&mutable_entry, true, &specifics);
+
+  histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 2, 1);
+}
+
+};  // namespace
+};  // namespace sync_sessions
diff --git a/components/sync_sessions/sessions_sync_manager.cc b/components/sync_sessions/sessions_sync_manager.cc
index a1e5d13..fd7fd50 100644
--- a/components/sync_sessions/sessions_sync_manager.cc
+++ b/components/sync_sessions/sessions_sync_manager.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 #include <utility>
 
+#include "base/memory/ptr_util.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram_macros.h"
 #include "build/build_config.h"
@@ -16,6 +17,7 @@
 #include "components/sync/api/time.h"
 #include "components/sync/device_info/local_device_info_provider.h"
 #include "components/sync/syncable/syncable_util.h"
+#include "components/sync_sessions/lost_navigations_recorder.h"
 #include "components/sync_sessions/sync_sessions_client.h"
 #include "components/sync_sessions/synced_tab_delegate.h"
 #include "components/sync_sessions/synced_window_delegate.h"
@@ -77,7 +79,7 @@
 // |local_device| is owned by ProfileSyncService, its lifetime exceeds
 // lifetime of SessionSyncManager.
 SessionsSyncManager::SessionsSyncManager(
-    SyncSessionsClient* sessions_client,
+    sync_sessions::SyncSessionsClient* sessions_client,
     sync_driver::SyncPrefs* sync_prefs,
     LocalDeviceInfoProvider* local_device,
     std::unique_ptr<LocalSessionEventRouter> router,
@@ -120,6 +122,10 @@
   error_handler_ = std::move(error_handler);
   sync_processor_ = std::move(sync_processor);
 
+  lost_navigations_recorder_ =
+      base::MakeUnique<sync_sessions::LostNavigationsRecorder>();
+  sync_processor_->AddLocalChangeObserver(lost_navigations_recorder_.get());
+
   local_session_header_node_id_ = TabNodePool::kInvalidTabNodeID;
 
   // Make sure we have a machine tag.  We do this now (versus earlier) as it's
@@ -436,8 +442,13 @@
 
 void SessionsSyncManager::StopSyncing(syncer::ModelType type) {
   local_event_router_->Stop();
+  if (sync_processor_.get() && lost_navigations_recorder_.get()) {
+    sync_processor_->RemoveLocalChangeObserver(
+        lost_navigations_recorder_.get());
+  }
   sync_processor_.reset(NULL);
   error_handler_.reset();
+  lost_navigations_recorder_.reset();
   session_tracker_.Clear();
   local_tab_map_.clear();
   local_tab_pool_.Clear();
diff --git a/components/sync_sessions/sessions_sync_manager.h b/components/sync_sessions/sessions_sync_manager.h
index 6735bcc..360601b 100644
--- a/components/sync_sessions/sessions_sync_manager.h
+++ b/components/sync_sessions/sessions_sync_manager.h
@@ -25,6 +25,7 @@
 #include "components/sync/driver/sync_prefs.h"
 #include "components/sync_sessions/favicon_cache.h"
 #include "components/sync_sessions/local_session_event_router.h"
+#include "components/sync_sessions/lost_navigations_recorder.h"
 #include "components/sync_sessions/open_tabs_ui_delegate.h"
 #include "components/sync_sessions/revisit/page_revisit_broadcaster.h"
 #include "components/sync_sessions/synced_session.h"
@@ -370,6 +371,9 @@
   // Owns revisiting instrumentation logic for page visit events.
   PageRevisitBroadcaster page_revisit_broadcaster_;
 
+  std::unique_ptr<sync_sessions::LostNavigationsRecorder>
+      lost_navigations_recorder_;
+
   // Callback to inform interested observer that new sessions data has arrived.
   base::Closure sessions_updated_callback_;
 
diff --git a/components/test_runner/mock_web_user_media_client.cc b/components/test_runner/mock_web_user_media_client.cc
index bd774a0..bc4e1bb 100644
--- a/components/test_runner/mock_web_user_media_client.cc
+++ b/components/test_runner/mock_web_user_media_client.cc
@@ -151,10 +151,6 @@
     media_device_change_observer_.didChangeMediaDevices();
 }
 
-void MockWebUserMediaClient::cancelMediaDevicesRequest(
-    const WebMediaDevicesRequest&) {
-}
-
 void MockWebUserMediaClient::requestSources(
     const blink::WebMediaStreamTrackSourcesRequest& request) {
   struct {
diff --git a/components/test_runner/mock_web_user_media_client.h b/components/test_runner/mock_web_user_media_client.h
index f381417..374e336 100644
--- a/components/test_runner/mock_web_user_media_client.h
+++ b/components/test_runner/mock_web_user_media_client.h
@@ -22,7 +22,6 @@
   void requestUserMedia(const blink::WebUserMediaRequest&) override;
   void cancelUserMediaRequest(const blink::WebUserMediaRequest&) override;
   void requestMediaDevices(const blink::WebMediaDevicesRequest&) override;
-  void cancelMediaDevicesRequest(const blink::WebMediaDevicesRequest&) override;
   void requestSources(const blink::WebMediaStreamTrackSourcesRequest&) override;
   void setMediaDeviceChangeObserver(
       const blink::WebMediaDeviceChangeObserver&) override;
diff --git a/components/user_prefs/tracked/pref_hash_filter.cc b/components/user_prefs/tracked/pref_hash_filter.cc
index 42ce04a..d72a5c6 100644
--- a/components/user_prefs/tracked/pref_hash_filter.cc
+++ b/components/user_prefs/tracked/pref_hash_filter.cc
@@ -156,7 +156,7 @@
 // Updates the stored hashes for |changed_paths_| before serializing data to
 // disk. This is required as storing the hash everytime a pref's value changes
 // is too expensive (see perf regression @ http://crbug.com/331273).
-void PrefHashFilter::FilterSerializeData(
+PrefFilter::OnWriteCallbackPair PrefHashFilter::FilterSerializeData(
     base::DictionaryValue* pref_store_contents) {
   if (!changed_paths_.empty()) {
     base::TimeTicks checkpoint = base::TimeTicks::Now();
@@ -180,6 +180,9 @@
     UMA_HISTOGRAM_TIMES("Settings.FilterSerializeDataTime",
                         base::TimeTicks::Now() - checkpoint);
   }
+
+  // TODO(proberge): return callbacks if external validation is enabled.
+  return std::make_pair(base::Closure(), base::Callback<void(bool success)>());
 }
 
 void PrefHashFilter::FinalizeFilterOnLoad(
diff --git a/components/user_prefs/tracked/pref_hash_filter.h b/components/user_prefs/tracked/pref_hash_filter.h
index 8652a7f..fae8dcd 100644
--- a/components/user_prefs/tracked/pref_hash_filter.h
+++ b/components/user_prefs/tracked/pref_hash_filter.h
@@ -101,7 +101,8 @@
 
   // PrefFilter remaining implementation.
   void FilterUpdate(const std::string& path) override;
-  void FilterSerializeData(base::DictionaryValue* pref_store_contents) override;
+  OnWriteCallbackPair FilterSerializeData(
+      base::DictionaryValue* pref_store_contents) override;
 
  private:
   // InterceptablePrefFilter implementation.
diff --git a/components/user_prefs/tracked/tracked_preferences_migration_unittest.cc b/components/user_prefs/tracked/tracked_preferences_migration_unittest.cc
index 3340649f..b113754 100644
--- a/components/user_prefs/tracked/tracked_preferences_migration_unittest.cc
+++ b/components/user_prefs/tracked/tracked_preferences_migration_unittest.cc
@@ -47,9 +47,11 @@
  public:
   // PrefFilter remaining implementation.
   void FilterUpdate(const std::string& path) override { ADD_FAILURE(); }
-  void FilterSerializeData(
+  OnWriteCallbackPair FilterSerializeData(
       base::DictionaryValue* pref_store_contents) override {
     ADD_FAILURE();
+    return std::make_pair(base::Closure(),
+                          base::Callback<void(bool success)>());
   }
 
  private:
diff --git a/components/web_contents_delegate_android/android/java/src/org/chromium/components/web_contents_delegate_android/WebContentsDelegateAndroid.java b/components/web_contents_delegate_android/android/java/src/org/chromium/components/web_contents_delegate_android/WebContentsDelegateAndroid.java
index fe55dce..c1cc9be 100644
--- a/components/web_contents_delegate_android/android/java/src/org/chromium/components/web_contents_delegate_android/WebContentsDelegateAndroid.java
+++ b/components/web_contents_delegate_android/android/java/src/org/chromium/components/web_contents_delegate_android/WebContentsDelegateAndroid.java
@@ -8,6 +8,7 @@
 
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
+import org.chromium.content.browser.ContentVideoViewEmbedder;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.common.ResourceRequestBody;
 
@@ -153,4 +154,19 @@
     public boolean isFullscreenForTabOrPending() {
         return false;
     }
+
+    @CalledByNative
+    public ContentVideoViewEmbedder getContentVideoViewEmbedder() {
+        return null;
+    }
+
+    /**
+     * Called when BrowserMediaPlayerManager wants to load a media resource.
+     * @param url the URL of media resource to load.
+     * @return true to prevent the resource from being loaded.
+     */
+    @CalledByNative
+    public boolean shouldBlockMediaRequest(String url) {
+        return false;
+    }
 }
diff --git a/components/web_contents_delegate_android/web_contents_delegate_android.cc b/components/web_contents_delegate_android/web_contents_delegate_android.cc
index 7d6c23a..8e309d5a 100644
--- a/components/web_contents_delegate_android/web_contents_delegate_android.cc
+++ b/components/web_contents_delegate_android/web_contents_delegate_android.cc
@@ -327,6 +327,25 @@
   Java_WebContentsDelegateAndroid_showRepostFormWarningDialog(env, obj);
 }
 
+ScopedJavaLocalRef<jobject>
+WebContentsDelegateAndroid::GetContentVideoViewEmbedder() {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
+  if (obj.is_null())
+    return ScopedJavaLocalRef<jobject>();
+
+  return Java_WebContentsDelegateAndroid_getContentVideoViewEmbedder(env, obj);
+}
+
+bool WebContentsDelegateAndroid::ShouldBlockMediaRequest(const GURL& url) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
+  if (obj.is_null())
+    return false;
+  ScopedJavaLocalRef<jstring> j_url = ConvertUTF8ToJavaString(env, url.spec());
+  return Java_WebContentsDelegateAndroid_shouldBlockMediaRequest(env, obj, j_url);
+}
+
 void WebContentsDelegateAndroid::EnterFullscreenModeForTab(
     WebContents* web_contents,
     const GURL& origin) {
diff --git a/components/web_contents_delegate_android/web_contents_delegate_android.h b/components/web_contents_delegate_android/web_contents_delegate_android.h
index e349d17f..e4d63c199 100644
--- a/components/web_contents_delegate_android/web_contents_delegate_android.h
+++ b/components/web_contents_delegate_android/web_contents_delegate_android.h
@@ -101,6 +101,9 @@
       const content::NativeWebKeyboardEvent& event) override;
   bool TakeFocus(content::WebContents* source, bool reverse) override;
   void ShowRepostFormWarningDialog(content::WebContents* source) override;
+  base::android::ScopedJavaLocalRef<jobject>
+      GetContentVideoViewEmbedder() override;
+  bool ShouldBlockMediaRequest(const GURL& url) override;
   void EnterFullscreenModeForTab(content::WebContents* web_contents,
                                  const GURL& origin) override;
   void ExitFullscreenModeForTab(content::WebContents* web_contents) override;
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index eefa129..dcad8ba7 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -57,6 +57,7 @@
     "//content/public/common:common_sources",
     "//crypto",
     "//device/battery",
+    "//device/battery:mojo_bindings",
     "//device/bluetooth",
     "//device/gamepad",
     "//device/generic_sensor",
@@ -1074,17 +1075,11 @@
     "renderer_host/media/shared_memory_buffer_handle.h",
     "renderer_host/media/shared_memory_buffer_tracker.cc",
     "renderer_host/media/shared_memory_buffer_tracker.h",
-    "renderer_host/media/video_capture_buffer_handle.h",
-    "renderer_host/media/video_capture_buffer_pool.cc",
-    "renderer_host/media/video_capture_buffer_pool.h",
-    "renderer_host/media/video_capture_buffer_tracker.h",
-    "renderer_host/media/video_capture_buffer_tracker_factory.cc",
-    "renderer_host/media/video_capture_buffer_tracker_factory.h",
+    "renderer_host/media/video_capture_buffer_tracker_factory_impl.cc",
+    "renderer_host/media/video_capture_buffer_tracker_factory_impl.h",
     "renderer_host/media/video_capture_controller.cc",
     "renderer_host/media/video_capture_controller.h",
     "renderer_host/media/video_capture_controller_event_handler.h",
-    "renderer_host/media/video_capture_device_client.cc",
-    "renderer_host/media/video_capture_device_client.h",
     "renderer_host/media/video_capture_gpu_jpeg_decoder.cc",
     "renderer_host/media/video_capture_gpu_jpeg_decoder.h",
     "renderer_host/media/video_capture_host.cc",
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index 26e5b48..afcbd003 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -414,7 +414,7 @@
       else
         start = 0;
     }
-    return RelativeToAbsoluteBounds(gfx::RectF(bounds), false);
+    return bounds;
   }
 
   int end = start + len;
@@ -457,7 +457,7 @@
     int end_pixel_offset =
         local_end > 0 ? character_offsets[local_end - 1] : 0;
 
-    gfx::Rect child_rect = gfx::ToEnclosingRect(child->GetLocation());
+    gfx::Rect child_rect = child->GetPageBoundsRect();
     auto text_direction = static_cast<ui::AXTextDirection>(
         child->GetIntAttribute(ui::AX_ATTR_TEXT_DIRECTION));
     gfx::Rect child_overlap_rect;
@@ -501,7 +501,7 @@
       bounds.Union(child_overlap_rect);
   }
 
-  return RelativeToAbsoluteBounds(gfx::RectF(bounds), false);
+  return bounds;
 }
 
 gfx::Rect BrowserAccessibility::GetScreenBoundsForRange(int start, int len)
diff --git a/content/browser/android/content_video_view.cc b/content/browser/android/content_video_view.cc
index 9b919e8..4df61ff 100644
--- a/content/browser/android/content_video_view.cc
+++ b/content/browser/android/content_video_view.cc
@@ -16,6 +16,7 @@
 using base::android::AttachCurrentThread;
 using base::android::CheckException;
 using base::android::JavaParamRef;
+using base::android::JavaRef;
 using base::android::ScopedJavaGlobalRef;
 using base::android::ScopedJavaLocalRef;
 using base::UserMetricsAction;
@@ -49,11 +50,12 @@
 
 ContentVideoView::ContentVideoView(Client* client,
                                    ContentViewCore* content_view_core,
+                                   const JavaRef<jobject>& video_embedder,
                                    const gfx::Size& video_natural_size)
     : client_(client), weak_factory_(this) {
   DCHECK(!g_content_video_view);
   j_content_video_view_ =
-      CreateJavaObject(content_view_core, video_natural_size);
+      CreateJavaObject(content_view_core, video_embedder, video_natural_size);
   g_content_video_view = this;
 }
 
@@ -162,16 +164,19 @@
 
 JavaObjectWeakGlobalRef ContentVideoView::CreateJavaObject(
     ContentViewCore* content_view_core,
+    const JavaRef<jobject>& j_content_video_view_embedder,
     const gfx::Size& video_natural_size) {
   JNIEnv* env = AttachCurrentThread();
   base::android::ScopedJavaLocalRef<jobject> j_content_view_core =
       content_view_core->GetJavaObject();
+
   if (j_content_view_core.is_null())
     return JavaObjectWeakGlobalRef(env, nullptr);
 
   return JavaObjectWeakGlobalRef(
       env, Java_ContentVideoView_createContentVideoView(
-               env, j_content_view_core, reinterpret_cast<intptr_t>(this),
+               env, j_content_view_core, j_content_video_view_embedder,
+               reinterpret_cast<intptr_t>(this),
                video_natural_size.width(), video_natural_size.height())
                .obj());
 }
diff --git a/content/browser/android/content_video_view.h b/content/browser/android/content_video_view.h
index 7efe330..cb9c0d3 100644
--- a/content/browser/android/content_video_view.h
+++ b/content/browser/android/content_video_view.h
@@ -46,6 +46,7 @@
 
   explicit ContentVideoView(Client* client,
                             ContentViewCore* content_view_core,
+                            const base::android::JavaRef<jobject>& embedder,
                             const gfx::Size& video_natural_size);
   ~ContentVideoView();
 
@@ -90,8 +91,10 @@
 
  private:
   // Creates the corresponding ContentVideoView Java object.
-  JavaObjectWeakGlobalRef CreateJavaObject(ContentViewCore* content_view_core,
-                                           const gfx::Size& video_natural_size);
+  JavaObjectWeakGlobalRef CreateJavaObject(
+      ContentViewCore* content_view_core,
+      const base::android::JavaRef<jobject>& j_content_video_view_embedder,
+      const gfx::Size& video_natural_size);
 
   Client* client_;
 
diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc
index 2a0b665e..7854c3e 100644
--- a/content/browser/android/content_view_core_impl.cc
+++ b/content/browser/android/content_view_core_impl.cc
@@ -707,16 +707,6 @@
   return Java_ContentViewCore_createMotionEventSynthesizer(env, obj);
 }
 
-bool ContentViewCoreImpl::ShouldBlockMediaRequest(const GURL& url) {
-  JNIEnv* env = AttachCurrentThread();
-
-  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
-  if (obj.is_null())
-    return true;
-  ScopedJavaLocalRef<jstring> j_url = ConvertUTF8ToJavaString(env, url.spec());
-  return Java_ContentViewCore_shouldBlockMediaRequest(env, obj, j_url);
-}
-
 void ContentViewCoreImpl::DidStopFlinging() {
   JNIEnv* env = AttachCurrentThread();
 
diff --git a/content/browser/android/content_view_core_impl.h b/content/browser/android/content_view_core_impl.h
index c7fb4f30..387d4a5 100644
--- a/content/browser/android/content_view_core_impl.h
+++ b/content/browser/android/content_view_core_impl.h
@@ -358,9 +358,6 @@
   // testing/benchmarking purposes.
   base::android::ScopedJavaLocalRef<jobject> CreateMotionEventSynthesizer();
 
-  // Returns True if the given media should be blocked to load.
-  bool ShouldBlockMediaRequest(const GURL& url);
-
   void DidStopFlinging();
 
   // Returns the context with which the ContentViewCore was created, typically
diff --git a/content/browser/bluetooth/tools/bluetooth_metrics_hash.cc b/content/browser/bluetooth/tools/bluetooth_metrics_hash.cc
index 1b50283..35f96f2 100644
--- a/content/browser/bluetooth/tools/bluetooth_metrics_hash.cc
+++ b/content/browser/bluetooth/tools/bluetooth_metrics_hash.cc
@@ -9,7 +9,7 @@
 #include "device/bluetooth/bluetooth_uuid.h"
 
 int main(int argc, char** argv) {
-  if (argc <= 1) {
+  if (argc <= 2) {
     std::cout << "Generates hash values given UUIDs using the same method\n"
               << "as in bluetooth_metrics.cc.\n"
               << "\n"
@@ -17,21 +17,22 @@
               << "Note that tools/metrics/histograms/pretty_print.py will\n"
               << "sort enum entries for you.\n"
               << "\n"
-              << "Usage: " << argv[0] << " <uuid> [uuid2 ...]\n"
+              << "Usage: " << argv[0] << " <uuid> <label> [uuid2 label2...]\n"
               << "       The UUIDs may be short UUIDs, and will be made\n"
               << "       canonical before being hashed.\n"
               << "\n"
-              << "Example: " << argv[0] << " FEFF FEFE\n"
+              << "Example: " << argv[0] << " FEFF foo FEFE bar\n"
               << "  <int value=\"62669585\" "
-                 "label=\"0000feff-0000-1000-8000-00805f9b34fb\"/>\n"
+                 "label=\"foo; 0000feff-0000-1000-8000-00805f9b34fb\"/>\n"
               << "  <int value=\"643543662\" "
-                 "label=\"0000fefe-0000-1000-8000-00805f9b34fb\"/>\n";
+                 "label=\"bar; 0000fefe-0000-1000-8000-00805f9b34fb\"/>\n";
     return 1;
   }
 
-  for (int i = 1; i < argc; i++) {
-    std::string input_string(argv[i]);
-    device::BluetoothUUID uuid(input_string);
+  for (int i = 1; i < argc; i = i + 2) {
+    std::string uuid_string(argv[i]);
+    std::string label_string((i + 1 < argc) ? argv[i + 1] : "");
+    device::BluetoothUUID uuid(uuid_string);
     std::string uuid_canonical_string = uuid.canonical_value();
     uint32_t hash = base::SuperFastHash(uuid_canonical_string.data(),
                                         uuid_canonical_string.size());
@@ -40,8 +41,8 @@
     // but takes a signed int as input.
     hash &= 0x7fffffff;
 
-    std::cout << "  <int value=\"" << hash << "\" label=\""
-              << uuid_canonical_string << "\"/>\n";
+    std::cout << "  <int value=\"" << hash << "\" label=\"" << label_string
+              << "; " << uuid_canonical_string << "\"/>\n";
   }
   return 0;
 }
diff --git a/content/browser/cross_site_transfer_browsertest.cc b/content/browser/cross_site_transfer_browsertest.cc
index 9ac51f6..8a4a836 100644
--- a/content/browser/cross_site_transfer_browsertest.cc
+++ b/content/browser/cross_site_transfer_browsertest.cc
@@ -154,7 +154,7 @@
  public:
   NoTransferRequestDelegate() {}
 
-  bool ShouldTransferNavigation() override {
+  bool ShouldTransferNavigation(bool is_main_frame_navigation) override {
     // Intentionally cancel the transfer.
     return false;
   }
diff --git a/content/browser/devtools/browser_devtools_agent_host.cc b/content/browser/devtools/browser_devtools_agent_host.cc
index 2f8bc9e..8fd6a52 100644
--- a/content/browser/devtools/browser_devtools_agent_host.cc
+++ b/content/browser/devtools/browser_devtools_agent_host.cc
@@ -7,7 +7,6 @@
 #include "base/bind.h"
 #include "base/guid.h"
 #include "content/browser/devtools/devtools_protocol_handler.h"
-#include "content/browser/devtools/protocol/browser_handler.h"
 #include "content/browser/devtools/protocol/io_handler.h"
 #include "content/browser/devtools/protocol/memory_handler.h"
 #include "content/browser/devtools/protocol/system_info_handler.h"
@@ -27,7 +26,6 @@
     scoped_refptr<base::SingleThreadTaskRunner> tethering_task_runner,
     const CreateServerSocketCallback& socket_callback)
     : DevToolsAgentHostImpl(base::GenerateGUID()),
-      browser_handler_(new devtools::browser::BrowserHandler()),
       io_handler_(new devtools::io::IOHandler(GetIOContext())),
       memory_handler_(new devtools::memory::MemoryHandler()),
       system_info_handler_(new devtools::system_info::SystemInfoHandler()),
@@ -40,7 +38,6 @@
           GetIOContext())),
       protocol_handler_(new DevToolsProtocolHandler(this)) {
   DevToolsProtocolDispatcher* dispatcher = protocol_handler_->dispatcher();
-  dispatcher->SetBrowserHandler(browser_handler_.get());
   dispatcher->SetIOHandler(io_handler_.get());
   dispatcher->SetMemoryHandler(memory_handler_.get());
   dispatcher->SetSystemInfoHandler(system_info_handler_.get());
diff --git a/content/browser/devtools/browser_devtools_agent_host.h b/content/browser/devtools/browser_devtools_agent_host.h
index 6e2f66e..527fc5f 100644
--- a/content/browser/devtools/browser_devtools_agent_host.h
+++ b/content/browser/devtools/browser_devtools_agent_host.h
@@ -12,7 +12,6 @@
 class DevToolsProtocolHandler;
 
 namespace devtools {
-namespace browser { class BrowserHandler; }
 namespace io { class IOHandler; }
 namespace memory { class MemoryHandler; }
 namespace system_info { class SystemInfoHandler; }
@@ -41,7 +40,6 @@
   bool Close() override;
   bool DispatchProtocolMessage(const std::string& message) override;
 
-  std::unique_ptr<devtools::browser::BrowserHandler> browser_handler_;
   std::unique_ptr<devtools::io::IOHandler> io_handler_;
   std::unique_ptr<devtools::memory::MemoryHandler> memory_handler_;
   std::unique_ptr<devtools::system_info::SystemInfoHandler>
diff --git a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
index 2a6d27c..8be20751 100644
--- a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
+++ b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
@@ -358,7 +358,7 @@
   }
 
   void AgentHostClosed(DevToolsAgentHost* agent_host, bool replaced) override {
-    EXPECT_TRUE(false);
+    DCHECK(false);
   }
 
   std::string waiting_for_notification_;
@@ -838,6 +838,27 @@
   EXPECT_TRUE(success);
 }
 
+// CrashTab() works differently on Windows, leading to RFH removal before
+// RenderProcessGone is called. TODO(dgozman): figure out the problem.
+#if defined(OS_WIN)
+#define MAYBE_DoubleCrash DISABLED_DoubleCrash
+#else
+#define MAYBE_DoubleCrash DoubleCrash
+#endif
+IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, MAYBE_DoubleCrash) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL test_url = embedded_test_server()->GetURL("/devtools/navigation.html");
+  NavigateToURLBlockUntilNavigationsComplete(shell(), GURL("about:blank"), 1);
+  Attach();
+  SendCommand("ServiceWorker.enable", nullptr);
+  NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
+  CrashTab(shell()->web_contents());
+  NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
+  CrashTab(shell()->web_contents());
+  NavigateToURLBlockUntilNavigationsComplete(shell(), GURL("about:blank"), 1);
+  // Should not crash at this point.
+}
+
 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, ReloadBlankPage) {
   Shell* window =  Shell::CreateNewWindow(
       shell()->web_contents()->GetBrowserContext(),
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc
index 9a85982..1945bde 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -330,6 +330,7 @@
   if (agent_host->pending_ && agent_host->pending_->host() == pending) {
     DCHECK(agent_host->current_ && agent_host->current_->host() == current);
     agent_host->DiscardPending();
+    DCHECK(agent_host->CheckConsistency());
   }
 }
 
@@ -394,6 +395,7 @@
       emulation_handler_(nullptr),
       frame_trace_recorder_(nullptr),
       protocol_handler_(new DevToolsProtocolHandler(this)),
+      handlers_frame_host_(nullptr),
       current_frame_crashed_(false),
       pending_handle_(nullptr),
       frame_tree_node_(host->frame_tree_node()) {
@@ -583,7 +585,14 @@
   if (current_->host() != render_frame_host_impl || current_frame_crashed_) {
     SetPending(render_frame_host_impl);
     pending_handle_ = navigation_handle;
+    // Commit when navigating the same frame after crash, avoiding the same
+    // host in current_ and pending_.
+    if (current_->host() == render_frame_host_impl) {
+      pending_handle_ = nullptr;
+      CommitPending();
+    }
   }
+  DCHECK(CheckConsistency());
 }
 
 void RenderFrameDevToolsAgentHost::DidFinishNavigation(
@@ -612,6 +621,7 @@
   }
   DispatchBufferedProtocolMessagesIfNecessary();
 
+  DCHECK(CheckConsistency());
   if (navigation_handle->HasCommitted())
     target_handler_->UpdateServiceWorkers();
 }
@@ -623,12 +633,21 @@
     return;
 
   DCHECK(!pending_ || pending_->host() != old_host);
-  if (!current_ || current_->host() != old_host)
+  if (!current_ || current_->host() != old_host) {
+    DCHECK(CheckConsistency());
     return;
-  if (old_host == new_host && !current_frame_crashed_)
+  }
+  if (old_host == new_host && !current_frame_crashed_) {
+    DCHECK(CheckConsistency());
     return;
+  }
   DCHECK(!pending_);
   SetPending(static_cast<RenderFrameHostImpl*>(new_host));
+  // Commit when navigating the same frame after crash, avoiding the same
+  // host in current_ and pending_.
+  if (old_host == new_host)
+    CommitPending();
+  DCHECK(CheckConsistency());
 }
 
 void RenderFrameDevToolsAgentHost::AboutToNavigate(
@@ -637,6 +656,7 @@
     return;
   DCHECK(current_);
   navigating_handles_.insert(navigation_handle);
+  DCHECK(CheckConsistency());
 }
 
 void RenderFrameDevToolsAgentHost::RenderFrameHostChanged(
@@ -646,21 +666,24 @@
     return;
 
   DCHECK(!pending_ || pending_->host() != old_host);
-  if (!current_ || current_->host() != old_host)
+  if (!current_ || current_->host() != old_host) {
+    DCHECK(CheckConsistency());
     return;
+  }
 
   // AboutToNavigateRenderFrame was not called for renderer-initiated
   // navigation.
   if (!pending_)
     SetPending(static_cast<RenderFrameHostImpl*>(new_host));
-
   CommitPending();
+  DCHECK(CheckConsistency());
 }
 
 void RenderFrameDevToolsAgentHost::FrameDeleted(RenderFrameHost* rfh) {
   if (pending_ && pending_->host() == rfh) {
     if (!IsBrowserSideNavigationEnabled())
       DiscardPending();
+    DCHECK(CheckConsistency());
     return;
   }
 
@@ -671,6 +694,8 @@
 void RenderFrameDevToolsAgentHost::RenderFrameDeleted(RenderFrameHost* rfh) {
   if (!current_frame_crashed_)
     FrameDeleted(rfh);
+  else
+    DCHECK(CheckConsistency());
 }
 
 void RenderFrameDevToolsAgentHost::DestroyOnRenderFrameGone() {
@@ -688,6 +713,18 @@
   Release();
 }
 
+bool RenderFrameDevToolsAgentHost::CheckConsistency() {
+  if (current_ && pending_ && current_->host() == pending_->host())
+    return false;
+  if (IsBrowserSideNavigationEnabled())
+    return true;
+  if (!frame_tree_node_)
+    return !handlers_frame_host_;
+  RenderFrameHostManager* manager = frame_tree_node_->render_manager();
+  return handlers_frame_host_ == manager->current_frame_host() ||
+      handlers_frame_host_ == manager->pending_frame_host();
+}
+
 void RenderFrameDevToolsAgentHost::CreatePowerSaveBlocker() {
 #if defined(OS_ANDROID)
   power_save_blocker_.reset(new device::PowerSaveBlocker(
@@ -722,6 +759,7 @@
       inspector_handler_->TargetDetached("Render process gone.");
       break;
   }
+  DCHECK(CheckConsistency());
 }
 
 bool RenderFrameDevToolsAgentHost::OnMessageReceived(
@@ -759,12 +797,15 @@
     page_handler_->DidAttachInterstitialPage();
 
   // TODO(dgozman): this may break for cross-process subframes.
-  if (!pending_)
+  if (!pending_) {
+    DCHECK(CheckConsistency());
     return;
+  }
   // Pending set in AboutToNavigateRenderFrame turned out to be interstitial.
   // Connect back to the real one.
   DiscardPending();
   pending_handle_ = nullptr;
+  DCHECK(CheckConsistency());
 }
 
 void RenderFrameDevToolsAgentHost::DidDetachInterstitialPage() {
@@ -780,6 +821,7 @@
     return;
   if (pending_ && pending_->host() == render_frame_host)
     CommitPending();
+  DCHECK(CheckConsistency());
   target_handler_->UpdateServiceWorkers();
 }
 
@@ -793,6 +835,7 @@
     return;
   if (pending_ && pending_->host() == render_frame_host)
     DiscardPending();
+  DCHECK(CheckConsistency());
 }
 
 void RenderFrameDevToolsAgentHost::WasShown() {
@@ -821,6 +864,7 @@
 
 void RenderFrameDevToolsAgentHost::UpdateProtocolHandlers(
     RenderFrameHostImpl* host) {
+  handlers_frame_host_ = host;
   dom_handler_->SetRenderFrameHost(host);
   if (emulation_handler_)
     emulation_handler_->SetRenderFrameHost(host);
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.h b/content/browser/devtools/render_frame_devtools_agent_host.h
index d328694..2a1350f0 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.h
+++ b/content/browser/devtools/render_frame_devtools_agent_host.h
@@ -162,6 +162,8 @@
   void OnRequestNewWindow(RenderFrameHost* sender, int new_routing_id);
   void DestroyOnRenderFrameGone();
 
+  bool CheckConsistency();
+
   void CreatePowerSaveBlocker();
 
   class FrameHostHolder;
@@ -193,6 +195,7 @@
   std::unique_ptr<device::PowerSaveBlocker> power_save_blocker_;
 #endif
   std::unique_ptr<DevToolsProtocolHandler> protocol_handler_;
+  RenderFrameHostImpl* handlers_frame_host_;
   bool current_frame_crashed_;
 
   // PlzNavigate
diff --git a/content/browser/download/quarantine_mac.mm b/content/browser/download/quarantine_mac.mm
index 3ff5774..e3351e2f 100644
--- a/content/browser/download/quarantine_mac.mm
+++ b/content/browser/download/quarantine_mac.mm
@@ -4,8 +4,8 @@
 
 #include "content/browser/download/quarantine.h"
 
-#include <ApplicationServices/ApplicationServices.h>
-#include <Foundation/Foundation.h>
+#import <ApplicationServices/ApplicationServices.h>
+#import <Foundation/Foundation.h>
 
 #include "base/files/file_path.h"
 #include "base/logging.h"
@@ -13,9 +13,129 @@
 #include "base/mac/mac_logging.h"
 #include "base/mac/mac_util.h"
 #include "base/mac/scoped_cftyperef.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/strings/sys_string_conversions.h"
 #include "base/threading/thread_restrictions.h"
 #include "url/gurl.h"
 
+namespace {
+
+// Once Chrome no longer supports macOS 10.9, this code will no longer be
+// necessary. Note that LSCopyItemAttribute was deprecated in macOS 10.8, but
+// the replacement to kLSItemQuarantineProperties did not exist until macOS
+// 10.10.
+#if !defined(MAC_OS_X_VERSION_10_10) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+bool GetQuarantinePropertiesDeprecated(
+    const base::FilePath& file,
+    base::scoped_nsobject<NSMutableDictionary>* properties) {
+  FSRef file_ref;
+  if (!base::mac::FSRefFromPath(file.value(), &file_ref))
+    return false;
+
+  base::ScopedCFTypeRef<CFTypeRef> quarantine_properties;
+  OSStatus status = LSCopyItemAttribute(&file_ref, kLSRolesAll,
+      kLSItemQuarantineProperties, quarantine_properties.InitializeInto());
+  if (status != noErr)
+    return true;
+
+  CFDictionaryRef quarantine_properties_dict =
+      base::mac::CFCast<CFDictionaryRef>(quarantine_properties.get());
+  if (!quarantine_properties_dict) {
+    LOG(WARNING) << "kLSItemQuarantineProperties is not a dictionary on file "
+                 << file.value();
+    return false;
+  }
+
+  properties->reset(
+      [base::mac::CFToNSCast(quarantine_properties_dict) mutableCopy]);
+  return true;
+}
+
+bool SetQuarantinePropertiesDeprecated(const base::FilePath& file,
+                                       NSDictionary* properties) {
+  FSRef file_ref;
+  if (!base::mac::FSRefFromPath(file.value(), &file_ref))
+    return false;
+  OSStatus os_error = LSSetItemAttribute(
+      &file_ref, kLSRolesAll, kLSItemQuarantineProperties, properties);
+  if (os_error != noErr) {
+    OSSTATUS_LOG(WARNING, os_error)
+        << "Unable to set quarantine attributes on file " << file.value();
+    return false;
+  }
+  return true;
+}
+#pragma clang diagnostic pop
+#endif
+
+bool GetQuarantineProperties(
+    const base::FilePath& file,
+    base::scoped_nsobject<NSMutableDictionary>* properties) {
+  base::scoped_nsobject<NSURL> file_url([[NSURL alloc]
+      initFileURLWithPath:base::SysUTF8ToNSString(file.value())]);
+  if (!file_url)
+    return false;
+
+// NSURLQuarantinePropertiesKey is only available on macOS 10.10+.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunguarded-availability"
+  NSError* error = nil;
+  id quarantine_properties = nil;
+  BOOL success = [file_url getResourceValue:&quarantine_properties
+                                     forKey:NSURLQuarantinePropertiesKey
+                                      error:&error];
+#pragma clang diagnostic pop
+  if (!success) {
+    std::string error_message(error ? error.description.UTF8String : "");
+    LOG(WARNING) << "Unable to get quarantine attributes for file "
+                 << file.value() << ". Error: " << error_message;
+    return false;
+  }
+
+  if (!quarantine_properties)
+    return true;
+
+  NSDictionary* quarantine_properties_dict =
+      base::mac::ObjCCast<NSDictionary>(quarantine_properties);
+  if (!quarantine_properties_dict) {
+    LOG(WARNING) << "Quarantine properties have wrong class: "
+                 << [[[quarantine_properties class] description] UTF8String];
+    return false;
+  }
+
+  properties->reset([quarantine_properties_dict mutableCopy]);
+  return true;
+}
+
+bool SetQuarantineProperties(const base::FilePath& file,
+                             NSDictionary* properties) {
+  base::scoped_nsobject<NSURL> file_url([[NSURL alloc]
+      initFileURLWithPath:base::SysUTF8ToNSString(file.value())]);
+  if (!file_url)
+    return false;
+
+// NSURLQuarantinePropertiesKey is only available on macOS 10.10+.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunguarded-availability"
+  NSError* error = nil;
+  bool success = [file_url setResourceValue:properties
+                                     forKey:NSURLQuarantinePropertiesKey
+                                      error:&error];
+#pragma clang diagnostic pop
+  if (!success) {
+    std::string error_message(error ? error.description.UTF8String : "");
+    LOG(WARNING) << "Unable to set quarantine attributes on file "
+                 << file.value() << ". Error: " << error_message;
+    return false;
+  }
+  return true;
+}
+
+}  // namespace
+
 namespace content {
 
 namespace {
@@ -111,27 +231,18 @@
                                  const GURL& source,
                                  const GURL& referrer) {
   base::ThreadRestrictions::AssertIOAllowed();
-  FSRef file_ref;
-  if (!base::mac::FSRefFromPath(file.value(), &file_ref))
-    return false;
-
-  NSMutableDictionary* quarantine_properties = nil;
-  CFTypeRef quarantine_properties_base = NULL;
-  if (LSCopyItemAttribute(&file_ref, kLSRolesAll, kLSItemQuarantineProperties,
-                          &quarantine_properties_base) == noErr) {
-    if (CFGetTypeID(quarantine_properties_base) == CFDictionaryGetTypeID()) {
-      // Quarantine properties will already exist if LSFileQuarantineEnabled
-      // is on and the file doesn't match an exclusion.
-      quarantine_properties =
-          [[(NSDictionary*)quarantine_properties_base mutableCopy] autorelease];
-    } else {
-      LOG(WARNING) << "kLSItemQuarantineProperties is not a dictionary on file "
-                   << file.value();
-    }
-    CFRelease(quarantine_properties_base);
+  base::scoped_nsobject<NSMutableDictionary> properties;
+  bool success = false;
+  if (base::mac::IsAtLeastOS10_10()) {
+    success = GetQuarantineProperties(file, &properties);
+  } else {
+    success = GetQuarantinePropertiesDeprecated(file, &properties);
   }
 
-  if (!quarantine_properties) {
+  if (!success)
+    return false;
+
+  if (!properties) {
     // If there are no quarantine properties, then the file isn't quarantined
     // (e.g., because the user has set up exclusions for certain file types).
     // We don't want to add any metadata, because that will cause the file to
@@ -143,40 +254,34 @@
   // kLSQuarantineTimeStampKey are set for us (see LSQuarantine.h), so we only
   // need to set the values that the OS can't infer.
 
-  if (![quarantine_properties valueForKey:(NSString*)kLSQuarantineTypeKey]) {
+  if (![properties valueForKey:(NSString*)kLSQuarantineTypeKey]) {
     CFStringRef type = source.SchemeIsHTTPOrHTTPS()
-                           ? kLSQuarantineTypeWebDownload
-                           : kLSQuarantineTypeOtherDownload;
-    [quarantine_properties setValue:(NSString*)type
-                             forKey:(NSString*)kLSQuarantineTypeKey];
+                       ? kLSQuarantineTypeWebDownload
+                       : kLSQuarantineTypeOtherDownload;
+    [properties setValue:(NSString*)type
+                  forKey:(NSString*)kLSQuarantineTypeKey];
   }
 
-  if (![quarantine_properties
-          valueForKey:(NSString*)kLSQuarantineOriginURLKey] &&
+  if (![properties valueForKey:(NSString*)kLSQuarantineOriginURLKey] &&
       referrer.is_valid()) {
     NSString* referrer_url =
         [NSString stringWithUTF8String:referrer.spec().c_str()];
-    [quarantine_properties setValue:referrer_url
-                             forKey:(NSString*)kLSQuarantineOriginURLKey];
+    [properties setValue:referrer_url
+                  forKey:(NSString*)kLSQuarantineOriginURLKey];
   }
 
-  if (![quarantine_properties valueForKey:(NSString*)kLSQuarantineDataURLKey] &&
+  if (![properties valueForKey:(NSString*)kLSQuarantineDataURLKey] &&
       source.is_valid()) {
     NSString* origin_url =
         [NSString stringWithUTF8String:source.spec().c_str()];
-    [quarantine_properties setValue:origin_url
-                             forKey:(NSString*)kLSQuarantineDataURLKey];
+    [properties setValue:origin_url forKey:(NSString*)kLSQuarantineDataURLKey];
   }
 
-  OSStatus os_error =
-      LSSetItemAttribute(&file_ref, kLSRolesAll, kLSItemQuarantineProperties,
-                         quarantine_properties);
-  if (os_error != noErr) {
-    OSSTATUS_LOG(WARNING, os_error)
-        << "Unable to set quarantine attributes on file " << file.value();
-    return false;
+  if (base::mac::IsAtLeastOS10_10()) {
+    return SetQuarantineProperties(file, properties);
+  } else {
+    return SetQuarantinePropertiesDeprecated(file, properties);
   }
-  return true;
 }
 
 }  // namespace
diff --git a/content/browser/download/quarantine_mac_unittest.mm b/content/browser/download/quarantine_mac_unittest.mm
new file mode 100644
index 0000000..babe6345
--- /dev/null
+++ b/content/browser/download/quarantine_mac_unittest.mm
@@ -0,0 +1,108 @@
+// 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.
+
+#include <sys/xattr.h>
+
+#import <Foundation/Foundation.h>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/logging.h"
+#include "base/mac/mac_util.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/strings/sys_string_conversions.h"
+#include "content/browser/download/quarantine.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gtest_mac.h"
+#include "url/gurl.h"
+
+namespace content {
+namespace {
+
+class QuarantineMacTest : public testing::Test {
+ public:
+  QuarantineMacTest()
+      : source_url_("http://www.source.com"),
+        referrer_url_("http://www.referrer.com") {}
+
+ protected:
+  void SetUp() override {
+    if (base::mac::IsAtMostOS10_9())
+      return;
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    ASSERT_TRUE(
+        base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &test_file_));
+    file_url_.reset([[NSURL alloc]
+        initFileURLWithPath:base::SysUTF8ToNSString(test_file_.value())]);
+
+    base::scoped_nsobject<NSMutableDictionary> properties(
+        [[NSMutableDictionary alloc] init]);
+    [properties
+        setValue:@"com.google.Chrome"
+          forKey:static_cast<NSString*>(kLSQuarantineAgentBundleIdentifierKey)];
+    [properties setValue:@"Google Chrome.app"
+                  forKey:static_cast<NSString*>(kLSQuarantineAgentNameKey)];
+    [properties setValue:@(1) forKey:@"kLSQuarantineIsOwnedByCurrentUserKey"];
+// NSURLQuarantinePropertiesKey is only available on macOS 10.10+.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunguarded-availability"
+    bool success = [file_url_ setResourceValue:properties
+                                        forKey:NSURLQuarantinePropertiesKey
+                                         error:nullptr];
+#pragma clang diagnostic pop
+    ASSERT_TRUE(success);
+  }
+
+  void VerifyAttributesAreSetCorrectly() {
+    base::scoped_nsobject<NSURL> file_url([[NSURL alloc]
+        initFileURLWithPath:base::SysUTF8ToNSString(test_file_.value())]);
+    ASSERT_TRUE(file_url);
+
+    NSError* error = nil;
+    NSDictionary* properties = nil;
+// NSURLQuarantinePropertiesKey is only available on macOS 10.10+.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunguarded-availability"
+    BOOL success = [file_url getResourceValue:&properties
+                                       forKey:NSURLQuarantinePropertiesKey
+                                        error:&error];
+#pragma clang diagnostic pop
+    ASSERT_TRUE(success);
+    ASSERT_TRUE(properties);
+    ASSERT_NSEQ(
+        [[properties valueForKey:static_cast<NSString*>(
+                                     kLSQuarantineOriginURLKey)] description],
+        base::SysUTF8ToNSString(referrer_url_.spec()));
+    ASSERT_NSEQ([[properties
+                    valueForKey:static_cast<NSString*>(kLSQuarantineDataURLKey)]
+                    description],
+                base::SysUTF8ToNSString(source_url_.spec()));
+  }
+
+  base::ScopedTempDir temp_dir_;
+  base::FilePath test_file_;
+  GURL source_url_;
+  GURL referrer_url_;
+  base::scoped_nsobject<NSURL> file_url_;
+};
+
+TEST_F(QuarantineMacTest, CheckMetadataSetCorrectly) {
+  if (base::mac::IsAtMostOS10_9())
+    return;
+  QuarantineFile(test_file_, source_url_, referrer_url_, "");
+  VerifyAttributesAreSetCorrectly();
+}
+
+TEST_F(QuarantineMacTest, SetMetadataMultipleTimes) {
+  if (base::mac::IsAtMostOS10_9())
+    return;
+  GURL dummy_url("http://www.dummy.com");
+  QuarantineFile(test_file_, source_url_, referrer_url_, "");
+  QuarantineFile(test_file_, dummy_url, dummy_url, "");
+  VerifyAttributesAreSetCorrectly();
+}
+
+}  // namespace
+}  // namespace content
diff --git a/content/browser/download/quarantine_win.cc b/content/browser/download/quarantine_win.cc
index f45a694..59605bf9 100644
--- a/content/browser/download/quarantine_win.cc
+++ b/content/browser/download/quarantine_win.cc
@@ -82,16 +82,6 @@
 void RecordAttachmentServicesSaveResult(const base::FilePath& file,
                                         HRESULT hr) {
   bool file_exists = base::PathExists(file);
-  if (SUCCEEDED(hr)) {
-    bool motw_exists = file_exists && ZoneIdentifierPresentForFile(file);
-    RecordAttachmentServicesResult(
-        file_exists
-            ? motw_exists ? AttachmentServicesResult::SUCCESS_WITH_MOTW
-                          : AttachmentServicesResult::SUCCESS_WITHOUT_MOTW
-            : AttachmentServicesResult::SUCCESS_WITHOUT_FILE);
-    return;
-  }
-
   switch (hr) {
     case INET_E_SECURITY_PROBLEM:
       RecordAttachmentServicesResult(
@@ -107,12 +97,26 @@
 
     case E_ACCESSDENIED:
     case ERROR_ACCESS_DENIED:
+      // ERROR_ACCESS_DENIED is not a valid HRESULT. However,
+      // IAttachmentExecute::Save() is known to return it and other system error
+      // codes in practice.
       RecordAttachmentServicesResult(
           file_exists ? AttachmentServicesResult::ACCESS_DENIED_WITH_FILE
                       : AttachmentServicesResult::ACCESS_DENIED_WITHOUT_FILE);
       break;
 
     default:
+      if (SUCCEEDED(hr)) {
+        bool motw_exists = file_exists && ZoneIdentifierPresentForFile(file);
+        RecordAttachmentServicesResult(
+            file_exists
+                ? motw_exists ? AttachmentServicesResult::SUCCESS_WITH_MOTW
+                              : AttachmentServicesResult::SUCCESS_WITHOUT_MOTW
+                : AttachmentServicesResult::SUCCESS_WITHOUT_FILE);
+        return;
+      }
+
+      // Failure codes.
       RecordAttachmentServicesResult(
           file_exists ? AttachmentServicesResult::OTHER_WITH_FILE
                       : AttachmentServicesResult::OTHER_WITHOUT_FILE);
diff --git a/content/browser/download/quarantine_win_unittest.cc b/content/browser/download/quarantine_win_unittest.cc
index f0229f5..95bdc63 100644
--- a/content/browser/download/quarantine_win_unittest.cc
+++ b/content/browser/download/quarantine_win_unittest.cc
@@ -6,11 +6,13 @@
 
 #include <wininet.h>
 
-#include "content/browser/download/quarantine.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/macros.h"
 #include "base/test/histogram_tester.h"
+#include "base/test/test_file_util.h"
+#include "content/browser/download/quarantine.h"
 #include "net/base/filename_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
@@ -27,6 +29,8 @@
 const base::FilePath::CharType kMotwStreamSuffix[] =
     FILE_PATH_LITERAL(":Zone.Identifier");
 
+const char kTestData[] = "Hello world!";
+
 const char* const kUntrustedURLs[] = {
     "http://example.com/foo",
     "https://example.com/foo",
@@ -68,7 +72,8 @@
 
   for (const auto source_url : kLocalSourceURLs) {
     SCOPED_TRACE(::testing::Message() << "Trying URL " << source_url);
-    ASSERT_EQ(5, base::WriteFile(test_file, "Hello", 5u));
+    ASSERT_EQ(static_cast<int>(arraysize(kTestData)),
+              base::WriteFile(test_file, kTestData, arraysize(kTestData)));
 
     EXPECT_EQ(
         QuarantineFileResult::OK,
@@ -107,7 +112,8 @@
 
   for (const auto source_url : kUntrustedURLs) {
     SCOPED_TRACE(::testing::Message() << "Trying URL " << source_url);
-    ASSERT_EQ(5, base::WriteFile(test_file, "Hello", 5u));
+    ASSERT_EQ(static_cast<int>(arraysize(kTestData)),
+              base::WriteFile(test_file, kTestData, arraysize(kTestData)));
     EXPECT_EQ(
         QuarantineFileResult::OK,
         QuarantineFile(test_file, GURL(source_url), GURL(), kDummyClientGuid));
@@ -145,7 +151,8 @@
 
   for (const auto referrer_url : unsafe_referrers) {
     SCOPED_TRACE(::testing::Message() << "Trying URL " << referrer_url);
-    ASSERT_EQ(5, base::WriteFile(test_file, "Hello", 5u));
+    ASSERT_EQ(static_cast<int>(arraysize(kTestData)),
+              base::WriteFile(test_file, kTestData, arraysize(kTestData)));
     EXPECT_EQ(QuarantineFileResult::OK,
               QuarantineFile(test_file, GURL("http://example.com/good"),
                              GURL(referrer_url), kDummyClientGuid));
@@ -175,7 +182,8 @@
   base::ScopedTempDir test_dir;
   ASSERT_TRUE(test_dir.CreateUniqueTempDir());
   base::FilePath test_file = test_dir.path().AppendASCII("foo.exe");
-  ASSERT_EQ(5, base::WriteFile(test_file, "Hello", 5u));
+  ASSERT_EQ(static_cast<int>(arraysize(kTestData)),
+            base::WriteFile(test_file, kTestData, arraysize(kTestData)));
 
   EXPECT_EQ(QuarantineFileResult::OK,
             QuarantineFile(test_file, GURL(), GURL(), kDummyClientGuid));
@@ -195,6 +203,7 @@
 // the file is passed to AVScanFile, then there wouldn't be a MOTW attached to
 // it and the test would fail.
 TEST(QuarantineWinTest, EmptyFile) {
+  base::HistogramTester histogram_tester;
   base::ScopedTempDir test_dir;
   ASSERT_TRUE(test_dir.CreateUniqueTempDir());
   base::FilePath test_file = test_dir.path().AppendASCII("foo.exe");
@@ -207,6 +216,9 @@
   ASSERT_TRUE(base::ReadFileToString(
       base::FilePath(test_file.value() + kMotwStreamSuffix), &motw_contents));
   EXPECT_STREQ(kMotwForInternetZone, motw_contents.c_str());
+
+  // Attachment services shouldn't have been invoked at all.
+  histogram_tester.ExpectTotalCount("Download.AttachmentServices.Result", 0);
 }
 
 // If there is no client GUID supplied to the QuarantineFile() call, then rather
@@ -217,7 +229,8 @@
   base::ScopedTempDir test_dir;
   ASSERT_TRUE(test_dir.CreateUniqueTempDir());
   base::FilePath test_file = test_dir.path().AppendASCII("foo.exe");
-  ASSERT_EQ(5, base::WriteFile(test_file, "Hello", 5u));
+  ASSERT_EQ(static_cast<int>(arraysize(kTestData)),
+            base::WriteFile(test_file, kTestData, arraysize(kTestData)));
 
   EXPECT_EQ(QuarantineFileResult::OK,
             QuarantineFile(test_file, net::FilePathToFileURL(test_file), GURL(),
@@ -235,7 +248,8 @@
   base::ScopedTempDir test_dir;
   ASSERT_TRUE(test_dir.CreateUniqueTempDir());
   base::FilePath test_file = test_dir.path().AppendASCII("foo.exe");
-  ASSERT_EQ(5, base::WriteFile(test_file, "Hello", 5u));
+  ASSERT_EQ(static_cast<int>(arraysize(kTestData)),
+            base::WriteFile(test_file, kTestData, arraysize(kTestData)));
 
   std::string source_url("http://example.com/");
   source_url.append(INTERNET_MAX_URL_LENGTH * 2, 'a');
diff --git a/content/browser/frame_host/interstitial_page_impl.cc b/content/browser/frame_host/interstitial_page_impl.cc
index 8097c37..78650a3 100644
--- a/content/browser/frame_host/interstitial_page_impl.cc
+++ b/content/browser/frame_host/interstitial_page_impl.cc
@@ -740,7 +740,7 @@
     int32_t route_id,
     int32_t main_frame_route_id,
     int32_t main_frame_widget_route_id,
-    const ViewHostMsg_CreateWindow_Params& params,
+    const mojom::CreateNewWindowParams& params,
     SessionStorageNamespace* session_storage_namespace) {
   NOTREACHED() << "InterstitialPage does not support showing popups yet.";
 }
diff --git a/content/browser/frame_host/interstitial_page_impl.h b/content/browser/frame_host/interstitial_page_impl.h
index 6cfaefc..9866b47 100644
--- a/content/browser/frame_host/interstitial_page_impl.h
+++ b/content/browser/frame_host/interstitial_page_impl.h
@@ -33,6 +33,10 @@
 class TextInputManager;
 class WebContentsView;
 
+namespace mojom {
+class CreateNewWindowParams;
+}
+
 enum ResourceRequestAction {
   BLOCK,
   RESUME,
@@ -134,7 +138,7 @@
       int32_t route_id,
       int32_t main_frame_route_id,
       int32_t main_frame_widget_route_id,
-      const ViewHostMsg_CreateWindow_Params& params,
+      const mojom::CreateNewWindowParams& params,
       SessionStorageNamespace* session_storage_namespace) override;
   void CreateNewWidget(int32_t render_process_id,
                        int32_t route_id,
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc
index c0ddb1b..aadc9ace 100644
--- a/content/browser/frame_host/navigation_controller_impl.cc
+++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -226,7 +226,8 @@
       in_navigate_to_pending_entry_(false),
       pending_reload_(ReloadType::NONE),
       get_timestamp_callback_(base::Bind(&base::Time::Now)),
-      screenshot_manager_(new NavigationEntryScreenshotManager(this)) {
+      screenshot_manager_(new NavigationEntryScreenshotManager(this)),
+      last_committed_reload_type_(ReloadType::NONE) {
   DCHECK(browser_context_);
 }
 
@@ -329,6 +330,28 @@
   if (!entry)
     return;
 
+  // Check if previous navigation was a reload to track consecutive reload
+  // operations.
+  if (last_committed_reload_type_ != ReloadType::NONE) {
+    DCHECK(!last_committed_reload_time_.is_null());
+    base::Time now =
+        time_smoother_.GetSmoothedTime(get_timestamp_callback_.Run());
+    DCHECK_GT(now, last_committed_reload_time_);
+    if (!last_committed_reload_time_.is_null() &&
+        now > last_committed_reload_time_) {
+      base::TimeDelta delta = now - last_committed_reload_time_;
+      UMA_HISTOGRAM_MEDIUM_TIMES("Navigation.Reload.ReloadToReloadDuration",
+                                 delta);
+      if (last_committed_reload_type_ == ReloadType::MAIN_RESOURCE) {
+        UMA_HISTOGRAM_MEDIUM_TIMES(
+            "Navigation.Reload.ReloadMainResourceToReloadDuration", delta);
+      }
+    }
+  }
+
+  // Set ReloadType for |entry| in order to check it at commit time.
+  entry->set_reload_type(reload_type);
+
   if (g_check_for_repost && check_for_repost &&
       entry->GetHasPostData()) {
     // The user is asking to reload a page with POST data. Prompt to make sure
@@ -772,7 +795,8 @@
 bool NavigationControllerImpl::RendererDidNavigate(
     RenderFrameHostImpl* rfh,
     const FrameHostMsg_DidCommitProvisionalLoad_Params& params,
-    LoadCommittedDetails* details) {
+    LoadCommittedDetails* details,
+    bool is_navigation_within_page) {
   is_initial_navigation_ = false;
 
   // Save the previous state before we clobber it.
@@ -799,8 +823,21 @@
   details->type = ClassifyNavigation(rfh, params);
 
   // is_in_page must be computed before the entry gets committed.
-  details->is_in_page = IsURLInPageNavigation(params.url, params.origin,
-                                              params.was_within_same_page, rfh);
+  details->is_in_page = is_navigation_within_page;
+
+  // Save reload type and timestamp for a reload navigation to detect
+  // consecutive reloads when the next reload is requested.
+  if (PendingEntryMatchesHandle(rfh->navigation_handle())) {
+    if (pending_entry_->reload_type() != ReloadType::NONE) {
+      last_committed_reload_type_ = pending_entry_->reload_type();
+      last_committed_reload_time_ =
+          time_smoother_.GetSmoothedTime(get_timestamp_callback_.Run());
+    } else if (!pending_entry_->is_renderer_initiated() ||
+               params.gesture == NavigationGestureUser) {
+      last_committed_reload_type_ = ReloadType::NONE;
+      last_committed_reload_time_ = base::Time();
+    }
+  }
 
   switch (details->type) {
     case NAVIGATION_TYPE_NEW_PAGE:
diff --git a/content/browser/frame_host/navigation_controller_impl.h b/content/browser/frame_host/navigation_controller_impl.h
index 20bb0f6..527fb8f 100644
--- a/content/browser/frame_host/navigation_controller_impl.h
+++ b/content/browser/frame_host/navigation_controller_impl.h
@@ -149,7 +149,8 @@
   bool RendererDidNavigate(
       RenderFrameHostImpl* rfh,
       const FrameHostMsg_DidCommitProvisionalLoad_Params& params,
-      LoadCommittedDetails* details);
+      LoadCommittedDetails* details,
+      bool is_navigation_within_page);
 
   // Notifies us that we just became active. This is used by the WebContentsImpl
   // so that we know to load URLs that were pending as "lazy" loads.
@@ -450,6 +451,13 @@
 
   std::unique_ptr<NavigationEntryScreenshotManager> screenshot_manager_;
 
+  // Used for tracking consecutive reload requests.  If the last user-initiated
+  // navigation (either browser-initiated or renderer-initiated with a user
+  // gesture) was a reload, these hold the ReloadType and timestamp.  Otherwise
+  // these are ReloadType::NONE and a null timestamp, respectively.
+  ReloadType last_committed_reload_type_;
+  base::Time last_committed_reload_time_;
+
   DISALLOW_COPY_AND_ASSIGN(NavigationControllerImpl);
 };
 
diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
index 405e6500..158bc45 100644
--- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/histogram_tester.h"
 #include "content/browser/frame_host/frame_navigation_entry.h"
 #include "content/browser/frame_host/frame_tree.h"
 #include "content/browser/frame_host/navigation_entry_impl.h"
@@ -27,6 +28,7 @@
 #include "content/public/browser/resource_dispatcher_host_delegate.h"
 #include "content/public/browser/resource_throttle.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_delegate.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/bindings_policy.h"
 #include "content/public/common/browser_side_navigation_policy.h"
@@ -5968,7 +5970,7 @@
   EXPECT_EQ(start_url.GetOrigin().spec(), origin + "/");
 }
 
-// A BrowserMessageFilter that delays FrameHostMsg_DidCommitProvisionaLoad IPC
+// A BrowserMessageFilter that delays FrameHostMsg_DidCommitProvisionalLoad IPC
 // message for a specified URL, navigates the WebContents back and then
 // processes the commit message.
 class GoBackAndCommitFilter : public BrowserMessageFilter {
@@ -5996,7 +5998,7 @@
     if (message.type() != FrameHostMsg_DidCommitProvisionalLoad::ID)
       return false;
 
-    // Parse the IPC message so the URL can be checked agains the expected one.
+    // Parse the IPC message so the URL can be checked against the expected one.
     base::PickleIterator iter(message);
     FrameHostMsg_DidCommitProvisionalLoad_Params validated_params;
     if (!IPC::ParamTraits<FrameHostMsg_DidCommitProvisionalLoad_Params>::Read(
@@ -6137,4 +6139,212 @@
   EXPECT_FALSE(favicon_status3.valid);
 }
 
+namespace {
+
+// A BrowserMessageFilter that delays the FrameHostMsg_RunJavaScriptMessage IPC
+// message until a commit happens on a given WebContents. This allows testing a
+// race condition.
+class AllowDialogIPCOnCommitFilter : public BrowserMessageFilter,
+                                     public WebContentsDelegate {
+ public:
+  AllowDialogIPCOnCommitFilter(WebContents* web_contents)
+      : BrowserMessageFilter(FrameMsgStart),
+        render_frame_host_(web_contents->GetMainFrame()) {
+    web_contents_observer_.Observe(web_contents);
+  }
+
+ protected:
+  ~AllowDialogIPCOnCommitFilter() override {}
+
+ private:
+  // BrowserMessageFilter:
+  bool OnMessageReceived(const IPC::Message& message) override {
+    DCHECK_CURRENTLY_ON(BrowserThread::IO);
+    if (message.type() != FrameHostMsg_RunJavaScriptMessage::ID)
+      return false;
+
+    // Suspend the message.
+    web_contents_observer_.SetCallback(
+        base::Bind(&RenderFrameHost::OnMessageReceived,
+                   base::Unretained(render_frame_host_), message));
+    return true;
+  }
+
+  // WebContentsDelegate:
+  JavaScriptDialogManager* GetJavaScriptDialogManager(
+      WebContents* source) override {
+    CHECK(false);
+    return nullptr;  // agh compiler
+  }
+
+  // Separate because WebContentsObserver and BrowserMessageFilter each have an
+  // OnMessageReceived function; this is the simplest way to disambiguate.
+  class : public WebContentsObserver {
+   public:
+    using Callback = base::Callback<bool()>;
+
+    using WebContentsObserver::Observe;
+
+    void SetCallback(Callback callback) { callback_ = callback; }
+
+   private:
+    void DidNavigateAnyFrame(RenderFrameHost* render_frame_host,
+                             const LoadCommittedDetails& details,
+                             const FrameNavigateParams& params) override {
+      DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+      // Resume the message.
+      callback_.Run();
+    }
+
+    Callback callback_;
+  } web_contents_observer_;
+
+  RenderFrameHost* render_frame_host_;
+
+  DISALLOW_COPY_AND_ASSIGN(AllowDialogIPCOnCommitFilter);
+};
+
+}  // namespace
+
+// Check that swapped out frames cannot spawn JavaScript dialogs.
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+                       NoDialogsFromSwappedOutFrames) {
+  // Start on a normal page.
+  GURL url1 = embedded_test_server()->GetURL(
+      "/navigation_controller/beforeunload_dialog.html");
+  EXPECT_TRUE(NavigateToURL(shell(), url1));
+
+  // Add a filter to allow us to force an IPC race.
+  WebContents* web_contents = shell()->web_contents();
+  scoped_refptr<AllowDialogIPCOnCommitFilter> filter =
+      new AllowDialogIPCOnCommitFilter(web_contents);
+  web_contents->SetDelegate(filter.get());
+  web_contents->GetMainFrame()->GetProcess()->AddFilter(filter.get());
+
+  // Use a chrome:// url to force the second page to be in a different process.
+  GURL url2(std::string(kChromeUIScheme) + url::kStandardSchemeSeparator +
+            kChromeUIGpuHost);
+  EXPECT_TRUE(NavigateToURL(shell(), url2));
+
+  // What happens now is that attempting to unload the first page will trigger a
+  // JavaScript alert but allow navigation. The alert IPC will be suspended by
+  // the message filter. The commit of the second page will unblock the IPC. If
+  // the dialog IPC is allowed to spawn a dialog, the call by the WebContents to
+  // its delegate to get the JavaScriptDialogManager will cause a CHECK and the
+  // test will fail.
+}
+
+namespace {
+
+// Execute JavaScript without the user gesture flag set, and wait for the
+// triggered load finished.
+void ExecuteJavaScriptAndWaitForLoadStop(WebContents* web_contents,
+                                         const std::string script) {
+  // WaitForLoadStop() does not work to wait for loading that is triggered by
+  // JavaScript asynchronously.
+  TestNavigationObserver observer(web_contents);
+
+  // ExecuteScript() sets a user gesture flag internally for testing, but we
+  // want to run JavaScript without the flag.  Call ExecuteJavaScriptForTests
+  // directory.
+  static_cast<WebContentsImpl*>(web_contents)
+      ->GetMainFrame()
+      ->ExecuteJavaScriptForTests(base::UTF8ToUTF16(script));
+
+  observer.Wait();
+}
+
+}  // namespace
+
+// Check if consecutive reloads can be correctly captured by metrics.
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+                       ConsecutiveReloadMetrics) {
+  base::HistogramTester histogram;
+
+  const char kReloadToReloadMetricName[] =
+      "Navigation.Reload.ReloadToReloadDuration";
+  const char kReloadMainResourceToReloadMetricName[] =
+      "Navigation.Reload.ReloadMainResourceToReloadDuration";
+
+  // Navigate to a page, and check if metrics are initialized correctly.
+  NavigateToURL(shell(), embedded_test_server()->GetURL(
+                             "/navigation_controller/page_with_links.html"));
+  histogram.ExpectTotalCount(kReloadToReloadMetricName, 0);
+  histogram.ExpectTotalCount(kReloadMainResourceToReloadMetricName, 0);
+
+  NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
+      shell()->web_contents()->GetController());
+
+  // ReloadToRefreshContent triggers a reload of ReloadType::MAIN_RESOURCE.  The
+  // first reload should not be counted.
+  controller.ReloadToRefreshContent(false);
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+  histogram.ExpectTotalCount(kReloadToReloadMetricName, 0);
+  histogram.ExpectTotalCount(kReloadMainResourceToReloadMetricName, 0);
+
+  // ReloadBypassingCache triggers a reload of ReloadType::BYPASSING_CACHE.
+  // Both metrics should count the consecutive reloads.
+  controller.ReloadBypassingCache(false);
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+  histogram.ExpectTotalCount(kReloadToReloadMetricName, 1);
+  histogram.ExpectTotalCount(kReloadMainResourceToReloadMetricName, 1);
+
+  // Triggers another reload of ReloadType::BYPASSING_CACHE.
+  // ReloadMainResourceToReload should not be counted here.
+  controller.ReloadBypassingCache(false);
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+  histogram.ExpectTotalCount(kReloadToReloadMetricName, 2);
+  histogram.ExpectTotalCount(kReloadMainResourceToReloadMetricName, 1);
+
+  // A browser-initiated navigation should reset the reload tracking
+  // information.
+  NavigateToURL(shell(), embedded_test_server()->GetURL(
+                             "/navigation_controller/simple_page_1.html"));
+  histogram.ExpectTotalCount(kReloadToReloadMetricName, 2);
+  histogram.ExpectTotalCount(kReloadMainResourceToReloadMetricName, 1);
+
+  // Then, the next reload should be assumed as the first reload.  Metrics
+  // should not be changed for the first reload.
+  controller.ReloadToRefreshContent(false);
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+  histogram.ExpectTotalCount(kReloadToReloadMetricName, 2);
+  histogram.ExpectTotalCount(kReloadMainResourceToReloadMetricName, 1);
+
+  // Another reload of ReloadType::MAIN_RESOURCE should be counted by both
+  // metrics again.
+  controller.ReloadToRefreshContent(false);
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+  histogram.ExpectTotalCount(kReloadToReloadMetricName, 3);
+  histogram.ExpectTotalCount(kReloadMainResourceToReloadMetricName, 2);
+
+  // A renderer-initiated navigations with no user gesture don't reset reload
+  // tracking information, and the following reload will be counted by metrics.
+  ExecuteJavaScriptAndWaitForLoadStop(
+      shell()->web_contents(),
+      "history.pushState({}, 'page 1', 'simple_page_1.html')");
+  histogram.ExpectTotalCount(kReloadToReloadMetricName, 3);
+  histogram.ExpectTotalCount(kReloadMainResourceToReloadMetricName, 2);
+  ExecuteJavaScriptAndWaitForLoadStop(shell()->web_contents(),
+                                      "location.href='simple_page_2.html'");
+  histogram.ExpectTotalCount(kReloadToReloadMetricName, 3);
+  histogram.ExpectTotalCount(kReloadMainResourceToReloadMetricName, 2);
+
+  controller.ReloadToRefreshContent(false);
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+  histogram.ExpectTotalCount(kReloadToReloadMetricName, 4);
+  histogram.ExpectTotalCount(kReloadMainResourceToReloadMetricName, 3);
+
+  // Go back to the first page. Reload tracking information should be reset.
+  shell()->web_contents()->GetController().GoBack();
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+  histogram.ExpectTotalCount(kReloadToReloadMetricName, 4);
+  histogram.ExpectTotalCount(kReloadMainResourceToReloadMetricName, 3);
+
+  controller.ReloadToRefreshContent(false);
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+  histogram.ExpectTotalCount(kReloadToReloadMetricName, 4);
+  histogram.ExpectTotalCount(kReloadMainResourceToReloadMetricName, 3);
+}
+
 }  // namespace content
diff --git a/content/browser/frame_host/navigation_entry_impl.cc b/content/browser/frame_host/navigation_entry_impl.cc
index fbf56542..fd6f2b49 100644
--- a/content/browser/frame_host/navigation_entry_impl.cc
+++ b/content/browser/frame_host/navigation_entry_impl.cc
@@ -22,6 +22,7 @@
 #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"
 #include "content/public/common/content_constants.h"
 #include "content/public/common/url_constants.h"
@@ -259,7 +260,8 @@
       should_replace_entry_(false),
       should_clear_history_list_(false),
       can_load_local_resources_(false),
-      frame_tree_node_id_(-1) {
+      frame_tree_node_id_(-1),
+      reload_type_(ReloadType::NONE) {
 #if defined(OS_ANDROID)
   has_user_gesture_ = false;
 #endif
@@ -639,6 +641,7 @@
 #if defined(OS_ANDROID)
   copy->has_user_gesture_ = has_user_gesture_;
 #endif
+  // ResetForCommit: reload_type_
   copy->extra_data_ = extra_data_;
 
   return copy;
@@ -753,6 +756,7 @@
 
   set_should_clear_history_list(false);
   set_frame_tree_node_id(-1);
+  set_reload_type(ReloadType::NONE);
 
   if (frame_entry)
     frame_entry->set_source_site_instance(nullptr);
diff --git a/content/browser/frame_host/navigation_entry_impl.h b/content/browser/frame_host/navigation_entry_impl.h
index fa2c88e..873fed69 100644
--- a/content/browser/frame_host/navigation_entry_impl.h
+++ b/content/browser/frame_host/navigation_entry_impl.h
@@ -20,6 +20,7 @@
 #include "content/public/browser/favicon_status.h"
 #include "content/public/browser/global_request_id.h"
 #include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/reload_type.h"
 #include "content/public/browser/restore_type.h"
 #include "content/public/browser/ssl_status.h"
 #include "content/public/common/page_state.h"
@@ -313,7 +314,7 @@
   }
 
   // The RestoreType for this entry. This is set if the entry was retored. This
-  // is set to RESTORE_NONE once the entry is loaded.
+  // is set to RestoreType::NONE once the entry is loaded.
   void set_restore_type(RestoreType type) {
     restore_type_ = type;
   }
@@ -321,6 +322,12 @@
     return restore_type_;
   }
 
+  // The ReloadType for this entry.  This is set when a reload is requested.
+  // This is set to ReloadType::NONE if the entry isn't for a reload, or once
+  // the entry is loaded.
+  void set_reload_type(ReloadType type) { reload_type_ = type; }
+  ReloadType reload_type() const { return reload_type_; }
+
   void set_transferred_global_request_id(
       const GlobalRequestID& transferred_global_request_id) {
     transferred_global_request_id_ = transferred_global_request_id;
@@ -515,6 +522,10 @@
   bool has_user_gesture_;
 #endif
 
+  // Used to store ReloadType for the entry.  This is ReloadType::NONE for
+  // non-reload navigations.  Reset at commit and not persisted.
+  ReloadType reload_type_;
+
   // Used to store extra data to support browser features. This member is not
   // persisted, unless specific data is taken out/put back in at save/restore
   // time (see TabNavigation for an example of this).
diff --git a/content/browser/frame_host/navigation_handle_impl.cc b/content/browser/frame_host/navigation_handle_impl.cc
index 824063f5..03487ebf 100644
--- a/content/browser/frame_host/navigation_handle_impl.cc
+++ b/content/browser/frame_host/navigation_handle_impl.cc
@@ -19,6 +19,7 @@
 #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"
@@ -397,6 +398,9 @@
 
   RegisterNavigationThrottles();
 
+  if (IsBrowserSideNavigationEnabled())
+    navigation_ui_data_ = GetDelegate()->GetNavigationUIData(this);
+
   // Notify each throttle of the request.
   NavigationThrottle::ThrottleCheckResult result = CheckWillStartRequest();
 
diff --git a/content/browser/frame_host/navigation_handle_impl.h b/content/browser/frame_host/navigation_handle_impl.h
index c28761b..7e51f508 100644
--- a/content/browser/frame_host/navigation_handle_impl.h
+++ b/content/browser/frame_host/navigation_handle_impl.h
@@ -28,6 +28,7 @@
 
 namespace content {
 
+class NavigationUIData;
 class NavigatorDelegate;
 class ResourceRequestBodyImpl;
 class ServiceWorkerContextWrapper;
@@ -272,6 +273,10 @@
   // Called when the navigation is transferred to a different renderer.
   void Transfer();
 
+  NavigationUIData* navigation_ui_data() const {
+    return navigation_ui_data_.get();
+  }
+
  private:
   friend class NavigationHandleImplTest;
 
@@ -385,9 +390,13 @@
   // corresponding ServiceWorkerNetworkProvider is created in the renderer.
   std::unique_ptr<ServiceWorkerNavigationHandle> service_worker_handle_;
 
-  // Embedder data tied to this navigation.
+  // Embedder data from the IO thread tied to this navigation.
   std::unique_ptr<NavigationData> navigation_data_;
 
+  // PlzNavigate
+  // Embedder data from the UI thread tied to this navigation.
+  std::unique_ptr<NavigationUIData> navigation_ui_data_;
+
   SSLStatus ssl_status_;
 
   // The id of the URLRequest tied to this navigation.
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index 2fb9cd8..5cb0f13 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -23,6 +23,7 @@
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_data.h"
+#include "content/public/browser/navigation_ui_data.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/stream_handle.h"
 #include "content/public/common/content_client.h"
@@ -386,9 +387,8 @@
   // renderer, allow the embedder to cancel the transfer.
   if (!browser_initiated_ &&
       render_frame_host != frame_tree_node_->current_frame_host() &&
-      !frame_tree_node_->navigator()
-           ->GetDelegate()
-           ->ShouldTransferNavigation()) {
+      !frame_tree_node_->navigator()->GetDelegate()->ShouldTransferNavigation(
+          frame_tree_node_->IsMainFrame())) {
     frame_tree_node_->ResetNavigationRequest(false);
     return;
   }
@@ -486,6 +486,10 @@
                                   ? false
                                   : frame_tree_node_->parent()->IsMainFrame();
 
+  std::unique_ptr<NavigationUIData> navigation_ui_data;
+  if (navigation_handle_->navigation_ui_data())
+    navigation_ui_data = navigation_handle_->navigation_ui_data()->Clone();
+
   loader_ = NavigationURLLoader::Create(
       frame_tree_node_->navigator()->GetController()->GetBrowserContext(),
       base::MakeUnique<NavigationRequestInfo>(
@@ -493,6 +497,7 @@
           frame_tree_node_->current_origin(), frame_tree_node_->IsMainFrame(),
           parent_is_main_frame, IsSecureFrame(frame_tree_node_->parent()),
           frame_tree_node_->frame_tree_node_id()),
+      std::move(navigation_ui_data),
       navigation_handle_->service_worker_handle(), this);
 }
 
diff --git a/content/browser/frame_host/navigator_delegate.cc b/content/browser/frame_host/navigator_delegate.cc
index 0c812b7..1d4e3e7 100644
--- a/content/browser/frame_host/navigator_delegate.cc
+++ b/content/browser/frame_host/navigator_delegate.cc
@@ -10,7 +10,8 @@
   return false;
 }
 
-bool NavigatorDelegate::ShouldTransferNavigation() {
+bool NavigatorDelegate::ShouldTransferNavigation(
+    bool is_main_frame_navigation) {
   return true;
 }
 
@@ -24,4 +25,9 @@
   return ScopedVector<NavigationThrottle>();
 }
 
+std::unique_ptr<NavigationUIData> NavigatorDelegate::GetNavigationUIData(
+    NavigationHandle* navigation_handle) {
+  return nullptr;
+}
+
 }  // namespace content
diff --git a/content/browser/frame_host/navigator_delegate.h b/content/browser/frame_host/navigator_delegate.h
index 71019d1..0f435bf 100644
--- a/content/browser/frame_host/navigator_delegate.h
+++ b/content/browser/frame_host/navigator_delegate.h
@@ -10,6 +10,7 @@
 #include "content/public/browser/invalidate_type.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_throttle.h"
+#include "content/public/browser/navigation_ui_data.h"
 #include "content/public/browser/reload_type.h"
 #include "ui/base/page_transition_types.h"
 #include "ui/base/window_open_disposition.h"
@@ -115,7 +116,7 @@
 
   // Returns whether to continue a navigation that needs to transfer to a
   // different process between the load start and commit.
-  virtual bool ShouldTransferNavigation();
+  virtual bool ShouldTransferNavigation(bool is_main_frame_navigation);
 
   // Returns whether URLs for aborted browser-initiated navigations should be
   // preserved in the omnibox.  Defaults to false.
@@ -140,6 +141,14 @@
   // where no NavigationThrottles are added to the navigation.
   virtual ScopedVector<NavigationThrottle> CreateThrottlesForNavigation(
       NavigationHandle* navigation_handle);
+
+  // PlzNavigate
+  // Called at the start of the navigation to get opaque data the embedder
+  // wants to see passed to the corresponding URLRequest on the IO thread.
+  // In the case of a navigation to an interstitial, no call will be made to the
+  // embedder and |nullptr| is returned.
+  virtual std::unique_ptr<NavigationUIData> GetNavigationUIData(
+      NavigationHandle* navigation_handle);
 };
 
 }  // namspace content
diff --git a/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc
index aafb3ccf..50787510 100644
--- a/content/browser/frame_host/navigator_impl.cc
+++ b/content/browser/frame_host/navigator_impl.cc
@@ -562,8 +562,8 @@
 
   int old_entry_count = controller_->GetEntryCount();
   LoadCommittedDetails details;
-  bool did_navigate = controller_->RendererDidNavigate(render_frame_host,
-                                                       params, &details);
+  bool did_navigate = controller_->RendererDidNavigate(
+      render_frame_host, params, &details, is_navigation_within_page);
 
   // If the history length and/or offset changed, update other renderers in the
   // FrameTree.
@@ -756,7 +756,8 @@
          SiteIsolationPolicy::AreCrossProcessFramesPossible());
 
   // Allow the delegate to cancel the transfer.
-  if (!delegate_->ShouldTransferNavigation())
+  if (!delegate_->ShouldTransferNavigation(
+          render_frame_host->frame_tree_node()->IsMainFrame()))
     return;
 
   GURL dest_url(url);
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 8da6a4d..c658baf 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -1585,6 +1585,11 @@
     const GURL& frame_url,
     JavaScriptMessageType type,
     IPC::Message* reply_msg) {
+  if (!is_active()) {
+    JavaScriptDialogClosed(reply_msg, true, base::string16(), true);
+    return;
+  }
+
   int32_t message_length = static_cast<int32_t>(message.length());
   if (GetParent()) {
     UMA_HISTOGRAM_COUNTS("JSDialogs.CharacterCount.Subframe", message_length);
@@ -2499,6 +2504,10 @@
     const RequestNavigationParams& request_params,
     bool has_stale_copy_in_cache,
     int error_code) {
+  // Update renderer permissions even for failed commits, so that for example
+  // the URL bar correctly displays privileged URLs instead of filtering them.
+  UpdatePermissionsForNavigation(common_params, request_params);
+
   // Get back to a clean state, in case a new navigation started without
   // completing an unload handler.
   ResetWaitingState();
diff --git a/content/browser/loader/DEPS b/content/browser/loader/DEPS
index 39b0e67..c97bfc8 100644
--- a/content/browser/loader/DEPS
+++ b/content/browser/loader/DEPS
@@ -186,6 +186,7 @@
     "+content/common/net/url_request_service_worker_data.h",
     "+content/common/site_isolation_policy.h",
     "+content/public/browser/browser_thread.h",
+    "+content/public/browser/navigation_ui_data.h",
     "+content/public/browser/plugin_service.h",
     "+content/public/browser/resource_request_details.h",
     "+content/public/browser/stream_handle.h",
@@ -259,6 +260,7 @@
     "+content/common/net/url_request_service_worker_data.h",
     "+content/common/net/url_request_user_data.h",
     "+content/public/browser/browser_thread.h",
+    "+content/public/browser/navigation_ui_data.h",
     "+content/public/common/browser_side_navigation_policy.h",
     "+content/public/common/process_type.h",
   ],
diff --git a/content/browser/loader/mime_sniffing_resource_handler.cc b/content/browser/loader/mime_sniffing_resource_handler.cc
index 1c157df..25a4794 100644
--- a/content/browser/loader/mime_sniffing_resource_handler.cc
+++ b/content/browser/loader/mime_sniffing_resource_handler.cc
@@ -414,7 +414,8 @@
   std::unique_ptr<ResourceHandler> handler(
       host_->CreateResourceHandlerForDownload(request(),
                                               true,  // is_content_initiated
-                                              must_download));
+                                              must_download,
+                                              false /* is_new_request */));
   intercepting_handler_->UseNewHandler(std::move(handler), std::string());
   return true;
 }
diff --git a/content/browser/loader/mime_sniffing_resource_handler_unittest.cc b/content/browser/loader/mime_sniffing_resource_handler_unittest.cc
index ed407eb1..4964e28 100644
--- a/content/browser/loader/mime_sniffing_resource_handler_unittest.cc
+++ b/content/browser/loader/mime_sniffing_resource_handler_unittest.cc
@@ -151,7 +151,8 @@
   std::unique_ptr<ResourceHandler> CreateResourceHandlerForDownload(
       net::URLRequest* request,
       bool is_content_initiated,
-      bool must_download) override {
+      bool must_download,
+      bool is_new_request) override {
     return CreateNewResourceHandler();
   }
 
diff --git a/content/browser/loader/mojo_async_resource_handler_unittest.cc b/content/browser/loader/mojo_async_resource_handler_unittest.cc
index d20c649..5386d6e 100644
--- a/content/browser/loader/mojo_async_resource_handler_unittest.cc
+++ b/content/browser/loader/mojo_async_resource_handler_unittest.cc
@@ -84,6 +84,7 @@
                         ResourceContext* resource_context,
                         bool is_content_initiated,
                         bool must_download,
+                        bool is_new_request,
                         ScopedVector<ResourceThrottle>* throttles) override {
     ADD_FAILURE() << "DownloadStarting should not be called.";
   }
diff --git a/content/browser/loader/navigation_url_loader.cc b/content/browser/loader/navigation_url_loader.cc
index d9b0c927..5e9f29d8 100644
--- a/content/browser/loader/navigation_url_loader.cc
+++ b/content/browser/loader/navigation_url_loader.cc
@@ -9,6 +9,7 @@
 #include "content/browser/frame_host/navigation_request_info.h"
 #include "content/browser/loader/navigation_url_loader_factory.h"
 #include "content/browser/loader/navigation_url_loader_impl.h"
+#include "content/public/browser/navigation_ui_data.h"
 
 namespace content {
 
@@ -17,15 +18,17 @@
 std::unique_ptr<NavigationURLLoader> NavigationURLLoader::Create(
     BrowserContext* browser_context,
     std::unique_ptr<NavigationRequestInfo> request_info,
+    std::unique_ptr<NavigationUIData> navigation_ui_data,
     ServiceWorkerNavigationHandle* service_worker_handle,
     NavigationURLLoaderDelegate* delegate) {
   if (g_factory) {
     return g_factory->CreateLoader(browser_context, std::move(request_info),
+                                   std::move(navigation_ui_data),
                                    service_worker_handle, delegate);
   }
-  return std::unique_ptr<NavigationURLLoader>(
-      new NavigationURLLoaderImpl(browser_context, std::move(request_info),
-                                  service_worker_handle, delegate));
+  return std::unique_ptr<NavigationURLLoader>(new NavigationURLLoaderImpl(
+      browser_context, std::move(request_info), std::move(navigation_ui_data),
+      service_worker_handle, delegate));
 }
 
 void NavigationURLLoader::SetFactoryForTesting(
diff --git a/content/browser/loader/navigation_url_loader.h b/content/browser/loader/navigation_url_loader.h
index f7d3280..d4494aad 100644
--- a/content/browser/loader/navigation_url_loader.h
+++ b/content/browser/loader/navigation_url_loader.h
@@ -13,6 +13,7 @@
 namespace content {
 
 class BrowserContext;
+class NavigationUIData;
 class NavigationURLLoaderDelegate;
 class NavigationURLLoaderFactory;
 class ServiceWorkerNavigationHandle;
@@ -36,6 +37,7 @@
   static std::unique_ptr<NavigationURLLoader> Create(
       BrowserContext* browser_context,
       std::unique_ptr<NavigationRequestInfo> request_info,
+      std::unique_ptr<NavigationUIData> navigation_ui_data,
       ServiceWorkerNavigationHandle* service_worker_handle,
       NavigationURLLoaderDelegate* delegate);
 
diff --git a/content/browser/loader/navigation_url_loader_factory.h b/content/browser/loader/navigation_url_loader_factory.h
index df7ae0c0..2a2f534 100644
--- a/content/browser/loader/navigation_url_loader_factory.h
+++ b/content/browser/loader/navigation_url_loader_factory.h
@@ -19,6 +19,7 @@
   virtual std::unique_ptr<NavigationURLLoader> CreateLoader(
       BrowserContext* browser_context,
       std::unique_ptr<NavigationRequestInfo> request_info,
+      std::unique_ptr<NavigationUIData> navigation_ui_data,
       ServiceWorkerNavigationHandle* service_worker_handle,
       NavigationURLLoaderDelegate* delegate) = 0;
 
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index 2e5a41a..ab4db49 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -16,6 +16,7 @@
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_data.h"
+#include "content/public/browser/navigation_ui_data.h"
 #include "content/public/browser/stream_handle.h"
 
 namespace content {
@@ -23,6 +24,7 @@
 NavigationURLLoaderImpl::NavigationURLLoaderImpl(
     BrowserContext* browser_context,
     std::unique_ptr<NavigationRequestInfo> request_info,
+    std::unique_ptr<NavigationUIData> navigation_ui_data,
     ServiceWorkerNavigationHandle* service_worker_handle,
     NavigationURLLoaderDelegate* delegate)
     : delegate_(delegate), weak_factory_(this) {
@@ -44,7 +46,8 @@
       BrowserThread::IO, FROM_HERE,
       base::Bind(&NavigationURLLoaderImplCore::Start, base::Unretained(core_),
                  browser_context->GetResourceContext(),
-                 service_worker_handle_core, base::Passed(&request_info)));
+                 service_worker_handle_core, base::Passed(&request_info),
+                 base::Passed(&navigation_ui_data)));
 }
 
 NavigationURLLoaderImpl::~NavigationURLLoaderImpl() {
diff --git a/content/browser/loader/navigation_url_loader_impl.h b/content/browser/loader/navigation_url_loader_impl.h
index acd537d..e5d115e 100644
--- a/content/browser/loader/navigation_url_loader_impl.h
+++ b/content/browser/loader/navigation_url_loader_impl.h
@@ -31,6 +31,7 @@
   // The caller is responsible for ensuring that |delegate| outlives the loader.
   NavigationURLLoaderImpl(BrowserContext* browser_context,
                           std::unique_ptr<NavigationRequestInfo> request_info,
+                          std::unique_ptr<NavigationUIData> navigation_ui_data,
                           ServiceWorkerNavigationHandle* service_worker_handle,
                           NavigationURLLoaderDelegate* delegate);
   ~NavigationURLLoaderImpl() override;
diff --git a/content/browser/loader/navigation_url_loader_impl_core.cc b/content/browser/loader/navigation_url_loader_impl_core.cc
index de60e0a..9a35c9e2 100644
--- a/content/browser/loader/navigation_url_loader_impl_core.cc
+++ b/content/browser/loader/navigation_url_loader_impl_core.cc
@@ -14,6 +14,7 @@
 #include "content/common/navigation_params.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_data.h"
+#include "content/public/browser/navigation_ui_data.h"
 #include "content/public/browser/ssl_status.h"
 #include "content/public/browser/stream_handle.h"
 #include "content/public/common/resource_response.h"
@@ -40,7 +41,8 @@
 void NavigationURLLoaderImplCore::Start(
     ResourceContext* resource_context,
     ServiceWorkerNavigationHandleCore* service_worker_handle_core,
-    std::unique_ptr<NavigationRequestInfo> request_info) {
+    std::unique_ptr<NavigationRequestInfo> request_info,
+    std::unique_ptr<NavigationUIData> navigation_ui_data) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   BrowserThread::PostTask(
@@ -51,7 +53,8 @@
   // The ResourceDispatcherHostImpl can be null in unit tests.
   if (ResourceDispatcherHostImpl::Get()) {
     ResourceDispatcherHostImpl::Get()->BeginNavigationRequest(
-        resource_context, *request_info, this, service_worker_handle_core);
+        resource_context, *request_info, std::move(navigation_ui_data), this,
+        service_worker_handle_core);
   }
 }
 
diff --git a/content/browser/loader/navigation_url_loader_impl_core.h b/content/browser/loader/navigation_url_loader_impl_core.h
index 6392d27..786634c 100644
--- a/content/browser/loader/navigation_url_loader_impl_core.h
+++ b/content/browser/loader/navigation_url_loader_impl_core.h
@@ -44,7 +44,8 @@
   // Starts the request.
   void Start(ResourceContext* resource_context,
              ServiceWorkerNavigationHandleCore* service_worker_handle_core,
-             std::unique_ptr<NavigationRequestInfo> request_info);
+             std::unique_ptr<NavigationRequestInfo> request_info,
+             std::unique_ptr<NavigationUIData> navigation_ui_data);
 
   // Follows the current pending redirect.
   void FollowRedirect();
diff --git a/content/browser/loader/navigation_url_loader_unittest.cc b/content/browser/loader/navigation_url_loader_unittest.cc
index 20697ad..89604bb 100644
--- a/content/browser/loader/navigation_url_loader_unittest.cc
+++ b/content/browser/loader/navigation_url_loader_unittest.cc
@@ -20,6 +20,7 @@
 #include "content/browser/streams/stream_url_request_job.h"
 #include "content/common/navigation_params.h"
 #include "content/public/browser/browser_context.h"
+#include "content/public/browser/navigation_ui_data.h"
 #include "content/public/browser/resource_context.h"
 #include "content/public/browser/resource_dispatcher_host_delegate.h"
 #include "content/public/browser/stream_handle.h"
@@ -113,8 +114,9 @@
         new NavigationRequestInfo(common_params, begin_params, url,
                                   url::Origin(url), true, false, false, -1));
 
-    return NavigationURLLoader::Create(
-        browser_context_.get(), std::move(request_info), nullptr, delegate);
+    return NavigationURLLoader::Create(browser_context_.get(),
+                                       std::move(request_info), nullptr,
+                                       nullptr, delegate);
   }
 
   // Helper function for fetching the body of a URL to a string.
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc
index 2b3539ed..f2c1ac9 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -77,6 +77,7 @@
 #include "content/common/view_messages.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/global_request_id.h"
+#include "content/public/browser/navigation_ui_data.h"
 #include "content/public/browser/plugin_service.h"
 #include "content/public/browser/resource_dispatcher_host_delegate.h"
 #include "content/public/browser/resource_request_details.h"
@@ -648,15 +649,17 @@
 ResourceDispatcherHostImpl::CreateResourceHandlerForDownload(
     net::URLRequest* request,
     bool is_content_initiated,
-    bool must_download) {
+    bool must_download,
+    bool is_new_request) {
   DCHECK(!create_download_handler_intercept_.is_null());
   // TODO(ananta)
   // Find a better way to create the download handler and notifying the
   // delegate of the download start.
   std::unique_ptr<ResourceHandler> handler =
       create_download_handler_intercept_.Run(request);
-  handler = HandleDownloadStarted(request, std::move(handler),
-                                  is_content_initiated, must_download);
+  handler =
+      HandleDownloadStarted(request, std::move(handler), is_content_initiated,
+                            must_download, is_new_request);
   return handler;
 }
 
@@ -2044,6 +2047,7 @@
 void ResourceDispatcherHostImpl::BeginNavigationRequest(
     ResourceContext* resource_context,
     const NavigationRequestInfo& info,
+    std::unique_ptr<NavigationUIData> navigation_ui_data,
     NavigationURLLoaderImplCore* loader,
     ServiceWorkerNavigationHandleCore* service_worker_handle_core) {
   // PlzNavigate: BeginNavigationRequest currently should only be used for the
@@ -2165,6 +2169,8 @@
       // If in the future this changes this should be updated to somehow get a
       // meaningful value.
       false);  // initiated_in_secure_context
+  extra_info->set_navigation_ui_data(std::move(navigation_ui_data));
+
   // Request takes ownership.
   extra_info->AssociateWithRequest(new_request.get());
 
@@ -2353,8 +2359,9 @@
           blob_context->context()->GetBlobDataFromPublicURL(
               request->original_url()));
     }
-    handler = HandleDownloadStarted(request.get(), std::move(handler),
-                                    is_content_initiated, true);
+    handler = HandleDownloadStarted(
+        request.get(), std::move(handler), is_content_initiated,
+        true /* force_download */, true /* is_new_request */);
   }
   BeginRequestInternal(std::move(request), std::move(handler));
 }
@@ -2368,6 +2375,7 @@
           "456331 ResourceDispatcherHostImpl::StartLoading"));
 
   ResourceLoader* loader_ptr = loader.get();
+  DCHECK(pending_loaders_[info->GetGlobalRequestID()] == nullptr);
   pending_loaders_[info->GetGlobalRequestID()] = std::move(loader);
 
   loader_ptr->StartRequest();
@@ -2684,14 +2692,15 @@
     net::URLRequest* request,
     std::unique_ptr<ResourceHandler> handler,
     bool is_content_initiated,
-    bool must_download) {
+    bool must_download,
+    bool is_new_request) {
   if (delegate()) {
     const ResourceRequestInfoImpl* request_info(
         ResourceRequestInfoImpl::ForRequest(request));
     ScopedVector<ResourceThrottle> throttles;
-    delegate()->DownloadStarting(
-        request, request_info->GetContext(), is_content_initiated, true,
-        &throttles);
+    delegate()->DownloadStarting(request, request_info->GetContext(),
+                                 is_content_initiated, true, is_new_request,
+                                 &throttles);
     if (!throttles.empty()) {
       handler.reset(new ThrottlingResourceHandler(std::move(handler), request,
                                                   std::move(throttles)));
diff --git a/content/browser/loader/resource_dispatcher_host_impl.h b/content/browser/loader/resource_dispatcher_host_impl.h
index 76e6d282..0cd8d209 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.h
+++ b/content/browser/loader/resource_dispatcher_host_impl.h
@@ -59,6 +59,7 @@
 class AsyncRevalidationManager;
 class LoaderDelegate;
 class NavigationURLLoaderImplCore;
+class NavigationUIData;
 class RenderFrameHostImpl;
 class ResourceContext;
 class ResourceDispatcherHostDelegate;
@@ -234,7 +235,8 @@
   virtual std::unique_ptr<ResourceHandler> CreateResourceHandlerForDownload(
       net::URLRequest* request,
       bool is_content_initiated,
-      bool must_download);
+      bool must_download,
+      bool is_new_request);
 
   // Called to determine whether the response to |request| should be intercepted
   // and handled as a stream. Streams are used to pass direct access to a
@@ -272,6 +274,7 @@
   void BeginNavigationRequest(
       ResourceContext* resource_context,
       const NavigationRequestInfo& info,
+      std::unique_ptr<NavigationUIData> navigation_ui_data,
       NavigationURLLoaderImplCore* loader,
       ServiceWorkerNavigationHandleCore* service_worker_handle_core);
 
@@ -651,7 +654,8 @@
       net::URLRequest* request,
       std::unique_ptr<ResourceHandler> handler,
       bool is_content_initiated,
-      bool must_download);
+      bool must_download,
+      bool is_new_request);
 
   LoaderMap pending_loaders_;
 
diff --git a/content/browser/loader/resource_dispatcher_host_unittest.cc b/content/browser/loader/resource_dispatcher_host_unittest.cc
index 72f6a0a..91f332d 100644
--- a/content/browser/loader/resource_dispatcher_host_unittest.cc
+++ b/content/browser/loader/resource_dispatcher_host_unittest.cc
@@ -1082,7 +1082,7 @@
                                     url::Origin(url), true, false, false, -1));
       std::unique_ptr<NavigationURLLoader> test_loader =
           NavigationURLLoader::Create(browser_context_.get(),
-                                      std::move(request_info), nullptr,
+                                      std::move(request_info), nullptr, nullptr,
                                       &delegate);
 
       // The navigation should fail with the expected error code.
@@ -2569,7 +2569,8 @@
                                   url::Origin(download_url), true, false, false,
                                   -1));
     std::unique_ptr<NavigationURLLoader> loader = NavigationURLLoader::Create(
-        browser_context_.get(), std::move(request_info), nullptr, &delegate);
+        browser_context_.get(), std::move(request_info), nullptr, nullptr,
+        &delegate);
 
     // Wait until a response has been received and proceed with the response.
     KickOffRequest();
diff --git a/content/browser/loader/resource_request_info_impl.cc b/content/browser/loader/resource_request_info_impl.cc
index 90a17d5..18bd89a 100644
--- a/content/browser/loader/resource_request_info_impl.cc
+++ b/content/browser/loader/resource_request_info_impl.cc
@@ -305,6 +305,10 @@
   return report_raw_headers_;
 }
 
+NavigationUIData* ResourceRequestInfoImpl::GetNavigationUIData() const {
+  return navigation_ui_data_.get();
+}
+
 void ResourceRequestInfoImpl::AssociateWithRequest(net::URLRequest* request) {
   request->SetUserData(NULL, this);
   int render_process_id;
diff --git a/content/browser/loader/resource_request_info_impl.h b/content/browser/loader/resource_request_info_impl.h
index 726909f..b515277 100644
--- a/content/browser/loader/resource_request_info_impl.h
+++ b/content/browser/loader/resource_request_info_impl.h
@@ -14,6 +14,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/supports_user_data.h"
 #include "content/common/resource_request_body_impl.h"
+#include "content/public/browser/navigation_ui_data.h"
 #include "content/public/browser/resource_request_info.h"
 #include "content/public/common/referrer.h"
 #include "content/public/common/resource_type.h"
@@ -94,6 +95,7 @@
   bool IsDownload() const override;
   bool IsUsingLoFi() const override;
   bool ShouldReportRawHeaders() const;
+  NavigationUIData* GetNavigationUIData() const override;
 
   CONTENT_EXPORT void AssociateWithRequest(net::URLRequest* request);
 
@@ -189,6 +191,11 @@
     initiated_in_secure_context_ = secure;
   }
 
+  void set_navigation_ui_data(
+      std::unique_ptr<NavigationUIData> navigation_ui_data) {
+    navigation_ui_data_ = std::move(navigation_ui_data);
+  }
+
  private:
   FRIEND_TEST_ALL_PREFIXES(ResourceDispatcherHostTest,
                            DeletedFilterDetached);
@@ -231,6 +238,7 @@
   const std::string original_headers_;
   scoped_refptr<ResourceRequestBodyImpl> body_;
   bool initiated_in_secure_context_;
+  std::unique_ptr<NavigationUIData> navigation_ui_data_;
 
   DISALLOW_COPY_AND_ASSIGN(ResourceRequestInfoImpl);
 };
diff --git a/content/browser/manifest/manifest_manager_host.cc b/content/browser/manifest/manifest_manager_host.cc
index 5891affd..699576c 100644
--- a/content/browser/manifest/manifest_manager_host.cc
+++ b/content/browser/manifest/manifest_manager_host.cc
@@ -125,9 +125,7 @@
   for (auto& icon : manifest.icons) {
     if (!icon.src.is_valid())
       icon.src = GURL();
-    icon.type = base::NullableString16(
-        icon.type.string().substr(0, Manifest::kMaxIPCStringLength),
-        icon.type.is_null());
+    icon.type = icon.type.substr(0, Manifest::kMaxIPCStringLength);
   }
   manifest.gcm_sender_id = base::NullableString16(
         manifest.gcm_sender_id.string().substr(
diff --git a/content/browser/media/android/browser_media_player_manager.cc b/content/browser/media/android/browser_media_player_manager.cc
index c02a645..c46bc99e 100644
--- a/content/browser/media/android/browser_media_player_manager.cc
+++ b/content/browser/media/android/browser_media_player_manager.cc
@@ -214,14 +214,11 @@
           // small chunks of data.
           RequestDecoderResources(media_player_params.player_id, true);
 #if !defined(USE_AURA)
-      ContentViewCoreImpl* content_view_core_impl =
-          static_cast<ContentViewCoreImpl*>(
-              ContentViewCore::FromWebContents(web_contents_));
-      if (!content_view_core_impl) {
-        extract_metadata = false;
+      if (WebContentsDelegate* delegate = web_contents_->GetDelegate()) {
+        should_block =
+            delegate->ShouldBlockMediaRequest(media_player_params.url);
       } else {
-        should_block = content_view_core_impl->ShouldBlockMediaRequest(
-            media_player_params.url);
+        extract_metadata = false;
       }
 #endif
       if (!extract_metadata) {
@@ -455,8 +452,16 @@
         gfx::Size(player->GetVideoWidth(), player->GetVideoHeight());
   }
 
+  if (!web_contents()->GetDelegate())
+    return;
+
+  base::android::ScopedJavaLocalRef<jobject> embedder(
+      web_contents()->GetDelegate()->GetContentVideoViewEmbedder());
   video_view_.reset(
-      new ContentVideoView(this, GetContentViewCore(), natural_video_size));
+      new ContentVideoView(this,
+                           GetContentViewCore(),
+                           embedder,
+                           natural_video_size));
 
   base::android::ScopedJavaLocalRef<jobject> j_content_video_view =
       video_view_->GetJavaObject(base::android::AttachCurrentThread());
diff --git a/content/browser/media/android/browser_media_session_manager_browsertest.cc b/content/browser/media/android/browser_media_session_manager_browsertest.cc
index ddd11e1..09e65a9 100644
--- a/content/browser/media/android/browser_media_session_manager_browsertest.cc
+++ b/content/browser/media/android/browser_media_session_manager_browsertest.cc
@@ -55,7 +55,7 @@
   for (const auto& artwork : metadata->artwork) {
     generated_script << artwork_separator << "{"
        << "src: \"" << artwork.src.spec() << "\", "
-       << "type: \"" << artwork.type.string() << "\", "
+       << "type: \"" << artwork.type << "\", "
        << "sizes: \"";
     for (const auto& size : artwork.sizes) {
       generated_script << size.width() << "x" << size.height() << " ";
@@ -83,7 +83,7 @@
   *os << "artwork=[";
   for (const auto& artwork : metadata->artwork) {
     *os << "{ src=" << artwork.src.spec() << ", ";
-    *os << "type=" << artwork.type.string() << ", ";
+    *os << "type=" << artwork.type << ", ";
     *os << "sizes=[";
     for (const auto& size : artwork.sizes) {
       *os <<  size.width() << "x" << size.height() << " ";
@@ -150,7 +150,7 @@
   expected->album = base::ASCIIToUTF16("album1");
   MediaMetadata::Artwork artwork;
   artwork.src = GURL("http://foo.com/bar.png");
-  artwork.type = base::NullableString16(base::ASCIIToUTF16("image/png"), false);
+  artwork.type = base::ASCIIToUTF16("image/png");
   artwork.sizes.push_back(gfx::Size(128, 128));
   expected->artwork.push_back(artwork);
 
@@ -175,8 +175,7 @@
   expected->album = base::ASCIIToUTF16("album2");
   MediaMetadata::Artwork artwork;
   artwork.src = GURL("http://foo.com/bar.jpg");
-  artwork.type = base::NullableString16(
-      base::ASCIIToUTF16("image/jpeg"), false);
+  artwork.type = base::ASCIIToUTF16("image/jpeg");
   artwork.sizes.push_back(gfx::Size(256, 256));
   expected->artwork.push_back(artwork);
 
@@ -234,8 +233,7 @@
   base::Optional<MediaMetadata> dirty_metadata = MediaMetadata();
   MediaMetadata::Artwork file_artwork;
   file_artwork.src = GURL("file:///foo/bar.jpg");
-  file_artwork.type = base::NullableString16(
-      base::ASCIIToUTF16("image/jpeg"), false);
+  file_artwork.type = base::ASCIIToUTF16("image/jpeg");
   dirty_metadata->artwork.push_back(file_artwork);
 
   base::Optional<MediaMetadata> expected = MediaMetadata();
diff --git a/content/browser/media/android/browser_surface_view_manager.cc b/content/browser/media/android/browser_surface_view_manager.cc
index c5fab83..405f2281 100644
--- a/content/browser/media/android/browser_surface_view_manager.cc
+++ b/content/browser/media/android/browser_surface_view_manager.cc
@@ -13,6 +13,7 @@
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/media/surface_view_manager_messages_android.h"
 #include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents_delegate.h"
 #include "media/base/surface_manager.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -81,10 +82,15 @@
     return;
   }
 
-  ContentViewCore* cvc = ContentViewCore::FromWebContents(
-      WebContents::FromRenderFrameHost(render_frame_host_));
+  WebContents* web_contents =
+      WebContents::FromRenderFrameHost(render_frame_host_);
+  if (!web_contents->GetDelegate())
+    return;
+  ContentViewCore* cvc = ContentViewCore::FromWebContents(web_contents);
   content_video_view_.reset(
-      new ContentVideoView(this, cvc, video_natural_size));
+      new ContentVideoView(this, cvc,
+          web_contents->GetDelegate()->GetContentVideoViewEmbedder(),
+          video_natural_size));
 }
 
 void BrowserSurfaceViewManager::OnNaturalSizeChanged(const gfx::Size& size) {
diff --git a/content/browser/media/capture/aura_window_capture_machine.cc b/content/browser/media/capture/aura_window_capture_machine.cc
index 800d6f9c..0878419 100644
--- a/content/browser/media/capture/aura_window_capture_machine.cc
+++ b/content/browser/media/capture/aura_window_capture_machine.cc
@@ -38,6 +38,7 @@
 AuraWindowCaptureMachine::AuraWindowCaptureMachine()
     : desktop_window_(NULL),
       screen_capture_(false),
+      frame_capture_active_(true),
       weak_factory_(this) {}
 
 AuraWindowCaptureMachine::~AuraWindowCaptureMachine() {}
@@ -94,6 +95,30 @@
   return true;
 }
 
+void AuraWindowCaptureMachine::Suspend() {
+  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+                          base::Bind(&AuraWindowCaptureMachine::InternalSuspend,
+                                     base::Unretained(this)));
+}
+
+void AuraWindowCaptureMachine::InternalSuspend() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DVLOG(1) << "Suspending frame capture and delivery.";
+  frame_capture_active_ = false;
+}
+
+void AuraWindowCaptureMachine::Resume() {
+  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+                          base::Bind(&AuraWindowCaptureMachine::InternalResume,
+                                     base::Unretained(this)));
+}
+
+void AuraWindowCaptureMachine::InternalResume() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DVLOG(1) << "Resuming frame capture and delivery.";
+  frame_capture_active_ = true;
+}
+
 void AuraWindowCaptureMachine::Stop(const base::Closure& callback) {
   // Stops the capture machine asynchronously.
   BrowserThread::PostTask(
@@ -408,7 +433,8 @@
   // captures and quality/smoothness of animating content will suffer
   // significantly.
   // http://crbug.com/492839
-  Capture(timestamp);
+  if (frame_capture_active_)
+    Capture(timestamp);
 }
 
 void AuraWindowCaptureMachine::OnCompositingShuttingDown(
diff --git a/content/browser/media/capture/aura_window_capture_machine.h b/content/browser/media/capture/aura_window_capture_machine.h
index 848c325..ff233439 100644
--- a/content/browser/media/capture/aura_window_capture_machine.h
+++ b/content/browser/media/capture/aura_window_capture_machine.h
@@ -43,6 +43,8 @@
   void Start(const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy,
              const media::VideoCaptureParams& params,
              const base::Callback<void(bool)> callback) override;
+  void Suspend() override;
+  void Resume() override;
   void Stop(const base::Closure& callback) override;
   void MaybeCaptureForRefresh() override;
 
@@ -66,6 +68,8 @@
   bool InternalStart(
       const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy,
       const media::VideoCaptureParams& params);
+  void InternalSuspend();
+  void InternalResume();
   void InternalStop(const base::Closure& callback);
 
   // Captures a frame. |event_time| is provided by the compositor, or is null
@@ -126,6 +130,10 @@
   // screen from sleeping for the drive-by web.
   std::unique_ptr<device::PowerSaveBlocker> power_save_blocker_;
 
+  // False while frame capture has been suspended. All other aspects of the
+  // machine are maintained.
+  bool frame_capture_active_;
+
   // WeakPtrs are used for the asynchronous capture callbacks passed to external
   // modules.  They are only valid on the UI thread and become invalidated
   // immediately when InternalStop() is called to ensure that no more captured
diff --git a/content/browser/media/capture/web_contents_video_capture_device.cc b/content/browser/media/capture/web_contents_video_capture_device.cc
index f269ee4..e475cbd 100644
--- a/content/browser/media/capture/web_contents_video_capture_device.cc
+++ b/content/browser/media/capture/web_contents_video_capture_device.cc
@@ -61,6 +61,7 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/memory/weak_ptr.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/sequenced_task_runner.h"
@@ -264,6 +265,8 @@
   void Start(const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy,
              const media::VideoCaptureParams& params,
              const base::Callback<void(bool)> callback) override;
+  void Suspend() override;
+  void Resume() override;
   void Stop(const base::Closure& callback) override;
   bool IsAutoThrottlingEnabled() const override {
     return auto_throttling_enabled_;
@@ -284,6 +287,8 @@
   bool InternalStart(
       const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy,
       const media::VideoCaptureParams& params);
+  void InternalSuspend();
+  void InternalResume();
   void InternalStop(const base::Closure& callback);
   void InternalMaybeCaptureForRefresh();
   bool IsStarted() const;
@@ -345,6 +350,11 @@
   // oracle, and initiating captures accordingly.
   std::unique_ptr<ContentCaptureSubscription> subscription_;
 
+  // False while frame capture has been suspended. This prevents subscriptions
+  // from being created by RenewFrameSubscription() until frame capture is
+  // resumed.
+  bool frame_capture_active_;
+
   // Weak pointer factory used to invalidate callbacks.
   // NOTE: Weak pointers must be invalidated before all other member variables.
   base::WeakPtrFactory<WebContentsCaptureMachine> weak_ptr_factory_;
@@ -618,6 +628,7 @@
       initial_main_render_frame_id_(main_render_frame_id),
       tracker_(new WebContentsTracker(true)),
       auto_throttling_enabled_(enable_auto_throttling),
+      frame_capture_active_(true),
       weak_ptr_factory_(this) {
   DVLOG(1) << "Created WebContentsCaptureMachine for " << render_process_id
            << ':' << main_render_frame_id
@@ -668,10 +679,43 @@
   tracker_->Start(initial_render_process_id_, initial_main_render_frame_id_,
                   base::Bind(&WebContentsCaptureMachine::RenewFrameSubscription,
                              weak_ptr_factory_.GetWeakPtr()));
+  if (WebContents* contents = tracker_->web_contents())
+    contents->IncrementCapturerCount(ComputeOptimalViewSize());
 
   return true;
 }
 
+void WebContentsCaptureMachine::Suspend() {
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      base::Bind(&WebContentsCaptureMachine::InternalSuspend,
+                 base::Unretained(this)));
+}
+
+void WebContentsCaptureMachine::InternalSuspend() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  if (!frame_capture_active_)
+    return;
+  frame_capture_active_ = false;
+  if (IsStarted())
+    RenewFrameSubscription(true);
+}
+
+void WebContentsCaptureMachine::Resume() {
+  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+                          base::Bind(&WebContentsCaptureMachine::InternalResume,
+                                     base::Unretained(this)));
+}
+
+void WebContentsCaptureMachine::InternalResume() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  if (frame_capture_active_)
+    return;
+  frame_capture_active_ = true;
+  if (IsStarted())
+    RenewFrameSubscription(true);
+}
+
 void WebContentsCaptureMachine::Stop(const base::Closure& callback) {
   // Stops the capture machine asynchronously.
   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
@@ -691,9 +735,9 @@
   // return false from here onward.
   weak_ptr_factory_.InvalidateWeakPtrs();
 
-  // Note: RenewFrameSubscription() must be called before stopping |tracker_| so
-  // the web_contents() can be notified that the capturing is ending.
   RenewFrameSubscription(false);
+  if (WebContents* contents = tracker_->web_contents())
+    contents->DecrementCapturerCount();
   tracker_->Stop();
 
   // The render thread cannot be stopped on the UI thread, so post a message
@@ -884,15 +928,13 @@
       had_target ? tracker_->GetTargetRenderWidgetHost() : nullptr;
 
   // Always destroy the old subscription before creating a new one.
-  const bool had_subscription = !!subscription_;
-  subscription_.reset();
-
-  DVLOG(1) << "Renewing frame subscription to RWH@" << rwh
-           << ", had_subscription=" << had_subscription;
+  if (subscription_) {
+    DVLOG(1) << "Cancelling existing ContentCaptureSubscription.";
+    subscription_.reset();
+  }
 
   if (!rwh) {
-    if (had_subscription && tracker_->web_contents())
-      tracker_->web_contents()->DecrementCapturerCount();
+    DVLOG(1) << "Cannot renew ContentCaptureSubscription: no RWH target.";
     if (IsStarted()) {
       // Tracking of WebContents and/or its main frame has failed before Stop()
       // was called, so report this as an error:
@@ -902,12 +944,12 @@
     return;
   }
 
-  if (!had_subscription && tracker_->web_contents())
-    tracker_->web_contents()->IncrementCapturerCount(ComputeOptimalViewSize());
-
-  subscription_.reset(new ContentCaptureSubscription(
-      *rwh, oracle_proxy_, base::Bind(&WebContentsCaptureMachine::Capture,
-                                      weak_ptr_factory_.GetWeakPtr())));
+  if (frame_capture_active_) {
+    DVLOG(1) << "Renewing ContentCaptureSubscription to RWH@" << rwh;
+    subscription_.reset(new ContentCaptureSubscription(
+        *rwh, oracle_proxy_, base::Bind(&WebContentsCaptureMachine::Capture,
+                                        weak_ptr_factory_.GetWeakPtr())));
+  }
 }
 
 void WebContentsCaptureMachine::UpdateCaptureSize() {
@@ -976,6 +1018,14 @@
   core_->RequestRefreshFrame();
 }
 
+void WebContentsVideoCaptureDevice::MaybeSuspend() {
+  core_->Suspend();
+}
+
+void WebContentsVideoCaptureDevice::Resume() {
+  core_->Resume();
+}
+
 void WebContentsVideoCaptureDevice::StopAndDeAllocate() {
   core_->StopAndDeAllocate();
 }
diff --git a/content/browser/media/capture/web_contents_video_capture_device.h b/content/browser/media/capture/web_contents_video_capture_device.h
index ea92b3b..6bcddfa9 100644
--- a/content/browser/media/capture/web_contents_video_capture_device.h
+++ b/content/browser/media/capture/web_contents_video_capture_device.h
@@ -38,6 +38,8 @@
   void AllocateAndStart(const media::VideoCaptureParams& params,
                         std::unique_ptr<Client> client) override;
   void RequestRefreshFrame() override;
+  void MaybeSuspend() override;
+  void Resume() override;
   void StopAndDeAllocate() override;
 
  private:
diff --git a/content/browser/media/capture/web_contents_video_capture_device_unittest.cc b/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
index 60d20ff..922ce7c 100644
--- a/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
+++ b/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
@@ -20,8 +20,7 @@
 #include "build/build_config.h"
 #include "content/browser/browser_thread_impl.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
-#include "content/browser/renderer_host/media/video_capture_buffer_handle.h"
-#include "content/browser/renderer_host/media/video_capture_buffer_pool.h"
+#include "content/browser/renderer_host/media/video_capture_buffer_tracker_factory_impl.h"
 #include "content/browser/renderer_host/render_view_host_factory.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
@@ -38,6 +37,7 @@
 #include "media/base/video_frame.h"
 #include "media/base/video_util.h"
 #include "media/base/yuv_convert.h"
+#include "media/capture/video/video_capture_buffer_pool_impl.h"
 #include "skia/ext/platform_canvas.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -333,7 +333,8 @@
       const base::Closure& error_callback)
       : report_callback_(report_callback),
         error_callback_(error_callback) {
-    buffer_pool_ = new VideoCaptureBufferPoolImpl(2);
+    buffer_pool_ = new media::VideoCaptureBufferPoolImpl(
+        base::MakeUnique<VideoCaptureBufferTrackerFactoryImpl>(), 2);
   }
   ~StubClient() override {}
 
@@ -352,10 +353,11 @@
                       media::VideoPixelFormat format,
                       media::VideoPixelStorage storage) override {
     CHECK_EQ(format, media::PIXEL_FORMAT_I420);
-    int buffer_id_to_drop = VideoCaptureBufferPool::kInvalidId;  // Ignored.
+    int buffer_id_to_drop =
+        media::VideoCaptureBufferPool::kInvalidId;  // Ignored.
     const int buffer_id = buffer_pool_->ReserveForProducer(
         dimensions, format, storage, &buffer_id_to_drop);
-    if (buffer_id == VideoCaptureBufferPool::kInvalidId)
+    if (buffer_id == media::VideoCaptureBufferPool::kInvalidId)
       return NULL;
 
     return std::unique_ptr<media::VideoCaptureDevice::Client::Buffer>(
@@ -406,7 +408,7 @@
     CHECK_EQ(format, media::PIXEL_FORMAT_I420);
     const int buffer_id =
         buffer_pool_->ResurrectLastForProducer(dimensions, format, storage);
-    if (buffer_id == VideoCaptureBufferPool::kInvalidId)
+    if (buffer_id == media::VideoCaptureBufferPool::kInvalidId)
       return nullptr;
     return std::unique_ptr<media::VideoCaptureDevice::Client::Buffer>(
         new AutoReleaseBuffer(
@@ -423,9 +425,10 @@
  private:
   class AutoReleaseBuffer : public media::VideoCaptureDevice::Client::Buffer {
    public:
-    AutoReleaseBuffer(const scoped_refptr<VideoCaptureBufferPool>& pool,
-                      std::unique_ptr<VideoCaptureBufferHandle> buffer_handle,
-                      int buffer_id)
+    AutoReleaseBuffer(
+        const scoped_refptr<media::VideoCaptureBufferPool>& pool,
+        std::unique_ptr<media::VideoCaptureBufferHandle> buffer_handle,
+        int buffer_id)
         : id_(buffer_id),
           pool_(pool),
           buffer_handle_(std::move(buffer_handle)) {
@@ -450,11 +453,11 @@
     ~AutoReleaseBuffer() override { pool_->RelinquishProducerReservation(id_); }
 
     const int id_;
-    const scoped_refptr<VideoCaptureBufferPool> pool_;
-    const std::unique_ptr<VideoCaptureBufferHandle> buffer_handle_;
+    const scoped_refptr<media::VideoCaptureBufferPool> pool_;
+    const std::unique_ptr<media::VideoCaptureBufferHandle> buffer_handle_;
   };
 
-  scoped_refptr<VideoCaptureBufferPool> buffer_pool_;
+  scoped_refptr<media::VideoCaptureBufferPool> buffer_pool_;
   base::Callback<void(SkColor, const gfx::Size&)> report_callback_;
   base::Closure error_callback_;
 
@@ -465,7 +468,8 @@
  public:
   StubClientObserver()
       : error_encountered_(false),
-        wait_color_yuv_(0xcafe1950) {
+        wait_color_yuv_(0xcafe1950),
+        expecting_frames_(true) {
     client_.reset(new StubClient(
         base::Bind(&StubClientObserver::DidDeliverFrame,
                    base::Unretained(this)),
@@ -478,8 +482,14 @@
     return std::move(client_);
   }
 
+  void SetIsExpectingFrames(bool expecting_frames) {
+    base::AutoLock guard(lock_);
+    expecting_frames_ = expecting_frames;
+  }
+
   void QuitIfConditionsMet(SkColor color, const gfx::Size& size) {
     base::AutoLock guard(lock_);
+    EXPECT_TRUE(expecting_frames_);
     if (error_encountered_ || wait_color_yuv_ == kNotInterested ||
         wait_color_yuv_ == color) {
       last_frame_color_yuv_ = color;
@@ -563,6 +573,7 @@
   SkColor last_frame_color_yuv_;
   gfx::Size last_frame_size_;
   std::unique_ptr<StubClient> client_;
+  bool expecting_frames_;
 
   DISALLOW_COPY_AND_ASSIGN(StubClientObserver);
 };
@@ -1183,6 +1194,41 @@
   }
 }
 
+// Tests the Suspend/Resume() functionality.
+TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest, SuspendsAndResumes) {
+  media::VideoCaptureParams capture_params;
+  capture_params.requested_format.frame_size.SetSize(kTestWidth, kTestHeight);
+  capture_params.requested_format.frame_rate = kTestFramesPerSecond;
+  capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
+  device()->AllocateAndStart(capture_params, client_observer()->PassClient());
+
+  for (int i = 0; i < 3; ++i) {
+    // Draw a RED frame and wait for a normal frame capture to occur.
+    source()->SetSolidColor(SK_ColorRED);
+    SimulateDrawEvent();
+    ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColor(SK_ColorRED));
+
+    // Suspend capture and then draw a GREEN frame. No frame capture should
+    // occur.
+    device()->MaybeSuspend();
+    base::RunLoop().RunUntilIdle();
+    client_observer()->SetIsExpectingFrames(false);
+    source()->SetSolidColor(SK_ColorGREEN);
+    SimulateDrawEvent();
+    base::RunLoop().RunUntilIdle();
+
+    // Resume capture and then draw a BLUE frame and wait for it to be captured.
+    device()->Resume();
+    base::RunLoop().RunUntilIdle();
+    client_observer()->SetIsExpectingFrames(true);
+    source()->SetSolidColor(SK_ColorBLUE);
+    SimulateDrawEvent();
+    ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColor(SK_ColorBLUE));
+  }
+
+  device()->StopAndDeAllocate();
+}
+
 // Tests the RequestRefreshFrame() functionality.
 TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest, ProvidesRefreshFrames) {
   media::VideoCaptureParams capture_params;
diff --git a/content/browser/media/media_browsertest.cc b/content/browser/media/media_browsertest.cc
index 667d5419..633b562 100644
--- a/content/browser/media/media_browsertest.cc
+++ b/content/browser/media/media_browsertest.cc
@@ -133,6 +133,10 @@
 IN_PROC_BROWSER_TEST_P(MediaTest, VideoBearHighBitDepthVP9) {
   PlayVideo("bear-320x180-hi10p-vp9.webm", GetParam());
 }
+
+IN_PROC_BROWSER_TEST_P(MediaTest, VideoBear12DepthVP9) {
+  PlayVideo("bear-320x180-hi12p-vp9.webm", GetParam());
+}
 #endif
 
 #if defined(USE_PROPRIETARY_CODECS)
diff --git a/content/browser/memory/memory_monitor_android.cc b/content/browser/memory/memory_monitor_android.cc
index bbe33521..70c1e6d 100644
--- a/content/browser/memory/memory_monitor_android.cc
+++ b/content/browser/memory/memory_monitor_android.cc
@@ -15,27 +15,20 @@
 const size_t kMBShift = 20;
 }
 
-// static
-std::unique_ptr<MemoryMonitorAndroid> MemoryMonitorAndroid::Create() {
-  return base::WrapUnique(new MemoryMonitorAndroid);
-}
+// An implementation of MemoryMonitorAndroid::Delegate using the Android APIs.
+class MemoryMonitorAndroidDelegateImpl : public MemoryMonitorAndroid::Delegate {
+ public:
+  MemoryMonitorAndroidDelegateImpl() {}
+  ~MemoryMonitorAndroidDelegateImpl() override {}
 
-// static
-bool MemoryMonitorAndroid::Register(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
+  using MemoryInfo = MemoryMonitorAndroid::MemoryInfo;
+  void GetMemoryInfo(MemoryInfo* out) override;
 
-MemoryMonitorAndroid::MemoryMonitorAndroid() {}
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MemoryMonitorAndroidDelegateImpl);
+};
 
-MemoryMonitorAndroid::~MemoryMonitorAndroid() {}
-
-int MemoryMonitorAndroid::GetFreeMemoryUntilCriticalMB() {
-  MemoryInfo info;
-  GetMemoryInfo(&info);
-  return (info.avail_mem - info.threshold) >> kMBShift;
-}
-
-void MemoryMonitorAndroid::GetMemoryInfo(MemoryInfo* out) {
+void MemoryMonitorAndroidDelegateImpl::GetMemoryInfo(MemoryInfo* out) {
   DCHECK(out);
   JNIEnv* env = base::android::AttachCurrentThread();
   Java_MemoryMonitorAndroid_getMemoryInfo(
@@ -61,6 +54,34 @@
   info->total_mem = total_mem;
 }
 
+// static
+std::unique_ptr<MemoryMonitorAndroid> MemoryMonitorAndroid::Create() {
+  auto delegate = base::WrapUnique(new MemoryMonitorAndroidDelegateImpl);
+  return base::WrapUnique(new MemoryMonitorAndroid(std::move(delegate)));
+}
+
+// static
+bool MemoryMonitorAndroid::Register(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+MemoryMonitorAndroid::MemoryMonitorAndroid(std::unique_ptr<Delegate> delegate)
+    : delegate_(std::move(delegate)) {
+  DCHECK(delegate_.get());
+}
+
+MemoryMonitorAndroid::~MemoryMonitorAndroid() {}
+
+int MemoryMonitorAndroid::GetFreeMemoryUntilCriticalMB() {
+  MemoryInfo info;
+  GetMemoryInfo(&info);
+  return (info.avail_mem - info.threshold) >> kMBShift;
+}
+
+void MemoryMonitorAndroid::GetMemoryInfo(MemoryInfo* out) {
+  delegate_->GetMemoryInfo(out);
+}
+
 // Implementation of a factory function defined in memory_monitor.h.
 std::unique_ptr<MemoryMonitor> CreateMemoryMonitor() {
   return MemoryMonitorAndroid::Create();
diff --git a/content/browser/memory/memory_monitor_android.h b/content/browser/memory/memory_monitor_android.h
index abd7824c..a1733c5a 100644
--- a/content/browser/memory/memory_monitor_android.h
+++ b/content/browser/memory/memory_monitor_android.h
@@ -26,6 +26,17 @@
     jlong total_mem;
   };
 
+  // Delegate interface used by MemoryMonitorAndroid.
+  class Delegate {
+   public:
+    Delegate() {}
+    virtual ~Delegate() {};
+
+    // Get MemoryInfo. Implementations should fill |out| accordingly.
+    virtual void GetMemoryInfo(MemoryInfo* out) = 0;
+  };
+
+  MemoryMonitorAndroid(std::unique_ptr<Delegate> delegate);
   ~MemoryMonitorAndroid() override;
 
   // MemoryMonitor implementation:
@@ -34,8 +45,10 @@
   // Get memory info from the Android system.
   void GetMemoryInfo(MemoryInfo* out);
 
+  Delegate* delegate() { return delegate_.get(); }
+
  private:
-  MemoryMonitorAndroid();
+  std::unique_ptr<Delegate> delegate_;
 
   DISALLOW_COPY_AND_ASSIGN(MemoryMonitorAndroid);
 };
diff --git a/content/browser/memory/memory_monitor_android_unittest.cc b/content/browser/memory/memory_monitor_android_unittest.cc
index bb6e85c2..7c62d5f1 100644
--- a/content/browser/memory/memory_monitor_android_unittest.cc
+++ b/content/browser/memory/memory_monitor_android_unittest.cc
@@ -4,16 +4,50 @@
 
 #include "content/browser/memory/memory_monitor_android.h"
 
+#include "base/memory/ptr_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace content {
 
+class MockMemoryMonitorAndroidDelegate : public MemoryMonitorAndroid::Delegate {
+ public:
+  MockMemoryMonitorAndroidDelegate() {}
+  ~MockMemoryMonitorAndroidDelegate() override {}
+
+  using MemoryInfo = MemoryMonitorAndroid::MemoryInfo;
+
+  void SetMemoryInfo(const MemoryInfo& info) {
+    memcpy(&memory_info_, &info, sizeof(memory_info_));
+  }
+
+  void GetMemoryInfo(MemoryInfo* out) override {
+    memcpy(out, &memory_info_, sizeof(memory_info_));
+  }
+
+ private:
+  MemoryInfo memory_info_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockMemoryMonitorAndroidDelegate);
+};
+
 class MemoryMonitorAndroidTest : public testing::Test {
  public:
-  MemoryMonitorAndroidTest() : monitor_(MemoryMonitorAndroid::Create()) {}
+  MemoryMonitorAndroidTest() : monitor_(MemoryMonitorAndroid::Create()) {
+    auto mock_delegate = base::WrapUnique(new MockMemoryMonitorAndroidDelegate);
+    mocked_monitor_.reset(
+        new MemoryMonitorAndroid(std::move(mock_delegate)));
+  }
 
  protected:
+  static const int kMBShift = 20;
+
+  MockMemoryMonitorAndroidDelegate* mock_delegate() {
+    return static_cast<MockMemoryMonitorAndroidDelegate*>(
+        mocked_monitor_->delegate());
+  }
+
   std::unique_ptr<MemoryMonitorAndroid> monitor_;
+  std::unique_ptr<MemoryMonitorAndroid> mocked_monitor_;
 };
 
 TEST_F(MemoryMonitorAndroidTest, GetMemoryInfo) {
@@ -24,4 +58,15 @@
   EXPECT_GT(info.total_mem, 0);
 }
 
+TEST_F(MemoryMonitorAndroidTest, GetFreeMemoryUntilCriticalMB) {
+  MemoryMonitorAndroid::MemoryInfo info = {
+    .avail_mem = 100 << kMBShift,
+    .low_memory = false,
+    .threshold = 80 << kMBShift,
+    .total_mem = 150 << kMBShift,
+  };
+  mock_delegate()->SetMemoryInfo(info);
+  EXPECT_EQ(20, mocked_monitor_->GetFreeMemoryUntilCriticalMB());
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/DEPS b/content/browser/renderer_host/DEPS
index 3c872db..79ab5a9 100644
--- a/content/browser/renderer_host/DEPS
+++ b/content/browser/renderer_host/DEPS
@@ -3,7 +3,6 @@
   "+components/display_compositor",
   "+services/ui/public",
   "+third_party/zlib",
-  "+third_party/libyuv",
 
   # The renderer_host files should only call upwards in the layering via the
   # delegate interfaces.
diff --git a/content/browser/renderer_host/media/gpu_memory_buffer_handle.h b/content/browser/renderer_host/media/gpu_memory_buffer_handle.h
index 05e5ccf6..4dd61a22 100644
--- a/content/browser/renderer_host/media/gpu_memory_buffer_handle.h
+++ b/content/browser/renderer_host/media/gpu_memory_buffer_handle.h
@@ -5,7 +5,7 @@
 #ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_GPU_MEMORY_BUFFER_HANDLE_H_
 #define CONTENT_BROWSER_RENDERER_HOST_MEDIA_GPU_MEMORY_BUFFER_HANDLE_H_
 
-#include "content/browser/renderer_host/media/video_capture_buffer_handle.h"
+#include "media/capture/video/video_capture_buffer_handle.h"
 
 namespace content {
 
@@ -13,7 +13,7 @@
 
 // A simple proxy that implements the BufferHandle interface, providing
 // accessors to GpuMemoryBufferTracker's memory and properties.
-class GpuMemoryBufferBufferHandle : public VideoCaptureBufferHandle {
+class GpuMemoryBufferBufferHandle : public media::VideoCaptureBufferHandle {
  public:
   // |tracker| must outlive GpuMemoryBufferBufferHandle. This is ensured since
   // a tracker is pinned until ownership of this GpuMemoryBufferBufferHandle
diff --git a/content/browser/renderer_host/media/gpu_memory_buffer_tracker.cc b/content/browser/renderer_host/media/gpu_memory_buffer_tracker.cc
index b4e601c9..a19461f7 100644
--- a/content/browser/renderer_host/media/gpu_memory_buffer_tracker.cc
+++ b/content/browser/renderer_host/media/gpu_memory_buffer_tracker.cc
@@ -58,7 +58,7 @@
   return true;
 }
 
-std::unique_ptr<VideoCaptureBufferHandle>
+std::unique_ptr<media::VideoCaptureBufferHandle>
 GpuMemoryBufferTracker::GetBufferHandle() {
   DCHECK_EQ(gpu_memory_buffers_.size(),
             media::VideoFrame::NumPlanes(pixel_format()));
diff --git a/content/browser/renderer_host/media/gpu_memory_buffer_tracker.h b/content/browser/renderer_host/media/gpu_memory_buffer_tracker.h
index e12a88ce..c3f13d16 100644
--- a/content/browser/renderer_host/media/gpu_memory_buffer_tracker.h
+++ b/content/browser/renderer_host/media/gpu_memory_buffer_tracker.h
@@ -5,13 +5,13 @@
 #ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_GPU_MEMORY_BUFFER_TRACKER_H_
 #define CONTENT_BROWSER_RENDERER_HOST_MEDIA_GPU_MEMORY_BUFFER_TRACKER_H_
 
-#include "content/browser/renderer_host/media/video_capture_buffer_tracker.h"
+#include "media/capture/video/video_capture_buffer_tracker.h"
 
 namespace content {
 
 // Tracker specifics for GpuMemoryBuffer. Owns GpuMemoryBuffers and its
 // associated pixel dimensions.
-class GpuMemoryBufferTracker final : public VideoCaptureBufferTracker {
+class GpuMemoryBufferTracker final : public media::VideoCaptureBufferTracker {
  public:
   GpuMemoryBufferTracker();
   ~GpuMemoryBufferTracker() override;
@@ -21,7 +21,7 @@
             media::VideoPixelStorage storage_type,
             base::Lock* lock) override;
 
-  std::unique_ptr<VideoCaptureBufferHandle> GetBufferHandle() override;
+  std::unique_ptr<media::VideoCaptureBufferHandle> GetBufferHandle() override;
 
   bool ShareToProcess(base::ProcessHandle process_handle,
                       base::SharedMemoryHandle* new_handle) override;
diff --git a/content/browser/renderer_host/media/shared_memory_buffer_handle.h b/content/browser/renderer_host/media/shared_memory_buffer_handle.h
index 3f327528..da29983 100644
--- a/content/browser/renderer_host/media/shared_memory_buffer_handle.h
+++ b/content/browser/renderer_host/media/shared_memory_buffer_handle.h
@@ -5,7 +5,7 @@
 #ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_SHARED_MEMORY_BUFFER_HANDLE_H_
 #define CONTENT_BROWSER_RENDERER_HOST_MEDIA_SHARED_MEMORY_BUFFER_HANDLE_H_
 
-#include "content/browser/renderer_host/media/video_capture_buffer_handle.h"
+#include "media/capture/video/video_capture_buffer_handle.h"
 
 namespace content {
 
@@ -13,7 +13,7 @@
 
 // A simple proxy that implements the BufferHandle interface, providing
 // accessors to SharedMemTracker's memory and properties.
-class SharedMemoryBufferHandle : public VideoCaptureBufferHandle {
+class SharedMemoryBufferHandle : public media::VideoCaptureBufferHandle {
  public:
   // |tracker| must outlive SimpleBufferHandle. This is ensured since a
   // tracker is pinned until ownership of this SimpleBufferHandle is returned
diff --git a/content/browser/renderer_host/media/shared_memory_buffer_tracker.cc b/content/browser/renderer_host/media/shared_memory_buffer_tracker.cc
index 27dca64e..af9235be 100644
--- a/content/browser/renderer_host/media/shared_memory_buffer_tracker.cc
+++ b/content/browser/renderer_host/media/shared_memory_buffer_tracker.cc
@@ -30,7 +30,7 @@
   return shared_memory_.CreateAndMapAnonymous(mapped_size_);
 }
 
-std::unique_ptr<VideoCaptureBufferHandle>
+std::unique_ptr<media::VideoCaptureBufferHandle>
 SharedMemoryBufferTracker::GetBufferHandle() {
   return base::MakeUnique<SharedMemoryBufferHandle>(this);
 }
diff --git a/content/browser/renderer_host/media/shared_memory_buffer_tracker.h b/content/browser/renderer_host/media/shared_memory_buffer_tracker.h
index 2aad666..81504378 100644
--- a/content/browser/renderer_host/media/shared_memory_buffer_tracker.h
+++ b/content/browser/renderer_host/media/shared_memory_buffer_tracker.h
@@ -5,12 +5,13 @@
 #ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_SHARED_MEMORY_BUFFER_TRACKER_H_
 #define CONTENT_BROWSER_RENDERER_HOST_MEDIA_SHARED_MEMORY_BUFFER_TRACKER_H_
 
-#include "content/browser/renderer_host/media/video_capture_buffer_tracker.h"
+#include "media/capture/video/video_capture_buffer_tracker.h"
 
 namespace content {
 
 // Tracker specifics for SharedMemory.
-class SharedMemoryBufferTracker final : public VideoCaptureBufferTracker {
+class SharedMemoryBufferTracker final
+    : public media::VideoCaptureBufferTracker {
  public:
   SharedMemoryBufferTracker();
 
@@ -19,7 +20,7 @@
             media::VideoPixelStorage storage_type,
             base::Lock* lock) override;
 
-  std::unique_ptr<VideoCaptureBufferHandle> GetBufferHandle() override;
+  std::unique_ptr<media::VideoCaptureBufferHandle> GetBufferHandle() override;
   bool ShareToProcess(base::ProcessHandle process_handle,
                       base::SharedMemoryHandle* new_handle) override;
   bool ShareToProcess2(int plane,
diff --git a/content/browser/renderer_host/media/video_capture_buffer_pool_unittest.cc b/content/browser/renderer_host/media/video_capture_buffer_pool_unittest.cc
index 9933c76..e31d446 100644
--- a/content/browser/renderer_host/media/video_capture_buffer_pool_unittest.cc
+++ b/content/browser/renderer_host/media/video_capture_buffer_pool_unittest.cc
@@ -4,7 +4,7 @@
 
 // Unit test for VideoCaptureBufferPool.
 
-#include "content/browser/renderer_host/media/video_capture_buffer_pool.h"
+#include "media/capture/video/video_capture_buffer_pool.h"
 
 #include <stddef.h>
 #include <stdint.h>
@@ -24,9 +24,10 @@
 #include "cc/test/test_web_graphics_context_3d.h"
 #include "components/display_compositor/buffer_queue.h"
 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
-#include "content/browser/renderer_host/media/video_capture_buffer_handle.h"
+#include "content/browser/renderer_host/media/video_capture_buffer_tracker_factory_impl.h"
 #include "content/browser/renderer_host/media/video_capture_controller.h"
 #include "media/base/video_frame.h"
+#include "media/capture/video/video_capture_buffer_pool_impl.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -48,6 +49,10 @@
 
 static const int kTestBufferPoolSize = 3;
 
+// Note that this test does not exercise the class VideoCaptureBufferPool
+// in isolation. The "unit under test" is an instance of VideoCaptureBufferPool
+// with some context that is specific to renderer_host/media, and therefore
+// this test must live here and not in media/capture/video.
 class VideoCaptureBufferPoolTest
     : public testing::TestWithParam<PixelFormatAndStorage> {
  protected:
@@ -119,8 +124,8 @@
   // This is a generic Buffer tracker
   class Buffer {
    public:
-    Buffer(const scoped_refptr<VideoCaptureBufferPool> pool,
-           std::unique_ptr<VideoCaptureBufferHandle> buffer_handle,
+    Buffer(const scoped_refptr<media::VideoCaptureBufferPool> pool,
+           std::unique_ptr<media::VideoCaptureBufferHandle> buffer_handle,
            int id)
         : id_(id), pool_(pool), buffer_handle_(std::move(buffer_handle)) {}
     ~Buffer() { pool_->RelinquishProducerReservation(id()); }
@@ -130,13 +135,15 @@
 
    private:
     const int id_;
-    const scoped_refptr<VideoCaptureBufferPool> pool_;
-    const std::unique_ptr<VideoCaptureBufferHandle> buffer_handle_;
+    const scoped_refptr<media::VideoCaptureBufferPool> pool_;
+    const std::unique_ptr<media::VideoCaptureBufferHandle> buffer_handle_;
   };
 
   VideoCaptureBufferPoolTest()
       : expected_dropped_id_(0),
-        pool_(new VideoCaptureBufferPoolImpl(kTestBufferPoolSize)) {}
+        pool_(new media::VideoCaptureBufferPoolImpl(
+            base::MakeUnique<VideoCaptureBufferTrackerFactoryImpl>(),
+            kTestBufferPoolSize)) {}
 
 #if !defined(OS_ANDROID)
   void SetUp() override {
@@ -161,11 +168,11 @@
     const int buffer_id = pool_->ReserveForProducer(
         dimensions, format_and_storage.pixel_format,
         format_and_storage.pixel_storage, &buffer_id_to_drop);
-    if (buffer_id == VideoCaptureBufferPool::kInvalidId)
+    if (buffer_id == media::VideoCaptureBufferPool::kInvalidId)
       return std::unique_ptr<Buffer>();
     EXPECT_EQ(expected_dropped_id_, buffer_id_to_drop);
 
-    std::unique_ptr<VideoCaptureBufferHandle> buffer_handle =
+    std::unique_ptr<media::VideoCaptureBufferHandle> buffer_handle =
         pool_->GetBufferHandle(buffer_id);
     return std::unique_ptr<Buffer>(
         new Buffer(pool_, std::move(buffer_handle), buffer_id));
@@ -177,7 +184,7 @@
     const int buffer_id = pool_->ResurrectLastForProducer(
         dimensions, format_and_storage.pixel_format,
         format_and_storage.pixel_storage);
-    if (buffer_id == VideoCaptureBufferPool::kInvalidId)
+    if (buffer_id == media::VideoCaptureBufferPool::kInvalidId)
       return std::unique_ptr<Buffer>();
     return std::unique_ptr<Buffer>(
         new Buffer(pool_, pool_->GetBufferHandle(buffer_id), buffer_id));
@@ -185,7 +192,7 @@
 
   base::MessageLoop loop_;
   int expected_dropped_id_;
-  scoped_refptr<VideoCaptureBufferPool> pool_;
+  scoped_refptr<media::VideoCaptureBufferPool> pool_;
 
  private:
 #if !defined(OS_ANDROID)
@@ -204,7 +211,7 @@
       size_hi, 0.0, GetParam().pixel_format, GetParam().pixel_storage);
 
   // Reallocation won't happen for the first part of the test.
-  ExpectDroppedId(VideoCaptureBufferPool::kInvalidId);
+  ExpectDroppedId(media::VideoCaptureBufferPool::kInvalidId);
 
   // The buffer pool should have zero utilization before any buffers have been
   // reserved.
@@ -334,7 +341,7 @@
   ASSERT_EQ(3.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
   void* const memory_pointer_hi = buffer2->data();
   buffer2.reset();  // Frees it.
-  ExpectDroppedId(VideoCaptureBufferPool::kInvalidId);
+  ExpectDroppedId(media::VideoCaptureBufferPool::kInvalidId);
   ASSERT_EQ(2.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
   buffer2 = ReserveBuffer(size_lo, GetParam());
   void* const memory_pointer_lo = buffer2->data();
@@ -369,7 +376,7 @@
 // Tests that a previously-released buffer can be immediately resurrected under
 // normal conditions.
 TEST_P(VideoCaptureBufferPoolTest, ResurrectsLastBuffer) {
-  ExpectDroppedId(VideoCaptureBufferPool::kInvalidId);
+  ExpectDroppedId(media::VideoCaptureBufferPool::kInvalidId);
 
   // At the start, there should be nothing to resurrect.
   std::unique_ptr<Buffer> resurrected =
@@ -413,7 +420,7 @@
 
 // Tests that a buffer cannot be resurrected if its properties do not match.
 TEST_P(VideoCaptureBufferPoolTest, DoesNotResurrectIfPropertiesNotMatched) {
-  ExpectDroppedId(VideoCaptureBufferPool::kInvalidId);
+  ExpectDroppedId(media::VideoCaptureBufferPool::kInvalidId);
 
   // Reserve a 10x10 buffer, fill it with 0xcd values, and release it.
   std::unique_ptr<Buffer> original =
@@ -463,7 +470,7 @@
 // Tests that the buffers are managed by the pool such that the last-released
 // buffer is kept around as long as possible (for successful resurrection).
 TEST_P(VideoCaptureBufferPoolTest, AvoidsClobberingForResurrectingLastBuffer) {
-  ExpectDroppedId(VideoCaptureBufferPool::kInvalidId);
+  ExpectDroppedId(media::VideoCaptureBufferPool::kInvalidId);
 
   // Reserve a 10x10 buffer, fill it with 0xde values, and release it.
   std::unique_ptr<Buffer> original =
diff --git a/content/browser/renderer_host/media/video_capture_buffer_tracker_factory.h b/content/browser/renderer_host/media/video_capture_buffer_tracker_factory.h
deleted file mode 100644
index e687471..0000000
--- a/content/browser/renderer_host/media/video_capture_buffer_tracker_factory.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_TRACKER_FACTORY_H_
-#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_TRACKER_FACTORY_H_
-
-#include <memory>
-
-#include "content/browser/renderer_host/media/video_capture_buffer_tracker.h"
-
-namespace content {
-
-class VideoCaptureBufferTrackerFactory {
- public:
-  static std::unique_ptr<VideoCaptureBufferTracker> CreateTracker(
-      media::VideoPixelStorage storage);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_TRACKER_FACTORY_H_
diff --git a/content/browser/renderer_host/media/video_capture_buffer_tracker_factory.cc b/content/browser/renderer_host/media/video_capture_buffer_tracker_factory_impl.cc
similarity index 79%
rename from content/browser/renderer_host/media/video_capture_buffer_tracker_factory.cc
rename to content/browser/renderer_host/media/video_capture_buffer_tracker_factory_impl.cc
index c58f564..1d2831b 100644
--- a/content/browser/renderer_host/media/video_capture_buffer_tracker_factory.cc
+++ b/content/browser/renderer_host/media/video_capture_buffer_tracker_factory_impl.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 "content/browser/renderer_host/media/video_capture_buffer_tracker_factory.h"
+#include "content/browser/renderer_host/media/video_capture_buffer_tracker_factory_impl.h"
 
 #include "base/memory/ptr_util.h"
 
@@ -11,9 +11,8 @@
 
 namespace content {
 
-// static
-std::unique_ptr<VideoCaptureBufferTracker>
-VideoCaptureBufferTrackerFactory::CreateTracker(
+std::unique_ptr<media::VideoCaptureBufferTracker>
+VideoCaptureBufferTrackerFactoryImpl::CreateTracker(
     media::VideoPixelStorage storage) {
   switch (storage) {
     case media::PIXEL_STORAGE_GPUMEMORYBUFFER:
@@ -22,7 +21,7 @@
       return base::MakeUnique<SharedMemoryBufferTracker>();
   }
   NOTREACHED();
-  return std::unique_ptr<VideoCaptureBufferTracker>();
+  return std::unique_ptr<media::VideoCaptureBufferTracker>();
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/media/video_capture_buffer_tracker_factory_impl.h b/content/browser/renderer_host/media/video_capture_buffer_tracker_factory_impl.h
new file mode 100644
index 0000000..a256963
--- /dev/null
+++ b/content/browser/renderer_host/media/video_capture_buffer_tracker_factory_impl.h
@@ -0,0 +1,24 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_TRACKER_FACTORY_IMPL_H_
+#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_TRACKER_FACTORY_IMPL_H_
+
+#include <memory>
+
+#include "content/common/content_export.h"
+#include "media/capture/video/video_capture_buffer_tracker_factory.h"
+
+namespace content {
+
+class CONTENT_EXPORT VideoCaptureBufferTrackerFactoryImpl
+    : public media::VideoCaptureBufferTrackerFactory {
+ public:
+  std::unique_ptr<media::VideoCaptureBufferTracker> CreateTracker(
+      media::VideoPixelStorage storage) override;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_TRACKER_FACTORY_IMPL_H_
diff --git a/content/browser/renderer_host/media/video_capture_controller.cc b/content/browser/renderer_host/media/video_capture_controller.cc
index c922822..c594c3b 100644
--- a/content/browser/renderer_host/media/video_capture_controller.cc
+++ b/content/browser/renderer_host/media/video_capture_controller.cc
@@ -18,13 +18,14 @@
 #include "build/build_config.h"
 #include "components/display_compositor/gl_helper.h"
 #include "content/browser/renderer_host/media/media_stream_manager.h"
-#include "content/browser/renderer_host/media/video_capture_buffer_pool.h"
-#include "content/browser/renderer_host/media/video_capture_device_client.h"
+#include "content/browser/renderer_host/media/video_capture_buffer_tracker_factory_impl.h"
 #include "content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h"
 #include "content/browser/renderer_host/media/video_capture_manager.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/content_switches.h"
 #include "media/base/video_frame.h"
+#include "media/capture/video/video_capture_buffer_pool_impl.h"
+#include "media/capture/video/video_capture_device_client.h"
 
 #if !defined(OS_ANDROID)
 #include "content/browser/compositor/image_transport_factory.h"
@@ -79,14 +80,14 @@
 #endif
 }
 
-std::unique_ptr<VideoCaptureJpegDecoder> CreateGpuJpegDecoder(
-    const VideoCaptureJpegDecoder::DecodeDoneCB& decode_done_cb) {
+std::unique_ptr<media::VideoCaptureJpegDecoder> CreateGpuJpegDecoder(
+    const media::VideoCaptureJpegDecoder::DecodeDoneCB& decode_done_cb) {
   return base::MakeUnique<VideoCaptureGpuJpegDecoder>(decode_done_cb);
 }
 
-// Decorator for VideoFrameReceiver that forwards all incoming calls
+// Decorator for media::VideoFrameReceiver that forwards all incoming calls
 // to the Browser IO thread.
-class VideoFrameReceiverOnIOThread : public VideoFrameReceiver {
+class VideoFrameReceiverOnIOThread : public media::VideoFrameReceiver {
  public:
   explicit VideoFrameReceiverOnIOThread(
       const base::WeakPtr<VideoFrameReceiver>& receiver)
@@ -176,7 +177,9 @@
 };
 
 VideoCaptureController::VideoCaptureController(int max_buffers)
-    : buffer_pool_(new VideoCaptureBufferPoolImpl(max_buffers)),
+    : buffer_pool_(new media::VideoCaptureBufferPoolImpl(
+          base::MakeUnique<VideoCaptureBufferTrackerFactoryImpl>(),
+          max_buffers)),
       state_(VIDEO_CAPTURE_STATE_STARTED),
       has_received_frames_(false),
       weak_ptr_factory_(this) {
@@ -191,7 +194,7 @@
 std::unique_ptr<media::VideoCaptureDevice::Client>
 VideoCaptureController::NewDeviceClient() {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  return base::MakeUnique<VideoCaptureDeviceClient>(
+  return base::MakeUnique<media::VideoCaptureDeviceClient>(
       base::MakeUnique<VideoFrameReceiverOnIOThread>(
           this->GetWeakPtrForIOThread()),
       buffer_pool_,
@@ -408,7 +411,7 @@
     const scoped_refptr<VideoFrame>& frame) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   const int buffer_id = buffer->id();
-  DCHECK_NE(buffer_id, VideoCaptureBufferPool::kInvalidId);
+  DCHECK_NE(buffer_id, media::VideoCaptureBufferPool::kInvalidId);
 
   int count = 0;
   if (state_ == VIDEO_CAPTURE_STATE_STARTED) {
diff --git a/content/browser/renderer_host/media/video_capture_controller.h b/content/browser/renderer_host/media/video_capture_controller.h
index 9674bdd0..25c826b 100644
--- a/content/browser/renderer_host/media/video_capture_controller.h
+++ b/content/browser/renderer_host/media/video_capture_controller.h
@@ -52,24 +52,15 @@
 #include "content/common/content_export.h"
 #include "content/common/media/video_capture.h"
 #include "media/base/video_capture_types.h"
-#include "media/capture/video/video_capture_device.h"
+#include "media/capture/video/video_frame_receiver.h"
+
+namespace media {
+class VideoCaptureBufferPool;
+}
 
 namespace content {
-class VideoCaptureBufferPool;
 
-class CONTENT_EXPORT VideoFrameReceiver {
- public:
-  virtual ~VideoFrameReceiver(){};
-
-  virtual void OnIncomingCapturedVideoFrame(
-      std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> buffer,
-      const scoped_refptr<media::VideoFrame>& frame) = 0;
-  virtual void OnError() = 0;
-  virtual void OnLog(const std::string& message) = 0;
-  virtual void OnBufferDestroyed(int buffer_id_to_drop) = 0;
-};
-
-class CONTENT_EXPORT VideoCaptureController : public VideoFrameReceiver {
+class CONTENT_EXPORT VideoCaptureController : public media::VideoFrameReceiver {
  public:
   // |max_buffers| is the maximum number of video frame buffers in-flight at any
   // one time.  This value should be based on the logical capacity of the
@@ -137,7 +128,7 @@
 
   bool has_received_frames() const { return has_received_frames_; }
 
-  // Implementation of VideoFrameReceiver interface:
+  // Implementation of media::VideoFrameReceiver interface:
   void OnIncomingCapturedVideoFrame(
       std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> buffer,
       const scoped_refptr<media::VideoFrame>& frame) override;
@@ -164,7 +155,7 @@
                                const ControllerClients& clients);
 
   // The pool of shared-memory buffers used for capturing.
-  const scoped_refptr<VideoCaptureBufferPool> buffer_pool_;
+  const scoped_refptr<media::VideoCaptureBufferPool> buffer_pool_;
 
   // All clients served by this controller.
   ControllerClients controller_clients_;
diff --git a/content/browser/renderer_host/media/video_capture_device_client_unittest.cc b/content/browser/renderer_host/media/video_capture_device_client_unittest.cc
index 2260efb..507af16 100644
--- a/content/browser/renderer_host/media/video_capture_device_client_unittest.cc
+++ b/content/browser/renderer_host/media/video_capture_device_client_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 "content/browser/renderer_host/media/video_capture_device_client.h"
+#include "media/capture/video/video_capture_device_client.h"
 
 #include <stddef.h>
 
@@ -15,10 +15,10 @@
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
-#include "content/browser/renderer_host/media/video_capture_buffer_pool.h"
 #include "content/browser/renderer_host/media/video_capture_controller.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "media/base/limits.h"
+#include "media/capture/video/video_capture_buffer_pool.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -49,6 +49,11 @@
   }
 };
 
+// Note that this test does not exercise the class VideoCaptureDeviceClient
+// in isolation. The "unit under test" is an instance of
+// VideoCaptureDeviceClient with some context that is specific to
+// renderer_host/media, and therefore this test must live here and not in
+// media/capture/video.
 class VideoCaptureDeviceClientTest : public ::testing::Test {
  public:
   VideoCaptureDeviceClientTest()
diff --git a/content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h b/content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h
index 9367df2..672735eb 100644
--- a/content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h
+++ b/content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h
@@ -18,7 +18,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread.h"
 #include "content/common/content_export.h"
-#include "media/capture/video/video_capture_device.h"
+#include "media/capture/video/video_capture_jpeg_decoder.h"
 #include "media/video/jpeg_decode_accelerator.h"
 
 namespace gpu {
@@ -31,40 +31,6 @@
 
 namespace content {
 
-class CONTENT_EXPORT VideoCaptureJpegDecoder {
- public:
-  // Enumeration of decoder status. The enumeration is published for clients to
-  // decide the behavior according to STATUS.
-  enum STATUS {
-    INIT_PENDING,  // Default value while waiting initialization finished.
-    INIT_PASSED,   // Initialization succeed.
-    FAILED,        // JPEG decode is not supported, initialization failed, or
-                   // decode error.
-  };
-
-  using DecodeDoneCB = base::Callback<void(
-      std::unique_ptr<media::VideoCaptureDevice::Client::Buffer>,
-      const scoped_refptr<media::VideoFrame>&)>;
-
-  virtual ~VideoCaptureJpegDecoder() {}
-
-  // Creates and intializes decoder asynchronously.
-  virtual void Initialize() = 0;
-
-  // Returns initialization status.
-  virtual STATUS GetStatus() const = 0;
-
-  // Decodes a JPEG picture.
-  virtual void DecodeCapturedData(
-      const uint8_t* data,
-      size_t in_buffer_size,
-      const media::VideoCaptureFormat& frame_format,
-      base::TimeTicks reference_time,
-      base::TimeDelta timestamp,
-      std::unique_ptr<media::VideoCaptureDevice::Client::Buffer>
-          out_buffer) = 0;
-};
-
 // Adapter to GpuJpegDecodeAccelerator for VideoCaptureDevice::Client. It takes
 // care of GpuJpegDecodeAccelerator creation, shared memory, and threading
 // issues.
@@ -73,7 +39,7 @@
 // on the same thread. JpegDecodeAccelerator::Client methods should be called on
 // the IO thread.
 class CONTENT_EXPORT VideoCaptureGpuJpegDecoder
-    : public VideoCaptureJpegDecoder,
+    : public media::VideoCaptureJpegDecoder,
       public media::JpegDecodeAccelerator::Client,
       public base::NonThreadSafe,
       public base::SupportsWeakPtr<VideoCaptureGpuJpegDecoder> {
diff --git a/content/browser/renderer_host/media/video_capture_host.cc b/content/browser/renderer_host/media/video_capture_host.cc
index 20e34a2d..1b2757f 100644
--- a/content/browser/renderer_host/media/video_capture_host.cc
+++ b/content/browser/renderer_host/media/video_capture_host.cc
@@ -237,13 +237,12 @@
 
   VideoCaptureControllerID controller_id(device_id);
   EntryMap::iterator it = entries_.find(controller_id);
-  if (it == entries_.end())
+  if (it == entries_.end() || !it->second)
     return;
 
-  if (it->second) {
-    media_stream_manager_->video_capture_manager()->PauseCaptureForClient(
-        it->second.get(), controller_id, this);
-  }
+  media_stream_manager_->video_capture_manager()->PauseCaptureForClient(
+      it->second.get(), controller_id, this);
+  Send(new VideoCaptureMsg_StateChanged(device_id, VIDEO_CAPTURE_STATE_PAUSED));
 }
 
 void VideoCaptureHost::OnResumeCapture(
@@ -255,13 +254,13 @@
 
   VideoCaptureControllerID controller_id(device_id);
   EntryMap::iterator it = entries_.find(controller_id);
-  if (it == entries_.end())
+  if (it == entries_.end() || !it->second)
     return;
 
-  if (it->second) {
-    media_stream_manager_->video_capture_manager()->ResumeCaptureForClient(
-        session_id, params, it->second.get(), controller_id, this);
-  }
+  media_stream_manager_->video_capture_manager()->ResumeCaptureForClient(
+      session_id, params, it->second.get(), controller_id, this);
+  Send(new VideoCaptureMsg_StateChanged(device_id,
+                                        VIDEO_CAPTURE_STATE_RESUMED));
 }
 
 void VideoCaptureHost::OnRequestRefreshFrame(int device_id) {
diff --git a/content/browser/renderer_host/media/video_capture_manager.cc b/content/browser/renderer_host/media/video_capture_manager.cc
index 380c626b..f86009ae 100644
--- a/content/browser/renderer_host/media/video_capture_manager.cc
+++ b/content/browser/renderer_host/media/video_capture_manager.cc
@@ -739,11 +739,20 @@
   if (!entry)
     NOTREACHED() << "Got Null entry while pausing capture";
 
-  // Do not pause Content Video Capture devices, e.g. Tab or Screen capture.
-  if (entry->stream_type != MEDIA_DEVICE_VIDEO_CAPTURE)
-    return;
-
+  const bool had_active_client = controller->HasActiveClient();
   controller->PauseClient(client_id, client_handler);
+  if (!had_active_client || controller->HasActiveClient())
+    return;
+  if (media::VideoCaptureDevice* device = entry->video_capture_device()) {
+    device_task_runner_->PostTask(
+        FROM_HERE,
+        base::Bind(&VideoCaptureDevice::MaybeSuspend,
+                   // Unretained is safe to use here because |device| would be
+                   // null if it was scheduled for shutdown and destruction, and
+                   // because this task is guaranteed to run before the task
+                   // that destroys the |device|.
+                   base::Unretained(device)));
+  }
 }
 
 void VideoCaptureManager::ResumeCaptureForClient(
@@ -760,11 +769,20 @@
   if (!entry)
     NOTREACHED() << "Got Null entry while resuming capture";
 
-  // Do not resume Content Video Capture devices, e.g. Tab or Screen capture.
-  if (entry->stream_type != MEDIA_DEVICE_VIDEO_CAPTURE)
-    return;
-
+  const bool had_active_client = controller->HasActiveClient();
   controller->ResumeClient(client_id, client_handler);
+  if (had_active_client || !controller->HasActiveClient())
+    return;
+  if (media::VideoCaptureDevice* device = entry->video_capture_device()) {
+    device_task_runner_->PostTask(
+        FROM_HERE,
+        base::Bind(&VideoCaptureDevice::Resume,
+                   // Unretained is safe to use here because |device| would be
+                   // null if it was scheduled for shutdown and destruction, and
+                   // because this task is guaranteed to run before the task
+                   // that destroys the |device|.
+                   base::Unretained(device)));
+  }
 }
 
 void VideoCaptureManager::RequestRefreshFrameForClient(
diff --git a/content/browser/renderer_host/media/video_capture_manager_unittest.cc b/content/browser/renderer_host/media/video_capture_manager_unittest.cc
index 82c3e71c..9ec3c445 100644
--- a/content/browser/renderer_host/media/video_capture_manager_unittest.cc
+++ b/content/browser/renderer_host/media/video_capture_manager_unittest.cc
@@ -8,11 +8,14 @@
 
 #include <stdint.h>
 
+#include <algorithm>
 #include <memory>
 #include <string>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/run_loop.h"
 #include "content/browser/browser_thread_impl.h"
@@ -33,6 +36,91 @@
 
 namespace content {
 
+namespace {
+
+// Wraps FakeVideoCaptureDeviceFactory to allow mocking of the
+// VideoCaptureDevice MaybeSuspend() and Resume() methods. This is used to check
+// that devices are asked to suspend or resume at the correct times.
+class WrappedDeviceFactory : public media::FakeVideoCaptureDeviceFactory {
+ public:
+  class WrappedDevice : public media::VideoCaptureDevice {
+   public:
+    WrappedDevice(std::unique_ptr<media::VideoCaptureDevice> device,
+                  WrappedDeviceFactory* factory)
+        : device_(std::move(device)), factory_(factory) {
+      factory_->OnDeviceCreated(this);
+    }
+
+    ~WrappedDevice() final {
+      factory_->OnDeviceDestroyed(this);
+    }
+
+    void AllocateAndStart(const media::VideoCaptureParams& params,
+                          std::unique_ptr<Client> client) final {
+      device_->AllocateAndStart(params, std::move(client));
+    }
+
+    void RequestRefreshFrame() final {
+      device_->RequestRefreshFrame();
+    }
+
+    void MaybeSuspend() final {
+      factory_->WillSuspendDevice();
+      device_->MaybeSuspend();
+    }
+
+    void Resume() final {
+      factory_->WillResumeDevice();
+      device_->Resume();
+    }
+
+    void StopAndDeAllocate() final {
+      device_->StopAndDeAllocate();
+    }
+
+    void GetPhotoCapabilities(GetPhotoCapabilitiesCallback callback) final {
+      device_->GetPhotoCapabilities(std::move(callback));
+    }
+
+    void TakePhoto(TakePhotoCallback callback) final {
+      device_->TakePhoto(std::move(callback));
+    }
+
+   private:
+    const std::unique_ptr<media::VideoCaptureDevice> device_;
+    WrappedDeviceFactory* const factory_;
+
+    DISALLOW_COPY_AND_ASSIGN(WrappedDevice);
+  };
+
+  WrappedDeviceFactory() : FakeVideoCaptureDeviceFactory() {}
+  ~WrappedDeviceFactory() final {}
+
+  std::unique_ptr<media::VideoCaptureDevice> CreateDevice(
+      const media::VideoCaptureDeviceDescriptor& device_descriptor) final {
+    return base::MakeUnique<WrappedDevice>(
+        FakeVideoCaptureDeviceFactory::CreateDevice(device_descriptor), this);
+  }
+
+  MOCK_METHOD0(WillSuspendDevice, void());
+  MOCK_METHOD0(WillResumeDevice, void());
+
+ private:
+  void OnDeviceCreated(WrappedDevice* device) {
+    devices_.push_back(device);
+  }
+
+  void OnDeviceDestroyed(WrappedDevice* device) {
+    const auto it = std::find(devices_.begin(), devices_.end(), device);
+    CHECK(it != devices_.end());
+    devices_.erase(it);
+  }
+
+  std::vector<WrappedDevice*> devices_;
+
+  DISALLOW_COPY_AND_ASSIGN(WrappedDeviceFactory);
+};
+
 // Listener class used to track progress of VideoCaptureManager test.
 class MockMediaStreamProviderListener : public MediaStreamProviderListener {
  public:
@@ -65,6 +153,8 @@
   void OnGotControllerCallback(VideoCaptureControllerID) {}
 };
 
+}  // namespace
+
 // Test class
 class VideoCaptureManagerTest : public testing::Test {
  public:
@@ -93,10 +183,9 @@
                                            message_loop_.get()));
     vcm_ = new VideoCaptureManager(
         std::unique_ptr<media::VideoCaptureDeviceFactory>(
-            new media::FakeVideoCaptureDeviceFactory()));
-    video_capture_device_factory_ =
-        static_cast<media::FakeVideoCaptureDeviceFactory*>(
-            vcm_->video_capture_device_factory());
+            new WrappedDeviceFactory()));
+    video_capture_device_factory_ = static_cast<WrappedDeviceFactory*>(
+        vcm_->video_capture_device_factory());
     const int32_t kNumberOfFakeDevices = 2;
     video_capture_device_factory_->set_number_of_devices(kNumberOfFakeDevices);
     vcm_->Register(listener_.get(), message_loop_->task_runner().get());
@@ -114,7 +203,6 @@
 
   void OnGotControllerCallback(
       VideoCaptureControllerID id,
-      base::Closure quit_closure,
       bool expect_success,
       const base::WeakPtr<VideoCaptureController>& controller) {
     if (expect_success) {
@@ -124,7 +212,6 @@
     } else {
       ASSERT_FALSE(controller);
     }
-    quit_closure.Run();
   }
 
   VideoCaptureControllerID StartClient(int session_id, bool expect_success) {
@@ -133,7 +220,6 @@
         gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420);
 
     VideoCaptureControllerID client_id(next_client_id_++);
-    base::RunLoop run_loop;
     vcm_->StartCaptureForClient(
         session_id,
         params,
@@ -143,9 +229,8 @@
         base::Bind(&VideoCaptureManagerTest::OnGotControllerCallback,
                    base::Unretained(this),
                    client_id,
-                   run_loop.QuitClosure(),
                    expect_success));
-    run_loop.Run();
+    base::RunLoop().RunUntilIdle();
     return client_id;
   }
 
@@ -161,19 +246,22 @@
     media::VideoCaptureParams params;
     params.requested_format = media::VideoCaptureFormat(
         gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420);
-
     vcm_->ResumeCaptureForClient(
         session_id,
         params,
         controllers_[client_id],
         client_id,
         frame_observer_.get());
+    // Allow possible VideoCaptureDevice::Resume() task to run.
+    base::RunLoop().RunUntilIdle();
   }
 
   void PauseClient(VideoCaptureControllerID client_id) {
     ASSERT_EQ(1u, controllers_.count(client_id));
     vcm_->PauseCaptureForClient(controllers_[client_id], client_id,
-                               frame_observer_.get());
+                                frame_observer_.get());
+    // Allow possible VideoCaptureDevice::MaybeSuspend() task to run.
+    base::RunLoop().RunUntilIdle();
   }
 
 #if defined(OS_ANDROID)
@@ -190,7 +278,7 @@
   std::unique_ptr<BrowserThreadImpl> ui_thread_;
   std::unique_ptr<BrowserThreadImpl> io_thread_;
   std::unique_ptr<MockFrameObserver> frame_observer_;
-  media::FakeVideoCaptureDeviceFactory* video_capture_device_factory_;
+  WrappedDeviceFactory* video_capture_device_factory_;
   StreamDeviceInfoArray devices_;
 
  private:
@@ -476,21 +564,38 @@
   vcm_->Unregister();
 }
 
-// Try to open, start, pause and resume a device.
+// Try to open, start, pause and resume a device. Confirm the device is
+// paused/resumed at the correct times in both single-client and multiple-client
+// scenarios.
 TEST_F(VideoCaptureManagerTest, PauseAndResumeClient) {
-  InSequence s;
   EXPECT_CALL(*listener_, Opened(MEDIA_DEVICE_VIDEO_CAPTURE, _));
-  EXPECT_CALL(*listener_, Closed(MEDIA_DEVICE_VIDEO_CAPTURE, _));
 
-  int video_session_id = vcm_->Open(devices_.front());
-  VideoCaptureControllerID client_id = StartClient(video_session_id, true);
+  const int video_session_id = vcm_->Open(devices_.front());
+  const VideoCaptureControllerID client_id =
+      StartClient(video_session_id, true);
 
-  // Resume client a second time should cause no problem.
+  // Test pause/resume when only one client is present.
+  EXPECT_CALL(*video_capture_device_factory_, WillSuspendDevice()).Times(1);
   PauseClient(client_id);
+  EXPECT_CALL(*video_capture_device_factory_, WillResumeDevice()).Times(1);
   ResumeClient(video_session_id, client_id);
+
+  // Attempting to resume the client a second time should not cause any calls to
+  // VideoCaptureDevice::Resume().
+  ResumeClient(video_session_id, client_id);
+
+  // Add a second client that is never paused, then pause/resume the first
+  // client, and no calls to VideoCaptureDevice::MaybeSuspend() or Resume() are
+  // made.
+  const VideoCaptureControllerID client_id2 =
+      StartClient(video_session_id, true);
+  PauseClient(client_id);
   ResumeClient(video_session_id, client_id);
 
   StopClient(client_id);
+  StopClient(client_id2);
+
+  EXPECT_CALL(*listener_, Closed(MEDIA_DEVICE_VIDEO_CAPTURE, _));
   vcm_->Close(video_session_id);
 
   // Wait to check callbacks before removing the listener.
diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc
index abc660a..93f4ebd 100644
--- a/content/browser/renderer_host/render_message_filter.cc
+++ b/content/browser/renderer_host/render_message_filter.cc
@@ -45,6 +45,7 @@
 #include "content/common/child_process_messages.h"
 #include "content/common/content_constants_internal.h"
 #include "content/common/host_shared_bitmap_manager.h"
+#include "content/common/render_message_filter.mojom.h"
 #include "content/common/render_process_messages.h"
 #include "content/common/view_messages.h"
 #include "content/public/browser/browser_child_process_host.h"
@@ -167,7 +168,6 @@
 bool RenderMessageFilter::OnMessageReceived(const IPC::Message& message) {
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(RenderMessageFilter, message)
-    IPC_MESSAGE_HANDLER(ViewHostMsg_CreateWindow, OnCreateWindow)
     IPC_MESSAGE_HANDLER(ViewHostMsg_CreateWidget, OnCreateWidget)
     IPC_MESSAGE_HANDLER(ViewHostMsg_CreateFullscreenWidget,
                         OnCreateFullscreenWidget)
@@ -241,50 +241,6 @@
     *thread = BrowserThread::UI;
 }
 
-void RenderMessageFilter::OnCreateWindow(
-    const ViewHostMsg_CreateWindow_Params& params,
-    ViewHostMsg_CreateWindow_Reply* reply) {
-  bool no_javascript_access;
-
-  bool can_create_window =
-      GetContentClient()->browser()->CanCreateWindow(
-          params.opener_url,
-          params.opener_top_level_frame_url,
-          params.opener_security_origin,
-          params.window_container_type,
-          params.target_url,
-          params.referrer,
-          params.frame_name,
-          params.disposition,
-          params.features,
-          params.user_gesture,
-          params.opener_suppressed,
-          resource_context_,
-          render_process_id_,
-          params.opener_id,
-          params.opener_render_frame_id,
-          &no_javascript_access);
-
-  if (!can_create_window) {
-    reply->route_id = MSG_ROUTING_NONE;
-    reply->main_frame_route_id = MSG_ROUTING_NONE;
-    reply->main_frame_widget_route_id = MSG_ROUTING_NONE;
-    reply->cloned_session_storage_namespace_id = 0;
-    return;
-  }
-
-  // This will clone the sessionStorage for namespace_id_to_clone.
-  scoped_refptr<SessionStorageNamespaceImpl> cloned_namespace =
-      new SessionStorageNamespaceImpl(dom_storage_context_.get(),
-                                      params.session_storage_namespace_id);
-  reply->cloned_session_storage_namespace_id = cloned_namespace->id();
-
-  render_widget_helper_->CreateNewWindow(
-      params, no_javascript_access, PeerHandle(), &reply->route_id,
-      &reply->main_frame_route_id, &reply->main_frame_widget_route_id,
-      cloned_namespace.get());
-}
-
 void RenderMessageFilter::OnCreateWidget(int opener_id,
                                          blink::WebPopupType popup_type,
                                          int* route_id) {
@@ -301,6 +257,51 @@
   callback.Run(render_widget_helper_->GetNextRoutingID());
 }
 
+void RenderMessageFilter::CreateNewWindow(
+    mojom::CreateNewWindowParamsPtr params,
+    const CreateNewWindowCallback& callback) {
+  bool no_javascript_access;
+  bool can_create_window =
+      GetContentClient()->browser()->CanCreateWindow(
+          params->opener_url,
+          params->opener_top_level_frame_url,
+          params->opener_security_origin,
+          params->window_container_type,
+          params->target_url,
+          params->referrer,
+          params->frame_name,
+          params->disposition,
+          params->features,
+          params->user_gesture,
+          params->opener_suppressed,
+          resource_context_,
+          render_process_id_,
+          params->opener_id,
+          params->opener_render_frame_id,
+          &no_javascript_access);
+
+  mojom::CreateNewWindowReplyPtr reply = mojom::CreateNewWindowReply::New();
+  if (!can_create_window) {
+    reply->route_id = MSG_ROUTING_NONE;
+    reply->main_frame_route_id = MSG_ROUTING_NONE;
+    reply->main_frame_widget_route_id = MSG_ROUTING_NONE;
+    reply->cloned_session_storage_namespace_id = 0;
+    return callback.Run(std::move(reply));
+  }
+
+  // This will clone the sessionStorage for namespace_id_to_clone.
+  scoped_refptr<SessionStorageNamespaceImpl> cloned_namespace =
+      new SessionStorageNamespaceImpl(dom_storage_context_.get(),
+                                      params->session_storage_namespace_id);
+  reply->cloned_session_storage_namespace_id = cloned_namespace->id();
+
+  render_widget_helper_->CreateNewWindow(
+      std::move(params), no_javascript_access, PeerHandle(), &reply->route_id,
+      &reply->main_frame_route_id, &reply->main_frame_widget_route_id,
+      cloned_namespace.get());
+  callback.Run(std::move(reply));
+}
+
 #if defined(OS_MACOSX)
 
 void RenderMessageFilter::OnLoadFont(const FontDescriptor& font,
diff --git a/content/browser/renderer_host/render_message_filter.h b/content/browser/renderer_host/render_message_filter.h
index 1bec995..83afa13 100644
--- a/content/browser/renderer_host/render_message_filter.h
+++ b/content/browser/renderer_host/render_message_filter.h
@@ -49,8 +49,6 @@
 
 class GURL;
 struct FontDescriptor;
-struct ViewHostMsg_CreateWindow_Params;
-struct ViewHostMsg_CreateWindow_Reply;
 
 namespace base {
 class ProcessMetrics;
@@ -123,8 +121,6 @@
   friend class base::DeleteHelper<RenderMessageFilter>;
 
   void OnGetProcessMemorySizes(size_t* private_bytes, size_t* shared_bytes);
-  void OnCreateWindow(const ViewHostMsg_CreateWindow_Params& params,
-                      ViewHostMsg_CreateWindow_Reply* reply);
   void OnCreateWidget(int opener_id,
                       blink::WebPopupType popup_type,
                       int* route_id);
@@ -138,6 +134,8 @@
 
   // mojom::RenderMessageFilter:
   void GenerateRoutingID(const GenerateRoutingIDCallback& routing_id) override;
+  void CreateNewWindow(mojom::CreateNewWindowParamsPtr params,
+                       const CreateNewWindowCallback& callback) override;
 
   // Message handlers called on the browser IO thread:
   void OnEstablishGpuChannel(IPC::Message* reply);
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 78e6dc9..1c6011b 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1745,6 +1745,7 @@
     switches::kMaxUntiledLayerHeight,
     switches::kMemoryMetrics,
     switches::kMojoLocalStorage,
+    switches::kMojoServiceWorker,
     switches::kMSEAudioBufferSizeLimit,
     switches::kMSEVideoBufferSizeLimit,
     switches::kNoReferrers,
diff --git a/content/browser/renderer_host/render_view_host_delegate.h b/content/browser/renderer_host/render_view_host_delegate.h
index 8ec4ae25..ef18d5d2 100644
--- a/content/browser/renderer_host/render_view_host_delegate.h
+++ b/content/browser/renderer_host/render_view_host_delegate.h
@@ -20,7 +20,6 @@
 
 class GURL;
 class SkBitmap;
-struct ViewHostMsg_CreateWindow_Params;
 struct FrameHostMsg_DidCommitProvisionalLoad_Params;
 
 namespace base {
@@ -56,6 +55,10 @@
 struct RendererPreferences;
 struct WebPreferences;
 
+namespace mojom {
+class CreateNewWindowParams;
+}
+
 //
 // RenderViewHostDelegate
 //
@@ -165,7 +168,7 @@
       int32_t route_id,
       int32_t main_frame_route_id,
       int32_t main_frame_widget_route_id,
-      const ViewHostMsg_CreateWindow_Params& params,
+      const mojom::CreateNewWindowParams& params,
       SessionStorageNamespace* session_storage_namespace) {}
 
   // The page is trying to open a new widget (e.g. a select popup). The
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index dcb23093..b1fb741 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -48,6 +48,7 @@
 #include "content/common/frame_messages.h"
 #include "content/common/input_messages.h"
 #include "content/common/inter_process_time_ticks_converter.h"
+#include "content/common/render_message_filter.mojom.h"
 #include "content/common/site_isolation_policy.h"
 #include "content/common/speech_recognition_messages.h"
 #include "content/common/swapped_out_messages.h"
@@ -886,15 +887,15 @@
     int32_t route_id,
     int32_t main_frame_route_id,
     int32_t main_frame_widget_route_id,
-    const ViewHostMsg_CreateWindow_Params& params,
+    const mojom::CreateNewWindowParams& params,
     SessionStorageNamespace* session_storage_namespace) {
-  ViewHostMsg_CreateWindow_Params validated_params(params);
-  GetProcess()->FilterURL(false, &validated_params.target_url);
-  GetProcess()->FilterURL(false, &validated_params.opener_url);
-  GetProcess()->FilterURL(true, &validated_params.opener_security_origin);
+  mojom::CreateNewWindowParamsPtr validated_params(params.Clone());
+  GetProcess()->FilterURL(false, &validated_params->target_url);
+  GetProcess()->FilterURL(false, &validated_params->opener_url);
+  GetProcess()->FilterURL(true, &validated_params->opener_security_origin);
 
   delegate_->CreateNewWindow(GetSiteInstance(), route_id, main_frame_route_id,
-                             main_frame_widget_route_id, validated_params,
+                             main_frame_widget_route_id, *validated_params,
                              session_storage_namespace);
 }
 
diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h
index ca857d5..f8cce528 100644
--- a/content/browser/renderer_host/render_view_host_impl.h
+++ b/content/browser/renderer_host/render_view_host_impl.h
@@ -36,7 +36,6 @@
 #include "ui/base/window_open_disposition.h"
 
 class SkBitmap;
-struct ViewHostMsg_CreateWindow_Params;
 
 namespace content {
 
@@ -47,6 +46,10 @@
 struct FileChooserParams;
 struct FrameReplicationState;
 
+namespace mojom {
+class CreateNewWindowParams;
+}
+
 // This implements the RenderViewHost interface that is exposed to
 // embedders of content, and adds things only visible to content.
 //
@@ -225,7 +228,7 @@
   void CreateNewWindow(int32_t route_id,
                        int32_t main_frame_route_id,
                        int32_t main_frame_widget_route_id,
-                       const ViewHostMsg_CreateWindow_Params& params,
+                       const mojom::CreateNewWindowParams& params,
                        SessionStorageNamespace* session_storage_namespace);
 
   // Creates a new RenderWidget with the given route id.  |popup_type| indicates
diff --git a/content/browser/renderer_host/render_widget_helper.cc b/content/browser/renderer_host/render_widget_helper.cc
index e6a225c7..fce786a8 100644
--- a/content/browser/renderer_host/render_widget_helper.cc
+++ b/content/browser/renderer_host/render_widget_helper.cc
@@ -88,14 +88,14 @@
 }
 
 void RenderWidgetHelper::CreateNewWindow(
-    const ViewHostMsg_CreateWindow_Params& params,
+    mojom::CreateNewWindowParamsPtr params,
     bool no_javascript_access,
     base::ProcessHandle render_process,
     int32_t* route_id,
     int32_t* main_frame_route_id,
     int32_t* main_frame_widget_route_id,
     SessionStorageNamespace* session_storage_namespace) {
-  if (params.opener_suppressed || no_javascript_access) {
+  if (params->opener_suppressed || no_javascript_access) {
     // If the opener is supppressed or script access is disallowed, we should
     // open the window in a new BrowsingInstance, and thus a new process. That
     // means the current renderer process will not be able to route messages to
@@ -121,23 +121,25 @@
 
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
-      base::Bind(&RenderWidgetHelper::OnCreateWindowOnUI, this, params,
-                 *route_id, *main_frame_route_id, *main_frame_widget_route_id,
+      base::Bind(&RenderWidgetHelper::OnCreateWindowOnUI, this,
+                 base::Passed(&params), *route_id, *main_frame_route_id,
+                 *main_frame_widget_route_id,
                  base::RetainedRef(session_storage_namespace)));
 }
 
 void RenderWidgetHelper::OnCreateWindowOnUI(
-    const ViewHostMsg_CreateWindow_Params& params,
+    mojom::CreateNewWindowParamsPtr params,
     int32_t route_id,
     int32_t main_frame_route_id,
     int32_t main_frame_widget_route_id,
     SessionStorageNamespace* session_storage_namespace) {
   RenderViewHostImpl* host =
-      RenderViewHostImpl::FromID(render_process_id_, params.opener_id);
-  if (host)
+      RenderViewHostImpl::FromID(render_process_id_, params->opener_id);
+  if (host) {
     host->CreateNewWindow(route_id, main_frame_route_id,
-                          main_frame_widget_route_id, params,
+                          main_frame_widget_route_id, *params,
                           session_storage_namespace);
+  }
 }
 
 void RenderWidgetHelper::CreateNewWidget(int opener_id,
diff --git a/content/browser/renderer_host/render_widget_helper.h b/content/browser/renderer_host/render_widget_helper.h
index 43878c70..4666f27 100644
--- a/content/browser/renderer_host/render_widget_helper.h
+++ b/content/browser/renderer_host/render_widget_helper.h
@@ -14,6 +14,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/process/process.h"
+#include "content/common/render_message_filter.mojom.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/global_request_id.h"
@@ -29,8 +30,6 @@
 class TimeDelta;
 }
 
-struct ViewHostMsg_CreateWindow_Params;
-
 namespace content {
 class GpuProcessHost;
 class ResourceDispatcherHostImpl;
@@ -98,7 +97,7 @@
 
   // IO THREAD ONLY -----------------------------------------------------------
 
-  void CreateNewWindow(const ViewHostMsg_CreateWindow_Params& params,
+  void CreateNewWindow(mojom::CreateNewWindowParamsPtr params,
                        bool no_javascript_access,
                        base::ProcessHandle render_process,
                        int32_t* route_id,
@@ -118,7 +117,7 @@
   ~RenderWidgetHelper();
 
   // Called on the UI thread to finish creating a window.
-  void OnCreateWindowOnUI(const ViewHostMsg_CreateWindow_Params& params,
+  void OnCreateWindowOnUI(mojom::CreateNewWindowParamsPtr params,
                           int32_t route_id,
                           int32_t main_frame_route_id,
                           int32_t main_frame_widget_route_id,
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index 5fb4834..fe65bc1d0 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -440,6 +440,9 @@
       has_composition_text_(false),
       accept_return_character_(false),
       begin_frame_source_(nullptr),
+      needs_begin_frames_(false),
+      needs_flush_input_(false),
+      added_frame_observer_(false),
       synthetic_move_sent_(false),
       cursor_visibility_state_in_renderer_(UNKNOWN),
 #if defined(OS_WIN)
@@ -712,10 +715,25 @@
 }
 
 void RenderWidgetHostViewAura::SetNeedsBeginFrames(bool needs_begin_frames) {
+  needs_begin_frames_ = needs_begin_frames;
+  UpdateNeedsBeginFramesInternal();
+}
+
+void RenderWidgetHostViewAura::OnSetNeedsFlushInput() {
+  needs_flush_input_ = true;
+  UpdateNeedsBeginFramesInternal();
+}
+
+void RenderWidgetHostViewAura::UpdateNeedsBeginFramesInternal() {
   if (!begin_frame_source_)
     return;
 
-  if (needs_begin_frames)
+  bool needs_frame = needs_begin_frames_ || needs_flush_input_;
+  if (needs_frame == added_frame_observer_)
+    return;
+
+  added_frame_observer_ = needs_frame;
+  if (needs_frame)
     begin_frame_source_->AddObserver(this);
   else
     begin_frame_source_->RemoveObserver(this);
@@ -723,6 +741,9 @@
 
 void RenderWidgetHostViewAura::OnBeginFrame(
     const cc::BeginFrameArgs& args) {
+  needs_flush_input_ = false;
+  host_->FlushInput();
+  UpdateNeedsBeginFramesInternal();
   host_->Send(new ViewMsg_BeginFrame(host_->GetRoutingID(), args));
   last_begin_frame_args_ = args;
 }
@@ -2924,12 +2945,12 @@
 
 void RenderWidgetHostViewAura::SetBeginFrameSource(
     cc::BeginFrameSource* source) {
-  bool needs_begin_frames = host_->needs_begin_frames();
-  if (begin_frame_source_ && needs_begin_frames)
+  if (begin_frame_source_ && added_frame_observer_) {
     begin_frame_source_->RemoveObserver(this);
+    added_frame_observer_ = false;
+  }
   begin_frame_source_ = source;
-  if (begin_frame_source_ && needs_begin_frames)
-    begin_frame_source_->AddObserver(this);
+  UpdateNeedsBeginFramesInternal();
 }
 
 bool RenderWidgetHostViewAura::IsAutoResizeEnabled() const {
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h
index 190d5c9..c465b46e 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -162,6 +162,7 @@
   void EndFrameSubscription() override;
   bool HasAcceleratedSurface(const gfx::Size& desired_size) override;
   gfx::Rect GetBoundsInRootWindow() override;
+  void OnSetNeedsFlushInput() override;
   void WheelEventAck(const blink::WebMouseWheelEvent& event,
                      InputEventAckState ack_result) override;
   void GestureEventAck(const blink::WebGestureEvent& event,
@@ -532,6 +533,9 @@
   // Forwards a mouse event to this view's parent window delegate.
   void ForwardMouseEventToParent(ui::MouseEvent* event);
 
+  // Adds/Removes frame observer based on state.
+  void UpdateNeedsBeginFramesInternal();
+
   // Returns the RenderViewHostDelegateView instance for this view. Returns
   // NULL on failure.
   RenderViewHostDelegateView* GetRenderViewHostDelegateView();
@@ -592,8 +596,16 @@
   // The begin frame source being observed.  Null if none.
   cc::BeginFrameSource* begin_frame_source_;
   cc::BeginFrameArgs last_begin_frame_args_;
+
+  // Whether a request for begin frames has been issued.
   bool needs_begin_frames_;
 
+  // Whether a request to flush input has been issued.
+  bool needs_flush_input_;
+
+  // Whether we have added ourselves as a frame observer or not.
+  bool added_frame_observer_;
+
   // Used to record the last position of the mouse.
   // While the mouse is locked, they store the last known position just as mouse
   // lock was entered.
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.h b/content/browser/renderer_host/render_widget_host_view_mac.h
index 9a2f0da1..75ad48f 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.h
+++ b/content/browser/renderer_host/render_widget_host_view_mac.h
@@ -320,6 +320,7 @@
 
   bool LockMouse() override;
   void UnlockMouse() override;
+  void OnSetNeedsFlushInput() override;
   void GestureEventAck(const blink::WebGestureEvent& event,
                        InputEventAckState ack_result) override;
 
@@ -500,6 +501,9 @@
   // Get the focused view that should be used for retrieving the text selection.
   RenderWidgetHostViewBase* GetFocusedViewForTextSelection();
 
+  // Adds/Removes frame observer based on state.
+  void UpdateNeedsBeginFramesInternal();
+
   // The associated view. This is weak and is inserted into the view hierarchy
   // to own this RenderWidgetHostViewMac object. Set to nil at the start of the
   // destructor.
@@ -545,6 +549,12 @@
   gfx::Range composition_range_;
   std::vector<gfx::Rect> composition_bounds_;
 
+  // Whether a request for begin frames has been issued.
+  bool needs_begin_frames_;
+
+  // Whether a request to flush input has been issued.
+  bool needs_flush_input_;
+
   // Factory used to safely scope delayed calls to ShutdownHost().
   base::WeakPtrFactory<RenderWidgetHostViewMac> weak_factory_;
 
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 b5444dc9..fa22008 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -415,6 +415,9 @@
 
 void RenderWidgetHostViewMac::BrowserCompositorMacSendBeginFrame(
     const cc::BeginFrameArgs& args) {
+  needs_flush_input_ = false;
+  render_widget_host_->FlushInput();
+  UpdateNeedsBeginFramesInternal();
   render_widget_host_->Send(
       new ViewMsg_BeginFrame(render_widget_host_->GetRoutingID(), args));
 }
@@ -451,6 +454,8 @@
       allow_pause_for_resize_or_repaint_(true),
       is_guest_view_hack_(is_guest_view_hack),
       fullscreen_parent_host_view_(nullptr),
+      needs_begin_frames_(false),
+      needs_flush_input_(false),
       weak_factory_(this) {
   // |cocoa_view_| owns us and we will be deleted when |cocoa_view_|
   // goes away.  Since we autorelease it, our caller must put
@@ -1188,7 +1193,18 @@
 }
 
 void RenderWidgetHostViewMac::SetNeedsBeginFrames(bool needs_begin_frames) {
-  browser_compositor_->SetNeedsBeginFrames(needs_begin_frames);
+  needs_begin_frames_ = needs_begin_frames;
+  UpdateNeedsBeginFramesInternal();
+}
+
+void RenderWidgetHostViewMac::OnSetNeedsFlushInput() {
+  needs_flush_input_ = true;
+  UpdateNeedsBeginFramesInternal();
+}
+
+void RenderWidgetHostViewMac::UpdateNeedsBeginFramesInternal() {
+  browser_compositor_->SetNeedsBeginFrames(needs_begin_frames_ ||
+                                           needs_flush_input_);
 }
 
 void RenderWidgetHostViewMac::KillSelf() {
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc
index 2463c00..8b5c4cc 100644
--- a/content/browser/security_exploit_browsertest.cc
+++ b/content/browser/security_exploit_browsertest.cc
@@ -18,6 +18,7 @@
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/frame_messages.h"
+#include "content/common/render_message_filter.mojom.h"
 #include "content/common/resource_messages.h"
 #include "content/common/resource_request.h"
 #include "content/common/view_messages.h"
@@ -259,7 +260,6 @@
   // Since this test executes on the UI thread and hopping threads might cause
   // different timing in the test, let's simulate a CreateNewWindow call coming
   // from the IO thread.
-  ViewHostMsg_CreateWindow_Params params;
   DOMStorageContextWrapper* dom_storage_context =
       static_cast<DOMStorageContextWrapper*>(
           BrowserContext::GetStoragePartition(
@@ -273,7 +273,8 @@
   // RenderViewHostImpl has-a RenderWidgetHostImpl. https://crbug.com/545684
   int32_t main_frame_widget_routing_id = duplicate_routing_id;
   pending_rvh->CreateNewWindow(duplicate_routing_id, main_frame_routing_id,
-                               main_frame_widget_routing_id, params,
+                               main_frame_widget_routing_id,
+                               mojom::CreateNewWindowParams(),
                                session_storage.get());
 
   // If the above operation doesn't cause a crash, the test has succeeded!
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc
index a08d207..17d4cd4 100644
--- a/content/browser/service_worker/embedded_worker_instance.cc
+++ b/content/browser/service_worker/embedded_worker_instance.cc
@@ -20,11 +20,14 @@
 #include "content/common/service_worker/embedded_worker_messages.h"
 #include "content/common/service_worker/embedded_worker_settings.h"
 #include "content/common/service_worker/embedded_worker_setup.mojom.h"
+#include "content/common/service_worker/embedded_worker_start_params.h"
 #include "content/common/service_worker/service_worker_types.h"
+#include "content/common/service_worker/service_worker_utils.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/common/child_process_host.h"
+#include "content/public/common/content_switches.h"
 #include "ipc/ipc_message.h"
 #include "services/shell/public/cpp/interface_provider.h"
 #include "services/shell/public/cpp/interface_registry.h"
@@ -69,7 +72,7 @@
       worker_process_id, worker_route_id);
 }
 
-void RegisterToWorkerDevToolsManagerOnUI(
+void SetupOnUI(
     int process_id,
     const ServiceWorkerContextCore* service_worker_context,
     const base::WeakPtr<ServiceWorkerContextCore>& service_worker_context_weak,
@@ -77,6 +80,7 @@
     const GURL& url,
     const GURL& scope,
     bool is_installed,
+    mojom::EmbeddedWorkerInstanceClientRequest request,
     const base::Callback<void(int worker_devtools_agent_route_id,
                               bool wait_for_debugger)>& callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -92,6 +96,8 @@
                 service_worker_context, service_worker_context_weak,
                 service_worker_version_id, url, scope),
             is_installed);
+    if (request.is_pending())
+      rph->GetRemoteInterfaces()->GetInterface(std::move(request));
   }
   BrowserThread::PostTask(
       BrowserThread::IO,
@@ -211,8 +217,11 @@
  public:
   enum class ProcessAllocationState { NOT_ALLOCATED, ALLOCATING, ALLOCATED };
 
-  StartTask(EmbeddedWorkerInstance* instance, const GURL& script_url)
+  StartTask(EmbeddedWorkerInstance* instance,
+            const GURL& script_url,
+            mojom::EmbeddedWorkerInstanceClientRequest request)
       : instance_(instance),
+        request_(std::move(request)),
         state_(ProcessAllocationState::NOT_ALLOCATED),
         is_installed_(false),
         started_during_browser_startup_(false),
@@ -254,7 +263,7 @@
     // TODO(nhiroki): Reconsider this bizarre layering.
   }
 
-  void Start(std::unique_ptr<EmbeddedWorkerMsg_StartWorker_Params> params,
+  void Start(std::unique_ptr<EmbeddedWorkerStartParams> params,
              const StatusCallback& callback) {
     DCHECK_CURRENTLY_ON(BrowserThread::IO);
     state_ = ProcessAllocationState::ALLOCATING;
@@ -289,12 +298,11 @@
   bool is_installed() const { return is_installed_; }
 
  private:
-  void OnProcessAllocated(
-      std::unique_ptr<EmbeddedWorkerMsg_StartWorker_Params> params,
-      ServiceWorkerStatusCode status,
-      int process_id,
-      bool is_new_process,
-      const EmbeddedWorkerSettings& settings) {
+  void OnProcessAllocated(std::unique_ptr<EmbeddedWorkerStartParams> params,
+                          ServiceWorkerStatusCode status,
+                          int process_id,
+                          bool is_new_process,
+                          const EmbeddedWorkerSettings& settings) {
     DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
     if (status != SERVICE_WORKER_OK) {
@@ -342,23 +350,22 @@
     GURL script_url(params->script_url);
     BrowserThread::PostTask(
         BrowserThread::UI, FROM_HERE,
-        base::Bind(RegisterToWorkerDevToolsManagerOnUI, process_id,
-                   instance_->context_.get(), instance_->context_,
-                   service_worker_version_id, script_url, scope, is_installed_,
-                   base::Bind(&StartTask::OnRegisteredToDevToolsManager,
+        base::Bind(&SetupOnUI, process_id, instance_->context_.get(),
+                   instance_->context_, service_worker_version_id, script_url,
+                   scope, is_installed_, base::Passed(&request_),
+                   base::Bind(&StartTask::OnSetupOnUICompleted,
                               weak_factory_.GetWeakPtr(), base::Passed(&params),
                               is_new_process)));
   }
 
-  void OnRegisteredToDevToolsManager(
-      std::unique_ptr<EmbeddedWorkerMsg_StartWorker_Params> params,
-      bool is_new_process,
-      int worker_devtools_agent_route_id,
-      bool wait_for_debugger) {
+  void OnSetupOnUICompleted(std::unique_ptr<EmbeddedWorkerStartParams> params,
+                            bool is_new_process,
+                            int worker_devtools_agent_route_id,
+                            bool wait_for_debugger) {
     DCHECK_CURRENTLY_ON(BrowserThread::IO);
     TRACE_EVENT_ASYNC_STEP_PAST0("ServiceWorker",
                                  "EmbeddedWorkerInstance::Start", this,
-                                 "OnRegisteredToDevToolsManager");
+                                 "OnSetupOnUICompleted");
 
     // Notify the instance that it is registered to the devtools manager.
     instance_->OnRegisteredToDevToolsManager(
@@ -366,11 +373,14 @@
 
     params->worker_devtools_agent_route_id = worker_devtools_agent_route_id;
     params->wait_for_debugger = wait_for_debugger;
-    SendStartWorker(std::move(params));
+
+    if (ServiceWorkerUtils::IsMojoForServiceWorkerEnabled())
+      instance_->SendMojoStartWorker(std::move(params));
+    else
+      SendStartWorker(std::move(params));
   }
 
-  void SendStartWorker(
-      std::unique_ptr<EmbeddedWorkerMsg_StartWorker_Params> params) {
+  void SendStartWorker(std::unique_ptr<EmbeddedWorkerStartParams> params) {
     DCHECK_CURRENTLY_ON(BrowserThread::IO);
     ServiceWorkerStatusCode status = instance_->registry_->SendStartWorker(
         std::move(params), instance_->process_id());
@@ -393,6 +403,10 @@
   // |instance_| must outlive |this|.
   EmbeddedWorkerInstance* instance_;
 
+  // Ownership is transferred by base::Passed() to a task after process
+  // allocation.
+  mojom::EmbeddedWorkerInstanceClientRequest request_;
+
   StatusCallback start_callback_;
   ProcessAllocationState state_;
 
@@ -421,7 +435,7 @@
 }
 
 void EmbeddedWorkerInstance::Start(
-    std::unique_ptr<EmbeddedWorkerMsg_StartWorker_Params> params,
+    std::unique_ptr<EmbeddedWorkerStartParams> params,
     const StatusCallback& callback) {
   if (!context_) {
     callback.Run(SERVICE_WORKER_ERROR_ABORT);
@@ -445,7 +459,12 @@
   params->wait_for_debugger = false;
   params->settings.v8_cache_options = GetV8CacheOptions();
 
-  inflight_start_task_.reset(new StartTask(this, params->script_url));
+  mojom::EmbeddedWorkerInstanceClientRequest request;
+  if (ServiceWorkerUtils::IsMojoForServiceWorkerEnabled())
+    request = mojo::GetProxy(&client_);
+
+  inflight_start_task_.reset(
+      new StartTask(this, params->script_url, std::move(request)));
   inflight_start_task_->Start(std::move(params), callback);
 }
 
@@ -566,6 +585,15 @@
   FOR_EACH_OBSERVER(Listener, listener_list_, OnRegisteredToDevToolsManager());
 }
 
+void EmbeddedWorkerInstance::SendMojoStartWorker(
+    std::unique_ptr<EmbeddedWorkerStartParams> params) {
+  client_->StartWorker(*params);
+  registry_->BindWorkerToProcess(process_id(), embedded_worker_id());
+  TRACE_EVENT_ASYNC_STEP_PAST1("ServiceWorker", "EmbeddedWorkerInstance::Start",
+                               this, "SendStartWorker", "Status", "mojo");
+  OnStartWorkerMessageSent();
+}
+
 void EmbeddedWorkerInstance::OnStartWorkerMessageSent() {
   if (!step_time_.is_null()) {
     base::TimeDelta duration = UpdateStepTime();
@@ -660,9 +688,10 @@
   FOR_EACH_OBSERVER(Listener, listener_list_, OnThreadStarted());
 
   shell::mojom::InterfaceProviderPtr exposed_interfaces;
-  interface_registry_->Bind(GetProxy(&exposed_interfaces));
+  interface_registry_->Bind(mojo::GetProxy(&exposed_interfaces));
   shell::mojom::InterfaceProviderPtr remote_interfaces;
-  shell::mojom::InterfaceProviderRequest request = GetProxy(&remote_interfaces);
+  shell::mojom::InterfaceProviderRequest request =
+      mojo::GetProxy(&remote_interfaces);
   remote_interfaces_->Bind(std::move(remote_interfaces));
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
diff --git a/content/browser/service_worker/embedded_worker_instance.h b/content/browser/service_worker/embedded_worker_instance.h
index 13aca7e3..705b773 100644
--- a/content/browser/service_worker/embedded_worker_instance.h
+++ b/content/browser/service_worker/embedded_worker_instance.h
@@ -23,6 +23,7 @@
 #include "content/browser/service_worker/embedded_worker_status.h"
 #include "content/browser/service_worker/service_worker_metrics.h"
 #include "content/common/content_export.h"
+#include "content/common/service_worker/embedded_worker.mojom.h"
 #include "content/common/service_worker/service_worker_status_code.h"
 #include "content/public/common/console_message_level.h"
 #include "url/gurl.h"
@@ -32,8 +33,6 @@
 #undef SendMessage
 #endif
 
-struct EmbeddedWorkerMsg_StartWorker_Params;
-
 namespace IPC {
 class Message;
 }
@@ -46,6 +45,7 @@
 namespace content {
 
 class EmbeddedWorkerRegistry;
+struct EmbeddedWorkerStartParams;
 class MessagePortMessageFilter;
 class ServiceWorkerContextCore;
 
@@ -112,7 +112,7 @@
   // started and evaluated, or when an error occurs.
   // |params| should be populated with service worker version info needed
   // to start the worker.
-  void Start(std::unique_ptr<EmbeddedWorkerMsg_StartWorker_Params> params,
+  void Start(std::unique_ptr<EmbeddedWorkerStartParams> params,
              const StatusCallback& callback);
 
   // Stops the worker. It is invalid to call this when the worker is
@@ -224,6 +224,9 @@
                                      int worker_devtools_agent_route_id,
                                      bool wait_for_debugger);
 
+  // Sends StartWorker message via Mojo.
+  void SendMojoStartWorker(std::unique_ptr<EmbeddedWorkerStartParams> params);
+
   // Called back from StartTask after a start worker message is sent.
   void OnStartWorkerMessageSent();
 
@@ -306,8 +309,12 @@
   // Current running information.
   std::unique_ptr<EmbeddedWorkerInstance::WorkerProcessHandle> process_handle_;
   int thread_id_;
+
+  // These are connected to the renderer process after OnThreadStarted.
   std::unique_ptr<shell::InterfaceRegistry> interface_registry_;
   std::unique_ptr<shell::InterfaceProvider> remote_interfaces_;
+  // |client_| is used to send messages to the renderer process.
+  mojom::EmbeddedWorkerInstanceClientPtr client_;
 
   // Whether devtools is attached or not.
   bool devtools_attached_;
diff --git a/content/browser/service_worker/embedded_worker_instance_unittest.cc b/content/browser/service_worker/embedded_worker_instance_unittest.cc
index f2df6b57..1253a28 100644
--- a/content/browser/service_worker/embedded_worker_instance_unittest.cc
+++ b/content/browser/service_worker/embedded_worker_instance_unittest.cc
@@ -8,6 +8,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/command_line.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
@@ -16,9 +17,13 @@
 #include "content/browser/service_worker/embedded_worker_test_helper.h"
 #include "content/browser/service_worker/service_worker_context_core.h"
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/common/service_worker/embedded_worker.mojom.h"
 #include "content/common/service_worker/embedded_worker_messages.h"
+#include "content/common/service_worker/embedded_worker_start_params.h"
 #include "content/public/common/child_process_host.h"
+#include "content/public/common/content_switches.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -33,14 +38,15 @@
   callback.Run();
 }
 
-std::unique_ptr<EmbeddedWorkerMsg_StartWorker_Params>
+std::unique_ptr<EmbeddedWorkerStartParams>
 CreateStartParams(int version_id, const GURL& scope, const GURL& script_url) {
-  std::unique_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
-      new EmbeddedWorkerMsg_StartWorker_Params);
+  std::unique_ptr<EmbeddedWorkerStartParams> params(
+      new EmbeddedWorkerStartParams);
   params->service_worker_version_id = version_id;
   params->scope = scope;
   params->script_url = script_url;
   params->pause_after_download = false;
+  params->is_installed = false;
   return params;
 }
 
@@ -97,7 +103,7 @@
                                       const GURL& url) {
     ServiceWorkerStatusCode status;
     base::RunLoop run_loop;
-    std::unique_ptr<EmbeddedWorkerMsg_StartWorker_Params> params =
+    std::unique_ptr<EmbeddedWorkerStartParams> params =
         CreateStartParams(id, pattern, url);
     worker->Start(std::move(params), base::Bind(&SaveStatusAndCall, &status,
                                                 run_loop.QuitClosure()));
@@ -122,6 +128,24 @@
   DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerInstanceTest);
 };
 
+class EmbeddedWorkerInstanceTestP : public EmbeddedWorkerInstanceTest,
+                                    public testing::WithParamInterface<bool> {
+ protected:
+  void SetUp() override {
+    is_mojo_enabled_ = GetParam();
+    if (is_mojo_enabled()) {
+      base::CommandLine::ForCurrentProcess()->AppendSwitch(
+          switches::kMojoServiceWorker);
+    }
+    EmbeddedWorkerInstanceTest::SetUp();
+  }
+
+  bool is_mojo_enabled() { return is_mojo_enabled_; }
+
+ private:
+  bool is_mojo_enabled_ = false;
+};
+
 // A helper to simulate the start worker sequence is stalled in a worker
 // process.
 class StalledInStartWorkerHelper : public EmbeddedWorkerTestHelper {
@@ -162,10 +186,11 @@
   }
 };
 
-TEST_F(EmbeddedWorkerInstanceTest, StartAndStop) {
+TEST_P(EmbeddedWorkerInstanceTestP, StartAndStop) {
   std::unique_ptr<EmbeddedWorkerInstance> worker =
       embedded_worker_registry()->CreateWorker();
   EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, worker->status());
+  worker->AddListener(this);
 
   const int64_t service_worker_version_id = 55L;
   const GURL pattern("http://example.com/");
@@ -178,7 +203,7 @@
   // Start should succeed.
   ServiceWorkerStatusCode status;
   base::RunLoop run_loop;
-  std::unique_ptr<EmbeddedWorkerMsg_StartWorker_Params> params =
+  std::unique_ptr<EmbeddedWorkerStartParams> params =
       CreateStartParams(service_worker_version_id, pattern, url);
   worker->Start(std::move(params), base::Bind(&SaveStatusAndCall, &status,
                                               run_loop.QuitClosure()));
@@ -200,11 +225,21 @@
   // EmbeddedWorkerTestHelper.
   EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, worker->status());
 
-  // Verify that we've sent two messages to start and terminate the worker.
-  ASSERT_TRUE(
-      ipc_sink()->GetUniqueMessageMatching(EmbeddedWorkerMsg_StartWorker::ID));
+  if (!is_mojo_enabled()) {
+    // Verify that we've sent two messages to start and terminate the worker.
+    ASSERT_TRUE(ipc_sink()->GetUniqueMessageMatching(
+        EmbeddedWorkerMsg_StartWorker::ID));
+  }
+  // StopWorker should be sent in either case.
   ASSERT_TRUE(ipc_sink()->GetUniqueMessageMatching(
       EmbeddedWorkerMsg_StopWorker::ID));
+
+  // Check if the IPCs are fired in expected order.
+  ASSERT_EQ(4u, events_.size());
+  EXPECT_EQ(PROCESS_ALLOCATED, events_[0].type);
+  EXPECT_EQ(START_WORKER_MESSAGE_SENT, events_[1].type);
+  EXPECT_EQ(STARTED, events_[2].type);
+  EXPECT_EQ(STOPPED, events_[3].type);
 }
 
 // Test that a worker that failed twice will use a new render process
@@ -233,7 +268,7 @@
     // Start once normally.
     ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE;
     base::RunLoop run_loop;
-    std::unique_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
+    std::unique_ptr<EmbeddedWorkerStartParams> params(
         CreateStartParams(service_worker_version_id, pattern, url));
     worker->Start(std::move(params), base::Bind(&SaveStatusAndCall, &status,
                                                 run_loop.QuitClosure()));
@@ -257,7 +292,7 @@
     // Start again.
     ServiceWorkerStatusCode status;
     base::RunLoop run_loop;
-    std::unique_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
+    std::unique_ptr<EmbeddedWorkerStartParams> params(
         CreateStartParams(service_worker_version_id, pattern, url));
     worker->Start(std::move(params), base::Bind(&SaveStatusAndCall, &status,
                                                 run_loop.QuitClosure()));
@@ -337,7 +372,7 @@
     // Start worker1.
     ServiceWorkerStatusCode status;
     base::RunLoop run_loop;
-    std::unique_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
+    std::unique_ptr<EmbeddedWorkerStartParams> params(
         CreateStartParams(version_id1, pattern, url));
     worker1->Start(std::move(params), base::Bind(&SaveStatusAndCall, &status,
                                                  run_loop.QuitClosure()));
@@ -349,7 +384,7 @@
     // Start worker2.
     ServiceWorkerStatusCode status;
     base::RunLoop run_loop;
-    std::unique_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
+    std::unique_ptr<EmbeddedWorkerStartParams> params(
         CreateStartParams(version_id2, pattern, url));
     worker2->Start(std::move(params), base::Bind(&SaveStatusAndCall, &status,
                                                  run_loop.QuitClosure()));
@@ -386,7 +421,7 @@
 
   // Run the start worker sequence and detach during process allocation.
   ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE;
-  std::unique_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
+  std::unique_ptr<EmbeddedWorkerStartParams> params(
       CreateStartParams(version_id, scope, url));
   worker->Start(std::move(params), base::Bind(&SaveStatusAndCall, &status,
                                               base::Bind(&base::DoNothing)));
@@ -418,7 +453,7 @@
 
   // Run the start worker sequence until a start worker message is sent.
   ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE;
-  std::unique_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
+  std::unique_ptr<EmbeddedWorkerStartParams> params(
       CreateStartParams(version_id, scope, url));
   worker->Start(std::move(params), base::Bind(&SaveStatusAndCall, &status,
                                               base::Bind(&base::DoNothing)));
@@ -457,7 +492,7 @@
   // Stop the start worker sequence before a process is allocated.
   ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE;
 
-  std::unique_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
+  std::unique_ptr<EmbeddedWorkerStartParams> params(
       CreateStartParams(version_id, scope, url));
   worker->Start(std::move(params), base::Bind(&SaveStatusAndCall, &status,
                                               base::Bind(&base::DoNothing)));
@@ -507,7 +542,7 @@
   // Run the start worker sequence until pause after download.
   ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE;
 
-  std::unique_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
+  std::unique_ptr<EmbeddedWorkerStartParams> params(
       CreateStartParams(version_id, scope, url));
   params->pause_after_download = true;
   worker->Start(std::move(params), base::Bind(&SaveStatusAndCall, &status,
@@ -538,7 +573,7 @@
 
   // Run the start worker sequence until a start worker message is sent.
   ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE;
-  std::unique_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
+  std::unique_ptr<EmbeddedWorkerStartParams> params(
       CreateStartParams(version_id, scope, url));
   worker->Start(std::move(params), base::Bind(&SaveStatusAndCall, &status,
                                               base::Bind(&base::DoNothing)));
@@ -600,7 +635,7 @@
 
   // Start the worker.
   base::RunLoop run_loop;
-  std::unique_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
+  std::unique_ptr<EmbeddedWorkerStartParams> params(
       CreateStartParams(version_id, pattern, url));
   worker->Start(std::move(params), base::Bind(&SaveStatusAndCall, &status,
                                               run_loop.QuitClosure()));
@@ -635,7 +670,7 @@
 
   // Attempt to start the worker.
   base::RunLoop run_loop;
-  std::unique_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
+  std::unique_ptr<EmbeddedWorkerStartParams> params(
       CreateStartParams(version_id, pattern, url));
   worker->Start(std::move(params), base::Bind(&SaveStatusAndCall, &status,
                                               run_loop.QuitClosure()));
@@ -649,4 +684,8 @@
   EXPECT_EQ(EmbeddedWorkerStatus::STARTING, events_[1].status);
 }
 
+INSTANTIATE_TEST_CASE_P(EmbeddedWorkerInstanceTest,
+                        EmbeddedWorkerInstanceTestP,
+                        ::testing::Values(false, true));
+
 }  // namespace content
diff --git a/content/browser/service_worker/embedded_worker_registry.cc b/content/browser/service_worker/embedded_worker_registry.cc
index 1b75f94..3859b5aa 100644
--- a/content/browser/service_worker/embedded_worker_registry.cc
+++ b/content/browser/service_worker/embedded_worker_registry.cc
@@ -249,7 +249,7 @@
 }
 
 ServiceWorkerStatusCode EmbeddedWorkerRegistry::SendStartWorker(
-    std::unique_ptr<EmbeddedWorkerMsg_StartWorker_Params> params,
+    std::unique_ptr<EmbeddedWorkerStartParams> params,
     int process_id) {
   if (!context_)
     return SERVICE_WORKER_ERROR_ABORT;
@@ -269,10 +269,25 @@
   ServiceWorkerStatusCode status =
       Send(process_id, new EmbeddedWorkerMsg_StartWorker(*params));
   if (status == SERVICE_WORKER_OK)
-    worker_process_map_[process_id].insert(embedded_worker_id);
+    BindWorkerToProcess(process_id, embedded_worker_id);
   return status;
 }
 
+void EmbeddedWorkerRegistry::BindWorkerToProcess(int process_id,
+                                                 int embedded_worker_id) {
+  // The ServiceWorkerDispatcherHost is supposed to be created when the process
+  // is created, and keep an entry in process_sender_map_ for its whole
+  // lifetime.
+  DCHECK(base::ContainsKey(process_sender_map_, process_id));
+  DCHECK(GetWorker(embedded_worker_id));
+  DCHECK_EQ(GetWorker(embedded_worker_id)->process_id(), process_id);
+  DCHECK(
+      !base::ContainsKey(worker_process_map_, process_id) ||
+      !base::ContainsKey(worker_process_map_[process_id], embedded_worker_id));
+
+  worker_process_map_[process_id].insert(embedded_worker_id);
+}
+
 ServiceWorkerStatusCode EmbeddedWorkerRegistry::Send(
     int process_id, IPC::Message* message_ptr) {
   std::unique_ptr<IPC::Message> message(message_ptr);
diff --git a/content/browser/service_worker/embedded_worker_registry.h b/content/browser/service_worker/embedded_worker_registry.h
index 8e83b1d..70475ef 100644
--- a/content/browser/service_worker/embedded_worker_registry.h
+++ b/content/browser/service_worker/embedded_worker_registry.h
@@ -18,7 +18,6 @@
 #include "content/common/content_export.h"
 #include "content/common/service_worker/service_worker_status_code.h"
 
-struct EmbeddedWorkerMsg_StartWorker_Params;
 class GURL;
 
 namespace IPC {
@@ -29,6 +28,7 @@
 namespace content {
 
 class EmbeddedWorkerInstance;
+struct EmbeddedWorkerStartParams;
 class MessagePortMessageFilter;
 class ServiceWorkerContextCore;
 
@@ -59,7 +59,7 @@
 
   // Called from EmbeddedWorkerInstance, relayed to the child process.
   ServiceWorkerStatusCode SendStartWorker(
-      std::unique_ptr<EmbeddedWorkerMsg_StartWorker_Params> params,
+      std::unique_ptr<EmbeddedWorkerStartParams> params,
       int process_id);
   ServiceWorkerStatusCode StopWorker(int process_id,
                                      int embedded_worker_id);
@@ -114,10 +114,10 @@
   FRIEND_TEST_ALL_PREFIXES(EmbeddedWorkerInstanceTest,
                            RemoveWorkerInSharedProcess);
 
-  typedef std::map<int, EmbeddedWorkerInstance*> WorkerInstanceMap;
-  typedef std::map<int, IPC::Sender*> ProcessToSenderMap;
-  typedef std::map<int, MessagePortMessageFilter*>
-      ProcessToMessagePortMessageFilterMap;
+  using WorkerInstanceMap = std::map<int, EmbeddedWorkerInstance*>;
+  using ProcessToSenderMap = std::map<int, IPC::Sender*>;
+  using ProcessToMessagePortMessageFilterMap =
+      std::map<int, MessagePortMessageFilter*>;
 
   EmbeddedWorkerRegistry(
       const base::WeakPtr<ServiceWorkerContextCore>& context,
@@ -126,6 +126,11 @@
 
   ServiceWorkerStatusCode Send(int process_id, IPC::Message* message);
 
+  // Called when EmbeddedWorkerInstance is ready for IPC. This function
+  // prepares a route to the child worker thread.
+  // TODO(shimazu): Remove this function once mojofication is completed.
+  void BindWorkerToProcess(int process_id, int embedded_worker_id);
+
   // RemoveWorker is called when EmbeddedWorkerInstance is destructed.
   // |process_id| could be invalid (i.e. ChildProcessHost::kInvalidUniqueID)
   // if it's not running.
diff --git a/content/browser/service_worker/embedded_worker_test_helper.cc b/content/browser/service_worker/embedded_worker_test_helper.cc
index daf636d..674827f 100644
--- a/content/browser/service_worker/embedded_worker_test_helper.cc
+++ b/content/browser/service_worker/embedded_worker_test_helper.cc
@@ -21,6 +21,7 @@
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/common/service_worker/embedded_worker_messages.h"
 #include "content/common/service_worker/embedded_worker_setup.mojom.h"
+#include "content/common/service_worker/embedded_worker_start_params.h"
 #include "content/common/service_worker/service_worker_messages.h"
 #include "content/public/common/push_event_payload.h"
 #include "content/public/test/mock_render_process_host.h"
@@ -82,13 +83,66 @@
   base::WeakPtr<EmbeddedWorkerTestHelper> helper_;
 };
 
+EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient::
+    MockEmbeddedWorkerInstanceClient(
+        base::WeakPtr<EmbeddedWorkerTestHelper> helper)
+    : helper_(helper), binding_(this) {}
+
+EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient::
+    ~MockEmbeddedWorkerInstanceClient() {}
+
+void EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient::StartWorker(
+    const EmbeddedWorkerStartParams& params) {
+  if (!helper_)
+    return;
+
+  embedded_worker_id_ = params.embedded_worker_id;
+
+  EmbeddedWorkerInstance* worker =
+      helper_->registry()->GetWorker(params.embedded_worker_id);
+  ASSERT_TRUE(worker != NULL);
+  EXPECT_EQ(EmbeddedWorkerStatus::STARTING, worker->status());
+
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::Bind(&EmbeddedWorkerTestHelper::OnStartWorker,
+                 helper_->weak_factory_.GetWeakPtr(), params.embedded_worker_id,
+                 params.service_worker_version_id, params.scope,
+                 params.script_url, params.pause_after_download));
+}
+
+// static
+void EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient::Bind(
+    const base::WeakPtr<EmbeddedWorkerTestHelper>& helper,
+    mojom::EmbeddedWorkerInstanceClientRequest request) {
+  std::vector<std::unique_ptr<MockEmbeddedWorkerInstanceClient>>* clients =
+      helper->mock_instance_clients();
+  size_t next_client_index = helper->mock_instance_clients_next_index_;
+
+  ASSERT_GE(clients->size(), next_client_index);
+  if (clients->size() == next_client_index) {
+    clients->push_back(
+        base::MakeUnique<MockEmbeddedWorkerInstanceClient>(helper));
+  }
+
+  std::unique_ptr<MockEmbeddedWorkerInstanceClient>& client =
+      clients->at(next_client_index);
+  helper->mock_instance_clients_next_index_ = next_client_index + 1;
+  if (client)
+    client->binding_.Bind(std::move(request));
+}
+
 EmbeddedWorkerTestHelper::EmbeddedWorkerTestHelper(
     const base::FilePath& user_data_directory)
     : browser_context_(new TestBrowserContext),
       render_process_host_(new MockRenderProcessHost(browser_context_.get())),
+      new_render_process_host_(
+          new MockRenderProcessHost(browser_context_.get())),
       wrapper_(new ServiceWorkerContextWrapper(browser_context_.get())),
+      mock_instance_clients_next_index_(0),
       next_thread_id_(0),
       mock_render_process_id_(render_process_host_->GetID()),
+      new_mock_render_process_id_(new_render_process_host_->GetID()),
       weak_factory_(this) {
   std::unique_ptr<MockServiceWorkerDatabaseTaskManager> database_task_manager(
       new MockServiceWorkerDatabaseTaskManager(
@@ -101,16 +155,10 @@
                                     NewMessagePortMessageFilter());
 
   // Setup process level interface registry.
-  render_process_interface_registry_.reset(new shell::InterfaceRegistry);
-  render_process_interface_registry_->AddInterface(
-      base::Bind(&MockEmbeddedWorkerSetup::Create, weak_factory_.GetWeakPtr()));
-  shell::mojom::InterfaceProviderPtr interfaces;
-  render_process_interface_registry_->Bind(mojo::GetProxy(&interfaces));
-
-  std::unique_ptr<shell::InterfaceProvider> host_remote_interfaces(
-      new shell::InterfaceProvider);
-  host_remote_interfaces->Bind(std::move(interfaces));
-  render_process_host_->SetRemoteInterfaces(std::move(host_remote_interfaces));
+  render_process_interface_registry_ =
+      CreateInterfaceRegistry(render_process_host_.get());
+  new_render_process_interface_registry_ =
+      CreateInterfaceRegistry(new_render_process_host_.get());
 }
 
 EmbeddedWorkerTestHelper::~EmbeddedWorkerTestHelper() {
@@ -327,7 +375,7 @@
 }
 
 void EmbeddedWorkerTestHelper::OnStartWorkerStub(
-    const EmbeddedWorkerMsg_StartWorker_Params& params) {
+    const EmbeddedWorkerStartParams& params) {
   EmbeddedWorkerInstance* worker =
       registry()->GetWorker(params.embedded_worker_id);
   ASSERT_TRUE(worker != NULL);
@@ -444,4 +492,23 @@
   return filter.get();
 }
 
+std::unique_ptr<shell::InterfaceRegistry>
+EmbeddedWorkerTestHelper::CreateInterfaceRegistry(MockRenderProcessHost* rph) {
+  std::unique_ptr<shell::InterfaceRegistry> registry(
+      new shell::InterfaceRegistry);
+  registry->AddInterface(
+      base::Bind(&MockEmbeddedWorkerSetup::Create, weak_factory_.GetWeakPtr()));
+  registry->AddInterface(base::Bind(&MockEmbeddedWorkerInstanceClient::Bind,
+                                    weak_factory_.GetWeakPtr()));
+
+  shell::mojom::InterfaceProviderPtr interfaces;
+  registry->Bind(mojo::GetProxy(&interfaces));
+
+  std::unique_ptr<shell::InterfaceProvider> remote_interfaces(
+      new shell::InterfaceProvider);
+  remote_interfaces->Bind(std::move(interfaces));
+  rph->SetRemoteInterfaces(std::move(remote_interfaces));
+  return registry;
+}
+
 }  // namespace content
diff --git a/content/browser/service_worker/embedded_worker_test_helper.h b/content/browser/service_worker/embedded_worker_test_helper.h
index 88bf11b..97ec1637 100644
--- a/content/browser/service_worker/embedded_worker_test_helper.h
+++ b/content/browser/service_worker/embedded_worker_test_helper.h
@@ -15,14 +15,16 @@
 #include "base/containers/hash_tables.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "content/common/service_worker/embedded_worker.mojom.h"
 #include "ipc/ipc_listener.h"
 #include "ipc/ipc_test_sink.h"
+#include "mojo/public/cpp/bindings/binding.h"
 #include "services/shell/public/interfaces/interface_provider.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
 class GURL;
-struct EmbeddedWorkerMsg_StartWorker_Params;
 struct ServiceWorkerMsg_ExtendableMessageEvent_Params;
 
 namespace shell {
@@ -39,6 +41,7 @@
 class ServiceWorkerContextCore;
 class ServiceWorkerContextWrapper;
 class TestBrowserContext;
+struct EmbeddedWorkerStartParams;
 struct PushEventPayload;
 struct ServiceWorkerFetchRequest;
 
@@ -60,6 +63,28 @@
 class EmbeddedWorkerTestHelper : public IPC::Sender,
                                  public IPC::Listener {
  public:
+  class MockEmbeddedWorkerInstanceClient
+      : public mojom::EmbeddedWorkerInstanceClient {
+   public:
+    explicit MockEmbeddedWorkerInstanceClient(
+        base::WeakPtr<EmbeddedWorkerTestHelper> helper);
+    ~MockEmbeddedWorkerInstanceClient() override;
+
+    static void Bind(const base::WeakPtr<EmbeddedWorkerTestHelper>& helper,
+                     mojom::EmbeddedWorkerInstanceClientRequest request);
+
+   private:
+    // Implementation of mojo interfaces.
+    void StartWorker(const EmbeddedWorkerStartParams& params) override;
+
+    base::WeakPtr<EmbeddedWorkerTestHelper> helper_;
+    mojo::Binding<mojom::EmbeddedWorkerInstanceClient> binding_;
+
+    base::Optional<int> embedded_worker_id_;
+
+    DISALLOW_COPY_AND_ASSIGN(MockEmbeddedWorkerInstanceClient);
+  };
+
   // If |user_data_directory| is empty, the context makes storage stuff in
   // memory.
   explicit EmbeddedWorkerTestHelper(const base::FilePath& user_data_directory);
@@ -80,6 +105,11 @@
   // Inner IPC sink for script context messages sent via EmbeddedWorker.
   IPC::TestSink* inner_ipc_sink() { return &inner_sink_; }
 
+  std::vector<std::unique_ptr<MockEmbeddedWorkerInstanceClient>>*
+  mock_instance_clients() {
+    return &mock_instance_clients_;
+  }
+
   ServiceWorkerContextCore* context();
   ServiceWorkerContextWrapper* context_wrapper() { return wrapper_.get(); }
   void ShutdownContext();
@@ -95,9 +125,8 @@
     return embedded_worker_id_service_worker_version_id_map_;
   }
 
-  // Only used for tests that force creating a new render process. There is no
-  // corresponding MockRenderProcessHost.
-  int new_render_process_id() const { return mock_render_process_id_ + 1; }
+  // Only used for tests that force creating a new render process.
+  int new_render_process_id() const { return new_mock_render_process_id_; }
 
   TestBrowserContext* browser_context() { return browser_context_.get(); }
 
@@ -158,7 +187,7 @@
 
   class MockEmbeddedWorkerSetup;
 
-  void OnStartWorkerStub(const EmbeddedWorkerMsg_StartWorker_Params& params);
+  void OnStartWorkerStub(const EmbeddedWorkerStartParams& params);
   void OnResumeAfterDownloadStub(int embedded_worker_id);
   void OnStopWorkerStub(int embedded_worker_id);
   void OnMessageToWorkerStub(int thread_id,
@@ -179,18 +208,29 @@
 
   MessagePortMessageFilter* NewMessagePortMessageFilter();
 
+  std::unique_ptr<shell::InterfaceRegistry> CreateInterfaceRegistry(
+      MockRenderProcessHost* rph);
+
   std::unique_ptr<TestBrowserContext> browser_context_;
   std::unique_ptr<MockRenderProcessHost> render_process_host_;
+  std::unique_ptr<MockRenderProcessHost> new_render_process_host_;
 
   scoped_refptr<ServiceWorkerContextWrapper> wrapper_;
 
   IPC::TestSink sink_;
   IPC::TestSink inner_sink_;
 
+  std::vector<std::unique_ptr<MockEmbeddedWorkerInstanceClient>>
+      mock_instance_clients_;
+  size_t mock_instance_clients_next_index_;
+
   int next_thread_id_;
   int mock_render_process_id_;
+  int new_mock_render_process_id_;
 
   std::unique_ptr<shell::InterfaceRegistry> render_process_interface_registry_;
+  std::unique_ptr<shell::InterfaceRegistry>
+      new_render_process_interface_registry_;
 
   std::map<int, int64_t> embedded_worker_id_service_worker_version_id_map_;
 
diff --git a/content/browser/service_worker/service_worker_job_unittest.cc b/content/browser/service_worker/service_worker_job_unittest.cc
index 7762d42..50ed74f0 100644
--- a/content/browser/service_worker/service_worker_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_job_unittest.cc
@@ -1620,7 +1620,7 @@
     ASSERT_TRUE(start_msg);
     EmbeddedWorkerMsg_StartWorker::Param param;
     EmbeddedWorkerMsg_StartWorker::Read(start_msg, &param);
-    EmbeddedWorkerMsg_StartWorker_Params start_params = std::get<0>(param);
+    const EmbeddedWorkerStartParams& start_params = std::get<0>(param);
     EXPECT_FALSE(start_params.pause_after_download);
     sink->ClearMessages();
   }
@@ -1635,7 +1635,7 @@
     ASSERT_TRUE(start_msg);
     EmbeddedWorkerMsg_StartWorker::Param param;
     EmbeddedWorkerMsg_StartWorker::Read(start_msg, &param);
-    EmbeddedWorkerMsg_StartWorker_Params start_params = std::get<0>(param);
+    const EmbeddedWorkerStartParams& start_params = std::get<0>(param);
     EXPECT_TRUE(start_params.pause_after_download);
     sink->ClearMessages();
   }
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index 7c33cb28..337e676 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -35,6 +35,7 @@
 #include "content/browser/service_worker/service_worker_metrics.h"
 #include "content/browser/service_worker/service_worker_registration.h"
 #include "content/common/service_worker/embedded_worker_messages.h"
+#include "content/common/service_worker/embedded_worker_start_params.h"
 #include "content/common/service_worker/service_worker_messages.h"
 #include "content/common/service_worker/service_worker_type_converters.h"
 #include "content/common/service_worker/service_worker_utils.h"
@@ -1406,8 +1407,8 @@
 
   StartTimeoutTimer();
 
-  std::unique_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
-      new EmbeddedWorkerMsg_StartWorker_Params());
+  std::unique_ptr<EmbeddedWorkerStartParams> params(
+      new EmbeddedWorkerStartParams());
   params->service_worker_version_id = version_id_;
   params->scope = scope_;
   params->script_url = script_url_;
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 80c95ff..69e6bb0 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -3769,9 +3769,9 @@
 
   // frames[1] can't be used due to a bug where RemoteFrames are created out of
   // order (https://crbug.com/478792).  Instead, target second frame by name.
-  EXPECT_TRUE(ExecuteScript(
-      root->child_at(0),
-      "parent.frames['frame2'].location.href = 'data:text/html,foo'"));
+  EXPECT_TRUE(ExecuteScript(root->child_at(0),
+                            "try { parent.frames['frame2'].location.href = "
+                            "'data:text/html,foo'; } catch (e) {}"));
   console_delegate->Wait();
 
   std::string frame_origin = root->child_at(1)->current_origin().Serialize();
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 21ca407b..6d0a560 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -83,6 +83,7 @@
 #include "content/common/input_messages.h"
 #include "content/common/page_messages.h"
 #include "content/common/page_state_serialization.h"
+#include "content/common/render_message_filter.mojom.h"
 #include "content/common/site_isolation_policy.h"
 #include "content/common/view_messages.h"
 #include "content/public/browser/ax_event_notification_details.h"
@@ -2002,7 +2003,7 @@
     int32_t route_id,
     int32_t main_frame_route_id,
     int32_t main_frame_widget_route_id,
-    const ViewHostMsg_CreateWindow_Params& params,
+    const mojom::CreateNewWindowParams& params,
     SessionStorageNamespace* session_storage_namespace) {
   // We usually create the new window in the same BrowsingInstance (group of
   // script-related windows), by passing in the current SiteInstance.  However,
@@ -3352,10 +3353,10 @@
   }
 }
 
-bool WebContentsImpl::ShouldTransferNavigation() {
+bool WebContentsImpl::ShouldTransferNavigation(bool is_main_frame_navigation) {
   if (!delegate_)
     return true;
-  return delegate_->ShouldTransferNavigation();
+  return delegate_->ShouldTransferNavigation(is_main_frame_navigation);
 }
 
 bool WebContentsImpl::ShouldPreserveAbortedURLs() {
@@ -4499,6 +4500,12 @@
       navigation_handle);
 }
 
+std::unique_ptr<NavigationUIData> WebContentsImpl::GetNavigationUIData(
+    NavigationHandle* navigation_handle) {
+  DCHECK(IsBrowserSideNavigationEnabled());
+  return GetContentClient()->browser()->GetNavigationUIData(navigation_handle);
+}
+
 void WebContentsImpl::DidCancelLoading() {
   controller_.DiscardNonCommittedEntries();
 
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 397d2c4..52f656a 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -92,6 +92,10 @@
 struct ResourceRedirectDetails;
 struct ResourceRequestDetails;
 
+namespace mojom {
+class CreateNewWindowParams;
+}
+
 #if defined(OS_ANDROID)
 class WebContentsAndroid;
 #endif
@@ -536,7 +540,7 @@
       int32_t route_id,
       int32_t main_frame_route_id,
       int32_t main_frame_widget_route_id,
-      const ViewHostMsg_CreateWindow_Params& params,
+      const mojom::CreateNewWindowParams& params,
       SessionStorageNamespace* session_storage_namespace) override;
   void CreateNewWidget(int32_t render_process_id,
                        int32_t route_id,
@@ -605,7 +609,7 @@
                                         ReloadType reload_type) override;
   void RequestOpenURL(RenderFrameHostImpl* render_frame_host,
                       const OpenURLParams& params) override;
-  bool ShouldTransferNavigation() override;
+  bool ShouldTransferNavigation(bool is_main_frame_navigation) override;
   bool ShouldPreserveAbortedURLs() override;
   void DidStartLoading(FrameTreeNode* frame_tree_node,
                        bool to_different_document) override;
@@ -613,6 +617,8 @@
   void DidChangeLoadProgress() override;
   ScopedVector<NavigationThrottle> CreateThrottlesForNavigation(
       NavigationHandle* navigation_handle) override;
+  std::unique_ptr<NavigationUIData> GetNavigationUIData(
+      NavigationHandle* navigation_handle) override;
 
   // RenderWidgetHostDelegate --------------------------------------------------
 
diff --git a/content/browser/web_contents/web_contents_view_android.cc b/content/browser/web_contents/web_contents_view_android.cc
index b0a5fb6..0222bc6 100644
--- a/content/browser/web_contents/web_contents_view_android.cc
+++ b/content/browser/web_contents/web_contents_view_android.cc
@@ -245,12 +245,24 @@
     return;
   }
 
+  const SkBitmap* bitmap = image.bitmap();
+  SkBitmap dummy_bitmap;
+
+  if (image.size().IsEmpty()) {
+    // An empty drag image is possible if the Javascript sets an empty drag
+    // image on purpose.
+    // Create a dummy 1x1 pixel image to avoid crashes when converting to java
+    // bitmap.
+    dummy_bitmap.allocN32Pixels(1, 1);
+    dummy_bitmap.eraseColor(0);
+    bitmap = &dummy_bitmap;
+  }
+
   JNIEnv* env = AttachCurrentThread();
   ScopedJavaLocalRef<jstring> jtext =
       ConvertUTF16ToJavaString(env, drop_data.text.string());
 
-  if (!native_view->StartDragAndDrop(
-          jtext, gfx::ConvertToJavaBitmap(image.bitmap()))) {
+  if (!native_view->StartDragAndDrop(jtext, gfx::ConvertToJavaBitmap(bitmap))) {
     // Need to clear drag and drop state in blink.
     OnDragEnded();
     return;
diff --git a/content/child/child_thread_impl.cc b/content/child/child_thread_impl.cc
index 26a2c45..3b534c2 100644
--- a/content/child/child_thread_impl.cc
+++ b/content/child/child_thread_impl.cc
@@ -896,11 +896,8 @@
   int32_t routing_id = static_cast<int32_t>(reinterpret_cast<uintptr_t>(
       associated_interface_provider_bindings_.dispatch_context()));
   Listener* route = router_.GetRoute(routing_id);
-  base::debug::Alias(&name);
-  base::debug::Alias(&request);
-  base::debug::Alias(&routing_id);
-  base::debug::Alias(&route);
-  route->OnAssociatedInterfaceRequest(name, request.PassHandle());
+  if (route)
+    route->OnAssociatedInterfaceRequest(name, request.PassHandle());
 }
 
 bool ChildThreadImpl::IsInBrowserProcess() const {
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index 4d75009..487fc37 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -252,8 +252,8 @@
   WebRuntimeFeatures::enableMediaDocumentDownloadButton(
       base::FeatureList::IsEnabled(features::kMediaDocumentDownloadButton));
 
-  if (base::FeatureList::IsEnabled(features::kPointerEvents))
-    WebRuntimeFeatures::enablePointerEvent(true);
+  WebRuntimeFeatures::enablePointerEvent(
+      base::FeatureList::IsEnabled(features::kPointerEvents));
 
   if (base::FeatureList::IsEnabled(features::kPointerEventV1SpecCapturing))
     WebRuntimeFeatures::enablePointerEventV1SpecCapturing(true);
diff --git a/content/child/web_data_consumer_handle_impl.cc b/content/child/web_data_consumer_handle_impl.cc
index c111cca..50433a3 100644
--- a/content/child/web_data_consumer_handle_impl.cc
+++ b/content/child/web_data_consumer_handle_impl.cc
@@ -56,6 +56,15 @@
 
   *read_size = 0;
 
+  if (!size) {
+    // Even if there is unread data available, mojo::ReadDataRaw() returns
+    // FAILED_PRECONDITION when |size| is 0 and the producer handle was closed.
+    // But in this case, WebDataConsumerHandle::Reader::read() must return Ok.
+    // So we use mojo::Wait() with 0 deadline to check whether readable or not.
+    return HandleReadResult(mojo::Wait(
+        context_->handle().get(), MOJO_HANDLE_SIGNAL_READABLE, 0, nullptr));
+  }
+
   uint32_t size_to_pass = size;
   MojoReadDataFlags flags_to_pass = MOJO_READ_DATA_FLAG_NONE;
   MojoResult rv = mojo::ReadDataRaw(context_->handle().get(), data,
diff --git a/content/child/web_data_consumer_handle_impl_unittest.cc b/content/child/web_data_consumer_handle_impl_unittest.cc
index 46a5de9..98e6c25 100644
--- a/content/child/web_data_consumer_handle_impl_unittest.cc
+++ b/content/child/web_data_consumer_handle_impl_unittest.cc
@@ -193,12 +193,15 @@
     options.struct_size = sizeof(MojoCreateDataPipeOptions);
     options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE;
     options.element_num_bytes = 1;
-    options.capacity_num_bytes = 4;
+    options.capacity_num_bytes = kDataPipeCapacity;
 
     MojoResult result = mojo::CreateDataPipe(&options, &producer_, &consumer_);
     ASSERT_EQ(MOJO_RESULT_OK, result);
   }
 
+ protected:
+  static constexpr int kDataPipeCapacity = 4;
+
   // This function can be blocked if the associated consumer doesn't consume
   // the data.
   std::string ProduceData(size_t total_size) {
@@ -276,6 +279,29 @@
   EXPECT_EQ(expected, operation->result());
 }
 
+TEST_F(WebDataConsumerHandleImplTest, ZeroSizeRead) {
+  ASSERT_GT(kDataPipeCapacity - 1, 0);
+  constexpr size_t data_size = kDataPipeCapacity - 1;
+  std::string expected = ProduceData(data_size);
+  producer_.reset();
+  std::unique_ptr<WebDataConsumerHandleImpl> handle(
+      new WebDataConsumerHandleImpl(std::move(consumer_)));
+  std::unique_ptr<WebDataConsumerHandle::Reader> reader(
+      handle->obtainReader(nullptr));
+
+  size_t read_size;
+  WebDataConsumerHandle::Result rv =
+      reader->read(nullptr, 0, WebDataConsumerHandle::FlagNone, &read_size);
+  EXPECT_EQ(WebDataConsumerHandle::Result::Ok, rv);
+
+  char buffer[16];
+  rv = reader->read(&buffer, sizeof(buffer), WebDataConsumerHandle::FlagNone,
+                    &read_size);
+  EXPECT_EQ(WebDataConsumerHandle::Result::Ok, rv);
+  EXPECT_EQ(data_size, read_size);
+  EXPECT_EQ(expected, std::string(buffer, read_size));
+}
+
 }  // namespace
 
 }  // namespace content
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index df6d152..ff2cfe9 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -306,6 +306,8 @@
     "send_zygote_child_ping_linux.cc",
     "service_worker/embedded_worker_messages.h",
     "service_worker/embedded_worker_settings.h",
+    "service_worker/embedded_worker_start_params.cc",
+    "service_worker/embedded_worker_start_params.h",
     "service_worker/service_worker_client_info.cc",
     "service_worker/service_worker_client_info.h",
     "service_worker/service_worker_messages.h",
@@ -564,6 +566,7 @@
     "render_frame_message_filter.mojom",
     "render_message_filter.mojom",
     "render_widget_window_tree_client_factory.mojom",
+    "service_worker/embedded_worker.mojom",
     "service_worker/embedded_worker_setup.mojom",
     "storage_partition_service.mojom",
     "url_loader.mojom",
@@ -574,11 +577,14 @@
 
   public_deps = [
     "//components/leveldb/public/interfaces",
+    "//content/public/common:interfaces",
     "//device/sensors/public/interfaces",
     "//services/shell/public/interfaces",
     "//services/ui/public/interfaces",
     "//skia/public/interfaces",
     "//third_party/WebKit/public:mojo_bindings",
+    "//third_party/WebKit/public:new_wrapper_types_mojo_bindings",
+    "//ui/base/mojo:mojo_bindings",
     "//ui/gfx/geometry/mojo",
     "//url/mojo:url_mojom_gurl",
     "//url/mojo:url_mojom_origin",
diff --git a/content/common/android/media_metadata_android.cc b/content/common/android/media_metadata_android.cc
index d40f6cf..9238b86 100644
--- a/content/common/android/media_metadata_android.cc
+++ b/content/common/android/media_metadata_android.cc
@@ -46,12 +46,10 @@
 
   for (const auto& artwork : metadata.artwork) {
     std::string src = artwork.src.spec();
-    base::string16 type = artwork.type.is_null() ?
-        base::string16() : artwork.type.string();
     ScopedJavaLocalRef<jstring> j_src(
         base::android::ConvertUTF8ToJavaString(env, src));
     ScopedJavaLocalRef<jstring> j_type(
-        base::android::ConvertUTF16ToJavaString(env, type));
+        base::android::ConvertUTF16ToJavaString(env, artwork.type));
     ScopedJavaLocalRef<jintArray> j_sizes(
         base::android::ToJavaIntArray(
             env, GetFlattenedSizeArray(artwork.sizes)));
diff --git a/content/common/media/media_metadata_sanitizer.cc b/content/common/media/media_metadata_sanitizer.cc
index af2428a..16f5481 100644
--- a/content/common/media/media_metadata_sanitizer.cc
+++ b/content/common/media/media_metadata_sanitizer.cc
@@ -43,9 +43,7 @@
 bool CheckArtworkSanity(const MediaMetadata::Artwork& artwork) {
   if (!CheckArtworkSrcSanity(artwork.src))
     return false;
-  if (artwork.type.is_null())
-    return false;
-  if (artwork.type.string().size() > kMaxArtworkTypeLength)
+  if (artwork.type.size() > kMaxArtworkTypeLength)
     return false;
   if (artwork.sizes.size() > kMaxNumberOfArtworkSizes)
     return false;
@@ -58,10 +56,7 @@
   MediaMetadata::Artwork sanitized_artwork;
 
   sanitized_artwork.src = artwork.src;
-  sanitized_artwork.type = artwork.type.is_null() ?
-      base::NullableString16() :
-      base::NullableString16(
-          artwork.type.string().substr(0, kMaxArtworkTypeLength), false);
+  sanitized_artwork.type = artwork.type.substr(0, kMaxArtworkTypeLength);
   for (const auto& size : artwork.sizes) {
     sanitized_artwork.sizes.push_back(size);
     if (sanitized_artwork.sizes.size() == kMaxNumberOfArtworkSizes)
diff --git a/content/common/media/video_capture.h b/content/common/media/video_capture.h
index 3631273..d48a684 100644
--- a/content/common/media/video_capture.h
+++ b/content/common/media/video_capture.h
@@ -26,6 +26,7 @@
   VIDEO_CAPTURE_STATE_STARTING,
   VIDEO_CAPTURE_STATE_STARTED,
   VIDEO_CAPTURE_STATE_PAUSED,
+  VIDEO_CAPTURE_STATE_RESUMED,
   VIDEO_CAPTURE_STATE_STOPPING,
   VIDEO_CAPTURE_STATE_STOPPED,
   VIDEO_CAPTURE_STATE_ERROR,
diff --git a/content/common/page_state_serialization.cc b/content/common/page_state_serialization.cc
index c081616..2d4782e 100644
--- a/content/common/page_state_serialization.cc
+++ b/content/common/page_state_serialization.cc
@@ -514,7 +514,7 @@
   WriteReal(state.page_scale_factor, obj);
   WriteInteger64(state.item_sequence_number, obj);
   WriteInteger64(state.document_sequence_number, obj);
-  WriteInteger(state.referrer_policy, obj);
+  WriteInteger(static_cast<int>(state.referrer_policy), obj);
   WriteReal(state.visual_viewport_scroll_offset.x(), obj);
   WriteReal(state.visual_viewport_scroll_offset.y(), obj);
 
diff --git a/content/common/render_message_filter.mojom b/content/common/render_message_filter.mojom
index 4c3c810..3b19f688 100644
--- a/content/common/render_message_filter.mojom
+++ b/content/common/render_message_filter.mojom
@@ -4,7 +4,82 @@
 
 module content.mojom;
 
+import "content/public/common/window_container_type.mojom";
+import "third_party/WebKit/public/platform/referrer.mojom";
+import "third_party/WebKit/public/web/window_features.mojom";
+import "ui/base/mojo/window_open_disposition.mojom";
+import "url/mojo/url.mojom";
+
+struct CreateNewWindowParams {
+  // Routing ID of the view initiating the open.
+  int32 opener_id;
+
+  // True if this open request came in the context of a user gesture.
+  bool user_gesture;
+
+  // Type of window requested.
+  WindowContainerType window_container_type;
+
+  // The session storage namespace ID this view should use.
+  int64 session_storage_namespace_id;
+
+  // The name of the resulting frame that should be created (empty if none
+  // has been specified). UTF8 encoded string.
+  string frame_name;
+
+  // The routing id of the frame initiating the open.
+  int32 opener_render_frame_id;
+
+  // The URL of the frame initiating the open.
+  url.mojom.Url opener_url;
+
+  // The URL of the top frame containing the opener.
+  url.mojom.Url opener_top_level_frame_url;
+
+  // The security origin of the frame initiating the open.
+  url.mojom.Url opener_security_origin;
+
+  // Whether the opener will be suppressed in the new window, in which case
+  // scripting the new window is not allowed.
+  bool opener_suppressed;
+
+  // Whether the window should be opened in the foreground, background, etc.
+  ui.mojom.WindowOpenDisposition disposition;
+
+  // The URL that will be loaded in the new window (empty if none has been
+  // sepcified).
+  url.mojom.Url target_url;
+
+  // The referrer that will be used to load |target_url| (empty if none has
+  // been specified).
+  blink.mojom.Referrer referrer;
+
+  // The window features to use for the new view.
+  blink.mojom.WindowFeatures features;
+};
+
+struct CreateNewWindowReply {
+  // The ID of the view to be created. If the ID is MSG_ROUTING_NONE, then the
+  // view couldn't be created.
+  int32 route_id;
+
+  // The ID of the main frame hosted in the view.
+  int32 main_frame_route_id;
+
+  // The ID of the widget for the main frame.
+  int32 main_frame_widget_route_id;
+
+  // Duplicated from CreateNewWindowParams because legacy code.
+  int64 cloned_session_storage_namespace_id;
+};
+
 interface RenderMessageFilter {
   // Synchronously generates a new routing ID for the caller.
   [Sync] GenerateRoutingID() => (int32 routing_id);
+
+  // Sent by the renderer when it is creating a new window.  The browser creates
+  // a tab for it.  If |reply.route_id| is MSG_ROUTING_NONE, the view couldn't
+  // be created.
+  [Sync] CreateNewWindow(CreateNewWindowParams params)
+      => (CreateNewWindowReply reply);
 };
diff --git a/content/common/service_worker/embedded_worker.mojom b/content/common/service_worker/embedded_worker.mojom
new file mode 100644
index 0000000..d15d62b
--- /dev/null
+++ b/content/common/service_worker/embedded_worker.mojom
@@ -0,0 +1,16 @@
+// 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.
+
+module content.mojom;
+
+import "services/shell/public/interfaces/interface_provider.mojom";
+import "url/mojo/url.mojom";
+
+[Native]
+struct EmbeddedWorkerStartParams;
+
+// Interface to control a renderer-side worker's environment.
+interface EmbeddedWorkerInstanceClient {
+  StartWorker(EmbeddedWorkerStartParams params);
+};
diff --git a/content/common/service_worker/embedded_worker.typemap b/content/common/service_worker/embedded_worker.typemap
new file mode 100644
index 0000000..664936b
--- /dev/null
+++ b/content/common/service_worker/embedded_worker.typemap
@@ -0,0 +1,10 @@
+# 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.
+
+mojom = "//content/common/service_worker/embedded_worker.mojom"
+public_headers =
+    [ "//content/common/service_worker/embedded_worker_start_params.h" ]
+traits_headers =
+    [ "//content/common/service_worker/embedded_worker_messages.h" ]
+type_mappings = [ "content.mojom.EmbeddedWorkerStartParams=::content::EmbeddedWorkerStartParams" ]
diff --git a/content/common/service_worker/embedded_worker_messages.h b/content/common/service_worker/embedded_worker_messages.h
index a245c4e0..34dc1eb 100644
--- a/content/common/service_worker/embedded_worker_messages.h
+++ b/content/common/service_worker/embedded_worker_messages.h
@@ -9,6 +9,7 @@
 #include <string>
 
 #include "content/common/service_worker/embedded_worker_settings.h"
+#include "content/common/service_worker/embedded_worker_start_params.h"
 #include "content/public/common/console_message_level.h"
 #include "content/public/common/web_preferences.h"
 #include "ipc/ipc_message.h"
@@ -27,17 +28,17 @@
 IPC_STRUCT_TRAITS_END()
 
 // Parameters structure for EmbeddedWorkerMsg_StartWorker.
-IPC_STRUCT_BEGIN(EmbeddedWorkerMsg_StartWorker_Params)
-  IPC_STRUCT_MEMBER(int, embedded_worker_id)
-  IPC_STRUCT_MEMBER(int64_t, service_worker_version_id)
-  IPC_STRUCT_MEMBER(GURL, scope)
-  IPC_STRUCT_MEMBER(GURL, script_url)
-  IPC_STRUCT_MEMBER(int, worker_devtools_agent_route_id)
-  IPC_STRUCT_MEMBER(bool, pause_after_download)
-  IPC_STRUCT_MEMBER(bool, wait_for_debugger)
-  IPC_STRUCT_MEMBER(bool, is_installed)
-  IPC_STRUCT_MEMBER(content::EmbeddedWorkerSettings, settings)
-IPC_STRUCT_END()
+IPC_STRUCT_TRAITS_BEGIN(content::EmbeddedWorkerStartParams)
+  IPC_STRUCT_TRAITS_MEMBER(embedded_worker_id)
+  IPC_STRUCT_TRAITS_MEMBER(service_worker_version_id)
+  IPC_STRUCT_TRAITS_MEMBER(scope)
+  IPC_STRUCT_TRAITS_MEMBER(script_url)
+  IPC_STRUCT_TRAITS_MEMBER(worker_devtools_agent_route_id)
+  IPC_STRUCT_TRAITS_MEMBER(pause_after_download)
+  IPC_STRUCT_TRAITS_MEMBER(wait_for_debugger)
+  IPC_STRUCT_TRAITS_MEMBER(is_installed)
+  IPC_STRUCT_TRAITS_MEMBER(settings)
+IPC_STRUCT_TRAITS_END()
 
 // Parameters structure for EmbeddedWorkerHostMsg_ReportConsoleMessage.
 // The data members directly correspond to parameters of
@@ -52,7 +53,7 @@
 
 // Browser -> Renderer message to create a new embedded worker context.
 IPC_MESSAGE_CONTROL1(EmbeddedWorkerMsg_StartWorker,
-                     EmbeddedWorkerMsg_StartWorker_Params /* params */)
+                     content::EmbeddedWorkerStartParams /* params */)
 
 // Browser -> Renderer message to resume a worker that has been started
 // with the pause_after_download option.
diff --git a/content/common/service_worker/embedded_worker_start_params.cc b/content/common/service_worker/embedded_worker_start_params.cc
new file mode 100644
index 0000000..93f62ff
--- /dev/null
+++ b/content/common/service_worker/embedded_worker_start_params.cc
@@ -0,0 +1,11 @@
+// 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.
+
+#include "content/common/service_worker/embedded_worker_start_params.h"
+
+namespace content {
+
+EmbeddedWorkerStartParams::EmbeddedWorkerStartParams() {}
+
+}  // namespace content
diff --git a/content/common/service_worker/embedded_worker_start_params.h b/content/common/service_worker/embedded_worker_start_params.h
new file mode 100644
index 0000000..9e2ef2a
--- /dev/null
+++ b/content/common/service_worker/embedded_worker_start_params.h
@@ -0,0 +1,30 @@
+// 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.
+
+#include "content/common/content_export.h"
+#include "content/common/service_worker/embedded_worker_settings.h"
+#include "url/gurl.h"
+
+#ifndef CONTENT_COMMON_SERVICE_WORKER_EMBEDDED_WORKER_START_PARAMS_H_
+#define CONTENT_COMMON_SERVICE_WORKER_EMBEDDED_WORKER_START_PARAMS_H_
+
+namespace content {
+
+struct CONTENT_EXPORT EmbeddedWorkerStartParams {
+  EmbeddedWorkerStartParams();
+
+  int embedded_worker_id;
+  int64_t service_worker_version_id;
+  GURL scope;
+  GURL script_url;
+  int worker_devtools_agent_route_id;
+  bool pause_after_download;
+  bool wait_for_debugger;
+  bool is_installed;
+  EmbeddedWorkerSettings settings;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_COMMON_SERVICE_WORKER_EMBEDDED_WORKER_START_PARAMS_H_
diff --git a/content/common/service_worker/service_worker_utils.cc b/content/common/service_worker/service_worker_utils.cc
index 30faed4..fb3e7251 100644
--- a/content/common/service_worker/service_worker_utils.cc
+++ b/content/common/service_worker/service_worker_utils.cc
@@ -6,6 +6,7 @@
 
 #include <string>
 
+#include "base/command_line.h"
 #include "base/logging.h"
 #include "base/strings/string_util.h"
 #include "content/public/common/origin_util.h"
@@ -118,6 +119,12 @@
          OriginCanAccessServiceWorkers(script_url);
 }
 
+// static
+bool ServiceWorkerUtils::IsMojoForServiceWorkerEnabled() {
+  return base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kMojoServiceWorker);
+}
+
 bool LongestScopeMatcher::MatchLongest(const GURL& scope) {
   if (!ServiceWorkerUtils::ScopeMatches(scope, url_))
     return false;
diff --git a/content/common/service_worker/service_worker_utils.h b/content/common/service_worker/service_worker_utils.h
index 4ea403a3..b0c3cc8de 100644
--- a/content/common/service_worker/service_worker_utils.h
+++ b/content/common/service_worker/service_worker_utils.h
@@ -46,6 +46,8 @@
                                        const GURL& pattern,
                                        const GURL& script_url);
 
+  static bool IsMojoForServiceWorkerEnabled();
+
   // Returns true when '--disable-web-security' flag is set. Otherwise returns
   // whether the all origins of |urls| are same as the origin of |url|.
   template <typename... Args>
diff --git a/content/common/typemaps.gni b/content/common/typemaps.gni
index 2dd3ed67..1b08a89 100644
--- a/content/common/typemaps.gni
+++ b/content/common/typemaps.gni
@@ -6,4 +6,5 @@
   "//content/common/url_loader_status.typemap",
   "//content/common/url_request.typemap",
   "//content/common/url_response_head.typemap",
+  "//content/common/service_worker/embedded_worker.typemap",
 ]
diff --git a/content/common/view_messages.h b/content/common/view_messages.h
index 57b6348..e88fe86 100644
--- a/content/common/view_messages.h
+++ b/content/common/view_messages.h
@@ -94,7 +94,6 @@
                           blink::WebTextDirection::WebTextDirectionLast)
 IPC_ENUM_TRAITS_MAX_VALUE(blink::WebDisplayMode,
                           blink::WebDisplayMode::WebDisplayModeLast)
-IPC_ENUM_TRAITS_MAX_VALUE(WindowContainerType, WINDOW_CONTAINER_TYPE_MAX_VALUE)
 IPC_ENUM_TRAITS(content::FaviconURL::IconType)
 IPC_ENUM_TRAITS(content::MenuItem::Type)
 IPC_ENUM_TRAITS_MAX_VALUE(content::NavigationGesture,
@@ -288,74 +287,6 @@
   IPC_STRUCT_TRAITS_MEMBER(batch_edit)
 IPC_STRUCT_TRAITS_END()
 
-IPC_STRUCT_BEGIN(ViewHostMsg_CreateWindow_Params)
-  // Routing ID of the view initiating the open.
-  IPC_STRUCT_MEMBER(int, opener_id)
-
-  // True if this open request came in the context of a user gesture.
-  IPC_STRUCT_MEMBER(bool, user_gesture)
-
-  // Type of window requested.
-  IPC_STRUCT_MEMBER(WindowContainerType, window_container_type)
-
-  // The session storage namespace ID this view should use.
-  IPC_STRUCT_MEMBER(int64_t, session_storage_namespace_id)
-
-  // The name of the resulting frame that should be created (empty if none
-  // has been specified). UTF8 encoded string.
-  IPC_STRUCT_MEMBER(std::string, frame_name)
-
-  // The routing id of the frame initiating the open.
-  IPC_STRUCT_MEMBER(int, opener_render_frame_id)
-
-  // The URL of the frame initiating the open.
-  IPC_STRUCT_MEMBER(GURL, opener_url)
-
-  // The URL of the top frame containing the opener.
-  IPC_STRUCT_MEMBER(GURL, opener_top_level_frame_url)
-
-  // The security origin of the frame initiating the open.
-  IPC_STRUCT_MEMBER(GURL, opener_security_origin)
-
-  // Whether the opener will be suppressed in the new window, in which case
-  // scripting the new window is not allowed.
-  IPC_STRUCT_MEMBER(bool, opener_suppressed)
-
-  // Whether the window should be opened in the foreground, background, etc.
-  IPC_STRUCT_MEMBER(WindowOpenDisposition, disposition)
-
-  // The URL that will be loaded in the new window (empty if none has been
-  // sepcified).
-  IPC_STRUCT_MEMBER(GURL, target_url)
-
-  // The referrer that will be used to load |target_url| (empty if none has
-  // been specified).
-  IPC_STRUCT_MEMBER(content::Referrer, referrer)
-
-  // The window features to use for the new view.
-  IPC_STRUCT_MEMBER(blink::WebWindowFeatures, features)
-
-  // The additional window features to use for the new view. We pass these
-  // separately from |features| above because we cannot serialize WebStrings
-  // over IPC.
-  IPC_STRUCT_MEMBER(std::vector<base::string16>, additional_features)
-IPC_STRUCT_END()
-
-IPC_STRUCT_BEGIN(ViewHostMsg_CreateWindow_Reply)
-  // The ID of the view to be created. If the ID is MSG_ROUTING_NONE, then the
-  // view couldn't be created.
-  IPC_STRUCT_MEMBER(int32_t, route_id, MSG_ROUTING_NONE)
-
-  // The ID of the main frame hosted in the view.
-  IPC_STRUCT_MEMBER(int32_t, main_frame_route_id, MSG_ROUTING_NONE)
-
-  // The ID of the widget for the main frame.
-  IPC_STRUCT_MEMBER(int32_t, main_frame_widget_route_id, MSG_ROUTING_NONE)
-
-  // TODO(dcheng): No clue. This is kind of duplicated from ViewMsg_New_Params.
-  IPC_STRUCT_MEMBER(int64_t, cloned_session_storage_namespace_id)
-IPC_STRUCT_END()
-
 IPC_STRUCT_BEGIN(ViewHostMsg_CreateWorker_Params)
   // URL for the worker script.
   IPC_STRUCT_MEMBER(GURL, url)
@@ -825,13 +756,6 @@
 IPC_MESSAGE_ROUTED1(ViewHostMsg_SetNeedsBeginFrames,
                     bool /* enabled */)
 
-// Sent by the renderer when it is creating a new window.  The browser creates a
-// tab for it.  If |reply.route_id| is MSG_ROUTING_NONE, the view couldn't be
-// created.
-IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_CreateWindow,
-                            ViewHostMsg_CreateWindow_Params,
-                            ViewHostMsg_CreateWindow_Reply)
-
 // Similar to ViewHostMsg_CreateWindow, except used for sub-widgets, like
 // <select> dropdowns.  This message is sent to the WebContentsImpl that
 // contains the widget being created.
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentVideoView.java b/content/public/android/java/src/org/chromium/content/browser/ContentVideoView.java
index 262584e..e97a730 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentVideoView.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentVideoView.java
@@ -113,6 +113,21 @@
         }
     }
 
+    private static final ContentVideoViewEmbedder NULL_VIDEO_EMBEDDER =
+            new ContentVideoViewEmbedder() {
+                @Override
+                public void enterFullscreenVideo(View view, boolean isVideoLoaded) {}
+
+                @Override
+                public void fullscreenVideoLoaded() {}
+
+                @Override
+                public void exitFullscreenVideo() {}
+
+                @Override
+                public void setSystemUiVisibility(boolean enterFullscreen) {}
+    };
+
     private final Runnable mExitFullscreenRunnable = new Runnable() {
         @Override
         public void run() {
@@ -124,7 +139,7 @@
             ContentVideoViewEmbedder embedder, int videoWidth, int videoHeight) {
         super(context);
         mNativeContentVideoView = nativeContentVideoView;
-        mEmbedder = embedder;
+        mEmbedder = embedder != null ? embedder : NULL_VIDEO_EMBEDDER;
         mUmaRecorded = false;
         mPossibleAccidentalChange = false;
         mIsVideoLoaded = videoWidth > 0 && videoHeight > 0;
@@ -282,10 +297,10 @@
      */
     @CalledByNative
     private static ContentVideoView createContentVideoView(ContentViewCore contentViewCore,
-            long nativeContentVideoView, int videoWidth, int videoHeight) {
+            ContentVideoViewEmbedder embedder, long nativeContentVideoView,
+            int videoWidth, int videoHeight) {
         ThreadUtils.assertOnUiThread();
         Context context = contentViewCore.getContext();
-        ContentVideoViewEmbedder embedder = contentViewCore.getContentVideoViewEmbedder();
         ContentVideoView videoView = new ContentVideoView(
                 context, nativeContentVideoView, embedder, videoWidth, videoHeight);
         return videoView;
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewClient.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewClient.java
index d5b89bc6..0f52818 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewClient.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewClient.java
@@ -157,19 +157,6 @@
         }
     }
 
-    public ContentVideoViewEmbedder getContentVideoViewEmbedder() {
-        return null;
-    }
-
-    /**
-     * Called when BrowserMediaPlayerManager wants to load a media resource.
-     * @param url the URL of media resource to load.
-     * @return true to prevent the resource from being loaded.
-     */
-    public boolean shouldBlockMediaRequest(String url) {
-        return false;
-    }
-
     /**
      * Check whether a key should be propagated to the embedder or not.
      * We need to send almost every key to Blink. However:
@@ -259,11 +246,4 @@
     public int getSystemWindowInsetBottom() {
         return 0;
     }
-
-    /**
-     * Return the product version.
-     */
-    public String getProductVersion() {
-        return "";
-    }
 }
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
index 0d1ea54..b4799019 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
@@ -312,6 +312,7 @@
     }
 
     private final Context mContext;
+    private final String mProductVersion;
     private ViewGroup mContainerView;
     private InternalAccessDelegate mContainerViewInternals;
     private WebContents mWebContents;
@@ -477,8 +478,9 @@
      *
      * @param context The context used to create this.
      */
-    public ContentViewCore(Context context) {
+    public ContentViewCore(Context context, String productVersion) {
         mContext = context;
+        mProductVersion = productVersion;
         mRenderCoordinates = new RenderCoordinates();
         mJoystickScrollProvider = new JoystickScrollProvider(this);
         mAccessibilityManager = (AccessibilityManager)
@@ -2930,7 +2932,7 @@
             @Override
             public void onAccessibilitySnapshot(AccessibilitySnapshotNode root) {
                 viewRoot.setClassName("");
-                viewRoot.setHint(mContentViewClient.getProductVersion());
+                viewRoot.setHint(mProductVersion);
                 if (root == null) {
                     viewRoot.asyncCommit();
                     return;
@@ -3200,15 +3202,6 @@
         if (potentiallyActiveFlingCount > 0) updateGestureStateListener(GestureEventType.FLING_END);
     }
 
-    ContentVideoViewEmbedder getContentVideoViewEmbedder() {
-        return getContentViewClient().getContentVideoViewEmbedder();
-    }
-
-    @CalledByNative
-    private boolean shouldBlockMediaRequest(String url) {
-        return getContentViewClient().shouldBlockMediaRequest(url);
-    }
-
     @CalledByNative
     private void onNativeFlingStopped() {
         // Note that mTouchScrollInProgress should normally be false at this
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/PopupZoomerTest.java b/content/public/android/javatests/src/org/chromium/content/browser/PopupZoomerTest.java
index ee2b94d..7d96d71 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/PopupZoomerTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/PopupZoomerTest.java
@@ -79,7 +79,7 @@
     public void setUp() throws Exception {
         super.setUp();
         mPopupZoomer = createPopupZoomerForTest(getInstrumentation().getTargetContext());
-        mContentViewCore = new ContentViewCore(getActivity());
+        mContentViewCore = new ContentViewCore(getActivity(), "");
         mContentViewCore.setPopupZoomerForTest(mPopupZoomer);
         mContentViewCore.setImeAdapterForTest(
                 new ImeAdapter(new TestInputMethodManagerWrapper(mContentViewCore),
diff --git a/content/public/app/mojo/content_renderer_manifest.json b/content/public/app/mojo/content_renderer_manifest.json
index 399f7dc..bfb147b 100644
--- a/content/public/app/mojo/content_renderer_manifest.json
+++ b/content/public/app/mojo/content_renderer_manifest.json
@@ -6,6 +6,7 @@
     "provided": {
       "all_interfaces": [ "*" ],
       "browser": [
+        "content::mojom::EmbeddedWorkerInstanceClient",
         "content::mojom::EmbeddedWorkerSetup",
         "content::mojom::FrameFactory",
         "content::mojom::TestMojoService",
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn
index d5746648..c18095c8 100644
--- a/content/public/browser/BUILD.gn
+++ b/content/public/browser/BUILD.gn
@@ -151,6 +151,7 @@
     "navigation_throttle.cc",
     "navigation_throttle.h",
     "navigation_type.h",
+    "navigation_ui_data.h",
     "notification_database_data.cc",
     "notification_database_data.h",
     "notification_details.h",
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index ba972e9..0fb4bdd 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -8,6 +8,7 @@
 #include "base/guid.h"
 #include "build/build_config.h"
 #include "content/public/browser/client_certificate_delegate.h"
+#include "content/public/browser/navigation_ui_data.h"
 #include "content/public/browser/vpn_service_proxy.h"
 #include "content/public/common/sandbox_type.h"
 #include "media/base/cdm_factory.h"
@@ -393,6 +394,11 @@
   return ScopedVector<NavigationThrottle>();
 }
 
+std::unique_ptr<NavigationUIData> ContentBrowserClient::GetNavigationUIData(
+    NavigationHandle* navigation_handle) {
+  return nullptr;
+}
+
 #if defined(OS_WIN)
 const wchar_t* ContentBrowserClient::GetResourceDllName() {
   return nullptr;
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index 177437b..31333c57 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -115,6 +115,7 @@
 class LocationProvider;
 class MediaObserver;
 class NavigationHandle;
+class NavigationUIData;
 class PlatformNotificationService;
 class PresentationServiceDelegate;
 class QuotaPermissionContext;
@@ -741,6 +742,12 @@
   virtual ScopedVector<NavigationThrottle> CreateThrottlesForNavigation(
       NavigationHandle* navigation_handle);
 
+  // PlzNavigate
+  // Called at the start of the navigation to get opaque data the embedder
+  // wants to see passed to the corresponding URLRequest on the IO thread.
+  virtual std::unique_ptr<NavigationUIData> GetNavigationUIData(
+      NavigationHandle* navigation_handle);
+
   // Allows the embedder to provide its own AudioManager implementation.
   // If this function returns nullptr, a default platform implementation
   // will be used.
diff --git a/content/public/browser/navigation_ui_data.h b/content/public/browser/navigation_ui_data.h
new file mode 100644
index 0000000..c986330
--- /dev/null
+++ b/content/public/browser/navigation_ui_data.h
@@ -0,0 +1,26 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_BROWSER_NAVIGATION_UI_DATA_H_
+#define CONTENT_PUBLIC_BROWSER_NAVIGATION_UI_DATA_H_
+
+#include <memory>
+
+namespace content {
+
+// PlzNavigate
+// Copyable interface for embedders to pass opaque data to content/. It is
+// expected to be created on the UI thread at the start of the navigation, and
+// content/ will transfer it to the IO thread as a clone.
+class NavigationUIData {
+ public:
+  virtual ~NavigationUIData(){};
+
+  // Creates a new NavigationData that is a deep copy of the original.
+  virtual std::unique_ptr<NavigationUIData> Clone() const = 0;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_PUBLIC_BROWSER_NAVIGATION_UI_DATA_H_
diff --git a/content/public/browser/resource_dispatcher_host_delegate.cc b/content/public/browser/resource_dispatcher_host_delegate.cc
index 229e49f..0928d79 100644
--- a/content/public/browser/resource_dispatcher_host_delegate.cc
+++ b/content/public/browser/resource_dispatcher_host_delegate.cc
@@ -32,8 +32,8 @@
     ResourceContext* resource_context,
     bool is_content_initiated,
     bool must_download,
-    ScopedVector<ResourceThrottle>* throttles) {
-}
+    bool is_new_request,
+    ScopedVector<ResourceThrottle>* throttles) {}
 
 ResourceDispatcherHostLoginDelegate*
     ResourceDispatcherHostDelegate::CreateLoginDelegate(
diff --git a/content/public/browser/resource_dispatcher_host_delegate.h b/content/public/browser/resource_dispatcher_host_delegate.h
index db515bf0..dfaeacd6 100644
--- a/content/public/browser/resource_dispatcher_host_delegate.h
+++ b/content/public/browser/resource_dispatcher_host_delegate.h
@@ -55,10 +55,14 @@
 
   // Allows an embedder to add additional resource handlers for a download.
   // |must_download| is set if the request must be handled as a download.
+  // |is_new_request| is true if this is a call for a new, unstarted request
+  // which also means that RequestBeginning has not been and will not be
+  // called for this request.
   virtual void DownloadStarting(net::URLRequest* request,
                                 ResourceContext* resource_context,
                                 bool is_content_initiated,
                                 bool must_download,
+                                bool is_new_request,
                                 ScopedVector<ResourceThrottle>* throttles);
 
   // Creates a ResourceDispatcherHostLoginDelegate that asks the user for a
diff --git a/content/public/browser/resource_request_info.h b/content/public/browser/resource_request_info.h
index e03cc52e..ad3c07b 100644
--- a/content/public/browser/resource_request_info.h
+++ b/content/public/browser/resource_request_info.h
@@ -17,6 +17,7 @@
 }
 
 namespace content {
+class NavigationUIData;
 class ResourceContext;
 class WebContents;
 
@@ -156,6 +157,11 @@
   // Whether this request if using Lo-Fi mode.
   virtual bool IsUsingLoFi() const = 0;
 
+  // PlzNavigate
+  // Only used for navigations. Returns opaque data set by the embedder on the
+  // UI thread at the beginning of navigation.
+  virtual NavigationUIData* GetNavigationUIData() const = 0;
+
  protected:
   virtual ~ResourceRequestInfo() {}
 };
diff --git a/content/public/browser/web_contents_delegate.cc b/content/public/browser/web_contents_delegate.cc
index 399255a..d107135 100644
--- a/content/public/browser/web_contents_delegate.cc
+++ b/content/public/browser/web_contents_delegate.cc
@@ -27,7 +27,8 @@
   return nullptr;
 }
 
-bool WebContentsDelegate::ShouldTransferNavigation() {
+bool WebContentsDelegate::ShouldTransferNavigation(
+    bool is_main_frame_navigation) {
   return true;
 }
 
@@ -208,6 +209,15 @@
     const base::Callback<void(bool)>& callback) {
   callback.Run(false);
 }
+
+base::android::ScopedJavaLocalRef<jobject>
+WebContentsDelegate::GetContentVideoViewEmbedder() {
+  return base::android::ScopedJavaLocalRef<jobject>();
+}
+
+bool WebContentsDelegate::ShouldBlockMediaRequest(const GURL& url) {
+  return false;
+}
 #endif
 
 bool WebContentsDelegate::RequestPpapiBrokerPermission(
diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h
index b7d17d2..b6e34e4 100644
--- a/content/public/browser/web_contents_delegate.h
+++ b/content/public/browser/web_contents_delegate.h
@@ -26,6 +26,10 @@
 #include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/native_widget_types.h"
 
+#if defined(OS_ANDROID)
+#include "base/android/scoped_java_ref.h"
+#endif
+
 class GURL;
 
 namespace base {
@@ -98,7 +102,7 @@
   // Allows the delegate to optionally cancel navigations that attempt to
   // transfer to a different process between the start of the network load and
   // commit.  Defaults to true.
-  virtual bool ShouldTransferNavigation();
+  virtual bool ShouldTransferNavigation(bool is_main_frame_navigation);
 
   // Called to inform the delegate that the WebContents's navigation state
   // changed. The |changed_flags| indicates the parts of the navigation state
@@ -469,6 +473,13 @@
   virtual void RequestMediaDecodePermission(
       WebContents* web_contents,
       const base::Callback<void(bool)>& callback);
+
+  // Creates a view embedding the video view.
+  virtual base::android::ScopedJavaLocalRef<jobject>
+      GetContentVideoViewEmbedder();
+
+  // Returns true if the given media should be blocked to load.
+  virtual bool ShouldBlockMediaRequest(const GURL& url);
 #endif
 
   // Requests permission to access the PPAPI broker. The delegate should return
diff --git a/content/public/common/BUILD.gn b/content/public/common/BUILD.gn
index 42e486e..ae6a1ba 100644
--- a/content/public/common/BUILD.gn
+++ b/content/public/common/BUILD.gn
@@ -234,6 +234,7 @@
 
   public_deps = [
     "//content/common",
+    "//content/public/common:interfaces",
     "//mojo/public/cpp/bindings",
     "//services/shell/public/cpp",
     "//services/shell/public/interfaces",
@@ -301,3 +302,9 @@
     "feature_h264_with_openh264_ffmpeg.h",
   ]
 }
+
+mojom("interfaces") {
+  sources = [
+    "window_container_type.mojom",
+  ]
+}
diff --git a/content/public/common/OWNERS b/content/public/common/OWNERS
index d278610..dc88b1e 100644
--- a/content/public/common/OWNERS
+++ b/content/public/common/OWNERS
@@ -6,3 +6,5 @@
 
 per-file *.mojom=set noparent
 per-file *.mojom=file://ipc/SECURITY_OWNERS
+per-file *_struct_traits*.*=set noparent
+per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index d5445734..f2ca4fe4 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -117,7 +117,7 @@
 
 // Pointer events support.
 const base::Feature kPointerEvents{"PointerEvent",
-                                   base::FEATURE_DISABLED_BY_DEFAULT};
+                                   base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Whether pointer event capturing follow v1 spec instead of v2 proposal.
 // See https://rawgit.com/w3c/pointerevents/reduce-hit-tests/index.html.
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 223d56d..2db58be 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -653,6 +653,9 @@
 // Use a Mojo-based LocalStorage implementation.
 const char kMojoLocalStorage[]              = "mojo-local-storage";
 
+// Use a Mojo-based ServiceWorker implementation.
+const char kMojoServiceWorker[]             = "mojo-service-worker";
+
 // Mutes audio sent to the audio device so it is not audible during
 // automated testing.
 const char kMuteAudio[]                     = "mute-audio";
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index 4d065ca..3a36973a 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -197,6 +197,7 @@
 CONTENT_EXPORT extern const char kMHTMLSkipNostoreMain[];
 CONTENT_EXPORT extern const char kMHTMLSkipNostoreAll[];
 CONTENT_EXPORT extern const char kMojoLocalStorage[];
+CONTENT_EXPORT extern const char kMojoServiceWorker[];
 CONTENT_EXPORT extern const char kMuteAudio[];
 CONTENT_EXPORT extern const char kNoReferrers[];
 CONTENT_EXPORT extern const char kNoSandbox[];
diff --git a/content/public/common/manifest.h b/content/public/common/manifest.h
index 71e8f605..8e6ce266 100644
--- a/content/public/common/manifest.h
+++ b/content/public/common/manifest.h
@@ -11,6 +11,7 @@
 #include <vector>
 
 #include "base/strings/nullable_string16.h"
+#include "base/strings/string16.h"
 #include "content/common/content_export.h"
 #include "third_party/WebKit/public/platform/WebDisplayMode.h"
 #include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h"
@@ -36,11 +37,11 @@
     // successfully parsed, thus will not be represented in the Manifest.
     GURL src;
 
-    // Null if the parsing failed or the field was not present. The type can be
+    // Empty if the parsing failed or the field was not present. The type can be
     // any string and doesn't have to be a valid image MIME type at this point.
     // It is up to the consumer of the object to check if the type matches a
     // supported type.
-    base::NullableString16 type;
+    base::string16 type;
 
     // Empty if the parsing failed, the field was not present or empty.
     // The special value "any" is represented by gfx::Size(0, 0).
diff --git a/content/public/common/platform_notification_data.h b/content/public/common/platform_notification_data.h
index a2108d0b..7404901 100644
--- a/content/public/common/platform_notification_data.h
+++ b/content/public/common/platform_notification_data.h
@@ -31,7 +31,8 @@
   ~PlatformNotificationAction();
 
   // Type of the action (button or text input).
-  PlatformNotificationActionType type;
+  PlatformNotificationActionType type =
+      PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON;
 
   // Action name that the author can use to distinguish them.
   std::string action;
diff --git a/content/public/common/referrer.typemap b/content/public/common/referrer.typemap
new file mode 100644
index 0000000..00cff59
--- /dev/null
+++ b/content/public/common/referrer.typemap
@@ -0,0 +1,11 @@
+# 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.
+
+mojom = "//third_party/WebKit/public/platform/referrer.mojom"
+public_headers = [ "//content/public/common/referrer.h" ]
+traits_headers = [ "//content/public/common/referrer_struct_traits.h" ]
+sources = [
+  "//content/public/common/referrer_struct_traits.cc",
+]
+type_mappings = [ "blink.mojom.Referrer=content::Referrer" ]
diff --git a/content/public/common/referrer_struct_traits.cc b/content/public/common/referrer_struct_traits.cc
new file mode 100644
index 0000000..6fc851b
--- /dev/null
+++ b/content/public/common/referrer_struct_traits.cc
@@ -0,0 +1,19 @@
+// 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.
+
+#include "content/public/common/referrer_struct_traits.h"
+
+#include "third_party/WebKit/public/platform/ReferrerPolicyEnumTraits.h"
+#include "url/mojo/url_gurl_struct_traits.h"
+
+namespace mojo {
+
+// static
+bool StructTraits<::blink::mojom::ReferrerDataView, content::Referrer>::Read(
+    ::blink::mojom::ReferrerDataView data,
+    content::Referrer* out) {
+  return data.ReadUrl(&out->url) && data.ReadPolicy(&out->policy);
+}
+
+}  // namespace mojo
diff --git a/content/public/common/referrer_struct_traits.h b/content/public/common/referrer_struct_traits.h
new file mode 100644
index 0000000..a1103df2
--- /dev/null
+++ b/content/public/common/referrer_struct_traits.h
@@ -0,0 +1,29 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_COMMON_REFERRER_STRUCT_TRAITS_H_
+#define CONTENT_PUBLIC_COMMON_REFERRER_STRUCT_TRAITS_H_
+
+#include "content/public/common/referrer.h"
+#include "third_party/WebKit/public/platform/referrer.mojom.h"
+
+namespace mojo {
+
+template <>
+struct StructTraits<::blink::mojom::ReferrerDataView, content::Referrer> {
+  static const GURL& url(const content::Referrer& r) {
+    return r.url;
+  }
+
+  static ::blink::WebReferrerPolicy policy(const content::Referrer& r) {
+    return r.policy;
+  }
+
+  static bool Read(::blink::mojom::ReferrerDataView data,
+                   content::Referrer* out);
+};
+
+}
+
+#endif  // CONTENT_PUBLIC_COMMON_REFERRER_STRUCT_TRAITS_H_
diff --git a/content/public/common/typemaps.gni b/content/public/common/typemaps.gni
new file mode 100644
index 0000000..9e064ca
--- /dev/null
+++ b/content/public/common/typemaps.gni
@@ -0,0 +1,5 @@
+# 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.
+
+typemaps = [ "//content/public/common/referrer.typemap" ]
diff --git a/content/public/common/window_container_type.cc b/content/public/common/window_container_type.cc
index aec4e180..57291bb 100644
--- a/content/public/common/window_container_type.cc
+++ b/content/public/common/window_container_type.cc
@@ -18,6 +18,13 @@
 
 }  // namespace
 
+const WindowContainerType WINDOW_CONTAINER_TYPE_NORMAL =
+    content::mojom::WindowContainerType::NORMAL;
+const WindowContainerType WINDOW_CONTAINER_TYPE_BACKGROUND =
+    content::mojom::WindowContainerType::BACKGROUND;
+const WindowContainerType WINDOW_CONTAINER_TYPE_PERSISTENT =
+    content::mojom::WindowContainerType::PERSISTENT;
+
 WindowContainerType WindowFeaturesToContainerType(
     const blink::WebWindowFeatures& window_features) {
   bool background = false;
diff --git a/content/public/common/window_container_type.h b/content/public/common/window_container_type.h
index 3c9e728f..06f0267 100644
--- a/content/public/common/window_container_type.h
+++ b/content/public/common/window_container_type.h
@@ -5,28 +5,26 @@
 #ifndef CONTENT_PUBLIC_COMMON_WINDOW_CONTAINER_TYPE_H_
 #define CONTENT_PUBLIC_COMMON_WINDOW_CONTAINER_TYPE_H_
 
+#include "content/common/content_export.h"
+#include "content/public/common/window_container_type.mojom.h"
+
 namespace blink {
 
 struct WebWindowFeatures;
 
 }
 
-// "Container" types which can be requested via the window.open feature
-// string.
-enum WindowContainerType {
-  // A window shown in popup or tab.
-  WINDOW_CONTAINER_TYPE_NORMAL = 0,
+using WindowContainerType = content::mojom::WindowContainerType;
 
-  // A window run as a hidden "background" page.
-  WINDOW_CONTAINER_TYPE_BACKGROUND,
+// TODO(rockot): Remove these duplicate definitions by updating all references
+// to point directly to the mojom enum values.
+extern const WindowContainerType CONTENT_EXPORT WINDOW_CONTAINER_TYPE_NORMAL;
 
-  // A window run as a hidden "background" page that wishes to be started
-  // upon browser launch and run beyond the lifetime of the pages that
-  // reference it.
-  WINDOW_CONTAINER_TYPE_PERSISTENT,
+extern const WindowContainerType CONTENT_EXPORT
+WINDOW_CONTAINER_TYPE_BACKGROUND;
 
-  WINDOW_CONTAINER_TYPE_MAX_VALUE = WINDOW_CONTAINER_TYPE_PERSISTENT,
-};
+extern const WindowContainerType CONTENT_EXPORT
+WINDOW_CONTAINER_TYPE_PERSISTENT;
 
 // Conversion function:
 WindowContainerType WindowFeaturesToContainerType(
diff --git a/content/public/common/window_container_type.mojom b/content/public/common/window_container_type.mojom
new file mode 100644
index 0000000..c96302d
--- /dev/null
+++ b/content/public/common/window_container_type.mojom
@@ -0,0 +1,18 @@
+// 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.
+
+module content.mojom;
+
+enum WindowContainerType {
+  // A window shown in popup or tab.
+  NORMAL = 0,
+
+  // A window run as a hidden "background" page.
+  BACKGROUND,
+
+  // A window run as a hidden "background" page that wishes to be started
+  // upon browser launch and run beyond the lifetime of the pages that
+  // reference it.
+  PERSISTENT,
+};
diff --git a/content/public/test/mock_render_thread.cc b/content/public/test/mock_render_thread.cc
index ceeac534..ce24527a 100644
--- a/content/public/test/mock_render_thread.cc
+++ b/content/public/test/mock_render_thread.cc
@@ -9,8 +9,10 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "content/common/frame_messages.h"
+#include "content/common/render_message_filter.mojom.h"
 #include "content/common/view_messages.h"
 #include "content/public/renderer/render_thread_observer.h"
+#include "content/renderer/render_thread_impl.h"
 #include "content/renderer/render_view_impl.h"
 #include "ipc/ipc_message_utils.h"
 #include "ipc/ipc_sync_message.h"
@@ -22,13 +24,54 @@
 
 namespace content {
 
+namespace {
+
+class MockRenderMessageFilterImpl : public mojom::RenderMessageFilter {
+ public:
+  explicit MockRenderMessageFilterImpl(MockRenderThread* thread)
+      : thread_(thread) {}
+  ~MockRenderMessageFilterImpl() override {}
+
+  // mojom::RenderMessageFilter:
+  void GenerateRoutingID(const GenerateRoutingIDCallback& callback) override {
+    NOTREACHED();
+    callback.Run(MSG_ROUTING_NONE);
+  }
+
+  void CreateNewWindow(mojom::CreateNewWindowParamsPtr params,
+                       const CreateNewWindowCallback& callback) override {
+    // NOTE: This implementation of mojom::RenderMessageFilter is used client-
+    // side only. Because sync mojom methods have a different interface for
+    // bindings- and client-side, we only implement the client-side interface
+    // on this object.
+    NOTREACHED();
+  }
+
+  // Note that
+  bool CreateNewWindow(mojom::CreateNewWindowParamsPtr params,
+                       mojom::CreateNewWindowReplyPtr* reply) override {
+    *reply = mojom::CreateNewWindowReply::New();
+    thread_->OnCreateWindow(*params, reply->get());
+    return true;
+  }
+
+ private:
+  MockRenderThread* const thread_;
+};
+
+}  // namespace
+
 MockRenderThread::MockRenderThread()
     : routing_id_(0),
       opener_id_(0),
       new_window_routing_id_(0),
       new_window_main_frame_routing_id_(0),
       new_window_main_frame_widget_routing_id_(0),
-      new_frame_routing_id_(0) {}
+      new_frame_routing_id_(0),
+      mock_render_message_filter_(new MockRenderMessageFilterImpl(this)) {
+  RenderThreadImpl::SetRenderMessageFilterForTesting(
+      mock_render_message_filter_.get());
+}
 
 MockRenderThread::~MockRenderThread() {
   while (!filters_.empty()) {
@@ -218,16 +261,6 @@
   *route_id = routing_id_;
 }
 
-// The View expects to be returned a valid route_id different from its own.
-void MockRenderThread::OnCreateWindow(
-    const ViewHostMsg_CreateWindow_Params& params,
-    ViewHostMsg_CreateWindow_Reply* reply) {
-  reply->route_id = new_window_routing_id_;
-  reply->main_frame_route_id = new_window_main_frame_routing_id_;
-  reply->main_frame_widget_route_id = new_window_main_frame_widget_routing_id_;
-  reply->cloned_session_storage_namespace_id = 0;
-}
-
 // The Frame expects to be returned a valid route_id different from its own.
 void MockRenderThread::OnCreateChildFrame(
     const FrameHostMsg_CreateChildFrame_Params& params,
@@ -252,7 +285,6 @@
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(MockRenderThread, msg)
     IPC_MESSAGE_HANDLER(ViewHostMsg_CreateWidget, OnCreateWidget)
-    IPC_MESSAGE_HANDLER(ViewHostMsg_CreateWindow, OnCreateWindow)
     IPC_MESSAGE_HANDLER(FrameHostMsg_CreateChildFrame, OnCreateChildFrame)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
@@ -269,4 +301,14 @@
 }
 #endif  // defined(OS_WIN)
 
+// The View expects to be returned a valid route_id different from its own.
+void MockRenderThread::OnCreateWindow(
+    const mojom::CreateNewWindowParams& params,
+    mojom::CreateNewWindowReply* reply) {
+  reply->route_id = new_window_routing_id_;
+  reply->main_frame_route_id = new_window_main_frame_routing_id_;
+  reply->main_frame_widget_route_id = new_window_main_frame_widget_routing_id_;
+  reply->cloned_session_storage_namespace_id = 0;
+}
+
 }  // namespace content
diff --git a/content/public/test/mock_render_thread.h b/content/public/test/mock_render_thread.h
index 909b3530..acd2b81 100644
--- a/content/public/test/mock_render_thread.h
+++ b/content/public/test/mock_render_thread.h
@@ -20,8 +20,6 @@
 #include "third_party/WebKit/public/web/WebPopupType.h"
 
 struct FrameHostMsg_CreateChildFrame_Params;
-struct ViewHostMsg_CreateWindow_Params;
-struct ViewHostMsg_CreateWindow_Reply;
 
 namespace IPC {
 class MessageFilter;
@@ -35,10 +33,15 @@
 
 namespace content {
 
+namespace mojom {
+class CreateNewWindowParams;
+class CreateNewWindowReply;
+class RenderMessageFilter;
+}
+
 // This class is a very simple mock of RenderThread. It simulates an IPC channel
 // which supports only three messages:
 // ViewHostMsg_CreateWidget : sync message sent by the Widget.
-// ViewHostMsg_CreateWindow : sync message sent by the Widget.
 // ViewMsg_Close : async, send to the Widget.
 class MockRenderThread : public RenderThread {
  public:
@@ -111,6 +114,12 @@
 
   base::ObserverList<RenderThreadObserver>& observers() { return observers_; }
 
+  // The View expects to be returned a valid |reply.route_id| different from its
+  // own. We do not keep track of the newly created widget in MockRenderThread,
+  // so it must be cleaned up on its own.
+  void OnCreateWindow(const mojom::CreateNewWindowParams& params,
+                      mojom::CreateNewWindowReply* reply);
+
  protected:
   // This function operates as a regular IPC listener. Subclasses
   // overriding this should first delegate to this implementation.
@@ -121,12 +130,6 @@
                       blink::WebPopupType popup_type,
                       int* route_id);
 
-  // The View expects to be returned a valid |reply.route_id| different from its
-  // own. We do not keep track of the newly created widget in MockRenderThread,
-  // so it must be cleaned up on its own.
-  void OnCreateWindow(const ViewHostMsg_CreateWindow_Params& params,
-                      ViewHostMsg_CreateWindow_Reply* reply);
-
   // The Frame expects to be returned a valid route_id different from its own.
   void OnCreateChildFrame(const FrameHostMsg_CreateChildFrame_Params& params,
                           int* new_render_frame_id);
@@ -164,6 +167,8 @@
   std::unique_ptr<shell::InterfaceProvider> remote_interfaces_;
   shell::mojom::InterfaceProviderRequest
       pending_remote_interface_provider_request_;
+
+  std::unique_ptr<mojom::RenderMessageFilter> mock_render_message_filter_;
 };
 
 }  // namespace content
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 8df6b73..cb51761 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -345,6 +345,8 @@
     "service_worker/embedded_worker_devtools_agent.h",
     "service_worker/embedded_worker_dispatcher.cc",
     "service_worker/embedded_worker_dispatcher.h",
+    "service_worker/embedded_worker_instance_client_impl.cc",
+    "service_worker/embedded_worker_instance_client_impl.h",
     "service_worker/service_worker_context_client.cc",
     "service_worker/service_worker_context_client.h",
     "service_worker/service_worker_context_message_filter.cc",
diff --git a/content/renderer/gpu/gpu_benchmarking_extension.cc b/content/renderer/gpu/gpu_benchmarking_extension.cc
index e8d968e..88e14fa 100644
--- a/content/renderer/gpu/gpu_benchmarking_extension.cc
+++ b/content/renderer/gpu/gpu_benchmarking_extension.cc
@@ -39,6 +39,7 @@
 #include "third_party/WebKit/public/web/WebKit.h"
 #include "third_party/WebKit/public/web/WebLocalFrame.h"
 #include "third_party/WebKit/public/web/WebPrintParams.h"
+#include "third_party/WebKit/public/web/WebSettings.h"
 #include "third_party/WebKit/public/web/WebView.h"
 #include "third_party/skia/include/core/SkData.h"
 #include "third_party/skia/include/core/SkGraphics.h"
@@ -562,6 +563,7 @@
       blink::WebRect(kMarginLeft, kMarginTop, kContentWidth, kContentHeight);
   SkFILEWStream wStream(path.MaybeAsASCII().c_str());
   sk_sp<SkDocument> doc = SkMakeMultiPictureDocument(&wStream);
+  context.web_frame()->view()->settings()->setShouldPrintBackgrounds(true);
   int page_count = context.web_frame()->printBegin(params);
   for (int i = 0; i < page_count; ++i) {
     SkCanvas* canvas =
diff --git a/content/renderer/manifest/manifest_manager.cc b/content/renderer/manifest/manifest_manager.cc
index e23c99a..d54e41a 100644
--- a/content/renderer/manifest/manifest_manager.cc
+++ b/content/renderer/manifest/manifest_manager.cc
@@ -60,14 +60,10 @@
       ipc_manifest.name.string().substr(0, Manifest::kMaxIPCStringLength),
       ipc_manifest.name.is_null());
   ipc_manifest.short_name = base::NullableString16(
-        ipc_manifest.short_name.string().substr(0,
-                                                Manifest::kMaxIPCStringLength),
-        ipc_manifest.short_name.is_null());
-  for (auto& icon : ipc_manifest.icons) {
-    icon.type = base::NullableString16(
-        icon.type.string().substr(0, Manifest::kMaxIPCStringLength),
-        icon.type.is_null());
-  }
+      ipc_manifest.short_name.string().substr(0, Manifest::kMaxIPCStringLength),
+      ipc_manifest.short_name.is_null());
+  for (auto& icon : ipc_manifest.icons)
+    icon.type = icon.type.substr(0, Manifest::kMaxIPCStringLength);
   ipc_manifest.gcm_sender_id = base::NullableString16(
         ipc_manifest.gcm_sender_id.string().substr(
             0, Manifest::kMaxIPCStringLength),
diff --git a/content/renderer/manifest/manifest_parser.cc b/content/renderer/manifest/manifest_parser.cc
index 5f771a84..442e0d8 100644
--- a/content/renderer/manifest/manifest_parser.cc
+++ b/content/renderer/manifest/manifest_parser.cc
@@ -249,9 +249,12 @@
   return ParseURL(icon, "src", manifest_url_);
 }
 
-base::NullableString16 ManifestParser::ParseIconType(
+base::string16 ManifestParser::ParseIconType(
     const base::DictionaryValue& icon) {
-  return ParseString(icon, "type", Trim);
+  base::NullableString16 nullable_string = ParseString(icon, "type", Trim);
+  if (nullable_string.is_null())
+    return base::string16();
+  return nullable_string.string();
 }
 
 std::vector<gfx::Size> ManifestParser::ParseIconSizes(
diff --git a/content/renderer/manifest/manifest_parser.h b/content/renderer/manifest/manifest_parser.h
index 2c8d207..bf5acad6 100644
--- a/content/renderer/manifest/manifest_parser.h
+++ b/content/renderer/manifest/manifest_parser.h
@@ -121,8 +121,8 @@
 
   // Parses the 'type' field of an icon, as defined in:
   // http://w3c.github.io/manifest/#dfn-steps-for-processing-the-type-member-of-an-icon
-  // Returns the parsed string if any, a null string if the parsing failed.
-  base::NullableString16 ParseIconType(const base::DictionaryValue& icon);
+  // Returns the parsed string if any, an empty string if the parsing failed.
+  base::string16 ParseIconType(const base::DictionaryValue& icon);
 
   // Parses the 'sizes' field of an icon, as defined in:
   // http://w3c.github.io/manifest/#dfn-steps-for-processing-a-sizes-member-of-an-icon
diff --git a/content/renderer/manifest/manifest_parser_unittest.cc b/content/renderer/manifest/manifest_parser_unittest.cc
index 431153143..a2d1255 100644
--- a/content/renderer/manifest/manifest_parser_unittest.cc
+++ b/content/renderer/manifest/manifest_parser_unittest.cc
@@ -737,7 +737,7 @@
   {
     Manifest manifest =
         ParseManifest("{ \"icons\": [ {\"src\": \"\", \"type\": \"foo\" } ] }");
-    EXPECT_TRUE(base::EqualsASCII(manifest.icons[0].type.string(), "foo"));
+    EXPECT_TRUE(base::EqualsASCII(manifest.icons[0].type, "foo"));
     EXPECT_EQ(0u, GetErrorCount());
   }
 
@@ -745,7 +745,7 @@
   {
     Manifest manifest = ParseManifest("{ \"icons\": [ {\"src\": \"\","
                                       " \"type\": \"  foo  \" } ] }");
-    EXPECT_TRUE(base::EqualsASCII(manifest.icons[0].type.string(), "foo"));
+    EXPECT_TRUE(base::EqualsASCII(manifest.icons[0].type, "foo"));
     EXPECT_EQ(0u, GetErrorCount());
   }
 
@@ -753,7 +753,7 @@
   {
     Manifest manifest =
         ParseManifest("{ \"icons\": [ {\"src\": \"\", \"type\": {} } ] }");
-    EXPECT_TRUE(manifest.icons[0].type.is_null());
+    EXPECT_TRUE(manifest.icons[0].type.empty());
     EXPECT_EQ(1u, GetErrorCount());
     EXPECT_EQ("property 'type' ignored, type string expected.",
               errors()[0]);
@@ -763,7 +763,7 @@
   {
     Manifest manifest =
         ParseManifest("{ \"icons\": [ {\"src\": \"\", \"type\": 42 } ] }");
-    EXPECT_TRUE(manifest.icons[0].type.is_null());
+    EXPECT_TRUE(manifest.icons[0].type.empty());
     EXPECT_EQ(1u, GetErrorCount());
     EXPECT_EQ("property 'type' ignored, type string expected.",
               errors()[0]);
diff --git a/content/renderer/media/android/media_info_loader_unittest.cc b/content/renderer/media/android/media_info_loader_unittest.cc
index 10c67c1..f60b53e 100644
--- a/content/renderer/media/android/media_info_loader_unittest.cc
+++ b/content/renderer/media/android/media_info_loader_unittest.cc
@@ -7,12 +7,12 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "content/renderer/media/android/media_info_loader.h"
-#include "content/test/mock_webframeclient.h"
 #include "content/test/mock_weburlloader.h"
 #include "third_party/WebKit/public/platform/WebMediaPlayer.h"
 #include "third_party/WebKit/public/platform/WebURLError.h"
 #include "third_party/WebKit/public/platform/WebURLRequest.h"
 #include "third_party/WebKit/public/platform/WebURLResponse.h"
+#include "third_party/WebKit/public/web/WebFrameClient.h"
 #include "third_party/WebKit/public/web/WebLocalFrame.h"
 #include "third_party/WebKit/public/web/WebView.h"
 
@@ -40,15 +40,13 @@
 class MediaInfoLoaderTest : public testing::Test {
  public:
   MediaInfoLoaderTest()
-      : view_(WebView::create(nullptr, blink::WebPageVisibilityStateVisible)),
-        frame_(WebLocalFrame::create(blink::WebTreeScopeType::Document,
-                                     &client_)) {
-    view_->setMainFrame(frame_);
+      : view_(WebView::create(nullptr, blink::WebPageVisibilityStateVisible)) {
+    view_->setMainFrame(
+        WebLocalFrame::create(blink::WebTreeScopeType::Document, &client_));
   }
 
   virtual ~MediaInfoLoaderTest() {
     view_->close();
-    frame_->close();
   }
 
   void Initialize(
@@ -116,9 +114,8 @@
   std::unique_ptr<MediaInfoLoader> loader_;
   NiceMock<MockWebURLLoader>* url_loader_;
 
-  MockWebFrameClient client_;
+  blink::WebFrameClient client_;
   WebView* view_;
-  WebLocalFrame* frame_;
 
   base::MessageLoop message_loop_;
 
diff --git a/content/renderer/media/gpu/rtc_video_decoder.cc b/content/renderer/media/gpu/rtc_video_decoder.cc
index 19881ae5..47aae3ee 100644
--- a/content/renderer/media/gpu/rtc_video_decoder.cc
+++ b/content/renderer/media/gpu/rtc_video_decoder.cc
@@ -35,13 +35,9 @@
 const int32_t RTCVideoDecoder::ID_HALF = 0x20000000;
 const int32_t RTCVideoDecoder::ID_INVALID = -1;
 
-// Android vp8, vp9 decoders are quite finicky and often out of date, so give
-// them much less leeway on errors than other platforms.
-#if defined(OS_ANDROID)
+// Number of consecutive frames that can be lost due to a VDA error before
+// falling back to SW implementation.
 const uint32_t kNumVDAErrorsBeforeSWFallback = 5;
-#else
-const uint32_t kNumVDAErrorsBeforeSWFallback = 50;
-#endif
 
 // Maximum number of concurrent VDA::Decode() operations RVD will maintain.
 // Higher values allow better pipelining in the GPU, but also require more
diff --git a/content/renderer/media/media_stream_video_capturer_source.cc b/content/renderer/media/media_stream_video_capturer_source.cc
index 15583dc..35e8e2f 100644
--- a/content/renderer/media/media_stream_video_capturer_source.cc
+++ b/content/renderer/media/media_stream_video_capturer_source.cc
@@ -8,6 +8,7 @@
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
+#include "base/debug/stack_trace.h"
 #include "base/location.h"
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
@@ -212,6 +213,8 @@
                     const VideoCaptureDeliverFrameCB& new_frame_callback,
                     const RunningCallback& running_callback) override;
   void RequestRefreshFrame() override;
+  void MaybeSuspend() override;
+  void Resume() override;
   void StopCapture() override;
 
  private:
@@ -230,10 +233,13 @@
   // Indicates if we are capturing generated content, e.g. Tab or Desktop.
   const bool is_content_capture_;
 
-  // These two are valid between StartCapture() and StopCapture().
-  base::Closure stop_capture_cb_;
+  // This is run once to report whether the device was successfully started
+  // after a call to StartCapture().
   RunningCallback running_callback_;
 
+  // This is valid between StartCapture() and StopCapture().
+  base::Closure stop_capture_cb_;
+
   // Placeholder keeping the callback between asynchronous device enumeration
   // calls.
   VideoCaptureDeviceFormatsCB formats_enumerated_callback_;
@@ -319,6 +325,18 @@
   manager_->RequestRefreshFrame(session_id_);
 }
 
+void LocalVideoCapturerSource::MaybeSuspend() {
+  DVLOG(3) << __func__;
+  DCHECK(thread_checker_.CalledOnValidThread());
+  manager_->Suspend(session_id_);
+}
+
+void LocalVideoCapturerSource::Resume() {
+  DVLOG(3) << __func__;
+  DCHECK(thread_checker_.CalledOnValidThread());
+  manager_->Resume(session_id_);
+}
+
 void LocalVideoCapturerSource::StopCapture() {
   DVLOG(3) << __func__;
   DCHECK(thread_checker_.CalledOnValidThread());
@@ -335,10 +353,24 @@
   DCHECK(thread_checker_.CalledOnValidThread());
   if (running_callback_.is_null())
     return;
-  const bool is_started_ok = state == VIDEO_CAPTURE_STATE_STARTED;
-  running_callback_.Run(is_started_ok);
-  if (!is_started_ok)
-    running_callback_.Reset();
+  switch (state) {
+    case VIDEO_CAPTURE_STATE_STARTED:
+      base::ResetAndReturn(&running_callback_).Run(true);
+      break;
+
+    case VIDEO_CAPTURE_STATE_STOPPING:
+    case VIDEO_CAPTURE_STATE_STOPPED:
+    case VIDEO_CAPTURE_STATE_ERROR:
+    case VIDEO_CAPTURE_STATE_ENDED:
+      base::ResetAndReturn(&running_callback_).Run(false);
+      break;
+
+    case VIDEO_CAPTURE_STATE_STARTING:
+    case VIDEO_CAPTURE_STATE_PAUSED:
+    case VIDEO_CAPTURE_STATE_RESUMED:
+      // Not applicable to reporting on device start success/failure.
+      break;
+  }
 }
 
 void LocalVideoCapturerSource::OnDeviceFormatsInUseReceived(
@@ -414,7 +446,14 @@
   source_->RequestRefreshFrame();
 }
 
-void MediaStreamVideoCapturerSource::SetCapturingLinkSecured(bool is_secure) {
+void MediaStreamVideoCapturerSource::OnHasConsumers(bool has_consumers) {
+  if (has_consumers)
+    source_->Resume();
+  else
+    source_->MaybeSuspend();
+}
+
+void MediaStreamVideoCapturerSource::OnCapturingLinkSecured(bool is_secure) {
   Send(new MediaStreamHostMsg_SetCapturingLinkSecured(
       device_info().session_id, device_info().device.type, is_secure));
 }
diff --git a/content/renderer/media/media_stream_video_capturer_source.h b/content/renderer/media/media_stream_video_capturer_source.h
index 62301bc..6341cb7 100644
--- a/content/renderer/media/media_stream_video_capturer_source.h
+++ b/content/renderer/media/media_stream_video_capturer_source.h
@@ -35,16 +35,14 @@
                                  RenderFrame* render_frame);
   ~MediaStreamVideoCapturerSource() override;
 
-  // Implements MediaStreamVideoSource.
-  void RequestRefreshFrame() override;
-
-  void SetCapturingLinkSecured(bool is_secure) override;
-
  private:
   friend class CanvasCaptureHandlerTest;
   friend class MediaStreamVideoCapturerSourceTest;
 
-  // Implements MediaStreamVideoSource.
+  // MediaStreamVideoSource overrides.
+  void RequestRefreshFrame() override;
+  void OnHasConsumers(bool has_consumers) override;
+  void OnCapturingLinkSecured(bool is_secure) override;
   void GetCurrentSupportedFormats(
       int max_requested_width,
       int max_requested_height,
diff --git a/content/renderer/media/media_stream_video_source.cc b/content/renderer/media/media_stream_video_source.cc
index b2e550c2..0f53144 100644
--- a/content/renderer/media/media_stream_video_source.cc
+++ b/content/renderer/media/media_stream_video_source.cc
@@ -393,11 +393,26 @@
     StopSource();
 }
 
+void MediaStreamVideoSource::UpdateHasConsumers(MediaStreamVideoTrack* track,
+                                                bool has_consumers) {
+  DCHECK(CalledOnValidThread());
+  const auto it =
+      std::find(suspended_tracks_.begin(), suspended_tracks_.end(), track);
+  if (has_consumers) {
+    if (it != suspended_tracks_.end())
+      suspended_tracks_.erase(it);
+  } else {
+    if (it == suspended_tracks_.end())
+      suspended_tracks_.push_back(track);
+  }
+  OnHasConsumers(suspended_tracks_.size() < tracks_.size());
+}
+
 void MediaStreamVideoSource::UpdateCapturingLinkSecure(
-    MediaStreamVideoTrack* track,
-    bool is_secure) {
+    MediaStreamVideoTrack* track, bool is_secure) {
+  DCHECK(CalledOnValidThread());
   secure_tracker_.Update(track, is_secure);
-  SetCapturingLinkSecured(secure_tracker_.is_capturing_secure());
+  OnCapturingLinkSecured(secure_tracker_.is_capturing_secure());
 }
 
 base::SingleThreadTaskRunner* MediaStreamVideoSource::io_task_runner() const {
diff --git a/content/renderer/media/media_stream_video_source.h b/content/renderer/media/media_stream_video_source.h
index 3d79aeafb..ee11f63c 100644
--- a/content/renderer/media/media_stream_video_source.h
+++ b/content/renderer/media/media_stream_video_source.h
@@ -71,14 +71,15 @@
                 const ConstraintsCallback& callback);
   void RemoveTrack(MediaStreamVideoTrack* track);
 
+  // Called by |track| to notify the source whether it has any paths to a
+  // consuming endpoint.
+  void UpdateHasConsumers(MediaStreamVideoTrack* track, bool has_consumers);
+
   void UpdateCapturingLinkSecure(MediaStreamVideoTrack* track, bool is_secure);
 
   // Request underlying source to capture a new frame.
   virtual void RequestRefreshFrame() {}
 
-  // Notify underlying source if the capturing link is secure.
-  virtual void SetCapturingLinkSecured(bool is_secure) {}
-
   // Returns the task runner where video frames will be delivered on.
   base::SingleThreadTaskRunner* io_task_runner() const;
 
@@ -126,6 +127,16 @@
   // method has been called, MediaStreamVideoSource may be deleted.
   virtual void StopSourceImpl() = 0;
 
+  // Optionally overridden by subclasses to act on whether there are any
+  // consumers present. When none are present, the source can stop delivering
+  // frames, giving it the option of running in an "idle" state to minimize
+  // resource usage.
+  virtual void OnHasConsumers(bool has_consumers) {}
+
+  // Optionally overridden by subclasses to act on whether the capturing link
+  // has become secure or insecure.
+  virtual void OnCapturingLinkSecured(bool is_secure) {}
+
   enum State {
     NEW,
     RETRIEVING_CAPABILITIES,
@@ -183,6 +194,10 @@
   // Tracks that currently are connected to this source.
   std::vector<MediaStreamVideoTrack*> tracks_;
 
+  // Tracks that have no paths to a consuming endpoint, and so do not need
+  // frames delivered from the source. This is a subset of |tracks_|.
+  std::vector<MediaStreamVideoTrack*> suspended_tracks_;
+
   // This is used for tracking if all connected video sinks are secure.
   SecureDisplayLinkTracker<MediaStreamVideoTrack> secure_tracker_;
 
diff --git a/content/renderer/media/media_stream_video_track.cc b/content/renderer/media/media_stream_video_track.cc
index e23b290..cdfa86f 100644
--- a/content/renderer/media/media_stream_video_track.cc
+++ b/content/renderer/media/media_stream_video_track.cc
@@ -252,11 +252,12 @@
   frame_deliverer_->AddCallback(sink, callback);
   secure_tracker_.Add(sink, is_sink_secure);
   // Request source to deliver a frame because a new sink is added.
-  if (source_) {
-    source_->RequestRefreshFrame();
-    source_->UpdateCapturingLinkSecure(this,
-                                       secure_tracker_.is_capturing_secure());
-  }
+  if (!source_)
+    return;
+  source_->UpdateHasConsumers(this, true);
+  source_->RequestRefreshFrame();
+  source_->UpdateCapturingLinkSecure(this,
+                                     secure_tracker_.is_capturing_secure());
 }
 
 void MediaStreamVideoTrack::RemoveSink(MediaStreamVideoSink* sink) {
@@ -267,9 +268,12 @@
   sinks_.erase(it);
   frame_deliverer_->RemoveCallback(sink);
   secure_tracker_.Remove(sink);
-  if (source_)
-    source_->UpdateCapturingLinkSecure(this,
-                                       secure_tracker_.is_capturing_secure());
+  if (!source_)
+    return;
+  if (sinks_.empty())
+    source_->UpdateHasConsumers(this, false);
+  source_->UpdateCapturingLinkSecure(this,
+                                     secure_tracker_.is_capturing_secure());
 }
 
 void MediaStreamVideoTrack::SetEnabled(bool enabled) {
diff --git a/content/renderer/media/user_media_client_impl.cc b/content/renderer/media/user_media_client_impl.cc
index 10122a0..ff9a1fe 100644
--- a/content/renderer/media/user_media_client_impl.cc
+++ b/content/renderer/media/user_media_client_impl.cc
@@ -330,16 +330,6 @@
       security_origin);
 }
 
-void UserMediaClientImpl::cancelMediaDevicesRequest(
-    const blink::WebMediaDevicesRequest& media_devices_request) {
-  DCHECK(CalledOnValidThread());
-  MediaDevicesRequestInfo* request =
-      FindMediaDevicesRequestInfo(media_devices_request);
-  if (!request)
-    return;
-  CancelAndDeleteMediaDevicesRequest(request);
-}
-
 void UserMediaClientImpl::requestSources(
     const blink::WebMediaStreamTrackSourcesRequest& sources_request) {
   // We don't call UpdateWebRTCMethodCount() here to track the API count in UMA
diff --git a/content/renderer/media/user_media_client_impl.h b/content/renderer/media/user_media_client_impl.h
index 24c9cd1..dd7a0635 100644
--- a/content/renderer/media/user_media_client_impl.h
+++ b/content/renderer/media/user_media_client_impl.h
@@ -64,8 +64,6 @@
       const blink::WebUserMediaRequest& user_media_request) override;
   void requestMediaDevices(
       const blink::WebMediaDevicesRequest& media_devices_request) override;
-  void cancelMediaDevicesRequest(
-      const blink::WebMediaDevicesRequest& media_devices_request) override;
   void requestSources(
       const blink::WebMediaStreamTrackSourcesRequest& sources_request) override;
   void setMediaDeviceChangeObserver(
diff --git a/content/renderer/media/video_capture_impl.cc b/content/renderer/media/video_capture_impl.cc
index 7a269c6f..583fb97 100644
--- a/content/renderer/media/video_capture_impl.cc
+++ b/content/renderer/media/video_capture_impl.cc
@@ -105,33 +105,24 @@
 VideoCaptureImpl::ClientInfo::~ClientInfo() {}
 
 VideoCaptureImpl::VideoCaptureImpl(
-    const media::VideoCaptureSessionId session_id,
-    VideoCaptureMessageFilter* filter)
+    media::VideoCaptureSessionId session_id,
+    VideoCaptureMessageFilter* filter,
+    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner)
     : message_filter_(filter),
       device_id_(0),
       session_id_(session_id),
       suspended_(false),
       state_(VIDEO_CAPTURE_STATE_STOPPED),
+      io_task_runner_(std::move(io_task_runner)),
       weak_factory_(this) {
   DCHECK(filter);
+  io_task_runner_->PostTask(FROM_HERE,
+                            base::Bind(&VideoCaptureMessageFilter::AddDelegate,
+                                       message_filter_, this));
 }
 
 VideoCaptureImpl::~VideoCaptureImpl() {
   DCHECK(io_task_runner_->BelongsToCurrentThread());
-}
-
-void VideoCaptureImpl::Init() {
-  // For creating callbacks in unittest, this class may be constructed from a
-  // different thread than the IO thread, e.g. wherever unittest runs on.
-  // Therefore, this function should define the thread ownership.
-#if DCHECK_IS_ON()
-  io_task_runner_ = base::ThreadTaskRunnerHandle::Get();
-#endif
-  message_filter_->AddDelegate(this);
-}
-
-void VideoCaptureImpl::DeInit() {
-  DCHECK(io_task_runner_->BelongsToCurrentThread());
   if (state_ == VIDEO_CAPTURE_STATE_STARTED)
     Send(new VideoCaptureHostMsg_Stop(device_id_));
   message_filter_->RemoveDelegate(this);
@@ -448,8 +439,9 @@
         RestartCapture();
       break;
     case VIDEO_CAPTURE_STATE_PAUSED:
+    case VIDEO_CAPTURE_STATE_RESUMED:
       for (const auto& client : clients_)
-        client.second.state_update_cb.Run(VIDEO_CAPTURE_STATE_PAUSED);
+        client.second.state_update_cb.Run(state);
       break;
     case VIDEO_CAPTURE_STATE_ERROR:
       DVLOG(1) << "OnStateChanged: error!, device_id = " << device_id_;
diff --git a/content/renderer/media/video_capture_impl.h b/content/renderer/media/video_capture_impl.h
index 74c4d19..5df25bea 100644
--- a/content/renderer/media/video_capture_impl.h
+++ b/content/renderer/media/video_capture_impl.h
@@ -48,14 +48,10 @@
  public:
   ~VideoCaptureImpl() override;
 
-  VideoCaptureImpl(media::VideoCaptureSessionId session_id,
-                   VideoCaptureMessageFilter* filter);
-
-  // Start listening to IPC messages.
-  void Init();
-
-  // Stop listening to IPC messages.
-  void DeInit();
+  VideoCaptureImpl(
+      media::VideoCaptureSessionId session_id,
+      VideoCaptureMessageFilter* filter,
+      scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
 
   // Stop/resume delivering video frames to clients, based on flag |suspend|.
   void SuspendCapture(bool suspend);
@@ -87,6 +83,10 @@
 
   media::VideoCaptureSessionId session_id() const { return session_id_; }
 
+ protected:
+  // Note: Overridden only by unit test subclasses.
+  virtual void Send(IPC::Message* message);
+
  private:
   friend class VideoCaptureImplTest;
   friend class MockVideoCaptureImpl;
@@ -149,8 +149,6 @@
   void RestartCapture();
   void StartCaptureInternal();
 
-  virtual void Send(IPC::Message* message);
-
   // Helpers.
   bool RemoveClient(int client_id, ClientInfoMap* clients);
 
@@ -196,7 +194,7 @@
   VideoCaptureState state_;
 
   // IO message loop reference for checking correct class operation.
-  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+  const scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
 
   // WeakPtrFactory pointing back to |this| object, for use with
   // media::VideoFrames constructed in OnBufferReceived() from buffers cached
diff --git a/content/renderer/media/video_capture_impl_manager.cc b/content/renderer/media/video_capture_impl_manager.cc
index 1c052d7..7e0fff9 100644
--- a/content/renderer/media/video_capture_impl_manager.cc
+++ b/content/renderer/media/video_capture_impl_manager.cc
@@ -24,6 +24,8 @@
 
 #include "content/renderer/media/video_capture_impl_manager.h"
 
+#include <algorithm>
+
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/location.h"
@@ -35,10 +37,32 @@
 
 namespace content {
 
+struct VideoCaptureImplManager::DeviceEntry {
+  media::VideoCaptureSessionId session_id;
+
+  // To be used and destroyed only on the IO thread.
+  std::unique_ptr<VideoCaptureImpl> impl;
+
+  // Number of clients using |impl|.
+  int client_count;
+
+  // This is set to true if this device is being suspended, via
+  // VideoCaptureImplManager::Suspend().
+  // See also: VideoCaptureImplManager::is_suspending_all_.
+  bool is_individually_suspended;
+
+  DeviceEntry()
+      : session_id(0), client_count(0), is_individually_suspended(false) {}
+  DeviceEntry(DeviceEntry&& other) = default;
+  DeviceEntry& operator=(DeviceEntry&& other) = default;
+  ~DeviceEntry() = default;
+};
+
 VideoCaptureImplManager::VideoCaptureImplManager()
     : next_client_id_(0),
       filter_(new VideoCaptureMessageFilter()),
       render_main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+      is_suspending_all_(false),
       weak_factory_(this) {}
 
 VideoCaptureImplManager::~VideoCaptureImplManager() {
@@ -46,12 +70,9 @@
   if (devices_.empty())
     return;
   // Forcibly release all video capture resources.
-  for (const auto& device : devices_) {
-    VideoCaptureImpl* const impl = device.second.second;
-    ChildProcess::current()->io_task_runner()->PostTask(
-        FROM_HERE,
-        base::Bind(&VideoCaptureImpl::DeInit, base::Unretained(impl)));
-    ChildProcess::current()->io_task_runner()->DeleteSoon(FROM_HERE, impl);
+  for (auto& entry : devices_) {
+    ChildProcess::current()->io_task_runner()->DeleteSoon(FROM_HERE,
+                                                          entry.impl.release());
   }
   devices_.clear();
 }
@@ -59,18 +80,30 @@
 base::Closure VideoCaptureImplManager::UseDevice(
     media::VideoCaptureSessionId id) {
   DCHECK(render_main_task_runner_->BelongsToCurrentThread());
-  VideoCaptureImpl* impl = NULL;
-  const VideoCaptureDeviceMap::iterator it = devices_.find(id);
+  auto it = std::find_if(
+      devices_.begin(), devices_.end(),
+      [id] (const DeviceEntry& entry) { return entry.session_id == id; });
   if (it == devices_.end()) {
-    impl = CreateVideoCaptureImplForTesting(id, filter_.get());
-    if (!impl)
-      impl = new VideoCaptureImpl(id, filter_.get());
-    devices_[id] = std::make_pair(1, impl);
-    ChildProcess::current()->io_task_runner()->PostTask(
-        FROM_HERE, base::Bind(&VideoCaptureImpl::Init, base::Unretained(impl)));
-  } else {
-    ++it->second.first;
+    devices_.push_back(DeviceEntry());
+    it = devices_.end() - 1;
+    it->session_id = id;
+    it->impl = CreateVideoCaptureImplForTesting(id, filter_.get());
+    if (!it->impl) {
+      it->impl.reset(new VideoCaptureImpl(
+          id, filter_.get(), ChildProcess::current()->io_task_runner()));
+    }
   }
+  ++it->client_count;
+
+  // Design limit: When there are multiple clients, VideoCaptureImplManager
+  // would have to individually track which ones requested suspending/resuming,
+  // in order to determine whether the whole device should be suspended.
+  // Instead, handle the non-common use case of multiple clients by just
+  // resuming the suspended device, and disable suspend functionality while
+  // there are multiple clients.
+  if (it->is_individually_suspended)
+    Resume(id);
+
   return base::Bind(&VideoCaptureImplManager::UnrefDevice,
                     weak_factory_.GetWeakPtr(), id);
 }
@@ -81,17 +114,19 @@
     const VideoCaptureStateUpdateCB& state_update_cb,
     const VideoCaptureDeliverFrameCB& deliver_frame_cb) {
   DCHECK(render_main_task_runner_->BelongsToCurrentThread());
-  const VideoCaptureDeviceMap::const_iterator it = devices_.find(id);
+  const auto it = std::find_if(
+      devices_.begin(), devices_.end(),
+      [id] (const DeviceEntry& entry) { return entry.session_id == id; });
   DCHECK(it != devices_.end());
-  VideoCaptureImpl* const impl = it->second.second;
 
   // This ID is used to identify a client of VideoCaptureImpl.
   const int client_id = ++next_client_id_;
 
   ChildProcess::current()->io_task_runner()->PostTask(
       FROM_HERE,
-      base::Bind(&VideoCaptureImpl::StartCapture, base::Unretained(impl),
-                 client_id, params, state_update_cb, deliver_frame_cb));
+      base::Bind(&VideoCaptureImpl::StartCapture,
+                 base::Unretained(it->impl.get()), client_id, params,
+                 state_update_cb, deliver_frame_cb));
   return base::Bind(&VideoCaptureImplManager::StopCapture,
                     weak_factory_.GetWeakPtr(), client_id, id);
 }
@@ -99,83 +134,122 @@
 void VideoCaptureImplManager::RequestRefreshFrame(
     media::VideoCaptureSessionId id) {
   DCHECK(render_main_task_runner_->BelongsToCurrentThread());
-  const VideoCaptureDeviceMap::const_iterator it = devices_.find(id);
+  const auto it = std::find_if(
+      devices_.begin(), devices_.end(),
+      [id] (const DeviceEntry& entry) { return entry.session_id == id; });
   DCHECK(it != devices_.end());
-  VideoCaptureImpl* const impl = it->second.second;
   ChildProcess::current()->io_task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&VideoCaptureImpl::RequestRefreshFrame,
-                 base::Unretained(impl)));
+                 base::Unretained(it->impl.get())));
+}
+
+void VideoCaptureImplManager::Suspend(media::VideoCaptureSessionId id) {
+  DCHECK(render_main_task_runner_->BelongsToCurrentThread());
+  const auto it = std::find_if(
+      devices_.begin(), devices_.end(),
+      [id] (const DeviceEntry& entry) { return entry.session_id == id; });
+  DCHECK(it != devices_.end());
+  if (it->is_individually_suspended)
+    return;  // Device has already been individually suspended.
+  if (it->client_count > 1)
+    return;  // Punt when there is >1 client (see comments in UseDevice()).
+  it->is_individually_suspended = true;
+  if (is_suspending_all_)
+    return;  // Device should already be suspended.
+  ChildProcess::current()->io_task_runner()->PostTask(
+      FROM_HERE, base::Bind(&VideoCaptureImpl::SuspendCapture,
+                            base::Unretained(it->impl.get()), true));
+}
+
+void VideoCaptureImplManager::Resume(media::VideoCaptureSessionId id) {
+  DCHECK(render_main_task_runner_->BelongsToCurrentThread());
+  const auto it = std::find_if(
+      devices_.begin(), devices_.end(),
+      [id] (const DeviceEntry& entry) { return entry.session_id == id; });
+  DCHECK(it != devices_.end());
+  if (!it->is_individually_suspended)
+    return;  // Device was not individually suspended.
+  it->is_individually_suspended = false;
+  if (is_suspending_all_)
+    return;  // Device must remain suspended until all are resumed.
+  ChildProcess::current()->io_task_runner()->PostTask(
+      FROM_HERE, base::Bind(&VideoCaptureImpl::SuspendCapture,
+                            base::Unretained(it->impl.get()), false));
 }
 
 void VideoCaptureImplManager::GetDeviceSupportedFormats(
     media::VideoCaptureSessionId id,
     const VideoCaptureDeviceFormatsCB& callback) {
   DCHECK(render_main_task_runner_->BelongsToCurrentThread());
-  const VideoCaptureDeviceMap::const_iterator it = devices_.find(id);
+  const auto it = std::find_if(
+      devices_.begin(), devices_.end(),
+      [id] (const DeviceEntry& entry) { return entry.session_id == id; });
   DCHECK(it != devices_.end());
-  VideoCaptureImpl* const impl = it->second.second;
   ChildProcess::current()->io_task_runner()->PostTask(
       FROM_HERE, base::Bind(&VideoCaptureImpl::GetDeviceSupportedFormats,
-                            base::Unretained(impl), callback));
+                            base::Unretained(it->impl.get()), callback));
 }
 
 void VideoCaptureImplManager::GetDeviceFormatsInUse(
     media::VideoCaptureSessionId id,
     const VideoCaptureDeviceFormatsCB& callback) {
   DCHECK(render_main_task_runner_->BelongsToCurrentThread());
-  const VideoCaptureDeviceMap::const_iterator it = devices_.find(id);
+  const auto it = std::find_if(
+      devices_.begin(), devices_.end(),
+      [id] (const DeviceEntry& entry) { return entry.session_id == id; });
   DCHECK(it != devices_.end());
-  VideoCaptureImpl* const impl = it->second.second;
   ChildProcess::current()->io_task_runner()->PostTask(
       FROM_HERE, base::Bind(&VideoCaptureImpl::GetDeviceFormatsInUse,
-                            base::Unretained(impl), callback));
+                            base::Unretained(it->impl.get()), callback));
 }
 
-VideoCaptureImpl*
+std::unique_ptr<VideoCaptureImpl>
 VideoCaptureImplManager::CreateVideoCaptureImplForTesting(
     media::VideoCaptureSessionId id,
     VideoCaptureMessageFilter* filter) const {
-  return NULL;
+  return std::unique_ptr<VideoCaptureImpl>();
 }
 
 void VideoCaptureImplManager::StopCapture(int client_id,
                                           media::VideoCaptureSessionId id) {
   DCHECK(render_main_task_runner_->BelongsToCurrentThread());
-  const VideoCaptureDeviceMap::const_iterator it = devices_.find(id);
+  const auto it = std::find_if(
+      devices_.begin(), devices_.end(),
+      [id] (const DeviceEntry& entry) { return entry.session_id == id; });
   DCHECK(it != devices_.end());
-  VideoCaptureImpl* const impl = it->second.second;
   ChildProcess::current()->io_task_runner()->PostTask(
       FROM_HERE, base::Bind(&VideoCaptureImpl::StopCapture,
-                            base::Unretained(impl), client_id));
+                            base::Unretained(it->impl.get()), client_id));
 }
 
 void VideoCaptureImplManager::UnrefDevice(
     media::VideoCaptureSessionId id) {
   DCHECK(render_main_task_runner_->BelongsToCurrentThread());
-  const VideoCaptureDeviceMap::iterator it = devices_.find(id);
+  const auto it = std::find_if(
+      devices_.begin(), devices_.end(),
+      [id] (const DeviceEntry& entry) { return entry.session_id == id; });
   DCHECK(it != devices_.end());
-  VideoCaptureImpl* const impl = it->second.second;
-
-  // Unref and destroy on the IO thread if there's no more client.
-  DCHECK(it->second.first);
-  --it->second.first;
-  if (!it->second.first) {
-    devices_.erase(id);
-    ChildProcess::current()->io_task_runner()->PostTask(
-        FROM_HERE,
-        base::Bind(&VideoCaptureImpl::DeInit, base::Unretained(impl)));
-    ChildProcess::current()->io_task_runner()->DeleteSoon(FROM_HERE, impl);
-  }
+  DCHECK_GT(it->client_count, 0);
+  --it->client_count;
+  if (it->client_count > 0)
+    return;
+  ChildProcess::current()->io_task_runner()->DeleteSoon(FROM_HERE,
+                                                        it->impl.release());
+  devices_.erase(it);
 }
 
 void VideoCaptureImplManager::SuspendDevices(bool suspend) {
   DCHECK(render_main_task_runner_->BelongsToCurrentThread());
-  for (const auto& device : devices_) {
-    VideoCaptureImpl* const impl = device.second.second;
+  if (is_suspending_all_ == suspend)
+    return;
+  is_suspending_all_ = suspend;
+  for (auto& entry : devices_) {
+    if (entry.is_individually_suspended)
+      continue;  // Either: 1) Already suspended; or 2) Should not be resumed.
     ChildProcess::current()->io_task_runner()->PostTask(
         FROM_HERE, base::Bind(&VideoCaptureImpl::SuspendCapture,
-                              base::Unretained(impl), suspend));
+                              base::Unretained(entry.impl.get()), suspend));
   }
 }
 
diff --git a/content/renderer/media/video_capture_impl_manager.h b/content/renderer/media/video_capture_impl_manager.h
index 1b7c28b..005e70d 100644
--- a/content/renderer/media/video_capture_impl_manager.h
+++ b/content/renderer/media/video_capture_impl_manager.h
@@ -5,8 +5,8 @@
 #ifndef CONTENT_RENDERER_MEDIA_VIDEO_CAPTURE_IMPL_MANAGER_H_
 #define CONTENT_RENDERER_MEDIA_VIDEO_CAPTURE_IMPL_MANAGER_H_
 
-#include <map>
 #include <memory>
+#include <vector>
 
 #include "base/callback.h"
 #include "base/macros.h"
@@ -77,6 +77,10 @@
   // picture loss or quality issues).
   void RequestRefreshFrame(media::VideoCaptureSessionId id);
 
+  // Requests frame delivery be suspended/resumed for a given capture session.
+  void Suspend(media::VideoCaptureSessionId id);
+  void Resume(media::VideoCaptureSessionId id);
+
   // Get supported formats supported by the device for the given session
   // ID. |callback| will be called on the IO thread.
   void GetDeviceSupportedFormats(media::VideoCaptureSessionId id,
@@ -88,7 +92,9 @@
                              const VideoCaptureDeviceFormatsCB& callback);
 
   // Make all existing VideoCaptureImpl instances stop/resume delivering
-  // video frames to their clients, depends on flag |suspend|.
+  // video frames to their clients, depends on flag |suspend|. This is called in
+  // response to a RenderView-wide PageHidden/Shown() event. To suspend/resume
+  // an individual session, please call Suspend(id) or Resume(id).
   void SuspendDevices(bool suspend);
 
   VideoCaptureMessageFilter* video_capture_message_filter() const {
@@ -96,21 +102,19 @@
   }
 
  protected:
-  virtual VideoCaptureImpl* CreateVideoCaptureImplForTesting(
+  virtual std::unique_ptr<VideoCaptureImpl> CreateVideoCaptureImplForTesting(
       media::VideoCaptureSessionId id,
       VideoCaptureMessageFilter* filter) const;
 
  private:
+  // Holds bookkeeping info for each VideoCaptureImpl shared by clients.
+  struct DeviceEntry;
+
   void StopCapture(int client_id, media::VideoCaptureSessionId id);
   void UnrefDevice(media::VideoCaptureSessionId id);
 
-  // The int is used to count clients of the corresponding VideoCaptureImpl.
-  // VideoCaptureImpl objects are owned by this object. But they are
-  // destroyed on the IO thread. These are raw pointers because we destroy
-  // them manually.
-  typedef std::map<media::VideoCaptureSessionId,
-                   std::pair<int, VideoCaptureImpl*>> VideoCaptureDeviceMap;
-  VideoCaptureDeviceMap devices_;
+  // Devices currently in use.
+  std::vector<DeviceEntry> devices_;
 
   // This is an internal ID for identifying clients of VideoCaptureImpl.
   // The ID is global for the render process.
@@ -122,6 +126,11 @@
   // right thread.
   const scoped_refptr<base::SingleThreadTaskRunner> render_main_task_runner_;
 
+  // Set to true if SuspendDevices(true) was called. This, along with
+  // DeviceEntry::is_individually_suspended, is used to determine whether to
+  // take action when suspending/resuming each device.
+  bool is_suspending_all_;
+
   // Bound to the render thread.
   // NOTE: Weak pointers must be invalidated before all other member variables.
   base::WeakPtrFactory<VideoCaptureImplManager> weak_factory_;
diff --git a/content/renderer/media/video_capture_impl_manager_unittest.cc b/content/renderer/media/video_capture_impl_manager_unittest.cc
index 349a32e..40632a06 100644
--- a/content/renderer/media/video_capture_impl_manager_unittest.cc
+++ b/content/renderer/media/video_capture_impl_manager_unittest.cc
@@ -2,13 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <array>
+
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "content/child/child_process.h"
+#include "content/common/media/video_capture_messages.h"
 #include "content/renderer/media/video_capture_impl.h"
 #include "content/renderer/media/video_capture_impl_manager.h"
 #include "content/renderer/media/video_capture_message_filter.h"
@@ -27,99 +31,166 @@
   closure.Run();
 }
 
+namespace {
+
+// Callback interface to be implemented by
+// VideoCaptureImplManagerTest. MockVideoCaptureImpl intercepts IPC messages and
+// calls these methods to simulate what the VideoCaptureHost would do.
+class PauseResumeCallback {
+ public:
+  PauseResumeCallback() {}
+  virtual ~PauseResumeCallback() {}
+
+  virtual void OnPaused(media::VideoCaptureSessionId session_id) = 0;
+  virtual void OnResumed(media::VideoCaptureSessionId session_id) = 0;
+};
+
 class MockVideoCaptureImpl : public VideoCaptureImpl {
  public:
   MockVideoCaptureImpl(media::VideoCaptureSessionId session_id,
                        VideoCaptureMessageFilter* filter,
+                       PauseResumeCallback* pause_callback,
                        base::Closure destruct_callback)
-      : VideoCaptureImpl(session_id, filter),
-        destruct_callback_(destruct_callback) {
-  }
+      : VideoCaptureImpl(session_id,
+                         filter,
+                         ChildProcess::current()->io_task_runner()),
+        pause_callback_(pause_callback),
+        destruct_callback_(destruct_callback) {}
 
   ~MockVideoCaptureImpl() override { destruct_callback_.Run(); }
 
+  void Send(IPC::Message* message) override {
+    IPC_BEGIN_MESSAGE_MAP(MockVideoCaptureImpl, *message)
+      IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Pause, DevicePauseCapture)
+      IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Resume, DeviceResumeCapture)
+      default:
+        VideoCaptureImpl::Send(message);
+        return;
+    IPC_END_MESSAGE_MAP()
+    delete message;
+  }
+
  private:
-  base::Closure destruct_callback_;
+  void DevicePauseCapture(int device_id) {
+    pause_callback_->OnPaused(session_id());
+  }
+
+  void DeviceResumeCapture(int device_id,
+                           media::VideoCaptureSessionId session_id,
+                           const media::VideoCaptureParams& params) {
+    pause_callback_->OnResumed(session_id);
+  }
+
+  PauseResumeCallback* const pause_callback_;
+  const base::Closure destruct_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(MockVideoCaptureImpl);
 };
 
 class MockVideoCaptureImplManager : public VideoCaptureImplManager {
  public:
-  explicit MockVideoCaptureImplManager(
-      base::Closure destruct_video_capture_callback)
-      : destruct_video_capture_callback_(
-          destruct_video_capture_callback) {}
+  MockVideoCaptureImplManager(PauseResumeCallback* pause_callback,
+                              base::Closure destruct_video_capture_callback)
+      : pause_callback_(pause_callback),
+        destruct_video_capture_callback_(destruct_video_capture_callback) {}
   ~MockVideoCaptureImplManager() override {}
 
  protected:
-  VideoCaptureImpl* CreateVideoCaptureImplForTesting(
+  std::unique_ptr<VideoCaptureImpl> CreateVideoCaptureImplForTesting(
       media::VideoCaptureSessionId id,
       VideoCaptureMessageFilter* filter) const override {
-    return new MockVideoCaptureImpl(id,
-                                    filter,
-                                    destruct_video_capture_callback_);
+    return base::MakeUnique<MockVideoCaptureImpl>(
+        id, filter, pause_callback_, destruct_video_capture_callback_);
   }
 
  private:
-  base::Closure destruct_video_capture_callback_;
+  PauseResumeCallback* const pause_callback_;
+  const base::Closure destruct_video_capture_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(MockVideoCaptureImplManager);
 };
 
-class VideoCaptureImplManagerTest : public ::testing::Test {
+}  // namespace
+
+class VideoCaptureImplManagerTest : public ::testing::Test,
+                                    public PauseResumeCallback {
  public:
   VideoCaptureImplManagerTest()
-      : manager_(new MockVideoCaptureImplManager(
-          BindToCurrentLoop(cleanup_run_loop_.QuitClosure()))) {
-    params_.requested_format = media::VideoCaptureFormat(
-        gfx::Size(176, 144), 30, media::PIXEL_FORMAT_I420);
-    child_process_.reset(new ChildProcess());
-  }
-
-  void FakeChannelSetup() {
-    scoped_refptr<base::SingleThreadTaskRunner> task_runner =
-        child_process_->io_task_runner();
-    if (!task_runner->BelongsToCurrentThread()) {
-      task_runner->PostTask(
-          FROM_HERE, base::Bind(&VideoCaptureImplManagerTest::FakeChannelSetup,
-                                base::Unretained(this)));
-      return;
-    }
-    manager_->video_capture_message_filter()->OnFilterAdded(NULL);
-  }
+      : child_process_(new ChildProcess()),
+        manager_(new MockVideoCaptureImplManager(
+            this,
+            BindToCurrentLoop(cleanup_run_loop_.QuitClosure()))) {}
 
  protected:
+  static constexpr size_t kNumClients = 3;
+
+  std::array<base::Closure, kNumClients> StartCaptureForAllClients(
+      bool same_session_id) {
+    base::RunLoop run_loop;
+    base::Closure quit_closure = BindToCurrentLoop(run_loop.QuitClosure());
+    EXPECT_CALL(*this, OnStarted(_)).Times(kNumClients - 1)
+        .RetiresOnSaturation();
+    EXPECT_CALL(*this, OnStarted(_)).WillOnce(RunClosure(quit_closure))
+        .RetiresOnSaturation();
+    std::array<base::Closure, kNumClients> stop_callbacks;
+    media::VideoCaptureParams params;
+    params.requested_format = media::VideoCaptureFormat(
+        gfx::Size(176, 144), 30, media::PIXEL_FORMAT_I420);
+    for (size_t i = 0; i < kNumClients; ++i) {
+      stop_callbacks[i] = StartCapture(
+          same_session_id ? 0 : static_cast<media::VideoCaptureSessionId>(i),
+          params);
+    }
+    child_process_->io_task_runner()->PostTask(
+        FROM_HERE,
+        base::Bind(&VideoCaptureMessageFilter::OnFilterAdded,
+                   base::Unretained(manager_->video_capture_message_filter()),
+                   nullptr));
+    run_loop.Run();
+    return stop_callbacks;
+  }
+
+  void StopCaptureForAllClients(
+      std::array<base::Closure, kNumClients>* stop_callbacks) {
+    base::RunLoop run_loop;
+    base::Closure quit_closure = BindToCurrentLoop(run_loop.QuitClosure());
+    EXPECT_CALL(*this, OnStopped(_)).Times(kNumClients - 1)
+        .RetiresOnSaturation();
+    EXPECT_CALL(*this, OnStopped(_)).WillOnce(RunClosure(quit_closure))
+        .RetiresOnSaturation();
+    for (size_t i = 0; i < kNumClients; ++i)
+      (*stop_callbacks)[i].Run();
+    run_loop.Run();
+  }
+
   MOCK_METHOD2(OnFrameReady,
                void(const scoped_refptr<media::VideoFrame>&,
                     base::TimeTicks estimated_capture_time));
-  MOCK_METHOD0(OnStarted, void());
-  MOCK_METHOD0(OnStopped, void());
+  MOCK_METHOD1(OnStarted, void(media::VideoCaptureSessionId id));
+  MOCK_METHOD1(OnStopped, void(media::VideoCaptureSessionId id));
+  MOCK_METHOD1(OnPaused, void(media::VideoCaptureSessionId id));
+  MOCK_METHOD1(OnResumed, void(media::VideoCaptureSessionId id));
 
-  void OnStateUpdate(VideoCaptureState state) {
-    switch (state) {
-      case VIDEO_CAPTURE_STATE_STARTED:
-        OnStarted();
-        break;
-      case VIDEO_CAPTURE_STATE_STOPPED:
-        OnStopped();
-        break;
-      default:
-        NOTREACHED();
-    }
+  void OnStateUpdate(media::VideoCaptureSessionId id, VideoCaptureState state) {
+    if (state == VIDEO_CAPTURE_STATE_STARTED)
+      OnStarted(id);
+    else if (state == VIDEO_CAPTURE_STATE_STOPPED)
+      OnStopped(id);
+    else
+      NOTREACHED();
   }
 
-  base::Closure StartCapture(const media::VideoCaptureParams& params) {
+  base::Closure StartCapture(media::VideoCaptureSessionId id,
+                             const media::VideoCaptureParams& params) {
     return manager_->StartCapture(
-        0, params, base::Bind(&VideoCaptureImplManagerTest::OnStateUpdate,
-                              base::Unretained(this)),
+        id, params, base::Bind(&VideoCaptureImplManagerTest::OnStateUpdate,
+                               base::Unretained(this), id),
         base::Bind(&VideoCaptureImplManagerTest::OnFrameReady,
                    base::Unretained(this)));
   }
 
-  base::MessageLoop message_loop_;
-  std::unique_ptr<ChildProcess> child_process_;
-  media::VideoCaptureParams params_;
+  const base::MessageLoop message_loop_;
+  const std::unique_ptr<ChildProcess> child_process_;
   base::RunLoop cleanup_run_loop_;
   std::unique_ptr<MockVideoCaptureImplManager> manager_;
 
@@ -130,32 +201,14 @@
 // Multiple clients with the same session id. There is only one
 // media::VideoCapture object.
 TEST_F(VideoCaptureImplManagerTest, MultipleClients) {
-  base::Closure release_cb1 = manager_->UseDevice(0);
-  base::Closure release_cb2 = manager_->UseDevice(0);
-  base::Closure stop_cb1, stop_cb2;
-  {
-    base::RunLoop run_loop;
-    base::Closure quit_closure = BindToCurrentLoop(run_loop.QuitClosure());
-    EXPECT_CALL(*this, OnStarted()).WillOnce(RunClosure(quit_closure));
-    EXPECT_CALL(*this, OnStarted()).RetiresOnSaturation();
-    stop_cb1 = StartCapture(params_);
-    stop_cb2 = StartCapture(params_);
-    FakeChannelSetup();
-    run_loop.Run();
-  }
-
-  {
-    base::RunLoop run_loop;
-    base::Closure quit_closure = BindToCurrentLoop(run_loop.QuitClosure());
-    EXPECT_CALL(*this, OnStopped()).WillOnce(RunClosure(quit_closure));
-    EXPECT_CALL(*this, OnStopped()).RetiresOnSaturation();
-    stop_cb1.Run();
-    stop_cb2.Run();
-    run_loop.Run();
-  }
-
-  release_cb1.Run();
-  release_cb2.Run();
+  std::array<base::Closure, kNumClients> release_callbacks;
+  for (size_t i = 0; i < kNumClients; ++i)
+    release_callbacks[i] = manager_->UseDevice(0);
+  std::array<base::Closure, kNumClients> stop_callbacks =
+      StartCaptureForAllClients(true);
+  StopCaptureForAllClients(&stop_callbacks);
+  for (size_t i = 0; i < kNumClients; ++i)
+    release_callbacks[i].Run();
   cleanup_run_loop_.Run();
 }
 
@@ -165,4 +218,86 @@
   cleanup_run_loop_.Run();
 }
 
+TEST_F(VideoCaptureImplManagerTest, SuspendAndResumeSessions) {
+  std::array<base::Closure, kNumClients> release_callbacks;
+  for (size_t i = 0; i < kNumClients; ++i) {
+    release_callbacks[i] =
+        manager_->UseDevice(static_cast<media::VideoCaptureSessionId>(i));
+  }
+  std::array<base::Closure, kNumClients> stop_callbacks =
+      StartCaptureForAllClients(false);
+
+  // Call SuspendDevices(true) to suspend all clients, and expect all to be
+  // paused.
+  {
+    base::RunLoop run_loop;
+    base::Closure quit_closure = BindToCurrentLoop(run_loop.QuitClosure());
+    EXPECT_CALL(*this, OnPaused(0)).Times(1).RetiresOnSaturation();
+    EXPECT_CALL(*this, OnPaused(1)).Times(1).RetiresOnSaturation();
+    EXPECT_CALL(*this, OnPaused(2)).WillOnce(RunClosure(quit_closure))
+        .RetiresOnSaturation();
+    manager_->SuspendDevices(true);
+    run_loop.Run();
+  }
+
+  // Call SuspendDevices(false) and expect all to be resumed.
+  {
+    base::RunLoop run_loop;
+    base::Closure quit_closure = BindToCurrentLoop(run_loop.QuitClosure());
+    EXPECT_CALL(*this, OnResumed(0)).Times(1).RetiresOnSaturation();
+    EXPECT_CALL(*this, OnResumed(1)).Times(1).RetiresOnSaturation();
+    EXPECT_CALL(*this, OnResumed(2)).WillOnce(RunClosure(quit_closure))
+        .RetiresOnSaturation();
+    manager_->SuspendDevices(false);
+    run_loop.Run();
+  }
+
+  // Suspend just the first client and expect just the first client to be
+  // paused.
+  {
+    base::RunLoop run_loop;
+    base::Closure quit_closure = BindToCurrentLoop(run_loop.QuitClosure());
+    EXPECT_CALL(*this, OnPaused(0)).WillOnce(RunClosure(quit_closure))
+        .RetiresOnSaturation();
+    manager_->Suspend(0);
+    run_loop.Run();
+  }
+
+  // Now call SuspendDevices(true) again, and expect just the second and third
+  // clients to be paused.
+  {
+    base::RunLoop run_loop;
+    base::Closure quit_closure = BindToCurrentLoop(run_loop.QuitClosure());
+    EXPECT_CALL(*this, OnPaused(1)).Times(1).RetiresOnSaturation();
+    EXPECT_CALL(*this, OnPaused(2)).WillOnce(RunClosure(quit_closure))
+        .RetiresOnSaturation();
+    manager_->SuspendDevices(true);
+    run_loop.Run();
+  }
+
+  // Resume just the first client, but it should not resume because all devices
+  // are supposed to be suspended.
+  {
+    manager_->Resume(0);
+    base::RunLoop().RunUntilIdle();
+  }
+
+  // Now, call SuspendDevices(false) and expect all to be resumed.
+  {
+    base::RunLoop run_loop;
+    base::Closure quit_closure = BindToCurrentLoop(run_loop.QuitClosure());
+    EXPECT_CALL(*this, OnResumed(0)).Times(1).RetiresOnSaturation();
+    EXPECT_CALL(*this, OnResumed(1)).Times(1).RetiresOnSaturation();
+    EXPECT_CALL(*this, OnResumed(2)).WillOnce(RunClosure(quit_closure))
+        .RetiresOnSaturation();
+    manager_->SuspendDevices(false);
+    run_loop.Run();
+  }
+
+  StopCaptureForAllClients(&stop_callbacks);
+  for (size_t i = 0; i < kNumClients; ++i)
+    release_callbacks[i].Run();
+  cleanup_run_loop_.Run();
+}
+
 }  // namespace content
diff --git a/content/renderer/media/video_capture_impl_unittest.cc b/content/renderer/media/video_capture_impl_unittest.cc
index 7ad265e..990c07a 100644
--- a/content/renderer/media/video_capture_impl_unittest.cc
+++ b/content/renderer/media/video_capture_impl_unittest.cc
@@ -42,7 +42,8 @@
    public:
     MockVideoCaptureImpl(const media::VideoCaptureSessionId id,
                          VideoCaptureMessageFilter* filter)
-        : VideoCaptureImpl(id, filter), received_buffer_count_(0) {}
+        : VideoCaptureImpl(id, filter, base::ThreadTaskRunnerHandle::Get()),
+          received_buffer_count_(0) {}
     ~MockVideoCaptureImpl() override {}
 
     // Override Send() to mimic device to send events.
@@ -115,26 +116,21 @@
     media::VideoCaptureParams capture_params_;
   };
 
-  VideoCaptureImplTest() {
+  VideoCaptureImplTest()
+      : child_process_(new ChildProcess()),
+        message_filter_(new MockVideoCaptureMessageFilter),
+        session_id_(1),
+        video_capture_impl_(
+            new MockVideoCaptureImpl(session_id_, message_filter_.get())) {
     params_small_.requested_format = media::VideoCaptureFormat(
         gfx::Size(176, 144), 30, media::PIXEL_FORMAT_I420);
-
     params_large_.requested_format = media::VideoCaptureFormat(
         gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420);
 
-    child_process_.reset(new ChildProcess());
-
-    message_filter_ = new MockVideoCaptureMessageFilter;
-    session_id_ = 1;
-
-    video_capture_impl_.reset(new MockVideoCaptureImpl(
-        session_id_, message_filter_.get()));
-
     video_capture_impl_->device_id_ = 2;
   }
 
-  virtual ~VideoCaptureImplTest() {
-  }
+  virtual ~VideoCaptureImplTest() {}
 
  protected:
   MOCK_METHOD2(OnFrameReady,
@@ -145,10 +141,6 @@
   MOCK_METHOD1(OnDeviceSupportedFormats,
                void(const media::VideoCaptureFormats&));
 
-  void Init() {
-    video_capture_impl_->Init();
-  }
-
   void StartCapture(int client_id, const media::VideoCaptureParams& params) {
     video_capture_impl_->StartCapture(
         client_id, params, base::Bind(&VideoCaptureImplTest::OnStateUpdate,
@@ -186,10 +178,6 @@
     video_capture_impl_->OnBufferDestroyed(buffer_id);
   }
 
-  void DeInit() {
-    video_capture_impl_->DeInit();
-  }
-
   void GetDeviceSupportedFormats() {
     const base::Callback<void(const media::VideoCaptureFormats&)>
         callback = base::Bind(
@@ -206,10 +194,10 @@
     video_capture_impl_->GetDeviceFormatsInUse(callback);
   }
 
-  base::MessageLoop message_loop_;
-  std::unique_ptr<ChildProcess> child_process_;
-  scoped_refptr<MockVideoCaptureMessageFilter> message_filter_;
-  media::VideoCaptureSessionId session_id_;
+  const base::MessageLoop message_loop_;
+  const std::unique_ptr<ChildProcess> child_process_;
+  const scoped_refptr<MockVideoCaptureMessageFilter> message_filter_;
+  const media::VideoCaptureSessionId session_id_;
   std::unique_ptr<MockVideoCaptureImpl> video_capture_impl_;
   media::VideoCaptureParams params_small_;
   media::VideoCaptureParams params_large_;
@@ -223,46 +211,38 @@
   EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STARTED));
   EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STOPPED));
 
-  Init();
   StartCapture(0, params_small_);
   StopCapture(0);
-  DeInit();
 }
 
 TEST_F(VideoCaptureImplTest, TwoClientsInSequence) {
   EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STARTED)).Times(2);
   EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STOPPED)).Times(2);
 
-  Init();
   StartCapture(0, params_small_);
   StopCapture(0);
   StartCapture(1, params_small_);
   StopCapture(1);
-  DeInit();
 }
 
 TEST_F(VideoCaptureImplTest, LargeAndSmall) {
   EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STARTED)).Times(2);
   EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STOPPED)).Times(2);
 
-  Init();
   StartCapture(0, params_large_);
   StopCapture(0);
   StartCapture(1, params_small_);
   StopCapture(1);
-  DeInit();
 }
 
 TEST_F(VideoCaptureImplTest, SmallAndLarge) {
   EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STARTED)).Times(2);
   EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STOPPED)).Times(2);
 
-  Init();
   StartCapture(0, params_small_);
   StopCapture(0);
   StartCapture(1, params_large_);
   StopCapture(1);
-  DeInit();
 }
 
 // Check that a request to GetDeviceSupportedFormats() ends up eventually in the
@@ -270,9 +250,7 @@
 TEST_F(VideoCaptureImplTest, GetDeviceFormats) {
   EXPECT_CALL(*this, OnDeviceSupportedFormats(_));
 
-  Init();
   GetDeviceSupportedFormats();
-  DeInit();
 }
 
 // Check that two requests to GetDeviceSupportedFormats() end up eventually
@@ -280,10 +258,8 @@
 TEST_F(VideoCaptureImplTest, TwoClientsGetDeviceFormats) {
   EXPECT_CALL(*this, OnDeviceSupportedFormats(_)).Times(2);
 
-  Init();
   GetDeviceSupportedFormats();
   GetDeviceSupportedFormats();
-  DeInit();
 }
 
 // Check that a request to GetDeviceFormatsInUse() ends up eventually in the
@@ -291,9 +267,7 @@
 TEST_F(VideoCaptureImplTest, GetDeviceFormatsInUse) {
   EXPECT_CALL(*this, OnDeviceFormatsInUse(_));
 
-  Init();
   GetDeviceFormatsInUse();
-  DeInit();
 }
 
 TEST_F(VideoCaptureImplTest, BufferReceived) {
@@ -313,13 +287,11 @@
   params.requested_format = media::VideoCaptureFormat(
       size, 30, media::PIXEL_FORMAT_I420);
 
-  Init();
   StartCapture(0, params);
   NewBuffer(0, shm);
   BufferReceived(0, size);
   StopCapture(0);
   BufferDestroyed(0);
-  DeInit();
 }
 
 TEST_F(VideoCaptureImplTest, BufferReceivedAfterStop) {
@@ -333,13 +305,11 @@
       media::PIXEL_FORMAT_I420, params_large_.requested_format.frame_size);
   ASSERT_TRUE(shm.CreateAndMapAnonymous(i420_frame_size));
 
-  Init();
   StartCapture(0, params_large_);
   NewBuffer(0, shm);
   StopCapture(0);
   BufferReceived(0, params_large_.requested_format.frame_size);
   BufferDestroyed(0);
-  DeInit();
 
   EXPECT_EQ(this->video_capture_impl_->received_buffer_count(), 1);
 }
@@ -348,12 +318,10 @@
   EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STARTED)).Times(2);
   EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STOPPED)).Times(2);
 
-  Init();
   StartCapture(0, params_small_);
   StartCapture(1, params_large_);
   StopCapture(0);
   StopCapture(1);
-  DeInit();
   DCHECK(video_capture_impl_->capture_params().requested_format.frame_size ==
          params_small_.requested_format.frame_size);
 }
@@ -362,28 +330,24 @@
    EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STARTED));
    EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STOPPED));
 
-   Init();
    StartCapture(0, params_small_);
 
    // Receive state change message from browser.
    video_capture_impl_->ReceiveStateChangeMessage(VIDEO_CAPTURE_STATE_ENDED);
 
    StopCapture(0);
-   DeInit();
 }
 
 TEST_F(VideoCaptureImplTest, ErrorBeforeStop) {
    EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STARTED));
    EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_ERROR));
 
-   Init();
    StartCapture(0, params_small_);
 
    // Receive state change message from browser.
    video_capture_impl_->ReceiveStateChangeMessage(VIDEO_CAPTURE_STATE_ERROR);
 
    StopCapture(0);
-   DeInit();
 }
 
 }  // namespace content
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 59744b0..829f622 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -2818,7 +2818,7 @@
   has_accessed_initial_document_ = true;
 }
 
-blink::WebFrame* RenderFrameImpl::createChildFrame(
+blink::WebLocalFrame* RenderFrameImpl::createChildFrame(
     blink::WebLocalFrame* parent,
     blink::WebTreeScopeType scope,
     const blink::WebString& name,
@@ -2942,9 +2942,10 @@
   Send(new FrameHostMsg_FrameFocused(routing_id_));
 }
 
-void RenderFrameImpl::willClose(blink::WebFrame* frame) {
+void RenderFrameImpl::willCommitProvisionalLoad(blink::WebLocalFrame* frame) {
   DCHECK_EQ(frame_, frame);
 
+  // TODO(dcheng): Rename observer to FrameWillCommitProvisionalLoad.
   FOR_EACH_OBSERVER(RenderFrameObserver, observers_, FrameWillClose());
   FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
                     FrameWillClose(frame));
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 9523dbc..2fb7787a 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -470,7 +470,7 @@
   blink::BlameContext* frameBlameContext() override;
   blink::WebServiceWorkerProvider* createServiceWorkerProvider() override;
   void didAccessInitialDocument() override;
-  blink::WebFrame* createChildFrame(
+  blink::WebLocalFrame* createChildFrame(
       blink::WebLocalFrame* parent,
       blink::WebTreeScopeType scope,
       const blink::WebString& name,
@@ -480,7 +480,7 @@
   void didChangeOpener(blink::WebFrame* frame) override;
   void frameDetached(blink::WebLocalFrame* frame, DetachType type) override;
   void frameFocused() override;
-  void willClose(blink::WebFrame* frame) override;
+  void willCommitProvisionalLoad(blink::WebLocalFrame* frame) override;
   void didChangeName(const blink::WebString& name,
                      const blink::WebString& unique_name) override;
   void didEnforceInsecureRequestPolicy(
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 8160520..6c6bfc1d 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -119,6 +119,7 @@
 #include "content/renderer/renderer_blink_platform_impl.h"
 #include "content/renderer/scheduler/resource_dispatch_throttler.h"
 #include "content/renderer/service_worker/embedded_worker_dispatcher.h"
+#include "content/renderer/service_worker/embedded_worker_instance_client_impl.h"
 #include "content/renderer/service_worker/service_worker_context_client.h"
 #include "content/renderer/service_worker/service_worker_context_message_filter.h"
 #include "content/renderer/shared_worker/embedded_shared_worker_stub.h"
@@ -248,6 +249,10 @@
 // Unique identifier for each output surface created.
 uint32_t g_next_compositor_frame_sink_id = 1;
 
+// An implementation of mojom::RenderMessageFilter which can be mocked out
+// for tests which may indirectly send messages over this interface.
+mojom::RenderMessageFilter* g_render_message_filter_for_testing;
+
 // Keep the global RenderThreadImpl in a TLS slot so it is impossible to access
 // incorrectly from the wrong thread.
 base::LazyInstance<base::ThreadLocalPointer<RenderThreadImpl> >
@@ -570,10 +575,25 @@
                               std::move(renderer_scheduler));
 }
 
+// static
 RenderThreadImpl* RenderThreadImpl::current() {
   return lazy_tls.Pointer()->Get();
 }
 
+// static
+mojom::RenderMessageFilter* RenderThreadImpl::current_render_message_filter() {
+  if (g_render_message_filter_for_testing)
+    return g_render_message_filter_for_testing;
+  DCHECK(current());
+  return current()->render_message_filter();
+}
+
+// static
+void RenderThreadImpl::SetRenderMessageFilterForTesting(
+    mojom::RenderMessageFilter* render_message_filter) {
+  g_render_message_filter_for_testing = render_message_filter;
+}
+
 RenderThreadImpl::RenderThreadImpl(
     const InProcessChildThreadParams& params,
     std::unique_ptr<blink::scheduler::RendererScheduler> scheduler,
@@ -848,8 +868,11 @@
   GetContentClient()->renderer()->ExposeInterfacesToBrowser(
       GetInterfaceRegistry());
 
-  GetInterfaceRegistry()->AddInterface(base::Bind(CreateFrameFactory));
-  GetInterfaceRegistry()->AddInterface(base::Bind(CreateEmbeddedWorkerSetup));
+  GetInterfaceRegistry()->AddInterface(base::Bind(&CreateFrameFactory));
+  GetInterfaceRegistry()->AddInterface(base::Bind(&CreateEmbeddedWorkerSetup));
+  GetInterfaceRegistry()->AddInterface(
+      base::Bind(&EmbeddedWorkerInstanceClientImpl::Create,
+                 base::Unretained(embedded_worker_dispatcher_.get())));
 
   GetRemoteInterfaces()->GetInterface(
       mojo::GetProxy(&storage_partition_service_));
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index 5051bdf..12125f7 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -163,6 +163,10 @@
       std::unique_ptr<base::MessageLoop> main_message_loop,
       std::unique_ptr<blink::scheduler::RendererScheduler> renderer_scheduler);
   static RenderThreadImpl* current();
+  static mojom::RenderMessageFilter* current_render_message_filter();
+
+  static void SetRenderMessageFilterForTesting(
+      mojom::RenderMessageFilter* render_message_filter);
 
   ~RenderThreadImpl() override;
   void Shutdown() override;
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index c31ba7c..3855443 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -52,6 +52,7 @@
 #include "content/common/frame_replication_state.h"
 #include "content/common/input_messages.h"
 #include "content/common/page_messages.h"
+#include "content/common/render_message_filter.mojom.h"
 #include "content/common/site_isolation_policy.h"
 #include "content/common/view_messages.h"
 #include "content/public/common/bindings_policy.h"
@@ -1503,18 +1504,18 @@
                                     const WebString& frame_name,
                                     WebNavigationPolicy policy,
                                     bool suppress_opener) {
-  ViewHostMsg_CreateWindow_Params params;
-  params.opener_id = GetRoutingID();
-  params.user_gesture = WebUserGestureIndicator::isProcessingUserGesture();
+  mojom::CreateNewWindowParamsPtr params = mojom::CreateNewWindowParams::New();
+  params->opener_id = GetRoutingID();
+  params->user_gesture = WebUserGestureIndicator::isProcessingUserGesture();
   if (GetContentClient()->renderer()->AllowPopup())
-    params.user_gesture = true;
-  params.window_container_type = WindowFeaturesToContainerType(features);
-  params.session_storage_namespace_id = session_storage_namespace_id_;
+    params->user_gesture = true;
+  params->window_container_type = WindowFeaturesToContainerType(features);
+  params->session_storage_namespace_id = session_storage_namespace_id_;
   if (frame_name != "_blank")
-    params.frame_name = base::UTF16ToUTF8(base::StringPiece16(frame_name));
-  params.opener_render_frame_id =
+    params->frame_name = base::UTF16ToUTF8(base::StringPiece16(frame_name));
+  params->opener_render_frame_id =
       RenderFrameImpl::FromWebFrame(creator)->GetRoutingID();
-  params.opener_url = creator->document().url();
+  params->opener_url = creator->document().url();
 
   // The browser process uses the top frame's URL for a content settings check
   // to determine whether the popup is allowed.  If the top frame is remote,
@@ -1526,9 +1527,9 @@
   // path-based matching for file URLs from content settings.  See
   // https://crbug.com/466297.
   if (creator->top()->isWebLocalFrame()) {
-    params.opener_top_level_frame_url = creator->top()->document().url();
+    params->opener_top_level_frame_url = creator->top()->document().url();
   } else {
-    params.opener_top_level_frame_url =
+    params->opener_top_level_frame_url =
         blink::WebStringToGURL(creator->top()->getSecurityOrigin().toString());
   }
 
@@ -1536,22 +1537,26 @@
       creator->document().getSecurityOrigin().toString()));
   if (!security_url.is_valid())
     security_url = GURL();
-  params.opener_security_origin = security_url;
-  params.opener_suppressed = suppress_opener;
-  params.disposition = NavigationPolicyToDisposition(policy);
+  params->opener_security_origin = security_url;
+  params->opener_suppressed = suppress_opener;
+  params->disposition = NavigationPolicyToDisposition(policy);
   if (!request.isNull()) {
-    params.target_url = request.url();
-    params.referrer = GetReferrerFromRequest(creator, request);
+    params->target_url = request.url();
+    params->referrer = GetReferrerFromRequest(creator, request);
   }
-  params.features = features;
+  params->features = features;
 
-  for (size_t i = 0; i < features.additionalFeatures.size(); ++i)
-    params.additional_features.push_back(features.additionalFeatures[i]);
+  // We preserve this information before sending the message since |params| is
+  // moved on send.
+  bool is_background_tab =
+      params->disposition == WindowOpenDisposition::NEW_BACKGROUND_TAB;
+  bool opened_by_user_gesture = params->user_gesture;
 
-  ViewHostMsg_CreateWindow_Reply reply;
-  RenderThread::Get()->Send(new ViewHostMsg_CreateWindow(params, &reply));
-  if (reply.route_id == MSG_ROUTING_NONE)
-    return NULL;
+  mojom::CreateNewWindowReplyPtr reply;
+  RenderThreadImpl::current_render_message_filter()->CreateNewWindow(
+      std::move(params), &reply);
+  if (reply->route_id == MSG_ROUTING_NONE)
+    return nullptr;
 
   WebUserGestureIndicator::consumeUserGesture();
 
@@ -1578,16 +1583,15 @@
   view_params.window_was_created_with_opener = true;
   view_params.renderer_preferences = renderer_preferences_;
   view_params.web_preferences = webkit_preferences_;
-  view_params.view_id = reply.route_id;
-  view_params.main_frame_routing_id = reply.main_frame_route_id;
-  view_params.main_frame_widget_routing_id = reply.main_frame_widget_route_id;
+  view_params.view_id = reply->route_id;
+  view_params.main_frame_routing_id = reply->main_frame_route_id;
+  view_params.main_frame_widget_routing_id = reply->main_frame_widget_route_id;
   view_params.session_storage_namespace_id =
-      reply.cloned_session_storage_namespace_id;
+      reply->cloned_session_storage_namespace_id;
   view_params.swapped_out = false;
   // WebCore will take care of setting the correct name.
   view_params.replicated_frame_state = FrameReplicationState();
-  view_params.hidden =
-      (params.disposition == WindowOpenDisposition::NEW_BACKGROUND_TAB);
+  view_params.hidden = is_background_tab;
   view_params.never_visible = never_visible;
   view_params.next_page_id = 1;
   view_params.initial_size = initial_size;
@@ -1598,7 +1602,7 @@
 
   RenderViewImpl* view =
       RenderViewImpl::Create(compositor_deps_, view_params, true);
-  view->opened_by_user_gesture_ = params.user_gesture;
+  view->opened_by_user_gesture_ = opened_by_user_gesture;
 
   return view->webview();
 }
diff --git a/content/renderer/service_worker/embedded_worker_dispatcher.cc b/content/renderer/service_worker/embedded_worker_dispatcher.cc
index ec12c06d..bd49677 100644
--- a/content/renderer/service_worker/embedded_worker_dispatcher.cc
+++ b/content/renderer/service_worker/embedded_worker_dispatcher.cc
@@ -10,7 +10,6 @@
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "content/child/child_process.h"
-#include "content/child/scoped_child_process_reference.h"
 #include "content/child/thread_safe_sender.h"
 #include "content/child/worker_thread_registry.h"
 #include "content/common/devtools_messages.h"
@@ -27,23 +26,14 @@
 
 namespace content {
 
-// A thin wrapper of WebEmbeddedWorker which also adds and releases process
-// references automatically.
-class EmbeddedWorkerDispatcher::WorkerWrapper {
- public:
-  WorkerWrapper(blink::WebEmbeddedWorker* worker, int devtools_agent_route_id)
-      : worker_(worker),
-        dev_tools_agent_(
-            new EmbeddedWorkerDevToolsAgent(worker, devtools_agent_route_id)) {}
-  ~WorkerWrapper() {}
+EmbeddedWorkerDispatcher::WorkerWrapper::WorkerWrapper(
+    blink::WebEmbeddedWorker* worker,
+    int devtools_agent_route_id)
+    : worker_(worker),
+      dev_tools_agent_(
+          new EmbeddedWorkerDevToolsAgent(worker, devtools_agent_route_id)) {}
 
-  blink::WebEmbeddedWorker* worker() { return worker_.get(); }
-
- private:
-  ScopedChildProcessReference process_ref_;
-  std::unique_ptr<blink::WebEmbeddedWorker> worker_;
-  std::unique_ptr<EmbeddedWorkerDevToolsAgent> dev_tools_agent_;
-};
+EmbeddedWorkerDispatcher::WorkerWrapper::~WorkerWrapper() {}
 
 EmbeddedWorkerDispatcher::EmbeddedWorkerDispatcher() : weak_factory_(this) {}
 
@@ -79,35 +69,15 @@
 }
 
 void EmbeddedWorkerDispatcher::OnStartWorker(
-    const EmbeddedWorkerMsg_StartWorker_Params& params) {
+    const EmbeddedWorkerStartParams& params) {
   DCHECK(!workers_.Lookup(params.embedded_worker_id));
   TRACE_EVENT0("ServiceWorker", "EmbeddedWorkerDispatcher::OnStartWorker");
-  std::unique_ptr<WorkerWrapper> wrapper(new WorkerWrapper(
-      blink::WebEmbeddedWorker::create(
-          new ServiceWorkerContextClient(params.embedded_worker_id,
-                                         params.service_worker_version_id,
-                                         params.scope, params.script_url,
-                                         params.worker_devtools_agent_route_id),
-          NULL),
-      params.worker_devtools_agent_route_id));
-
-  blink::WebEmbeddedWorkerStartData start_data;
-  start_data.scriptURL = params.script_url;
-  start_data.userAgent = base::UTF8ToUTF16(GetContentClient()->GetUserAgent());
-  start_data.waitForDebuggerMode =
-      params.wait_for_debugger ?
-          blink::WebEmbeddedWorkerStartData::WaitForDebugger :
-          blink::WebEmbeddedWorkerStartData::DontWaitForDebugger;
-  start_data.v8CacheOptions = static_cast<blink::WebSettings::V8CacheOptions>(
-      params.settings.v8_cache_options);
-  start_data.dataSaverEnabled = params.settings.data_saver_enabled;
-  start_data.pauseAfterDownloadMode =
-      params.pause_after_download
-          ? blink::WebEmbeddedWorkerStartData::PauseAfterDownload
-          : blink::WebEmbeddedWorkerStartData::DontPauseAfterDownload;
-
-  wrapper->worker()->startWorkerContext(start_data);
-  workers_.AddWithID(wrapper.release(), params.embedded_worker_id);
+  std::unique_ptr<WorkerWrapper> wrapper = StartWorkerContext(
+      params, base::MakeUnique<ServiceWorkerContextClient>(
+                  params.embedded_worker_id, params.service_worker_version_id,
+                  params.scope, params.script_url,
+                  params.worker_devtools_agent_route_id));
+  RegisterWorker(params.embedded_worker_id, std::move(wrapper));
 }
 
 void EmbeddedWorkerDispatcher::OnStopWorker(int embedded_worker_id) {
@@ -163,4 +133,37 @@
       target_level, blink::WebString::fromUTF8(message)));
 }
 
+std::unique_ptr<EmbeddedWorkerDispatcher::WorkerWrapper>
+EmbeddedWorkerDispatcher::StartWorkerContext(
+    const EmbeddedWorkerStartParams& params,
+    std::unique_ptr<ServiceWorkerContextClient> context_client) {
+  std::unique_ptr<WorkerWrapper> wrapper(new WorkerWrapper(
+      blink::WebEmbeddedWorker::create(context_client.release(), nullptr),
+      params.worker_devtools_agent_route_id));
+
+  blink::WebEmbeddedWorkerStartData start_data;
+  start_data.scriptURL = params.script_url;
+  start_data.userAgent = base::UTF8ToUTF16(GetContentClient()->GetUserAgent());
+  start_data.waitForDebuggerMode =
+      params.wait_for_debugger
+          ? blink::WebEmbeddedWorkerStartData::WaitForDebugger
+          : blink::WebEmbeddedWorkerStartData::DontWaitForDebugger;
+  start_data.v8CacheOptions = static_cast<blink::WebSettings::V8CacheOptions>(
+      params.settings.v8_cache_options);
+  start_data.dataSaverEnabled = params.settings.data_saver_enabled;
+  start_data.pauseAfterDownloadMode =
+      params.pause_after_download
+          ? blink::WebEmbeddedWorkerStartData::PauseAfterDownload
+          : blink::WebEmbeddedWorkerStartData::DontPauseAfterDownload;
+
+  wrapper->worker()->startWorkerContext(start_data);
+  return wrapper;
+}
+
+void EmbeddedWorkerDispatcher::RegisterWorker(
+    int embedded_worker_id,
+    std::unique_ptr<WorkerWrapper> wrapper) {
+  workers_.AddWithID(wrapper.release(), embedded_worker_id);
+}
+
 }  // namespace content
diff --git a/content/renderer/service_worker/embedded_worker_dispatcher.h b/content/renderer/service_worker/embedded_worker_dispatcher.h
index e77086f7..9c706fa8 100644
--- a/content/renderer/service_worker/embedded_worker_dispatcher.h
+++ b/content/renderer/service_worker/embedded_worker_dispatcher.h
@@ -6,19 +6,30 @@
 #define CONTENT_RENDERER_SERVICE_WORKER_EMBEDDED_WORKER_DISPATCHER_H_
 
 #include <map>
+#include <memory>
 
 #include "base/id_map.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
+#include "content/child/scoped_child_process_reference.h"
 #include "content/public/common/console_message_level.h"
 #include "ipc/ipc_listener.h"
 
-struct EmbeddedWorkerMsg_StartWorker_Params;
 class GURL;
 
+namespace blink {
+
+class WebEmbeddedWorker;
+
+}  // namespace blink
+
 namespace content {
 
+class EmbeddedWorkerDevToolsAgent;
+class ServiceWorkerContextClient;
+struct EmbeddedWorkerStartParams;
+
 // A tiny dispatcher which handles embedded worker start/stop messages.
 class EmbeddedWorkerDispatcher : public IPC::Listener {
  public:
@@ -31,15 +42,37 @@
   void WorkerContextDestroyed(int embedded_worker_id);
 
  private:
-  class WorkerWrapper;
+  friend class EmbeddedWorkerInstanceClientImpl;
 
-  void OnStartWorker(const EmbeddedWorkerMsg_StartWorker_Params& params);
+  // A thin wrapper of WebEmbeddedWorker which also adds and releases process
+  // references automatically.
+  class WorkerWrapper {
+   public:
+    WorkerWrapper(blink::WebEmbeddedWorker* worker,
+                  int devtools_agent_route_id);
+    ~WorkerWrapper();
+
+    blink::WebEmbeddedWorker* worker() { return worker_.get(); }
+
+   private:
+    ScopedChildProcessReference process_ref_;
+    std::unique_ptr<blink::WebEmbeddedWorker> worker_;
+    std::unique_ptr<EmbeddedWorkerDevToolsAgent> dev_tools_agent_;
+  };
+
+  void OnStartWorker(const EmbeddedWorkerStartParams& params);
   void OnStopWorker(int embedded_worker_id);
   void OnResumeAfterDownload(int embedded_worker_id);
   void OnAddMessageToConsole(int embedded_worker_id,
                              ConsoleMessageLevel level,
                              const std::string& message);
 
+  std::unique_ptr<WorkerWrapper> StartWorkerContext(
+      const EmbeddedWorkerStartParams& params,
+      std::unique_ptr<ServiceWorkerContextClient> context_client);
+  void RegisterWorker(int embedded_worker_id,
+                      std::unique_ptr<WorkerWrapper> wrapper);
+
   IDMap<WorkerWrapper, IDMapOwnPointer> workers_;
   std::map<int /* embedded_worker_id */, base::TimeTicks> stop_worker_times_;
   base::WeakPtrFactory<EmbeddedWorkerDispatcher> weak_factory_;
diff --git a/content/renderer/service_worker/embedded_worker_instance_client_impl.cc b/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
new file mode 100644
index 0000000..1d045dd
--- /dev/null
+++ b/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
@@ -0,0 +1,62 @@
+// Copyright (c) 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.
+
+#include "content/renderer/service_worker/embedded_worker_instance_client_impl.h"
+
+#include <memory>
+
+#include "base/strings/utf_string_conversions.h"
+#include "content/child/scoped_child_process_reference.h"
+#include "content/common/service_worker/embedded_worker_messages.h"
+#include "content/public/common/content_client.h"
+#include "content/renderer/service_worker/embedded_worker_devtools_agent.h"
+#include "content/renderer/service_worker/service_worker_context_client.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "third_party/WebKit/public/web/WebEmbeddedWorker.h"
+#include "third_party/WebKit/public/web/WebEmbeddedWorkerStartData.h"
+
+namespace content {
+
+namespace {
+
+void OnError() {
+  // TODO(shimazu): Implement here
+  NOTIMPLEMENTED();
+}
+
+}  // namespace
+
+// static
+void EmbeddedWorkerInstanceClientImpl::Create(
+    EmbeddedWorkerDispatcher* dispatcher,
+    mojo::InterfaceRequest<mojom::EmbeddedWorkerInstanceClient> request) {
+  auto binding = mojo::MakeStrongBinding(
+      base::MakeUnique<EmbeddedWorkerInstanceClientImpl>(dispatcher),
+      std::move(request));
+  binding->set_connection_error_handler(base::Bind(&OnError));
+}
+
+void EmbeddedWorkerInstanceClientImpl::StartWorker(
+    const EmbeddedWorkerStartParams& params) {
+  TRACE_EVENT0("ServiceWorker",
+               "EmbeddedWorkerInstanceClientImpl::StartWorker");
+
+  std::unique_ptr<EmbeddedWorkerDispatcher::WorkerWrapper> wrapper =
+      dispatcher_->StartWorkerContext(
+          params,
+          base::MakeUnique<ServiceWorkerContextClient>(
+              params.embedded_worker_id, params.service_worker_version_id,
+              params.scope, params.script_url,
+              params.worker_devtools_agent_route_id));
+  wrapper_ = wrapper.get();
+  dispatcher_->RegisterWorker(params.embedded_worker_id, std::move(wrapper));
+}
+
+EmbeddedWorkerInstanceClientImpl::EmbeddedWorkerInstanceClientImpl(
+    EmbeddedWorkerDispatcher* dispatcher)
+    : dispatcher_(dispatcher) {}
+
+EmbeddedWorkerInstanceClientImpl::~EmbeddedWorkerInstanceClientImpl() {}
+
+}  // namespace content
diff --git a/content/renderer/service_worker/embedded_worker_instance_client_impl.h b/content/renderer/service_worker/embedded_worker_instance_client_impl.h
new file mode 100644
index 0000000..893ae1d
--- /dev/null
+++ b/content/renderer/service_worker/embedded_worker_instance_client_impl.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_SERVICE_WORKER_EMBEDDED_WORKER_INSTANCE_CLIENT_IMPL_H_
+#define CONTENT_RENDERER_SERVICE_WORKER_EMBEDDED_WORKER_INSTANCE_CLIENT_IMPL_H_
+
+#include "base/id_map.h"
+#include "content/common/service_worker/embedded_worker.mojom.h"
+#include "content/renderer/service_worker/embedded_worker_dispatcher.h"
+
+namespace content {
+
+class EmbeddedWorkerInstanceClientImpl
+    : public mojom::EmbeddedWorkerInstanceClient {
+ public:
+  static void Create(
+      EmbeddedWorkerDispatcher* dispatcher,
+      mojo::InterfaceRequest<mojom::EmbeddedWorkerInstanceClient> request);
+
+  explicit EmbeddedWorkerInstanceClientImpl(
+      EmbeddedWorkerDispatcher* dispatcher);
+  ~EmbeddedWorkerInstanceClientImpl() override;
+
+  // Implementation of mojo interface
+  void StartWorker(const EmbeddedWorkerStartParams& params) override;
+
+ private:
+  EmbeddedWorkerDispatcher* dispatcher_;
+
+  EmbeddedWorkerDispatcher::WorkerWrapper* wrapper_;
+
+  DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerInstanceClientImpl);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_SERVICE_WORKER_EMBEDDED_WORKER_INSTANCE_CLIENT_IMPL_H_
diff --git a/content/renderer/webgraphicscontext3d_provider_impl.cc b/content/renderer/webgraphicscontext3d_provider_impl.cc
index dac541f..dbdae197 100644
--- a/content/renderer/webgraphicscontext3d_provider_impl.cc
+++ b/content/renderer/webgraphicscontext3d_provider_impl.cc
@@ -6,7 +6,6 @@
 
 #include "content/common/gpu/client/context_provider_command_buffer.h"
 #include "gpu/command_buffer/client/context_support.h"
-#include "third_party/WebKit/public/platform/functional/WebFunction.h"
 
 namespace content {
 
@@ -38,13 +37,13 @@
 }
 
 void WebGraphicsContext3DProviderImpl::setLostContextCallback(
-    blink::WebClosure c) {
-  provider_->SetLostContextCallback(c.TakeBaseCallback());
+    const base::Closure& c) {
+  provider_->SetLostContextCallback(c);
 }
 
 void WebGraphicsContext3DProviderImpl::setErrorMessageCallback(
-    blink::WebFunction<void(const char*, int32_t)> c) {
-  provider_->ContextSupport()->SetErrorMessageCallback(c.TakeBaseCallback());
+    const base::Callback<void(const char*, int32_t)>& c) {
+  provider_->ContextSupport()->SetErrorMessageCallback(c);
 }
 
 }  // namespace content
diff --git a/content/renderer/webgraphicscontext3d_provider_impl.h b/content/renderer/webgraphicscontext3d_provider_impl.h
index 52ce2e5..5adc7ff 100644
--- a/content/renderer/webgraphicscontext3d_provider_impl.h
+++ b/content/renderer/webgraphicscontext3d_provider_impl.h
@@ -33,9 +33,9 @@
   GrContext* grContext() override;
   gpu::Capabilities getCapabilities() override;
   bool isSoftwareRendering() const override;
-  void setLostContextCallback(blink::WebClosure) override;
+  void setLostContextCallback(const base::Closure&) override;
   void setErrorMessageCallback(
-      blink::WebFunction<void(const char*, int32_t)>) override;
+      const base::Callback<void(const char*, int32_t)>&) override;
 
   ContextProviderCommandBuffer* context_provider() const {
     return provider_.get();
diff --git a/content/shell/android/java/src/org/chromium/content_shell/Shell.java b/content/shell/android/java/src/org/chromium/content_shell/Shell.java
index 2151dbd9..7cc7a726 100644
--- a/content/shell/android/java/src/org/chromium/content_shell/Shell.java
+++ b/content/shell/android/java/src/org/chromium/content_shell/Shell.java
@@ -4,6 +4,7 @@
 
 package org.chromium.content_shell;
 
+import android.app.Activity;
 import android.content.Context;
 import android.graphics.drawable.ClipDrawable;
 import android.text.TextUtils;
@@ -22,6 +23,8 @@
 
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
+import org.chromium.content.browser.ActivityContentVideoViewEmbedder;
+import org.chromium.content.browser.ContentVideoViewEmbedder;
 import org.chromium.content.browser.ContentView;
 import org.chromium.content.browser.ContentViewClient;
 import org.chromium.content.browser.ContentViewCore;
@@ -287,7 +290,7 @@
     @CalledByNative
     private void initFromNativeTabContents(WebContents webContents) {
         Context context = getContext();
-        mContentViewCore = new ContentViewCore(context);
+        mContentViewCore = new ContentViewCore(context, "");
         ContentView cv = ContentView.createContentView(context, mContentViewCore);
         mContentViewCore.initialize(ViewAndroidDelegate.createBasicDelegate(cv), cv,
                 webContents, mWindow);
@@ -306,6 +309,23 @@
         mContentViewRenderView.setCurrentContentViewCore(mContentViewCore);
     }
 
+    @CalledByNative
+    public ContentVideoViewEmbedder getContentVideoViewEmbedder() {
+        return new ActivityContentVideoViewEmbedder((Activity) getContext()) {
+            @Override
+            public void enterFullscreenVideo(View view, boolean isVideoLoaded) {
+                super.enterFullscreenVideo(view, isVideoLoaded);
+                mContentViewRenderView.setOverlayVideoMode(true);
+            }
+
+            @Override
+            public void exitFullscreenVideo() {
+                super.exitFullscreenVideo();
+                mContentViewRenderView.setOverlayVideoMode(false);
+            }
+        };
+    }
+
     /**
      * Enable/Disable navigation(Prev/Next) button if navigation is allowed/disallowed
      * in respective direction.
diff --git a/content/shell/android/java/src/org/chromium/content_shell/ShellManager.java b/content/shell/android/java/src/org/chromium/content_shell/ShellManager.java
index d41997f2..cfddd40 100644
--- a/content/shell/android/java/src/org/chromium/content_shell/ShellManager.java
+++ b/content/shell/android/java/src/org/chromium/content_shell/ShellManager.java
@@ -4,18 +4,14 @@
 
 package org.chromium.content_shell;
 
-import android.app.Activity;
 import android.content.Context;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
-import android.view.View;
 import android.widget.FrameLayout;
 
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
-import org.chromium.content.browser.ActivityContentVideoViewEmbedder;
-import org.chromium.content.browser.ContentVideoViewEmbedder;
 import org.chromium.content.browser.ContentViewClient;
 import org.chromium.content.browser.ContentViewCore;
 import org.chromium.content.browser.ContentViewRenderView;
@@ -35,7 +31,7 @@
 
     // The target for all content rendering.
     private ContentViewRenderView mContentViewRenderView;
-    private ContentViewClient mContentViewClient;
+    private final ContentViewClient mContentViewClient = new ContentViewClient();
 
     /**
      * Constructor for inflating via XML.
@@ -43,24 +39,6 @@
     public ShellManager(final Context context, AttributeSet attrs) {
         super(context, attrs);
         nativeInit(this);
-        mContentViewClient = new ContentViewClient() {
-            @Override
-            public ContentVideoViewEmbedder getContentVideoViewEmbedder() {
-                return new ActivityContentVideoViewEmbedder((Activity) context) {
-                    @Override
-                    public void enterFullscreenVideo(View view, boolean isVideoLoaded) {
-                        super.enterFullscreenVideo(view, isVideoLoaded);
-                        setOverlayVideoMode(true);
-                    }
-
-                    @Override
-                    public void exitFullscreenVideo() {
-                        super.exitFullscreenVideo();
-                        setOverlayVideoMode(false);
-                    }
-                };
-            }
-        };
     }
 
     /**
diff --git a/content/shell/browser/layout_test/layout_test_browser_main.cc b/content/shell/browser/layout_test/layout_test_browser_main.cc
index 543d64fc..7ed7ea72 100644
--- a/content/shell/browser/layout_test/layout_test_browser_main.cc
+++ b/content/shell/browser/layout_test/layout_test_browser_main.cc
@@ -146,6 +146,7 @@
   exit_code = RunTests(main_runner);
   base::RunLoop().RunUntilIdle();
 
+  content::Shell::CloseAllWindows();
 #if !defined(OS_ANDROID)
   main_runner->Shutdown();
 #endif
diff --git a/content/shell/browser/shell.h b/content/shell/browser/shell.h
index bbf44ca..708b3d57 100644
--- a/content/shell/browser/shell.h
+++ b/content/shell/browser/shell.h
@@ -128,6 +128,8 @@
                            bool to_different_document) override;
 #if defined(OS_ANDROID)
   void LoadProgressChanged(WebContents* source, double progress) override;
+  base::android::ScopedJavaLocalRef<jobject>
+      GetContentVideoViewEmbedder() override;
 #endif
   void EnterFullscreenModeForTab(WebContents* web_contents,
                                  const GURL& origin) override;
diff --git a/content/shell/browser/shell_android.cc b/content/shell/browser/shell_android.cc
index 720b7ee2..c38e902a 100644
--- a/content/shell/browser/shell_android.cc
+++ b/content/shell/browser/shell_android.cc
@@ -77,6 +77,11 @@
   Java_Shell_onLoadProgressChanged(env, java_object_, progress);
 }
 
+ScopedJavaLocalRef<jobject> Shell::GetContentVideoViewEmbedder() {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  return Java_Shell_getContentVideoViewEmbedder(env, java_object_);
+}
+
 void Shell::PlatformToggleFullscreenModeForTab(WebContents* web_contents,
                                                bool enter_fullscreen) {
   JNIEnv* env = AttachCurrentThread();
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 0adada2..abf85ca 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -151,7 +151,6 @@
     "mock_webblob_registry_impl.h",
     "mock_webclipboard_impl.cc",
     "mock_webclipboard_impl.h",
-    "mock_webframeclient.h",
     "mock_weburlloader.cc",
     "mock_weburlloader.h",
     "net/url_request_abort_on_end_job.cc",
@@ -1005,6 +1004,7 @@
     "../browser/download/download_item_impl_unittest.cc",
     "../browser/download/download_manager_impl_unittest.cc",
     "../browser/download/quarantine_linux_unittest.cc",
+    "../browser/download/quarantine_mac_unittest.mm",
     "../browser/download/quarantine_win_unittest.cc",
     "../browser/download/rate_estimator_unittest.cc",
     "../browser/download/save_package_unittest.cc",
diff --git a/content/test/data/navigation_controller/beforeunload_dialog.html b/content/test/data/navigation_controller/beforeunload_dialog.html
new file mode 100644
index 0000000..8e3c825e
--- /dev/null
+++ b/content/test/data/navigation_controller/beforeunload_dialog.html
@@ -0,0 +1,13 @@
+<html>
+<head>
+<script>
+window.addEventListener("beforeunload", function (event) {
+  setTimeout(function() {
+    window.alert("hi");
+  }, 0);
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/content/test/gpu/gpu_tests/context_lost.py b/content/test/gpu/gpu_tests/context_lost.py
deleted file mode 100644
index 5d01009..0000000
--- a/content/test/gpu/gpu_tests/context_lost.py
+++ /dev/null
@@ -1,362 +0,0 @@
-# Copyright (c) 2013 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 os
-import time
-
-from gpu_tests import context_lost_expectations
-from gpu_tests import gpu_test_base
-from gpu_tests import path_util
-
-from telemetry.core import exceptions
-from telemetry.core import util
-from telemetry.page import page_test
-from telemetry.story import story_set as story_set_module
-
-data_path = os.path.join(
-    path_util.GetChromiumSrcDir(), 'content', 'test', 'data', 'gpu')
-
-wait_timeout = 60  # seconds
-
-harness_script = r"""
-  var domAutomationController = {};
-
-  domAutomationController._loaded = false;
-  domAutomationController._succeeded = false;
-  domAutomationController._finished = false;
-
-  domAutomationController.setAutomationId = function(id) {}
-
-  domAutomationController.send = function(msg) {
-    msg = msg.toLowerCase()
-    if (msg == "loaded") {
-      domAutomationController._loaded = true;
-    } else if (msg == "success") {
-      /* Don't squelch earlier failures! */
-      if (!domAutomationController._finished) {
-        domAutomationController._succeeded = true;
-      }
-      domAutomationController._finished = true;
-    } else {
-      /* Always record failures. */
-      domAutomationController._succeeded = false;
-      domAutomationController._finished = true;
-    }
-  }
-
-  domAutomationController.reset = function() {
-    domAutomationController._succeeded = false;
-    domAutomationController._finished = false;
-  }
-
-  window.domAutomationController = domAutomationController;
-  console.log("Harness injected.");
-"""
-
-class ContextLostValidator(gpu_test_base.ValidatorBase):
-  def __init__(self):
-    # Strictly speaking this test doesn't yet need a browser restart
-    # after each run, but if more tests are added which crash the GPU
-    # process, then it will.
-    super(ContextLostValidator, self).__init__(
-      needs_browser_restart_after_each_page=True)
-
-  def CustomizeBrowserOptions(self, options):
-    options.AppendExtraBrowserArgs(
-        '--disable-domain-blocking-for-3d-apis')
-    options.AppendExtraBrowserArgs(
-        '--disable-gpu-process-crash-limit')
-    # Required for about:gpucrash handling from Telemetry.
-    options.AppendExtraBrowserArgs('--enable-gpu-benchmarking')
-
-  def ValidateAndMeasurePage(self, page, tab, results):
-    def WaitForPageToFinish():
-      print "Waiting for page to finish."
-      try:
-        util.WaitFor(lambda: tab.EvaluateJavaScript(
-            'window.domAutomationController._finished'), wait_timeout)
-        return True
-      except exceptions.TimeoutException:
-        return False
-
-    if page.kill_gpu_process:
-      # Doing the GPU process kill operation cooperatively -- in the
-      # same page's context -- is much more stressful than restarting
-      # the browser every time.
-      for x in range(page.number_of_gpu_process_kills):
-        if not tab.browser.supports_tab_control:
-          raise page_test.Failure('Browser must support tab control')
-
-        expected_kills = x + 1
-
-        # Reset the test's state.
-        tab.EvaluateJavaScript(
-          'window.domAutomationController.reset()')
-
-        # If we're running the GPU process crash test, we need the
-        # test to have fully reset before crashing the GPU process.
-        if page.check_crash_count:
-          util.WaitFor(lambda: tab.EvaluateJavaScript(
-              'window.domAutomationController._finished'), wait_timeout)
-
-        # Crash the GPU process.
-        gpucrash_tab = tab.browser.tabs.New()
-        # To access these debug URLs from Telemetry, they have to be
-        # written using the chrome:// scheme.
-        # The try/except is a workaround for crbug.com/368107.
-        try:
-          gpucrash_tab.Navigate('chrome://gpucrash')
-        except Exception:
-          print 'Tab crashed while navigating to chrome://gpucrash'
-        # Activate the original tab and wait for completion.
-        tab.Activate()
-        completed = WaitForPageToFinish()
-
-        if page.check_crash_count:
-          if not tab.browser.supports_system_info:
-            raise page_test.Failure('Browser must support system info')
-
-          if not tab.EvaluateJavaScript(
-            'window.domAutomationController._succeeded'):
-            raise page_test.Failure(
-              'Test failed (didn\'t render content properly?)')
-
-          number_of_crashes = -1
-          # To allow time for a gpucrash to complete, wait up to 20s,
-          # polling repeatedly.
-          start_time = time.time()
-          current_time = time.time()
-          while current_time - start_time < 20:
-            system_info = tab.browser.GetSystemInfo()
-            number_of_crashes = \
-                system_info.gpu.aux_attributes[u'process_crash_count']
-            if number_of_crashes >= expected_kills:
-              break
-            time.sleep(1)
-            current_time = time.time()
-
-          # Wait 5 more seconds and re-read process_crash_count, in
-          # attempt to catch latent process crashes.
-          time.sleep(5)
-          system_info = tab.browser.GetSystemInfo()
-          number_of_crashes = \
-              system_info.gpu.aux_attributes[u'process_crash_count']
-
-          if number_of_crashes < expected_kills:
-            raise page_test.Failure(
-                'Timed out waiting for a gpu process crash')
-          elif number_of_crashes != expected_kills:
-            raise page_test.Failure(
-                'Expected %d gpu process crashes; got: %d' %
-                (expected_kills, number_of_crashes))
-
-        # The try/except is a workaround for crbug.com/368107.
-        try:
-          gpucrash_tab.Close()
-        except Exception:
-          print 'Tab crashed while closing chrome://gpucrash'
-        if not completed:
-          raise page_test.Failure(
-              'Test didn\'t complete (no context lost event?)')
-        if not tab.EvaluateJavaScript(
-          'window.domAutomationController._succeeded'):
-          raise page_test.Failure(
-            'Test failed (context not restored properly?)')
-    elif page.force_garbage_collection:
-      # Try to corce GC to clean up any contexts not attached to the page.
-      # This method seem unreliable, so the page will also attempt to force
-      # GC through excessive allocations.
-      tab.CollectGarbage()
-      completed = WaitForPageToFinish()
-
-      if not completed:
-        raise page_test.Failure(
-            'Test didn\'t complete (no context restored event?)')
-      if not tab.EvaluateJavaScript(
-        'window.domAutomationController._succeeded'):
-        raise page_test.Failure(
-          'Test failed (context not restored properly?)')
-    elif page.hide_tab_and_lose_context:
-      if not tab.browser.supports_tab_control:
-        raise page_test.Failure('Browser must support tab control')
-
-      # Test losing a context in a hidden tab. This test passes if the tab
-      # doesn't crash.
-      dummy_tab = tab.browser.tabs.New()
-      tab.EvaluateJavaScript('loseContextUsingExtension()')
-      tab.Activate()
-
-      completed = WaitForPageToFinish()
-
-      if not completed:
-        raise page_test.Failure('Test didn\'t complete')
-      if not tab.EvaluateJavaScript(
-        'window.domAutomationController._succeeded'):
-        raise page_test.Failure('Test failed')
-    else:
-      completed = WaitForPageToFinish()
-
-      if not completed:
-        raise page_test.Failure('Test didn\'t complete')
-      if not tab.EvaluateJavaScript(
-        'window.domAutomationController._succeeded'):
-        raise page_test.Failure('Test failed')
-
-# Test that navigating to chrome://gpucrash causes the GPU process to crash
-# exactly one time per navigation.
-class GPUProcessCrashesExactlyOnce(gpu_test_base.PageBase):
-  def __init__(self, story_set, base_dir, expectations):
-    super(GPUProcessCrashesExactlyOnce, self).__init__(
-      url='file://gpu_process_crash.html',
-      page_set=story_set,
-      base_dir=base_dir,
-      name='GpuCrash.GPUProcessCrashesExactlyOnce',
-      expectations=expectations)
-    self.script_to_evaluate_on_commit = harness_script
-    self.kill_gpu_process = True
-    self.number_of_gpu_process_kills = 2
-    self.check_crash_count = True
-    self.force_garbage_collection = False
-    self.hide_tab_and_lose_context = False
-
-  def RunNavigateSteps(self, action_runner):
-    super(GPUProcessCrashesExactlyOnce, self).RunNavigateSteps(
-      action_runner)
-    action_runner.WaitForJavaScriptCondition(
-        'window.domAutomationController._loaded')
-
-class WebGLContextLostFromGPUProcessExitPage(gpu_test_base.PageBase):
-  def __init__(self, story_set, base_dir, expectations):
-    super(WebGLContextLostFromGPUProcessExitPage, self).__init__(
-      url='file://webgl.html?query=kill_after_notification',
-      page_set=story_set,
-      base_dir=base_dir,
-      name='ContextLost.WebGLContextLostFromGPUProcessExit',
-      expectations=expectations)
-    self.script_to_evaluate_on_commit = harness_script
-    self.kill_gpu_process = True
-    self.check_crash_count = False
-    self.number_of_gpu_process_kills = 1
-    self.force_garbage_collection = False
-    self.hide_tab_and_lose_context = False
-
-  def RunNavigateSteps(self, action_runner):
-    super(WebGLContextLostFromGPUProcessExitPage, self).RunNavigateSteps(
-      action_runner)
-    action_runner.WaitForJavaScriptCondition(
-        'window.domAutomationController._loaded')
-
-
-class WebGLContextLostFromLoseContextExtensionPage(gpu_test_base.PageBase):
-  def __init__(self, story_set, base_dir, expectations):
-    super(WebGLContextLostFromLoseContextExtensionPage, self).__init__(
-      url='file://webgl.html?query=WEBGL_lose_context',
-      page_set=story_set,
-      base_dir=base_dir,
-      name='ContextLost.WebGLContextLostFromLoseContextExtension',
-      expectations=expectations)
-    self.script_to_evaluate_on_commit = harness_script
-    self.kill_gpu_process = False
-    self.check_crash_count = False
-    self.force_garbage_collection = False
-    self.hide_tab_and_lose_context = False
-
-  def RunNavigateSteps(self, action_runner):
-    super(WebGLContextLostFromLoseContextExtensionPage, self).RunNavigateSteps(
-      action_runner)
-    action_runner.WaitForJavaScriptCondition(
-        'window.domAutomationController._finished')
-
-
-class WebGLContextLostInHiddenTabPage(gpu_test_base.PageBase):
-  def __init__(self, story_set, base_dir, expectations):
-    super(WebGLContextLostInHiddenTabPage, self).__init__(
-      url='file://webgl.html?query=kill_after_notification',
-      page_set=story_set,
-      base_dir=base_dir,
-      name='ContextLost.WebGLContextLostInHiddenTab',
-      expectations=expectations)
-    self.script_to_evaluate_on_commit = harness_script
-    self.kill_gpu_process = False
-    self.check_crash_count = False
-    self.force_garbage_collection = False
-    self.hide_tab_and_lose_context = True
-
-  def RunNavigateSteps(self, action_runner):
-    super(WebGLContextLostInHiddenTabPage, self).RunNavigateSteps(
-      action_runner)
-    action_runner.WaitForJavaScriptCondition(
-        'window.domAutomationController._loaded')
-
-
-class WebGLContextLostFromQuantityPage(gpu_test_base.PageBase):
-  def __init__(self, story_set, base_dir, expectations):
-    super(WebGLContextLostFromQuantityPage, self).__init__(
-      url='file://webgl.html?query=forced_quantity_loss',
-      page_set=story_set,
-      base_dir=base_dir,
-      name='ContextLost.WebGLContextLostFromQuantity',
-      expectations=expectations)
-    self.script_to_evaluate_on_commit = harness_script
-    self.kill_gpu_process = False
-    self.check_crash_count = False
-    self.force_garbage_collection = True
-    self.hide_tab_and_lose_context = False
-
-  def RunNavigateSteps(self, action_runner):
-    super(WebGLContextLostFromQuantityPage, self).RunNavigateSteps(
-      action_runner)
-    action_runner.WaitForJavaScriptCondition(
-        'window.domAutomationController._loaded')
-
-class WebGLContextLostFromSelectElementPage(gpu_test_base.PageBase):
-  def __init__(self, story_set, base_dir, expectations):
-    super(WebGLContextLostFromSelectElementPage, self).__init__(
-      url='file://webgl_with_select_element.html',
-      page_set=story_set,
-      base_dir=base_dir,
-      name='ContextLost.WebGLContextLostFromSelectElement',
-      expectations=expectations)
-    self.script_to_evaluate_on_commit = harness_script
-    self.kill_gpu_process = False
-    self.check_crash_count = False
-    self.force_garbage_collection = False
-    self.hide_tab_and_lose_context = False
-
-  def RunNavigateSteps(self, action_runner):
-    super(WebGLContextLostFromSelectElementPage, self).RunNavigateSteps(
-      action_runner)
-    action_runner.WaitForJavaScriptCondition(
-        'window.domAutomationController._loaded')
-
-class ContextLost(gpu_test_base.TestBase):
-  enabled = True
-  test = ContextLostValidator
-
-  @classmethod
-  def Name(cls):
-    return 'context_lost'
-
-  def _CreateExpectations(self):
-    return context_lost_expectations.ContextLostExpectations()
-
-  # For the record, this would have been another way to get the pages
-  # to repeat. pageset_repeat would be another option.
-  # options = {'page_repeat': 5}
-  def CreateStorySet(self, options):
-    ps = story_set_module.StorySet(
-      base_dir=data_path,
-      serving_dirs=set(['']))
-    ps.AddStory(GPUProcessCrashesExactlyOnce(
-        ps, ps.base_dir, self.GetExpectations()))
-    ps.AddStory(WebGLContextLostFromGPUProcessExitPage(
-        ps, ps.base_dir, self.GetExpectations()))
-    ps.AddStory(WebGLContextLostFromLoseContextExtensionPage(
-        ps, ps.base_dir, self.GetExpectations()))
-    ps.AddStory(WebGLContextLostFromQuantityPage(
-        ps, ps.base_dir, self.GetExpectations()))
-    ps.AddStory(WebGLContextLostFromSelectElementPage(
-        ps, ps.base_dir, self.GetExpectations()))
-    ps.AddStory(WebGLContextLostInHiddenTabPage(
-        ps, ps.base_dir, self.GetExpectations()))
-    return ps
diff --git a/content/test/gpu/gpu_tests/gpu_integration_test.py b/content/test/gpu/gpu_tests/gpu_integration_test.py
index 4ad6af2..75df3cb 100644
--- a/content/test/gpu/gpu_tests/gpu_integration_test.py
+++ b/content/test/gpu/gpu_tests/gpu_integration_test.py
@@ -68,6 +68,12 @@
       # aborts the control flow here.
       self.skipTest('SKIPPING TEST due to test expectations')
     try:
+      # TODO(nednguyen): For some reason the arguments are getting wrapped
+      # in another tuple sometimes (like in the WebGL extension tests).
+      # Perhaps only if multiple arguments are yielded in the test
+      # generator?
+      if len(args) == 1 and isinstance(args[0], tuple):
+        args = args[0]
       self.RunActualGpuTest(url, *args)
     except Exception:
       if expectation == 'pass':
diff --git a/content/test/gpu/gpu_tests/gpu_test_expectations.py b/content/test/gpu/gpu_tests/gpu_test_expectations.py
index 0ada4a6..dd4a2385 100644
--- a/content/test/gpu/gpu_tests/gpu_test_expectations.py
+++ b/content/test/gpu/gpu_tests/gpu_test_expectations.py
@@ -58,6 +58,9 @@
 
 
 class GpuTestExpectations(test_expectations.TestExpectations):
+  def __init__(self, url_prefixes=None):
+    super(GpuTestExpectations, self).__init__(url_prefixes=url_prefixes)
+
   def CreateExpectation(self, expectation, pattern, conditions=None,
                         bug=None):
     return GpuExpectation(expectation, pattern, conditions, bug)
diff --git a/content/test/gpu/gpu_tests/test_expectations.py b/content/test/gpu/gpu_tests/test_expectations.py
index 695d99f2..7e9d2c5a 100644
--- a/content/test/gpu/gpu_tests/test_expectations.py
+++ b/content/test/gpu/gpu_tests/test_expectations.py
@@ -36,14 +36,21 @@
   Supports conditions based on operating system (e.g., win, mac) and
   browser type (e.g. 'debug', 'release').
 
+  The pattern, if a URL, *must* be a relative URL. Absolute URLs
+  (e.g. starting with a scheme like http://, https://, file://) are
+  not allowed. A ValueError is raised if one is passed to __init__.
+
   Subclass this class and call super.__init__ last in your constructor
   in order to add new user-defined conditions. The conditions are
   parsed at the end of this class's constructor, so be careful not to
   overwrite the results of the constructor call!
+
   """
 
   def __init__(self, expectation, pattern, conditions=None, bug=None):
     self.expectation = expectation.lower()
+    if pattern.find('://') > 0:
+      raise ValueError('Absolute URLs are not allowed in patterns')
     self.pattern = pattern
     self.bug = bug
 
@@ -89,12 +96,16 @@
 class TestExpectations(object):
   """A class which defines the expectations for a page set test execution"""
 
-  def __init__(self):
+  def __init__(self, url_prefixes=None):
     self._expectations = []
+    self._url_prefixes = []
     self._skip_matching_names = False
     self._built_expectation_cache = True
     self._ClearExpectationsCache()
     self.SetExpectations()
+    if url_prefixes:
+      for p in url_prefixes:
+        self._url_prefixes.append(p)
 
   def SetExpectations(self):
     """Called on creation. Override to set up custom expectations."""
@@ -160,8 +171,9 @@
       return url
     return url.replace('\\', '/')
 
-  def _GetURLPath(self, url):
-    components = urlparse.urlsplit(url)
+  def _GetURLPath(self, url, browser):
+    normalized_url = self._GetNormalizedURL(url, browser)
+    components = urlparse.urlsplit(normalized_url)
     # For compatibility, the file:// scheme must be treated specially.
     # The top-level directory shows up in the netloc portion of the URL.
     if components[0] == 'file':
@@ -177,6 +189,13 @@
     query_index = url_path.find('?')
     if query_index > 0:
       url_path = url_path[0:query_index]
+    # Look for the URL prefixes specified at construction time, and
+    # trim the first one found, if any.
+    if self._url_prefixes:
+      for p in self._url_prefixes:
+        if url_path.startswith(p):
+          url_path = url_path[len(p):]
+          break
     return url_path
 
   def _GetExpectationObjectForPage(self, browser, page):
@@ -185,15 +204,11 @@
     # First attempt to look up by the page's URL or name.
     e = None
     # Relative URL (common case).
-    url = self._GetNormalizedURL(page.url, browser)
-    url_path = self._GetURLPath(url)
+    url_path = self._GetURLPath(page.url, browser)
     if url_path:
       e = self._expectations_by_pattern.get(url_path)
     if e:
       return e
-    e = self._expectations_by_pattern.get(url)
-    if e:
-      return e
     if page.name:
       e = self._expectations_by_pattern.get(page.name)
     if e:
@@ -242,15 +257,12 @@
     # everything except the page's name or URL.
     if not self._skip_matching_names:
       # Relative URL.
-      if not fnmatch.fnmatch(self._GetURLPath(page.url),
+      if not fnmatch.fnmatch(self._GetURLPath(page.url, browser),
                              expectation.pattern):
-        # Absolute URL.
-        if not fnmatch.fnmatch(page.url,
-                               expectation.pattern):
-          # Name.
-          if not (page.name and fnmatch.fnmatch(page.name,
-                                                expectation.pattern)):
-            return False
+        # Name.
+        if not (page.name and fnmatch.fnmatch(page.name,
+                                              expectation.pattern)):
+          return False
 
     platform = browser.platform
     os_matches = (not expectation.os_conditions or
diff --git a/content/test/gpu/gpu_tests/test_expectations_unittest.py b/content/test/gpu/gpu_tests/test_expectations_unittest.py
index ad5acda..c81f0d6 100644
--- a/content/test/gpu/gpu_tests/test_expectations_unittest.py
+++ b/content/test/gpu/gpu_tests/test_expectations_unittest.py
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 import unittest
 
+from gpu_tests import gpu_integration_test
 from gpu_tests import test_expectations
 
 from telemetry.page import page as page_module
@@ -57,7 +58,6 @@
     self.Fail('page2.html', ['vista'], bug=123)
     self.Fail('page3.html', bug=123)
     self.Fail('page4.*', bug=123)
-    self.Fail('http://test.com/page5.html', bug=123)
     self.Fail('Pages.page_6')
     self.Fail('page7.html', ['mountainlion'])
     self.Fail('page8.html', ['mavericks'])
@@ -86,9 +86,20 @@
       return True
     return expectation.valid_condition_matched
 
+class FailingAbsoluteTestExpectations(test_expectations.TestExpectations):
+  def CreateExpectation(self, expectation, url_pattern, conditions=None,
+                        bug=None):
+    return SampleExpectationSubclass(expectation, url_pattern,
+                                     conditions=conditions, bug=bug)
+
+  def SetExpectations(self):
+    self.Fail('http://test.com/page5.html', bug=123)
+
 class TestExpectationsTest(unittest.TestCase):
   def setUp(self):
-    self.expectations = SampleTestExpectations()
+    self.expectations = SampleTestExpectations(url_prefixes=[
+      'third_party/webgl/src/sdk/tests/',
+      'content/test/data/gpu'])
 
   def assertExpectationEquals(self, expected, page, platform=StubPlatform(''),
                               browser_type=None):
@@ -137,15 +148,10 @@
     self.assertExpectationEquals('fail', page, StubPlatform('win'))
     self.assertExpectationEquals('fail', page_js, StubPlatform('win'))
 
-  # Expectations with absolute paths should match the entire path
-  def testAbsoluteExpectations(self):
-    ps = story_set.StorySet()
-    page = page_module.Page('http://test.com/page5.html', ps)
-    page_org = page_module.Page('http://test.org/page5.html', ps)
-    page_https = page_module.Page('https://test.com/page5.html', ps)
-    self.assertExpectationEquals('fail', page, StubPlatform('win'))
-    self.assertExpectationEquals('pass', page_org, StubPlatform('win'))
-    self.assertExpectationEquals('pass', page_https, StubPlatform('win'))
+  # Absolute URLs in expectations are no longer allowed.
+  def testAbsoluteExpectationsAreForbidden(self):
+    with self.assertRaises(ValueError):
+      FailingAbsoluteTestExpectations()
 
   # Expectations can be set against page names as well as urls
   def testPageNameExpectations(self):
@@ -225,3 +231,30 @@
     page = page_module.Page(
       'file://conformance/glsl/page15.html?webglVersion=2', ps)
     self.assertExpectationEquals('skip', page)
+
+  def testURLPrefixesAreStripped(self):
+    # This test uses the "_EmulatedPage" class from the GPU integration tests
+    # because it's in that context where support for URL prefixes was added.
+    self.assertExpectationEquals(
+      'skip',
+      gpu_integration_test._EmulatedPage(
+        'third_party/webgl/src/sdk/tests/conformance/glsl/page15.html',
+        'Page15'))
+    self.assertExpectationEquals(
+      'fail',
+      gpu_integration_test._EmulatedPage(
+        'third_party/webgl/src/sdk/tests/conformance/glsl/foo.html',
+        'Foo'))
+    # Test exact and wildcard matches on Windows.
+    self.assertExpectationEquals(
+      'skip',
+      gpu_integration_test._EmulatedPage(
+        'third_party\\webgl\\src\\sdk\\tests\\conformance\\glsl\\page15.html',
+        'Page15'),
+      StubPlatform('win'))
+    self.assertExpectationEquals(
+      'fail',
+      gpu_integration_test._EmulatedPage(
+        'third_party\\webgl\\src\\sdk\\tests\\conformance\\glsl\\foo.html',
+        'Foo'),
+      StubPlatform('win'))
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
index dbf43ef..a5bee6f2 100644
--- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -6,8 +6,9 @@
 # See the GpuTestExpectations class for documentation.
 
 class WebGL2ConformanceExpectations(WebGLConformanceExpectations):
-  def __init__(self, conformance_path):
-    super(WebGL2ConformanceExpectations, self).__init__(conformance_path)
+  def __init__(self, conformance_path, url_prefixes=None):
+    super(WebGL2ConformanceExpectations, self).__init__(
+      conformance_path, url_prefixes=url_prefixes)
 
   def SetExpectations(self):
     # ===================================
@@ -16,13 +17,20 @@
     # It's expected that not all extensions will be available on all platforms.
     # Having a test listed here is not necessarily a problem.
 
-    self.Fail('WebglExtension.WEBGL_compressed_texture_astc',
+    # Skip these, rather than expect them to fail, to speed up test
+    # execution. The browser is restarted even after expected test
+    # failures.
+    self.Skip('WebglExtension_WEBGL_compressed_texture_astc',
         ['win', 'mac', 'linux'])
-    self.Fail('WebglExtension.WEBGL_compressed_texture_atc',
+    self.Skip('WebglExtension_WEBGL_compressed_texture_atc',
         ['win', 'mac', 'linux'])
-    self.Fail('WebglExtension.WEBGL_compressed_texture_etc1',
+    self.Skip('WebglExtension_WEBGL_compressed_texture_es3_0',
+        ['linux', 'mac'])
+    self.Skip('WebglExtension_WEBGL_compressed_texture_etc1',
         ['mac', 'linux'])
-    self.Fail('WebglExtension.WEBGL_compressed_texture_pvrtc',
+    self.Skip('WebglExtension_WEBGL_compressed_texture_pvrtc',
+        ['win', 'mac', 'linux'])
+    self.Skip('WebglExtension_WEBGL_compressed_texture_s3tc_srgb',
         ['win', 'mac', 'linux'])
 
     # ========================
@@ -511,7 +519,7 @@
                'tex-2d-rgb-rgb-unsigned_short_5_6_5.html',
                ['linux'], bug=627525)
 
-    # Multi-vendor failures.
+    # Linux Multi-vendor failures.
 
     self.Fail('deqp/data/gles3/shaders/functions.html',
         ['linux', 'amd', 'intel'], bug=483282)
@@ -525,12 +533,6 @@
     self.Fail('deqp/data/gles3/shaders/linkage.html',
         ['linux', 'amd', 'intel'], bug=483282)
 
-    # Linux with ANGLE only
-    self.Fail('conformance2/textures/misc/tex-unpack-params.html',
-        ['linux', 'opengl'], bug=483282)
-    self.Fail('conformance2/reading/read-pixels-pack-parameters.html',
-        ['linux', 'opengl'], bug=483282)
-
     # Linux without ANGLE only
     self.Flaky('conformance2/buffers/getBufferSubData.html',
                ['linux', 'no_angle'], bug=650123)
diff --git a/content/test/gpu/gpu_tests/webgl_conformance.py b/content/test/gpu/gpu_tests/webgl_conformance.py
deleted file mode 100644
index 73af5df..0000000
--- a/content/test/gpu/gpu_tests/webgl_conformance.py
+++ /dev/null
@@ -1,368 +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.
-import os
-
-from gpu_tests import gpu_test_base
-from gpu_tests import path_util
-from gpu_tests import webgl_conformance_expectations
-from gpu_tests import webgl2_conformance_expectations
-
-from telemetry.internal.browser import browser_finder
-from telemetry.page import page_test
-from telemetry.story.story_set import StorySet
-
-extensions_path = os.path.join(
-    path_util.GetChromiumSrcDir(),
-    'content', 'test', 'data', 'gpu')
-conformance_path = os.path.join(
-    path_util.GetChromiumSrcDir(),
-    'third_party', 'webgl', 'src', 'sdk', 'tests')
-
-conformance_harness_script = r"""
-  var testHarness = {};
-  testHarness._allTestSucceeded = true;
-  testHarness._messages = '';
-  testHarness._failures = 0;
-  testHarness._finished = false;
-  testHarness._originalLog = window.console.log;
-
-  testHarness.log = function(msg) {
-    testHarness._messages += msg + "\n";
-    testHarness._originalLog.apply(window.console, [msg]);
-  }
-
-  testHarness.reportResults = function(url, success, msg) {
-    testHarness._allTestSucceeded = testHarness._allTestSucceeded && !!success;
-    if(!success) {
-      testHarness._failures++;
-      if(msg) {
-        testHarness.log(msg);
-      }
-    }
-  };
-  testHarness.notifyFinished = function(url) {
-    testHarness._finished = true;
-  };
-  testHarness.navigateToPage = function(src) {
-    var testFrame = document.getElementById("test-frame");
-    testFrame.src = src;
-  };
-
-  window.webglTestHarness = testHarness;
-  window.parent.webglTestHarness = testHarness;
-  window.console.log = testHarness.log;
-  window.onerror = function(message, url, line) {
-    testHarness.reportResults(null, false, message);
-    testHarness.notifyFinished(null);
-  };
-  window.quietMode = function() { return true; }
-"""
-
-def _DidWebGLTestSucceed(tab):
-  return tab.EvaluateJavaScript('webglTestHarness._allTestSucceeded')
-
-def _WebGLTestMessages(tab):
-  return tab.EvaluateJavaScript('webglTestHarness._messages')
-
-def _CompareVersion(version1, version2):
-  ver_num1 = [int(x) for x in version1.split('.')]
-  ver_num2 = [int(x) for x in version2.split('.')]
-  size = min(len(ver_num1), len(ver_num2))
-  return cmp(ver_num1[0:size], ver_num2[0:size])
-
-
-def GenerateTestNameFromTestPath(test_path):
-  return  ('WebglConformance.%s' %
-           test_path.replace('/', '_').replace('-', '_').
-           replace('\\', '_').rpartition('.')[0].replace('.', '_'))
-
-
-class WebglConformanceValidator(gpu_test_base.ValidatorBase):
-  def __init__(self):
-    super(WebglConformanceValidator, self).__init__()
-
-  def ValidateAndMeasurePage(self, page, tab, results):
-    if not _DidWebGLTestSucceed(tab):
-      messages = _WebGLTestMessages(tab)
-      is_valid_dump = False
-      # Problems have been seen attempting to get stack traces on
-      # Android via this API; see crbug.com/609252. Skip this logic
-      # there for the time being.
-      if tab.browser.platform.GetOSName() != 'android':
-        is_valid_dump, trace_output = tab.browser.GetStackTrace()
-      if is_valid_dump:
-        messages += '\nStack Trace:\n' + trace_output
-      raise page_test.Failure(messages)
-
-  def CustomizeBrowserOptions(self, options):
-    # --test-type=gpu is used only to suppress the "Google API Keys are missing"
-    # infobar, which causes flakiness in tests.
-    options.AppendExtraBrowserArgs([
-        '--disable-gesture-requirement-for-media-playback',
-        '--disable-domain-blocking-for-3d-apis',
-        '--disable-gpu-process-crash-limit',
-        '--js-flags=--expose-gc',
-        '--test-type=gpu',
-        '--enable-experimental-canvas-features'
-    ])
-    browser = browser_finder.FindBrowser(options.finder_options)
-    if (browser.target_os.startswith('android') and
-      browser.browser_type == 'android-webview-shell'):
-      # TODO(kbr): this is overly broad. We'd like to do this only on
-      # Nexus 9. It'll go away shortly anyway. crbug.com/499928
-      #
-      # The --ignore_egl_sync_failures is only there to work around
-      # some strange failure on the Nexus 9 bot, not reproducible on
-      # local hardware.
-      options.AppendExtraBrowserArgs([
-        '--disable-gl-extensions=GL_EXT_disjoint_timer_query',
-        '--ignore_egl_sync_failures',
-      ])
-
-
-class Webgl2ConformanceValidator(WebglConformanceValidator):
-  def __init__(self):
-    super(Webgl2ConformanceValidator, self).__init__()
-
-  def CustomizeBrowserOptions(self, options):
-    # --test-type=gpu is used only to suppress the "Google API Keys are missing"
-    # infobar, which causes flakiness in tests.
-    options.AppendExtraBrowserArgs([
-        '--disable-gesture-requirement-for-media-playback',
-        '--disable-domain-blocking-for-3d-apis',
-        '--disable-gpu-process-crash-limit',
-        '--js-flags=--expose-gc',
-        '--enable-unsafe-es3-apis',
-        '--test-type=gpu',
-        '--enable-experimental-canvas-features'
-    ])
-    browser = browser_finder.FindBrowser(options.finder_options)
-    if browser.target_os == 'darwin':
-      # crbug.com/539993
-      options.AppendExtraBrowserArgs([
-          '--disable-accelerated-video-decode'
-      ])
-
-class WebglExtensionPage(gpu_test_base.PageBase):
-  def __init__(self, story_set, extension, webgl_version, expectations):
-    super(WebglExtensionPage, self).__init__(
-      url='file://' + extensions_path + '/webgl_extension_test.html',
-      page_set=story_set, base_dir=extensions_path,
-      shared_page_state_class=gpu_test_base.DesktopGpuSharedPageState,
-      name=('WebglExtension.%s' % extension),
-      expectations=expectations)
-    self.extension = extension
-    self.context_type = "webgl2" if webgl_version == 2 else "webgl"
-    self.script_to_evaluate_on_commit = conformance_harness_script
-
-  def RunNavigateSteps(self, action_runner):
-    super(WebglExtensionPage, self).RunNavigateSteps(action_runner)
-    action_runner.EvaluateJavaScript('checkExtension("%s", "%s")' %
-        (self.extension, self.context_type))
-    action_runner.WaitForJavaScriptCondition(
-        'webglTestHarness._finished', timeout_in_seconds=3)
-
-class WebglExtensionListPage(gpu_test_base.PageBase):
-  def __init__(self, story_set, extension_list, webgl_version, expectations):
-    super(WebglExtensionListPage, self).__init__(
-      url='file://' + extensions_path + '/webgl_extension_test.html',
-      page_set=story_set, base_dir=extensions_path,
-      shared_page_state_class=gpu_test_base.DesktopGpuSharedPageState,
-      name=('WebglExtension.TestCoverage'),
-      expectations=expectations)
-    self.extension_list = extension_list
-    self.context_type = "webgl2" if webgl_version == 2 else "webgl"
-    self.script_to_evaluate_on_commit = conformance_harness_script
-
-  def RunNavigateSteps(self, action_runner):
-    super(WebglExtensionListPage, self).RunNavigateSteps(action_runner)
-    extension_list_string = "["
-    for extension in self.extension_list:
-      extension_list_string = extension_list_string + extension + ", "
-    extension_list_string = extension_list_string + "]"
-    action_runner.EvaluateJavaScript('checkSupportedExtensions("%s", "%s")' %
-        (extension_list_string, self.context_type))
-    action_runner.WaitForJavaScriptCondition(
-        'webglTestHarness._finished', timeout_in_seconds=3)
-
-class WebglConformancePage(gpu_test_base.PageBase):
-  def __init__(self, story_set, test, expectations):
-    super(WebglConformancePage, self).__init__(
-      url='file://' + test, page_set=story_set, base_dir=story_set.base_dir,
-      shared_page_state_class=gpu_test_base.DesktopGpuSharedPageState,
-      name=(GenerateTestNameFromTestPath(test)),
-      expectations=expectations)
-    self.script_to_evaluate_on_commit = conformance_harness_script
-
-  def RunNavigateSteps(self, action_runner):
-    super(WebglConformancePage, self).RunNavigateSteps(action_runner)
-    action_runner.WaitForJavaScriptCondition(
-        'webglTestHarness._finished', timeout_in_seconds=300)
-
-class WebglConformance(gpu_test_base.TestBase):
-  """Conformance with Khronos WebGL Conformance Tests"""
-  def __init__(self):
-    super(WebglConformance, self).__init__(max_failures=10)
-    self._cached_expectations = None
-    self._webgl_version = 0
-
-  @classmethod
-  def Name(cls):
-    return 'webgl_conformance'
-
-  @classmethod
-  def AddBenchmarkCommandLineArgs(cls, group):
-    group.add_option('--webgl-conformance-version',
-        help='Version of the WebGL conformance tests to run.',
-        default='1.0.4')
-    group.add_option('--webgl2-only',
-        help='Whether we include webgl 1 tests if version is 2.0.0 or above.',
-        default='false')
-
-  def CreatePageTest(self, options):
-    if _CompareVersion(options.webgl_conformance_version, '2.0.0') >= 0:
-      return Webgl2ConformanceValidator()
-    return WebglConformanceValidator()
-
-  def CreateStorySet(self, options):
-    tests = self._ParseTests('00_test_list.txt',
-        options.webgl_conformance_version,
-        (options.webgl2_only == 'true'),
-        None)
-
-    self._webgl_version = [
-        int(x) for x in options.webgl_conformance_version.split('.')][0]
-
-    ps = StorySet(serving_dirs=[''], base_dir=conformance_path)
-
-    expectations = self.GetExpectations()
-
-    extension_tests = self.GetExtensionList()
-    ps.AddStory(WebglExtensionListPage(ps, extension_tests, self._webgl_version,
-          expectations))
-    for extension in extension_tests:
-      ps.AddStory(WebglExtensionPage(ps, extension, self._webgl_version,
-          expectations))
-
-    for test in tests:
-      ps.AddStory(WebglConformancePage(ps, test, expectations))
-
-    return ps
-
-  def _CreateExpectations(self):
-    assert self._webgl_version == 1 or self._webgl_version == 2
-    if self._webgl_version == 1:
-      return webgl_conformance_expectations.WebGLConformanceExpectations(
-          conformance_path)
-    else:
-      return webgl2_conformance_expectations.WebGL2ConformanceExpectations(
-          conformance_path)
-
-  def GetExtensionList(self):
-    if self._webgl_version == 1:
-      return [
-        'ANGLE_instanced_arrays',
-        'EXT_blend_minmax',
-        'EXT_disjoint_timer_query',
-        'EXT_frag_depth',
-        'EXT_shader_texture_lod',
-        'EXT_sRGB',
-        'EXT_texture_filter_anisotropic',
-        'OES_element_index_uint',
-        'OES_standard_derivatives',
-        'OES_texture_float',
-        'OES_texture_float_linear',
-        'OES_texture_half_float',
-        'OES_texture_half_float_linear',
-        'OES_vertex_array_object',
-        'WEBGL_compressed_texture_astc',
-        'WEBGL_compressed_texture_atc',
-        'WEBGL_compressed_texture_etc1',
-        'WEBGL_compressed_texture_pvrtc',
-        'WEBGL_compressed_texture_s3tc',
-        'WEBGL_debug_renderer_info',
-        'WEBGL_debug_shaders',
-        'WEBGL_depth_texture',
-        'WEBGL_draw_buffers',
-        'WEBGL_lose_context',
-      ]
-    else:
-      return [
-        'EXT_color_buffer_float',
-        'EXT_disjoint_timer_query',
-        'EXT_texture_filter_anisotropic',
-        'OES_texture_float_linear',
-        'WEBGL_compressed_texture_astc',
-        'WEBGL_compressed_texture_atc',
-        'WEBGL_compressed_texture_etc1',
-        'WEBGL_compressed_texture_pvrtc',
-        'WEBGL_compressed_texture_s3tc',
-        'WEBGL_debug_renderer_info',
-        'WEBGL_debug_shaders',
-        'WEBGL_lose_context',
-      ]
-
-  @staticmethod
-  def _ParseTests(path, version, webgl2_only, folder_min_version):
-    test_paths = []
-    current_dir = os.path.dirname(path)
-    full_path = os.path.normpath(os.path.join(conformance_path, path))
-    webgl_version = int(version.split('.')[0])
-
-    if not os.path.exists(full_path):
-      raise Exception('The WebGL conformance test path specified ' +
-        'does not exist: ' + full_path)
-
-    with open(full_path, 'r') as f:
-      for line in f:
-        line = line.strip()
-
-        if not line:
-          continue
-
-        if line.startswith('//') or line.startswith('#'):
-          continue
-
-        line_tokens = line.split(' ')
-        test_name = line_tokens[-1]
-
-        i = 0
-        min_version = None
-        max_version = None
-        while i < len(line_tokens):
-          token = line_tokens[i]
-          if token == '--min-version':
-            i += 1
-            min_version = line_tokens[i]
-          elif token == '--max-version':
-            i += 1
-            max_version = line_tokens[i]
-          i += 1
-
-        min_version_to_compare = min_version or folder_min_version
-
-        if (min_version_to_compare and
-            _CompareVersion(version, min_version_to_compare) < 0):
-          continue
-
-        if max_version and _CompareVersion(version, max_version) > 0:
-          continue
-
-        if (webgl2_only and not '.txt' in test_name and
-            (not min_version_to_compare or
-             not min_version_to_compare.startswith('2'))):
-          continue
-
-        if '.txt' in test_name:
-          include_path = os.path.join(current_dir, test_name)
-          # We only check min-version >= 2.0.0 for the top level list.
-          test_paths += WebglConformance._ParseTests(
-              include_path, version, webgl2_only, min_version_to_compare)
-        else:
-          test = os.path.join(current_dir, test_name)
-          if webgl_version > 1:
-            test += '?webglVersion=' + str(webgl_version)
-          test_paths.append(test)
-
-    return test_paths
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
index a54ab26..b59c02a 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -8,9 +8,10 @@
 # See the GpuTestExpectations class for documentation.
 
 class WebGLConformanceExpectations(GpuTestExpectations):
-  def __init__(self, conformance_path):
+  def __init__(self, conformance_path, url_prefixes=None):
     self.conformance_path = conformance_path
-    super(WebGLConformanceExpectations, self).__init__()
+    super(WebGLConformanceExpectations, self).__init__(
+      url_prefixes=url_prefixes)
 
   def Fail(self, pattern, condition=None, bug=None):
     self.CheckPatternIsValid(pattern)
@@ -27,7 +28,7 @@
 
   def CheckPatternIsValid(self, pattern):
     # Look for basic wildcards.
-    if not '*' in pattern and not 'WebglExtension.' in pattern:
+    if not '*' in pattern and not 'WebglExtension_' in pattern:
       full_path = os.path.normpath(os.path.join(self.conformance_path, pattern))
       if not os.path.exists(full_path):
         raise Exception('The WebGL conformance test path specified in ' +
@@ -40,61 +41,70 @@
     # It's expected that not all extensions will be available on all platforms.
     # Having a test listed here is not necessarily a problem.
 
-    self.Fail('WebglExtension.EXT_color_buffer_float',
+    self.Fail('WebglExtension_EXT_color_buffer_float',
         ['win', 'mac'])
-    self.Fail('WebglExtension.WEBGL_compressed_texture_astc',
+    # Skip these, rather than expect them to fail, to speed up test
+    # execution. The browser is restarted even after expected test
+    # failures.
+    self.Skip('WebglExtension_WEBGL_compressed_texture_astc',
         ['win', 'mac', 'linux'])
-    self.Fail('WebglExtension.WEBGL_compressed_texture_atc',
+    self.Skip('WebglExtension_WEBGL_compressed_texture_atc',
         ['win', 'mac', 'linux'])
-    self.Fail('WebglExtension.WEBGL_compressed_texture_etc1',
+    self.Skip('WebglExtension_WEBGL_compressed_texture_etc1',
         ['mac', 'linux'])
-    self.Fail('WebglExtension.WEBGL_compressed_texture_pvrtc',
+    self.Skip('WebglExtension_WEBGL_compressed_texture_pvrtc',
         ['win', 'mac', 'linux'])
+    self.Skip('WebglExtension_WEBGL_compressed_texture_s3tc_srgb',
+        ['win', 'mac', 'linux', 'android'])
 
     # Extensions not available under D3D9
-    self.Fail('WebglExtension.EXT_disjoint_timer_query',
+    self.Fail('WebglExtension_EXT_disjoint_timer_query',
         ['win', 'd3d9'])
-    self.Fail('WebglExtension.EXT_sRGB',
+    self.Fail('WebglExtension_EXT_sRGB',
         ['win', 'd3d9'])
-    self.Fail('WebglExtension.WEBGL_compressed_texture_etc1',
+    self.Fail('WebglExtension_WEBGL_compressed_texture_etc1',
         ['win', 'd3d9'])
 
-    self.Fail('WebglExtension.WEBGL_depth_texture',
+    self.Fail('WebglExtension_WEBGL_depth_texture',
         ['win', 'amd', 'd3d9'])
 
-    self.Fail('WebglExtension.WEBGL_draw_buffers',
+    self.Fail('WebglExtension_WEBGL_draw_buffers',
         ['win', 'd3d9'])
 
     # Android general
-    self.Fail('WebglExtension.EXT_disjoint_timer_query',
+    self.Fail('WebglExtension_EXT_disjoint_timer_query',
         ['android'])
-    self.Fail('WebglExtension.EXT_frag_depth',
+    self.Fail('WebglExtension_EXT_frag_depth',
         ['android'])
-    self.Fail('WebglExtension.EXT_shader_texture_lod',
+    self.Fail('WebglExtension_EXT_shader_texture_lod',
         ['android'])
-    self.Fail('WebglExtension.WEBGL_compressed_texture_astc',
+    self.Fail('WebglExtension_WEBGL_compressed_texture_astc',
         ['android'])
-    self.Fail('WebglExtension.WEBGL_compressed_texture_pvrtc',
+    self.Fail('WebglExtension_WEBGL_compressed_texture_pvrtc',
         ['android'])
-    self.Fail('WebglExtension.WEBGL_compressed_texture_s3tc',
+    self.Fail('WebglExtension_WEBGL_compressed_texture_s3tc',
         ['android'])
-    self.Fail('WebglExtension.WEBGL_depth_texture',
+    self.Fail('WebglExtension_WEBGL_depth_texture',
         ['android'])
-    self.Fail('WebglExtension.WEBGL_draw_buffers',
+    self.Fail('WebglExtension_WEBGL_draw_buffers',
         ['android'])
 
     # Nexus 5
-    self.Fail('WebglExtension.OES_texture_float_linear',
+    self.Fail('WebglExtension_OES_texture_float_linear',
               ['android', ('qualcomm', 'Adreno (TM) 330')])
 
+    # Nexus 5X
+    self.Fail('WebglExtension_EXT_sRGB',
+              ['android', ('qualcomm', 'Adreno (TM) 418')], bug=610951)
+
     # Nexus 6 (Adreno 420) and 6P (Adreno 430)
-    self.Fail('WebglExtension.EXT_sRGB',
+    self.Fail('WebglExtension_EXT_sRGB',
               ['android',
                ('qualcomm', 'Adreno (TM) 420'),
                ('qualcomm', 'Adreno (TM) 430')])
 
     # Nexus 9
-    self.Fail('WebglExtension.WEBGL_compressed_texture_atc',
+    self.Fail('WebglExtension_WEBGL_compressed_texture_atc',
               ['android', ('nvidia', 'NVIDIA Tegra')])
 
     # ========================
@@ -112,8 +122,6 @@
         ['win', 'linux', 'nvidia', 'opengl'], bug=1007) # angle bug ID
 
     # Win failures
-    self.Fail('conformance/extensions/oes-texture-half-float.html',
-        ['win'], bug=607283)
     # Note that the following test seems to pass, but it may still be flaky.
     self.Fail('conformance/glsl/constructors/' +
               'glsl-construct-vec-mat-index.html',
@@ -248,10 +256,6 @@
                'tex-2d-rgb-rgb-unsigned_short_5_6_5.html',
                ['linux'], bug=627525)
 
-    # OpenGL
-    self.Fail('conformance/extensions/oes-texture-half-float.html',
-        ['linux', 'opengl'], bug=607283)
-
     # NVIDIA
     self.Fail('conformance/extensions/angle-instanced-arrays.html',
               ['linux', 'nvidia'], bug=544989) # Too flaky to retry
@@ -436,8 +440,6 @@
     # This test is skipped because it is crashing the GPU process.
     self.Skip('conformance/glsl/misc/shader-with-non-reserved-words.html',
               ['android', ('qualcomm', 'Adreno (TM) 418')], bug=609883)
-    self.Fail('WebglExtension.EXT_sRGB',
-              ['android', ('qualcomm', 'Adreno (TM) 418')], bug=610951)
     self.Fail('conformance/textures/misc/' +
               'tex-image-and-sub-image-2d-with-array-buffer-view.html',
               ['android', ('qualcomm', 'Adreno (TM) 418')], bug=610951)
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations_unittest.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations_unittest.py
index c6f5e5e0..08961fe 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_expectations_unittest.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations_unittest.py
@@ -12,8 +12,8 @@
 from gpu_tests import gpu_test_base
 from gpu_tests import path_util
 from gpu_tests import test_expectations
-from gpu_tests import webgl_conformance
 from gpu_tests import webgl_conformance_expectations
+from gpu_tests import webgl_conformance_integration_test
 from gpu_tests import webgl2_conformance_expectations
 
 class FakeWindowsPlatform(fakes.FakePlatform):
@@ -69,13 +69,15 @@
 
   def testWebGLExpectationsHaveNoCollisions(self):
     conformance = webgl_conformance_expectations.\
-      WebGLConformanceExpectations(webgl_conformance.conformance_path)
+      WebGLConformanceExpectations(
+        webgl_conformance_integration_test.conformance_path)
 
     self.checkConformanceHasNoCollisions(conformance)
 
   def testWebGL2ExpectationsHaveNoCollisions(self):
     conformance = webgl2_conformance_expectations.\
-      WebGL2ConformanceExpectations(webgl_conformance.conformance_path)
+      WebGL2ConformanceExpectations(
+        webgl_conformance_integration_test.conformance_path)
 
     self.checkConformanceHasNoCollisions(conformance)
 
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_integration_test.py b/content/test/gpu/gpu_tests/webgl_conformance_integration_test.py
index 500e000..68847eb 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_integration_test.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance_integration_test.py
@@ -2,11 +2,89 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import os
+
 from gpu_tests import gpu_integration_test
-from gpu_tests import webgl_conformance
+from gpu_tests import path_util
 from gpu_tests import webgl_conformance_expectations
 from gpu_tests import webgl2_conformance_expectations
 
+from telemetry.internal.browser import browser_finder
+
+conformance_relcomps = (
+  'third_party', 'webgl', 'src', 'sdk', 'tests')
+
+extensions_relcomps = (
+    'content', 'test', 'data', 'gpu')
+
+conformance_relpath = os.path.join(*conformance_relcomps)
+extensions_relpath = os.path.join(*extensions_relcomps)
+conformance_path = os.path.join(path_util.GetChromiumSrcDir(),
+                                conformance_relpath)
+
+# These URL prefixes are needed because having more than one static
+# server dir is causing the base server directory to be moved up the
+# directory hierarchy.
+url_prefixes_to_trim = [
+  '/'.join(conformance_relcomps) + '/',
+  '/'.join(extensions_relcomps) + '/'
+]
+
+conformance_harness_script = r"""
+  var testHarness = {};
+  testHarness._allTestSucceeded = true;
+  testHarness._messages = '';
+  testHarness._failures = 0;
+  testHarness._finished = false;
+  testHarness._originalLog = window.console.log;
+
+  testHarness.log = function(msg) {
+    testHarness._messages += msg + "\n";
+    testHarness._originalLog.apply(window.console, [msg]);
+  }
+
+  testHarness.reportResults = function(url, success, msg) {
+    testHarness._allTestSucceeded = testHarness._allTestSucceeded && !!success;
+    if(!success) {
+      testHarness._failures++;
+      if(msg) {
+        testHarness.log(msg);
+      }
+    }
+  };
+  testHarness.notifyFinished = function(url) {
+    testHarness._finished = true;
+  };
+  testHarness.navigateToPage = function(src) {
+    var testFrame = document.getElementById("test-frame");
+    testFrame.src = src;
+  };
+
+  window.webglTestHarness = testHarness;
+  window.parent.webglTestHarness = testHarness;
+  window.console.log = testHarness.log;
+  window.onerror = function(message, url, line) {
+    testHarness.reportResults(null, false, message);
+    testHarness.notifyFinished(null);
+  };
+  window.quietMode = function() { return true; }
+"""
+
+extension_harness_additional_script = r"""
+  window.onload = function() { window._loaded = true; }
+"""
+
+def _GenerateTestNameFromTestPath(test_path):
+  return ('WebglConformance.%s' %
+          test_path.replace('/', '_').replace('-', '_').
+          replace('\\', '_').rpartition('.')[0].replace('.', '_'))
+
+def _CompareVersion(version1, version2):
+  ver_num1 = [int(x) for x in version1.split('.')]
+  ver_num2 = [int(x) for x in version2.split('.')]
+  size = min(len(ver_num1), len(ver_num2))
+  return cmp(ver_num1[0:size], ver_num2[0:size])
+
 
 class WebGLConformanceIntegrationTest(gpu_integration_test.GpuIntegrationTest):
 
@@ -27,7 +105,10 @@
 
   @classmethod
   def GenerateGpuTests(cls, options):
-    test_paths = webgl_conformance.WebglConformance._ParseTests(
+    #
+    # Conformance tests
+    #
+    test_paths = cls._ParseTests(
         '00_test_list.txt',
         options.webgl_conformance_version,
         (options.webgl2_only == 'true'),
@@ -36,38 +117,170 @@
         int(x) for x in options.webgl_conformance_version.split('.')][0]
     for test_path in test_paths:
       # generated test name cannot contain '.'
-      name = webgl_conformance.GenerateTestNameFromTestPath(test_path).replace(
+      name = _GenerateTestNameFromTestPath(test_path).replace(
           '.', '_')
-      yield (name, test_path, ())
+      yield (name,
+             os.path.join(conformance_relpath, test_path),
+             ('_RunConformanceTest'))
+
+    #
+    # Extension tests
+    #
+    extension_tests = cls._GetExtensionList()
+    # Coverage test.
+    yield('WebglExtension_TestCoverage',
+          os.path.join(extensions_relpath, 'webgl_extension_test.html'),
+          ('_RunExtensionCoverageTest',
+           extension_tests,
+           cls._webgl_version))
+    # Individual extension tests.
+    for extension in extension_tests:
+      yield('WebglExtension_%s' % extension,
+            os.path.join(extensions_relpath, 'webgl_extension_test.html'),
+            ('_RunExtensionTest',
+             extension,
+             cls._webgl_version))
+
+  @classmethod
+  def _GetExtensionList(cls):
+    if cls._webgl_version == 1:
+      return [
+        'ANGLE_instanced_arrays',
+        'EXT_blend_minmax',
+        'EXT_disjoint_timer_query',
+        'EXT_frag_depth',
+        'EXT_shader_texture_lod',
+        'EXT_sRGB',
+        'EXT_texture_filter_anisotropic',
+        'OES_element_index_uint',
+        'OES_standard_derivatives',
+        'OES_texture_float',
+        'OES_texture_float_linear',
+        'OES_texture_half_float',
+        'OES_texture_half_float_linear',
+        'OES_vertex_array_object',
+        'WEBGL_compressed_texture_astc',
+        'WEBGL_compressed_texture_atc',
+        'WEBGL_compressed_texture_etc1',
+        'WEBGL_compressed_texture_pvrtc',
+        'WEBGL_compressed_texture_s3tc',
+        'WEBGL_compressed_texture_s3tc_srgb',
+        'WEBGL_debug_renderer_info',
+        'WEBGL_debug_shaders',
+        'WEBGL_depth_texture',
+        'WEBGL_draw_buffers',
+        'WEBGL_lose_context',
+      ]
+    else:
+      return [
+        'EXT_color_buffer_float',
+        'EXT_disjoint_timer_query',
+        'EXT_texture_filter_anisotropic',
+        'OES_texture_float_linear',
+        'WEBGL_compressed_texture_astc',
+        'WEBGL_compressed_texture_atc',
+        'WEBGL_compressed_texture_es3_0',
+        'WEBGL_compressed_texture_etc1',
+        'WEBGL_compressed_texture_pvrtc',
+        'WEBGL_compressed_texture_s3tc',
+        'WEBGL_compressed_texture_s3tc_srgb',
+        'WEBGL_debug_renderer_info',
+        'WEBGL_debug_shaders',
+        'WEBGL_lose_context',
+      ]
 
   def RunActualGpuTest(self, test_path, *args):
+    # This indirection allows these tests to trampoline through
+    # _RunGpuTest.
+    test_name = args[0]
+    getattr(self, test_name)(test_path, *args[1:])
+
+  def _NavigateTo(self, test_path, harness_script):
     url = self.UrlOfStaticFilePath(test_path)
-    harness_script = webgl_conformance.conformance_harness_script
     self.tab.Navigate(url, script_to_evaluate_on_commit=harness_script)
+
+  def _CheckTestCompletion(self):
     self.tab.action_runner.WaitForJavaScriptCondition(
         'webglTestHarness._finished', timeout_in_seconds=300)
-    if not webgl_conformance._DidWebGLTestSucceed(self.tab):
-      self.fail(webgl_conformance._WebGLTestMessages(self.tab))
+    if not self._DidWebGLTestSucceed(self.tab):
+      self.fail(self._WebGLTestMessages(self.tab))
+
+  def _RunConformanceTest(self, test_path, *args):
+    self._NavigateTo(test_path, conformance_harness_script)
+    self._CheckTestCompletion()
+
+
+  def _GetExtensionHarnessScript(self):
+    return conformance_harness_script + extension_harness_additional_script
+
+  def _RunExtensionCoverageTest(self, test_path, *args):
+    self._NavigateTo(test_path, self._GetExtensionHarnessScript())
+    self.tab.action_runner.WaitForJavaScriptCondition(
+        'window._loaded', timeout_in_seconds=300)
+    extension_list = args[0]
+    webgl_version = args[1]
+    context_type = "webgl2" if webgl_version == 2 else "webgl"
+    extension_list_string = "["
+    for extension in extension_list:
+      extension_list_string = extension_list_string + extension + ", "
+    extension_list_string = extension_list_string + "]"
+    self.tab.action_runner.EvaluateJavaScript(
+      'checkSupportedExtensions("%s", "%s")' % (
+        extension_list_string, context_type))
+    self._CheckTestCompletion()
+
+  def _RunExtensionTest(self, test_path, *args):
+    self._NavigateTo(test_path, self._GetExtensionHarnessScript())
+    self.tab.action_runner.WaitForJavaScriptCondition(
+        'window._loaded', timeout_in_seconds=300)
+    extension = args[0]
+    webgl_version = args[1]
+    context_type = "webgl2" if webgl_version == 2 else "webgl"
+    self.tab.action_runner.EvaluateJavaScript(
+      'checkExtension("%s", "%s")' % (extension, context_type))
+    self._CheckTestCompletion()
 
   @classmethod
   def CustomizeOptions(cls):
     assert cls._webgl_version == 1 or cls._webgl_version == 2
-    validator = None
-    if cls._webgl_version == 1:
-      validator = webgl_conformance.WebglConformanceValidator()
-    else:
-      validator = webgl_conformance.Webgl2ConformanceValidator()
-    validator.CustomizeBrowserOptions(cls._finder_options.browser_options)
+    browser_options = cls._finder_options.browser_options
+    # --test-type=gpu is used only to suppress the "Google API Keys are missing"
+    # infobar, which causes flakiness in tests.
+    browser_options.AppendExtraBrowserArgs([
+        '--disable-gesture-requirement-for-media-playback',
+        '--disable-domain-blocking-for-3d-apis',
+        '--disable-gpu-process-crash-limit',
+        '--js-flags=--expose-gc',
+        '--test-type=gpu',
+        '--enable-experimental-canvas-features'
+    ])
+    if cls._webgl_version == 2:
+      browser_options.AppendExtraBrowserArgs([
+        '--enable-unsafe-es3-apis',
+      ])
+    browser = browser_finder.FindBrowser(browser_options.finder_options)
+    if (browser.target_os.startswith('android') and
+      browser.browser_type == 'android-webview-shell'):
+      # TODO(kbr): this is overly broad. We'd like to do this only on
+      # Nexus 9. It'll go away shortly anyway. crbug.com/499928
+      #
+      # The --ignore_egl_sync_failures is only there to work around
+      # some strange failure on the Nexus 9 bot, not reproducible on
+      # local hardware.
+      browser_options.AppendExtraBrowserArgs([
+        '--disable-gl-extensions=GL_EXT_disjoint_timer_query',
+        '--ignore_egl_sync_failures',
+      ])
 
   @classmethod
   def _CreateExpectations(cls):
     assert cls._webgl_version == 1 or cls._webgl_version == 2
     if cls._webgl_version == 1:
       return webgl_conformance_expectations.WebGLConformanceExpectations(
-          webgl_conformance.conformance_path)
+          conformance_path, url_prefixes=url_prefixes_to_trim)
     else:
       return webgl2_conformance_expectations.WebGL2ConformanceExpectations(
-          webgl_conformance.conformance_path)
+          conformance_path, url_prefixes=url_prefixes_to_trim)
 
   @classmethod
   def setUpClass(cls):
@@ -75,4 +288,83 @@
     cls.CustomizeOptions()
     cls.SetBrowserOptions(cls._finder_options)
     cls.StartBrowser()
-    cls.SetStaticServerDirs([webgl_conformance.conformance_path])
+    # By setting multiple server directories, the root of the server
+    # implicitly becomes the common base directory, i.e., the Chromium
+    # src dir, and all URLs have to be specified relative to that.
+    cls.SetStaticServerDirs([
+      os.path.join(path_util.GetChromiumSrcDir(), conformance_relpath),
+      os.path.join(path_util.GetChromiumSrcDir(), extensions_relpath)])
+
+  # Helper functions.
+
+  @staticmethod
+  def _DidWebGLTestSucceed(tab):
+    return tab.EvaluateJavaScript('webglTestHarness._allTestSucceeded')
+
+  @staticmethod
+  def _WebGLTestMessages(tab):
+    return tab.EvaluateJavaScript('webglTestHarness._messages')
+
+  @classmethod
+  def _ParseTests(cls, path, version, webgl2_only, folder_min_version):
+    test_paths = []
+    current_dir = os.path.dirname(path)
+    full_path = os.path.normpath(os.path.join(conformance_path, path))
+    webgl_version = int(version.split('.')[0])
+
+    if not os.path.exists(full_path):
+      raise Exception('The WebGL conformance test path specified ' +
+        'does not exist: ' + full_path)
+
+    with open(full_path, 'r') as f:
+      for line in f:
+        line = line.strip()
+
+        if not line:
+          continue
+
+        if line.startswith('//') or line.startswith('#'):
+          continue
+
+        line_tokens = line.split(' ')
+        test_name = line_tokens[-1]
+
+        i = 0
+        min_version = None
+        max_version = None
+        while i < len(line_tokens):
+          token = line_tokens[i]
+          if token == '--min-version':
+            i += 1
+            min_version = line_tokens[i]
+          elif token == '--max-version':
+            i += 1
+            max_version = line_tokens[i]
+          i += 1
+
+        min_version_to_compare = min_version or folder_min_version
+
+        if (min_version_to_compare and
+            _CompareVersion(version, min_version_to_compare) < 0):
+          continue
+
+        if max_version and _CompareVersion(version, max_version) > 0:
+          continue
+
+        if (webgl2_only and not '.txt' in test_name and
+            (not min_version_to_compare or
+             not min_version_to_compare.startswith('2'))):
+          continue
+
+        if '.txt' in test_name:
+          include_path = os.path.join(current_dir, test_name)
+          # We only check min-version >= 2.0.0 for the top level list.
+          test_paths += cls._ParseTests(
+              include_path, version, webgl2_only, min_version_to_compare)
+        else:
+          test = os.path.join(current_dir, test_name)
+          if webgl_version > 1:
+            test += '?webglVersion=' + str(webgl_version)
+          test_paths.append(test)
+
+    return test_paths
diff --git a/content/test/gpu/gpu_tests/webgl_robustness.py b/content/test/gpu/gpu_tests/webgl_robustness.py
deleted file mode 100644
index caaa8534..0000000
--- a/content/test/gpu/gpu_tests/webgl_robustness.py
+++ /dev/null
@@ -1,72 +0,0 @@
-# Copyright 2013 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.
-from telemetry import benchmark
-from telemetry.page import page
-from telemetry.story import story_set as story_set_module
-
-from gpu_tests.webgl_conformance import conformance_harness_script, \
-                                        conformance_path, \
-                                        WebglConformanceValidator
-
-
-robustness_harness_script = conformance_harness_script + r"""
-  var robustnessTestHarness = {};
-  robustnessTestHarness._contextLost = false;
-  robustnessTestHarness.initialize = function() {
-    var canvas = document.getElementById('example');
-    canvas.addEventListener('webglcontextlost', function() {
-      robustnessTestHarness._contextLost = true;
-    });
-  }
-  robustnessTestHarness.runTestLoop = function() {
-    // Run the test in a loop until the context is lost.
-    main();
-    if (!robustnessTestHarness._contextLost)
-      window.requestAnimationFrame(robustnessTestHarness.runTestLoop);
-    else
-      robustnessTestHarness.notifyFinished();
-  }
-  robustnessTestHarness.notifyFinished = function() {
-    // The test may fail in unpredictable ways depending on when the context is
-    // lost. We ignore such errors and only require that the browser doesn't
-    // crash.
-    webglTestHarness._allTestSucceeded = true;
-    // Notify test completion after a delay to make sure the browser is able to
-    // recover from the lost context.
-    setTimeout(webglTestHarness.notifyFinished, 3000);
-  }
-
-  window.confirm = function() {
-    robustnessTestHarness.initialize();
-    robustnessTestHarness.runTestLoop();
-    return false;
-  }
-  window.webglRobustnessTestHarness = robustnessTestHarness;
-"""
-
-class WebglRobustnessPage(page.Page):
-  def __init__(self, story_set, base_dir):
-    super(WebglRobustnessPage, self).__init__(
-      url='file://extra/lots-of-polys-example.html',
-      page_set=story_set,
-      base_dir=base_dir)
-    self.script_to_evaluate_on_commit = robustness_harness_script
-
-  def RunNavigateSteps(self, action_runner):
-    super(WebglRobustnessPage, self).RunNavigateSteps(action_runner)
-    action_runner.WaitForJavaScriptCondition('webglTestHarness._finished')
-
-class WebglRobustness(benchmark.Benchmark):
-  test = WebglConformanceValidator
-
-  @classmethod
-  def Name(cls):
-    return 'webgl_robustness'
-
-  def CreateStorySet(self, options):
-    ps = story_set_module.StorySet(
-      base_dir=conformance_path,
-      serving_dirs=[''])
-    ps.AddStory(WebglRobustnessPage(ps, ps.base_dir))
-    return ps
diff --git a/content/test/mock_webframeclient.h b/content/test/mock_webframeclient.h
deleted file mode 100644
index bba8aa5..0000000
--- a/content/test/mock_webframeclient.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2013 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_TEST_MOCK_WEBFRAMECLIENT_H_
-#define CONTENT_TEST_MOCK_WEBFRAMECLIENT_H_
-
-#include "third_party/WebKit/public/web/WebFrameClient.h"
-
-namespace content {
-
-class MockWebFrameClient : public blink::WebFrameClient {};
-
-}  // namespace content
-
-#endif  // CONTENT_TEST_MOCK_WEBFRAMECLIENT_H_
diff --git a/content/test/test_navigation_url_loader_factory.cc b/content/test/test_navigation_url_loader_factory.cc
index ee6d37c4..2a8fd288 100644
--- a/content/test/test_navigation_url_loader_factory.cc
+++ b/content/test/test_navigation_url_loader_factory.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "content/browser/loader/navigation_url_loader.h"
+#include "content/public/browser/navigation_ui_data.h"
 #include "content/test/test_navigation_url_loader.h"
 
 namespace content {
@@ -23,6 +24,7 @@
 TestNavigationURLLoaderFactory::CreateLoader(
     BrowserContext* browser_context,
     std::unique_ptr<NavigationRequestInfo> request_info,
+    std::unique_ptr<NavigationUIData> navigation_ui_data,
     ServiceWorkerNavigationHandle* service_worker_handle,
     NavigationURLLoaderDelegate* delegate) {
   return std::unique_ptr<NavigationURLLoader>(
diff --git a/content/test/test_navigation_url_loader_factory.h b/content/test/test_navigation_url_loader_factory.h
index ba4cc31..460393a4 100644
--- a/content/test/test_navigation_url_loader_factory.h
+++ b/content/test/test_navigation_url_loader_factory.h
@@ -29,6 +29,7 @@
   std::unique_ptr<NavigationURLLoader> CreateLoader(
       BrowserContext* browser_context,
       std::unique_ptr<NavigationRequestInfo> request_info,
+      std::unique_ptr<NavigationUIData> navigation_ui_data,
       ServiceWorkerNavigationHandle* service_worker_handle,
       NavigationURLLoaderDelegate* delegate) override;
 
diff --git a/content/test/test_web_contents.cc b/content/test/test_web_contents.cc
index 752f6cc..5d496f4 100644
--- a/content/test/test_web_contents.cc
+++ b/content/test/test_web_contents.cc
@@ -15,6 +15,7 @@
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/site_instance_impl.h"
 #include "content/common/frame_messages.h"
+#include "content/common/render_message_filter.mojom.h"
 #include "content/common/view_messages.h"
 #include "content/public/browser/navigation_data.h"
 #include "content/public/browser/notification_registrar.h"
@@ -325,7 +326,7 @@
     int32_t route_id,
     int32_t main_frame_route_id,
     int32_t main_frame_widget_route_id,
-    const ViewHostMsg_CreateWindow_Params& params,
+    const mojom::CreateNewWindowParams& params,
     SessionStorageNamespace* session_storage_namespace) {}
 
 void TestWebContents::CreateNewWidget(int32_t render_process_id,
diff --git a/content/test/test_web_contents.h b/content/test/test_web_contents.h
index f3bee90..92baea0 100644
--- a/content/test/test_web_contents.h
+++ b/content/test/test_web_contents.h
@@ -128,7 +128,7 @@
       int32_t route_id,
       int32_t main_frame_route_id,
       int32_t main_frame_widget_route_id,
-      const ViewHostMsg_CreateWindow_Params& params,
+      const mojom::CreateNewWindowParams& params,
       SessionStorageNamespace* session_storage_namespace) override;
   void CreateNewWidget(int32_t render_process_id,
                        int32_t route_id,
diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn
index 93ecfcda..6618f7a 100644
--- a/extensions/browser/BUILD.gn
+++ b/extensions/browser/BUILD.gn
@@ -118,6 +118,8 @@
       "extension_message_filter.h",
       "extension_navigation_throttle.cc",
       "extension_navigation_throttle.h",
+      "extension_navigation_ui_data.cc",
+      "extension_navigation_ui_data.h",
       "extension_pref_store.cc",
       "extension_pref_store.h",
       "extension_pref_value_map.cc",
@@ -250,6 +252,7 @@
       "//extensions/browser/app_window",
       "//extensions/browser/guest_view",
       "//extensions/browser/install",
+      "//extensions/browser/kiosk",
       "//extensions/browser/mojo",
       "//extensions/browser/updater",
       "//extensions/browser/value_store",
diff --git a/extensions/browser/api/BUILD.gn b/extensions/browser/api/BUILD.gn
index f164be169..bae9ea9 100644
--- a/extensions/browser/api/BUILD.gn
+++ b/extensions/browser/api/BUILD.gn
@@ -29,6 +29,7 @@
     "//extensions/browser/api/app_window",
     "//extensions/browser/api/audio",
     "//extensions/browser/api/bluetooth",
+    "//extensions/browser/api/bluetooth_low_energy",
     "//extensions/browser/api/bluetooth_socket",
     "//extensions/browser/api/cast_channel",
     "//extensions/browser/api/clipboard",
diff --git a/extensions/browser/api/bluetooth_low_energy/BUILD.gn b/extensions/browser/api/bluetooth_low_energy/BUILD.gn
new file mode 100644
index 0000000..000918e
--- /dev/null
+++ b/extensions/browser/api/bluetooth_low_energy/BUILD.gn
@@ -0,0 +1,29 @@
+# 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.
+
+source_set("bluetooth_low_energy") {
+  sources = [
+    "bluetooth_api_advertisement.cc",
+    "bluetooth_api_advertisement.h",
+    "bluetooth_low_energy_api.cc",
+    "bluetooth_low_energy_api.h",
+    "bluetooth_low_energy_connection.cc",
+    "bluetooth_low_energy_connection.h",
+    "bluetooth_low_energy_event_router.cc",
+    "bluetooth_low_energy_event_router.h",
+    "bluetooth_low_energy_notify_session.cc",
+    "bluetooth_low_energy_notify_session.h",
+    "utils.cc",
+    "utils.h",
+  ]
+
+  configs += [
+    # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+    "//build/config/compiler:no_size_t_to_int_warning",
+  ]
+
+  deps = [
+    "//device/bluetooth",
+  ]
+}
diff --git a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_api_advertisement.cc b/extensions/browser/api/bluetooth_low_energy/bluetooth_api_advertisement.cc
similarity index 77%
rename from chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_api_advertisement.cc
rename to extensions/browser/api/bluetooth_low_energy/bluetooth_api_advertisement.cc
index 9eb998e..3f3dcdf 100644
--- a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_api_advertisement.cc
+++ b/extensions/browser/api/bluetooth_low_energy/bluetooth_api_advertisement.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 "chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_api_advertisement.h"
+#include "extensions/browser/api/bluetooth_low_energy/bluetooth_api_advertisement.h"
 
 #include "base/lazy_instance.h"
 #include "device/bluetooth/bluetooth_advertisement.h"
@@ -12,8 +12,8 @@
 
 // static
 static base::LazyInstance<BrowserContextKeyedAPIFactory<
-    ApiResourceManager<BluetoothApiAdvertisement>>> g_server_factory =
-    LAZY_INSTANCE_INITIALIZER;
+    ApiResourceManager<BluetoothApiAdvertisement>>>
+    g_server_factory = LAZY_INSTANCE_INITIALIZER;
 
 // static
 template <>
@@ -29,7 +29,6 @@
   DCHECK_CURRENTLY_ON(kThreadId);
 }
 
-BluetoothApiAdvertisement::~BluetoothApiAdvertisement() {
-}
+BluetoothApiAdvertisement::~BluetoothApiAdvertisement() {}
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_api_advertisement.h b/extensions/browser/api/bluetooth_low_energy/bluetooth_api_advertisement.h
similarity index 80%
rename from chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_api_advertisement.h
rename to extensions/browser/api/bluetooth_low_energy/bluetooth_api_advertisement.h
index f570dfa..3ac8a01 100644
--- a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_api_advertisement.h
+++ b/extensions/browser/api/bluetooth_low_energy/bluetooth_api_advertisement.h
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_API_ADVERTISEMENT_H_
-#define CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_API_ADVERTISEMENT_H_
+#ifndef EXTENSIONS_BROWSER_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_API_ADVERTISEMENT_H_
+#define EXTENSIONS_BROWSER_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_API_ADVERTISEMENT_H_
 
 #include <string>
 
 #include "base/macros.h"
-#include "chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h"
 #include "device/bluetooth/bluetooth_advertisement.h"
 #include "extensions/browser/api/api_resource.h"
 #include "extensions/browser/api/api_resource_manager.h"
+#include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h"
 
 namespace device {
 class BluetoothAdvertisement;
@@ -52,4 +52,4 @@
 
 }  // namespace extensions
 
-#endif  // CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_API_ADVERTISEMENT_H_
+#endif  // EXTENSIONS_BROWSER_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_API_ADVERTISEMENT_H_
diff --git a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_api.cc b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.cc
similarity index 96%
rename from chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_api.cc
rename to extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.cc
index fc50f4ea..db956ab7 100644
--- a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_api.cc
+++ b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.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 "chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_api.h"
+#include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.h"
 
 #include <stdint.h>
 #include <algorithm>
@@ -18,8 +18,6 @@
 #include "base/logging.h"
 #include "base/memory/weak_ptr.h"
 #include "base/values.h"
-#include "chrome/browser/extensions/api/bluetooth_low_energy/utils.h"
-#include "chrome/common/extensions/api/bluetooth_low_energy.h"
 #include "content/public/browser/browser_thread.h"
 #include "device/bluetooth/bluetooth_adapter.h"
 #include "device/bluetooth/bluetooth_gatt_characteristic.h"
@@ -27,14 +25,15 @@
 #include "device/bluetooth/bluetooth_local_gatt_descriptor.h"
 #include "device/bluetooth/bluetooth_local_gatt_service.h"
 #include "device/bluetooth/bluetooth_uuid.h"
+#include "extensions/browser/api/bluetooth_low_energy/utils.h"
+#include "extensions/browser/api/extensions_api_client.h"
+#include "extensions/browser/kiosk/kiosk_delegate.h"
 #include "extensions/common/api/bluetooth/bluetooth_manifest_data.h"
+#include "extensions/common/api/bluetooth_low_energy.h"
 #include "extensions/common/extension.h"
+#include "extensions/common/extension_id.h"
 #include "extensions/common/switches.h"
 
-#if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
-#endif
-
 using content::BrowserContext;
 using content::BrowserThread;
 
@@ -329,13 +328,9 @@
 }
 
 bool IsAutoLaunchedKioskApp(const ExtensionId& id) {
-#if defined(OS_CHROMEOS)
-  chromeos::KioskAppManager::App app_info;
-  return chromeos::KioskAppManager::Get()->GetApp(id, &app_info) &&
-         app_info.was_auto_launched_with_zero_delay;
-#else
-  return false;
-#endif
+  KioskDelegate* delegate = ExtensionsBrowserClient::Get()->GetKioskDelegate();
+  DCHECK(delegate);
+  return delegate->IsAutoLaunchedKioskApp(id);
 }
 
 bool IsPeripheralFlagEnabled() {
@@ -345,8 +340,7 @@
 
 }  // namespace
 
-
-static base::LazyInstance<BrowserContextKeyedAPIFactory<BluetoothLowEnergyAPI> >
+static base::LazyInstance<BrowserContextKeyedAPIFactory<BluetoothLowEnergyAPI>>
     g_factory = LAZY_INSTANCE_INITIALIZER;
 
 // static
@@ -366,8 +360,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
-BluetoothLowEnergyAPI::~BluetoothLowEnergyAPI() {
-}
+BluetoothLowEnergyAPI::~BluetoothLowEnergyAPI() {}
 
 void BluetoothLowEnergyAPI::Shutdown() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -497,9 +490,7 @@
     persistent = properties->persistent;
 
   event_router->Connect(
-      persistent,
-      extension(),
-      params->device_address,
+      persistent, extension(), params->device_address,
       base::Bind(&BluetoothLowEnergyConnectFunction::SuccessCallback, this),
       base::Bind(&BluetoothLowEnergyConnectFunction::ErrorCallback, this));
 
@@ -535,8 +526,7 @@
   EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
 
   event_router->Disconnect(
-      extension(),
-      params->device_address,
+      extension(), params->device_address,
       base::Bind(&BluetoothLowEnergyDisconnectFunction::SuccessCallback, this),
       base::Bind(&BluetoothLowEnergyDisconnectFunction::ErrorCallback, this));
 
@@ -637,8 +627,8 @@
 
   apibtle::Characteristic characteristic;
   BluetoothLowEnergyEventRouter::Status status =
-      event_router->GetCharacteristic(
-          extension(), params->characteristic_id, &characteristic);
+      event_router->GetCharacteristic(extension(), params->characteristic_id,
+                                      &characteristic);
   if (status != BluetoothLowEnergyEventRouter::kStatusSuccess) {
     SetError(StatusToString(status));
     SendResponse(false);
@@ -674,8 +664,8 @@
 
   BluetoothLowEnergyEventRouter::CharacteristicList characteristic_list;
   BluetoothLowEnergyEventRouter::Status status =
-      event_router->GetCharacteristics(
-          extension(), params->service_id, &characteristic_list);
+      event_router->GetCharacteristics(extension(), params->service_id,
+                                       &characteristic_list);
   if (status != BluetoothLowEnergyEventRouter::kStatusSuccess) {
     SetError(StatusToString(status));
     SendResponse(false);
@@ -824,8 +814,7 @@
 
   instance_id_ = params->characteristic_id;
   event_router->ReadCharacteristicValue(
-      extension(),
-      instance_id_,
+      extension(), instance_id_,
       base::Bind(
           &BluetoothLowEnergyReadCharacteristicValueFunction::SuccessCallback,
           this),
@@ -882,9 +871,7 @@
 
   std::vector<uint8_t> value(params->value.begin(), params->value.end());
   event_router->WriteCharacteristicValue(
-      extension(),
-      params->characteristic_id,
-      value,
+      extension(), params->characteristic_id, value,
       base::Bind(
           &BluetoothLowEnergyWriteCharacteristicValueFunction::SuccessCallback,
           this),
@@ -930,9 +917,7 @@
     persistent = properties->persistent;
 
   event_router->StartCharacteristicNotifications(
-      persistent,
-      extension(),
-      params->characteristic_id,
+      persistent, extension(), params->characteristic_id,
       base::Bind(&BluetoothLowEnergyStartCharacteristicNotificationsFunction::
                      SuccessCallback,
                  this),
@@ -943,8 +928,8 @@
   return true;
 }
 
-void
-BluetoothLowEnergyStartCharacteristicNotificationsFunction::SuccessCallback() {
+void BluetoothLowEnergyStartCharacteristicNotificationsFunction::
+    SuccessCallback() {
   SendResponse(true);
 }
 
@@ -973,8 +958,7 @@
   EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
 
   event_router->StopCharacteristicNotifications(
-      extension(),
-      params->characteristic_id,
+      extension(), params->characteristic_id,
       base::Bind(&BluetoothLowEnergyStopCharacteristicNotificationsFunction::
                      SuccessCallback,
                  this),
@@ -985,8 +969,8 @@
   return true;
 }
 
-void
-BluetoothLowEnergyStopCharacteristicNotificationsFunction::SuccessCallback() {
+void BluetoothLowEnergyStopCharacteristicNotificationsFunction::
+    SuccessCallback() {
   SendResponse(true);
 }
 
@@ -1016,8 +1000,7 @@
 
   instance_id_ = params->descriptor_id;
   event_router->ReadDescriptorValue(
-      extension(),
-      instance_id_,
+      extension(), instance_id_,
       base::Bind(
           &BluetoothLowEnergyReadDescriptorValueFunction::SuccessCallback,
           this),
@@ -1073,9 +1056,7 @@
 
   std::vector<uint8_t> value(params->value.begin(), params->value.end());
   event_router->WriteDescriptorValue(
-      extension(),
-      params->descriptor_id,
-      value,
+      extension(), params->descriptor_id, value,
       base::Bind(
           &BluetoothLowEnergyWriteDescriptorValueFunction::SuccessCallback,
           this),
@@ -1098,12 +1079,10 @@
 
 BluetoothLowEnergyAdvertisementFunction::
     BluetoothLowEnergyAdvertisementFunction()
-    : advertisements_manager_(nullptr) {
-}
+    : advertisements_manager_(nullptr) {}
 
 BluetoothLowEnergyAdvertisementFunction::
-    ~BluetoothLowEnergyAdvertisementFunction() {
-}
+    ~BluetoothLowEnergyAdvertisementFunction() {}
 
 int BluetoothLowEnergyAdvertisementFunction::AddAdvertisement(
     BluetoothApiAdvertisement* advertisement) {
diff --git a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_api.h b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.h
similarity index 97%
rename from chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_api.h
rename to extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.h
index 9743dd21..b56d3bfd 100644
--- a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_api.h
+++ b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.h
@@ -2,19 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_LOW_ENERGY_API_H_
-#define CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_LOW_ENERGY_API_H_
+#ifndef EXTENSIONS_BROWSER_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_LOW_ENERGY_API_H_
+#define EXTENSIONS_BROWSER_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_LOW_ENERGY_API_H_
 
 #include <memory>
 #include <string>
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_api_advertisement.h"
-#include "chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h"
 #include "content/public/browser/browser_context.h"
 #include "device/bluetooth/bluetooth_advertisement.h"
 #include "extensions/browser/api/api_resource_manager.h"
+#include "extensions/browser/api/bluetooth_low_energy/bluetooth_api_advertisement.h"
+#include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h"
 #include "extensions/browser/browser_context_keyed_api_factory.h"
 #include "extensions/browser/extension_function.h"
 #include "extensions/browser/extension_function_histogram_value.h"
@@ -56,7 +56,7 @@
 class BluetoothLowEnergyAPI : public BrowserContextKeyedAPI {
  public:
   static BrowserContextKeyedAPIFactory<BluetoothLowEnergyAPI>*
-      GetFactoryInstance();
+  GetFactoryInstance();
 
   // Convenience method to get the BluetoothLowEnergy API for a browser context.
   static BluetoothLowEnergyAPI* Get(content::BrowserContext* context);
@@ -631,4 +631,4 @@
 }  // namespace api
 }  // namespace extensions
 
-#endif  // CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_LOW_ENERGY_API_H_
+#endif  // EXTENSIONS_BROWSER_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_LOW_ENERGY_API_H_
diff --git a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_connection.cc b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_connection.cc
similarity index 65%
rename from chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_connection.cc
rename to extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_connection.cc
index 0cfbbe0..3365ad8 100644
--- a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_connection.cc
+++ b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_connection.cc
@@ -2,19 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_connection.h"
+#include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_connection.h"
 
 #include "base/lazy_instance.h"
 
 namespace extensions {
 
 static base::LazyInstance<BrowserContextKeyedAPIFactory<
-    ApiResourceManager<BluetoothLowEnergyConnection> > > g_factory =
-    LAZY_INSTANCE_INITIALIZER;
+    ApiResourceManager<BluetoothLowEnergyConnection>>>
+    g_factory = LAZY_INSTANCE_INITIALIZER;
 
 template <>
-BrowserContextKeyedAPIFactory<
-    ApiResourceManager<BluetoothLowEnergyConnection> >*
+BrowserContextKeyedAPIFactory<ApiResourceManager<BluetoothLowEnergyConnection>>*
 ApiResourceManager<BluetoothLowEnergyConnection>::GetFactoryInstance() {
   return g_factory.Pointer();
 }
@@ -27,11 +26,10 @@
       persistent_(persistent),
       connection_(connection.release()) {}
 
-BluetoothLowEnergyConnection::~BluetoothLowEnergyConnection() {
-}
+BluetoothLowEnergyConnection::~BluetoothLowEnergyConnection() {}
 
-device::BluetoothGattConnection*
-BluetoothLowEnergyConnection::GetConnection() const {
+device::BluetoothGattConnection* BluetoothLowEnergyConnection::GetConnection()
+    const {
   return connection_.get();
 }
 
diff --git a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_connection.h b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_connection.h
similarity index 84%
rename from chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_connection.h
rename to extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_connection.h
index 28e3d9d8..2e0357c 100644
--- a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_connection.h
+++ b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_connection.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_LOW_ENERGY_CONNECTION_H_
-#define CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_LOW_ENERGY_CONNECTION_H_
+#ifndef EXTENSIONS_BROWSER_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_LOW_ENERGY_CONNECTION_H_
+#define EXTENSIONS_BROWSER_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_LOW_ENERGY_CONNECTION_H_
 
 #include <memory>
 
@@ -51,4 +51,4 @@
 
 }  // namespace extensions
 
-#endif  // CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_LOW_ENERGY_CONNECTION_H_
+#endif  // EXTENSIONS_BROWSER_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_LOW_ENERGY_CONNECTION_H_
diff --git a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_event_router.cc b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.cc
similarity index 96%
rename from chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_event_router.cc
rename to extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.cc
index 7c687e0e..d81d40e9 100644
--- a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_event_router.cc
+++ b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.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 "chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h"
+#include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h"
 
 #include <algorithm>
 #include <iterator>
@@ -15,9 +15,6 @@
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
-#include "chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_connection.h"
-#include "chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_notify_session.h"
-#include "chrome/browser/extensions/api/bluetooth_low_energy/utils.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
@@ -28,6 +25,9 @@
 #include "device/bluetooth/bluetooth_remote_gatt_characteristic.h"
 #include "device/bluetooth/bluetooth_remote_gatt_descriptor.h"
 #include "extensions/browser/api/api_resource_manager.h"
+#include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_connection.h"
+#include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_notify_session.h"
+#include "extensions/browser/api/bluetooth_low_energy/utils.h"
 #include "extensions/browser/event_listener_map.h"
 #include "extensions/browser/event_router.h"
 #include "extensions/browser/extension_registry.h"
@@ -167,7 +167,8 @@
 }
 
 typedef extensions::ApiResourceManager<
-    extensions::BluetoothLowEnergyNotifySession> NotifySessionResourceManager;
+    extensions::BluetoothLowEnergyNotifySession>
+    NotifySessionResourceManager;
 NotifySessionResourceManager* GetNotifySessionResourceManager(
     content::BrowserContext* context) {
   NotifySessionResourceManager* manager =
@@ -293,8 +294,7 @@
 
   BluetoothAdapterFactory::GetAdapter(
       base::Bind(&BluetoothLowEnergyEventRouter::OnGetAdapter,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 callback));
+                 weak_ptr_factory_.GetWeakPtr(), callback));
   return true;
 }
 
@@ -346,15 +346,10 @@
   connecting_devices_.insert(connect_id);
   device->CreateGattConnection(
       base::Bind(&BluetoothLowEnergyEventRouter::OnCreateGattConnection,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 persistent,
-                 extension_id,
-                 device_address,
-                 callback),
+                 weak_ptr_factory_.GetWeakPtr(), persistent, extension_id,
+                 device_address, callback),
       base::Bind(&BluetoothLowEnergyEventRouter::OnConnectError,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 extension_id,
-                 device_address,
+                 weak_ptr_factory_.GetWeakPtr(), extension_id, device_address,
                  error_callback));
 }
 
@@ -644,11 +639,9 @@
 
   characteristic->ReadRemoteCharacteristic(
       base::Bind(&BluetoothLowEnergyEventRouter::OnValueSuccess,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 callback),
+                 weak_ptr_factory_.GetWeakPtr(), callback),
       base::Bind(&BluetoothLowEnergyEventRouter::OnError,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 error_callback));
+                 weak_ptr_factory_.GetWeakPtr(), error_callback));
 }
 
 void BluetoothLowEnergyEventRouter::WriteCharacteristicValue(
@@ -683,11 +676,9 @@
   }
 
   characteristic->WriteRemoteCharacteristic(
-      value,
-      callback,
+      value, callback,
       base::Bind(&BluetoothLowEnergyEventRouter::OnError,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 error_callback));
+                 weak_ptr_factory_.GetWeakPtr(), error_callback));
 }
 
 void BluetoothLowEnergyEventRouter::StartCharacteristicNotifications(
@@ -744,15 +735,10 @@
   pending_session_calls_.insert(session_id);
   characteristic->StartNotifySession(
       base::Bind(&BluetoothLowEnergyEventRouter::OnStartNotifySession,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 persistent,
-                 extension_id,
-                 instance_id,
-                 callback),
+                 weak_ptr_factory_.GetWeakPtr(), persistent, extension_id,
+                 instance_id, callback),
       base::Bind(&BluetoothLowEnergyEventRouter::OnStartNotifySessionError,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 extension_id,
-                 instance_id,
+                 weak_ptr_factory_.GetWeakPtr(), extension_id, instance_id,
                  error_callback));
 }
 
@@ -779,12 +765,9 @@
     return;
   }
 
-  session->GetSession()->Stop(
-      base::Bind(&BluetoothLowEnergyEventRouter::OnStopNotifySession,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 extension_id,
-                 instance_id,
-                 callback));
+  session->GetSession()->Stop(base::Bind(
+      &BluetoothLowEnergyEventRouter::OnStopNotifySession,
+      weak_ptr_factory_.GetWeakPtr(), extension_id, instance_id, callback));
 }
 
 void BluetoothLowEnergyEventRouter::ReadDescriptorValue(
@@ -818,11 +801,9 @@
 
   descriptor->ReadRemoteDescriptor(
       base::Bind(&BluetoothLowEnergyEventRouter::OnValueSuccess,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 callback),
+                 weak_ptr_factory_.GetWeakPtr(), callback),
       base::Bind(&BluetoothLowEnergyEventRouter::OnError,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 error_callback));
+                 weak_ptr_factory_.GetWeakPtr(), error_callback));
 }
 
 void BluetoothLowEnergyEventRouter::WriteDescriptorValue(
@@ -856,11 +837,9 @@
   }
 
   descriptor->WriteRemoteDescriptor(
-      value,
-      callback,
+      value, callback,
       base::Bind(&BluetoothLowEnergyEventRouter::OnError,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 error_callback));
+                 weak_ptr_factory_.GetWeakPtr(), error_callback));
 }
 
 void BluetoothLowEnergyEventRouter::SetAdapterForTesting(
@@ -1421,8 +1400,7 @@
   // Devices
   BluetoothAdapter::DeviceList devices = adapter_->GetDevices();
   for (BluetoothAdapter::DeviceList::iterator iter = devices.begin();
-       iter != devices.end();
-       ++iter) {
+       iter != devices.end(); ++iter) {
     BluetoothDevice* device = *iter;
 
     // Services
@@ -1813,8 +1791,7 @@
     return NULL;
 
   for (base::hash_set<int>::const_iterator iter = connection_ids->begin();
-       iter != connection_ids->end();
-       ++iter) {
+       iter != connection_ids->end(); ++iter) {
     extensions::BluetoothLowEnergyConnection* conn =
         manager->Get(extension_id, *iter);
     if (!conn)
@@ -1838,8 +1815,7 @@
     return false;
 
   for (base::hash_set<int>::const_iterator iter = connection_ids->begin();
-       iter != connection_ids->end();
-       ++iter) {
+       iter != connection_ids->end(); ++iter) {
     extensions::BluetoothLowEnergyConnection* conn =
         manager->Get(extension_id, *iter);
     if (!conn || conn->GetConnection()->GetDeviceAddress() != device_address)
@@ -1864,8 +1840,7 @@
     return NULL;
 
   for (base::hash_set<int>::const_iterator iter = ids->begin();
-       iter != ids->end();
-       ++iter) {
+       iter != ids->end(); ++iter) {
     BluetoothLowEnergyNotifySession* session =
         manager->Get(extension_id, *iter);
     if (!session)
@@ -1890,8 +1865,7 @@
     return false;
 
   for (base::hash_set<int>::const_iterator iter = ids->begin();
-       iter != ids->end();
-       ++iter) {
+       iter != ids->end(); ++iter) {
     BluetoothLowEnergyNotifySession* session =
         manager->Get(extension_id, *iter);
     if (!session ||
diff --git a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h
similarity index 98%
rename from chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h
rename to extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h
index a7e6c29..a06f33c 100644
--- a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h
+++ b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_LOW_ENERGY_EVENT_ROUTER_H_
-#define CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_LOW_ENERGY_EVENT_ROUTER_H_
+#ifndef EXTENSIONS_BROWSER_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_LOW_ENERGY_EVENT_ROUTER_H_
+#define EXTENSIONS_BROWSER_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_LOW_ENERGY_EVENT_ROUTER_H_
 
 #include <cstddef>
 #include <cstdint>
@@ -17,7 +17,6 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observer.h"
-#include "chrome/common/extensions/api/bluetooth_low_energy.h"
 #include "device/bluetooth/bluetooth_adapter.h"
 #include "device/bluetooth/bluetooth_device.h"
 #include "device/bluetooth/bluetooth_gatt_connection.h"
@@ -27,6 +26,7 @@
 #include "device/bluetooth/bluetooth_uuid.h"
 #include "extensions/browser/extension_event_histogram_value.h"
 #include "extensions/browser/extension_registry_observer.h"
+#include "extensions/common/api/bluetooth_low_energy.h"
 
 namespace base {
 
@@ -585,4 +585,4 @@
 
 }  // namespace extensions
 
-#endif  // CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_LOW_ENERGY_EVENT_ROUTER_H_
+#endif  // EXTENSIONS_BROWSER_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_LOW_ENERGY_EVENT_ROUTER_H_
diff --git a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_notify_session.cc b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_notify_session.cc
similarity index 79%
rename from chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_notify_session.cc
rename to extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_notify_session.cc
index 714a5bf..0d351a3 100644
--- a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_notify_session.cc
+++ b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_notify_session.cc
@@ -2,19 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_notify_session.h"
+#include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_notify_session.h"
 
 #include "base/lazy_instance.h"
 
 namespace extensions {
 
 static base::LazyInstance<BrowserContextKeyedAPIFactory<
-    ApiResourceManager<BluetoothLowEnergyNotifySession> > > g_factory =
-    LAZY_INSTANCE_INITIALIZER;
+    ApiResourceManager<BluetoothLowEnergyNotifySession>>>
+    g_factory = LAZY_INSTANCE_INITIALIZER;
 
 template <>
 BrowserContextKeyedAPIFactory<
-    ApiResourceManager<BluetoothLowEnergyNotifySession> >*
+    ApiResourceManager<BluetoothLowEnergyNotifySession>>*
 ApiResourceManager<BluetoothLowEnergyNotifySession>::GetFactoryInstance() {
   return g_factory.Pointer();
 }
@@ -27,8 +27,7 @@
       persistent_(persistent),
       session_(session.release()) {}
 
-BluetoothLowEnergyNotifySession::~BluetoothLowEnergyNotifySession() {
-}
+BluetoothLowEnergyNotifySession::~BluetoothLowEnergyNotifySession() {}
 
 device::BluetoothGattNotifySession*
 BluetoothLowEnergyNotifySession::GetSession() const {
diff --git a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_notify_session.h b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_notify_session.h
similarity index 84%
rename from chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_notify_session.h
rename to extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_notify_session.h
index b5a4cae..653b8bd 100644
--- a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_notify_session.h
+++ b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_notify_session.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_LOW_ENERGY_NOTIFY_SESSION_H_
-#define CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_LOW_ENERGY_NOTIFY_SESSION_H_
+#ifndef EXTENSIONS_BROWSER_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_LOW_ENERGY_NOTIFY_SESSION_H_
+#define EXTENSIONS_BROWSER_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_LOW_ENERGY_NOTIFY_SESSION_H_
 
 #include <memory>
 #include <string>
@@ -52,4 +52,4 @@
 
 }  // namespace extensions
 
-#endif  // CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_LOW_ENERGY_NOTIFY_SESSION_H_
+#endif  // EXTENSIONS_BROWSER_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_LOW_ENERGY_NOTIFY_SESSION_H_
diff --git a/chrome/browser/extensions/api/bluetooth_low_energy/utils.cc b/extensions/browser/api/bluetooth_low_energy/utils.cc
similarity index 94%
rename from chrome/browser/extensions/api/bluetooth_low_energy/utils.cc
rename to extensions/browser/api/bluetooth_low_energy/utils.cc
index 61befe6..5767b7a6 100644
--- a/chrome/browser/extensions/api/bluetooth_low_energy/utils.cc
+++ b/extensions/browser/api/bluetooth_low_energy/utils.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 "chrome/browser/extensions/api/bluetooth_low_energy/utils.h"
+#include "extensions/browser/api/bluetooth_low_energy/utils.h"
 
 #include <stddef.h>
 #include <iterator>
@@ -22,8 +22,7 @@
   std::unique_ptr<base::ListValue> property_list(new base::ListValue());
   for (std::vector<CharacteristicProperty>::const_iterator iter =
            properties.begin();
-       iter != properties.end();
-       ++iter)
+       iter != properties.end(); ++iter)
     property_list->AppendString(ToString(*iter));
   return property_list;
 }
diff --git a/chrome/browser/extensions/api/bluetooth_low_energy/utils.h b/extensions/browser/api/bluetooth_low_energy/utils.h
similarity index 80%
rename from chrome/browser/extensions/api/bluetooth_low_energy/utils.h
rename to extensions/browser/api/bluetooth_low_energy/utils.h
index 18821d7..ff1f770 100644
--- a/chrome/browser/extensions/api/bluetooth_low_energy/utils.h
+++ b/extensions/browser/api/bluetooth_low_energy/utils.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_LOW_ENERGY_UTILS_H_
-#define CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_LOW_ENERGY_UTILS_H_
+#ifndef EXTENSIONS_BROWSER_API_BLUETOOTH_LOW_ENERGY_UTILS_H_
+#define EXTENSIONS_BROWSER_API_BLUETOOTH_LOW_ENERGY_UTILS_H_
 
 #include <memory>
 
 #include "base/values.h"
-#include "chrome/common/extensions/api/bluetooth_low_energy.h"
+#include "extensions/common/api/bluetooth_low_energy.h"
 
 namespace extensions {
 namespace api {
@@ -33,4 +33,4 @@
 }  // namespace api
 }  // namespace extensions
 
-#endif  // CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_LOW_ENERGY_UTILS_H_
+#endif  // EXTENSIONS_BROWSER_API_BLUETOOTH_LOW_ENERGY_UTILS_H_
diff --git a/extensions/browser/api/runtime/runtime_api.cc b/extensions/browser/api/runtime/runtime_api.cc
index 559d5b6..7e08c04 100644
--- a/extensions/browser/api/runtime/runtime_api.cc
+++ b/extensions/browser/api/runtime/runtime_api.cc
@@ -21,7 +21,6 @@
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/child_process_security_policy.h"
-#include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "extensions/browser/api/runtime/runtime_api_delegate.h"
@@ -33,13 +32,13 @@
 #include "extensions/browser/extension_util.h"
 #include "extensions/browser/extensions_browser_client.h"
 #include "extensions/browser/lazy_background_task_queue.h"
-#include "extensions/browser/notification_types.h"
 #include "extensions/browser/process_manager_factory.h"
 #include "extensions/common/api/runtime.h"
 #include "extensions/common/error_utils.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/manifest_handlers/background_info.h"
 #include "extensions/common/manifest_handlers/shared_module_info.h"
+#include "extensions/common/one_shot_event.h"
 #include "storage/browser/fileapi/isolated_context.h"
 #include "url/gurl.h"
 
@@ -205,9 +204,9 @@
   // incognito.
   DCHECK(!browser_context_->IsOffTheRecord());
 
-  registrar_.Add(this,
-                 extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED,
-                 content::Source<BrowserContext>(context));
+  ExtensionSystem::Get(context)->ready().Post(
+      FROM_HERE, base::Bind(&RuntimeAPI::OnExtensionsReady,
+                            weak_ptr_factory_.GetWeakPtr()));
   extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
   process_manager_observer_.Add(ProcessManager::Get(browser_context_));
 
@@ -223,16 +222,6 @@
 RuntimeAPI::~RuntimeAPI() {
 }
 
-void RuntimeAPI::Observe(int type,
-                         const content::NotificationSource& source,
-                         const content::NotificationDetails& details) {
-  DCHECK_EQ(extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED, type);
-  // We're done restarting Chrome after an update.
-  dispatch_chrome_updated_event_ = false;
-
-  delegate_->AddUpdateObserver(this);
-}
-
 void RuntimeAPI::OnExtensionLoaded(content::BrowserContext* browser_context,
                                    const Extension* extension) {
   base::Version previous_version;
@@ -437,6 +426,12 @@
     restart_after_delay_timer_.Stop();
 }
 
+void RuntimeAPI::OnExtensionsReady() {
+  // We're done restarting Chrome after an update.
+  dispatch_chrome_updated_event_ = false;
+  delegate_->AddUpdateObserver(this);
+}
+
 RuntimeAPI::RestartAfterDelayStatus RuntimeAPI::ScheduleDelayedRestart(
     const base::Time& now,
     int seconds_from_now) {
diff --git a/extensions/browser/api/runtime/runtime_api.h b/extensions/browser/api/runtime/runtime_api.h
index cebaad7..e3329a4 100644
--- a/extensions/browser/api/runtime/runtime_api.h
+++ b/extensions/browser/api/runtime/runtime_api.h
@@ -11,8 +11,6 @@
 #include "base/scoped_observer.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
 #include "extensions/browser/api/runtime/runtime_api_delegate.h"
 #include "extensions/browser/browser_context_keyed_api_factory.h"
 #include "extensions/browser/extension_function.h"
@@ -48,7 +46,6 @@
 // extensions. There is one instance shared between a browser context and
 // its related incognito instance.
 class RuntimeAPI : public BrowserContextKeyedAPI,
-                   public content::NotificationObserver,
                    public ExtensionRegistryObserver,
                    public UpdateObserver,
                    public ProcessManagerObserver {
@@ -78,11 +75,6 @@
   explicit RuntimeAPI(content::BrowserContext* context);
   ~RuntimeAPI() override;
 
-  // content::NotificationObserver overrides:
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
-
   void ReloadExtension(const std::string& extension_id);
   bool CheckForUpdates(const std::string& extension_id,
                        const RuntimeAPIDelegate::UpdateCheckCallback& callback);
@@ -114,6 +106,9 @@
   // Cancels any previously scheduled restart request.
   void MaybeCancelRunningDelayedRestartTimer();
 
+  // Handler for the signal from ExtensionSystem::ready().
+  void OnExtensionsReady();
+
   RestartAfterDelayStatus ScheduleDelayedRestart(const base::Time& now,
                                                  int seconds_from_now);
 
diff --git a/extensions/browser/api/web_request/web_request_api.cc b/extensions/browser/api/web_request/web_request_api.cc
index 6179d96..ebc2b3e 100644
--- a/extensions/browser/api/web_request/web_request_api.cc
+++ b/extensions/browser/api/web_request/web_request_api.cc
@@ -25,6 +25,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/resource_request_info.h"
 #include "content/public/browser/user_metrics.h"
+#include "content/public/common/browser_side_navigation_policy.h"
 #include "content/public/common/child_process_host.h"
 #include "extensions/browser/api/activity_log/web_request_constants.h"
 #include "extensions/browser/api/declarative/rules_registry_service.h"
@@ -39,6 +40,7 @@
 #include "extensions/browser/api/web_request/web_request_time_tracker.h"
 #include "extensions/browser/api_activity_monitor.h"
 #include "extensions/browser/event_router.h"
+#include "extensions/browser/extension_navigation_ui_data.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
@@ -555,6 +557,7 @@
 int ExtensionWebRequestEventRouter::OnBeforeRequest(
     void* browser_context,
     const InfoMap* extension_info_map,
+    ExtensionNavigationUIData* navigation_ui_data,
     net::URLRequest* request,
     const net::CompletionCallback& callback,
     GURL* new_url) {
@@ -587,8 +590,9 @@
         CreateEventDetails(request, extra_info_spec));
     event_details->SetRequestBody(request);
 
-    initialize_blocked_requests |= DispatchEvent(
-        browser_context, request, listeners, std::move(event_details));
+    initialize_blocked_requests |=
+        DispatchEvent(browser_context, request, listeners, navigation_ui_data,
+                      std::move(event_details));
   }
 
   if (!initialize_blocked_requests)
@@ -614,6 +618,7 @@
 int ExtensionWebRequestEventRouter::OnBeforeSendHeaders(
     void* browser_context,
     const InfoMap* extension_info_map,
+    ExtensionNavigationUIData* navigation_ui_data,
     net::URLRequest* request,
     const net::CompletionCallback& callback,
     net::HttpRequestHeaders* headers) {
@@ -636,8 +641,9 @@
         CreateEventDetails(request, extra_info_spec));
     event_details->SetRequestHeaders(*headers);
 
-    initialize_blocked_requests |= DispatchEvent(
-        browser_context, request, listeners, std::move(event_details));
+    initialize_blocked_requests |=
+        DispatchEvent(browser_context, request, listeners, navigation_ui_data,
+                      std::move(event_details));
   }
 
   if (!initialize_blocked_requests)
@@ -663,6 +669,7 @@
 void ExtensionWebRequestEventRouter::OnSendHeaders(
     void* browser_context,
     const InfoMap* extension_info_map,
+    ExtensionNavigationUIData* navigation_ui_data,
     net::URLRequest* request,
     const net::HttpRequestHeaders& headers) {
   if (ShouldHideEvent(browser_context, extension_info_map, request))
@@ -684,12 +691,14 @@
       CreateEventDetails(request, extra_info_spec));
   event_details->SetRequestHeaders(headers);
 
-  DispatchEvent(browser_context, request, listeners, std::move(event_details));
+  DispatchEvent(browser_context, request, listeners, navigation_ui_data,
+                std::move(event_details));
 }
 
 int ExtensionWebRequestEventRouter::OnHeadersReceived(
     void* browser_context,
     const InfoMap* extension_info_map,
+    ExtensionNavigationUIData* navigation_ui_data,
     net::URLRequest* request,
     const net::CompletionCallback& callback,
     const net::HttpResponseHeaders* original_response_headers,
@@ -715,8 +724,9 @@
         CreateEventDetails(request, extra_info_spec));
     event_details->SetResponseHeaders(request, original_response_headers);
 
-    initialize_blocked_requests |= DispatchEvent(
-        browser_context, request, listeners, std::move(event_details));
+    initialize_blocked_requests |=
+        DispatchEvent(browser_context, request, listeners, navigation_ui_data,
+                      std::move(event_details));
   }
 
   if (!initialize_blocked_requests)
@@ -745,6 +755,7 @@
 ExtensionWebRequestEventRouter::OnAuthRequired(
     void* browser_context,
     const InfoMap* extension_info_map,
+    ExtensionNavigationUIData* navigation_ui_data,
     net::URLRequest* request,
     const net::AuthChallengeInfo& auth_info,
     const net::NetworkDelegate::AuthCallback& callback,
@@ -768,7 +779,7 @@
   event_details->SetResponseHeaders(request, request->response_headers());
   event_details->SetAuthInfo(auth_info);
 
-  if (DispatchEvent(browser_context, request, listeners,
+  if (DispatchEvent(browser_context, request, listeners, navigation_ui_data,
                     std::move(event_details))) {
     BlockedRequest& blocked_request = blocked_requests_[request->identifier()];
     blocked_request.event = kOnAuthRequired;
@@ -785,6 +796,7 @@
 void ExtensionWebRequestEventRouter::OnBeforeRedirect(
     void* browser_context,
     const InfoMap* extension_info_map,
+    ExtensionNavigationUIData* navigation_ui_data,
     net::URLRequest* request,
     const GURL& new_location) {
   if (ShouldHideEvent(browser_context, extension_info_map, request))
@@ -811,12 +823,14 @@
   event_details->SetResponseSource(request);
   event_details->SetString(keys::kRedirectUrlKey, new_location.spec());
 
-  DispatchEvent(browser_context, request, listeners, std::move(event_details));
+  DispatchEvent(browser_context, request, listeners, navigation_ui_data,
+                std::move(event_details));
 }
 
 void ExtensionWebRequestEventRouter::OnResponseStarted(
     void* browser_context,
     const InfoMap* extension_info_map,
+    ExtensionNavigationUIData* navigation_ui_data,
     net::URLRequest* request,
     int net_error) {
   DCHECK_NE(net::ERR_IO_PENDING, net_error);
@@ -840,7 +854,8 @@
   event_details->SetResponseHeaders(request, request->response_headers());
   event_details->SetResponseSource(request);
 
-  DispatchEvent(browser_context, request, listeners, std::move(event_details));
+  DispatchEvent(browser_context, request, listeners, navigation_ui_data,
+                std::move(event_details));
 }
 
 // Deprecated.
@@ -848,14 +863,16 @@
 void ExtensionWebRequestEventRouter::OnResponseStarted(
     void* browser_context,
     const InfoMap* extension_info_map,
+    ExtensionNavigationUIData* navigation_ui_data,
     net::URLRequest* request) {
-  OnResponseStarted(browser_context, extension_info_map, request,
-                    request->status().error());
+  OnResponseStarted(browser_context, extension_info_map, navigation_ui_data,
+                    request, request->status().error());
 }
 
 void ExtensionWebRequestEventRouter::OnCompleted(
     void* browser_context,
     const InfoMap* extension_info_map,
+    ExtensionNavigationUIData* navigation_ui_data,
     net::URLRequest* request,
     int net_error) {
   // We hide events from the system context as well as sensitive requests.
@@ -889,7 +906,8 @@
   event_details->SetResponseHeaders(request, request->response_headers());
   event_details->SetResponseSource(request);
 
-  DispatchEvent(browser_context, request, listeners, std::move(event_details));
+  DispatchEvent(browser_context, request, listeners, navigation_ui_data,
+                std::move(event_details));
 }
 
 // Deprecated.
@@ -897,14 +915,16 @@
 void ExtensionWebRequestEventRouter::OnCompleted(
     void* browser_context,
     const InfoMap* extension_info_map,
+    ExtensionNavigationUIData* navigation_ui_data,
     net::URLRequest* request) {
-  OnCompleted(browser_context, extension_info_map, request,
+  OnCompleted(browser_context, extension_info_map, navigation_ui_data, request,
               request->status().error());
 }
 
 void ExtensionWebRequestEventRouter::OnErrorOccurred(
     void* browser_context,
     const InfoMap* extension_info_map,
+    ExtensionNavigationUIData* navigation_ui_data,
     net::URLRequest* request,
     bool started,
     int net_error) {
@@ -943,16 +963,18 @@
     event_details->SetBoolean(keys::kFromCache, request->was_cached());
   event_details->SetString(keys::kErrorKey, net::ErrorToString(net_error));
 
-  DispatchEvent(browser_context, request, listeners, std::move(event_details));
+  DispatchEvent(browser_context, request, listeners, navigation_ui_data,
+                std::move(event_details));
 }
 
 void ExtensionWebRequestEventRouter::OnErrorOccurred(
     void* browser_context,
     const InfoMap* extension_info_map,
+    ExtensionNavigationUIData* navigation_ui_data,
     net::URLRequest* request,
     bool started) {
-  OnErrorOccurred(browser_context, extension_info_map, request, started,
-                  request->status().error());
+  OnErrorOccurred(browser_context, extension_info_map, navigation_ui_data,
+                  request, started, request->status().error());
 }
 
 void ExtensionWebRequestEventRouter::OnURLRequestDestroyed(
@@ -975,6 +997,7 @@
     void* browser_context,
     net::URLRequest* request,
     const RawListeners& listeners,
+    ExtensionNavigationUIData* navigation_ui_data,
     std::unique_ptr<WebRequestEventDetails> event_details) {
   // TODO(mpcomplete): Consider consolidating common (extension_id,json_args)
   // pairs into a single message sent to a list of sub_event_names.
@@ -1001,9 +1024,28 @@
     }
   }
 
-  event_details.release()->DetermineFrameDataOnIO(base::Bind(
-      &ExtensionWebRequestEventRouter::DispatchEventToListeners, AsWeakPtr(),
-      browser_context, base::Passed(&listeners_to_dispatch)));
+  // PlzNavigate: if this request corresponds to a navigation, use the
+  // NavigationUIData that was provided to the navigation on the UI thread to
+  // get the FrameData.
+  // For subresources loads, the request is first received on the IO thread,
+  // therefore a construct such as the NavigationUIData cannot be used. Instead,
+  // use the map of FrameData with the ids of the renderer that sent the
+  // request.
+  // Note: it's possible for ResourceRequestInfo to be null in certain cases
+  // (eg when created by a URLFetcher instead of the ResourceDispatcherHost).
+  const content::ResourceRequestInfo* info =
+      content::ResourceRequestInfo::ForRequest(request);
+  if (content::IsBrowserSideNavigationEnabled() && info &&
+      IsResourceTypeFrame(info->GetResourceType())) {
+    DCHECK(navigation_ui_data);
+    event_details->SetFrameData(navigation_ui_data->frame_data());
+    DispatchEventToListeners(browser_context, std::move(listeners_to_dispatch),
+                             std::move(event_details));
+  } else {
+    event_details.release()->DetermineFrameDataOnIO(base::Bind(
+        &ExtensionWebRequestEventRouter::DispatchEventToListeners, AsWeakPtr(),
+        browser_context, base::Passed(&listeners_to_dispatch)));
+  }
 
   if (num_handlers_blocking > 0) {
     BlockedRequest& blocked_request = blocked_requests_[request->identifier()];
diff --git a/extensions/browser/api/web_request/web_request_api.h b/extensions/browser/api/web_request/web_request_api.h
index a1074ce..e0051e6 100644
--- a/extensions/browser/api/web_request/web_request_api.h
+++ b/extensions/browser/api/web_request/web_request_api.h
@@ -57,6 +57,7 @@
 
 namespace extensions {
 
+class ExtensionNavigationUIData;
 class InfoMap;
 class WebRequestEventDetails;
 class WebRequestRulesRegistry;
@@ -171,6 +172,7 @@
   // intercepting the request, OK otherwise.
   int OnBeforeRequest(void* browser_context,
                       const extensions::InfoMap* extension_info_map,
+                      ExtensionNavigationUIData* navigation_ui_data,
                       net::URLRequest* request,
                       const net::CompletionCallback& callback,
                       GURL* new_url);
@@ -181,6 +183,7 @@
   // otherwise.
   int OnBeforeSendHeaders(void* browser_context,
                           const extensions::InfoMap* extension_info_map,
+                          ExtensionNavigationUIData* navigation_ui_data,
                           net::URLRequest* request,
                           const net::CompletionCallback& callback,
                           net::HttpRequestHeaders* headers);
@@ -189,6 +192,7 @@
   // only.
   void OnSendHeaders(void* browser_context,
                      const extensions::InfoMap* extension_info_map,
+                     ExtensionNavigationUIData* navigation_ui_data,
                      net::URLRequest* request,
                      const net::HttpRequestHeaders& headers);
 
@@ -204,6 +208,7 @@
   int OnHeadersReceived(
       void* browser_context,
       const extensions::InfoMap* extension_info_map,
+      ExtensionNavigationUIData* navigation_ui_data,
       net::URLRequest* request,
       const net::CompletionCallback& callback,
       const net::HttpResponseHeaders* original_response_headers,
@@ -218,6 +223,7 @@
   net::NetworkDelegate::AuthRequiredResponse OnAuthRequired(
       void* browser_context,
       const extensions::InfoMap* extension_info_map,
+      ExtensionNavigationUIData* navigation_ui_data,
       net::URLRequest* request,
       const net::AuthChallengeInfo& auth_info,
       const net::NetworkDelegate::AuthCallback& callback,
@@ -227,6 +233,7 @@
   // only.
   void OnBeforeRedirect(void* browser_context,
                         const extensions::InfoMap* extension_info_map,
+                        ExtensionNavigationUIData* navigation_ui_data,
                         net::URLRequest* request,
                         const GURL& new_location);
 
@@ -234,28 +241,33 @@
   // the response have arrived.
   void OnResponseStarted(void* browser_context,
                          const extensions::InfoMap* extension_info_map,
+                         ExtensionNavigationUIData* navigation_ui_data,
                          net::URLRequest* request,
                          int net_error);
   // Deprecated.
   // TODO(maksims): Remove this.
   void OnResponseStarted(void* browser_context,
                          const extensions::InfoMap* extension_info_map,
+                         ExtensionNavigationUIData* navigation_ui_data,
                          net::URLRequest* request);
 
   // Dispatches the onComplete event.
   void OnCompleted(void* browser_context,
                    const extensions::InfoMap* extension_info_map,
+                   ExtensionNavigationUIData* navigation_ui_data,
                    net::URLRequest* request,
                    int net_error);
   // Deprecated.
   // TODO(maksims): Remove this.
   void OnCompleted(void* browser_context,
                    const extensions::InfoMap* extension_info_map,
+                   ExtensionNavigationUIData* navigation_ui_data,
                    net::URLRequest* request);
 
   // Dispatches an onErrorOccurred event.
   void OnErrorOccurred(void* browser_context,
                        const extensions::InfoMap* extension_info_map,
+                       ExtensionNavigationUIData* navigation_ui_data,
                        net::URLRequest* request,
                        bool started,
                        int net_error);
@@ -263,6 +275,7 @@
   // TODO(maksims): Remove this.
   void OnErrorOccurred(void* browser_context,
                        const extensions::InfoMap* extension_info_map,
+                       ExtensionNavigationUIData* navigation_ui_data,
                        net::URLRequest* request,
                        bool started);
 
@@ -409,6 +422,7 @@
   bool DispatchEvent(void* browser_context,
                      net::URLRequest* request,
                      const RawListeners& listener_ids,
+                     ExtensionNavigationUIData* navigation_ui_data,
                      std::unique_ptr<WebRequestEventDetails> event_details);
 
   void DispatchEventToListeners(
diff --git a/extensions/browser/api/web_request/web_request_event_details.cc b/extensions/browser/api/web_request/web_request_event_details.cc
index 56ec81f..a0ba5ba505 100644
--- a/extensions/browser/api/web_request/web_request_event_details.cc
+++ b/extensions/browser/api/web_request/web_request_event_details.cc
@@ -154,16 +154,20 @@
     dict_.SetString(keys::kIpKey, response_ip);
 }
 
+void WebRequestEventDetails::SetFrameData(
+    const ExtensionApiFrameIdMap::FrameData& frame_data) {
+  dict_.SetInteger(keys::kTabIdKey, frame_data.tab_id);
+  dict_.SetInteger(keys::kFrameIdKey, frame_data.frame_id);
+  dict_.SetInteger(keys::kParentFrameIdKey, frame_data.parent_frame_id);
+}
+
 void WebRequestEventDetails::DetermineFrameDataOnUI() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   content::RenderFrameHost* rfh =
       content::RenderFrameHost::FromID(render_process_id_, render_frame_id_);
   ExtensionApiFrameIdMap::FrameData frame_data =
       ExtensionApiFrameIdMap::Get()->GetFrameData(rfh);
-
-  dict_.SetInteger(keys::kTabIdKey, frame_data.tab_id);
-  dict_.SetInteger(keys::kFrameIdKey, frame_data.frame_id);
-  dict_.SetInteger(keys::kParentFrameIdKey, frame_data.parent_frame_id);
+  SetFrameData(frame_data);
 }
 
 void WebRequestEventDetails::DetermineFrameDataOnIO(
@@ -198,9 +202,7 @@
     std::unique_ptr<WebRequestEventDetails> self,
     const DeterminedFrameDataCallback& callback,
     const ExtensionApiFrameIdMap::FrameData& frame_data) {
-  dict_.SetInteger(keys::kTabIdKey, frame_data.tab_id);
-  dict_.SetInteger(keys::kFrameIdKey, frame_data.frame_id);
-  dict_.SetInteger(keys::kParentFrameIdKey, frame_data.parent_frame_id);
+  SetFrameData(frame_data);
   callback.Run(std::move(self));
 }
 
diff --git a/extensions/browser/api/web_request/web_request_event_details.h b/extensions/browser/api/web_request/web_request_event_details.h
index 200e28e..9bc73d1 100644
--- a/extensions/browser/api/web_request/web_request_event_details.h
+++ b/extensions/browser/api/web_request/web_request_event_details.h
@@ -88,6 +88,12 @@
     dict_.SetString(key, value);
   }
 
+  // Sets the following keys using the value provided.
+  // - tabId
+  // - frameId
+  // - parentFrameId
+  void SetFrameData(const ExtensionApiFrameIdMap::FrameData& frame_data);
+
   // Sets the following keys using information from constructor.
   // - tabId
   // - frameId
diff --git a/extensions/browser/extension_navigation_ui_data.cc b/extensions/browser/extension_navigation_ui_data.cc
new file mode 100644
index 0000000..c7576ba1
--- /dev/null
+++ b/extensions/browser/extension_navigation_ui_data.cc
@@ -0,0 +1,34 @@
+// 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.
+
+#include "extensions/browser/extension_navigation_ui_data.h"
+
+#include "content/public/browser/navigation_handle.h"
+
+namespace extensions {
+
+ExtensionNavigationUIData::ExtensionNavigationUIData() {}
+
+ExtensionNavigationUIData::ExtensionNavigationUIData(
+    content::NavigationHandle* navigation_handle,
+    int tab_id,
+    int window_id) {
+  // TODO(clamy): See if it would be possible to have just one source for the
+  // FrameData that works both for navigations and subresources loads.
+  frame_data_.frame_id = ExtensionApiFrameIdMap::GetFrameId(navigation_handle);
+  frame_data_.parent_frame_id =
+      ExtensionApiFrameIdMap::GetParentFrameId(navigation_handle);
+  frame_data_.tab_id = tab_id;
+  frame_data_.window_id = window_id;
+}
+
+std::unique_ptr<ExtensionNavigationUIData> ExtensionNavigationUIData::DeepCopy()
+    const {
+  std::unique_ptr<ExtensionNavigationUIData> copy(
+      new ExtensionNavigationUIData());
+  copy->set_frame_data(frame_data_);
+  return copy;
+}
+
+}  // namespace extensions
diff --git a/extensions/browser/extension_navigation_ui_data.h b/extensions/browser/extension_navigation_ui_data.h
new file mode 100644
index 0000000..b514568
--- /dev/null
+++ b/extensions/browser/extension_navigation_ui_data.h
@@ -0,0 +1,46 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_BROWSER_EXTENSION_NAVIGATION_UI_DATA_H_
+#define EXTENSIONS_BROWSER_EXTENSION_NAVIGATION_UI_DATA_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "extensions/browser/extension_api_frame_id_map.h"
+
+namespace content {
+class NavigationHandle;
+}
+
+namespace extensions {
+
+// PlzNavigate: initialized on the UI thread for all navigations. A copy is used
+// on the IO thread by the WebRequest API to access to the FrameData.
+class ExtensionNavigationUIData {
+ public:
+  ExtensionNavigationUIData();
+  ExtensionNavigationUIData(content::NavigationHandle* navigation_handle,
+                            int tab_id,
+                            int window_id);
+
+  std::unique_ptr<ExtensionNavigationUIData> DeepCopy() const;
+
+  const ExtensionApiFrameIdMap::FrameData& frame_data() const {
+    return frame_data_;
+  }
+
+ private:
+  void set_frame_data(const ExtensionApiFrameIdMap::FrameData& frame_data) {
+    frame_data_ = frame_data;
+  }
+
+  ExtensionApiFrameIdMap::FrameData frame_data_;
+
+  DISALLOW_COPY_AND_ASSIGN(ExtensionNavigationUIData);
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_EXTENSION_NAVIGATION_UI_DATA_H_
diff --git a/extensions/browser/extensions_browser_client.h b/extensions/browser/extensions_browser_client.h
index 9fa0a88..c27ae73 100644
--- a/extensions/browser/extensions_browser_client.h
+++ b/extensions/browser/extensions_browser_client.h
@@ -56,6 +56,7 @@
 class ExtensionSystemProvider;
 class ExtensionWebContentsObserver;
 class InfoMap;
+class KioskDelegate;
 class ProcessManagerDelegate;
 class RuntimeAPIDelegate;
 
@@ -255,6 +256,9 @@
   // Returns true if activity logging is enabled for the given |context|.
   virtual bool IsActivityLoggingEnabled(content::BrowserContext* context);
 
+  // Returns a delegate that provides kiosk mode functionality.
+  virtual KioskDelegate* GetKioskDelegate() = 0;
+
   // Returns the single instance of |this|.
   static ExtensionsBrowserClient* Get();
 
diff --git a/extensions/browser/kiosk/BUILD.gn b/extensions/browser/kiosk/BUILD.gn
new file mode 100644
index 0000000..39801fd
--- /dev/null
+++ b/extensions/browser/kiosk/BUILD.gn
@@ -0,0 +1,10 @@
+# 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.
+
+source_set("kiosk") {
+  sources = [
+    "kiosk_delegate.cc",
+    "kiosk_delegate.h",
+  ]
+}
diff --git a/extensions/browser/kiosk/kiosk_delegate.cc b/extensions/browser/kiosk/kiosk_delegate.cc
new file mode 100644
index 0000000..e517f9de7
--- /dev/null
+++ b/extensions/browser/kiosk/kiosk_delegate.cc
@@ -0,0 +1,13 @@
+// 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.
+
+#include "extensions/browser/kiosk/kiosk_delegate.h"
+
+namespace extensions {
+
+KioskDelegate::KioskDelegate() {}
+
+KioskDelegate::~KioskDelegate() {}
+
+}  // namespace extensions
diff --git a/extensions/browser/kiosk/kiosk_delegate.h b/extensions/browser/kiosk/kiosk_delegate.h
new file mode 100644
index 0000000..cc3d0af
--- /dev/null
+++ b/extensions/browser/kiosk/kiosk_delegate.h
@@ -0,0 +1,28 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_BROWSER_KIOSK_KIOSK_DELEGATE_H_
+#define EXTENSIONS_BROWSER_KIOSK_KIOSK_DELEGATE_H_
+
+#include "extensions/common/extension_id.h"
+
+namespace extensions {
+
+// Delegate to provide various Kiosk mode functionality. At some point, we'll
+// have the KioskAppManager outside of Chrome. We can then directly use it as
+// a delegate but till then, this class is mostly a wrapper to it.
+// Note: Kiosk mode is not supported on other platforms but this delegate
+// needs to exist since on AppShell, KioskMode will exist on multiple
+// platforms.
+class KioskDelegate {
+ public:
+  KioskDelegate();
+  virtual ~KioskDelegate();
+
+  virtual bool IsAutoLaunchedKioskApp(const ExtensionId& id) const = 0;
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_KIOSK_KIOSK_DELEGATE_H_
diff --git a/extensions/browser/test_extensions_browser_client.cc b/extensions/browser/test_extensions_browser_client.cc
index ca3875b..32bcfce5 100644
--- a/extensions/browser/test_extensions_browser_client.cc
+++ b/extensions/browser/test_extensions_browser_client.cc
@@ -205,6 +205,10 @@
   return nullptr;
 }
 
+KioskDelegate* TestExtensionsBrowserClient::GetKioskDelegate() {
+  return nullptr;
+}
+
 scoped_refptr<update_client::UpdateClient>
 TestExtensionsBrowserClient::CreateUpdateClient(
     content::BrowserContext* context) {
diff --git a/extensions/browser/test_extensions_browser_client.h b/extensions/browser/test_extensions_browser_client.h
index 990ab0e..ee572fa 100644
--- a/extensions/browser/test_extensions_browser_client.h
+++ b/extensions/browser/test_extensions_browser_client.h
@@ -19,6 +19,7 @@
 #include "extensions/browser/updater/extension_cache.h"
 
 namespace extensions {
+class KioskDelegate;
 
 // A simplified ExtensionsBrowserClient for a single normal browser context and
 // an optional incognito browser context associated with it. A test that uses
@@ -109,6 +110,7 @@
   bool IsMinBrowserVersionSupported(const std::string& min_version) override;
   ExtensionWebContentsObserver* GetExtensionWebContentsObserver(
       content::WebContents* web_contents) override;
+  KioskDelegate* GetKioskDelegate() override;
   scoped_refptr<update_client::UpdateClient> CreateUpdateClient(
       content::BrowserContext* context) override;
 
diff --git a/extensions/common/api/BUILD.gn b/extensions/common/api/BUILD.gn
index 0276c57..010da6db 100644
--- a/extensions/common/api/BUILD.gn
+++ b/extensions/common/api/BUILD.gn
@@ -16,6 +16,7 @@
   "app_window.idl",
   "audio.idl",
   "bluetooth.idl",
+  "bluetooth_low_energy.idl",
   "bluetooth_private.idl",
   "bluetooth_socket.idl",
   "cast_channel.idl",
diff --git a/chrome/common/extensions/api/bluetooth_low_energy.idl b/extensions/common/api/bluetooth_low_energy.idl
similarity index 100%
rename from chrome/common/extensions/api/bluetooth_low_energy.idl
rename to extensions/common/api/bluetooth_low_energy.idl
diff --git a/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder_svc.cc b/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder_svc.cc
index cf81ae5..8c57b5c 100644
--- a/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder_svc.cc
+++ b/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder_svc.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/task_runner_util.h"
+#include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder.h"
 #include "third_party/openh264/src/codec/api/svc/codec_api.h"
diff --git a/extensions/renderer/scoped_web_frame.cc b/extensions/renderer/scoped_web_frame.cc
index e2e0111..60066b3 100644
--- a/extensions/renderer/scoped_web_frame.cc
+++ b/extensions/renderer/scoped_web_frame.cc
@@ -10,14 +10,13 @@
 
 ScopedWebFrame::ScopedWebFrame() : view_(nullptr), frame_(nullptr) {
   view_ = blink::WebView::create(nullptr, blink::WebPageVisibilityStateVisible);
-  frame_ = blink::WebLocalFrame::create(
-      blink::WebTreeScopeType::Document, nullptr);
+  frame_ = blink::WebLocalFrame::create(blink::WebTreeScopeType::Document,
+                                        &frame_client_);
   view_->setMainFrame(frame_);
 }
 
 ScopedWebFrame::~ScopedWebFrame() {
   view_->close();
-  frame_->close();
   blink::WebHeap::collectAllGarbageForTesting();
 }
 
diff --git a/extensions/renderer/scoped_web_frame.h b/extensions/renderer/scoped_web_frame.h
index 948a289..ebcc877 100644
--- a/extensions/renderer/scoped_web_frame.h
+++ b/extensions/renderer/scoped_web_frame.h
@@ -6,6 +6,7 @@
 #define SCOPED_WEB_FRAME_H_
 
 #include "base/macros.h"
+#include "third_party/WebKit/public/web/WebFrameClient.h"
 #include "third_party/WebKit/public/web/WebLocalFrame.h"
 #include "third_party/WebKit/public/web/WebView.h"
 
@@ -21,12 +22,15 @@
   blink::WebLocalFrame* frame() { return frame_; }
 
 private:
-  // The webview and the frame are kept alive by the ScopedWebFrame
-  // because they are not destructed unless ~ScopedWebFrame explicitly
-  // closes the webview and the frame.
-  blink::WebView* view_;
-  blink::WebLocalFrame* frame_;
-  DISALLOW_COPY_AND_ASSIGN(ScopedWebFrame);
+ blink::WebFrameClient frame_client_;
+
+ // The webview and the frame are kept alive by the ScopedWebFrame
+ // because they are not destructed unless ~ScopedWebFrame explicitly
+ // closes the WebView.
+ blink::WebView* view_;
+ blink::WebLocalFrame* frame_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedWebFrame);
 };
 
 }  // namespace extensions
diff --git a/extensions/shell/BUILD.gn b/extensions/shell/BUILD.gn
index 2be94d5..eddb55e1 100644
--- a/extensions/shell/BUILD.gn
+++ b/extensions/shell/BUILD.gn
@@ -42,6 +42,7 @@
     "//extensions:extensions_resources",
     "//extensions:shell_and_test_pak",
     "//extensions/browser",
+    "//extensions/browser/kiosk",
     "//extensions/common",
     "//extensions/common/api",
     "//extensions/common/api:api_registration",
@@ -67,6 +68,8 @@
     "browser/api/identity/identity_api.h",
     "browser/default_shell_browser_main_delegate.cc",
     "browser/default_shell_browser_main_delegate.h",
+    "browser/delegates/shell_kiosk_delegate.cc",
+    "browser/delegates/shell_kiosk_delegate.h",
     "browser/desktop_controller.cc",
     "browser/desktop_controller.h",
     "browser/media_capture_util.cc",
diff --git a/extensions/shell/browser/delegates/shell_kiosk_delegate.cc b/extensions/shell/browser/delegates/shell_kiosk_delegate.cc
new file mode 100644
index 0000000..f265461
--- /dev/null
+++ b/extensions/shell/browser/delegates/shell_kiosk_delegate.cc
@@ -0,0 +1,19 @@
+// 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.
+
+#include "extensions/shell/browser/delegates/shell_kiosk_delegate.h"
+
+namespace extensions {
+
+ShellKioskDelegate::ShellKioskDelegate() {}
+
+ShellKioskDelegate::~ShellKioskDelegate() {}
+
+bool ShellKioskDelegate::IsAutoLaunchedKioskApp(const ExtensionId& id) const {
+  // Every app in AppShell is auto-launched and AppShell only runs in
+  // kiosk mode.
+  return true;
+}
+
+}  // namespace extensions
diff --git a/extensions/shell/browser/delegates/shell_kiosk_delegate.h b/extensions/shell/browser/delegates/shell_kiosk_delegate.h
new file mode 100644
index 0000000..f2be390d
--- /dev/null
+++ b/extensions/shell/browser/delegates/shell_kiosk_delegate.h
@@ -0,0 +1,26 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_SHELL_BROWSER_DELEGATES_SHELL_KIOSK_DELEGATE_H_
+#define EXTENSIONS_SHELL_BROWSER_DELEGATES_SHELL_KIOSK_DELEGATE_H_
+
+#include "extensions/browser/kiosk/kiosk_delegate.h"
+#include "extensions/common/extension_id.h"
+
+namespace extensions {
+
+// Delegate in AppShell that provides an extension/app API with Kiosk mode
+// functionality.
+class ShellKioskDelegate : public KioskDelegate {
+ public:
+  ShellKioskDelegate();
+  ~ShellKioskDelegate() override;
+
+  // KioskDelegate overrides:
+  bool IsAutoLaunchedKioskApp(const ExtensionId& id) const override;
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_SHELL_BROWSER_DELEGATES_SHELL_KIOSK_DELEGATE_H_
diff --git a/extensions/shell/browser/shell_extensions_api_client.cc b/extensions/shell/browser/shell_extensions_api_client.cc
index 527b883..f01d7c7e 100644
--- a/extensions/shell/browser/shell_extensions_api_client.cc
+++ b/extensions/shell/browser/shell_extensions_api_client.cc
@@ -4,6 +4,7 @@
 
 #include "extensions/shell/browser/shell_extensions_api_client.h"
 
+#include "extensions/shell/browser/delegates/shell_kiosk_delegate.h"
 #include "extensions/shell/browser/shell_app_view_guest_delegate.h"
 #include "extensions/shell/browser/shell_extension_web_contents_observer.h"
 
diff --git a/extensions/shell/browser/shell_extensions_browser_client.cc b/extensions/shell/browser/shell_extensions_browser_client.cc
index 6a935ed..e832a94 100644
--- a/extensions/shell/browser/shell_extensions_browser_client.cc
+++ b/extensions/shell/browser/shell_extensions_browser_client.cc
@@ -20,6 +20,7 @@
 #include "extensions/browser/updater/null_extension_cache.h"
 #include "extensions/browser/url_request_util.h"
 #include "extensions/shell/browser/api/generated_api_registration.h"
+#include "extensions/shell/browser/delegates/shell_kiosk_delegate.h"
 #include "extensions/shell/browser/shell_extension_host_delegate.h"
 #include "extensions/shell/browser/shell_extension_system_factory.h"
 #include "extensions/shell/browser/shell_extension_web_contents_observer.h"
@@ -244,4 +245,10 @@
   return ShellExtensionWebContentsObserver::FromWebContents(web_contents);
 }
 
+KioskDelegate* ShellExtensionsBrowserClient::GetKioskDelegate() {
+  if (!kiosk_delegate_)
+    kiosk_delegate_.reset(new ShellKioskDelegate());
+  return kiosk_delegate_.get();
+}
+
 }  // namespace extensions
diff --git a/extensions/shell/browser/shell_extensions_browser_client.h b/extensions/shell/browser/shell_extensions_browser_client.h
index 94f2288..b76ece2 100644
--- a/extensions/shell/browser/shell_extensions_browser_client.h
+++ b/extensions/shell/browser/shell_extensions_browser_client.h
@@ -11,6 +11,7 @@
 #include "base/macros.h"
 #include "build/build_config.h"
 #include "extensions/browser/extensions_browser_client.h"
+#include "extensions/browser/kiosk/kiosk_delegate.h"
 
 class PrefService;
 
@@ -91,6 +92,7 @@
   bool IsMinBrowserVersionSupported(const std::string& min_version) override;
   ExtensionWebContentsObserver* GetExtensionWebContentsObserver(
       content::WebContents* web_contents) override;
+  KioskDelegate* GetKioskDelegate() override;
 
   // Sets the API client.
   void SetAPIClientForTest(ExtensionsAPIClient* api_client);
@@ -108,6 +110,8 @@
   // The extension cache used for download and installation.
   std::unique_ptr<ExtensionCache> extension_cache_;
 
+  std::unique_ptr<KioskDelegate> kiosk_delegate_;
+
   DISALLOW_COPY_AND_ASSIGN(ShellExtensionsBrowserClient);
 };
 
diff --git a/extensions/shell/browser/shell_network_delegate.cc b/extensions/shell/browser/shell_network_delegate.cc
index 51ea88a..3a3ebdd 100644
--- a/extensions/shell/browser/shell_network_delegate.cc
+++ b/extensions/shell/browser/shell_network_delegate.cc
@@ -35,7 +35,8 @@
     const net::CompletionCallback& callback,
     GURL* new_url) {
   return ExtensionWebRequestEventRouter::GetInstance()->OnBeforeRequest(
-      browser_context_, extension_info_map_.get(), request, callback, new_url);
+      browser_context_, extension_info_map_.get(), nullptr, request, callback,
+      new_url);
 }
 
 int ShellNetworkDelegate::OnBeforeStartTransaction(
@@ -43,14 +44,15 @@
     const net::CompletionCallback& callback,
     net::HttpRequestHeaders* headers) {
   return ExtensionWebRequestEventRouter::GetInstance()->OnBeforeSendHeaders(
-      browser_context_, extension_info_map_.get(), request, callback, headers);
+      browser_context_, extension_info_map_.get(), nullptr, request, callback,
+      headers);
 }
 
 void ShellNetworkDelegate::OnStartTransaction(
     net::URLRequest* request,
     const net::HttpRequestHeaders& headers) {
   ExtensionWebRequestEventRouter::GetInstance()->OnSendHeaders(
-      browser_context_, extension_info_map_.get(), request, headers);
+      browser_context_, extension_info_map_.get(), nullptr, request, headers);
 }
 
 int ShellNetworkDelegate::OnHeadersReceived(
@@ -60,12 +62,8 @@
     scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
     GURL* allowed_unsafe_redirect_url) {
   return ExtensionWebRequestEventRouter::GetInstance()->OnHeadersReceived(
-      browser_context_,
-      extension_info_map_.get(),
-      request,
-      callback,
-      original_response_headers,
-      override_response_headers,
+      browser_context_, extension_info_map_.get(), nullptr, request, callback,
+      original_response_headers, override_response_headers,
       allowed_unsafe_redirect_url);
 }
 
@@ -73,13 +71,14 @@
     net::URLRequest* request,
     const GURL& new_location) {
   ExtensionWebRequestEventRouter::GetInstance()->OnBeforeRedirect(
-      browser_context_, extension_info_map_.get(), request, new_location);
+      browser_context_, extension_info_map_.get(), nullptr, request,
+      new_location);
 }
 
 void ShellNetworkDelegate::OnResponseStarted(net::URLRequest* request,
                                              int net_error) {
   ExtensionWebRequestEventRouter::GetInstance()->OnResponseStarted(
-      browser_context_, extension_info_map_.get(), request, net_error);
+      browser_context_, extension_info_map_.get(), nullptr, request, net_error);
 }
 
 void ShellNetworkDelegate::OnCompleted(net::URLRequest* request,
@@ -93,11 +92,12 @@
             request->response_headers()->response_code());
     if (!is_redirect) {
       ExtensionWebRequestEventRouter::GetInstance()->OnCompleted(
-          browser_context_, extension_info_map_.get(), request, net_error);
+          browser_context_, extension_info_map_.get(), nullptr, request,
+          net_error);
     }
   } else {
     ExtensionWebRequestEventRouter::GetInstance()->OnErrorOccurred(
-        browser_context_, extension_info_map_.get(), request, started,
+        browser_context_, extension_info_map_.get(), nullptr, request, started,
         net_error);
   }
 }
@@ -120,8 +120,8 @@
     const AuthCallback& callback,
     net::AuthCredentials* credentials) {
   return ExtensionWebRequestEventRouter::GetInstance()->OnAuthRequired(
-      browser_context_, extension_info_map_.get(), request, auth_info, callback,
-      credentials);
+      browser_context_, extension_info_map_.get(), nullptr, request, auth_info,
+      callback, credentials);
 }
 
 }  // namespace extensions
diff --git a/extensions/utility/unpacker.cc b/extensions/utility/unpacker.cc
index 217c31a..3620f388 100644
--- a/extensions/utility/unpacker.cc
+++ b/extensions/utility/unpacker.cc
@@ -6,6 +6,7 @@
 
 #include <stddef.h>
 
+#include <algorithm>
 #include <set>
 #include <tuple>
 #include <utility>
@@ -47,6 +48,12 @@
 // A limit to stop us passing dangerously large canvases to the browser.
 const int kMaxImageCanvas = 4096 * 4096;
 
+static const base::FilePath::CharType* kAllowedThemeFiletypes[] = {
+    FILE_PATH_LITERAL(".bmp"),  FILE_PATH_LITERAL(".gif"),
+    FILE_PATH_LITERAL(".jpeg"), FILE_PATH_LITERAL(".jpg"),
+    FILE_PATH_LITERAL(".json"), FILE_PATH_LITERAL(".png"),
+    FILE_PATH_LITERAL(".webp")};
+
 SkBitmap DecodeImage(const base::FilePath& path) {
   // Read the file from disk.
   std::string file_contents;
@@ -116,29 +123,50 @@
 }
 
 // static
-bool Unpacker::ShouldExtractFile(const base::FilePath& file_path) {
+bool Unpacker::ShouldExtractFile(bool is_theme,
+                                 const base::FilePath& file_path) {
+  if (is_theme) {
+    const base::FilePath::StringType extension =
+        base::ToLowerASCII(file_path.FinalExtension());
+    // Allow filenames with no extension.
+    if (extension.empty())
+      return true;
+    return std::find(kAllowedThemeFiletypes,
+                     kAllowedThemeFiletypes + arraysize(kAllowedThemeFiletypes),
+                     extension) !=
+           (kAllowedThemeFiletypes + arraysize(kAllowedThemeFiletypes));
+  }
   return !base::FilePath::CompareEqualIgnoreCase(file_path.FinalExtension(),
                                                  FILE_PATH_LITERAL(".exe"));
 }
 
-std::unique_ptr<base::DictionaryValue> Unpacker::ReadManifest() {
-  base::FilePath manifest_path = extension_dir_.Append(kManifestFilename);
+// static
+bool Unpacker::IsManifestFile(const base::FilePath& file_path) {
+  CHECK(!file_path.IsAbsolute());
+  return base::FilePath::CompareEqualIgnoreCase(file_path.value(),
+                                                kManifestFilename);
+}
+
+// static
+std::unique_ptr<base::DictionaryValue> Unpacker::ReadManifest(
+    const base::FilePath& extension_dir,
+    std::string* error) {
+  DCHECK(error);
+  base::FilePath manifest_path = extension_dir.Append(kManifestFilename);
   if (!base::PathExists(manifest_path)) {
-    SetError(errors::kInvalidManifest);
-    return NULL;
+    *error = errors::kInvalidManifest;
+    return nullptr;
   }
 
   JSONFileValueDeserializer deserializer(manifest_path);
-  std::string error;
-  std::unique_ptr<base::Value> root = deserializer.Deserialize(NULL, &error);
+  std::unique_ptr<base::Value> root = deserializer.Deserialize(NULL, error);
   if (!root.get()) {
-    SetError(error);
-    return NULL;
+    return nullptr;
   }
 
   if (!root->IsType(base::Value::TYPE_DICTIONARY)) {
-    SetError(errors::kInvalidManifest);
-    return NULL;
+    *error = errors::kInvalidManifest;
+    return nullptr;
   }
 
   return base::DictionaryValue::From(std::move(root));
@@ -170,11 +198,13 @@
 
 bool Unpacker::Run() {
   // Parse the manifest.
-  parsed_manifest_ = ReadManifest();
-  if (!parsed_manifest_.get())
-    return false;  // Error was already reported.
-
   std::string error;
+  parsed_manifest_ = ReadManifest(extension_dir_, &error);
+  if (!parsed_manifest_.get()) {
+    SetError(error);
+    return false;
+  }
+
   scoped_refptr<Extension> extension(
       Extension::Create(extension_dir_, location_, *parsed_manifest_,
                         creation_flags_, extension_id_, &error));
diff --git a/extensions/utility/unpacker.h b/extensions/utility/unpacker.h
index 25c9e529..db893d7 100644
--- a/extensions/utility/unpacker.h
+++ b/extensions/utility/unpacker.h
@@ -35,7 +35,15 @@
   ~Unpacker();
 
   // Returns true if the given base::FilePath should be unzipped.
-  static bool ShouldExtractFile(const base::FilePath& file_path);
+  static bool ShouldExtractFile(bool is_theme, const base::FilePath& file_path);
+
+  // Returns true for manifest.json only.
+  static bool IsManifestFile(const base::FilePath& file_path);
+
+  // Parse the manifest.json file inside the extension (not in the header).
+  static std::unique_ptr<base::DictionaryValue> ReadManifest(
+      const base::FilePath& extension_dir,
+      std::string* error);
 
   // Runs the processing steps for the extension. On success, this returns true
   // and the decoded images will be in a file at
@@ -58,9 +66,6 @@
   // success.
   bool DumpMessageCatalogsToFile();
 
-  // Parse the manifest.json file inside the extension (not in the header).
-  std::unique_ptr<base::DictionaryValue> ReadManifest();
-
   // Parse all _locales/*/messages.json files inside the extension.
   bool ReadAllMessageCatalogs(const std::string& default_locale);
 
diff --git a/extensions/utility/unpacker_unittest.cc b/extensions/utility/unpacker_unittest.cc
index d66e00e..3f9a53c 100644
--- a/extensions/utility/unpacker_unittest.cc
+++ b/extensions/utility/unpacker_unittest.cc
@@ -4,6 +4,7 @@
 
 #include <memory>
 
+#include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/path_service.h"
@@ -196,38 +197,67 @@
       << unpacker_->error_message() << "\"";
 }
 
-base::FilePath CreateEmptyTestFile(const base::FilePath& test_dir,
-                                   const base::FilePath& file_path) {
-  base::FilePath test_file(test_dir.Append(file_path));
-  base::FilePath temp_file;
-  EXPECT_TRUE(base::CreateTemporaryFileInDir(test_dir, &temp_file));
-  EXPECT_TRUE(base::Move(temp_file, test_file));
-  return test_file;
+struct UnzipFileFilterTestCase {
+  const base::FilePath::CharType* input;
+  const bool should_unzip;
+};
+
+void RunZipFileFilterTest(const std::vector<UnzipFileFilterTestCase>& cases,
+                          base::Callback<bool(const base::FilePath&)>& filter) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+  for (size_t i = 0; i < cases.size(); ++i) {
+    base::FilePath input(cases[i].input);
+    bool observed = filter.Run(input);
+    EXPECT_EQ(cases[i].should_unzip, observed) << "i: " << i
+                                               << ", input: " << input.value();
+  }
 }
 
-TEST_F(UnpackerTest, BlockedFileTypes) {
-  const struct {
-    const base::FilePath::CharType* input;
-    bool expected;
-  } cases[] = {
+TEST_F(UnpackerTest, NonTheme_FileExtractionFilter) {
+  const std::vector<UnzipFileFilterTestCase> cases = {
       {FILE_PATH_LITERAL("foo"), true},
       {FILE_PATH_LITERAL("foo.nexe"), true},
       {FILE_PATH_LITERAL("foo.dll"), true},
       {FILE_PATH_LITERAL("foo.jpg.exe"), false},
       {FILE_PATH_LITERAL("foo.exe"), false},
       {FILE_PATH_LITERAL("foo.EXE"), false},
+      {FILE_PATH_LITERAL("file_without_extension"), true},
   };
+  base::Callback<bool(const base::FilePath&)> filter =
+      base::Bind(&Unpacker::ShouldExtractFile, false);
+  RunZipFileFilterTest(cases, filter);
+}
 
-  base::ScopedTempDir temp_dir;
-  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+TEST_F(UnpackerTest, Theme_FileExtractionFilter) {
+  const std::vector<UnzipFileFilterTestCase> cases = {
+      {FILE_PATH_LITERAL("image.jpg"), true},
+      {FILE_PATH_LITERAL("IMAGE.JPEG"), true},
+      {FILE_PATH_LITERAL("test/image.bmp"), true},
+      {FILE_PATH_LITERAL("test/IMAGE.gif"), true},
+      {FILE_PATH_LITERAL("test/image.WEBP"), true},
+      {FILE_PATH_LITERAL("test/dir/file.image.png"), true},
+      {FILE_PATH_LITERAL("manifest.json"), true},
+      {FILE_PATH_LITERAL("other.html"), false},
+      {FILE_PATH_LITERAL("file_without_extension"), true},
+  };
+  base::Callback<bool(const base::FilePath&)> filter =
+      base::Bind(&Unpacker::ShouldExtractFile, true);
+  RunZipFileFilterTest(cases, filter);
+}
 
-  for (size_t i = 0; i < arraysize(cases); ++i) {
-    base::FilePath input(cases[i].input);
-    base::FilePath test_file(CreateEmptyTestFile(temp_dir.path(), input));
-    bool observed = Unpacker::ShouldExtractFile(test_file);
-    EXPECT_EQ(cases[i].expected, observed) << "i: " << i
-                                           << ", input: " << test_file.value();
-  }
+TEST_F(UnpackerTest, ManifestExtractionFilter) {
+  const std::vector<UnzipFileFilterTestCase> cases = {
+      {FILE_PATH_LITERAL("manifest.json"), true},
+      {FILE_PATH_LITERAL("MANIFEST.JSON"), true},
+      {FILE_PATH_LITERAL("test/manifest.json"), false},
+      {FILE_PATH_LITERAL("manifest.json/test"), false},
+      {FILE_PATH_LITERAL("other.file"), false},
+  };
+  base::Callback<bool(const base::FilePath&)> filter =
+      base::Bind(&Unpacker::IsManifestFile);
+  RunZipFileFilterTest(cases, filter);
 }
 
 }  // namespace extensions
diff --git a/extensions/utility/utility_handler.cc b/extensions/utility/utility_handler.cc
index 7d6af353..ac4d1d3 100644
--- a/extensions/utility/utility_handler.cc
+++ b/extensions/utility/utility_handler.cc
@@ -81,17 +81,38 @@
 
 void UtilityHandler::OnUnzipToDir(const base::FilePath& zip_path,
                                   const base::FilePath& dir) {
-  const base::Callback<bool(const base::FilePath&)>& filter_cb =
-      base::Bind(&Unpacker::ShouldExtractFile);
+  // First extract only the manifest to determine the extension type.
+  if (!zip::UnzipWithFilterCallback(zip_path, dir,
+                                    base::Bind(&Unpacker::IsManifestFile))) {
+    Send(new ExtensionUtilityHostMsg_UnzipToDir_Failed(
+        std::string(kExtensionHandlerUnzipError)));
+    ReleaseProcessIfNeeded();
+    return;
+  }
+
+  // Load the manifest.
+  std::string error;
+  std::unique_ptr<base::DictionaryValue> dict =
+      Unpacker::ReadManifest(dir, &error);
+  if (!dict.get()) {
+    Send(new ExtensionUtilityHostMsg_UnzipToDir_Failed(
+        std::string(kExtensionHandlerUnzipError)));
+    ReleaseProcessIfNeeded();
+    return;
+  }
+
+  Manifest manifest(Manifest::INTERNAL, std::move(dict));
+  base::Callback<bool(const base::FilePath&)> filetype_filter_cb =
+      base::Bind(&Unpacker::ShouldExtractFile, manifest.is_theme());
+
   // TODO(crbug.com/645263): This silently ignores blocked file types.
   //                         Add install warnings.
-  if (!zip::UnzipWithFilterCallback(zip_path, dir, filter_cb)) {
+  if (!zip::UnzipWithFilterCallback(zip_path, dir, filetype_filter_cb)) {
     Send(new ExtensionUtilityHostMsg_UnzipToDir_Failed(
         std::string(kExtensionHandlerUnzipError)));
   } else {
     Send(new ExtensionUtilityHostMsg_UnzipToDir_Succeeded(dir));
   }
-
   ReleaseProcessIfNeeded();
 }
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index fad05fe..25096abf 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -2438,7 +2438,7 @@
       decoder_->should_use_native_gmb_for_backbuffer_ &&
       !decoder_->offscreen_buffer_should_have_alpha_ &&
       decoder_->ChromiumImageNeedsRGBEmulation() &&
-      decoder_->feature_info_->workarounds()
+      decoder_->workarounds()
           .disable_multisampling_color_mask_usage;
   if (alpha_channel_needs_clear) {
     glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT,
@@ -2978,7 +2978,7 @@
   // Create GPU Tracer for timing values.
   gpu_tracer_.reset(new GPUTracer(this));
 
-  if (feature_info_->workarounds().disable_timestamp_queries) {
+  if (workarounds().disable_timestamp_queries) {
     // Forcing time elapsed query for any GPU Timing Client forces it for all
     // clients in the context.
     GetGLContext()->CreateGPUTimingClient()->ForceTimeElapsedQuery();
@@ -3072,7 +3072,7 @@
 
   state_.default_vertex_attrib_manager->Initialize(
       group_->max_vertex_attribs(),
-      feature_info_->workarounds().init_vertex_attributes);
+      workarounds().init_vertex_attributes);
 
   // vertex_attrib_manager is set to default_vertex_attrib_manager by this call
   DoBindVertexArrayOES(0);
@@ -3353,7 +3353,7 @@
   // always enabled and there is no way to disable it.
   // Therefore, it seems OK to also always enable it on top of Desktop GL for
   // both ES2 and ES3 contexts.
-  if (!feature_info_->workarounds().disable_texture_cube_map_seamless &&
+  if (!workarounds().disable_texture_cube_map_seamless &&
       gl_version_info().IsAtLeastGL(3, 2)) {
     glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
   }
@@ -3414,7 +3414,7 @@
   }
 
   supports_post_sub_buffer_ = surface->SupportsPostSubBuffer();
-  if (feature_info_->workarounds()
+  if (workarounds()
           .disable_post_sub_buffers_for_onscreen_surfaces &&
       !surface->IsOffscreen())
     supports_post_sub_buffer_ = false;
@@ -3425,11 +3425,11 @@
 
   supports_async_swap_ = surface->SupportsAsyncSwap();
 
-  if (feature_info_->workarounds().reverse_point_sprite_coord_origin) {
+  if (workarounds().reverse_point_sprite_coord_origin) {
     glPointParameteri(GL_POINT_SPRITE_COORD_ORIGIN, GL_LOWER_LEFT);
   }
 
-  if (feature_info_->workarounds().unbind_fbo_on_context_switch) {
+  if (workarounds().unbind_fbo_on_context_switch) {
     context_->SetUnbindFboOnMakeCurrent();
   }
 
@@ -3580,7 +3580,7 @@
   caps.surfaceless = surfaceless_;
   bool is_offscreen = !!offscreen_target_frame_buffer_.get();
   caps.flips_vertically = !is_offscreen && surface_->FlipsVertically();
-  caps.msaa_is_slow = feature_info_->workarounds().msaa_is_slow;
+  caps.msaa_is_slow = workarounds().msaa_is_slow;
 
   caps.blend_equation_advanced =
       feature_info_->feature_flags().blend_equation_advanced;
@@ -3594,7 +3594,7 @@
   caps.image_ycbcr_420v =
       feature_info_->feature_flags().chromium_image_ycbcr_420v;
   caps.max_copy_texture_chromium_size =
-      feature_info_->workarounds().max_copy_texture_chromium_size;
+      workarounds().max_copy_texture_chromium_size;
   caps.render_buffer_format_bgra8888 =
       feature_info_->feature_flags().ext_render_buffer_format_bgra8888;
   caps.occlusion_query_boolean =
@@ -3602,11 +3602,11 @@
   caps.timer_queries =
       query_manager_->GPUTimingAvailable();
   caps.disable_multisampling_color_mask_usage =
-      feature_info_->workarounds().disable_multisampling_color_mask_usage;
+      workarounds().disable_multisampling_color_mask_usage;
   caps.disable_webgl_rgb_multisampling_usage =
-      feature_info_->workarounds().disable_webgl_rgb_multisampling_usage;
+      workarounds().disable_webgl_rgb_multisampling_usage;
   caps.emulate_rgb_buffer_with_rgba =
-      feature_info_->workarounds().disable_gl_rgb_format;
+      workarounds().disable_gl_rgb_format;
 
   return caps;
 }
@@ -5713,7 +5713,7 @@
                        "transform feedback is not active or not paused");
     return;
   }
-  if (feature_info_->workarounds().rebind_transform_feedback_before_resume) {
+  if (workarounds().rebind_transform_feedback_before_resume) {
     glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
     glBindTransformFeedback(GL_TRANSFORM_FEEDBACK,
         state_.bound_transform_feedback->service_id());
@@ -10868,7 +10868,7 @@
         "format and type incompatible with the current read framebuffer");
     return error::kNoError;
   }
-  if (type == GL_HALF_FLOAT_OES && !gl_version_info().is_es2) {
+  if (type == GL_HALF_FLOAT_OES && !gl_version_info().is_es) {
     type = GL_HALF_FLOAT;
   }
   if (width == 0 || height == 0) {
@@ -16041,7 +16041,7 @@
     compatibility_internal_format = format_info->decompressed_internal_format;
   }
 
-  if (feature_info_->workarounds().reset_base_mipmap_level_before_texstorage &&
+  if (workarounds().reset_base_mipmap_level_before_texstorage &&
       texture->base_level() > 0)
     glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, 0);
 
@@ -16055,7 +16055,7 @@
     glTexStorage3D(target, levels, compatibility_internal_format, width, height,
                    depth);
   }
-  if (feature_info_->workarounds().reset_base_mipmap_level_before_texstorage &&
+  if (workarounds().reset_base_mipmap_level_before_texstorage &&
       texture->base_level() > 0)
     glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, texture->base_level());
 
@@ -16514,7 +16514,7 @@
 void GLES2DecoderImpl::DoFlushDriverCachesCHROMIUM(void) {
   // On Adreno Android devices we need to use a workaround to force caches to
   // clear.
-  if (feature_info_->workarounds().unbind_egl_context_to_flush_driver_caches) {
+  if (workarounds().unbind_egl_context_to_flush_driver_caches) {
     context_->ReleaseCurrent(nullptr);
     context_->MakeCurrent(surface_.get());
   }
diff --git a/gpu/ipc/client/gpu_memory_buffer_impl_ozone_native_pixmap.cc b/gpu/ipc/client/gpu_memory_buffer_impl_ozone_native_pixmap.cc
index 86855a8..8e84b7d 100644
--- a/gpu/ipc/client/gpu_memory_buffer_impl_ozone_native_pixmap.cc
+++ b/gpu/ipc/client/gpu_memory_buffer_impl_ozone_native_pixmap.cc
@@ -35,8 +35,7 @@
     : GpuMemoryBufferImpl(id, size, format, callback),
       pixmap_(std::move(pixmap)),
       planes_(planes),
-      fd_(std::move(fd)),
-      data_(nullptr) {}
+      fd_(std::move(fd)) {}
 
 GpuMemoryBufferImplOzoneNativePixmap::~GpuMemoryBufferImplOzoneNativePixmap() {}
 
@@ -101,33 +100,24 @@
 
 bool GpuMemoryBufferImplOzoneNativePixmap::Map() {
   DCHECK(!mapped_);
-  DCHECK(!data_);
-  data_ = pixmap_->Map();
-  if (!data_)
-    return false;
-  mapped_ = true;
+  mapped_ = pixmap_->Map();
   return mapped_;
 }
 
 void* GpuMemoryBufferImplOzoneNativePixmap::memory(size_t plane) {
   DCHECK(mapped_);
-  DCHECK_LT(plane, gfx::NumberOfPlanesForBufferFormat(format_));
-  return data_;
+  return pixmap_->GetMemoryAddress(plane);
 }
 
 void GpuMemoryBufferImplOzoneNativePixmap::Unmap() {
   DCHECK(mapped_);
-  DCHECK(data_);
   pixmap_->Unmap();
   mapped_ = false;
-  data_ = nullptr;
 }
 
 int GpuMemoryBufferImplOzoneNativePixmap::stride(size_t plane) const {
   DCHECK_LT(plane, gfx::NumberOfPlanesForBufferFormat(format_));
-  int stride;
-  pixmap_->GetStride(&stride);
-  return stride;
+  return pixmap_->GetStride(plane);
 }
 
 gfx::GpuMemoryBufferHandle GpuMemoryBufferImplOzoneNativePixmap::GetHandle()
diff --git a/gpu/ipc/client/gpu_memory_buffer_impl_ozone_native_pixmap.h b/gpu/ipc/client/gpu_memory_buffer_impl_ozone_native_pixmap.h
index 450d102..50ececf 100644
--- a/gpu/ipc/client/gpu_memory_buffer_impl_ozone_native_pixmap.h
+++ b/gpu/ipc/client/gpu_memory_buffer_impl_ozone_native_pixmap.h
@@ -60,7 +60,6 @@
   std::unique_ptr<ui::ClientNativePixmap> pixmap_;
   std::vector<gfx::NativePixmapPlane> planes_;
   base::ScopedFD fd_;
-  void* data_;
 
   DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferImplOzoneNativePixmap);
 };
diff --git a/infra/config/recipes.cfg b/infra/config/recipes.cfg
index 8aaba70..e28c694 100644
--- a/infra/config/recipes.cfg
+++ b/infra/config/recipes.cfg
@@ -5,13 +5,13 @@
   project_id: "build"
   url: "https://chromium.googlesource.com/chromium/tools/build.git"
   branch: "master"
-  revision: "567475a8f817b58253b6e305bf5eb5c980f04bc6"
+  revision: "30f4b262c12c00e0c8287f33e1bca2abb5100307"
 }
 deps {
   project_id: "depot_tools"
   url: "https://chromium.googlesource.com/chromium/tools/depot_tools.git"
   branch: "master"
-  revision: "3e1cde7a87d6cb600d6bf3b5860b72da8c121c59"
+  revision: "8818977467d88125743535010c5b37521694df0a"
 }
 deps {
   project_id: "recipe_engine"
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn
index 7dd7514..c3ec4ff 100644
--- a/ios/chrome/browser/BUILD.gn
+++ b/ios/chrome/browser/BUILD.gn
@@ -287,6 +287,10 @@
     "notification_promo.h",
     "ntp_snippets/ios_chrome_content_suggestions_service_factory.cc",
     "ntp_snippets/ios_chrome_content_suggestions_service_factory.h",
+    "ntp_tiles/ios_most_visited_sites_factory.cc",
+    "ntp_tiles/ios_most_visited_sites_factory.h",
+    "ntp_tiles/ios_popular_sites_factory.cc",
+    "ntp_tiles/ios_popular_sites_factory.h",
     "open_from_clipboard/create_clipboard_recent_content.h",
     "open_from_clipboard/create_clipboard_recent_content.mm",
     "open_url_util.h",
diff --git a/ios/chrome/browser/interstitials/ios_chrome_controller_client.h b/ios/chrome/browser/interstitials/ios_chrome_controller_client.h
index ad38b8c..fb4f83e9 100644
--- a/ios/chrome/browser/interstitials/ios_chrome_controller_client.h
+++ b/ios/chrome/browser/interstitials/ios_chrome_controller_client.h
@@ -12,6 +12,10 @@
 
 class GURL;
 
+namespace security_interstitials {
+class MetricsHelper;
+}
+
 namespace web {
 class WebInterstitial;
 class WebState;
@@ -21,7 +25,9 @@
 class IOSChromeControllerClient
     : public security_interstitials::ControllerClient {
  public:
-  explicit IOSChromeControllerClient(web::WebState* web_state);
+  IOSChromeControllerClient(
+      web::WebState* web_state,
+      std::unique_ptr<security_interstitials::MetricsHelper> metrics_helper);
   ~IOSChromeControllerClient() override;
 
   void SetWebInterstitial(web::WebInterstitial* web_interstitial);
diff --git a/ios/chrome/browser/interstitials/ios_chrome_controller_client.mm b/ios/chrome/browser/interstitials/ios_chrome_controller_client.mm
index d221ce2..9b6732f 100644
--- a/ios/chrome/browser/interstitials/ios_chrome_controller_client.mm
+++ b/ios/chrome/browser/interstitials/ios_chrome_controller_client.mm
@@ -5,6 +5,7 @@
 #include "ios/chrome/browser/interstitials/ios_chrome_controller_client.h"
 
 #include "base/logging.h"
+#include "components/security_interstitials/core/metrics_helper.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/pref_names.h"
@@ -12,8 +13,12 @@
 #import "ios/web/public/navigation_manager.h"
 #include "ios/web/public/web_state/web_state.h"
 
-IOSChromeControllerClient::IOSChromeControllerClient(web::WebState* web_state)
-    : web_state_(web_state), web_interstitial_(nullptr) {}
+IOSChromeControllerClient::IOSChromeControllerClient(
+    web::WebState* web_state,
+    std::unique_ptr<security_interstitials::MetricsHelper> metrics_helper)
+    : security_interstitials::ControllerClient(std::move(metrics_helper)),
+      web_state_(web_state),
+      web_interstitial_(nullptr) {}
 
 IOSChromeControllerClient::~IOSChromeControllerClient() {}
 
diff --git a/ios/chrome/browser/interstitials/ios_security_interstitial_page.h b/ios/chrome/browser/interstitials/ios_security_interstitial_page.h
index 128f833..1a508e54 100644
--- a/ios/chrome/browser/interstitials/ios_security_interstitial_page.h
+++ b/ios/chrome/browser/interstitials/ios_security_interstitial_page.h
@@ -12,16 +12,10 @@
 #include "ios/web/public/interstitials/web_interstitial_delegate.h"
 #include "url/gurl.h"
 
-class IOSChromeControllerClient;
-
 namespace base {
 class DictionaryValue;
 }
 
-namespace security_interstitials {
-class MetricsHelper;
-}
-
 namespace web {
 class WebInterstitial;
 class WebState;
diff --git a/ios/chrome/browser/interstitials/ios_security_interstitial_page.mm b/ios/chrome/browser/interstitials/ios_security_interstitial_page.mm
index dc9158a..496e9e9 100644
--- a/ios/chrome/browser/interstitials/ios_security_interstitial_page.mm
+++ b/ios/chrome/browser/interstitials/ios_security_interstitial_page.mm
@@ -8,10 +8,8 @@
 #include "components/grit/components_resources.h"
 #include "components/prefs/pref_service.h"
 #include "components/security_interstitials/core/common_string_util.h"
-#include "components/security_interstitials/core/metrics_helper.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#include "ios/chrome/browser/interstitials/ios_chrome_controller_client.h"
 #include "ios/chrome/browser/pref_names.h"
 #include "ios/web/public/interstitials/web_interstitial.h"
 #include "ios/web/public/web_state/web_state.h"
diff --git a/ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory.cc b/ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory.cc
index d6516d9..27969f5f9 100644
--- a/ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory.cc
+++ b/ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory.cc
@@ -20,10 +20,10 @@
 #include "components/ntp_snippets/content_suggestions_service.h"
 #include "components/ntp_snippets/features.h"
 #include "components/ntp_snippets/ntp_snippets_constants.h"
-#include "components/ntp_snippets/ntp_snippets_database.h"
-#include "components/ntp_snippets/ntp_snippets_fetcher.h"
-#include "components/ntp_snippets/ntp_snippets_service.h"
-#include "components/ntp_snippets/ntp_snippets_status_service.h"
+#include "components/ntp_snippets/remote/ntp_snippets_database.h"
+#include "components/ntp_snippets/remote/ntp_snippets_fetcher.h"
+#include "components/ntp_snippets/remote/ntp_snippets_service.h"
+#include "components/ntp_snippets/remote/ntp_snippets_status_service.h"
 #include "components/signin/core/browser/signin_manager.h"
 #include "components/version_info/version_info.h"
 #include "google_apis/google_api_keys.h"
diff --git a/ios/chrome/browser/ntp_tiles/OWNERS b/ios/chrome/browser/ntp_tiles/OWNERS
new file mode 100644
index 0000000..b622730
--- /dev/null
+++ b/ios/chrome/browser/ntp_tiles/OWNERS
@@ -0,0 +1,2 @@
+sfiera@chromium.org
+file://components/ntp_tiles/OWNERS
diff --git a/ios/chrome/browser/ntp_tiles/ios_most_visited_sites_factory.cc b/ios/chrome/browser/ntp_tiles/ios_most_visited_sites_factory.cc
new file mode 100644
index 0000000..696c0738
--- /dev/null
+++ b/ios/chrome/browser/ntp_tiles/ios_most_visited_sites_factory.cc
@@ -0,0 +1,23 @@
+// 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.
+
+#include "ios/chrome/browser/ntp_tiles/ios_most_visited_sites_factory.h"
+
+#include "base/memory/ptr_util.h"
+#include "components/history/core/browser/top_sites.h"
+#include "components/ntp_tiles/most_visited_sites.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/chrome/browser/history/top_sites_factory.h"
+#include "ios/chrome/browser/ntp_tiles/ios_popular_sites_factory.h"
+#include "ios/chrome/browser/suggestions/suggestions_service_factory.h"
+
+std::unique_ptr<ntp_tiles::MostVisitedSites>
+IOSMostVisitedSitesFactory::NewForBrowserState(
+    ios::ChromeBrowserState* browser_state) {
+  return base::MakeUnique<ntp_tiles::MostVisitedSites>(
+      browser_state->GetPrefs(),
+      ios::TopSitesFactory::GetForBrowserState(browser_state),
+      suggestions::SuggestionsServiceFactory::GetForBrowserState(browser_state),
+      IOSPopularSitesFactory::NewForBrowserState(browser_state), nil);
+}
diff --git a/ios/chrome/browser/ntp_tiles/ios_most_visited_sites_factory.h b/ios/chrome/browser/ntp_tiles/ios_most_visited_sites_factory.h
new file mode 100644
index 0000000..35e466c2
--- /dev/null
+++ b/ios/chrome/browser/ntp_tiles/ios_most_visited_sites_factory.h
@@ -0,0 +1,24 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_NTP_TILES_IOS_MOST_VISITED_SITES_FACTORY_H_
+#define IOS_CHROME_BROWSER_NTP_TILES_IOS_MOST_VISITED_SITES_FACTORY_H_
+
+#include <memory>
+
+namespace ios {
+class ChromeBrowserState;
+}
+
+namespace ntp_tiles {
+class MostVisitedSites;
+}
+
+class IOSMostVisitedSitesFactory {
+ public:
+  static std::unique_ptr<ntp_tiles::MostVisitedSites> NewForBrowserState(
+      ios::ChromeBrowserState* browser_state);
+};
+
+#endif  // IOS_CHROME_BROWSER_NTP_TILES_IOS_MOST_VISITED_SITES_FACTORY_H_
diff --git a/ios/chrome/browser/ntp_tiles/ios_popular_sites_factory.cc b/ios/chrome/browser/ntp_tiles/ios_popular_sites_factory.cc
new file mode 100644
index 0000000..3573d1b
--- /dev/null
+++ b/ios/chrome/browser/ntp_tiles/ios_popular_sites_factory.cc
@@ -0,0 +1,73 @@
+// 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.
+
+#include "ios/chrome/browser/ntp_tiles/ios_popular_sites_factory.h"
+
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/json/json_reader.h"
+#include "base/memory/ptr_util.h"
+#include "base/path_service.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/values.h"
+#include "components/ntp_tiles/popular_sites.h"
+#include "ios/chrome/browser/application_context.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/chrome/browser/chrome_paths.h"
+#include "ios/chrome/browser/search_engines/template_url_service_factory.h"
+#include "ios/web/public/web_thread.h"
+
+namespace {
+
+// Mimics SafeJsonParser API, but parses unsafely for iOS.
+class JsonUnsafeParser {
+ public:
+  using SuccessCallback = base::Callback<void(std::unique_ptr<base::Value>)>;
+  using ErrorCallback = base::Callback<void(const std::string&)>;
+
+  // As with SafeJsonParser, runs either success_callback or error_callback on
+  // the calling thread, but not before the call returns.
+  static void Parse(const std::string& unsafe_json,
+                    const SuccessCallback& success_callback,
+                    const ErrorCallback& error_callback) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::Bind(DoParse, unsafe_json, success_callback, error_callback));
+  }
+
+  JsonUnsafeParser() = delete;
+
+ private:
+  static void DoParse(const std::string& unsafe_json,
+                      const SuccessCallback& success_callback,
+                      const ErrorCallback& error_callback) {
+    std::string error_msg;
+    int error_line, error_column;
+    std::unique_ptr<base::Value> value = base::JSONReader::ReadAndReturnError(
+        unsafe_json, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, &error_msg,
+        &error_line, &error_column);
+    if (value) {
+      success_callback.Run(std::move(value));
+    } else {
+      error_callback.Run(base::StringPrintf("%s (%d:%d)", error_msg.c_str(),
+                                            error_line, error_column));
+    }
+  }
+};
+
+}  // namespace
+
+std::unique_ptr<ntp_tiles::PopularSites>
+IOSPopularSitesFactory::NewForBrowserState(
+    ios::ChromeBrowserState* browser_state) {
+  base::FilePath popular_sites_path;
+  base::PathService::Get(ios::DIR_USER_DATA, &popular_sites_path);
+  return base::MakeUnique<ntp_tiles::PopularSites>(
+      web::WebThread::GetBlockingPool(), browser_state->GetPrefs(),
+      ios::TemplateURLServiceFactory::GetForBrowserState(browser_state),
+      GetApplicationContext()->GetVariationsService(),
+      browser_state->GetRequestContext(), popular_sites_path,
+      base::Bind(JsonUnsafeParser::Parse));
+}
diff --git a/ios/chrome/browser/ntp_tiles/ios_popular_sites_factory.h b/ios/chrome/browser/ntp_tiles/ios_popular_sites_factory.h
new file mode 100644
index 0000000..7faadd7
--- /dev/null
+++ b/ios/chrome/browser/ntp_tiles/ios_popular_sites_factory.h
@@ -0,0 +1,24 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_NTP_TILES_IOS_POPULAR_SITES_FACTORY_H_
+#define IOS_CHROME_BROWSER_NTP_TILES_IOS_POPULAR_SITES_FACTORY_H_
+
+#include <memory>
+
+namespace ios {
+class ChromeBrowserState;
+}
+
+namespace ntp_tiles {
+class PopularSites;
+}
+
+class IOSPopularSitesFactory {
+ public:
+  static std::unique_ptr<ntp_tiles::PopularSites> NewForBrowserState(
+      ios::ChromeBrowserState* browser_state);
+};
+
+#endif  // IOS_CHROME_BROWSER_NTP_TILES_IOS_POPULAR_SITES_FACTORY_H_
diff --git a/ios/chrome/browser/prefs/browser_prefs.mm b/ios/chrome/browser/prefs/browser_prefs.mm
index 6e297d6..f7255e37 100644
--- a/ios/chrome/browser/prefs/browser_prefs.mm
+++ b/ios/chrome/browser/prefs/browser_prefs.mm
@@ -11,7 +11,7 @@
 #include "components/flags_ui/pref_service_flags_storage.h"
 #include "components/gcm_driver/gcm_channel_status_syncer.h"
 #include "components/network_time/network_time_tracker.h"
-#include "components/ntp_snippets/ntp_snippets_service.h"
+#include "components/ntp_snippets/remote/ntp_snippets_service.h"
 #include "components/ntp_tiles/most_visited_sites.h"
 #include "components/ntp_tiles/popular_sites.h"
 #include "components/omnibox/browser/zero_suggest_provider.h"
diff --git a/ios/chrome/browser/ssl/ios_ssl_blocking_page.mm b/ios/chrome/browser/ssl/ios_ssl_blocking_page.mm
index e4f29d5..e349c12 100644
--- a/ios/chrome/browser/ssl/ios_ssl_blocking_page.mm
+++ b/ios/chrome/browser/ssl/ios_ssl_blocking_page.mm
@@ -65,6 +65,21 @@
         END_OF_SSL_EXPIRATION_AND_DECISION);
   }
 }
+
+IOSChromeMetricsHelper* CreateMetricsHelper(web::WebState* web_state,
+                                            const GURL& request_url,
+                                            bool overridable) {
+  // Set up the metrics helper for the SSLErrorUI.
+  security_interstitials::MetricsHelper::ReportDetails reporting_info;
+  reporting_info.metric_prefix =
+      overridable ? "ssl_overridable" : "ssl_nonoverridable";
+  reporting_info.rappor_prefix = kSSLRapporPrefix;
+  reporting_info.deprecated_rappor_prefix = kDeprecatedSSLRapporPrefix;
+  reporting_info.rappor_report_type = rappor::LOW_FREQUENCY_UMA_RAPPOR_TYPE;
+  reporting_info.deprecated_rappor_report_type = rappor::UMA_RAPPOR_TYPE;
+  return new IOSChromeMetricsHelper(web_state, request_url, reporting_info);
+}
+
 }  // namespace
 
 // Note that we always create a navigation entry with SSL errors.
@@ -83,25 +98,17 @@
       overridable_(IsOverridable(options_mask)),
       expired_but_previously_allowed_(
           (options_mask & SSLErrorUI::EXPIRED_BUT_PREVIOUSLY_ALLOWED) != 0),
-      controller_(new IOSChromeControllerClient(web_state)) {
+      controller_(new IOSChromeControllerClient(
+          web_state,
+          base::WrapUnique(CreateMetricsHelper(web_state,
+                                               request_url,
+                                               IsOverridable(options_mask))))) {
   // Override prefs for the SSLErrorUI.
   if (overridable_)
     options_mask |= SSLErrorUI::SOFT_OVERRIDE_ENABLED;
   else
     options_mask &= ~SSLErrorUI::SOFT_OVERRIDE_ENABLED;
 
-  // Set up the metrics helper for the SSLErrorUI.
-  security_interstitials::MetricsHelper::ReportDetails reporting_info;
-  reporting_info.metric_prefix =
-      overridable_ ? "ssl_overridable" : "ssl_nonoverridable";
-  reporting_info.rappor_prefix = kSSLRapporPrefix;
-  reporting_info.deprecated_rappor_prefix = kDeprecatedSSLRapporPrefix;
-  reporting_info.rappor_report_type = rappor::LOW_FREQUENCY_UMA_RAPPOR_TYPE;
-  reporting_info.deprecated_rappor_report_type = rappor::UMA_RAPPOR_TYPE;
-  IOSChromeMetricsHelper* ios_chrome_metrics_helper =
-      new IOSChromeMetricsHelper(web_state, request_url, reporting_info);
-  controller_->set_metrics_helper(base::WrapUnique(ios_chrome_metrics_helper));
-
   ssl_error_ui_.reset(new SSLErrorUI(request_url, cert_error, ssl_info,
                                      options_mask, time_triggered,
                                      controller_.get()));
@@ -211,8 +218,6 @@
 
 // static
 bool IOSSSLBlockingPage::IsOverridable(int options_mask) {
-  const bool is_overridable =
-      (options_mask & SSLErrorUI::SOFT_OVERRIDE_ENABLED) &&
-      !(options_mask & SSLErrorUI::STRICT_ENFORCEMENT);
-  return is_overridable;
+  return (options_mask & SSLErrorUI::SOFT_OVERRIDE_ENABLED) &&
+         !(options_mask & SSLErrorUI::STRICT_ENFORCEMENT);
 }
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn
index 42c306f..7583843 100644
--- a/ios/web/BUILD.gn
+++ b/ios/web/BUILD.gn
@@ -112,6 +112,16 @@
     "webui/url_data_manager_ios_backend.h",
     "webui/url_data_manager_ios_backend.mm",
     "webui/url_data_source_ios.mm",
+    "webui/url_data_source_ios_impl.cc",
+    "webui/url_data_source_ios_impl.h",
+    "webui/url_fetcher_block_adapter.h",
+    "webui/url_fetcher_block_adapter.mm",
+    "webui/web_ui_ios_controller_factory_registry.cc",
+    "webui/web_ui_ios_controller_factory_registry.h",
+    "webui/web_ui_ios_data_source_impl.h",
+    "webui/web_ui_ios_data_source_impl.mm",
+    "webui/web_ui_ios_impl.h",
+    "webui/web_ui_ios_impl.mm",
   ]
 
   libs = [ "WebKit.framework" ]
@@ -282,16 +292,6 @@
     "web_state/web_view_internal_creation_util.mm",
     "web_state/wk_web_view_security_util.h",
     "web_state/wk_web_view_security_util.mm",
-    "webui/url_data_source_ios_impl.cc",
-    "webui/url_data_source_ios_impl.h",
-    "webui/url_fetcher_block_adapter.h",
-    "webui/url_fetcher_block_adapter.mm",
-    "webui/web_ui_ios_controller_factory_registry.cc",
-    "webui/web_ui_ios_controller_factory_registry.h",
-    "webui/web_ui_ios_data_source_impl.h",
-    "webui/web_ui_ios_data_source_impl.mm",
-    "webui/web_ui_ios_impl.h",
-    "webui/web_ui_ios_impl.mm",
   ]
 
   libs = [ "WebKit.framework" ]
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index acbcdec9a..a1f5aa0 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -4801,6 +4801,13 @@
 
   GURL requestURL = net::GURLWithNSURL(action.request.URL);
 
+  // Don't create windows for non-empty invalid URLs.
+  if (!requestURL.is_empty() && !requestURL.is_valid()) {
+    DLOG(WARNING) << "Unable to open a window with invalid URL: "
+                  << requestURL.spec();
+    return nil;
+  }
+
   if (![self userIsInteracting]) {
     NSString* referer = [self refererFromNavigationAction:action];
     GURL referrerURL =
diff --git a/ios/web/webui/url_fetcher_block_adapter.mm b/ios/web/webui/url_fetcher_block_adapter.mm
index deb6178a..df7e1fa7 100644
--- a/ios/web/webui/url_fetcher_block_adapter.mm
+++ b/ios/web/webui/url_fetcher_block_adapter.mm
@@ -8,6 +8,10 @@
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_request_context_getter.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 namespace web {
 
 URLFetcherBlockAdapter::URLFetcherBlockAdapter(
diff --git a/ios/web/webui/web_ui_ios_data_source_impl.mm b/ios/web/webui/web_ui_ios_data_source_impl.mm
index 1f44034..efb9e793 100644
--- a/ios/web/webui/web_ui_ios_data_source_impl.mm
+++ b/ios/web/webui/web_ui_ios_data_source_impl.mm
@@ -13,6 +13,10 @@
 #include "ui/base/webui/jstemplate_builder.h"
 #include "ui/base/webui/web_ui_util.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 namespace web {
 
 // static
diff --git a/ios/web/webui/web_ui_ios_impl.mm b/ios/web/webui/web_ui_ios_impl.mm
index 619b2e6..9123ed3 100644
--- a/ios/web/webui/web_ui_ios_impl.mm
+++ b/ios/web/webui/web_ui_ios_impl.mm
@@ -15,6 +15,10 @@
 #include "ios/web/public/webui/web_ui_ios_message_handler.h"
 #include "ios/web/web_state/web_state_impl.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 using web::WebUIIOSController;
 
 namespace web {
diff --git a/media/base/pipeline_impl.cc b/media/base/pipeline_impl.cc
index 7eb522b..4729e23 100644
--- a/media/base/pipeline_impl.cc
+++ b/media/base/pipeline_impl.cc
@@ -578,7 +578,7 @@
   }
 
   DCHECK(demuxer_);
-  DCHECK(shared_state_.renderer);
+  DCHECK(shared_state_.renderer || (state_ != kPlaying));
 
   base::TimeDelta currTime = (state_ == kPlaying)
                                  ? shared_state_.renderer->GetMediaTime()
@@ -597,7 +597,7 @@
   }
 
   DCHECK(demuxer_);
-  DCHECK(shared_state_.renderer);
+  DCHECK(shared_state_.renderer || (state_ != kPlaying));
 
   base::TimeDelta currTime = (state_ == kPlaying)
                                  ? shared_state_.renderer->GetMediaTime()
diff --git a/media/base/text_renderer.cc b/media/base/text_renderer.cc
index 4c688c8..46c5a42 100644
--- a/media/base/text_renderer.cc
+++ b/media/base/text_renderer.cc
@@ -5,13 +5,13 @@
 #include "media/base/text_renderer.h"
 
 #include <stddef.h>
+
 #include <utility>
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/logging.h"
 #include "base/single_thread_task_runner.h"
-#include "base/stl_util.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/decoder_buffer.h"
 #include "media/base/demuxer.h"
@@ -30,7 +30,7 @@
 
 TextRenderer::~TextRenderer() {
   DCHECK(task_runner_->BelongsToCurrentThread());
-  base::STLDeleteValues(&text_track_state_map_);
+  text_track_state_map_.clear();
   if (!pause_cb_.is_null())
     base::ResetAndReturn(&pause_cb_).Run();
 }
@@ -52,9 +52,9 @@
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK_EQ(state_, kPaused) << "state_ " << state_;
 
-  for (TextTrackStateMap::iterator itr = text_track_state_map_.begin();
+  for (auto itr = text_track_state_map_.begin();
        itr != text_track_state_map_.end(); ++itr) {
-    TextTrackState* state = itr->second;
+    TextTrackState* state = itr->second.get();
     if (state->read_state == TextTrackState::kReadPending) {
       DCHECK_GT(pending_read_count_, 0);
       continue;
@@ -86,7 +86,7 @@
   DCHECK_EQ(pending_read_count_, 0);
   DCHECK(state_ == kPaused) << "state_ " << state_;
 
-  for (TextTrackStateMap::iterator itr = text_track_state_map_.begin();
+  for (auto itr = text_track_state_map_.begin();
        itr != text_track_state_map_.end(); ++itr) {
     pending_eos_set_.insert(itr->first);
     itr->second->text_ranges_.Reset();
@@ -115,12 +115,11 @@
 void TextRenderer::RemoveTextStream(DemuxerStream* text_stream) {
   DCHECK(task_runner_->BelongsToCurrentThread());
 
-  TextTrackStateMap::iterator itr = text_track_state_map_.find(text_stream);
+  auto itr = text_track_state_map_.find(text_stream);
   DCHECK(itr != text_track_state_map_.end());
 
-  TextTrackState* state = itr->second;
+  TextTrackState* state = itr->second.get();
   DCHECK_EQ(state->read_state, TextTrackState::kReadIdle);
-  delete state;
   text_track_state_map_.erase(itr);
 
   pending_eos_set_.erase(text_stream);
@@ -143,10 +142,10 @@
     DCHECK_GT(pending_read_count_, 0);
     DCHECK(pending_eos_set_.find(stream) != pending_eos_set_.end());
 
-    TextTrackStateMap::iterator itr = text_track_state_map_.find(stream);
+    auto itr = text_track_state_map_.find(stream);
     DCHECK(itr != text_track_state_map_.end());
 
-    TextTrackState* state = itr->second;
+    TextTrackState* state = itr->second.get();
     DCHECK_EQ(state->read_state, TextTrackState::kReadPending);
 
     --pending_read_count_;
@@ -214,10 +213,10 @@
   DCHECK_GT(pending_read_count_, 0);
   DCHECK(pending_eos_set_.find(text_stream) != pending_eos_set_.end());
 
-  TextTrackStateMap::iterator itr = text_track_state_map_.find(text_stream);
+  auto itr = text_track_state_map_.find(text_stream);
   DCHECK(itr != text_track_state_map_.end());
 
-  TextTrackState* state = itr->second;
+  TextTrackState* state = itr->second.get();
   DCHECK_EQ(state->read_state, TextTrackState::kReadPending);
   DCHECK(state->text_track);
 
@@ -299,11 +298,11 @@
 
   std::unique_ptr<TextTrackState> state(
       new TextTrackState(std::move(text_track)));
-  text_track_state_map_[text_stream] = state.release();
+  text_track_state_map_[text_stream] = std::move(state);
   pending_eos_set_.insert(text_stream);
 
   if (state_ == kPlaying)
-    Read(text_track_state_map_[text_stream], text_stream);
+    Read(text_track_state_map_[text_stream].get(), text_stream);
 }
 
 void TextRenderer::Read(
diff --git a/media/base/text_renderer.h b/media/base/text_renderer.h
index ab1867d..96aa0d5 100644
--- a/media/base/text_renderer.h
+++ b/media/base/text_renderer.h
@@ -121,8 +121,8 @@
   };
   State state_;
 
-  typedef std::map<DemuxerStream*, TextTrackState*> TextTrackStateMap;
-  TextTrackStateMap text_track_state_map_;
+  std::map<DemuxerStream*, std::unique_ptr<TextTrackState>>
+      text_track_state_map_;
 
   // Indicates how many read requests are in flight.
   int pending_read_count_;
diff --git a/media/base/video_capturer_source.h b/media/base/video_capturer_source.h
index ddec90c..7605301 100644
--- a/media/base/video_capturer_source.h
+++ b/media/base/video_capturer_source.h
@@ -81,11 +81,34 @@
   // the screen's content has not changed in a while), consumers may request a
   // "refresh frame" to be delivered. For instance, this would be needed when
   // a new sink is added to a MediaStreamTrack.
+  //
   // The default implementation is a no-op and implementations are not required
   // to honor this request. If they decide to and capturing is started
   // successfully, then |new_frame_callback| should be called with a frame.
+  //
+  // Note: This should only be called after StartCapture() and before
+  // StopCapture(). Otherwise, its behavior is undefined.
   virtual void RequestRefreshFrame() {}
 
+  // Optionally suspends frame delivery. The source may or may not honor this
+  // request. Thus, the caller cannot assume frame delivery will actually
+  // stop. Even if frame delivery is suspended, this might not take effect
+  // immediately.
+  //
+  // The purpose of this is to allow minimizing resource usage while
+  // there are no frame consumers present.
+  //
+  // Note: This should only be called after StartCapture() and before
+  // StopCapture(). Otherwise, its behavior is undefined.
+  virtual void MaybeSuspend() {}
+
+  // Resumes frame delivery, if it was suspended. If frame delivery was not
+  // suspended, this is a no-op, and frame delivery will continue.
+  //
+  // Note: This should only be called after StartCapture() and before
+  // StopCapture(). Otherwise, its behavior is undefined.
+  virtual void Resume() {}
+
   // Stops capturing frames and clears all callbacks including the
   // SupportedFormatsCallback callback. Note that queued frame callbacks
   // may still occur after this call, so the caller must take care to
diff --git a/media/base/video_frame.cc b/media/base/video_frame.cc
index f88dff3f..62b347d 100644
--- a/media/base/video_frame.cc
+++ b/media/base/video_frame.cc
@@ -121,7 +121,7 @@
     return true;
 
   // Make sure new formats are properly accounted for in the method.
-  static_assert(PIXEL_FORMAT_MAX == 21,
+  static_assert(PIXEL_FORMAT_MAX == 26,
                 "Added pixel format, please review IsValidConfig()");
 
   if (format == PIXEL_FORMAT_UNKNOWN) {
@@ -509,6 +509,8 @@
     case PIXEL_FORMAT_RGB24:
     case PIXEL_FORMAT_RGB32:
     case PIXEL_FORMAT_MJPEG:
+    case PIXEL_FORMAT_Y8:
+    case PIXEL_FORMAT_Y16:
       return 1;
     case PIXEL_FORMAT_NV12:
     case PIXEL_FORMAT_NV21:
@@ -524,6 +526,9 @@
     case PIXEL_FORMAT_YUV420P10:
     case PIXEL_FORMAT_YUV422P10:
     case PIXEL_FORMAT_YUV444P10:
+    case PIXEL_FORMAT_YUV420P12:
+    case PIXEL_FORMAT_YUV422P12:
+    case PIXEL_FORMAT_YUV444P12:
       return 3;
     case PIXEL_FORMAT_YV12A:
       return 4;
@@ -1014,11 +1019,13 @@
         case PIXEL_FORMAT_YV24:
         case PIXEL_FORMAT_YUV444P9:
         case PIXEL_FORMAT_YUV444P10:
+        case PIXEL_FORMAT_YUV444P12:
           return gfx::Size(1, 1);
 
         case PIXEL_FORMAT_YV16:
         case PIXEL_FORMAT_YUV422P9:
         case PIXEL_FORMAT_YUV422P10:
+        case PIXEL_FORMAT_YUV422P12:
           return gfx::Size(2, 1);
 
         case PIXEL_FORMAT_YV12:
@@ -1029,6 +1036,7 @@
         case PIXEL_FORMAT_MT21:
         case PIXEL_FORMAT_YUV420P9:
         case PIXEL_FORMAT_YUV420P10:
+        case PIXEL_FORMAT_YUV420P12:
           return gfx::Size(2, 2);
 
         case PIXEL_FORMAT_UNKNOWN:
@@ -1039,6 +1047,8 @@
         case PIXEL_FORMAT_RGB24:
         case PIXEL_FORMAT_RGB32:
         case PIXEL_FORMAT_MJPEG:
+        case PIXEL_FORMAT_Y8:
+        case PIXEL_FORMAT_Y16:
           break;
       }
   }
@@ -1056,6 +1066,7 @@
       return 4;
     case PIXEL_FORMAT_RGB24:
       return 3;
+    case PIXEL_FORMAT_Y16:
     case PIXEL_FORMAT_UYVY:
     case PIXEL_FORMAT_YUY2:
     case PIXEL_FORMAT_YUV420P9:
@@ -1064,6 +1075,9 @@
     case PIXEL_FORMAT_YUV420P10:
     case PIXEL_FORMAT_YUV422P10:
     case PIXEL_FORMAT_YUV444P10:
+    case PIXEL_FORMAT_YUV420P12:
+    case PIXEL_FORMAT_YUV422P12:
+    case PIXEL_FORMAT_YUV444P12:
       return 2;
     case PIXEL_FORMAT_NV12:
     case PIXEL_FORMAT_NV21:
@@ -1077,6 +1091,7 @@
     case PIXEL_FORMAT_YV16:
     case PIXEL_FORMAT_YV12A:
     case PIXEL_FORMAT_YV24:
+    case PIXEL_FORMAT_Y8:
       return 1;
     case PIXEL_FORMAT_MJPEG:
       return 0;
diff --git a/media/base/video_types.cc b/media/base/video_types.cc
index f8eeb3e..0f2d540a 100644
--- a/media/base/video_types.cc
+++ b/media/base/video_types.cc
@@ -54,6 +54,16 @@
       return "PIXEL_FORMAT_YUV444P9";
     case PIXEL_FORMAT_YUV444P10:
       return "PIXEL_FORMAT_YUV444P10";
+    case PIXEL_FORMAT_YUV420P12:
+      return "PIXEL_FORMAT_YUV420P12";
+    case PIXEL_FORMAT_YUV422P12:
+      return "PIXEL_FORMAT_YUV422P12";
+    case PIXEL_FORMAT_YUV444P12:
+      return "PIXEL_FORMAT_YUV444P12";
+    case PIXEL_FORMAT_Y8:
+      return "PIXEL_FORMAT_Y8";
+    case PIXEL_FORMAT_Y16:
+      return "PIXEL_FORMAT_Y16";
   }
   NOTREACHED() << "Invalid VideoPixelFormat provided: " << format;
   return "";
@@ -75,6 +85,9 @@
     case PIXEL_FORMAT_YUV422P10:
     case PIXEL_FORMAT_YUV444P9:
     case PIXEL_FORMAT_YUV444P10:
+    case PIXEL_FORMAT_YUV420P12:
+    case PIXEL_FORMAT_YUV422P12:
+    case PIXEL_FORMAT_YUV444P12:
       return true;
 
     case PIXEL_FORMAT_UNKNOWN:
@@ -85,6 +98,8 @@
     case PIXEL_FORMAT_RGB24:
     case PIXEL_FORMAT_RGB32:
     case PIXEL_FORMAT_MJPEG:
+    case PIXEL_FORMAT_Y8:
+    case PIXEL_FORMAT_Y16:
       return false;
   }
   return false;
@@ -111,6 +126,11 @@
     case PIXEL_FORMAT_YUV422P10:
     case PIXEL_FORMAT_YUV444P9:
     case PIXEL_FORMAT_YUV444P10:
+    case PIXEL_FORMAT_YUV420P12:
+    case PIXEL_FORMAT_YUV422P12:
+    case PIXEL_FORMAT_YUV444P12:
+    case PIXEL_FORMAT_Y8:
+    case PIXEL_FORMAT_Y16:
       return true;
     case PIXEL_FORMAT_YV12A:
     case PIXEL_FORMAT_ARGB:
diff --git a/media/base/video_types.h b/media/base/video_types.h
index 7590b1b3..734a133 100644
--- a/media/base/video_types.h
+++ b/media/base/video_types.h
@@ -54,9 +54,16 @@
   PIXEL_FORMAT_YUV444P9 = 20,
   PIXEL_FORMAT_YUV444P10 = 21,
 
+  PIXEL_FORMAT_YUV420P12 = 22,
+  PIXEL_FORMAT_YUV422P12 = 23,
+  PIXEL_FORMAT_YUV444P12 = 24,
+
+  PIXEL_FORMAT_Y8 = 25,   // single 8bpp plane.
+  PIXEL_FORMAT_Y16 = 26,  // single 16bpp plane.
+
   // Please update UMA histogram enumeration when adding new formats here.
   PIXEL_FORMAT_MAX =
-      PIXEL_FORMAT_YUV444P10,  // Must always be equal to largest entry logged.
+      PIXEL_FORMAT_Y16,  // Must always be equal to largest entry logged.
 };
 
 // Color space or color range used for the pixels.
diff --git a/media/blink/BUILD.gn b/media/blink/BUILD.gn
index 44813f1..19b0b58 100644
--- a/media/blink/BUILD.gn
+++ b/media/blink/BUILD.gn
@@ -130,7 +130,6 @@
     "interval_map_unittest.cc",
     "key_system_config_selector_unittest.cc",
     "lru_unittest.cc",
-    "mock_webframeclient.h",
     "mock_weburlloader.cc",
     "mock_weburlloader.h",
     "multibuffer_data_source_unittest.cc",
diff --git a/media/blink/mock_webframeclient.h b/media/blink/mock_webframeclient.h
deleted file mode 100644
index 7a63358..0000000
--- a/media/blink/mock_webframeclient.h
+++ /dev/null
@@ -1,16 +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 MEDIA_BLINK_MOCK_WEBFRAMECLIENT_H_
-#define MEDIA_BLINK_MOCK_WEBFRAMECLIENT_H_
-
-#include "third_party/WebKit/public/web/WebFrameClient.h"
-
-namespace media {
-
-class MockWebFrameClient : public blink::WebFrameClient {};
-
-}  // namespace media
-
-#endif  // MEDIA_BLINK_MOCK_WEBFRAMECLIENT_H_
diff --git a/media/blink/multibuffer_data_source_unittest.cc b/media/blink/multibuffer_data_source_unittest.cc
index 91cfe3d6..8142aa5 100644
--- a/media/blink/multibuffer_data_source_unittest.cc
+++ b/media/blink/multibuffer_data_source_unittest.cc
@@ -14,13 +14,13 @@
 #include "media/base/mock_filters.h"
 #include "media/base/test_helpers.h"
 #include "media/blink/buffered_data_source_host_impl.h"
-#include "media/blink/mock_webframeclient.h"
 #include "media/blink/mock_weburlloader.h"
 #include "media/blink/multibuffer_data_source.h"
 #include "media/blink/multibuffer_reader.h"
 #include "media/blink/resource_multibuffer_data_provider.h"
 #include "media/blink/test_response_generator.h"
 #include "third_party/WebKit/public/platform/WebURLResponse.h"
+#include "third_party/WebKit/public/web/WebFrameClient.h"
 #include "third_party/WebKit/public/web/WebLocalFrame.h"
 #include "third_party/WebKit/public/web/WebView.h"
 
@@ -225,16 +225,15 @@
  public:
   MultibufferDataSourceTest()
       : view_(WebView::create(nullptr, blink::WebPageVisibilityStateVisible)),
-        frame_(
-            WebLocalFrame::create(blink::WebTreeScopeType::Document, &client_)),
-        preload_(MultibufferDataSource::AUTO),
-        url_index_(make_linked_ptr(new TestUrlIndex(frame_))) {
-    view_->setMainFrame(frame_);
+        preload_(MultibufferDataSource::AUTO) {
+    WebLocalFrame* frame =
+        WebLocalFrame::create(blink::WebTreeScopeType::Document, &client_);
+    view_->setMainFrame(frame);
+    url_index_ = make_linked_ptr(new TestUrlIndex(frame));
   }
 
   virtual ~MultibufferDataSourceTest() {
     view_->close();
-    frame_->close();
   }
 
   MOCK_METHOD1(OnInitialize, void(bool));
@@ -476,9 +475,8 @@
   }
 
  protected:
-  MockWebFrameClient client_;
+  blink::WebFrameClient client_;
   WebView* view_;
-  WebLocalFrame* frame_;
   MultibufferDataSource::Preload preload_;
   base::MessageLoop message_loop_;
   linked_ptr<TestUrlIndex> url_index_;
diff --git a/media/blink/resource_multibuffer_data_provider_unittest.cc b/media/blink/resource_multibuffer_data_provider_unittest.cc
index 518fc5e..fcfbeba7 100644
--- a/media/blink/resource_multibuffer_data_provider_unittest.cc
+++ b/media/blink/resource_multibuffer_data_provider_unittest.cc
@@ -17,7 +17,6 @@
 #include "base/strings/stringprintf.h"
 #include "media/base/media_log.h"
 #include "media/base/seekable_buffer.h"
-#include "media/blink/mock_webframeclient.h"
 #include "media/blink/mock_weburlloader.h"
 #include "media/blink/url_index.h"
 #include "net/base/net_errors.h"
@@ -27,6 +26,7 @@
 #include "third_party/WebKit/public/platform/WebURLError.h"
 #include "third_party/WebKit/public/platform/WebURLRequest.h"
 #include "third_party/WebKit/public/platform/WebURLResponse.h"
+#include "third_party/WebKit/public/web/WebFrameClient.h"
 #include "third_party/WebKit/public/web/WebLocalFrame.h"
 #include "third_party/WebKit/public/web/WebView.h"
 
@@ -71,11 +71,11 @@
 class ResourceMultiBufferDataProviderTest : public testing::Test {
  public:
   ResourceMultiBufferDataProviderTest()
-      : view_(WebView::create(nullptr, blink::WebPageVisibilityStateVisible)),
-        frame_(WebLocalFrame::create(blink::WebTreeScopeType::Document,
-                                     &client_)) {
-    view_->setMainFrame(frame_);
-    url_index_.reset(new UrlIndex(frame_, 0));
+      : view_(WebView::create(nullptr, blink::WebPageVisibilityStateVisible)) {
+    WebLocalFrame* frame =
+        WebLocalFrame::create(blink::WebTreeScopeType::Document, &client_);
+    view_->setMainFrame(frame);
+    url_index_.reset(new UrlIndex(frame, 0));
 
     for (int i = 0; i < kDataSize; ++i) {
       data_[i] = i;
@@ -84,7 +84,6 @@
 
   virtual ~ResourceMultiBufferDataProviderTest() {
     view_->close();
-    frame_->close();
   }
 
   void Initialize(const char* url, int first_position) {
@@ -234,9 +233,8 @@
   ResourceMultiBufferDataProvider* loader_;
   NiceMock<MockWebURLLoader>* url_loader_;
 
-  MockWebFrameClient client_;
+  blink::WebFrameClient client_;
   WebView* view_;
-  WebLocalFrame* frame_;
 
   base::MessageLoop message_loop_;
 
diff --git a/media/blink/webmediaplayer_impl_unittest.cc b/media/blink/webmediaplayer_impl_unittest.cc
index 9112cff0..f903c2d 100644
--- a/media/blink/webmediaplayer_impl_unittest.cc
+++ b/media/blink/webmediaplayer_impl_unittest.cc
@@ -21,7 +21,6 @@
 #include "media/base/media_log.h"
 #include "media/base/media_switches.h"
 #include "media/base/test_helpers.h"
-#include "media/blink/mock_webframeclient.h"
 #include "media/blink/webmediaplayer_delegate.h"
 #include "media/blink/webmediaplayer_params.h"
 #include "media/renderers/default_renderer_factory.h"
@@ -152,7 +151,6 @@
     base::RunLoop().RunUntilIdle();
 
     web_view_->close();
-    web_local_frame_->close();
   }
 
  protected:
@@ -243,7 +241,7 @@
   base::Thread media_thread_;
 
   // Blink state.
-  MockWebFrameClient web_frame_client_;
+  blink::WebFrameClient web_frame_client_;
   blink::WebView* web_view_;
   blink::WebLocalFrame* web_local_frame_;
 
diff --git a/media/capture/BUILD.gn b/media/capture/BUILD.gn
index a6340f5..d5ebd5c6 100644
--- a/media/capture/BUILD.gn
+++ b/media/capture/BUILD.gn
@@ -47,12 +47,22 @@
     "video/mac/video_capture_device_mac.h",
     "video/mac/video_capture_device_mac.mm",
     "video/scoped_result_callback.h",
+    "video/video_capture_buffer_handle.h",
+    "video/video_capture_buffer_pool.h",
+    "video/video_capture_buffer_pool_impl.cc",
+    "video/video_capture_buffer_pool_impl.h",
+    "video/video_capture_buffer_tracker.h",
+    "video/video_capture_buffer_tracker_factory.h",
     "video/video_capture_device.cc",
     "video/video_capture_device.h",
+    "video/video_capture_device_client.cc",
+    "video/video_capture_device_client.h",
     "video/video_capture_device_descriptor.cc",
     "video/video_capture_device_descriptor.h",
     "video/video_capture_device_factory.cc",
     "video/video_capture_device_factory.h",
+    "video/video_capture_jpeg_decoder.h",
+    "video/video_frame_receiver.h",
     "video/win/capability_list_win.cc",
     "video/win/capability_list_win.h",
     "video/win/filter_base_win.cc",
@@ -79,6 +89,7 @@
     "//media",
     "//media/mojo/interfaces:image_capture",
     "//skia",
+    "//third_party/libyuv",
     "//ui/display",
     "//ui/gfx",
   ]
@@ -138,7 +149,6 @@
       "video/blob_utils.cc",
       "video/blob_utils.h",
     ]
-    deps += [ "//third_party/libyuv" ]
   }
 }
 
diff --git a/media/capture/content/screen_capture_device_core.cc b/media/capture/content/screen_capture_device_core.cc
index 0f06dfa..f65ea59 100644
--- a/media/capture/content/screen_capture_device_core.cc
+++ b/media/capture/content/screen_capture_device_core.cc
@@ -69,7 +69,7 @@
 void ScreenCaptureDeviceCore::RequestRefreshFrame() {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  if (state_ != kCapturing)
+  if (state_ != kCapturing && state_ != kSuspended)
     return;
 
   if (oracle_proxy_->AttemptPassiveRefresh())
@@ -77,12 +77,34 @@
   capture_machine_->MaybeCaptureForRefresh();
 }
 
-void ScreenCaptureDeviceCore::StopAndDeAllocate() {
+void ScreenCaptureDeviceCore::Suspend() {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   if (state_ != kCapturing)
     return;
 
+  TransitionStateTo(kSuspended);
+
+  capture_machine_->Suspend();
+}
+
+void ScreenCaptureDeviceCore::Resume() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  if (state_ != kSuspended)
+    return;
+
+  TransitionStateTo(kCapturing);
+
+  capture_machine_->Resume();
+}
+
+void ScreenCaptureDeviceCore::StopAndDeAllocate() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  if (state_ != kCapturing && state_ != kSuspended)
+    return;
+
   oracle_proxy_->Stop();
   oracle_proxy_ = NULL;
 
@@ -105,7 +127,7 @@
 
 ScreenCaptureDeviceCore::~ScreenCaptureDeviceCore() {
   DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK_NE(state_, kCapturing);
+  DCHECK(state_ != kCapturing && state_ != kSuspended);
   if (capture_machine_) {
     capture_machine_->Stop(
         base::Bind(&DeleteCaptureMachine, base::Passed(&capture_machine_)));
@@ -117,7 +139,8 @@
   DCHECK(thread_checker_.CalledOnValidThread());
 
 #ifndef NDEBUG
-  static const char* kStateNames[] = {"Idle", "Capturing", "Error"};
+  static const char* kStateNames[] = {"Idle", "Capturing", "Suspended",
+                                      "Error"};
   static_assert(arraysize(kStateNames) == kLastCaptureState,
                 "Different number of states and textual descriptions");
   DVLOG(1) << "State change: " << kStateNames[state_] << " --> "
diff --git a/media/capture/content/screen_capture_device_core.h b/media/capture/content/screen_capture_device_core.h
index 3f8884b..c965043 100644
--- a/media/capture/content/screen_capture_device_core.h
+++ b/media/capture/content/screen_capture_device_core.h
@@ -37,6 +37,10 @@
                      const VideoCaptureParams& params,
                      const base::Callback<void(bool)> callback) = 0;
 
+  // Suspend/Resume frame delivery. Implementations of these are optional.
+  virtual void Suspend() {}
+  virtual void Resume() {}
+
   // Stops capturing.
   // |callback| is invoked after the capturing has stopped.
   virtual void Stop(const base::Closure& callback) = 0;
@@ -82,11 +86,13 @@
   void AllocateAndStart(const VideoCaptureParams& params,
                         std::unique_ptr<VideoCaptureDevice::Client> client);
   void RequestRefreshFrame();
+  void Suspend();
+  void Resume();
   void StopAndDeAllocate();
 
  private:
   // Flag indicating current state.
-  enum State { kIdle, kCapturing, kError, kLastCaptureState };
+  enum State { kIdle, kCapturing, kSuspended, kError, kLastCaptureState };
 
   void TransitionStateTo(State next_state);
 
diff --git a/media/capture/video/DEPS b/media/capture/video/DEPS
index 896f509..6ed765f7 100644
--- a/media/capture/video/DEPS
+++ b/media/capture/video/DEPS
@@ -1,3 +1,4 @@
 include_rules = [
   "+mojo/public/cpp/bindings",
-]
\ No newline at end of file
+  "+third_party/libyuv",
+]
diff --git a/content/browser/renderer_host/media/video_capture_buffer_handle.h b/media/capture/video/video_capture_buffer_handle.h
similarity index 68%
rename from content/browser/renderer_host/media/video_capture_buffer_handle.h
rename to media/capture/video/video_capture_buffer_handle.h
index 1e17004..d9c4cc62 100644
--- a/content/browser/renderer_host/media/video_capture_buffer_handle.h
+++ b/media/capture/video/video_capture_buffer_handle.h
@@ -2,17 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_HANDLE_H_
-#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_HANDLE_H_
+#ifndef MEDIA_CAPTURE_VIDEO_VIDEO_CAPTURE_BUFFER_HANDLE_H_
+#define MEDIA_CAPTURE_VIDEO_VIDEO_CAPTURE_BUFFER_HANDLE_H_
 
 #include "base/files/file.h"
+#include "media/capture/capture_export.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/gpu_memory_buffer.h"
 
-namespace content {
+namespace media {
 
 // Abstraction of a pool's buffer data buffer and size for clients.
-class VideoCaptureBufferHandle {
+class CAPTURE_EXPORT VideoCaptureBufferHandle {
  public:
   virtual ~VideoCaptureBufferHandle() {}
   virtual gfx::Size dimensions() const = 0;
@@ -24,6 +25,6 @@
 #endif
 };
 
-}  // namespace content
+}  // namespace media
 
-#endif  // CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_HANDLE_H_
+#endif  // MEDIA_CAPTURE_VIDEO_VIDEO_CAPTURE_BUFFER_HANDLE_H_
diff --git a/content/browser/renderer_host/media/video_capture_buffer_pool.h b/media/capture/video/video_capture_buffer_pool.h
similarity index 62%
rename from content/browser/renderer_host/media/video_capture_buffer_pool.h
rename to media/capture/video/video_capture_buffer_pool.h
index 4dc59ac..0f0a4920 100644
--- a/content/browser/renderer_host/media/video_capture_buffer_pool.h
+++ b/media/capture/video/video_capture_buffer_pool.h
@@ -1,33 +1,41 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_POOL_H_
-#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_POOL_H_
+#ifndef MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_BUFFER_POOL_H_
+#define MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_BUFFER_POOL_H_
 
-#include <stddef.h>
-
-#include <map>
-
-#include "base/files/file.h"
-#include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/shared_memory.h"
-#include "base/process/process.h"
-#include "base/synchronization/lock.h"
-#include "build/build_config.h"
-#include "content/common/content_export.h"
 #include "media/base/video_capture_types.h"
-#include "media/base/video_frame.h"
+#include "media/capture/capture_export.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/gpu_memory_buffer.h"
 
-namespace content {
+namespace media {
 
 class VideoCaptureBufferHandle;
-class VideoCaptureBufferTracker;
 
-class CONTENT_EXPORT VideoCaptureBufferPool
+// A thread-safe class that does the bookkeeping and lifetime management for a
+// pool of pixel buffers cycled between an in-process producer (e.g. a
+// VideoCaptureDevice) and a set of out-of-process consumers. The pool is
+// intended to be orchestrated by a VideoCaptureDevice::Client, but is designed
+// to outlive the controller if necessary. The pixel buffers may be backed by a
+// SharedMemory, but this is not compulsory.
+//
+// Producers get a buffer by calling ReserveForProducer(), and may pass on their
+// ownership to the consumer by calling HoldForConsumers(), or drop the buffer
+// (without further processing) by calling RelinquishProducerReservation().
+// Consumers signal that they are done with the buffer by calling
+// RelinquishConsumerHold().
+//
+// Buffers are allocated on demand, but there will never be more than |count|
+// buffers in existence at any time. Buffers are identified by an int value
+// called |buffer_id|. -1 (kInvalidId) is never a valid ID, and is returned by
+// some methods to indicate failure. The active set of buffer ids may change
+// over the lifetime of the buffer pool, as existing buffers are freed and
+// reallocated at larger size. When reallocation occurs, new buffer IDs will
+// circulate.
+class CAPTURE_EXPORT VideoCaptureBufferPool
     : public base::RefCountedThreadSafe<VideoCaptureBufferPool> {
  public:
   static constexpr int kInvalidId = -1;
@@ -102,84 +110,6 @@
   friend class base::RefCountedThreadSafe<VideoCaptureBufferPool>;
 };
 
-// A thread-safe class that does the bookkeeping and lifetime management for a
-// pool of pixel buffers cycled between an in-process producer (e.g. a
-// VideoCaptureDevice) and a set of out-of-process consumers. The pool is
-// intended to be orchestrated by a VideoCaptureDevice::Client, but is designed
-// to outlive the controller if necessary. The pixel buffers may be backed by a
-// SharedMemory, but this is not compulsory.
-//
-// Producers get a buffer by calling ReserveForProducer(), and may pass on their
-// ownership to the consumer by calling HoldForConsumers(), or drop the buffer
-// (without further processing) by calling RelinquishProducerReservation().
-// Consumers signal that they are done with the buffer by calling
-// RelinquishConsumerHold().
-//
-// Buffers are allocated on demand, but there will never be more than |count|
-// buffers in existence at any time. Buffers are identified by an int value
-// called |buffer_id|. -1 (kInvalidId) is never a valid ID, and is returned by
-// some methods to indicate failure. The active set of buffer ids may change
-// over the lifetime of the buffer pool, as existing buffers are freed and
-// reallocated at larger size. When reallocation occurs, new buffer IDs will
-// circulate.
-class CONTENT_EXPORT VideoCaptureBufferPoolImpl
-    : public VideoCaptureBufferPool {
- public:
-  explicit VideoCaptureBufferPoolImpl(int count);
+}  // namespace media
 
-  // Implementation of VideoCaptureBufferPool interface:
-  bool ShareToProcess(int buffer_id,
-                      base::ProcessHandle process_handle,
-                      base::SharedMemoryHandle* new_handle) override;
-  bool ShareToProcess2(int buffer_id,
-                       int plane,
-                       base::ProcessHandle process_handle,
-                       gfx::GpuMemoryBufferHandle* new_handle) override;
-  std::unique_ptr<VideoCaptureBufferHandle> GetBufferHandle(
-      int buffer_id) override;
-  int ReserveForProducer(const gfx::Size& dimensions,
-                         media::VideoPixelFormat format,
-                         media::VideoPixelStorage storage,
-                         int* buffer_id_to_drop) override;
-  void RelinquishProducerReservation(int buffer_id) override;
-  int ResurrectLastForProducer(const gfx::Size& dimensions,
-                               media::VideoPixelFormat format,
-                               media::VideoPixelStorage storage) override;
-  double GetBufferPoolUtilization() const override;
-  void HoldForConsumers(int buffer_id, int num_clients) override;
-  void RelinquishConsumerHold(int buffer_id, int num_clients) override;
-
- private:
-  friend class base::RefCountedThreadSafe<VideoCaptureBufferPoolImpl>;
-  ~VideoCaptureBufferPoolImpl() override;
-
-  int ReserveForProducerInternal(const gfx::Size& dimensions,
-                                 media::VideoPixelFormat format,
-                                 media::VideoPixelStorage storage,
-                                 int* tracker_id_to_drop);
-
-  VideoCaptureBufferTracker* GetTracker(int buffer_id);
-
-  // The max number of buffers that the pool is allowed to have at any moment.
-  const int count_;
-
-  // Protects everything below it.
-  mutable base::Lock lock_;
-
-  // The ID of the next buffer.
-  int next_buffer_id_;
-
-  // The ID of the buffer last relinquished by the producer (a candidate for
-  // resurrection).
-  int last_relinquished_buffer_id_;
-
-  // The buffers, indexed by the first parameter, a buffer id.
-  using TrackerMap = std::map<int, VideoCaptureBufferTracker*>;
-  TrackerMap trackers_;
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(VideoCaptureBufferPoolImpl);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_POOL_H_
+#endif  // MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_BUFFER_POOL_H_
diff --git a/content/browser/renderer_host/media/video_capture_buffer_pool.cc b/media/capture/video/video_capture_buffer_pool_impl.cc
similarity index 93%
rename from content/browser/renderer_host/media/video_capture_buffer_pool.cc
rename to media/capture/video/video_capture_buffer_pool_impl.cc
index bc335a8c..cce7ef0 100644
--- a/content/browser/renderer_host/media/video_capture_buffer_pool.cc
+++ b/media/capture/video/video_capture_buffer_pool_impl.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 "content/browser/renderer_host/media/video_capture_buffer_pool.h"
+#include "media/capture/video/video_capture_buffer_pool_impl.h"
 
 #include <memory>
 
@@ -10,17 +10,19 @@
 #include "base/memory/ptr_util.h"
 #include "base/stl_util.h"
 #include "build/build_config.h"
-#include "content/browser/renderer_host/media/video_capture_buffer_handle.h"
-#include "content/browser/renderer_host/media/video_capture_buffer_tracker.h"
-#include "content/browser/renderer_host/media/video_capture_buffer_tracker_factory.h"
+#include "media/capture/video/video_capture_buffer_handle.h"
+#include "media/capture/video/video_capture_buffer_tracker.h"
 #include "ui/gfx/buffer_format_util.h"
 
-namespace content {
+namespace media {
 
-VideoCaptureBufferPoolImpl::VideoCaptureBufferPoolImpl(int count)
+VideoCaptureBufferPoolImpl::VideoCaptureBufferPoolImpl(
+    std::unique_ptr<VideoCaptureBufferTrackerFactory> buffer_tracker_factory,
+    int count)
     : count_(count),
       next_buffer_id_(0),
-      last_relinquished_buffer_id_(kInvalidId) {
+      last_relinquished_buffer_id_(kInvalidId),
+      buffer_tracker_factory_(std::move(buffer_tracker_factory)) {
   DCHECK_GT(count, 0);
 }
 
@@ -236,7 +238,7 @@
   const int buffer_id = next_buffer_id_++;
 
   std::unique_ptr<VideoCaptureBufferTracker> tracker =
-      VideoCaptureBufferTrackerFactory::CreateTracker(storage_type);
+      buffer_tracker_factory_->CreateTracker(storage_type);
   // TODO(emircan): We pass the lock here to solve GMB allocation issue, see
   // crbug.com/545238.
   if (!tracker->Init(dimensions, pixel_format, storage_type, &lock_)) {
@@ -256,4 +258,4 @@
   return (it == trackers_.end()) ? NULL : it->second;
 }
 
-}  // namespace content
+}  // namespace media
diff --git a/media/capture/video/video_capture_buffer_pool_impl.h b/media/capture/video/video_capture_buffer_pool_impl.h
new file mode 100644
index 0000000..aa94367
--- /dev/null
+++ b/media/capture/video/video_capture_buffer_pool_impl.h
@@ -0,0 +1,95 @@
+// Copyright (c) 2013 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 MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_BUFFER_POOL_IMPL_H_
+#define MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_BUFFER_POOL_IMPL_H_
+
+#include <stddef.h>
+
+#include <map>
+
+#include "base/files/file.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/shared_memory.h"
+#include "base/process/process.h"
+#include "base/synchronization/lock.h"
+#include "build/build_config.h"
+#include "media/base/video_capture_types.h"
+#include "media/base/video_frame.h"
+#include "media/capture/capture_export.h"
+#include "media/capture/video/video_capture_buffer_handle.h"
+#include "media/capture/video/video_capture_buffer_pool.h"
+#include "media/capture/video/video_capture_buffer_tracker_factory.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/gpu_memory_buffer.h"
+
+namespace media {
+
+class CAPTURE_EXPORT VideoCaptureBufferPoolImpl
+    : public VideoCaptureBufferPool {
+ public:
+  explicit VideoCaptureBufferPoolImpl(
+      std::unique_ptr<VideoCaptureBufferTrackerFactory> buffer_tracker_factory,
+      int count);
+
+  // Implementation of VideoCaptureBufferPool interface:
+  bool ShareToProcess(int buffer_id,
+                      base::ProcessHandle process_handle,
+                      base::SharedMemoryHandle* new_handle) override;
+  bool ShareToProcess2(int buffer_id,
+                       int plane,
+                       base::ProcessHandle process_handle,
+                       gfx::GpuMemoryBufferHandle* new_handle) override;
+  std::unique_ptr<VideoCaptureBufferHandle> GetBufferHandle(
+      int buffer_id) override;
+  int ReserveForProducer(const gfx::Size& dimensions,
+                         media::VideoPixelFormat format,
+                         media::VideoPixelStorage storage,
+                         int* buffer_id_to_drop) override;
+  void RelinquishProducerReservation(int buffer_id) override;
+  int ResurrectLastForProducer(const gfx::Size& dimensions,
+                               media::VideoPixelFormat format,
+                               media::VideoPixelStorage storage) override;
+  double GetBufferPoolUtilization() const override;
+  void HoldForConsumers(int buffer_id, int num_clients) override;
+  void RelinquishConsumerHold(int buffer_id, int num_clients) override;
+
+ private:
+  friend class base::RefCountedThreadSafe<VideoCaptureBufferPoolImpl>;
+  ~VideoCaptureBufferPoolImpl() override;
+
+  int ReserveForProducerInternal(const gfx::Size& dimensions,
+                                 media::VideoPixelFormat format,
+                                 media::VideoPixelStorage storage,
+                                 int* tracker_id_to_drop);
+
+  VideoCaptureBufferTracker* GetTracker(int buffer_id);
+
+  // The max number of buffers that the pool is allowed to have at any moment.
+  const int count_;
+
+  // Protects everything below it.
+  mutable base::Lock lock_;
+
+  // The ID of the next buffer.
+  int next_buffer_id_;
+
+  // The ID of the buffer last relinquished by the producer (a candidate for
+  // resurrection).
+  int last_relinquished_buffer_id_;
+
+  // The buffers, indexed by the first parameter, a buffer id.
+  using TrackerMap = std::map<int, VideoCaptureBufferTracker*>;
+  TrackerMap trackers_;
+
+  const std::unique_ptr<VideoCaptureBufferTrackerFactory>
+      buffer_tracker_factory_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(VideoCaptureBufferPoolImpl);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_BUFFER_POOL_IMPL_H_
diff --git a/content/browser/renderer_host/media/video_capture_buffer_tracker.h b/media/capture/video/video_capture_buffer_tracker.h
similarity index 88%
rename from content/browser/renderer_host/media/video_capture_buffer_tracker.h
rename to media/capture/video/video_capture_buffer_tracker.h
index 182d42f..778459209 100644
--- a/content/browser/renderer_host/media/video_capture_buffer_tracker.h
+++ b/media/capture/video/video_capture_buffer_tracker.h
@@ -2,22 +2,22 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_TRACKER_H_
-#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_TRACKER_H_
+#ifndef MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_BUFFER_TRACKER_H_
+#define MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_BUFFER_TRACKER_H_
 
 #include <memory>
 
 #include "base/synchronization/lock.h"
-#include "content/browser/renderer_host/media/video_capture_buffer_handle.h"
 #include "media/base/video_capture_types.h"
+#include "media/capture/video/video_capture_buffer_handle.h"
 
-namespace content {
+namespace media {
 
 // Keeps track of the state of a given mappable resource. Each
 // VideoCaptureBufferTracker carries indication of pixel format and storage
 // type. This is a base class for implementations using different kinds of
 // storage.
-class VideoCaptureBufferTracker {
+class CAPTURE_EXPORT VideoCaptureBufferTracker {
  public:
   VideoCaptureBufferTracker()
       : max_pixel_count_(0),
@@ -75,4 +75,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_TRACKER_H_
+#endif  // MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_BUFFER_TRACKER_H_
diff --git a/media/capture/video/video_capture_buffer_tracker_factory.h b/media/capture/video/video_capture_buffer_tracker_factory.h
new file mode 100644
index 0000000..2828a5b
--- /dev/null
+++ b/media/capture/video/video_capture_buffer_tracker_factory.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2013 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 MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_BUFFER_TRACKER_FACTORY_H_
+#define MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_BUFFER_TRACKER_FACTORY_H_
+
+#include <memory>
+
+#include "media/base/video_capture_types.h"
+#include "media/capture/capture_export.h"
+
+namespace media {
+
+class VideoCaptureBufferTracker;
+
+class CAPTURE_EXPORT VideoCaptureBufferTrackerFactory {
+ public:
+  virtual ~VideoCaptureBufferTrackerFactory() {}
+  virtual std::unique_ptr<VideoCaptureBufferTracker> CreateTracker(
+      VideoPixelStorage storage_type) = 0;
+};
+
+}  // namespace media
+
+#endif  // MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_BUFFER_TRACKER_FACTORY_H_
diff --git a/media/capture/video/video_capture_device.h b/media/capture/video/video_capture_device.h
index cbdc8ad..b662f5c4 100644
--- a/media/capture/video/video_capture_device.h
+++ b/media/capture/video/video_capture_device.h
@@ -165,8 +165,31 @@
   // configured maximum frame rate. Any VideoCaptureDevice that does self-pause,
   // however, should provide an implementation of this method that makes
   // reasonable attempts to honor these requests.
+  //
+  // Note: This should only be called after AllocateAndStart() and before
+  // StopAndDeAllocate(). Otherwise, its behavior is undefined.
   virtual void RequestRefreshFrame() {}
 
+  // Optionally suspends frame delivery. The VideoCaptureDevice may or may not
+  // honor this request. Thus, the caller cannot assume frame delivery will
+  // actually stop. Even if frame delivery is suspended, this might not take
+  // effect immediately.
+  //
+  // The purpose of this is to quickly place the device into a state where it's
+  // resource utilization is minimized while there are no frame consumers; and
+  // then quickly resume once a frame consumer is present.
+  //
+  // Note: This should only be called after AllocateAndStart() and before
+  // StopAndDeAllocate(). Otherwise, its behavior is undefined.
+  virtual void MaybeSuspend() {}
+
+  // Resumes frame delivery, if it was suspended. If frame delivery was not
+  // suspended, this is a no-op, and frame delivery will continue.
+  //
+  // Note: This should only be called after AllocateAndStart() and before
+  // StopAndDeAllocate(). Otherwise, its behavior is undefined.
+  virtual void Resume() {}
+
   // Deallocates the video capturer, possibly asynchronously.
   //
   // This call requires the device to do the following things, eventually: put
diff --git a/content/browser/renderer_host/media/video_capture_device_client.cc b/media/capture/video/video_capture_device_client.cc
similarity index 88%
rename from content/browser/renderer_host/media/video_capture_device_client.cc
rename to media/capture/video/video_capture_device_client.cc
index a70f5992..368af81 100644
--- a/content/browser/renderer_host/media/video_capture_device_client.cc
+++ b/media/capture/video/video_capture_device_client.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 "content/browser/renderer_host/media/video_capture_device_client.h"
+#include "media/capture/video/video_capture_device_client.h"
 
 #include <algorithm>
 #include <utility>
@@ -14,21 +14,21 @@
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
-#include "content/browser/renderer_host/media/video_capture_buffer_handle.h"
-#include "content/browser/renderer_host/media/video_capture_buffer_pool.h"
-#include "content/browser/renderer_host/media/video_capture_controller.h"
-#include "content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/media_switches.h"
 #include "media/base/video_capture_types.h"
 #include "media/base/video_frame.h"
+#include "media/capture/video/video_capture_buffer_handle.h"
+#include "media/capture/video/video_capture_buffer_pool.h"
+#include "media/capture/video/video_capture_jpeg_decoder.h"
+#include "media/capture/video/video_frame_receiver.h"
 #include "third_party/libyuv/include/libyuv.h"
 
 using media::VideoCaptureFormat;
 using media::VideoFrame;
 using media::VideoFrameMetadata;
 
-namespace content {
+namespace media {
 
 // Class combining a Client::Buffer interface implementation and a pool buffer
 // implementation to guarantee proper cleanup on destruction on our side.
@@ -118,8 +118,8 @@
   if (rotation == 90 || rotation == 270)
     std::swap(destination_width, destination_height);
 
-  DCHECK_EQ(0, rotation % 90)
-      << " Rotation must be a multiple of 90, now: " << rotation;
+  DCHECK_EQ(0, rotation % 90) << " Rotation must be a multiple of 90, now: "
+                              << rotation;
   libyuv::RotationMode rotation_mode = libyuv::kRotate0;
   if (rotation == 90)
     rotation_mode = libyuv::kRotate90;
@@ -180,10 +180,10 @@
       origin_colorspace = libyuv::FOURCC_UYVY;
       break;
     case media::PIXEL_FORMAT_RGB24:
-      // Linux RGB24 defines red at lowest byte address,
-      // see http://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html.
-      // Windows RGB24 defines blue at lowest byte,
-      // see https://msdn.microsoft.com/en-us/library/windows/desktop/dd407253
+// Linux RGB24 defines red at lowest byte address,
+// see http://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html.
+// Windows RGB24 defines blue at lowest byte,
+// see https://msdn.microsoft.com/en-us/library/windows/desktop/dd407253
 #if defined(OS_LINUX)
       origin_colorspace = libyuv::FOURCC_RAW;
 #elif defined(OS_WIN)
@@ -220,13 +220,13 @@
   DCHECK_GE(static_cast<size_t>(length), frame_format.ImageAllocationSize());
 
   if (external_jpeg_decoder_) {
-    const VideoCaptureGpuJpegDecoder::STATUS status =
+    const VideoCaptureJpegDecoder::STATUS status =
         external_jpeg_decoder_->GetStatus();
-    if (status == VideoCaptureGpuJpegDecoder::FAILED) {
+    if (status == VideoCaptureJpegDecoder::FAILED) {
       external_jpeg_decoder_.reset();
-    } else if (status == VideoCaptureGpuJpegDecoder::INIT_PASSED &&
-        frame_format.pixel_format == media::PIXEL_FORMAT_MJPEG &&
-        rotation == 0 && !flip) {
+    } else if (status == VideoCaptureJpegDecoder::INIT_PASSED &&
+               frame_format.pixel_format == media::PIXEL_FORMAT_MJPEG &&
+               rotation == 0 && !flip) {
       external_jpeg_decoder_->DecodeCapturedData(data, length, frame_format,
                                                  reference_time, timestamp,
                                                  std::move(buffer));
@@ -234,30 +234,21 @@
     }
   }
 
-  if (libyuv::ConvertToI420(data,
-                            length,
-                            y_plane_data,
-                            yplane_stride,
-                            u_plane_data,
-                            uv_plane_stride,
-                            v_plane_data,
-                            uv_plane_stride,
-                            crop_x,
-                            crop_y,
+  if (libyuv::ConvertToI420(data, length, y_plane_data, yplane_stride,
+                            u_plane_data, uv_plane_stride, v_plane_data,
+                            uv_plane_stride, crop_x, crop_y,
                             frame_format.frame_size.width(),
                             (flip ? -1 : 1) * frame_format.frame_size.height(),
-                            new_unrotated_width,
-                            new_unrotated_height,
-                            rotation_mode,
-                            origin_colorspace) != 0) {
+                            new_unrotated_width, new_unrotated_height,
+                            rotation_mode, origin_colorspace) != 0) {
     DLOG(WARNING) << "Failed to convert buffer's pixel format to I420 from "
                   << media::VideoPixelFormatToString(frame_format.pixel_format);
     return;
   }
 
-  const VideoCaptureFormat output_format = VideoCaptureFormat(
-      dimensions, frame_format.frame_rate,
-      media::PIXEL_FORMAT_I420, output_pixel_storage);
+  const VideoCaptureFormat output_format =
+      VideoCaptureFormat(dimensions, frame_format.frame_rate,
+                         media::PIXEL_FORMAT_I420, output_pixel_storage);
   OnIncomingCapturedBuffer(std::move(buffer), output_format, reference_time,
                            timestamp);
 }
@@ -358,8 +349,7 @@
   receiver_->OnError();
 }
 
-void VideoCaptureDeviceClient::OnLog(
-    const std::string& message) {
+void VideoCaptureDeviceClient::OnLog(const std::string& message) {
   receiver_->OnLog(message);
 }
 
@@ -412,4 +402,4 @@
   return std::unique_ptr<Buffer>();
 }
 
-}  // namespace content
+}  // namespace media
diff --git a/content/browser/renderer_host/media/video_capture_device_client.h b/media/capture/video/video_capture_device_client.h
similarity index 92%
rename from content/browser/renderer_host/media/video_capture_device_client.h
rename to media/capture/video/video_capture_device_client.h
index ac63f8b..821c58d 100644
--- a/content/browser/renderer_host/media/video_capture_device_client.h
+++ b/media/capture/video/video_capture_device_client.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_DEVICE_CLIENT_H_
-#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_DEVICE_CLIENT_H_
+#ifndef MEDIA_CAPTURE_VIDEO_VIDEO_CAPTURE_DEVICE_CLIENT_H_
+#define MEDIA_CAPTURE_VIDEO_VIDEO_CAPTURE_DEVICE_CLIENT_H_
 
 #include <stddef.h>
 #include <stdint.h>
@@ -13,10 +13,10 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "content/common/content_export.h"
+#include "media/capture/capture_export.h"
 #include "media/capture/video/video_capture_device.h"
 
-namespace content {
+namespace media {
 class VideoCaptureBufferPool;
 class VideoFrameReceiver;
 class VideoCaptureJpegDecoder;
@@ -39,7 +39,7 @@
 // GpuMemoryBuffers into Texture backed VideoFrames. This class creates and
 // manages the necessary entities to interact with the GPU process, notably an
 // offscreen Context to avoid janking the UI thread.
-class CONTENT_EXPORT VideoCaptureDeviceClient
+class CAPTURE_EXPORT VideoCaptureDeviceClient
     : public media::VideoCaptureDevice::Client,
       public base::SupportsWeakPtr<VideoCaptureDeviceClient> {
  public:
@@ -125,7 +125,6 @@
   DISALLOW_COPY_AND_ASSIGN(VideoCaptureDeviceClient);
 };
 
+}  // namespace media
 
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_DEVICE_CLIENT_H_
+#endif  // MEDIA_CAPTURE_VIDEO_VIDEO_CAPTURE_DEVICE_CLIENT_H_
diff --git a/media/capture/video/video_capture_jpeg_decoder.h b/media/capture/video/video_capture_jpeg_decoder.h
new file mode 100644
index 0000000..e9d91dc
--- /dev/null
+++ b/media/capture/video/video_capture_jpeg_decoder.h
@@ -0,0 +1,45 @@
+// 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.
+
+#include "base/callback.h"
+#include "media/capture/capture_export.h"
+#include "media/capture/video/video_capture_device.h"
+
+namespace media {
+
+class CAPTURE_EXPORT VideoCaptureJpegDecoder {
+ public:
+  // Enumeration of decoder status. The enumeration is published for clients to
+  // decide the behavior according to STATUS.
+  enum STATUS {
+    INIT_PENDING,  // Default value while waiting initialization finished.
+    INIT_PASSED,   // Initialization succeed.
+    FAILED,        // JPEG decode is not supported, initialization failed, or
+                   // decode error.
+  };
+
+  using DecodeDoneCB = base::Callback<void(
+      std::unique_ptr<media::VideoCaptureDevice::Client::Buffer>,
+      const scoped_refptr<media::VideoFrame>&)>;
+
+  virtual ~VideoCaptureJpegDecoder() {}
+
+  // Creates and intializes decoder asynchronously.
+  virtual void Initialize() = 0;
+
+  // Returns initialization status.
+  virtual STATUS GetStatus() const = 0;
+
+  // Decodes a JPEG picture.
+  virtual void DecodeCapturedData(
+      const uint8_t* data,
+      size_t in_buffer_size,
+      const media::VideoCaptureFormat& frame_format,
+      base::TimeTicks reference_time,
+      base::TimeDelta timestamp,
+      std::unique_ptr<media::VideoCaptureDevice::Client::Buffer>
+          out_buffer) = 0;
+};
+
+}  // namespace media
diff --git a/media/capture/video/video_frame_receiver.h b/media/capture/video/video_frame_receiver.h
new file mode 100644
index 0000000..df2dabc
--- /dev/null
+++ b/media/capture/video/video_frame_receiver.h
@@ -0,0 +1,24 @@
+// 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.
+
+#include "media/capture/capture_export.h"
+#include "media/capture/video/video_capture_device.h"
+
+namespace media {
+
+// Callback interface for VideoCaptureDeviceClient to communicate with its
+// clients.
+class CAPTURE_EXPORT VideoFrameReceiver {
+ public:
+  virtual ~VideoFrameReceiver(){};
+
+  virtual void OnIncomingCapturedVideoFrame(
+      std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> buffer,
+      const scoped_refptr<media::VideoFrame>& frame) = 0;
+  virtual void OnError() = 0;
+  virtual void OnLog(const std::string& message) = 0;
+  virtual void OnBufferDestroyed(int buffer_id_to_drop) = 0;
+};
+
+}  // namespace media
diff --git a/media/cast/test/end2end_unittest.cc b/media/cast/test/end2end_unittest.cc
index 06b40a59..7d9994b 100644
--- a/media/cast/test/end2end_unittest.cc
+++ b/media/cast/test/end2end_unittest.cc
@@ -257,7 +257,7 @@
         AudioBus::Create(audio_bus.channels(), audio_bus.frames());
     audio_bus.CopyTo(expected_audio_frame->audio_bus.get());
     expected_audio_frame->playout_time = playout_time;
-    expected_frames_.push_back(expected_audio_frame.release());
+    expected_frames_.push_back(std::move(expected_audio_frame));
   }
 
   void IgnoreAudioFrame(std::unique_ptr<AudioBus> audio_bus,
@@ -273,8 +273,8 @@
 
     ASSERT_TRUE(audio_bus);
     ASSERT_FALSE(expected_frames_.empty());
-    const std::unique_ptr<ExpectedAudioFrame> expected_audio_frame(
-        expected_frames_.front());
+    const std::unique_ptr<ExpectedAudioFrame> expected_audio_frame =
+        std::move(expected_frames_.front());
     expected_frames_.pop_front();
 
     EXPECT_EQ(audio_bus->channels(), kAudioChannels);
@@ -304,7 +304,6 @@
 
  protected:
   virtual ~TestReceiverAudioCallback() {
-    base::STLDeleteElements(&expected_frames_);
   }
 
  private:
@@ -312,7 +311,7 @@
 
   int num_called_;
   int expected_sampling_frequency_;
-  std::list<ExpectedAudioFrame*> expected_frames_;
+  std::list<std::unique_ptr<ExpectedAudioFrame>> expected_frames_;
   base::TimeTicks last_playout_time_;
 };
 
diff --git a/media/cdm/aes_decryptor.cc b/media/cdm/aes_decryptor.cc
index 7e93f4a..37dc4172 100644
--- a/media/cdm/aes_decryptor.cc
+++ b/media/cdm/aes_decryptor.cc
@@ -11,7 +11,6 @@
 
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "crypto/encryptor.h"
 #include "crypto/symmetric_key.h"
@@ -38,11 +37,12 @@
   // Use a std::list to actually hold the data. Insertion is always done
   // at the front, so the "latest" decryption key is always the first one
   // in the list.
-  typedef std::list<std::pair<std::string, DecryptionKey*> > KeyList;
+  using KeyList =
+      std::list<std::pair<std::string, std::unique_ptr<DecryptionKey>>>;
 
  public:
   SessionIdDecryptionKeyMap() {}
-  ~SessionIdDecryptionKeyMap() { base::STLDeleteValues(&key_list_); }
+  ~SessionIdDecryptionKeyMap() {}
 
   // Replaces value if |session_id| is already present, or adds it if not.
   // This |decryption_key| becomes the latest until another insertion or
@@ -59,7 +59,7 @@
   // Returns the last inserted DecryptionKey.
   DecryptionKey* LatestDecryptionKey() {
     DCHECK(!key_list_.empty());
-    return key_list_.begin()->second;
+    return key_list_.begin()->second.get();
   }
 
   bool Contains(const std::string& session_id) {
@@ -84,8 +84,7 @@
   KeyList::iterator it = Find(session_id);
   if (it != key_list_.end())
     Erase(it);
-  DecryptionKey* raw_ptr = decryption_key.release();
-  key_list_.push_front(std::make_pair(session_id, raw_ptr));
+  key_list_.push_front(std::make_pair(session_id, std::move(decryption_key)));
 }
 
 void AesDecryptor::SessionIdDecryptionKeyMap::Erase(
@@ -108,7 +107,6 @@
 void AesDecryptor::SessionIdDecryptionKeyMap::Erase(
     KeyList::iterator position) {
   DCHECK(position->second);
-  delete position->second;
   key_list_.erase(position);
 }
 
diff --git a/media/ffmpeg/ffmpeg_common.cc b/media/ffmpeg/ffmpeg_common.cc
index a37e0c3..8c4a55c 100644
--- a/media/ffmpeg/ffmpeg_common.cc
+++ b/media/ffmpeg/ffmpeg_common.cc
@@ -653,16 +653,22 @@
       return PIXEL_FORMAT_YUV420P9;
     case AV_PIX_FMT_YUV420P10LE:
       return PIXEL_FORMAT_YUV420P10;
+    case AV_PIX_FMT_YUV420P12LE:
+      return PIXEL_FORMAT_YUV420P12;
 
     case AV_PIX_FMT_YUV422P9LE:
       return PIXEL_FORMAT_YUV422P9;
     case AV_PIX_FMT_YUV422P10LE:
       return PIXEL_FORMAT_YUV422P10;
+    case AV_PIX_FMT_YUV422P12LE:
+      return PIXEL_FORMAT_YUV422P12;
 
     case AV_PIX_FMT_YUV444P9LE:
       return PIXEL_FORMAT_YUV444P9;
     case AV_PIX_FMT_YUV444P10LE:
       return PIXEL_FORMAT_YUV444P10;
+    case AV_PIX_FMT_YUV444P12LE:
+      return PIXEL_FORMAT_YUV444P12;
 
     default:
       DVLOG(1) << "Unsupported AVPixelFormat: " << pixel_format;
@@ -684,14 +690,20 @@
       return AV_PIX_FMT_YUV420P9LE;
     case PIXEL_FORMAT_YUV420P10:
       return AV_PIX_FMT_YUV420P10LE;
+    case PIXEL_FORMAT_YUV420P12:
+      return AV_PIX_FMT_YUV420P12LE;
     case PIXEL_FORMAT_YUV422P9:
       return AV_PIX_FMT_YUV422P9LE;
     case PIXEL_FORMAT_YUV422P10:
       return AV_PIX_FMT_YUV422P10LE;
+    case PIXEL_FORMAT_YUV422P12:
+      return AV_PIX_FMT_YUV422P12LE;
     case PIXEL_FORMAT_YUV444P9:
       return AV_PIX_FMT_YUV444P9LE;
     case PIXEL_FORMAT_YUV444P10:
       return AV_PIX_FMT_YUV444P10LE;
+    case PIXEL_FORMAT_YUV444P12:
+      return AV_PIX_FMT_YUV444P12LE;
 
     default:
       DVLOG(1) << "Unsupported Format: " << video_format;
diff --git a/media/filters/android/media_codec_audio_decoder.cc b/media/filters/android/media_codec_audio_decoder.cc
index f002dff..961e462 100644
--- a/media/filters/android/media_codec_audio_decoder.cc
+++ b/media/filters/android/media_codec_audio_decoder.cc
@@ -80,6 +80,8 @@
   config_ = config;
   output_cb_ = BindToCurrentLoop(output_cb);
 
+  ResetTimestampState();
+
   if (config_.is_encrypted()) {
     // Postpone initialization after MediaCrypto is available.
     // SetCdm uses init_cb in a method that's already bound to the current loop.
@@ -93,7 +95,6 @@
     return;
   }
 
-  ResetTimestampState();
   SetState(STATE_READY);
   bound_init_cb.Run(true);
 }
diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc
index c50923c..9c3a9d76 100644
--- a/media/filters/chunk_demuxer.cc
+++ b/media/filters/chunk_demuxer.cc
@@ -12,8 +12,8 @@
 #include "base/callback_helpers.h"
 #include "base/location.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "media/base/audio_decoder_config.h"
 #include "media/base/bind_to_current_loop.h"
@@ -621,7 +621,7 @@
       base::Bind(&ChunkDemuxer::OnSourceInitDone, base::Unretained(this), id),
       expected_mss_codecs, encrypted_media_init_data_cb_, new_text_track_cb);
 
-  source_state_map_[id] = source_state.release();
+  source_state_map_[id] = std::move(source_state);
   return kOk;
 }
 
@@ -638,7 +638,6 @@
   base::AutoLock auto_lock(lock_);
   CHECK(IsValidId(id));
 
-  delete source_state_map_[id];
   source_state_map_.erase(id);
   pending_source_init_ids_.erase(id);
   // Remove demuxer streams created for this id.
@@ -671,7 +670,7 @@
   base::AutoLock auto_lock(lock_);
   DCHECK(!id.empty());
 
-  MediaSourceStateMap::const_iterator itr = source_state_map_.find(id);
+  auto itr = source_state_map_.find(id);
 
   DCHECK(itr != source_state_map_.end());
   return itr->second->GetBufferedRanges(duration_, state_ == ENDED);
@@ -682,7 +681,7 @@
   base::AutoLock auto_lock(lock_);
   DCHECK(!id.empty());
 
-  MediaSourceStateMap::const_iterator itr = source_state_map_.find(id);
+  auto itr = source_state_map_.find(id);
 
   DCHECK(itr != source_state_map_.end());
   return itr->second->GetHighestPresentationTimestamp();
@@ -757,7 +756,7 @@
       DecodeTimestamp::FromPresentationTime(currentMediaTime);
 
   DCHECK(!id.empty());
-  MediaSourceStateMap::const_iterator itr = source_state_map_.find(id);
+  auto itr = source_state_map_.find(id);
   if (itr == source_state_map_.end()) {
     LOG(WARNING) << __func__ << " stream " << id << " not found";
     return false;
@@ -924,8 +923,8 @@
   duration_ = duration_td;
   host_->SetDuration(duration_);
 
-  for (MediaSourceStateMap::iterator itr = source_state_map_.begin();
-       itr != source_state_map_.end(); ++itr) {
+  for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
+       ++itr) {
     itr->second->OnSetDuration(duration_);
   }
 }
@@ -977,8 +976,8 @@
   }
 
   bool old_waiting_for_data = IsSeekWaitingForData_Locked();
-  for (MediaSourceStateMap::iterator itr = source_state_map_.begin();
-       itr != source_state_map_.end(); ++itr) {
+  for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
+       ++itr) {
     itr->second->MarkEndOfStream();
   }
 
@@ -1008,8 +1007,8 @@
 
   ChangeState_Locked(INITIALIZED);
 
-  for (MediaSourceStateMap::iterator itr = source_state_map_.begin();
-       itr != source_state_map_.end(); ++itr) {
+  for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
+       ++itr) {
     itr->second->UnmarkEndOfStream();
   }
 }
@@ -1031,8 +1030,8 @@
 
 void ChunkDemuxer::SetMemoryLimitsForTest(DemuxerStream::Type type,
                                           size_t memory_limit) {
-  for (MediaSourceStateMap::iterator itr = source_state_map_.begin();
-       itr != source_state_map_.end(); ++itr) {
+  for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
+       ++itr) {
     itr->second->SetMemoryLimits(type, memory_limit);
   }
 }
@@ -1046,8 +1045,6 @@
 
 ChunkDemuxer::~ChunkDemuxer() {
   DCHECK_NE(state_, INITIALIZED);
-
-  base::STLDeleteValues(&source_state_map_);
 }
 
 void ChunkDemuxer::ReportError_Locked(PipelineStatus error) {
@@ -1079,8 +1076,8 @@
 
 bool ChunkDemuxer::IsSeekWaitingForData_Locked() const {
   lock_.AssertAcquired();
-  for (MediaSourceStateMap::const_iterator itr = source_state_map_.begin();
-       itr != source_state_map_.end(); ++itr) {
+  for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
+       ++itr) {
     if (itr->second->IsSeekWaitingForData())
       return true;
   }
@@ -1175,40 +1172,35 @@
 
   MediaTrack::Id media_track_id = GenerateMediaTrackId();
 
+  OwnedChunkDemuxerStreamVector* owning_vector = nullptr;
   switch (type) {
-    case DemuxerStream::AUDIO: {
-      std::unique_ptr<ChunkDemuxerStream> audio_stream(new ChunkDemuxerStream(
-          DemuxerStream::AUDIO, splice_frames_enabled_, media_track_id));
-      DCHECK(track_id_to_demux_stream_map_.find(media_track_id) ==
-             track_id_to_demux_stream_map_.end());
-      track_id_to_demux_stream_map_[media_track_id] = audio_stream.get();
-      id_to_streams_map_[source_id].push_back(audio_stream.get());
-      audio_streams_.push_back(std::move(audio_stream));
-      return audio_streams_.back().get();
-    }
-    case DemuxerStream::VIDEO: {
-      std::unique_ptr<ChunkDemuxerStream> video_stream(new ChunkDemuxerStream(
-          DemuxerStream::VIDEO, splice_frames_enabled_, media_track_id));
-      DCHECK(track_id_to_demux_stream_map_.find(media_track_id) ==
-             track_id_to_demux_stream_map_.end());
-      track_id_to_demux_stream_map_[media_track_id] = video_stream.get();
-      id_to_streams_map_[source_id].push_back(video_stream.get());
-      video_streams_.push_back(std::move(video_stream));
-      return video_streams_.back().get();
-    }
-    case DemuxerStream::TEXT: {
-      ChunkDemuxerStream* text_stream = new ChunkDemuxerStream(
-          DemuxerStream::TEXT, splice_frames_enabled_, media_track_id);
-      id_to_streams_map_[source_id].push_back(text_stream);
-      return text_stream;
-    }
+    case DemuxerStream::AUDIO:
+      owning_vector = &audio_streams_;
+      break;
+
+    case DemuxerStream::VIDEO:
+      owning_vector = &video_streams_;
+      break;
+
+    case DemuxerStream::TEXT:
+      owning_vector = &text_streams_;
+      break;
+
     case DemuxerStream::UNKNOWN:
     case DemuxerStream::NUM_TYPES:
       NOTREACHED();
-      return NULL;
+      return nullptr;
   }
-  NOTREACHED();
-  return NULL;
+
+  std::unique_ptr<ChunkDemuxerStream> stream =
+      base::MakeUnique<ChunkDemuxerStream>(type, splice_frames_enabled_,
+                                           media_track_id);
+  DCHECK(track_id_to_demux_stream_map_.find(media_track_id) ==
+         track_id_to_demux_stream_map_.end());
+  track_id_to_demux_stream_map_[media_track_id] = stream.get();
+  id_to_streams_map_[source_id].push_back(stream.get());
+  owning_vector->push_back(std::move(stream));
+  return owning_vector->back().get();
 }
 
 void ChunkDemuxer::OnNewTextTrack(ChunkDemuxerStream* text_stream,
@@ -1255,8 +1247,8 @@
 
   TimeDelta max_duration;
 
-  for (MediaSourceStateMap::const_iterator itr = source_state_map_.begin();
-       itr != source_state_map_.end(); ++itr) {
+  for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
+       ++itr) {
     max_duration = std::max(max_duration,
                             itr->second->GetMaxBufferedDuration());
   }
@@ -1280,8 +1272,8 @@
   // TODO(acolwell): When we start allowing SourceBuffers that are not active,
   // we'll need to update this loop to only add ranges from active sources.
   MediaSourceState::RangesList ranges_list;
-  for (MediaSourceStateMap::const_iterator itr = source_state_map_.begin();
-       itr != source_state_map_.end(); ++itr) {
+  for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
+       ++itr) {
     ranges_list.push_back(itr->second->GetBufferedRanges(duration_, ended));
   }
 
@@ -1289,36 +1281,36 @@
 }
 
 void ChunkDemuxer::StartReturningData() {
-  for (MediaSourceStateMap::iterator itr = source_state_map_.begin();
-       itr != source_state_map_.end(); ++itr) {
+  for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
+       ++itr) {
     itr->second->StartReturningData();
   }
 }
 
 void ChunkDemuxer::AbortPendingReads_Locked() {
-  for (MediaSourceStateMap::iterator itr = source_state_map_.begin();
-       itr != source_state_map_.end(); ++itr) {
+  for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
+       ++itr) {
     itr->second->AbortReads();
   }
 }
 
 void ChunkDemuxer::SeekAllSources(TimeDelta seek_time) {
-  for (MediaSourceStateMap::iterator itr = source_state_map_.begin();
-       itr != source_state_map_.end(); ++itr) {
+  for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
+       ++itr) {
     itr->second->Seek(seek_time);
   }
 }
 
 void ChunkDemuxer::CompletePendingReadsIfPossible() {
-  for (MediaSourceStateMap::iterator itr = source_state_map_.begin();
-       itr != source_state_map_.end(); ++itr) {
+  for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
+       ++itr) {
     itr->second->CompletePendingReadIfPossible();
   }
 }
 
 void ChunkDemuxer::ShutdownAllStreams() {
-  for (MediaSourceStateMap::iterator itr = source_state_map_.begin();
-       itr != source_state_map_.end(); ++itr) {
+  for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
+       ++itr) {
     itr->second->Shutdown();
   }
 }
diff --git a/media/filters/chunk_demuxer.h b/media/filters/chunk_demuxer.h
index 5601e7f..0ab9c1b 100644
--- a/media/filters/chunk_demuxer.h
+++ b/media/filters/chunk_demuxer.h
@@ -413,8 +413,11 @@
   // http://crbug.com/308226
   PipelineStatusCB seek_cb_;
 
-  std::vector<std::unique_ptr<ChunkDemuxerStream>> audio_streams_;
-  std::vector<std::unique_ptr<ChunkDemuxerStream>> video_streams_;
+  using OwnedChunkDemuxerStreamVector =
+      std::vector<std::unique_ptr<ChunkDemuxerStream>>;
+  OwnedChunkDemuxerStreamVector audio_streams_;
+  OwnedChunkDemuxerStreamVector video_streams_;
+  OwnedChunkDemuxerStreamVector text_streams_;
 
   // Keep track of which ids still remain uninitialized so that we transition
   // into the INITIALIZED only after all ids/SourceBuffers got init segment.
@@ -432,8 +435,7 @@
   base::Time timeline_offset_;
   DemuxerStream::Liveness liveness_;
 
-  typedef std::map<std::string, MediaSourceState*> MediaSourceStateMap;
-  MediaSourceStateMap source_state_map_;
+  std::map<std::string, std::unique_ptr<MediaSourceState>> source_state_map_;
 
   std::map<std::string, std::vector<ChunkDemuxerStream*>> id_to_streams_map_;
   // Used to hold alive the demuxer streams that were created for removed /
diff --git a/media/filters/ffmpeg_video_decoder.cc b/media/filters/ffmpeg_video_decoder.cc
index 0dfd6a0..05849f2 100644
--- a/media/filters/ffmpeg_video_decoder.cc
+++ b/media/filters/ffmpeg_video_decoder.cc
@@ -96,7 +96,8 @@
          format == PIXEL_FORMAT_YV24 || format == PIXEL_FORMAT_YUV420P9 ||
          format == PIXEL_FORMAT_YUV420P10 || format == PIXEL_FORMAT_YUV422P9 ||
          format == PIXEL_FORMAT_YUV422P10 || format == PIXEL_FORMAT_YUV444P9 ||
-         format == PIXEL_FORMAT_YUV444P10);
+         format == PIXEL_FORMAT_YUV444P10 || format == PIXEL_FORMAT_YUV420P12 ||
+         format == PIXEL_FORMAT_YUV422P12 || format == PIXEL_FORMAT_YUV444P12);
 
   gfx::Size size(codec_context->width, codec_context->height);
   const int ret = av_image_check_size(size.width(), size.height(), 0, NULL);
diff --git a/media/filters/frame_processor.cc b/media/filters/frame_processor.cc
index c6b1bc0..0430c08 100644
--- a/media/filters/frame_processor.cc
+++ b/media/filters/frame_processor.cc
@@ -9,7 +9,7 @@
 #include <cstdlib>
 
 #include "base/macros.h"
-#include "base/stl_util.h"
+#include "base/memory/ptr_util.h"
 #include "media/base/stream_parser_buffer.h"
 #include "media/base/timestamp_constants.h"
 
@@ -172,7 +172,6 @@
 
 FrameProcessor::~FrameProcessor() {
   DVLOG(2) << __func__ << "()";
-  base::STLDeleteValues(&track_buffers_);
 }
 
 void FrameProcessor::SetSequenceMode(bool sequence_mode) {
@@ -260,7 +259,7 @@
     return false;
   }
 
-  track_buffers_[id] = new MseTrackBuffer(stream);
+  track_buffers_[id] = base::MakeUnique<MseTrackBuffer>(stream);
   return true;
 }
 
@@ -274,30 +273,27 @@
     return false;
   }
 
-  track_buffers_[new_id] = track_buffers_[old_id];
+  track_buffers_[new_id] = std::move(track_buffers_[old_id]);
   CHECK_EQ(1u, track_buffers_.erase(old_id));
   return true;
 }
 
 void FrameProcessor::SetAllTrackBuffersNeedRandomAccessPoint() {
-  for (TrackBufferMap::iterator itr = track_buffers_.begin();
-       itr != track_buffers_.end();
-       ++itr) {
+  for (auto itr = track_buffers_.begin(); itr != track_buffers_.end(); ++itr) {
     itr->second->set_needs_random_access_point(true);
   }
 }
 
 void FrameProcessor::Reset() {
   DVLOG(2) << __func__ << "()";
-  for (TrackBufferMap::iterator itr = track_buffers_.begin();
-       itr != track_buffers_.end(); ++itr) {
+  for (auto itr = track_buffers_.begin(); itr != track_buffers_.end(); ++itr) {
     itr->second->Reset();
   }
 
   // Maintain current |coded_frame_group_last_dts_| state for Reset() during
   // sequence mode. Reset it here only if in segments mode. In sequence mode,
   // the current coded frame group may be continued across Reset() operations to
-  // allow the stream to coaelesce what might otherwise be gaps in the buffered
+  // allow the stream to coalesce what might otherwise be gaps in the buffered
   // ranges. See also the declaration for |coded_frame_group_last_dts_|.
   if (!sequence_mode_) {
     coded_frame_group_last_dts_ = kNoDecodeTimestamp();
@@ -325,20 +321,18 @@
 }
 
 MseTrackBuffer* FrameProcessor::FindTrack(StreamParser::TrackId id) {
-  TrackBufferMap::iterator itr = track_buffers_.find(id);
+  auto itr = track_buffers_.find(id);
   if (itr == track_buffers_.end())
     return NULL;
 
-  return itr->second;
+  return itr->second.get();
 }
 
 void FrameProcessor::NotifyStartOfCodedFrameGroup(
     DecodeTimestamp start_timestamp) {
   DVLOG(2) << __func__ << "(" << start_timestamp.InSecondsF() << ")";
 
-  for (TrackBufferMap::iterator itr = track_buffers_.begin();
-       itr != track_buffers_.end();
-       ++itr) {
+  for (auto itr = track_buffers_.begin(); itr != track_buffers_.end(); ++itr) {
     itr->second->stream()->OnStartOfCodedFrameGroup(start_timestamp);
   }
 }
@@ -347,9 +341,7 @@
   DVLOG(2) << __func__ << "()";
 
   bool result = true;
-  for (TrackBufferMap::iterator itr = track_buffers_.begin();
-       itr != track_buffers_.end();
-       ++itr) {
+  for (auto itr = track_buffers_.begin(); itr != track_buffers_.end(); ++itr) {
     if (!itr->second->FlushProcessedFrames())
       result = false;
   }
diff --git a/media/filters/frame_processor.h b/media/filters/frame_processor.h
index e83c2d1..69a313e 100644
--- a/media/filters/frame_processor.h
+++ b/media/filters/frame_processor.h
@@ -6,6 +6,7 @@
 #define MEDIA_FILTERS_FRAME_PROCESSOR_H_
 
 #include <map>
+#include <memory>
 
 #include "base/callback_forward.h"
 #include "base/macros.h"
@@ -80,8 +81,6 @@
  private:
   friend class FrameProcessorTest;
 
-  typedef std::map<StreamParser::TrackId, MseTrackBuffer*> TrackBufferMap;
-
   // If |track_buffers_| contains |id|, returns a pointer to the associated
   // MseTrackBuffer. Otherwise, returns NULL.
   MseTrackBuffer* FindTrack(StreamParser::TrackId id);
@@ -124,7 +123,8 @@
                     base::TimeDelta* timestamp_offset);
 
   // TrackId-indexed map of each track's stream.
-  TrackBufferMap track_buffers_;
+  std::map<StreamParser::TrackId, std::unique_ptr<MseTrackBuffer>>
+      track_buffers_;
 
   // The last audio buffer seen by the frame processor that was removed because
   // it was entirely before the start of the append window.
diff --git a/media/filters/h264_parser.cc b/media/filters/h264_parser.cc
index 991599e..7aced4c 100644
--- a/media/filters/h264_parser.cc
+++ b/media/filters/h264_parser.cc
@@ -10,7 +10,6 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/numerics/safe_math.h"
-#include "base/stl_util.h"
 #include "media/base/decrypt_config.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
@@ -206,8 +205,6 @@
 }
 
 H264Parser::~H264Parser() {
-  base::STLDeleteValues(&active_SPSes_);
-  base::STLDeleteValues(&active_PPSes_);
 }
 
 void H264Parser::Reset() {
@@ -251,7 +248,7 @@
     return nullptr;
   }
 
-  return it->second;
+  return it->second.get();
 }
 
 const H264SPS* H264Parser::GetSPS(int sps_id) const {
@@ -261,7 +258,7 @@
     return nullptr;
   }
 
-  return it->second;
+  return it->second.get();
 }
 
 static inline bool IsStartCode(const uint8_t* data) {
@@ -999,8 +996,7 @@
 
   // If an SPS with the same id already exists, replace it.
   *sps_id = sps->seq_parameter_set_id;
-  delete active_SPSes_[*sps_id];
-  active_SPSes_[*sps_id] = sps.release();
+  active_SPSes_[*sps_id] = std::move(sps);
 
   return kOk;
 }
@@ -1075,8 +1071,7 @@
 
   // If a PPS with the same id already exists, replace it.
   *pps_id = pps->pic_parameter_set_id;
-  delete active_PPSes_[*pps_id];
-  active_PPSes_[*pps_id] = pps.release();
+  active_PPSes_[*pps_id] = std::move(pps);
 
   return kOk;
 }
diff --git a/media/filters/h264_parser.h b/media/filters/h264_parser.h
index 64519e8..e7f4bc4c 100644
--- a/media/filters/h264_parser.h
+++ b/media/filters/h264_parser.h
@@ -12,6 +12,7 @@
 #include <sys/types.h>
 
 #include <map>
+#include <memory>
 #include <vector>
 
 #include "base/macros.h"
@@ -486,10 +487,8 @@
   H264BitReader br_;
 
   // PPSes and SPSes stored for future reference.
-  typedef std::map<int, H264SPS*> SPSById;
-  typedef std::map<int, H264PPS*> PPSById;
-  SPSById active_SPSes_;
-  PPSById active_PPSes_;
+  std::map<int, std::unique_ptr<H264SPS>> active_SPSes_;
+  std::map<int, std::unique_ptr<H264PPS>> active_PPSes_;
 
   // Ranges of encrypted bytes in the buffer passed to
   // SetEncryptedStream().
diff --git a/media/filters/media_source_state.cc b/media/filters/media_source_state.cc
index a4630e2..801e3f0 100644
--- a/media/filters/media_source_state.cc
+++ b/media/filters/media_source_state.cc
@@ -8,7 +8,6 @@
 
 #include "base/callback_helpers.h"
 #include "base/command_line.h"
-#include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "media/base/media_switches.h"
 #include "media/base/media_track.h"
@@ -66,7 +65,7 @@
   // TODO(servolk): Perhaps this can be removed in favor of blink implementation
   // (MediaSource::buffered)? Currently this is only used on Android and for
   // updating DemuxerHost's buffered ranges during AppendData() as well as
-  // SourceBuffer.buffered property implemetation.
+  // SourceBuffer.buffered property implementation.
   // Implementation of HTMLMediaElement.buffered algorithm in MSE spec.
   // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#dom-htmlmediaelement.buffered
 
@@ -135,8 +134,6 @@
 
 MediaSourceState::~MediaSourceState() {
   Shutdown();
-
-  base::STLDeleteValues(&text_stream_map_);
 }
 
 void MediaSourceState::Init(
@@ -254,9 +251,8 @@
     it.second->Remove(start, end, duration);
   }
 
-  for (TextStreamMap::iterator itr = text_stream_map_.begin();
-       itr != text_stream_map_.end(); ++itr) {
-    itr->second->Remove(start, end, duration);
+  for (const auto& it : text_streams_) {
+    it.second->Remove(start, end, duration);
   }
 }
 
@@ -267,7 +263,7 @@
     total_buffered_size += it.second->GetBufferedSize();
   for (const auto& it : video_streams_)
     total_buffered_size += it.second->GetBufferedSize();
-  for (const auto& it : text_stream_map_)
+  for (const auto& it : text_streams_)
     total_buffered_size += it.second->GetBufferedSize();
 
   DVLOG(3) << __func__ << " media_time=" << media_time.InSecondsF()
@@ -296,7 +292,7 @@
     success &= it.second->EvictCodedFrames(
         media_time, static_cast<size_t>(estimated_new_size));
   }
-  for (const auto& it : text_stream_map_) {
+  for (const auto& it : text_streams_) {
     uint64_t curr_size = it.second->GetBufferedSize();
     if (curr_size == 0)
       continue;
@@ -319,10 +315,8 @@
   for (const auto& it : video_streams_)
     ranges_list.push_back(it.second->GetBufferedRanges(duration));
 
-  for (TextStreamMap::const_iterator itr = text_stream_map_.begin();
-       itr != text_stream_map_.end(); ++itr) {
-    ranges_list.push_back(itr->second->GetBufferedRanges(duration));
-  }
+  for (const auto& it : text_streams_)
+    ranges_list.push_back(it.second->GetBufferedRanges(duration));
 
   return ComputeRangesIntersection(ranges_list, ended);
 }
@@ -338,9 +332,8 @@
     max_pts = std::max(max_pts, it.second->GetHighestPresentationTimestamp());
   }
 
-  for (TextStreamMap::const_iterator itr = text_stream_map_.begin();
-       itr != text_stream_map_.end(); ++itr) {
-    max_pts = std::max(max_pts, itr->second->GetHighestPresentationTimestamp());
+  for (const auto& it : text_streams_) {
+    max_pts = std::max(max_pts, it.second->GetHighestPresentationTimestamp());
   }
 
   return max_pts;
@@ -357,9 +350,8 @@
     max_duration = std::max(max_duration, it.second->GetBufferedDuration());
   }
 
-  for (TextStreamMap::const_iterator itr = text_stream_map_.begin();
-       itr != text_stream_map_.end(); ++itr) {
-    max_duration = std::max(max_duration, itr->second->GetBufferedDuration());
+  for (const auto& it : text_streams_) {
+    max_duration = std::max(max_duration, it.second->GetBufferedDuration());
   }
 
   return max_duration;
@@ -374,9 +366,8 @@
     it.second->StartReturningData();
   }
 
-  for (TextStreamMap::iterator itr = text_stream_map_.begin();
-       itr != text_stream_map_.end(); ++itr) {
-    itr->second->StartReturningData();
+  for (const auto& it : text_streams_) {
+    it.second->StartReturningData();
   }
 }
 
@@ -389,9 +380,8 @@
     it.second->AbortReads();
   }
 
-  for (TextStreamMap::iterator itr = text_stream_map_.begin();
-       itr != text_stream_map_.end(); ++itr) {
-    itr->second->AbortReads();
+  for (const auto& it : text_streams_) {
+    it.second->AbortReads();
   }
 }
 
@@ -404,9 +394,8 @@
     it.second->Seek(seek_time);
   }
 
-  for (TextStreamMap::iterator itr = text_stream_map_.begin();
-       itr != text_stream_map_.end(); ++itr) {
-    itr->second->Seek(seek_time);
+  for (const auto& it : text_streams_) {
+    it.second->Seek(seek_time);
   }
 }
 
@@ -419,9 +408,8 @@
     it.second->CompletePendingReadIfPossible();
   }
 
-  for (TextStreamMap::iterator itr = text_stream_map_.begin();
-       itr != text_stream_map_.end(); ++itr) {
-    itr->second->CompletePendingReadIfPossible();
+  for (const auto& it : text_streams_) {
+    it.second->CompletePendingReadIfPossible();
   }
 }
 
@@ -434,9 +422,8 @@
     it.second->OnSetDuration(duration);
   }
 
-  for (TextStreamMap::iterator itr = text_stream_map_.begin();
-       itr != text_stream_map_.end(); ++itr) {
-    itr->second->OnSetDuration(duration);
+  for (const auto& it : text_streams_) {
+    it.second->OnSetDuration(duration);
   }
 }
 
@@ -449,9 +436,8 @@
     it.second->MarkEndOfStream();
   }
 
-  for (TextStreamMap::iterator itr = text_stream_map_.begin();
-       itr != text_stream_map_.end(); ++itr) {
-    itr->second->MarkEndOfStream();
+  for (const auto& it : text_streams_) {
+    it.second->MarkEndOfStream();
   }
 }
 
@@ -464,9 +450,8 @@
     it.second->UnmarkEndOfStream();
   }
 
-  for (TextStreamMap::iterator itr = text_stream_map_.begin();
-       itr != text_stream_map_.end(); ++itr) {
-    itr->second->UnmarkEndOfStream();
+  for (const auto& it : text_streams_) {
+    it.second->UnmarkEndOfStream();
   }
 }
 
@@ -479,9 +464,8 @@
     it.second->Shutdown();
   }
 
-  for (TextStreamMap::iterator itr = text_stream_map_.begin();
-       itr != text_stream_map_.end(); ++itr) {
-    itr->second->Shutdown();
+  for (const auto& it : text_streams_) {
+    it.second->Shutdown();
   }
 }
 
@@ -499,9 +483,8 @@
       }
       break;
     case DemuxerStream::TEXT:
-      for (TextStreamMap::iterator itr = text_stream_map_.begin();
-           itr != text_stream_map_.end(); ++itr) {
-        itr->second->SetStreamMemoryLimit(memory_limit);
+      for (const auto& it : text_streams_) {
+        it.second->SetStreamMemoryLimit(memory_limit);
       }
       break;
     case DemuxerStream::UNKNOWN:
@@ -601,7 +584,7 @@
             stream = it->second;
         } else {
           // If there is only one audio track then bytestream id might change in
-          // a new init segment. So update our state and nofity frame processor.
+          // a new init segment. So update our state and notify frame processor.
           const auto& it = audio_streams_.begin();
           if (it != audio_streams_.end()) {
             stream = it->second;
@@ -657,7 +640,7 @@
             stream = it->second;
         } else {
           // If there is only one video track then bytestream id might change in
-          // a new init segment. So update our state and nofity frame processor.
+          // a new init segment. So update our state and notify frame processor.
           const auto& it = video_streams_.begin();
           if (it != video_streams_.end()) {
             stream = it->second;
@@ -696,10 +679,8 @@
     return false;
   }
 
-  typedef StreamParser::TextTrackConfigMap::const_iterator TextConfigItr;
-  if (text_stream_map_.empty()) {
-    for (TextConfigItr itr = text_configs.begin(); itr != text_configs.end();
-         ++itr) {
+  if (text_streams_.empty()) {
+    for (auto itr = text_configs.begin(); itr != text_configs.end(); ++itr) {
       ChunkDemuxerStream* const text_stream =
           create_demuxer_stream_cb_.Run(DemuxerStream::TEXT);
       if (!frame_processor_->AddTrack(itr->first, text_stream)) {
@@ -709,18 +690,18 @@
         break;
       }
       text_stream->UpdateTextConfig(itr->second, media_log_);
-      text_stream_map_[itr->first] = text_stream;
+      text_streams_[itr->first] = text_stream;
       new_text_track_cb_.Run(text_stream, itr->second);
     }
   } else {
-    const size_t text_count = text_stream_map_.size();
+    const size_t text_count = text_streams_.size();
     if (text_configs.size() != text_count) {
       success &= false;
       MEDIA_LOG(ERROR, media_log_)
           << "The number of text track configs changed.";
     } else if (text_count == 1) {
-      TextConfigItr config_itr = text_configs.begin();
-      TextStreamMap::iterator stream_itr = text_stream_map_.begin();
+      auto config_itr = text_configs.begin();
+      auto stream_itr = text_streams_.begin();
       ChunkDemuxerStream* text_stream = stream_itr->second;
       TextTrackConfig old_config = text_stream->text_track_config();
       TextTrackConfig new_config(
@@ -735,8 +716,8 @@
         StreamParser::TrackId new_id = config_itr->first;
         if (new_id != old_id) {
           if (frame_processor_->UpdateTrack(old_id, new_id)) {
-            text_stream_map_.clear();
-            text_stream_map_[config_itr->first] = text_stream;
+            text_streams_.clear();
+            text_streams_[config_itr->first] = text_stream;
           } else {
             success &= false;
             MEDIA_LOG(ERROR, media_log_)
@@ -745,11 +726,10 @@
         }
       }
     } else {
-      for (TextConfigItr config_itr = text_configs.begin();
+      for (auto config_itr = text_configs.begin();
            config_itr != text_configs.end(); ++config_itr) {
-        TextStreamMap::iterator stream_itr =
-            text_stream_map_.find(config_itr->first);
-        if (stream_itr == text_stream_map_.end()) {
+        auto stream_itr = text_streams_.find(config_itr->first);
+        if (stream_itr == text_streams_.end()) {
           success &= false;
           MEDIA_LOG(ERROR, media_log_)
               << "Unexpected text track configuration for track ID "
diff --git a/media/filters/media_source_state.h b/media/filters/media_source_state.h
index 588cc90d..0e1012f1 100644
--- a/media/filters/media_source_state.h
+++ b/media/filters/media_source_state.h
@@ -194,9 +194,7 @@
   using DemuxerStreamMap = std::map<StreamParser::TrackId, ChunkDemuxerStream*>;
   DemuxerStreamMap audio_streams_;
   DemuxerStreamMap video_streams_;
-
-  typedef std::map<StreamParser::TrackId, ChunkDemuxerStream*> TextStreamMap;
-  TextStreamMap text_stream_map_;  // |this| owns the map's stream pointers.
+  DemuxerStreamMap text_streams_;
 
   std::unique_ptr<FrameProcessor> frame_processor_;
   scoped_refptr<MediaLog> media_log_;
diff --git a/media/filters/vpx_video_decoder.cc b/media/filters/vpx_video_decoder.cc
index e95de6d..196d1ae 100644
--- a/media/filters/vpx_video_decoder.cc
+++ b/media/filters/vpx_video_decoder.cc
@@ -8,6 +8,7 @@
 #include <stdint.h>
 
 #include <algorithm>
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -18,8 +19,8 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/single_thread_task_runner.h"
-#include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/sys_byteorder.h"
 #include "base/sys_info.h"
@@ -223,7 +224,7 @@
   void OnVideoFrameDestroyed(VP9FrameBuffer* frame_buffer);
 
   // Frame buffers to be used by libvpx for VP9 Decoding.
-  std::vector<VP9FrameBuffer*> frame_buffers_;
+  std::vector<std::unique_ptr<VP9FrameBuffer>> frame_buffers_;
 
   DISALLOW_COPY_AND_ASSIGN(MemoryPool);
 };
@@ -234,7 +235,6 @@
 }
 
 VpxVideoDecoder::MemoryPool::~MemoryPool() {
-  base::STLDeleteElements(&frame_buffers_);
   base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
       this);
 }
@@ -250,13 +250,13 @@
 
   if (i == frame_buffers_.size()) {
     // Create a new frame buffer.
-    frame_buffers_.push_back(new VP9FrameBuffer());
+    frame_buffers_.push_back(base::MakeUnique<VP9FrameBuffer>());
   }
 
   // Resize the frame buffer if necessary.
   if (frame_buffers_[i]->data.size() < min_size)
     frame_buffers_[i]->data.resize(min_size);
-  return frame_buffers_[i];
+  return frame_buffers_[i].get();
 }
 
 int32_t VpxVideoDecoder::MemoryPool::GetVP9FrameBuffer(
@@ -317,7 +317,7 @@
                             ->system_allocator_pool_name());
   size_t bytes_used = 0;
   size_t bytes_reserved = 0;
-  for (const VP9FrameBuffer* frame_buffer : frame_buffers_) {
+  for (const auto& frame_buffer : frame_buffers_) {
     if (frame_buffer->ref_cnt)
       bytes_used += frame_buffer->data.size();
     bytes_reserved += frame_buffer->data.size();
@@ -727,12 +727,12 @@
 
     case VPX_IMG_FMT_I42016:
       switch (vpx_image->bit_depth) {
-        case 9:
-          codec_format = PIXEL_FORMAT_YUV420P9;
-          break;
         case 10:
           codec_format = PIXEL_FORMAT_YUV420P10;
           break;
+        case 12:
+          codec_format = PIXEL_FORMAT_YUV420P12;
+          break;
         default:
           DLOG(ERROR) << "Unsupported bit depth: " << vpx_image->bit_depth;
           return false;
@@ -741,12 +741,12 @@
 
     case VPX_IMG_FMT_I42216:
       switch (vpx_image->bit_depth) {
-        case 9:
-          codec_format = PIXEL_FORMAT_YUV422P9;
-          break;
         case 10:
           codec_format = PIXEL_FORMAT_YUV422P10;
           break;
+        case 12:
+          codec_format = PIXEL_FORMAT_YUV422P12;
+          break;
         default:
           DLOG(ERROR) << "Unsupported bit depth: " << vpx_image->bit_depth;
           return false;
@@ -755,12 +755,12 @@
 
     case VPX_IMG_FMT_I44416:
       switch (vpx_image->bit_depth) {
-        case 9:
-          codec_format = PIXEL_FORMAT_YUV444P9;
-          break;
         case 10:
           codec_format = PIXEL_FORMAT_YUV444P10;
           break;
+        case 12:
+          codec_format = PIXEL_FORMAT_YUV444P12;
+          break;
         default:
           DLOG(ERROR) << "Unsupported bit depth: " << vpx_image->bit_depth;
           return false;
diff --git a/media/formats/mp2t/mp2t_stream_parser.cc b/media/formats/mp2t/mp2t_stream_parser.cc
index 2d9da61..59029dc 100644
--- a/media/formats/mp2t/mp2t_stream_parser.cc
+++ b/media/formats/mp2t/mp2t_stream_parser.cc
@@ -9,7 +9,6 @@
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
-#include "base/stl_util.h"
 #include "media/base/media_tracks.h"
 #include "media/base/stream_parser_buffer.h"
 #include "media/base/text_track_config.h"
@@ -45,7 +44,7 @@
   };
 
   PidState(int pid,
-           PidType pid_tyoe,
+           PidType pid_type,
            std::unique_ptr<TsSection> section_parser);
 
   // Extract the content of the TS packet and parse it.
@@ -168,7 +167,6 @@
 }
 
 Mp2tStreamParser::~Mp2tStreamParser() {
-  base::STLDeleteValues(&pids_);
 }
 
 void Mp2tStreamParser::Init(
@@ -202,12 +200,9 @@
   DVLOG(1) << "Mp2tStreamParser::Flush";
 
   // Flush the buffers and reset the pids.
-  for (std::map<int, PidState*>::iterator it = pids_.begin();
-       it != pids_.end(); ++it) {
-    DVLOG(1) << "Flushing PID: " << it->first;
-    PidState* pid_state = it->second;
-    pid_state->Flush();
-    delete pid_state;
+  for (const auto& pid_pair : pids_) {
+    DVLOG(1) << "Flushing PID: " << pid_pair.first;
+    pid_pair.second->Flush();
   }
   pids_.clear();
 
@@ -284,7 +279,7 @@
         << " start_unit=" << ts_packet->payload_unit_start_indicator();
 
     // Parse the section.
-    std::map<int, PidState*>::iterator it = pids_.find(ts_packet->pid());
+    auto it = pids_.find(ts_packet->pid());
     if (it == pids_.end() &&
         ts_packet->pid() == TsSection::kPidPat) {
       // Create the PAT state here if needed.
@@ -293,9 +288,10 @@
       std::unique_ptr<PidState> pat_pid_state(new PidState(
           ts_packet->pid(), PidState::kPidPat, std::move(pat_section_parser)));
       pat_pid_state->Enable();
-      it = pids_.insert(
-          std::pair<int, PidState*>(ts_packet->pid(),
-                                    pat_pid_state.release())).first;
+      it = pids_
+               .insert(
+                   std::make_pair(ts_packet->pid(), std::move(pat_pid_state)))
+               .first;
     }
 
     if (it != pids_.end()) {
@@ -322,11 +318,11 @@
 
   // Only one TS program is allowed. Ignore the incoming program map table,
   // if there is already one registered.
-  for (std::map<int, PidState*>::iterator it = pids_.begin();
-       it != pids_.end(); ++it) {
-    PidState* pid_state = it->second;
+  for (const auto& pid_pair : pids_) {
+    PidState* pid_state = pid_pair.second.get();
     if (pid_state->pid_type() == PidState::kPidPmt) {
-      DVLOG_IF(1, pmt_pid != it->first) << "More than one program is defined";
+      DVLOG_IF(1, pmt_pid != pid_pair.first)
+          << "More than one program is defined";
       return;
     }
   }
@@ -338,7 +334,7 @@
   std::unique_ptr<PidState> pmt_pid_state(
       new PidState(pmt_pid, PidState::kPidPmt, std::move(pmt_section_parser)));
   pmt_pid_state->Enable();
-  pids_.insert(std::pair<int, PidState*>(pmt_pid, pmt_pid_state.release()));
+  pids_.insert(std::make_pair(pmt_pid, std::move(pmt_pid_state)));
 }
 
 void Mp2tStreamParser::RegisterPes(int pmt_pid,
@@ -348,7 +344,7 @@
   DVLOG(1) << "RegisterPes:"
            << " pes_pid=" << pes_pid
            << " stream_type=" << std::hex << stream_type << std::dec;
-  std::map<int, PidState*>::iterator it = pids_.find(pes_pid);
+  auto it = pids_.find(pes_pid);
   if (it != pids_.end())
     return;
 
@@ -395,7 +391,7 @@
       is_audio ? PidState::kPidAudioPes : PidState::kPidVideoPes;
   std::unique_ptr<PidState> pes_pid_state(
       new PidState(pes_pid, pid_type, std::move(pes_section_parser)));
-  pids_.insert(std::pair<int, PidState*>(pes_pid, pes_pid_state.release()));
+  pids_.insert(std::make_pair(pes_pid, std::move(pes_pid_state)));
 
   // A new PES pid has been added, the PID filter might change.
   UpdatePidFilter();
@@ -406,11 +402,11 @@
   // select the audio/video streams with the lowest PID.
   // TODO(damienv): this can be changed when the StreamParser interface
   // supports multiple audio/video streams.
-  PidMap::iterator lowest_audio_pid = pids_.end();
-  PidMap::iterator lowest_video_pid = pids_.end();
-  for (PidMap::iterator it = pids_.begin(); it != pids_.end(); ++it) {
+  auto lowest_audio_pid = pids_.end();
+  auto lowest_video_pid = pids_.end();
+  for (auto it = pids_.begin(); it != pids_.end(); ++it) {
     int pid = it->first;
-    PidState* pid_state = it->second;
+    PidState* pid_state = it->second.get();
     if (pid_state->pid_type() == PidState::kPidAudioPes &&
         (lowest_audio_pid == pids_.end() || pid < lowest_audio_pid->first))
       lowest_audio_pid = it;
@@ -432,8 +428,8 @@
   }
 
   // Disable all the other audio and video PIDs.
-  for (PidMap::iterator it = pids_.begin(); it != pids_.end(); ++it) {
-    PidState* pid_state = it->second;
+  for (auto it = pids_.begin(); it != pids_.end(); ++it) {
+    PidState* pid_state = it->second.get();
     if (it != lowest_audio_pid && it != lowest_video_pid &&
         (pid_state->pid_type() == PidState::kPidAudioPes ||
          pid_state->pid_type() == PidState::kPidVideoPes))
diff --git a/media/formats/mp2t/mp2t_stream_parser.h b/media/formats/mp2t/mp2t_stream_parser.h
index d013ee48..7c5c6951 100644
--- a/media/formats/mp2t/mp2t_stream_parser.h
+++ b/media/formats/mp2t/mp2t_stream_parser.h
@@ -46,8 +46,6 @@
   bool Parse(const uint8_t* buf, int size) override;
 
  private:
-  typedef std::map<int, PidState*> PidMap;
-
   struct BufferQueueWithConfig {
     BufferQueueWithConfig(bool is_cfg_sent,
                           const AudioDecoderConfig& audio_cfg,
@@ -114,7 +112,7 @@
   ByteQueue ts_byte_queue_;
 
   // List of PIDs and their state.
-  PidMap pids_;
+  std::map<int, std::unique_ptr<PidState>> pids_;
 
   // Selected audio and video PIDs.
   int selected_audio_pid_;
diff --git a/media/formats/webm/webm_content_encodings_client.cc b/media/formats/webm/webm_content_encodings_client.cc
index 0d3aa2c..82dbd60 100644
--- a/media/formats/webm/webm_content_encodings_client.cc
+++ b/media/formats/webm/webm_content_encodings_client.cc
@@ -5,7 +5,6 @@
 #include "media/formats/webm/webm_content_encodings_client.h"
 
 #include "base/logging.h"
-#include "base/stl_util.h"
 #include "media/formats/webm/webm_constants.h"
 
 namespace media {
@@ -18,7 +17,6 @@
 }
 
 WebMContentEncodingsClient::~WebMContentEncodingsClient() {
-  base::STLDeleteElements(&content_encodings_);
 }
 
 const ContentEncodings& WebMContentEncodingsClient::content_encodings() const {
@@ -30,7 +28,7 @@
   if (id == kWebMIdContentEncodings) {
     DCHECK(!cur_content_encoding_.get());
     DCHECK(!content_encryption_encountered_);
-    base::STLDeleteElements(&content_encodings_);
+    content_encodings_.clear();
     content_encodings_ready_ = false;
     return this;
   }
@@ -112,7 +110,7 @@
       return false;
     }
 
-    content_encodings_.push_back(cur_content_encoding_.release());
+    content_encodings_.push_back(std::move(cur_content_encoding_));
     content_encryption_encountered_ = false;
     return true;
   }
diff --git a/media/formats/webm/webm_content_encodings_client.h b/media/formats/webm/webm_content_encodings_client.h
index 09dfcf0..a72db118 100644
--- a/media/formats/webm/webm_content_encodings_client.h
+++ b/media/formats/webm/webm_content_encodings_client.h
@@ -20,7 +20,7 @@
 
 namespace media {
 
-typedef std::vector<ContentEncoding*> ContentEncodings;
+typedef std::vector<std::unique_ptr<ContentEncoding>> ContentEncodings;
 
 // Parser for WebM ContentEncodings element.
 class MEDIA_EXPORT WebMContentEncodingsClient : public WebMParserClient {
diff --git a/media/gpu/dxva_video_decode_accelerator_win.cc b/media/gpu/dxva_video_decode_accelerator_win.cc
index 5f730e8..86b6f2dc 100644
--- a/media/gpu/dxva_video_decode_accelerator_win.cc
+++ b/media/gpu/dxva_video_decode_accelerator_win.cc
@@ -897,7 +897,7 @@
       main_thread_task_runner_->PostTask(
           FROM_HERE,
           base::Bind(&DXVAVideoDecodeAccelerator::DeferredDismissStaleBuffer,
-                     weak_this_factory_.GetWeakPtr(), picture_buffer_id));
+                     weak_ptr_, picture_buffer_id));
     }
     return;
   }
@@ -946,8 +946,7 @@
   if (count <= kMaxIterationsForANGLEReuseFlush && !fence->HasCompleted()) {
     main_thread_task_runner_->PostDelayedTask(
         FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::WaitForOutputBuffer,
-                              weak_this_factory_.GetWeakPtr(),
-                              picture_buffer_id, count + 1),
+                              weak_ptr_, picture_buffer_id, count + 1),
         base::TimeDelta::FromMilliseconds(kFlushDecoderSurfaceTimeoutMs));
     return;
   }
@@ -1033,8 +1032,8 @@
                                PLATFORM_FAILURE, );
 
   main_thread_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::NotifyResetDone,
-                            weak_this_factory_.GetWeakPtr()));
+      FROM_HERE,
+      base::Bind(&DXVAVideoDecodeAccelerator::NotifyResetDone, weak_ptr_));
 
   StartDecoderThread();
   SetState(kNormal);
@@ -1672,7 +1671,7 @@
     main_thread_task_runner_->PostTask(
         FROM_HERE,
         base::Bind(&DXVAVideoDecodeAccelerator::ProcessPendingSamples,
-                   weak_this_factory_.GetWeakPtr()));
+                   weak_ptr_));
     return true;
   }
 
@@ -1686,7 +1685,7 @@
   // Go ahead and request picture buffers.
   main_thread_task_runner_->PostTask(
       FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::RequestPictureBuffers,
-                            weak_this_factory_.GetWeakPtr(), width, height));
+                            weak_ptr_, width, height));
 
   pictures_requested_ = true;
   return true;
@@ -1739,8 +1738,7 @@
         main_thread_task_runner_->PostTask(
             FROM_HERE,
             base::Bind(&DXVAVideoDecodeAccelerator::BindPictureBufferToSample,
-                       weak_this_factory_.GetWeakPtr(),
-                       pending_sample->output_sample,
+                       weak_ptr_, pending_sample->output_sample,
                        pending_sample->picture_buffer_id,
                        pending_sample->input_buffer_id));
         continue;
@@ -1784,8 +1782,8 @@
     VideoDecodeAccelerator::Error error) {
   if (!main_thread_task_runner_->BelongsToCurrentThread()) {
     main_thread_task_runner_->PostTask(
-        FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::StopOnError,
-                              weak_this_factory_.GetWeakPtr(), error));
+        FROM_HERE,
+        base::Bind(&DXVAVideoDecodeAccelerator::StopOnError, weak_ptr_, error));
     return;
   }
 
@@ -1807,6 +1805,7 @@
 
   decoder_thread_.Stop();
   weak_this_factory_.InvalidateWeakPtrs();
+  weak_ptr_ = weak_this_factory_.GetWeakPtr();
   pending_output_samples_.clear();
   decoder_.Release();
   config_change_detector_.reset();
@@ -1982,13 +1981,13 @@
     SetState(kFlushing);
 
     main_thread_task_runner_->PostTask(
-        FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::NotifyFlushDone,
-                              weak_this_factory_.GetWeakPtr()));
+        FROM_HERE,
+        base::Bind(&DXVAVideoDecodeAccelerator::NotifyFlushDone, weak_ptr_));
   } else {
     processing_config_changed_ = false;
     main_thread_task_runner_->PostTask(
         FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::ConfigChanged,
-                              weak_this_factory_.GetWeakPtr(), config_));
+                              weak_ptr_, config_));
   }
 
   SetState(kNormal);
@@ -2096,7 +2095,7 @@
   // http://code.google.com/p/chromium/issues/detail?id=150925
   main_thread_task_runner_->PostTask(
       FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::NotifyInputBufferRead,
-                            weak_this_factory_.GetWeakPtr(), input_buffer_id));
+                            weak_ptr_, input_buffer_id));
 }
 
 void DXVAVideoDecodeAccelerator::HandleResolutionChanged(int width,
@@ -2105,11 +2104,11 @@
 
   main_thread_task_runner_->PostTask(
       FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::DismissStaleBuffers,
-                            weak_this_factory_.GetWeakPtr(), false));
+                            weak_ptr_, false));
 
   main_thread_task_runner_->PostTask(
       FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::RequestPictureBuffers,
-                            weak_this_factory_.GetWeakPtr(), width, height));
+                            weak_ptr_, width, height));
 }
 
 void DXVAVideoDecodeAccelerator::DismissStaleBuffers(bool force) {
@@ -2158,8 +2157,8 @@
 void DXVAVideoDecodeAccelerator::SetState(State new_state) {
   if (!main_thread_task_runner_->BelongsToCurrentThread()) {
     main_thread_task_runner_->PostTask(
-        FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::SetState,
-                              weak_this_factory_.GetWeakPtr(), new_state));
+        FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::SetState, weak_ptr_,
+                              new_state));
     return;
   }
 
@@ -2205,10 +2204,9 @@
   // complete.
   if (using_angle_device_) {
     main_thread_task_runner_->PostTask(
-        FROM_HERE,
-        base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete,
-                   weak_this_factory_.GetWeakPtr(), src_surface, dest_surface,
-                   picture_buffer_id, input_buffer_id));
+        FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete,
+                              weak_ptr_, src_surface, dest_surface,
+                              picture_buffer_id, input_buffer_id));
     return;
   }
 
@@ -2451,9 +2449,9 @@
                                  PLATFORM_FAILURE, );
 
     main_thread_task_runner_->PostTask(
-        FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete,
-                              weak_this_factory_.GetWeakPtr(), nullptr, nullptr,
-                              picture_buffer_id, input_buffer_id));
+        FROM_HERE,
+        base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete, weak_ptr_,
+                   nullptr, nullptr, picture_buffer_id, input_buffer_id));
   } else {
     d3d11_device_context_->Flush();
     d3d11_device_context_->End(d3d11_query_.get());
@@ -2512,8 +2510,8 @@
 
   main_thread_task_runner_->PostTask(
       FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete,
-                            weak_this_factory_.GetWeakPtr(), src_surface,
-                            dest_surface, picture_buffer_id, input_buffer_id));
+                            weak_ptr_, src_surface, dest_surface,
+                            picture_buffer_id, input_buffer_id));
 }
 
 bool DXVAVideoDecodeAccelerator::InitializeDX11VideoFormatConverterMediaType(
diff --git a/media/gpu/ipc/service/gpu_jpeg_decode_accelerator.cc b/media/gpu/ipc/service/gpu_jpeg_decode_accelerator.cc
index eabded5..432c992 100644
--- a/media/gpu/ipc/service/gpu_jpeg_decode_accelerator.cc
+++ b/media/gpu/ipc/service/gpu_jpeg_decode_accelerator.cc
@@ -12,9 +12,9 @@
 #include "base/bind.h"
 #include "base/containers/hash_tables.h"
 #include "base/logging.h"
+#include "base/memory/ptr_util.h"
 #include "base/memory/shared_memory.h"
 #include "base/single_thread_task_runner.h"
-#include "base/stl_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
@@ -39,7 +39,7 @@
 
 void DecodeFinished(std::unique_ptr<base::SharedMemory> shm) {
   // Do nothing. Because VideoFrame is backed by |shm|, the purpose of this
-  // function is to just keep reference of |shm| to make sure it lives util
+  // function is to just keep reference of |shm| to make sure it lives until
   // decode finishes.
 }
 
@@ -158,7 +158,8 @@
     DCHECK(io_task_runner_->BelongsToCurrentThread());
     DCHECK(client_map_.count(route_id) == 0);
 
-    client_map_[route_id] = client;
+    // See the comment on GpuJpegDecodeAccelerator::AddClient.
+    client_map_[route_id] = base::WrapUnique(client);
     response.Run(true);
   }
 
@@ -166,19 +167,20 @@
     DCHECK(io_task_runner_->BelongsToCurrentThread());
     const auto& it = client_map_.find(*route_id);
     DCHECK(it != client_map_.end());
-    Client* client = it->second;
+    std::unique_ptr<Client> client = std::move(it->second);
     DCHECK(client);
     client_map_.erase(it);
 
     child_task_runner_->PostTask(
-        FROM_HERE, base::Bind(&MessageFilter::DestroyClient, this, client));
+        FROM_HERE,
+        base::Bind(&MessageFilter::DestroyClient, this, base::Passed(&client)));
   }
 
-  void DestroyClient(Client* client) {
+  void DestroyClient(std::unique_ptr<Client> client) {
     DCHECK(child_task_runner_->BelongsToCurrentThread());
-    delete client;
     if (owner_)
       owner_->ClientRemoved();
+    // |client| is destroyed when the scope of this function is left.
   }
 
   void NotifyDecodeStatusOnIOThread(int32_t route_id,
@@ -241,7 +243,7 @@
         base::Bind(DecodeFinished, base::Passed(&output_shm)));
 
     DCHECK_GT(client_map_.count(*route_id), 0u);
-    Client* client = client_map_[*route_id];
+    Client* client = client_map_[*route_id].get();
     client->Decode(params.input_buffer, frame);
   }
 
@@ -251,7 +253,7 @@
       return;
 
     if (child_task_runner_->BelongsToCurrentThread()) {
-      base::STLDeleteValues(&client_map_);
+      client_map_.clear();
     } else {
       // Make sure |Client| are deleted on child thread.
       std::unique_ptr<ClientMap> client_map(new ClientMap);
@@ -264,12 +266,12 @@
   }
 
  private:
-  using ClientMap = base::hash_map<int32_t, Client*>;
+  using ClientMap = base::hash_map<int32_t, std::unique_ptr<Client>>;
 
   // Must be static because this method runs after destructor.
   static void DeleteClientMapOnChildThread(
       std::unique_ptr<ClientMap> client_map) {
-    base::STLDeleteValues(client_map.get());
+    // |client_map| is cleared when the scope of this function is left.
   }
 
   base::WeakPtr<GpuJpegDecodeAccelerator> owner_;
@@ -348,7 +350,7 @@
   // to protect it because |client| can only be deleted on child thread. The IO
   // thread is destroyed at termination, at which point it's ok to leak since
   // we're going to tear down the process anyway. So we just crossed fingers
-  // here instead of making the code unnecessary complicated.
+  // here instead of making the code unnecessarily complicated.
   io_task_runner_->PostTask(
       FROM_HERE, base::Bind(&MessageFilter::AddClientOnIOThread, filter_,
                             route_id, client.release(), response));
diff --git a/media/gpu/video_decode_accelerator_unittest.cc b/media/gpu/video_decode_accelerator_unittest.cc
index 70bc4399..365859f0 100644
--- a/media/gpu/video_decode_accelerator_unittest.cc
+++ b/media/gpu/video_decode_accelerator_unittest.cc
@@ -37,6 +37,7 @@
 #include "base/location.h"
 #include "base/macros.h"
 #include "base/md5.h"
+#include "base/memory/ptr_util.h"
 #include "base/process/process_handle.h"
 #include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
@@ -372,7 +373,7 @@
   handle.native_pixmap_handle.fds.emplace_back(
       base::FileDescriptor(duped_fd, true));
   handle.native_pixmap_handle.planes.emplace_back(
-      pixmap_->GetDmaBufPitch(0), pixmap_->GetDmaBufOffset(0),
+      pixmap_->GetDmaBufPitch(0), pixmap_->GetDmaBufOffset(0), 0,
       pixmap_->GetDmaBufModifier(0));
 #endif
   return handle;
@@ -1075,6 +1076,8 @@
 
 class VideoDecodeAcceleratorTest : public ::testing::Test {
  protected:
+  using TestFilesVector = std::vector<std::unique_ptr<TestVideoFile>>;
+
   VideoDecodeAcceleratorTest();
   void SetUp() override;
   void TearDown() override;
@@ -1083,14 +1086,14 @@
   // accordingly, and read in video stream. CHECK-fails on unexpected or
   // missing required data. Unspecified optional fields are set to -1.
   void ParseAndReadTestVideoData(base::FilePath::StringType data,
-                                 std::vector<TestVideoFile*>* test_video_files);
+                                 TestFilesVector* test_video_files);
 
   // Update the parameters of |test_video_files| according to
   // |num_concurrent_decoders| and |reset_point|. Ex: the expected number of
   // frames should be adjusted if decoder is reset in the middle of the stream.
   void UpdateTestVideoFileParams(size_t num_concurrent_decoders,
                                  int reset_point,
-                                 std::vector<TestVideoFile*>* test_video_files);
+                                 TestFilesVector* test_video_files);
 
   void InitializeRenderingHelper(const RenderingHelperParams& helper_params);
   void CreateAndStartDecoder(GLRenderingVDAClient* client,
@@ -1100,9 +1103,16 @@
   void OutputLogFile(const base::FilePath::CharType* log_path,
                      const std::string& content);
 
-  std::vector<TestVideoFile*> test_video_files_;
+  TestFilesVector test_video_files_;
   RenderingHelper rendering_helper_;
 
+ protected:
+  // Must be static because this method may run after the destructor.
+  template <typename T>
+  static void Delete(std::unique_ptr<T> item) {
+    // |item| is cleared when the scope of this function is left.
+  }
+
  private:
   // Required for Thread to work.  Not used otherwise.
   base::ShadowingAtExitManager at_exit_manager_;
@@ -1117,10 +1127,12 @@
 }
 
 void VideoDecodeAcceleratorTest::TearDown() {
+  std::unique_ptr<TestFilesVector> test_video_files(new TestFilesVector);
+  test_video_files->swap(test_video_files_);
+
   g_env->GetRenderingTaskRunner()->PostTask(
       FROM_HERE,
-      base::Bind(&base::STLDeleteElements<std::vector<TestVideoFile*>>,
-                 &test_video_files_));
+      base::Bind(&Delete<TestFilesVector>, base::Passed(&test_video_files)));
 
   base::WaitableEvent done(base::WaitableEvent::ResetPolicy::AUTOMATIC,
                            base::WaitableEvent::InitialState::NOT_SIGNALED);
@@ -1134,7 +1146,7 @@
 
 void VideoDecodeAcceleratorTest::ParseAndReadTestVideoData(
     base::FilePath::StringType data,
-    std::vector<TestVideoFile*>* test_video_files) {
+    TestFilesVector* test_video_files) {
   std::vector<base::FilePath::StringType> entries =
       base::SplitString(data, base::FilePath::StringType(1, ';'),
                         base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
@@ -1145,7 +1157,8 @@
                           base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
     LOG_ASSERT(fields.size() >= 1U) << entries[index];
     LOG_ASSERT(fields.size() <= 8U) << entries[index];
-    TestVideoFile* video_file = new TestVideoFile(fields[0]);
+    std::unique_ptr<TestVideoFile> video_file =
+        base::MakeUnique<TestVideoFile>(fields[0]);
     if (!fields[1].empty())
       LOG_ASSERT(base::StringToInt(fields[1], &video_file->width));
     if (!fields[2].empty())
@@ -1168,16 +1181,16 @@
     LOG_ASSERT(base::ReadFileToString(filepath, &video_file->data_str))
         << "test_video_file: " << filepath.MaybeAsASCII();
 
-    test_video_files->push_back(video_file);
+    test_video_files->push_back(std::move(video_file));
   }
 }
 
 void VideoDecodeAcceleratorTest::UpdateTestVideoFileParams(
     size_t num_concurrent_decoders,
     int reset_point,
-    std::vector<TestVideoFile*>* test_video_files) {
+    TestFilesVector* test_video_files) {
   for (size_t i = 0; i < test_video_files->size(); i++) {
-    TestVideoFile* video_file = (*test_video_files)[i];
+    TestVideoFile* video_file = (*test_video_files)[i].get();
     if (reset_point == MID_STREAM_RESET) {
       // Reset should not go beyond the last frame;
       // reset in the middle of the stream for short videos.
@@ -1301,9 +1314,11 @@
   // Suppress GL rendering for all tests when the "--rendering_fps" is 0.
   const bool suppress_rendering = g_rendering_fps == 0;
 
-  std::vector<ClientStateNotification<ClientState>*> notes(
-      num_concurrent_decoders, NULL);
-  std::vector<GLRenderingVDAClient*> clients(num_concurrent_decoders, NULL);
+  using NotesVector =
+      std::vector<std::unique_ptr<ClientStateNotification<ClientState>>>;
+  using ClientsVector = std::vector<std::unique_ptr<GLRenderingVDAClient>>;
+  NotesVector notes(num_concurrent_decoders);
+  ClientsVector clients(num_concurrent_decoders);
 
   RenderingHelperParams helper_params;
   helper_params.rendering_fps = g_rendering_fps;
@@ -1319,10 +1334,10 @@
   // First kick off all the decoders.
   for (size_t index = 0; index < num_concurrent_decoders; ++index) {
     TestVideoFile* video_file =
-        test_video_files_[index % test_video_files_.size()];
-    ClientStateNotification<ClientState>* note =
-        new ClientStateNotification<ClientState>();
-    notes[index] = note;
+        test_video_files_[index % test_video_files_.size()].get();
+    std::unique_ptr<ClientStateNotification<ClientState>> note =
+        base::MakeUnique<ClientStateNotification<ClientState>>();
+    notes[index] = std::move(note);
 
     int delay_after_frame_num = std::numeric_limits<int>::max();
     if (test_reuse_delay &&
@@ -1330,25 +1345,16 @@
       delay_after_frame_num = video_file->num_frames - kMaxFramesToDelayReuse;
     }
 
-    GLRenderingVDAClient* client =
-        new GLRenderingVDAClient(index,
-                                 &rendering_helper_,
-                                 note,
-                                 video_file->data_str,
-                                 num_in_flight_decodes,
-                                 num_play_throughs,
-                                 video_file->reset_after_frame_num,
-                                 delete_decoder_state,
-                                 video_file->width,
-                                 video_file->height,
-                                 video_file->profile,
-                                 g_fake_decoder,
-                                 suppress_rendering,
-                                 delay_after_frame_num,
-                                 0,
-                                 render_as_thumbnails);
+    std::unique_ptr<GLRenderingVDAClient> client =
+        base::MakeUnique<GLRenderingVDAClient>(
+            index, &rendering_helper_, notes[index].get(), video_file->data_str,
+            num_in_flight_decodes, num_play_throughs,
+            video_file->reset_after_frame_num, delete_decoder_state,
+            video_file->width, video_file->height, video_file->profile,
+            g_fake_decoder, suppress_rendering, delay_after_frame_num, 0,
+            render_as_thumbnails);
 
-    clients[index] = client;
+    clients[index] = std::move(client);
     helper_params.window_sizes.push_back(
         render_as_thumbnails
             ? kThumbnailsPageSize
@@ -1358,14 +1364,14 @@
   InitializeRenderingHelper(helper_params);
 
   for (size_t index = 0; index < num_concurrent_decoders; ++index) {
-    CreateAndStartDecoder(clients[index], notes[index]);
+    CreateAndStartDecoder(clients[index].get(), notes[index].get());
   }
 
   // Then wait for all the decodes to finish.
   // Only check performance & correctness later if we play through only once.
   bool skip_performance_and_correctness_checks = num_play_throughs > 1;
   for (size_t i = 0; i < num_concurrent_decoders; ++i) {
-    ClientStateNotification<ClientState>* note = notes[i];
+    ClientStateNotification<ClientState>* note = notes[i].get();
     ClientState state = note->Wait();
     if (state != CS_INITIALIZED) {
       skip_performance_and_correctness_checks = true;
@@ -1381,24 +1387,24 @@
       // For play-throughs other than the first, we expect initialization to
       // succeed unconditionally.
       if (n > 0) {
-        ASSERT_NO_FATAL_FAILURE(
-            AssertWaitForStateOrDeleted(note, clients[i], CS_INITIALIZED));
+        ASSERT_NO_FATAL_FAILURE(AssertWaitForStateOrDeleted(
+            note, clients[i].get(), CS_INITIALIZED));
       }
       // InitializeDone kicks off decoding inside the client, so we just need to
       // wait for Flush.
       ASSERT_NO_FATAL_FAILURE(
-          AssertWaitForStateOrDeleted(note, clients[i], CS_FLUSHING));
+          AssertWaitForStateOrDeleted(note, clients[i].get(), CS_FLUSHING));
       ASSERT_NO_FATAL_FAILURE(
-          AssertWaitForStateOrDeleted(note, clients[i], CS_FLUSHED));
+          AssertWaitForStateOrDeleted(note, clients[i].get(), CS_FLUSHED));
       // FlushDone requests Reset().
       ASSERT_NO_FATAL_FAILURE(
-          AssertWaitForStateOrDeleted(note, clients[i], CS_RESETTING));
+          AssertWaitForStateOrDeleted(note, clients[i].get(), CS_RESETTING));
     }
     ASSERT_NO_FATAL_FAILURE(
-        AssertWaitForStateOrDeleted(note, clients[i], CS_RESET));
+        AssertWaitForStateOrDeleted(note, clients[i].get(), CS_RESET));
     // ResetDone requests Destroy().
     ASSERT_NO_FATAL_FAILURE(
-        AssertWaitForStateOrDeleted(note, clients[i], CS_DESTROYED));
+        AssertWaitForStateOrDeleted(note, clients[i].get(), CS_DESTROYED));
   }
   // Finally assert that decoding went as expected.
   for (size_t i = 0;
@@ -1408,8 +1414,9 @@
     // allowed to finish.
     if (delete_decoder_state < CS_FLUSHED)
       continue;
-    GLRenderingVDAClient* client = clients[i];
-    TestVideoFile* video_file = test_video_files_[i % test_video_files_.size()];
+    GLRenderingVDAClient* client = clients[i].get();
+    TestVideoFile* video_file =
+        test_video_files_[i % test_video_files_.size()].get();
     if (video_file->num_frames > 0) {
       // Expect the decoded frames may be more than the video frames as frames
       // could still be returned until resetting done.
@@ -1447,7 +1454,7 @@
     std::vector<std::string> golden_md5s;
     std::string md5_string = base::MD5String(
         base::StringPiece(reinterpret_cast<char*>(&rgb[0]), rgb.size()));
-    ReadGoldenThumbnailMD5s(test_video_files_[0], &golden_md5s);
+    ReadGoldenThumbnailMD5s(test_video_files_[0].get(), &golden_md5s);
     std::vector<std::string>::iterator match =
         find(golden_md5s.begin(), golden_md5s.end(), md5_string);
     if (match == golden_md5s.end()) {
@@ -1486,15 +1493,17 @@
     }
   }
 
+  std::unique_ptr<NotesVector> notes2(new NotesVector);
+  notes2->swap(notes);
+  std::unique_ptr<ClientsVector> clients2(new ClientsVector);
+  clients2->swap(clients);
+
   g_env->GetRenderingTaskRunner()->PostTask(
-      FROM_HERE,
-      base::Bind(&base::STLDeleteElements<std::vector<GLRenderingVDAClient*>>,
-                 &clients));
+      FROM_HERE, base::Bind(&Delete<NotesVector>, base::Passed(&notes2)));
+
   g_env->GetRenderingTaskRunner()->PostTask(
-      FROM_HERE,
-      base::Bind(&base::STLDeleteElements<
-                     std::vector<ClientStateNotification<ClientState>*>>,
-                 &notes));
+      FROM_HERE, base::Bind(&Delete<ClientsVector>, base::Passed(&clients2)));
+
   WaitUntilIdle();
 };
 
diff --git a/media/mojo/common/media_type_converters.cc b/media/mojo/common/media_type_converters.cc
index 9db0f85..84f914e 100644
--- a/media/mojo/common/media_type_converters.cc
+++ b/media/mojo/common/media_type_converters.cc
@@ -185,6 +185,17 @@
 ASSERT_ENUM_EQ_RAW(VideoPixelFormat,
                    PIXEL_FORMAT_YUV444P10,
                    VideoFormat::YUV444P10);
+ASSERT_ENUM_EQ_RAW(VideoPixelFormat,
+                   PIXEL_FORMAT_YUV420P12,
+                   VideoFormat::YUV420P12);
+ASSERT_ENUM_EQ_RAW(VideoPixelFormat,
+                   PIXEL_FORMAT_YUV422P12,
+                   VideoFormat::YUV422P12);
+ASSERT_ENUM_EQ_RAW(VideoPixelFormat,
+                   PIXEL_FORMAT_YUV444P12,
+                   VideoFormat::YUV444P12);
+ASSERT_ENUM_EQ_RAW(VideoPixelFormat, PIXEL_FORMAT_Y8, VideoFormat::Y8);
+ASSERT_ENUM_EQ_RAW(VideoPixelFormat, PIXEL_FORMAT_Y16, VideoFormat::Y16);
 ASSERT_ENUM_EQ_RAW(VideoPixelFormat, PIXEL_FORMAT_MAX, VideoFormat::FORMAT_MAX);
 
 // ColorSpace.
diff --git a/media/mojo/interfaces/media_types.mojom b/media/mojo/interfaces/media_types.mojom
index 810ba1a..bd61064 100644
--- a/media/mojo/interfaces/media_types.mojom
+++ b/media/mojo/interfaces/media_types.mojom
@@ -123,7 +123,12 @@
   YUV422P10,
   YUV444P9,
   YUV444P10,
-  FORMAT_MAX = YUV444P10,
+  YUV420P12,
+  YUV422P12,
+  YUV444P12,
+  Y8,
+  Y16,
+  FORMAT_MAX = Y16,
 };
 
 // Kept in sync with media::ColorSpace via static_asserts.
diff --git a/media/renderers/audio_renderer_impl.cc b/media/renderers/audio_renderer_impl.cc
index 3d24cf6..c653bfc 100644
--- a/media/renderers/audio_renderer_impl.cc
+++ b/media/renderers/audio_renderer_impl.cc
@@ -348,14 +348,17 @@
   if (!expecting_config_changes_ || !hw_params.IsValid() ||
       hw_params.format() == AudioParameters::AUDIO_FAKE) {
     // The actual buffer size is controlled via the size of the AudioBus
-    // provided to Render(), so just choose something reasonable here for looks.
-    int buffer_size = stream->audio_decoder_config().samples_per_second() / 100;
-    audio_parameters_.Reset(
-        AudioParameters::AUDIO_PCM_LOW_LATENCY,
-        stream->audio_decoder_config().channel_layout(),
-        stream->audio_decoder_config().samples_per_second(),
-        stream->audio_decoder_config().bits_per_channel(),
-        buffer_size);
+    // provided to Render(), but we should choose a value here based on hardware
+    // parameters if possible since it affects the initial buffer size used by
+    // the algorithm. Too little will cause underflow on Bluetooth devices.
+    int buffer_size =
+        std::max(stream->audio_decoder_config().samples_per_second() / 100,
+                 hw_params.IsValid() ? hw_params.frames_per_buffer() : 0);
+    audio_parameters_.Reset(AudioParameters::AUDIO_PCM_LOW_LATENCY,
+                            stream->audio_decoder_config().channel_layout(),
+                            stream->audio_decoder_config().samples_per_second(),
+                            stream->audio_decoder_config().bits_per_channel(),
+                            buffer_size);
     buffer_converter_.reset();
   } else {
     // To allow for seamless sample rate adaptations (i.e. changes from say
@@ -851,6 +854,10 @@
         algorithm_->IncreaseQueueCapacity();
         SetBufferingState_Locked(BUFFERING_HAVE_NOTHING);
       }
+    } else if (frames_written < frames_requested && !received_end_of_stream_) {
+      // If we only partially filled the request and should have more data, go
+      // ahead and increase queue capacity to try and meet the next request.
+      algorithm_->IncreaseQueueCapacity();
     }
 
     audio_clock_->WroteAudio(frames_written + frames_after_end_of_stream,
diff --git a/media/renderers/audio_renderer_impl_unittest.cc b/media/renderers/audio_renderer_impl_unittest.cc
index bc80b03f..3fdee31f 100644
--- a/media/renderers/audio_renderer_impl_unittest.cc
+++ b/media/renderers/audio_renderer_impl_unittest.cc
@@ -114,6 +114,21 @@
     SCOPED_TRACE("~AudioRendererImplTest()");
   }
 
+  // Reconfigures a renderer without config change support using given params.
+  void ConfigureBasicRenderer(const AudioParameters& params) {
+    hardware_params_ = params;
+    sink_ = new FakeAudioRendererSink(hardware_params_);
+    decoder_ = new MockAudioDecoder();
+    ScopedVector<AudioDecoder> decoders;
+    decoders.push_back(decoder_);
+    renderer_.reset(new AudioRendererImpl(message_loop_.task_runner(),
+                                          sink_.get(), std::move(decoders),
+                                          new MediaLog()));
+    testing::Mock::VerifyAndClearExpectations(&demuxer_stream_);
+    EXPECT_CALL(demuxer_stream_, SupportsConfigChanges())
+        .WillRepeatedly(Return(false));
+  }
+
   void ExpectUnsupportedAudioDecoder() {
     EXPECT_CALL(*decoder_, Initialize(_, _, _, _))
         .WillOnce(DoAll(SaveArg<3>(&output_cb_), RunCallback<2>(false)));
@@ -537,6 +552,37 @@
   EXPECT_EQ(buffer_capacity().value, initial_capacity.value);
 }
 
+TEST_F(AudioRendererImplTest, Underflow_CapacityIncreasesBeforeHaveNothing) {
+  Initialize();
+  Preroll();
+  StartTicking();
+
+  // Verify the next FillBuffer() call triggers the underflow callback
+  // since the decoder hasn't delivered any data after it was drained.
+  OutputFrames initial_capacity = buffer_capacity();
+
+  // Drain internal buffer, we should have a pending read.
+  EXPECT_FALSE(ConsumeBufferedData(OutputFrames(frames_buffered().value + 1)));
+
+  // Verify that the buffer capacity increased despite not sending have nothing.
+  EXPECT_GT(buffer_capacity().value, initial_capacity.value);
+}
+
+TEST_F(AudioRendererImplTest, CapacityAppropriateForHardware) {
+  // Verify that initial capacity is reasonable in normal case.
+  Initialize();
+  EXPECT_GT(buffer_capacity().value, hardware_params_.frames_per_buffer());
+
+  // Verify in the no-config-changes-expected case.
+  ConfigureBasicRenderer(AudioParameters(
+      AudioParameters::AUDIO_PCM_LOW_LATENCY, kChannelLayout,
+      kOutputSamplesPerSecond, SampleFormatToBytesPerChannel(kSampleFormat) * 8,
+      1024 * 15));
+
+  Initialize();
+  EXPECT_GT(buffer_capacity().value, hardware_params_.frames_per_buffer());
+}
+
 TEST_F(AudioRendererImplTest, Underflow_Flush) {
   Initialize();
   Preroll();
diff --git a/media/renderers/renderer_impl.cc b/media/renderers/renderer_impl.cc
index b087171..4b2ed96 100644
--- a/media/renderers/renderer_impl.cc
+++ b/media/renderers/renderer_impl.cc
@@ -229,7 +229,7 @@
   bool video = (stream->type() == DemuxerStream::VIDEO);
   DVLOG(1) << __func__ << (video ? " video" : " audio") << " stream=" << stream
            << " enabled=" << stream->enabled() << " time=" << time.InSecondsF();
-  if (state_ != STATE_PLAYING)
+  if ((state_ != STATE_PLAYING) || (audio_ended_ && video_ended_))
     return;
   if (stream->type() == DemuxerStream::VIDEO) {
     DCHECK(video_renderer_);
diff --git a/media/renderers/skcanvas_video_renderer.cc b/media/renderers/skcanvas_video_renderer.cc
index 3ff3510..5b20c24 100644
--- a/media/renderers/skcanvas_video_renderer.cc
+++ b/media/renderers/skcanvas_video_renderer.cc
@@ -451,19 +451,48 @@
   VideoPixelFormat format;
   int shift = 1;
   switch (video_frame->format()) {
-    case PIXEL_FORMAT_YUV420P10:
-      shift = 2;
-    case PIXEL_FORMAT_YUV420P9:
+    case PIXEL_FORMAT_YUV420P12:
+      shift = 4;
       format = PIXEL_FORMAT_I420;
       break;
-    case PIXEL_FORMAT_YUV422P10:
+
+    case PIXEL_FORMAT_YUV420P10:
       shift = 2;
-    case PIXEL_FORMAT_YUV422P9:
+      format = PIXEL_FORMAT_I420;
+      break;
+
+    case PIXEL_FORMAT_YUV420P9:
+      shift = 1;
+      format = PIXEL_FORMAT_I420;
+      break;
+
+    case PIXEL_FORMAT_YUV422P12:
+      shift = 4;
       format = PIXEL_FORMAT_YV16;
       break;
+
+    case PIXEL_FORMAT_YUV422P10:
+      shift = 2;
+      format = PIXEL_FORMAT_YV16;
+      break;
+
+    case PIXEL_FORMAT_YUV422P9:
+      shift = 1;
+      format = PIXEL_FORMAT_YV16;
+      break;
+
+    case PIXEL_FORMAT_YUV444P12:
+      shift = 4;
+      format = PIXEL_FORMAT_YV24;
+      break;
+
     case PIXEL_FORMAT_YUV444P10:
       shift = 2;
+      format = PIXEL_FORMAT_YV24;
+      break;
+
     case PIXEL_FORMAT_YUV444P9:
+      shift = 1;
       format = PIXEL_FORMAT_YV24;
       break;
 
@@ -592,7 +621,10 @@
     case PIXEL_FORMAT_YUV444P9:
     case PIXEL_FORMAT_YUV420P10:
     case PIXEL_FORMAT_YUV422P10:
-    case PIXEL_FORMAT_YUV444P10: {
+    case PIXEL_FORMAT_YUV444P10:
+    case PIXEL_FORMAT_YUV420P12:
+    case PIXEL_FORMAT_YUV422P12:
+    case PIXEL_FORMAT_YUV444P12: {
       scoped_refptr<VideoFrame> temporary_frame =
           DownShiftHighbitVideoFrame(video_frame);
       ConvertVideoFrameToRGBPixels(temporary_frame.get(), rgb_pixels,
@@ -610,6 +642,12 @@
     case PIXEL_FORMAT_RGB32:
     case PIXEL_FORMAT_MJPEG:
     case PIXEL_FORMAT_MT21:
+    // TODO(dshwang): Use either I400ToARGB or J400ToARGB depending if we want
+    // BT.601 constrained range of 16 to 240, or JPEG full range BT.601
+    // coefficients. Implement it when Y8/16 foramt is supported.
+    // crbug.com/624436
+    case PIXEL_FORMAT_Y8:
+    case PIXEL_FORMAT_Y16:
     case PIXEL_FORMAT_UNKNOWN:
       NOTREACHED();
   }
diff --git a/media/test/data/bear-320x180-hi12p-vp9.webm b/media/test/data/bear-320x180-hi12p-vp9.webm
new file mode 100644
index 0000000..5eb54ad8c
--- /dev/null
+++ b/media/test/data/bear-320x180-hi12p-vp9.webm
Binary files differ
diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc
index 6c188b1..6646712 100644
--- a/media/test/pipeline_integration_test.cc
+++ b/media/test/pipeline_integration_test.cc
@@ -921,6 +921,10 @@
   EXPECT_TRUE(demuxer_->GetTimelineOffset().is_null());
 }
 
+base::TimeDelta TimestampMs(int milliseconds) {
+  return base::TimeDelta::FromMilliseconds(milliseconds);
+}
+
 TEST_F(PipelineIntegrationTest, PlaybackWithAudioTrackDisabledThenEnabled) {
   ASSERT_EQ(PIPELINE_OK, Start("bear-320x240.webm", kHashed));
 
@@ -933,7 +937,7 @@
   ASSERT_TRUE(Seek(base::TimeDelta()));
 
   Play();
-  const base::TimeDelta k500ms = base::TimeDelta::FromMilliseconds(500);
+  const base::TimeDelta k500ms = TimestampMs(500);
   ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(k500ms));
   Pause();
 
@@ -971,7 +975,7 @@
   ResetVideoHash();
 
   Play();
-  const base::TimeDelta k500ms = base::TimeDelta::FromMilliseconds(500);
+  const base::TimeDelta k500ms = TimestampMs(500);
   ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(k500ms));
   Pause();
 
@@ -998,6 +1002,64 @@
   EXPECT_HASH_EQ("fd59357dfd9c144ab4fb8181b2de32c3", GetVideoHash());
 }
 
+TEST_F(PipelineIntegrationTest, TrackStatusChangesAfterPipelineEnded) {
+  ASSERT_EQ(PIPELINE_OK, Start("bear-320x240.webm", kHashed));
+  Play();
+  ASSERT_TRUE(WaitUntilOnEnded());
+  std::vector<MediaTrack::Id> track_ids;
+  // Disable audio track.
+  pipeline_->OnEnabledAudioTracksChanged(track_ids);
+  // Re-enable audio track.
+  track_ids.push_back("2");
+  pipeline_->OnEnabledAudioTracksChanged(track_ids);
+  // Disable video track.
+  track_ids.clear();
+  pipeline_->OnSelectedVideoTrackChanged(track_ids);
+  // Re-enable video track.
+  track_ids.push_back("1");
+  pipeline_->OnSelectedVideoTrackChanged(track_ids);
+}
+
+TEST_F(PipelineIntegrationTest, TrackStatusChangesWhileSuspended) {
+  ASSERT_EQ(PIPELINE_OK, Start("bear-320x240.webm", kHashed));
+  Play();
+
+  ASSERT_TRUE(Suspend());
+
+  // These get triggered every time playback is resumed.
+  EXPECT_CALL(*this, OnVideoNaturalSizeChange(gfx::Size(320, 240)))
+      .Times(AnyNumber());
+  EXPECT_CALL(*this, OnVideoOpacityChange(true)).Times(AnyNumber());
+
+  std::vector<MediaTrack::Id> track_ids;
+
+  // Disable audio track.
+  pipeline_->OnEnabledAudioTracksChanged(track_ids);
+  ASSERT_TRUE(Resume(TimestampMs(100)));
+  ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(TimestampMs(200)));
+  ASSERT_TRUE(Suspend());
+
+  // Re-enable audio track.
+  track_ids.push_back("2");
+  pipeline_->OnEnabledAudioTracksChanged(track_ids);
+  ASSERT_TRUE(Resume(TimestampMs(200)));
+  ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(TimestampMs(300)));
+  ASSERT_TRUE(Suspend());
+
+  // Disable video track.
+  track_ids.clear();
+  pipeline_->OnSelectedVideoTrackChanged(track_ids);
+  ASSERT_TRUE(Resume(TimestampMs(300)));
+  ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(TimestampMs(400)));
+  ASSERT_TRUE(Suspend());
+
+  // Re-enable video track.
+  track_ids.push_back("1");
+  pipeline_->OnSelectedVideoTrackChanged(track_ids);
+  ASSERT_TRUE(Resume(TimestampMs(400)));
+  ASSERT_TRUE(WaitUntilOnEnded());
+}
+
 TEST_F(PipelineIntegrationTest,
        MAYBE_CLOCKLESS(BasicPlaybackOpusOggTrimmingHashed)) {
   ASSERT_EQ(PIPELINE_OK,
@@ -1450,6 +1512,14 @@
 
   ASSERT_TRUE(WaitUntilOnEnded());
 }
+
+TEST_F(PipelineIntegrationTest, BasicPlaybackHi12PVP9) {
+  ASSERT_EQ(PIPELINE_OK, Start("bear-320x180-hi12p-vp9.webm", kClockless));
+
+  Play();
+
+  ASSERT_TRUE(WaitUntilOnEnded());
+}
 #endif
 
 #if defined(USE_PROPRIETARY_CODECS)
diff --git a/media/video/gpu_memory_buffer_video_frame_pool.cc b/media/video/gpu_memory_buffer_video_frame_pool.cc
index 1f77ebb..4b2f7a1b6b 100644
--- a/media/video/gpu_memory_buffer_video_frame_pool.cc
+++ b/media/video/gpu_memory_buffer_video_frame_pool.cc
@@ -380,6 +380,11 @@
     case PIXEL_FORMAT_YUV420P10:
     case PIXEL_FORMAT_YUV422P10:
     case PIXEL_FORMAT_YUV444P10:
+    case PIXEL_FORMAT_YUV420P12:
+    case PIXEL_FORMAT_YUV422P12:
+    case PIXEL_FORMAT_YUV444P12:
+    case PIXEL_FORMAT_Y8:
+    case PIXEL_FORMAT_Y16:
     case PIXEL_FORMAT_UNKNOWN:
       frame_ready_cb.Run(video_frame);
       return;
diff --git a/mojo/public/cpp/bindings/array.h b/mojo/public/cpp/bindings/array.h
index 8d74763..faf7398 100644
--- a/mojo/public/cpp/bindings/array.h
+++ b/mojo/public/cpp/bindings/array.h
@@ -134,6 +134,11 @@
   // Sets the array to empty (even if previously it was null.)
   void SetToEmpty() { resize(0); }
 
+  // Ensures the underlying storage can store up to |size| elements without
+  // performing reallocations. This works like the reserve method of
+  // |std::vector|.
+  void reserve(size_t size) { vec_.reserve(size); }
+
   // Returns a const reference to the |std::vector| managed by this class. If
   // the array is null, this will be an empty vector.
   const std::vector<T>& storage() const { return vec_; }
diff --git a/mojo/public/tools/bindings/blink_bindings_configuration.gni b/mojo/public/tools/bindings/blink_bindings_configuration.gni
index 18c4eeb..8598cd8 100644
--- a/mojo/public/tools/bindings/blink_bindings_configuration.gni
+++ b/mojo/public/tools/bindings/blink_bindings_configuration.gni
@@ -10,6 +10,7 @@
   "//mojo/public/cpp/bindings/tests/blink_typemaps.gni",
   "//third_party/WebKit/Source/platform/mojo/blink_typemaps.gni",
   "//third_party/WebKit/public/blink_typemaps.gni",
+  "//third_party/WebKit/public/public_typemaps.gni",
 ]
 _typemaps = []
 
diff --git a/mojo/public/tools/bindings/chromium_bindings_configuration.gni b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
index 806f4fc..53cc633 100644
--- a/mojo/public/tools/bindings/chromium_bindings_configuration.gni
+++ b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
@@ -11,6 +11,7 @@
   "//components/typemaps.gni",
   "//content/common/bluetooth/typemaps.gni",
   "//content/common/typemaps.gni",
+  "//content/public/common/typemaps.gni",
   "//device/bluetooth/public/interfaces/typemaps.gni",
   "//device/generic_sensor/public/interfaces/typemaps.gni",
   "//gpu/ipc/common/typemaps.gni",
@@ -20,6 +21,7 @@
   "//services/shell/public/cpp/typemaps.gni",
   "//services/ui/public/interfaces/display/typemaps.gni",
   "//skia/public/interfaces/typemaps.gni",
+  "//third_party/WebKit/public/public_typemaps.gni",
   "//ui/base/mojo/typemaps.gni",
   "//ui/events/devices/mojo/typemaps.gni",
   "//ui/events/mojo/typemaps.gni",
diff --git a/net/cert/x509_util_mac.cc b/net/cert/x509_util_mac.cc
index 3e71be1..46ae8fa7 100644
--- a/net/cert/x509_util_mac.cc
+++ b/net/cert/x509_util_mac.cc
@@ -6,6 +6,8 @@
 
 #include "base/logging.h"
 #include "base/mac/mac_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/strings/sys_string_conversions.h"
 #include "third_party/apple_apsl/cssmapplePriv.h"
 
 namespace net {
@@ -52,33 +54,26 @@
 
 
 OSStatus CreateSSLClientPolicy(SecPolicyRef* policy) {
-  CSSM_APPLE_TP_SSL_OPTIONS tp_ssl_options;
-  memset(&tp_ssl_options, 0, sizeof(tp_ssl_options));
-  tp_ssl_options.Version = CSSM_APPLE_TP_SSL_OPTS_VERSION;
-  tp_ssl_options.Flags |= CSSM_APPLE_TP_SSL_CLIENT;
-
-  return CreatePolicy(&CSSMOID_APPLE_TP_SSL, &tp_ssl_options,
-                      sizeof(tp_ssl_options), policy);
+  *policy = SecPolicyCreateSSL(false /* server */, nullptr);
+  return *policy ? noErr : errSecNoPolicyModule;
 }
 
 OSStatus CreateSSLServerPolicy(const std::string& hostname,
                                SecPolicyRef* policy) {
+  base::ScopedCFTypeRef<CFStringRef> hostname_cfstring;
   if (!hostname.empty()) {
-    CSSM_APPLE_TP_SSL_OPTIONS tp_ssl_options;
-    memset(&tp_ssl_options, 0, sizeof(tp_ssl_options));
-    tp_ssl_options.Version = CSSM_APPLE_TP_SSL_OPTS_VERSION;
-    tp_ssl_options.ServerName = hostname.data();
-    tp_ssl_options.ServerNameLen = hostname.size();
-
-    return CreatePolicy(&CSSMOID_APPLE_TP_SSL, &tp_ssl_options,
-                        sizeof(tp_ssl_options), policy);
+    hostname_cfstring.reset(base::SysUTF8ToCFStringRef(hostname));
+    if (!hostname_cfstring)
+      return errSecNoPolicyModule;
   }
 
-  return CreatePolicy(&CSSMOID_APPLE_TP_SSL, nullptr, 0U, policy);
+  *policy = SecPolicyCreateSSL(true /* server */, hostname_cfstring.get());
+  return *policy ? noErr : errSecNoPolicyModule;
 }
 
 OSStatus CreateBasicX509Policy(SecPolicyRef* policy) {
-  return CreatePolicy(&CSSMOID_APPLE_X509_BASIC, NULL, 0, policy);
+  *policy = SecPolicyCreateBasicX509();
+  return *policy ? noErr : errSecNoPolicyModule;
 }
 
 OSStatus CreateRevocationPolicies(bool enable_revocation_checking,
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index 0329c5c..5a484205 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -10,6 +10,7 @@
 #include "base/compiler_specific.h"
 #include "base/debug/stack_trace.h"
 #include "base/logging.h"
+#include "base/memory/memory_coordinator_client_registry.h"
 #include "base/profiler/scoped_tracker.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
@@ -219,11 +220,13 @@
 
   memory_pressure_listener_.reset(new base::MemoryPressureListener(base::Bind(
       &HttpNetworkSession::OnMemoryPressure, base::Unretained(this))));
+  base::MemoryCoordinatorClientRegistry::GetInstance()->Register(this);
 }
 
 HttpNetworkSession::~HttpNetworkSession() {
   base::STLDeleteElements(&response_drainers_);
   spdy_session_pool_.CloseAllSessions();
+  base::MemoryCoordinatorClientRegistry::GetInstance()->Unregister(this);
 }
 
 void HttpNetworkSession::AddResponseDrainer(HttpResponseBodyDrainer* drainer) {
@@ -395,4 +398,22 @@
   }
 }
 
+void HttpNetworkSession::OnMemoryStateChange(base::MemoryState state) {
+  // TODO(hajimehoshi): When the state changes, adjust the sizes of the caches
+  // to reduce the limits. HttpNetworkSession doesn't have the ability to limit
+  // at present.
+  switch (state) {
+    case base::MemoryState::NORMAL:
+      break;
+    case base::MemoryState::THROTTLED:
+      CloseIdleConnections();
+      break;
+    case base::MemoryState::SUSPENDED:
+    // Note: Not supported at present. Fall through.
+    case base::MemoryState::UNKNOWN:
+      NOTREACHED();
+      break;
+  }
+}
+
 }  // namespace net
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h
index 149cf71..07a7d72 100644
--- a/net/http/http_network_session.h
+++ b/net/http/http_network_session.h
@@ -14,6 +14,7 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/memory/memory_coordinator_client.h"
 #include "base/memory/memory_pressure_monitor.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
@@ -61,7 +62,8 @@
 
 // This class holds session objects used by HttpNetworkTransaction objects.
 class NET_EXPORT HttpNetworkSession
-    : NON_EXPORTED_BASE(public base::NonThreadSafe) {
+    : NON_EXPORTED_BASE(public base::NonThreadSafe),
+      public base::MemoryCoordinatorClient {
  public:
   struct NET_EXPORT Params {
     Params();
@@ -199,7 +201,7 @@
   };
 
   explicit HttpNetworkSession(const Params& params);
-  ~HttpNetworkSession();
+  ~HttpNetworkSession() override;
 
   HttpAuthCache* http_auth_cache() { return &http_auth_cache_; }
   SSLClientAuthCache* ssl_client_auth_cache() {
@@ -279,6 +281,9 @@
   void OnMemoryPressure(
       base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
 
+  // base::MemoryCoordinatorClient implementation:
+  void OnMemoryStateChange(base::MemoryState state) override;
+
   NetLog* const net_log_;
   HttpServerProperties* const http_server_properties_;
   CertVerifier* const cert_verifier_;
diff --git a/net/net.gypi b/net/net.gypi
index 88f8cfee..22b25470 100644
--- a/net/net.gypi
+++ b/net/net.gypi
@@ -1793,6 +1793,24 @@
       'quic/test_tools/rtt_stats_peer.h',
       'quic/test_tools/simple_quic_framer.cc',
       'quic/test_tools/simple_quic_framer.h',
+      'quic/test_tools/simulator/actor.cc',
+      'quic/test_tools/simulator/actor.h',
+      'quic/test_tools/simulator/alarm_factory.cc',
+      'quic/test_tools/simulator/alarm_factory.h',
+      'quic/test_tools/simulator/link.cc',
+      'quic/test_tools/simulator/link.h',
+      'quic/test_tools/simulator/port.cc',
+      'quic/test_tools/simulator/port.h',
+      'quic/test_tools/simulator/queue.cc',
+      'quic/test_tools/simulator/queue.h',
+      'quic/test_tools/simulator/quic_endpoint.cc',
+      'quic/test_tools/simulator/quic_endpoint.h',
+      'quic/test_tools/simulator/quic_endpoint_test.cc',
+      'quic/test_tools/simulator/simulator.cc',
+      'quic/test_tools/simulator/simulator.h',
+      'quic/test_tools/simulator/simulator_test.cc',
+      'quic/test_tools/simulator/switch.cc',
+      'quic/test_tools/simulator/switch.h',
       'quic/test_tools/test_task_runner.cc',
       'quic/test_tools/test_task_runner.h',
       'sdch/sdch_owner_unittest.cc',
diff --git a/net/quic/core/congestion_control/general_loss_algorithm.cc b/net/quic/core/congestion_control/general_loss_algorithm.cc
index 6415f2c..6c82329a 100644
--- a/net/quic/core/congestion_control/general_loss_algorithm.cc
+++ b/net/quic/core/congestion_control/general_loss_algorithm.cc
@@ -87,7 +87,10 @@
     // there are retransmittable packets in flight.
     // This also implements a timer-protected variant of FACK.
     if ((!it->retransmittable_frames.empty() &&
-         unacked_packets.largest_sent_packet() == largest_newly_acked) ||
+         (FLAGS_quic_largest_sent_retransmittable
+              ? unacked_packets.largest_sent_retransmittable_packet()
+              : unacked_packets.largest_sent_packet()) <=
+             largest_newly_acked) ||
         (loss_type_ == kTime || loss_type_ == kAdaptiveTime)) {
       QuicTime when_lost = it->sent_time + loss_delay;
       if (time < when_lost) {
diff --git a/net/quic/core/congestion_control/general_loss_algorithm_test.cc b/net/quic/core/congestion_control/general_loss_algorithm_test.cc
index fef1ccb..107674d 100644
--- a/net/quic/core/congestion_control/general_loss_algorithm_test.cc
+++ b/net/quic/core/congestion_control/general_loss_algorithm_test.cc
@@ -44,6 +44,14 @@
                                    true);
   }
 
+  void SendAckPacket(QuicPacketNumber packet_number) {
+    SerializedPacket packet(kDefaultPathId, packet_number,
+                            PACKET_1BYTE_PACKET_NUMBER, nullptr, kDefaultLength,
+                            0, true, false);
+    unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, clock_.Now(),
+                                   false);
+  }
+
   void VerifyLosses(QuicPacketNumber largest_newly_acked,
                     QuicPacketNumber* losses_expected,
                     size_t num_losses) {
@@ -184,6 +192,28 @@
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
 
+TEST_F(GeneralLossAlgorithmTest, EarlyRetransmitWithLargerUnackablePackets) {
+  FLAGS_quic_largest_sent_retransmittable = true;
+  // Transmit 2 data packets and one ack.
+  SendDataPacket(1);
+  SendDataPacket(2);
+  SendAckPacket(3);
+  clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
+
+  // Early retransmit when the final packet gets acked and the first is nacked.
+  unacked_packets_.IncreaseLargestObserved(2);
+  unacked_packets_.RemoveFromInFlight(2);
+  VerifyLosses(2, nullptr, 0);
+  EXPECT_EQ(clock_.Now() + 0.25 * rtt_stats_.smoothed_rtt(),
+            loss_algorithm_.GetLossTimeout());
+
+  // The packet should be lost once the loss timeout is reached.
+  clock_.AdvanceTime(0.25 * rtt_stats_.latest_rtt());
+  QuicPacketNumber lost[] = {1};
+  VerifyLosses(2, lost, arraysize(lost));
+  EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
+}
+
 TEST_F(GeneralLossAlgorithmTest, AlwaysLosePacketSent1RTTEarlier) {
   // Transmit 1 packet and then wait an rtt plus 1ms.
   SendDataPacket(1);
diff --git a/net/quic/core/crypto/crypto_server_test.cc b/net/quic/core/crypto/crypto_server_test.cc
index c148e9b..43fad918 100644
--- a/net/quic/core/crypto/crypto_server_test.cc
+++ b/net/quic/core/crypto/crypto_server_test.cc
@@ -480,7 +480,6 @@
 }
 
 TEST_P(CryptoServerTest, RejectNotTooLarge) {
-  FLAGS_quic_use_chlo_packet_size = true;
   // When the CHLO packet is large enough, ensure that a full REJ is sent.
   chlo_packet_size_ *= 2;
 
diff --git a/net/quic/core/crypto/quic_crypto_server_config.cc b/net/quic/core/crypto/quic_crypto_server_config.cc
index 66860e7..0853835 100644
--- a/net/quic/core/crypto/quic_crypto_server_config.cc
+++ b/net/quic/core/crypto/quic_crypto_server_config.cc
@@ -231,7 +231,8 @@
       source_address_token_lifetime_secs_(86400),
       server_nonce_strike_register_max_entries_(1 << 10),
       server_nonce_strike_register_window_secs_(120),
-      enable_serving_sct_(false) {
+      enable_serving_sct_(false),
+      rejection_observer_(nullptr) {
   DCHECK(proof_source_.get());
   source_address_token_boxer_.SetKeys(
       {DeriveSourceAddressTokenKey(source_address_token_secret)});
@@ -645,6 +646,10 @@
                    use_stateless_rejects, server_designated_connection_id, rand,
                    compressed_certs_cache, params, *crypto_proof,
                    total_framing_overhead, chlo_packet_size, out);
+    if (FLAGS_quic_export_rej_for_all_rejects &&
+        rejection_observer_ != nullptr) {
+      rejection_observer_->OnRejectionBuilt(info.reject_reasons, out);
+    }
     return QUIC_NO_ERROR;
   }
 
@@ -1518,14 +1523,9 @@
   // max_unverified_size is the number of bytes that the certificate chain,
   // signature, and (optionally) signed certificate timestamp can consume before
   // we will demand a valid source-address token.
-  const size_t old_max_unverified_size =
-      client_hello.size() * chlo_multiplier_ - kREJOverheadBytes;
-  const size_t new_max_unverified_size =
+  const size_t max_unverified_size =
       chlo_multiplier_ * (chlo_packet_size - total_framing_overhead) -
       kREJOverheadBytes;
-  const size_t max_unverified_size = FLAGS_quic_use_chlo_packet_size
-                                         ? new_max_unverified_size
-                                         : old_max_unverified_size;
   static_assert(kClientHelloMinimumSize * kMultiplier >= kREJOverheadBytes,
                 "overhead calculation may underflow");
   bool should_return_sct =
@@ -1544,13 +1544,11 @@
       }
     }
   } else {
-    if (FLAGS_quic_use_chlo_packet_size) {
-      DLOG(WARNING) << "Sending inchoate REJ for hostname: " << info.sni
-                    << " signature: " << crypto_proof.signature.size()
-                    << " cert: " << compressed.size() << " sct:" << sct_size
-                    << " total: " << total_size
-                    << " max: " << max_unverified_size;
-    }
+    DLOG(WARNING) << "Sending inchoate REJ for hostname: " << info.sni
+                  << " signature: " << crypto_proof.signature.size()
+                  << " cert: " << compressed.size() << " sct:" << sct_size
+                  << " total: " << total_size
+                  << " max: " << max_unverified_size;
   }
 }
 
diff --git a/net/quic/core/crypto/quic_crypto_server_config.h b/net/quic/core/crypto/quic_crypto_server_config.h
index 48449ad..12316b1b 100644
--- a/net/quic/core/crypto/quic_crypto_server_config.h
+++ b/net/quic/core/crypto/quic_crypto_server_config.h
@@ -128,6 +128,20 @@
   DISALLOW_COPY_AND_ASSIGN(BuildServerConfigUpdateMessageResultCallback);
 };
 
+// Object that is interested in built rejections (which include REJ, SREJ and
+// cheap SREJ).
+class RejectionObserver {
+ public:
+  RejectionObserver() = default;
+  virtual ~RejectionObserver() {}
+  // Called after a rejection is built.
+  virtual void OnRejectionBuilt(const std::vector<uint32_t>& reasons,
+                                CryptoHandshakeMessage* out) const = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RejectionObserver);
+};
+
 // QuicCryptoServerConfig contains the crypto configuration of a QUIC server.
 // Unlike a client, a QUIC server can have multiple configurations active in
 // order to support clients resuming with a previous configuration.
@@ -427,6 +441,12 @@
   // Returns the number of configs this object owns.
   int NumberOfConfigs() const;
 
+  // Callers retain the ownership of |rejection_observer| which must outlive the
+  // config.
+  void set_rejection_observer(RejectionObserver* rejection_observer) {
+    rejection_observer_ = rejection_observer;
+  }
+
  private:
   friend class test::QuicCryptoServerConfigPeer;
   friend struct QuicCryptoProof;
@@ -784,6 +804,9 @@
   // Enable serving SCT or not.
   bool enable_serving_sct_;
 
+  // Does not own this observer.
+  RejectionObserver* rejection_observer_;
+
   DISALLOW_COPY_AND_ASSIGN(QuicCryptoServerConfig);
 };
 
diff --git a/net/quic/core/quic_connection.cc b/net/quic/core/quic_connection.cc
index 6985d7d..c93735b 100644
--- a/net/quic/core/quic_connection.cc
+++ b/net/quic/core/quic_connection.cc
@@ -1298,6 +1298,15 @@
   stats_.bytes_received += packet.length();
   ++stats_.packets_received;
 
+  // Ensure the time coming from the packet reader is within a minute of now.
+  if (FLAGS_quic_allow_large_send_deltas &&
+      std::abs((packet.receipt_time() - clock_->ApproximateNow()).ToSeconds()) >
+          60) {
+    QUIC_BUG << "Packet receipt time:"
+             << packet.receipt_time().ToDebuggingValue()
+             << " too far from current time:"
+             << clock_->ApproximateNow().ToDebuggingValue();
+  }
   time_of_last_received_packet_ = packet.receipt_time();
   DVLOG(1) << ENDPOINT << "time of last received packet: "
            << time_of_last_received_packet_.ToDebuggingValue();
diff --git a/net/quic/core/quic_flags_list.h b/net/quic/core/quic_flags_list.h
index ffda3d9..a2859c6 100644
--- a/net/quic/core/quic_flags_list.h
+++ b/net/quic/core/quic_flags_list.h
@@ -72,10 +72,6 @@
 // versions less than 33.
 QUIC_FLAG(bool, FLAGS_quic_require_handshake_confirmation_pre33, false)
 
-// If true, use the CHLO packet size, not message size when determining how
-// large a REJ can be.
-QUIC_FLAG(bool, FLAGS_quic_use_chlo_packet_size, true)
-
 // If true, defer creation of new connection till its CHLO arrives.
 QUIC_FLAG(bool, FLAGS_quic_buffer_packet_till_chlo, true)
 
@@ -102,7 +98,7 @@
 // If true, only open limited number of quic sessions per epoll event. Leave the
 // rest to next event. This flag can be turned on only if
 // --quic_buffer_packet_till_chlo is true.
-QUIC_FLAG(bool, FLAGS_quic_limit_num_new_sessions_per_epoll_loop, false)
+QUIC_FLAG(bool, FLAGS_quic_limit_num_new_sessions_per_epoll_loop, true)
 
 // If true, lazy allocate and early release memeory used in
 // QuicStreamSequencerBuffer to buffer incoming data.
@@ -136,3 +132,17 @@
 // As the Linux kernel does, limit QUIC's Cubic congestion control to
 // only increase the CWND 1 packet for every two packets acked.
 QUIC_FLAG(bool, FLAGS_quic_limit_cubic_cwnd_increase, true)
+
+// If true, export reject reasons for all rejects, i.e., rejects,
+// stateless rejects and cheap stateless rejects.
+QUIC_FLAG(bool, FLAGS_quic_export_rej_for_all_rejects, true)
+
+// Allow large send deltas to be used as RTT samples.
+QUIC_FLAG(bool, FLAGS_quic_allow_large_send_deltas, true)
+
+// Engage early retransmit anytime the largest acked is greater than
+// or equal to the largest retransmittable packet.
+QUIC_FLAG(bool, FLAGS_quic_largest_sent_retransmittable, true)
+
+// If true, close connection when sequencer buffer enter into unexpected state.
+QUIC_FLAG(bool, FLAGS_quic_stream_sequencer_buffer_debug, true)
diff --git a/net/quic/core/quic_headers_stream.h b/net/quic/core/quic_headers_stream.h
index 89a8c3f..603dd45 100644
--- a/net/quic/core/quic_headers_stream.h
+++ b/net/quic/core/quic_headers_stream.h
@@ -167,9 +167,6 @@
   SpdyFramer spdy_framer_;
   std::unique_ptr<SpdyFramerVisitor> spdy_framer_visitor_;
 
-  // Either empty, or contains the complete list of headers.
-  QuicHeaderList header_list_;
-
   DISALLOW_COPY_AND_ASSIGN(QuicHeadersStream);
 };
 
diff --git a/net/quic/core/quic_multipath_sent_packet_manager.cc b/net/quic/core/quic_multipath_sent_packet_manager.cc
index 0800a6a..5d46ec10 100644
--- a/net/quic/core/quic_multipath_sent_packet_manager.cc
+++ b/net/quic/core/quic_multipath_sent_packet_manager.cc
@@ -354,12 +354,6 @@
   path_manager->OnConnectionMigration(path_id, type);
 }
 
-bool QuicMultipathSentPacketManager::IsHandshakeConfirmed() const {
-  QuicSentPacketManagerInterface* path_manager =
-      MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
-  return path_manager != nullptr && path_manager->IsHandshakeConfirmed();
-}
-
 void QuicMultipathSentPacketManager::SetDebugDelegate(
     DebugDelegate* debug_delegate) {
   for (PathSentPacketManagerInfo path_manager_info : path_managers_info_) {
diff --git a/net/quic/core/quic_multipath_sent_packet_manager.h b/net/quic/core/quic_multipath_sent_packet_manager.h
index c805280..75b35dd 100644
--- a/net/quic/core/quic_multipath_sent_packet_manager.h
+++ b/net/quic/core/quic_multipath_sent_packet_manager.h
@@ -143,8 +143,6 @@
   void OnConnectionMigration(QuicPathId path_id,
                              PeerAddressChangeType type) override;
 
-  bool IsHandshakeConfirmed() const override;
-
   // Sets debug delegate for all active paths.
   void SetDebugDelegate(DebugDelegate* debug_delegate) override;
 
diff --git a/net/quic/core/quic_multipath_sent_packet_manager_test.cc b/net/quic/core/quic_multipath_sent_packet_manager_test.cc
index 62177aa..bcff44d 100644
--- a/net/quic/core/quic_multipath_sent_packet_manager_test.cc
+++ b/net/quic/core/quic_multipath_sent_packet_manager_test.cc
@@ -275,11 +275,6 @@
       multipath_manager_.OnConnectionMigration(kTestPathId3, PORT_CHANGE), "");
 }
 
-TEST_F(QuicMultipathSentPacketManagerTest, IsHandshakeConfirmed) {
-  EXPECT_CALL(*manager_0_, IsHandshakeConfirmed()).WillOnce(Return(true));
-  EXPECT_TRUE(multipath_manager_.IsHandshakeConfirmed());
-}
-
 TEST_F(QuicMultipathSentPacketManagerTest, SetDebugDelegate) {
   EXPECT_CALL(*manager_0_, SetDebugDelegate(nullptr));
   EXPECT_CALL(*manager_1_, SetDebugDelegate(nullptr));
diff --git a/net/quic/core/quic_protocol.h b/net/quic/core/quic_protocol.h
index 72a5b69c..8906879 100644
--- a/net/quic/core/quic_protocol.h
+++ b/net/quic/core/quic_protocol.h
@@ -724,8 +724,12 @@
   // maintains too many gaps.
   QUIC_TOO_MANY_FRAME_GAPS = 93,
 
+  // Sequencer buffer get into weird state where continuing read/write will lead
+  // to crash.
+  QUIC_STREAM_SEQUENCER_INVALID_STATE = 95,
+
   // No error. Used as bound while iterating.
-  QUIC_LAST_ERROR = 95,
+  QUIC_LAST_ERROR = 96,
 };
 
 typedef std::array<char, 32> DiversificationNonce;
diff --git a/net/quic/core/quic_sent_packet_manager.cc b/net/quic/core/quic_sent_packet_manager.cc
index 5a97b1e..7738e34 100644
--- a/net/quic/core/quic_sent_packet_manager.cc
+++ b/net/quic/core/quic_sent_packet_manager.cc
@@ -632,9 +632,6 @@
     if (!it->in_flight || it->retransmittable_frames.empty()) {
       continue;
     }
-    if (!handshake_confirmed_) {
-      DCHECK(!it->has_crypto_handshake);
-    }
     MarkForRetransmission(packet_number, TLP_RETRANSMISSION);
     return true;
   }
@@ -743,7 +740,8 @@
 
   QuicTime::Delta send_delta = ack_receive_time - transmission_info.sent_time;
   const int kMaxSendDeltaSeconds = 30;
-  if (send_delta.ToSeconds() > kMaxSendDeltaSeconds) {
+  if (!FLAGS_quic_allow_large_send_deltas &&
+      send_delta.ToSeconds() > kMaxSendDeltaSeconds) {
     // send_delta can be very high if local clock is changed mid-connection.
     LOG(WARNING) << "Excessive send delta: " << send_delta.ToSeconds()
                  << ", setting to: " << kMaxSendDeltaSeconds
@@ -946,9 +944,6 @@
   send_algorithm_->OnConnectionMigration();
 }
 
-bool QuicSentPacketManager::IsHandshakeConfirmed() const {
-  return handshake_confirmed_;
-}
 
 void QuicSentPacketManager::SetDebugDelegate(DebugDelegate* debug_delegate) {
   debug_delegate_ = debug_delegate;
diff --git a/net/quic/core/quic_sent_packet_manager.h b/net/quic/core/quic_sent_packet_manager.h
index 17e2203..b442951 100644
--- a/net/quic/core/quic_sent_packet_manager.h
+++ b/net/quic/core/quic_sent_packet_manager.h
@@ -189,8 +189,6 @@
   // Called when peer address changes and the connection migrates.
   void OnConnectionMigration(QuicPathId, PeerAddressChangeType type) override;
 
-  bool IsHandshakeConfirmed() const override;
-
   void SetDebugDelegate(DebugDelegate* debug_delegate) override;
 
   QuicPacketNumber GetLargestObserved(QuicPathId) const override;
diff --git a/net/quic/core/quic_sent_packet_manager_interface.h b/net/quic/core/quic_sent_packet_manager_interface.h
index c366ed6..7d80e6f 100644
--- a/net/quic/core/quic_sent_packet_manager_interface.h
+++ b/net/quic/core/quic_sent_packet_manager_interface.h
@@ -165,8 +165,6 @@
   virtual void OnConnectionMigration(QuicPathId path_id,
                                      PeerAddressChangeType type) = 0;
 
-  virtual bool IsHandshakeConfirmed() const = 0;
-
   virtual void SetDebugDelegate(DebugDelegate* debug_delegate) = 0;
 
   virtual QuicPacketNumber GetLargestObserved(QuicPathId path_id) const = 0;
diff --git a/net/quic/core/quic_stream_sequencer.cc b/net/quic/core/quic_stream_sequencer.cc
index 4a6ea83..45f1e88c 100644
--- a/net/quic/core/quic_stream_sequencer.cc
+++ b/net/quic/core/quic_stream_sequencer.cc
@@ -9,8 +9,10 @@
 #include <string>
 #include <utility>
 
+#include "base/format_macros.h"
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
 #include "net/quic/core/quic_bug_tracker.h"
 #include "net/quic/core/quic_clock.h"
 #include "net/quic/core/quic_flags.h"
@@ -21,6 +23,7 @@
 
 using base::IntToString;
 using base::StringPiece;
+using base::StringPrintf;
 using std::min;
 using std::numeric_limits;
 using std::string;
@@ -135,7 +138,17 @@
 
 int QuicStreamSequencer::Readv(const struct iovec* iov, size_t iov_len) {
   DCHECK(!blocked_);
-  size_t bytes_read = buffered_frames_.Readv(iov, iov_len);
+  string error_details;
+  size_t bytes_read;
+  QuicErrorCode read_error =
+      buffered_frames_.Readv(iov, iov_len, &bytes_read, &error_details);
+  if (FLAGS_quic_stream_sequencer_buffer_debug && read_error != QUIC_NO_ERROR) {
+    string details = StringPrintf("Stream %" PRIu32 ": %s", stream_->id(),
+                                  error_details.c_str());
+    stream_->CloseConnectionWithDetails(read_error, details);
+    return static_cast<int>(bytes_read);
+  }
+
   stream_->AddBytesConsumed(bytes_read);
   return static_cast<int>(bytes_read);
 }
diff --git a/net/quic/core/quic_stream_sequencer_buffer.cc b/net/quic/core/quic_stream_sequencer_buffer.cc
index 0c55fe75..fcb617fb6 100644
--- a/net/quic/core/quic_stream_sequencer_buffer.cc
+++ b/net/quic/core/quic_stream_sequencer_buffer.cc
@@ -4,11 +4,14 @@
 
 #include "net/quic/core/quic_stream_sequencer_buffer.h"
 
+#include "base/format_macros.h"
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
 #include "net/quic/core/quic_bug_tracker.h"
 #include "net/quic/core/quic_flags.h"
 
+using base::StringPrintf;
 using std::min;
 using std::string;
 
@@ -76,11 +79,15 @@
   frame_arrival_time_map_.clear();
 }
 
-void QuicStreamSequencerBuffer::RetireBlock(size_t idx) {
-  DCHECK(blocks_[idx] != nullptr);
+bool QuicStreamSequencerBuffer::RetireBlock(size_t idx) {
+  if (FLAGS_quic_stream_sequencer_buffer_debug && blocks_[idx] == nullptr) {
+    QUIC_BUG << "Try to retire block twice";
+    return false;
+  }
   delete blocks_[idx];
   blocks_[idx] = nullptr;
   DVLOG(1) << "Retired block with index: " << idx;
+  return true;
 }
 
 QuicErrorCode QuicStreamSequencerBuffer::OnStreamData(
@@ -181,6 +188,20 @@
       }
     }
 
+    if (FLAGS_quic_stream_sequencer_buffer_debug &&
+        write_block_num >= blocks_count_) {
+      *error_details = StringPrintf(
+          "QuicStreamSequencerBuffer error: OnStreamData() exceed array bounds."
+          "write offset = %" PRIu64 " write_block_num = %" PRIuS
+          " blocks_count_ = %" PRIuS,
+          offset, write_block_num, blocks_count_);
+      return QUIC_STREAM_SEQUENCER_INVALID_STATE;
+    }
+    if (blocks_ == nullptr) {
+      *error_details =
+          "QuicStreamSequencerBuffer error: OnStreamData() blocks_ is null";
+      return QUIC_STREAM_SEQUENCER_INVALID_STATE;
+    }
     if (blocks_[write_block_num] == nullptr) {
       // TODO(danzh): Investigate if using a freelist would improve performance.
       // Same as RetireBlock().
@@ -190,6 +211,23 @@
     const size_t bytes_to_copy = min<size_t>(bytes_avail, source_remaining);
     char* dest = blocks_[write_block_num]->buffer + write_block_offset;
     DVLOG(1) << "Write at offset: " << offset << " length: " << bytes_to_copy;
+
+    if (FLAGS_quic_stream_sequencer_buffer_debug &&
+        (dest == nullptr || source == nullptr)) {
+      *error_details = StringPrintf(
+          "QuicStreamSequencerBuffer error: OnStreamData()"
+          " dest == nullptr: %s"
+          " source == nullptr: %s"
+          " Writing at offset %" PRIu64
+          " Gaps: %s"
+          " Remaining frames: %s"
+          " total_bytes_read_ = %" PRIu64,
+          (dest == nullptr ? "true" : "false"),
+          (source == nullptr ? "true" : "false"), offset,
+          GapsDebugString().c_str(), ReceivedFramesDebugString().c_str(),
+          total_bytes_read_);
+      return QUIC_STREAM_SEQUENCER_INVALID_STATE;
+    }
     memcpy(dest, source, bytes_to_copy);
     source += bytes_to_copy;
     source_remaining -= bytes_to_copy;
@@ -237,9 +275,11 @@
   }
 }
 
-size_t QuicStreamSequencerBuffer::Readv(const iovec* dest_iov,
-                                        size_t dest_count) {
-  size_t bytes_read = 0;
+QuicErrorCode QuicStreamSequencerBuffer::Readv(const iovec* dest_iov,
+                                               size_t dest_count,
+                                               size_t* bytes_read,
+                                               string* error_details) {
+  *bytes_read = 0;
   for (size_t i = 0; i < dest_count && ReadableBytes() > 0; ++i) {
     char* dest = reinterpret_cast<char*>(dest_iov[i].iov_base);
     size_t dest_remaining = dest_iov[i].iov_len;
@@ -251,28 +291,47 @@
           min<size_t>(ReadableBytes(), block_capacity - start_offset_in_block);
       size_t bytes_to_copy =
           min<size_t>(bytes_available_in_block, dest_remaining);
-      DCHECK_GT(bytes_to_copy, 0u);
-      DCHECK_NE(static_cast<BufferBlock*>(nullptr), blocks_[block_idx]);
+      DCHECK_GT(bytes_to_copy, 0UL);
+      if (FLAGS_quic_stream_sequencer_buffer_debug &&
+          (blocks_[block_idx] == nullptr || dest == nullptr)) {
+        *error_details = StringPrintf(
+            "QuicStreamSequencerBuffer error:"
+            " Readv() dest == nullptr: %s"
+            " blocks_[%" PRIuS "] == nullptr: %s",
+            (dest == nullptr ? "true" : "false"), block_idx,
+            (blocks_[block_idx] == nullptr ? "true" : "false"));
+        return QUIC_STREAM_SEQUENCER_INVALID_STATE;
+      }
       memcpy(dest, blocks_[block_idx]->buffer + start_offset_in_block,
              bytes_to_copy);
       dest += bytes_to_copy;
       dest_remaining -= bytes_to_copy;
       num_bytes_buffered_ -= bytes_to_copy;
       total_bytes_read_ += bytes_to_copy;
-      bytes_read += bytes_to_copy;
+      *bytes_read += bytes_to_copy;
 
-      // Retire the block if all the data is read out
-      // and no other data is stored in this block.
+      // Retire the block if all the data is read out and no other data is
+      // stored in this block.
+      // In case of failing to retire a block which is ready to retire, return
+      // immediately.
       if (bytes_to_copy == bytes_available_in_block) {
-        RetireBlockIfEmpty(block_idx);
+        bool retire_successfully = RetireBlockIfEmpty(block_idx);
+        if (FLAGS_quic_stream_sequencer_buffer_debug && !retire_successfully) {
+          *error_details = StringPrintf(
+              "QuicStreamSequencerBuffer error: fail to retire block %" PRIuS
+              " as the block is already released + total_bytes_read_ = %" PRIu64
+              " Gaps: %s",
+              block_idx, total_bytes_read_, GapsDebugString().c_str());
+          return QUIC_STREAM_SEQUENCER_INVALID_STATE;
+        }
       }
     }
   }
 
-  if (bytes_read > 0) {
+  if (*bytes_read > 0) {
     UpdateFrameArrivalMap(total_bytes_read_);
   }
-  return bytes_read;
+  return QUIC_NO_ERROR;
 }
 
 int QuicStreamSequencerBuffer::GetReadableRegions(struct iovec* iov,
@@ -447,21 +506,20 @@
   return GetBlockIndex(total_bytes_read_);
 }
 
-void QuicStreamSequencerBuffer::RetireBlockIfEmpty(size_t block_index) {
+bool QuicStreamSequencerBuffer::RetireBlockIfEmpty(size_t block_index) {
   DCHECK(ReadableBytes() == 0 || GetInBlockOffset(total_bytes_read_) == 0)
       << "RetireBlockIfEmpty() should only be called when advancing to next "
          "block"
          " or a gap has been reached.";
   // If the whole buffer becomes empty, the last piece of data has been read.
   if (Empty()) {
-    RetireBlock(block_index);
-    return;
+    return RetireBlock(block_index);
   }
 
   // Check where the logical end of this buffer is.
   // Not empty if the end of circular buffer has been wrapped to this block.
   if (GetBlockIndex(gaps_.back().begin_offset - 1) == block_index) {
-    return;
+    return true;
   }
 
   // Read index remains in this block, which means a gap has been reached.
@@ -473,10 +531,10 @@
     bool gap_ends_in_this_block =
         (GetBlockIndex(first_gap.end_offset) == block_index);
     if (gap_ends_in_this_block) {
-      return;
+      return true;
     }
   }
-  RetireBlock(block_index);
+  return RetireBlock(block_index);
 }
 
 bool QuicStreamSequencerBuffer::Empty() const {
@@ -534,8 +592,16 @@
     QuicStreamOffset current_frame_begin_offset = it.first;
     QuicStreamOffset current_frame_end_offset =
         it.second.length + current_frame_begin_offset;
-    current_frames_string +=
-        RangeDebugString(current_frame_begin_offset, current_frame_end_offset);
+    if (FLAGS_quic_stream_sequencer_buffer_debug) {
+      current_frames_string = string(StringPrintf(
+          "%s[%" PRIu64 ", %" PRIu64 ") receiving time %" PRId64 " ",
+          current_frames_string.c_str(), current_frame_begin_offset,
+          current_frame_end_offset, it.second.timestamp.ToDebuggingValue()));
+    } else {
+      current_frames_string = string(StringPrintf(
+          "%s[%" PRIu64 ", %" PRIu64 ") ", current_frames_string.c_str(),
+          current_frame_begin_offset, current_frame_end_offset));
+    }
   }
   return current_frames_string;
 }
diff --git a/net/quic/core/quic_stream_sequencer_buffer.h b/net/quic/core/quic_stream_sequencer_buffer.h
index 135e7d1..a79d8b4 100644
--- a/net/quic/core/quic_stream_sequencer_buffer.h
+++ b/net/quic/core/quic_stream_sequencer_buffer.h
@@ -125,7 +125,10 @@
 
   // Reads from this buffer into given iovec array, up to number of iov_len
   // iovec objects and returns the number of bytes read.
-  size_t Readv(const struct iovec* dest_iov, size_t dest_count);
+  QuicErrorCode Readv(const struct iovec* dest_iov,
+                      size_t dest_count,
+                      size_t* bytes_read,
+                      std::string* error_details);
 
   // Returns the readable region of valid data in iovec format. The readable
   // region is the buffer region where there is valid data not yet read by
@@ -174,13 +177,15 @@
   // Dispose the given buffer block.
   // After calling this method, blocks_[index] is set to nullptr
   // in order to indicate that no memory set is allocated for that block.
-  void RetireBlock(size_t index);
+  // Returns true on success, false otherwise.
+  bool RetireBlock(size_t index);
 
   // Should only be called after the indexed block is read till the end of the
   // block or a gap has been reached.
-  // If the block at |block_index| contains no buffered data, then the block is
-  // retired.
-  void RetireBlockIfEmpty(size_t block_index);
+  // If the block at |block_index| contains no buffered data, the block
+  // should be retired.
+  // Return false on success, or false otherwise.
+  bool RetireBlockIfEmpty(size_t block_index);
 
   // Called within OnStreamData() to update the gap OnStreamData() writes into
   // (remove, split or change begin/end offset).
diff --git a/net/quic/core/quic_stream_sequencer_buffer_test.cc b/net/quic/core/quic_stream_sequencer_buffer_test.cc
index f4ae84c..944b41a 100644
--- a/net/quic/core/quic_stream_sequencer_buffer_test.cc
+++ b/net/quic/core/quic_stream_sequencer_buffer_test.cc
@@ -66,7 +66,11 @@
   size_t Read(char* dest_buffer, size_t size) {
     iovec dest;
     dest.iov_base = dest_buffer, dest.iov_len = size;
-    return buffer_->Readv(&dest, 1);
+    size_t bytes_read;
+    string error_details;
+    EXPECT_EQ(QUIC_NO_ERROR,
+              buffer_->Readv(&dest, 1, &bytes_read, &error_details));
+    return bytes_read;
   }
 
   // If buffer is empty, the blocks_ array must be empty, which means all
@@ -186,6 +190,7 @@
   MockClock clock_;
   std::unique_ptr<QuicStreamSequencerBuffer> buffer_;
   std::unique_ptr<QuicStreamSequencerBufferPeer> helper_;
+  QuicFlagSaver flag_saver_;
   string error_details_;
 };
 
@@ -240,6 +245,22 @@
   EXPECT_TRUE(helper_->IsBufferAllocated());
 }
 
+TEST_F(QuicStreamSequencerBufferTest, OnStreamDataInvalidSource) {
+  FLAGS_quic_stream_sequencer_buffer_debug = true;
+  // Pass in an invalid source, expects to return error.
+  StringPiece source;
+  source.set(nullptr, 1024);
+  size_t written;
+  clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+  QuicTime t = clock_.ApproximateNow();
+  EXPECT_EQ(QUIC_STREAM_SEQUENCER_INVALID_STATE,
+            buffer_->OnStreamData(800, source, t, &written, &error_details_));
+  EXPECT_EQ(
+      0u, error_details_.find("QuicStreamSequencerBuffer error: OnStreamData()"
+                              " dest == nullptr: false"
+                              " source == nullptr: true"));
+}
+
 TEST_F(QuicStreamSequencerBufferTest, OnStreamDataWithOverlap) {
   string source(1024, 'a');
   // Write something into [800, 1824)
@@ -411,7 +432,9 @@
   // Read into a iovec array with total capacity of 120 bytes.
   char dest[120];
   iovec iovecs[3]{iovec{dest, 40}, iovec{dest + 40, 40}, iovec{dest + 80, 40}};
-  size_t read = buffer_->Readv(iovecs, 3);
+  size_t read;
+  EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(iovecs, 3, &read, &error_details_));
+  LOG(ERROR) << error_details_;
   EXPECT_EQ(100u, read);
   EXPECT_EQ(100u, buffer_->BytesConsumed());
   EXPECT_EQ(source, string(dest, read));
@@ -421,6 +444,27 @@
   EXPECT_TRUE(helper_->CheckBufferInvariants());
 }
 
+TEST_F(QuicStreamSequencerBufferTest, ReadvError) {
+  FLAGS_quic_stream_sequencer_buffer_debug = true;
+  string source = string(100, 'b');
+  clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+  QuicTime t1 = clock_.ApproximateNow();
+  // Write something into [0, 100).
+  size_t written;
+  buffer_->OnStreamData(0, source, t1, &written, &error_details_);
+  EXPECT_TRUE(helper_->GetBlock(0) != nullptr);
+  EXPECT_TRUE(buffer_->HasBytesToRead());
+  // Read into a iovec array with total capacity of 120 bytes.
+  iovec iov{nullptr, 120};
+  size_t read;
+  EXPECT_EQ(QUIC_STREAM_SEQUENCER_INVALID_STATE,
+            buffer_->Readv(&iov, 1, &read, &error_details_));
+  EXPECT_EQ(0u,
+            error_details_.find(
+                "QuicStreamSequencerBuffer error: Readv() dest == nullptr: true"
+                " blocks_[0] == nullptr: false"));
+}
+
 TEST_F(QuicStreamSequencerBufferTest, ReadvAcrossBlocks) {
   string source(kBlockSizeBytes + 50, 'a');
   // Write 1st block to full and extand 50 bytes to next block.
@@ -433,7 +477,8 @@
   while (helper_->ReadableBytes()) {
     std::fill(dest, dest + 512, 0);
     iovec iovecs[2]{iovec{dest, 256}, iovec{dest + 256, 256}};
-    buffer_->Readv(iovecs, 2);
+    size_t read;
+    EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(iovecs, 2, &read, &error_details_));
   }
   // The last read only reads the rest 50 bytes in 2nd block.
   EXPECT_EQ(string(50, 'a'), string(dest, 50));
@@ -452,7 +497,8 @@
   // Read first 512 bytes from buffer to make space at the beginning.
   char dest[512]{0};
   const iovec iov{dest, 512};
-  buffer_->Readv(&iov, 1);
+  size_t read;
+  EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(&iov, 1, &read, &error_details_));
   // Clear() should make buffer empty while preserving BytesConsumed()
   buffer_->Clear();
   EXPECT_TRUE(buffer_->Empty());
@@ -469,7 +515,8 @@
   // Read first 512 bytes from buffer to make space at the beginning.
   char dest[512]{0};
   const iovec iov{dest, 512};
-  buffer_->Readv(&iov, 1);
+  size_t read;
+  EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(&iov, 1, &read, &error_details_));
   EXPECT_EQ(source.size(), written);
 
   // Write more than half block size of bytes in the last block with 'b', which
@@ -492,7 +539,8 @@
   // Read first 512 bytes from buffer to make space at the beginning.
   char dest[512]{0};
   const iovec iov{dest, 512};
-  buffer_->Readv(&iov, 1);
+  size_t read;
+  EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(&iov, 1, &read, &error_details_));
 
   // Try to write from [max_capacity_bytes_ - 0.5 * kBlockSizeBytes,
   // max_capacity_bytes_ +  512 + 1). But last bytes exceeds current capacity.
@@ -514,7 +562,8 @@
   buffer_->OnStreamData(0, source, t, &written, &error_details_);
   char dest[512]{0};
   const iovec iov{dest, 512};
-  buffer_->Readv(&iov, 1);
+  size_t read;
+  EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(&iov, 1, &read, &error_details_));
   source = string(256, 'b');
   clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
   QuicTime t2 = clock_.ApproximateNow();
@@ -527,7 +576,8 @@
   std::unique_ptr<char[]> dest1{new char[max_capacity_bytes_]};
   dest1[0] = 0;
   const iovec iov1{dest1.get(), max_capacity_bytes_};
-  EXPECT_EQ(max_capacity_bytes_ - 512 + 256, buffer_->Readv(&iov1, 1));
+  EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(&iov1, 1, &read, &error_details_));
+  EXPECT_EQ(max_capacity_bytes_ - 512 + 256, read);
   EXPECT_EQ(max_capacity_bytes_ + 256, buffer_->BytesConsumed());
   EXPECT_TRUE(buffer_->Empty());
   EXPECT_TRUE(helper_->CheckBufferInvariants());
@@ -537,7 +587,8 @@
 TEST_F(QuicStreamSequencerBufferTest, ReadvEmpty) {
   char dest[512]{0};
   iovec iov{dest, 512};
-  size_t read = buffer_->Readv(&iov, 1);
+  size_t read;
+  EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(&iov, 1, &read, &error_details_));
   EXPECT_EQ(0u, read);
   EXPECT_TRUE(helper_->CheckBufferInvariants());
 }
@@ -566,7 +617,8 @@
   EXPECT_TRUE(buffer_->HasBytesToRead());
   char dest[120];
   iovec iovecs[3]{iovec{dest, 40}, iovec{dest + 40, 40}, iovec{dest + 80, 40}};
-  size_t read = buffer_->Readv(iovecs, 3);
+  size_t read;
+  EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(iovecs, 3, &read, &error_details_));
   EXPECT_EQ(100u, read);
   EXPECT_EQ(100u, buffer_->BytesConsumed());
   EXPECT_TRUE(helper_->CheckBufferInvariants());
@@ -1013,7 +1065,10 @@
           dest_iov[i].iov_len = rng_.RandUint64() % kMaxReadSize;
           num_to_read += dest_iov[i].iov_len;
         }
-        size_t actually_read = buffer_->Readv(dest_iov, kNumReads);
+        size_t actually_read;
+        EXPECT_EQ(QUIC_NO_ERROR,
+                  buffer_->Readv(dest_iov, kNumReads, &actually_read,
+                                 &error_details_));
         ASSERT_LE(actually_read, num_to_read);
         DVLOG(1) << " read from offset: " << total_bytes_read_
                  << " size: " << num_to_read
diff --git a/net/quic/core/quic_stream_sequencer_test.cc b/net/quic/core/quic_stream_sequencer_test.cc
index 0960f03..b3b473f0 100644
--- a/net/quic/core/quic_stream_sequencer_test.cc
+++ b/net/quic/core/quic_stream_sequencer_test.cc
@@ -662,6 +662,30 @@
   EXPECT_EQ(0u, sequencer_->NumBytesBuffered());
 }
 
+TEST_F(QuicStreamSequencerTest, OnStreamFrameWithNullSource) {
+  FLAGS_quic_stream_sequencer_buffer_debug = true;
+  // Pass in a frame with data pointing to null address, expect to close
+  // connection with error.
+  StringPiece source(nullptr, 5u);
+  QuicStreamFrame frame(kClientDataStreamId1, false, 1, source);
+  EXPECT_CALL(stream_, CloseConnectionWithDetails(
+                           QUIC_STREAM_SEQUENCER_INVALID_STATE, _));
+  sequencer_->OnStreamFrame(frame);
+}
+
+TEST_F(QuicStreamSequencerTest, ReadvError) {
+  FLAGS_quic_stream_sequencer_buffer_debug = true;
+  EXPECT_CALL(stream_, OnDataAvailable());
+  string source(100, 'a');
+  OnFrame(0u, source.data());
+  EXPECT_EQ(source.length(), sequencer_->NumBytesBuffered());
+  // Pass in a null iovec, expect to tear down connection.
+  EXPECT_CALL(stream_, CloseConnectionWithDetails(
+                           QUIC_STREAM_SEQUENCER_INVALID_STATE, _));
+  iovec iov{nullptr, 512};
+  sequencer_->Readv(&iov, 1u);
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/core/quic_unacked_packet_map.cc b/net/quic/core/quic_unacked_packet_map.cc
index 0c70d14..adc4a653 100644
--- a/net/quic/core/quic_unacked_packet_map.cc
+++ b/net/quic/core/quic_unacked_packet_map.cc
@@ -18,6 +18,7 @@
 
 QuicUnackedPacketMap::QuicUnackedPacketMap()
     : largest_sent_packet_(0),
+      largest_sent_retransmittable_packet_(0),
       largest_observed_(0),
       least_unacked_(1),
       bytes_in_flight_(0),
@@ -59,6 +60,7 @@
   if (set_in_flight) {
     bytes_in_flight_ += bytes_sent;
     info.in_flight = true;
+    largest_sent_retransmittable_packet_ = packet_number;
   }
   unacked_packets_.push_back(info);
   // Swap the ack listeners and retransmittable frames to avoid allocations.
diff --git a/net/quic/core/quic_unacked_packet_map.h b/net/quic/core/quic_unacked_packet_map.h
index 73969fd6..2357779 100644
--- a/net/quic/core/quic_unacked_packet_map.h
+++ b/net/quic/core/quic_unacked_packet_map.h
@@ -80,6 +80,11 @@
   // Returns the largest packet number that has been sent.
   QuicPacketNumber largest_sent_packet() const { return largest_sent_packet_; }
 
+  // Returns the largest retransmittable packet number that has been sent.
+  QuicPacketNumber largest_sent_retransmittable_packet() const {
+    return largest_sent_retransmittable_packet_;
+  }
+
   // Returns the largest packet number that has been acked.
   QuicPacketNumber largest_observed() const { return largest_observed_; }
 
@@ -169,6 +174,8 @@
                        const TransmissionInfo& info) const;
 
   QuicPacketNumber largest_sent_packet_;
+  // The largest sent packet we expect to receive an ack for.
+  QuicPacketNumber largest_sent_retransmittable_packet_;
   QuicPacketNumber largest_observed_;
 
   // Newly serialized retransmittable packets are added to this map, which
diff --git a/net/quic/core/quic_utils.cc b/net/quic/core/quic_utils.cc
index 52c0def6..f944dd1 100644
--- a/net/quic/core/quic_utils.cc
+++ b/net/quic/core/quic_utils.cc
@@ -303,6 +303,7 @@
     RETURN_STRING_LITERAL(QUIC_MULTIPATH_PATH_DOES_NOT_EXIST);
     RETURN_STRING_LITERAL(QUIC_MULTIPATH_PATH_NOT_ACTIVE);
     RETURN_STRING_LITERAL(QUIC_TOO_MANY_FRAME_GAPS);
+    RETURN_STRING_LITERAL(QUIC_STREAM_SEQUENCER_INVALID_STATE);
     RETURN_STRING_LITERAL(QUIC_LAST_ERROR);
     // Intentionally have no default case, so we'll break the build
     // if we add errors and don't put them here.
diff --git a/net/quic/core/spdy_utils.cc b/net/quic/core/spdy_utils.cc
index 64b781d..33917f4 100644
--- a/net/quic/core/spdy_utils.cc
+++ b/net/quic/core/spdy_utils.cc
@@ -47,6 +47,12 @@
     return false;  // Headers were invalid.
   }
 
+  return ExtractContentLengthFromHeaders(content_length, headers);
+}
+
+// static
+bool SpdyUtils::ExtractContentLengthFromHeaders(int64_t* content_length,
+                                                SpdyHeaderBlock* headers) {
   if (base::ContainsKey(*headers, "content-length")) {
     // Check whether multiple values are consistent.
     base::StringPiece content_length_header = (*headers)["content-length"];
@@ -56,6 +62,7 @@
     for (const string& value : values) {
       int64_t new_value;
       if (!base::StringToInt64(value, &new_value) || new_value < 0) {
+        DLOG(ERROR) << "Content length was either unparseable or negative.";
         return false;
       }
       if (*content_length < 0) {
@@ -63,11 +70,13 @@
         continue;
       }
       if (new_value != *content_length) {
+        DLOG(ERROR) << "Parsed content length " << new_value << " is "
+                    << "inconsistent with previously detected content length "
+                    << *content_length;
         return false;
       }
     }
   }
-
   return true;
 }
 
@@ -130,29 +139,8 @@
     headers->AppendValueOrAddHeader(name, p.second);
   }
 
-  if (base::ContainsKey(*headers, "content-length")) {
-    // Check whether multiple values are consistent.
-    StringPiece content_length_header = (*headers)["content-length"];
-    vector<string> values =
-        base::SplitString(content_length_header, base::StringPiece("\0", 1),
-                          base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
-    for (const string& value : values) {
-      int64_t new_value;
-      if (!base::StringToInt64(value, &new_value) || new_value < 0) {
-        DLOG(ERROR) << "Content length was either unparseable or negative.";
-        return false;
-      }
-      if (*content_length < 0) {
-        *content_length = new_value;
-        continue;
-      }
-      if (new_value != *content_length) {
-        DLOG(ERROR) << "Parsed content length " << new_value << " is "
-                    << "inconsistent with previously detected content length "
-                    << *content_length;
-        return false;
-      }
-    }
+  if (!ExtractContentLengthFromHeaders(content_length, headers)) {
+    return false;
   }
 
   DVLOG(1) << "Successfully parsed headers: " << headers->DebugString();
diff --git a/net/quic/core/spdy_utils.h b/net/quic/core/spdy_utils.h
index 69ef754..d1f14ad 100644
--- a/net/quic/core/spdy_utils.h
+++ b/net/quic/core/spdy_utils.h
@@ -34,6 +34,12 @@
                            int64_t* content_length,
                            SpdyHeaderBlock* headers);
 
+  // Populate |content length| with the value of the content-length header if
+  // one or more are present in the headers. Returns true on success, false if
+  // parsing fails.
+  static bool ExtractContentLengthFromHeaders(int64_t* content_length,
+                                              SpdyHeaderBlock* headers);
+
   // Parses |data| as a std::string containing serialized HTTP/2 HEADERS frame,
   // populating |trailers| with the key->value std:pairs found.
   // The final offset header will be excluded from |trailers|, and instead the
diff --git a/net/quic/core/congestion_control/simulation/README.md b/net/quic/test_tools/simulator/README.md
similarity index 100%
rename from net/quic/core/congestion_control/simulation/README.md
rename to net/quic/test_tools/simulator/README.md
diff --git a/net/quic/core/congestion_control/simulation/actor.cc b/net/quic/test_tools/simulator/actor.cc
similarity index 75%
rename from net/quic/core/congestion_control/simulation/actor.cc
rename to net/quic/test_tools/simulator/actor.cc
index fba9218..0fdf26f 100644
--- a/net/quic/core/congestion_control/simulation/actor.cc
+++ b/net/quic/test_tools/simulator/actor.cc
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "net/quic/core/congestion_control/simulation/actor.h"
-#include "net/quic/core/congestion_control/simulation/simulator.h"
+#include "net/quic/test_tools/simulator/actor.h"
+#include "net/quic/test_tools/simulator/simulator.h"
 
 namespace net {
-namespace simulation {
+namespace simulator {
 
 Actor::Actor(Simulator* simulator, std::string name)
     : simulator_(simulator),
@@ -25,5 +25,5 @@
   simulator_->Unschedule(this);
 }
 
-}  // namespace simulation
+}  // namespace simulator
 }  // namespace net
diff --git a/net/quic/core/congestion_control/simulation/actor.h b/net/quic/test_tools/simulator/actor.h
similarity index 89%
rename from net/quic/core/congestion_control/simulation/actor.h
rename to net/quic/test_tools/simulator/actor.h
index 7c84d6c5..f74b712b 100644
--- a/net/quic/core/congestion_control/simulation/actor.h
+++ b/net/quic/test_tools/simulator/actor.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef NET_QUIC_CORE_CONGESTION_CONTROL_SIMULATION_ACTOR_H_
-#define NET_QUIC_CORE_CONGESTION_CONTROL_SIMULATION_ACTOR_H_
+#ifndef NET_QUIC_TEST_TOOLS_SIMULATOR_ACTOR_H_
+#define NET_QUIC_TEST_TOOLS_SIMULATOR_ACTOR_H_
 
 #include <string>
 
@@ -11,7 +11,7 @@
 #include "net/quic/core/quic_time.h"
 
 namespace net {
-namespace simulation {
+namespace simulator {
 
 class Simulator;
 struct ScheduledActor;
@@ -61,7 +61,7 @@
   DISALLOW_COPY_AND_ASSIGN(Actor);
 };
 
-}  // namespace simulation
+}  // namespace simulator
 }  // namespace net
 
-#endif  // NET_QUIC_CORE_CONGESTION_CONTROL_SIMULATION_ACTOR_H_
+#endif  // NET_QUIC_TEST_TOOLS_SIMULATOR_ACTOR_H_
diff --git a/net/quic/core/congestion_control/simulation/alarm_factory.cc b/net/quic/test_tools/simulator/alarm_factory.cc
similarity index 94%
rename from net/quic/core/congestion_control/simulation/alarm_factory.cc
rename to net/quic/test_tools/simulator/alarm_factory.cc
index 2a2d505f..7c89557 100644
--- a/net/quic/core/congestion_control/simulation/alarm_factory.cc
+++ b/net/quic/test_tools/simulator/alarm_factory.cc
@@ -3,13 +3,13 @@
 // found in the LICENSE file.
 
 #include "base/strings/stringprintf.h"
-#include "net/quic/core/congestion_control/simulation/alarm_factory.h"
 #include "net/quic/core/quic_alarm.h"
+#include "net/quic/test_tools/simulator/alarm_factory.h"
 
 using base::StringPrintf;
 
 namespace net {
-namespace simulation {
+namespace simulator {
 
 // Alarm is an implementation of QuicAlarm which can schedule alarms in the
 // simulation timeline.
@@ -78,5 +78,5 @@
       new Alarm(simulator_, GetNewAlarmName(), std::move(delegate)));
 }
 
-}  // namespace simulation
+}  // namespace simulator
 }  // namespace net
diff --git a/net/quic/core/congestion_control/simulation/alarm_factory.h b/net/quic/test_tools/simulator/alarm_factory.h
similarity index 73%
rename from net/quic/core/congestion_control/simulation/alarm_factory.h
rename to net/quic/test_tools/simulator/alarm_factory.h
index d14b1de..284da2b 100644
--- a/net/quic/core/congestion_control/simulation/alarm_factory.h
+++ b/net/quic/test_tools/simulator/alarm_factory.h
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef NET_QUIC_CORE_CONGESTION_CONTROL_SIMULATION_ALARM_FACTORY_H_
-#define NET_QUIC_CORE_CONGESTION_CONTROL_SIMULATION_ALARM_FACTORY_H_
+#ifndef NET_QUIC_TEST_TOOLS_SIMULATOR_ALARM_FACTORY_H_
+#define NET_QUIC_TEST_TOOLS_SIMULATOR_ALARM_FACTORY_H_
 
-#include "net/quic/core/congestion_control/simulation/actor.h"
 #include "net/quic/core/quic_alarm_factory.h"
+#include "net/quic/test_tools/simulator/actor.h"
 
 namespace net {
-namespace simulation {
+namespace simulator {
 
 // AlarmFactory allows to schedule QuicAlarms using the simulation event queue.
 class AlarmFactory : public QuicAlarmFactory {
@@ -33,7 +33,7 @@
   DISALLOW_COPY_AND_ASSIGN(AlarmFactory);
 };
 
-}  // namespace simulation
+}  // namespace simulator
 }  // namespace net
 
-#endif  // NET_QUIC_CORE_CONGESTION_CONTROL_SIMULATION_ALARM_FACTORY_H_
+#endif  // NET_QUIC_TEST_TOOLS_SIMULATOR_ALARM_FACTORY_H_
diff --git a/net/quic/core/congestion_control/simulation/link.cc b/net/quic/test_tools/simulator/link.cc
similarity index 95%
rename from net/quic/core/congestion_control/simulation/link.cc
rename to net/quic/test_tools/simulator/link.cc
index ae1faf3..bf87f91 100644
--- a/net/quic/core/congestion_control/simulation/link.cc
+++ b/net/quic/test_tools/simulator/link.cc
@@ -3,13 +3,13 @@
 // found in the LICENSE file.
 
 #include "base/strings/stringprintf.h"
-#include "net/quic/core/congestion_control/simulation/link.h"
-#include "net/quic/core/congestion_control/simulation/simulator.h"
+#include "net/quic/test_tools/simulator/link.h"
+#include "net/quic/test_tools/simulator/simulator.h"
 
 using base::StringPrintf;
 
 namespace net {
-namespace simulation {
+namespace simulator {
 
 // Parameters for random noise delay.
 const uint64_t kMaxRandomDelayUs = 10;
@@ -112,5 +112,5 @@
   endpoint_b->SetTxPort(&b_to_a_link_);
 }
 
-}  // namespace simulation
+}  // namespace simulator
 }  // namespace net
diff --git a/net/quic/core/congestion_control/simulation/link.h b/net/quic/test_tools/simulator/link.h
similarity index 88%
rename from net/quic/core/congestion_control/simulation/link.h
rename to net/quic/test_tools/simulator/link.h
index 2d1b685..8df241d 100644
--- a/net/quic/core/congestion_control/simulation/link.h
+++ b/net/quic/test_tools/simulator/link.h
@@ -2,18 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef NET_QUIC_CORE_CONGESTION_CONTROL_SIMULATION_LINK_H_
-#define NET_QUIC_CORE_CONGESTION_CONTROL_SIMULATION_LINK_H_
+#ifndef NET_QUIC_TEST_TOOLS_SIMULATOR_LINK_H_
+#define NET_QUIC_TEST_TOOLS_SIMULATOR_LINK_H_
 
 #include <queue>
 #include <utility>
 
-#include "net/quic/core/congestion_control/simulation/actor.h"
-#include "net/quic/core/congestion_control/simulation/port.h"
 #include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/test_tools/simulator/actor.h"
+#include "net/quic/test_tools/simulator/port.h"
 
 namespace net {
-namespace simulation {
+namespace simulator {
 
 // A reliable simplex link between two endpoints with constrained bandwidth.  A
 // few microseconds of random delay are added for every packet to avoid
@@ -94,7 +94,7 @@
   DISALLOW_COPY_AND_ASSIGN(SymmetricLink);
 };
 
-}  // namespace simulation
+}  // namespace simulator
 }  // namespace net
 
-#endif  // NET_QUIC_CORE_CONGESTION_CONTROL_SIMULATION_LINK_H_
+#endif  // NET_QUIC_TEST_TOOLS_SIMULATOR_LINK_H_
diff --git a/net/quic/core/congestion_control/simulation/port.cc b/net/quic/test_tools/simulator/port.cc
similarity index 80%
rename from net/quic/core/congestion_control/simulation/port.cc
rename to net/quic/test_tools/simulator/port.cc
index 24315b5..11e4eda 100644
--- a/net/quic/core/congestion_control/simulation/port.cc
+++ b/net/quic/test_tools/simulator/port.cc
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "net/quic/core/congestion_control/simulation/port.h"
+#include "net/quic/test_tools/simulator/port.h"
 
 namespace net {
-namespace simulation {
+namespace simulator {
 
 Packet::Packet()
     : source(), destination(), tx_timestamp(QuicTime::Zero()), size(0) {}
@@ -17,5 +17,5 @@
 Endpoint::Endpoint(Simulator* simulator, std::string name)
     : Actor(simulator, name) {}
 
-}  // namespace simulation
+}  // namespace simulator
 }  // namespace net
diff --git a/net/quic/core/congestion_control/simulation/port.h b/net/quic/test_tools/simulator/port.h
similarity index 84%
rename from net/quic/core/congestion_control/simulation/port.h
rename to net/quic/test_tools/simulator/port.h
index 2efaaa0..62c47f2 100644
--- a/net/quic/core/congestion_control/simulation/port.h
+++ b/net/quic/test_tools/simulator/port.h
@@ -2,17 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef NET_QUIC_CORE_CONGESTION_CONTROL_SIMULATION_PORT_H_
-#define NET_QUIC_CORE_CONGESTION_CONTROL_SIMULATION_PORT_H_
+#ifndef NET_QUIC_TEST_TOOLS_SIMULATOR_PORT_H_
+#define NET_QUIC_TEST_TOOLS_SIMULATOR_PORT_H_
 
 #include <string>
 #include <utility>
 
-#include "net/quic/core/congestion_control/simulation/actor.h"
 #include "net/quic/core/quic_protocol.h"
+#include "net/quic/test_tools/simulator/actor.h"
 
 namespace net {
-namespace simulation {
+namespace simulator {
 
 struct Packet {
   Packet();
@@ -60,7 +60,7 @@
   Endpoint(Simulator* simulator, std::string name);
 };
 
-}  // namespace simulation
+}  // namespace simulator
 }  // namespace net
 
-#endif  // NET_QUIC_CORE_CONGESTION_CONTROL_SIMULATION_PORT_H_
+#endif  // NET_QUIC_TEST_TOOLS_SIMULATOR_PORT_H_
diff --git a/net/quic/core/congestion_control/simulation/queue.cc b/net/quic/test_tools/simulator/queue.cc
similarity index 93%
rename from net/quic/core/congestion_control/simulation/queue.cc
rename to net/quic/test_tools/simulator/queue.cc
index 24593e3..0570443 100644
--- a/net/quic/core/congestion_control/simulation/queue.cc
+++ b/net/quic/test_tools/simulator/queue.cc
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "net/quic/core/congestion_control/simulation/queue.h"
+#include "net/quic/test_tools/simulator/queue.h"
 
 namespace net {
-namespace simulation {
+namespace simulator {
 
 Queue::ListenerInterface::~ListenerInterface() {}
 
@@ -60,5 +60,5 @@
   Schedule(clock_->Now() + tx_port_->TimeUntilAvailable());
 }
 
-}  // namespace simulation
+}  // namespace simulator
 }  // namespace net
diff --git a/net/quic/core/congestion_control/simulation/queue.h b/net/quic/test_tools/simulator/queue.h
similarity index 82%
rename from net/quic/core/congestion_control/simulation/queue.h
rename to net/quic/test_tools/simulator/queue.h
index 2902d0ad..b704893 100644
--- a/net/quic/core/congestion_control/simulation/queue.h
+++ b/net/quic/test_tools/simulator/queue.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef NET_QUIC_CORE_CONGESTION_CONTROL_SIMULATION_QUEUE_H_
-#define NET_QUIC_CORE_CONGESTION_CONTROL_SIMULATION_QUEUE_H_
+#ifndef NET_QUIC_TEST_TOOLS_SIMULATOR_QUEUE_H_
+#define NET_QUIC_TEST_TOOLS_SIMULATOR_QUEUE_H_
 
-#include "net/quic/core/congestion_control/simulation/link.h"
+#include "net/quic/test_tools/simulator/link.h"
 
 namespace net {
-namespace simulation {
+namespace simulator {
 
 // A finitely sized queue which egresses packets onto a constrained link.  The
 // capacity of the queue is measured in bytes as opposed to packets.
@@ -53,7 +53,7 @@
   DISALLOW_COPY_AND_ASSIGN(Queue);
 };
 
-}  // namespace simulation
+}  // namespace simulator
 }  // namespace net
 
-#endif  // NET_QUIC_CORE_CONGESTION_CONTROL_SIMULATION_QUEUE_H_
+#endif  // NET_QUIC_TEST_TOOLS_SIMULATOR_QUEUE_H_
diff --git a/net/quic/core/congestion_control/simulation/quic_endpoint.cc b/net/quic/test_tools/simulator/quic_endpoint.cc
similarity index 89%
rename from net/quic/core/congestion_control/simulation/quic_endpoint.cc
rename to net/quic/test_tools/simulator/quic_endpoint.cc
index 9e3dde1..a65b571 100644
--- a/net/quic/core/congestion_control/simulation/quic_endpoint.cc
+++ b/net/quic/test_tools/simulator/quic_endpoint.cc
@@ -2,21 +2,23 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "net/quic/test_tools/simulator/quic_endpoint.h"
+
 #include "base/memory/ptr_util.h"
 #include "base/sha1.h"
 #include "base/strings/stringprintf.h"
-#include "net/quic/core/congestion_control/simulation/quic_endpoint.h"
-#include "net/quic/core/congestion_control/simulation/simulator.h"
 #include "net/quic/core/crypto/crypto_handshake_message.h"
 #include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/test_tools/simulator/simulator.h"
 
 using base::StringPrintf;
 
 namespace net {
-namespace simulation {
+namespace simulator {
 
 const QuicStreamId kDataStream = 3;
 const QuicByteCount kWriteChunkSize = 128 * 1024;
+const char kStreamDataContents = 'Q';
 
 // Takes a SHA-1 hash of the name and converts it into five 32-bit integers.
 static std::vector<uint32_t> HashNameIntoFive32BitIntegers(std::string name) {
@@ -72,8 +74,11 @@
                   CurrentSupportedVersions()),
       bytes_to_transfer_(0),
       bytes_transferred_(0),
+      write_blocked_count_(0),
       wrong_data_received_(false),
       transmission_buffer_(new char[kWriteChunkSize]) {
+  nic_tx_queue_.set_listener_interface(this);
+
   connection_.SetSelfAddress(GetAddressFromName(name));
   connection_.set_visitor(this);
   connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE, new NullEncrypter());
@@ -127,11 +132,6 @@
   nic_tx_queue_.set_tx_port(port);
 }
 
-// Return the data that |kDataStream| is supposed to have at offset |offset|.
-inline static uint8_t DataAtOffset(QuicStreamOffset offset) {
-  return offset % 256;
-}
-
 void QuicEndpoint::OnPacketDequeued() {
   if (writer_.IsWriteBlocked() &&
       (nic_tx_queue_.capacity() - nic_tx_queue_.bytes_queued()) >=
@@ -145,8 +145,7 @@
   // Verify that the data received always matches the output of DataAtOffset().
   DCHECK(frame.stream_id == kDataStream);
   for (size_t i = 0; i < frame.data_length; i++) {
-    const QuicStreamOffset absolute_offset = frame.offset + i;
-    if (frame.data_buffer[i] != DataAtOffset(absolute_offset)) {
+    if (frame.data_buffer[i] != kStreamDataContents) {
       wrong_data_received_ = true;
     }
   }
@@ -165,7 +164,7 @@
 }
 
 QuicEndpoint::Writer::Writer(QuicEndpoint* endpoint)
-    : QuicDefaultPacketWriter(0), endpoint_(endpoint) {}
+    : endpoint_(endpoint), is_blocked_(false) {}
 
 QuicEndpoint::Writer::~Writer() {}
 
@@ -178,13 +177,11 @@
   DCHECK(options == nullptr);
   DCHECK(buf_len <= kMaxPacketSize);
 
-  DCHECK(self_address == GetAddressFromName(endpoint_->name()).address());
-  DCHECK(peer_address == GetAddressFromName(endpoint_->peer_name_));
-
   // Instead of losing a packet, become write-blocked when the egress queue is
   // full.
   if (endpoint_->nic_tx_queue_.packets_queued() > kTxQueueSize) {
-    set_write_blocked(true);
+    is_blocked_ = true;
+    endpoint_->write_blocked_count_++;
     return WriteResult(WRITE_STATUS_BLOCKED, 0);
   }
 
@@ -201,6 +198,20 @@
   return WriteResult(WRITE_STATUS_OK, buf_len);
 }
 
+bool QuicEndpoint::Writer::IsWriteBlockedDataBuffered() const {
+  return false;
+}
+bool QuicEndpoint::Writer::IsWriteBlocked() const {
+  return is_blocked_;
+}
+void QuicEndpoint::Writer::SetWritable() {
+  is_blocked_ = false;
+}
+QuicByteCount QuicEndpoint::Writer::GetMaxPacketSize(
+    const IPEndPoint& /*peer_address*/) const {
+  return kMaxPacketSize;
+}
+
 void QuicEndpoint::WriteStreamData() {
   // Instantiate a bundler which would normally be here due to QuicSession.
   QuicConnection::ScopedPacketBundler packet_bundler(&connection_,
@@ -210,10 +221,7 @@
     // Transfer data in chunks of size at most |kWriteChunkSize|.
     const size_t transmission_size =
         std::min(kWriteChunkSize, bytes_to_transfer_);
-    for (size_t i = 0; i < transmission_size; i++) {
-      const QuicStreamOffset offset = bytes_transferred_ + i;
-      transmission_buffer_[i] = DataAtOffset(offset);
-    }
+    memset(transmission_buffer_.get(), kStreamDataContents, transmission_size);
 
     iovec iov;
     iov.iov_base = transmission_buffer_.get();
@@ -260,5 +268,5 @@
   }
 }
 
-}  // namespace simulation
+}  // namespace simulator
 }  // namespace net
diff --git a/net/quic/core/congestion_control/simulation/quic_endpoint.h b/net/quic/test_tools/simulator/quic_endpoint.h
similarity index 87%
rename from net/quic/core/congestion_control/simulation/quic_endpoint.h
rename to net/quic/test_tools/simulator/quic_endpoint.h
index d12e11ea..d6a64d7 100644
--- a/net/quic/core/congestion_control/simulation/quic_endpoint.h
+++ b/net/quic/test_tools/simulator/quic_endpoint.h
@@ -2,19 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef NET_QUIC_CORE_CONGESTION_CONTROL_SIMULATION_QUIC_ENDPOINT_H_
-#define NET_QUIC_CORE_CONGESTION_CONTROL_SIMULATION_QUIC_ENDPOINT_H_
+#ifndef NET_QUIC_TEST_TOOLS_SIMULATOR_QUIC_ENDPOINT_H_
+#define NET_QUIC_TEST_TOOLS_SIMULATOR_QUIC_ENDPOINT_H_
 
-#include "net/quic/core/congestion_control/simulation/link.h"
-#include "net/quic/core/congestion_control/simulation/queue.h"
 #include "net/quic/core/crypto/null_decrypter.h"
 #include "net/quic/core/crypto/null_encrypter.h"
 #include "net/quic/core/quic_connection.h"
 #include "net/quic/core/quic_protocol.h"
+#include "net/quic/test_tools/simulator/link.h"
+#include "net/quic/test_tools/simulator/queue.h"
 #include "net/tools/quic/quic_default_packet_writer.h"
 
 namespace net {
-namespace simulation {
+namespace simulator {
 
 // Size of the TX queue used by the kernel/NIC.  1000 is the Linux
 // kernel default.
@@ -47,6 +47,7 @@
   inline QuicByteCount bytes_received() {
     return connection_.GetStats().stream_bytes_received;
   }
+  inline size_t write_blocked_count() { return write_blocked_count_; }
   inline bool wrong_data_received() const { return wrong_data_received_; }
 
   // Send |bytes| bytes.  Initiates the transfer if one is not already in
@@ -92,7 +93,7 @@
 
  private:
   // A Writer object that writes into the |nic_tx_queue_|.
-  class Writer : public QuicDefaultPacketWriter {
+  class Writer : public QuicPacketWriter {
    public:
     explicit Writer(QuicEndpoint* endpoint);
     ~Writer() override;
@@ -102,9 +103,16 @@
                             const IPAddress& self_address,
                             const IPEndPoint& peer_address,
                             PerPacketOptions* options) override;
+    bool IsWriteBlockedDataBuffered() const override;
+    bool IsWriteBlocked() const override;
+    void SetWritable() override;
+    QuicByteCount GetMaxPacketSize(
+        const IPEndPoint& peer_address) const override;
 
    private:
     QuicEndpoint* endpoint_;
+
+    bool is_blocked_;
   };
 
   // Write stream data until |bytes_to_transfer_| is zero or the connection is
@@ -123,6 +131,9 @@
   QuicByteCount bytes_to_transfer_;
   QuicByteCount bytes_transferred_;
 
+  // Counts the number of times the writer became write-blocked.
+  size_t write_blocked_count_;
+
   // Set to true if the endpoint receives stream data different from what it
   // expects.
   bool wrong_data_received_;
@@ -152,7 +163,7 @@
   std::unordered_map<std::string, QuicEndpoint*> mapping_;
 };
 
-}  // namespace simulation
+}  // namespace simulator
 }  // namespace net
 
-#endif  // NET_QUIC_CORE_CONGESTION_CONTROL_SIMULATION_QUIC_ENDPOINT_H_
+#endif  // NET_QUIC_TEST_TOOLS_SIMULATOR_QUIC_ENDPOINT_H_
diff --git a/net/quic/core/congestion_control/simulation/quic_endpoint_test.cc b/net/quic/test_tools/simulator/quic_endpoint_test.cc
similarity index 69%
rename from net/quic/core/congestion_control/simulation/quic_endpoint_test.cc
rename to net/quic/test_tools/simulator/quic_endpoint_test.cc
index 951c6c87..f470410 100644
--- a/net/quic/core/congestion_control/simulation/quic_endpoint_test.cc
+++ b/net/quic/test_tools/simulator/quic_endpoint_test.cc
@@ -2,16 +2,23 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "net/quic/test_tools/simulator/quic_endpoint.h"
+
 #include "base/memory/ptr_util.h"
-#include "net/quic/core/congestion_control/simulation/quic_endpoint.h"
-#include "net/quic/core/congestion_control/simulation/simulator.h"
-#include "net/quic/core/congestion_control/simulation/switch.h"
+#include "net/quic/test_tools/quic_connection_peer.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/quic/test_tools/simulator/simulator.h"
+#include "net/quic/test_tools/simulator/switch.h"
 
 #include "net/test/gtest_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using ::testing::_;
+using ::testing::NiceMock;
+using ::testing::Return;
+
 namespace net {
-namespace simulation {
+namespace simulator {
 
 const QuicBandwidth kDefaultBandwidth =
     QuicBandwidth::FromKBitsPerSecond(10 * 1000);
@@ -37,7 +44,7 @@
 };
 
 // Test transmission from one host to another.
-TEST_F(QuicEndpointTest, DISABLED_OneWayTransmission) {
+TEST_F(QuicEndpointTest, OneWayTransmission) {
   QuicEndpoint endpoint_a(&simulator_, "Endpoint A", "Endpoint B",
                           Perspective::IS_CLIENT, 42);
   QuicEndpoint endpoint_b(&simulator_, "Endpoint B", "Endpoint A",
@@ -66,13 +73,54 @@
   const QuicByteCount total_bytes_transferred = 600 + 2 * 1024 * 1024;
   EXPECT_EQ(total_bytes_transferred, endpoint_a.bytes_transferred());
   EXPECT_EQ(total_bytes_transferred, endpoint_b.bytes_received());
+  EXPECT_EQ(0u, endpoint_a.write_blocked_count());
+  EXPECT_FALSE(endpoint_a.wrong_data_received());
+  EXPECT_FALSE(endpoint_b.wrong_data_received());
+}
+
+// Test the situation in which the writer becomes write-blocked.
+TEST_F(QuicEndpointTest, WriteBlocked) {
+  QuicEndpoint endpoint_a(&simulator_, "Endpoint A", "Endpoint B",
+                          Perspective::IS_CLIENT, 42);
+  QuicEndpoint endpoint_b(&simulator_, "Endpoint B", "Endpoint A",
+                          Perspective::IS_SERVER, 42);
+  auto link_a = Link(&endpoint_a, switch_.port(1));
+  auto link_b = Link(&endpoint_b, switch_.port(2));
+
+  // Will be owned by the sent packet manager.
+  auto* sender = new NiceMock<test::MockSendAlgorithm>();
+  EXPECT_CALL(*sender, TimeUntilSend(_, _))
+      .WillRepeatedly(Return(QuicTime::Delta::Zero()));
+  EXPECT_CALL(*sender, PacingRate(_))
+      .WillRepeatedly(Return(10 * kDefaultBandwidth));
+  EXPECT_CALL(*sender, BandwidthEstimate())
+      .WillRepeatedly(Return(10 * kDefaultBandwidth));
+  EXPECT_CALL(*sender, GetCongestionWindow())
+      .WillRepeatedly(
+          Return(kMaxPacketSize * kDefaultMaxCongestionWindowPackets));
+  test::QuicConnectionPeer::SetSendAlgorithm(endpoint_a.connection(),
+                                             kDefaultPathId, sender);
+
+  // First transmit a small, packet-size chunk of data.
+  QuicByteCount bytes_to_transfer = 3 * 1024 * 1024;
+  endpoint_a.AddBytesToTransfer(bytes_to_transfer);
+  QuicTime end_time =
+      simulator_.GetClock()->Now() + QuicTime::Delta::FromSeconds(30);
+  simulator_.RunUntil([this, &endpoint_b, bytes_to_transfer, end_time]() {
+    return endpoint_b.bytes_received() == bytes_to_transfer ||
+           simulator_.GetClock()->Now() >= end_time;
+  });
+
+  EXPECT_EQ(bytes_to_transfer, endpoint_a.bytes_transferred());
+  EXPECT_EQ(bytes_to_transfer, endpoint_b.bytes_received());
+  EXPECT_GT(endpoint_a.write_blocked_count(), 0u);
   EXPECT_FALSE(endpoint_a.wrong_data_received());
   EXPECT_FALSE(endpoint_b.wrong_data_received());
 }
 
 // Test transmission of 1 MiB of data between two hosts simultaneously in both
 // directions.
-TEST_F(QuicEndpointTest, DISABLED_TwoWayTransmission) {
+TEST_F(QuicEndpointTest, TwoWayTransmission) {
   QuicEndpoint endpoint_a(&simulator_, "Endpoint A", "Endpoint B",
                           Perspective::IS_CLIENT, 42);
   QuicEndpoint endpoint_b(&simulator_, "Endpoint B", "Endpoint A",
@@ -96,7 +144,7 @@
 }
 
 // Simulate three hosts trying to send data to a fourth one simultaneously.
-TEST_F(QuicEndpointTest, DISABLED_Competition) {
+TEST_F(QuicEndpointTest, Competition) {
   auto endpoint_a = base::MakeUnique<QuicEndpoint>(
       &simulator_, "Endpoint A", "Endpoint D (A)", Perspective::IS_CLIENT, 42);
   auto endpoint_b = base::MakeUnique<QuicEndpoint>(
@@ -138,5 +186,5 @@
   }
 }
 
-}  // namespace simulation
+}  // namespace simulator
 }  // namespace net
diff --git a/net/quic/core/congestion_control/simulation/simulator.cc b/net/quic/test_tools/simulator/simulator.cc
similarity index 96%
rename from net/quic/core/congestion_control/simulation/simulator.cc
rename to net/quic/test_tools/simulator/simulator.cc
index 7b4ae51..7885791 100644
--- a/net/quic/core/congestion_control/simulation/simulator.cc
+++ b/net/quic/test_tools/simulator/simulator.cc
@@ -3,11 +3,11 @@
 // found in the LICENSE file.
 
 #include "base/memory/ptr_util.h"
-#include "net/quic/core/congestion_control/simulation/simulator.h"
 #include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/test_tools/simulator/simulator.h"
 
 namespace net {
-namespace simulation {
+namespace simulator {
 
 Simulator::Simulator()
     : random_generator_(nullptr),
@@ -114,5 +114,5 @@
   actor->Act();
 }
 
-}  // namespace simulation
+}  // namespace simulator
 }  // namespace net
diff --git a/net/quic/core/congestion_control/simulation/simulator.h b/net/quic/test_tools/simulator/simulator.h
similarity index 89%
rename from net/quic/core/congestion_control/simulation/simulator.h
rename to net/quic/test_tools/simulator/simulator.h
index 9191d0bd..b09692b 100644
--- a/net/quic/core/congestion_control/simulation/simulator.h
+++ b/net/quic/test_tools/simulator/simulator.h
@@ -2,21 +2,21 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef NET_QUIC_CORE_CONGESTION_CONTROL_SIMULATION_SIMULATOR_H_
-#define NET_QUIC_CORE_CONGESTION_CONTROL_SIMULATION_SIMULATOR_H_
+#ifndef NET_QUIC_TEST_TOOLS_SIMULATOR_SIMULATOR_H_
+#define NET_QUIC_TEST_TOOLS_SIMULATOR_SIMULATOR_H_
 
 #include <map>
 #include <unordered_map>
 #include <unordered_set>
 
-#include "net/quic/core/congestion_control/simulation/actor.h"
-#include "net/quic/core/congestion_control/simulation/alarm_factory.h"
 #include "net/quic/core/quic_bug_tracker.h"
 #include "net/quic/core/quic_connection.h"
 #include "net/quic/core/quic_simple_buffer_allocator.h"
+#include "net/quic/test_tools/simulator/actor.h"
+#include "net/quic/test_tools/simulator/alarm_factory.h"
 
 namespace net {
-namespace simulation {
+namespace simulator {
 
 // Simulator is responsible for scheduling actors in the simulation and
 // providing basic utility interfaces (clock, alarms, RNG and others).
@@ -106,7 +106,7 @@
   return false;
 }
 
-}  // namespace simulation
+}  // namespace simulator
 }  // namespace net
 
-#endif  // NET_QUIC_CORE_CONGESTION_CONTROL_SIMULATION_SIMULATOR_H_
+#endif  // NET_QUIC_TEST_TOOLS_SIMULATOR_SIMULATOR_H_
diff --git a/net/quic/core/congestion_control/simulation/simulator_test.cc b/net/quic/test_tools/simulator/simulator_test.cc
similarity index 97%
rename from net/quic/core/congestion_control/simulation/simulator_test.cc
rename to net/quic/test_tools/simulator/simulator_test.cc
index c952a12..cee8a8e 100644
--- a/net/quic/core/congestion_control/simulation/simulator_test.cc
+++ b/net/quic/test_tools/simulator/simulator_test.cc
@@ -2,19 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "net/quic/test_tools/simulator/simulator.h"
+
 #include "base/memory/ptr_util.h"
-#include "net/quic/core/congestion_control/simulation/alarm_factory.h"
-#include "net/quic/core/congestion_control/simulation/link.h"
-#include "net/quic/core/congestion_control/simulation/queue.h"
-#include "net/quic/core/congestion_control/simulation/simulator.h"
-#include "net/quic/core/congestion_control/simulation/switch.h"
 #include "net/quic/test_tools/quic_test_utils.h"
+#include "net/quic/test_tools/simulator/alarm_factory.h"
+#include "net/quic/test_tools/simulator/link.h"
+#include "net/quic/test_tools/simulator/queue.h"
+#include "net/quic/test_tools/simulator/switch.h"
 
 #include "net/test/gtest_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace net {
-namespace simulation {
+namespace simulator {
 
 // A simple counter that increments its value by 1 every specified period.
 class Counter : public Actor {
@@ -209,7 +210,7 @@
   const QuicTime end_time = simulator.GetClock()->Now();
   const QuicBandwidth observed_bandwidth = QuicBandwidth::FromBytesAndTimeDelta(
       saturator_a.bytes_transmitted(), end_time - start_time);
-  test::ExpectApproxEq(link.bandwidth(), observed_bandwidth, 0.01);
+  test::ExpectApproxEq(link.bandwidth(), observed_bandwidth, 0.01f);
 }
 
 // Accepts packets and stores them internally.
@@ -526,5 +527,5 @@
   EXPECT_EQ(0u, alarm_counter);
 }
 
-}  // namespace simulation
+}  // namespace simulator
 }  // namespace net
diff --git a/net/quic/core/congestion_control/simulation/switch.cc b/net/quic/test_tools/simulator/switch.cc
similarity index 95%
rename from net/quic/core/congestion_control/simulation/switch.cc
rename to net/quic/test_tools/simulator/switch.cc
index 76d2dbd..6490274 100644
--- a/net/quic/core/congestion_control/simulation/switch.cc
+++ b/net/quic/test_tools/simulator/switch.cc
@@ -6,12 +6,12 @@
 
 #include "base/memory/ptr_util.h"
 #include "base/strings/stringprintf.h"
-#include "net/quic/core/congestion_control/simulation/switch.h"
+#include "net/quic/test_tools/simulator/switch.h"
 
 using base::StringPrintf;
 
 namespace net {
-namespace simulation {
+namespace simulator {
 
 Switch::Switch(Simulator* simulator,
                std::string name,
@@ -83,5 +83,5 @@
   }
 }
 
-}  // namespace simulation
+}  // namespace simulator
 }  // namespace net
diff --git a/net/quic/core/congestion_control/simulation/switch.h b/net/quic/test_tools/simulator/switch.h
similarity index 86%
rename from net/quic/core/congestion_control/simulation/switch.h
rename to net/quic/test_tools/simulator/switch.h
index 5d8cb55..29d42dc 100644
--- a/net/quic/core/congestion_control/simulation/switch.h
+++ b/net/quic/test_tools/simulator/switch.h
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef NET_QUIC_CORE_CONGESTION_CONTROL_SIMULATION_SWITCH_H_
-#define NET_QUIC_CORE_CONGESTION_CONTROL_SIMULATION_SWITCH_H_
+#ifndef NET_QUIC_TEST_TOOLS_SIMULATOR_SWITCH_H_
+#define NET_QUIC_TEST_TOOLS_SIMULATOR_SWITCH_H_
 
 #include <unordered_map>
 
-#include "net/quic/core/congestion_control/simulation/queue.h"
+#include "net/quic/test_tools/simulator/queue.h"
 
 namespace net {
-namespace simulation {
+namespace simulator {
 
 typedef size_t SwitchPortNumber;
 
@@ -75,7 +75,7 @@
   DISALLOW_COPY_AND_ASSIGN(Switch);
 };
 
-}  // namespace simulation
+}  // namespace simulator
 }  // namespace net
 
-#endif  // NET_QUIC_CORE_CONGESTION_CONTROL_SIMULATION_SWITCH_H_
+#endif  // NET_QUIC_TEST_TOOLS_SIMULATOR_SWITCH_H_
diff --git a/net/tools/quic/quic_client.cc b/net/tools/quic/quic_client.cc
index 9a071030..b65da60 100644
--- a/net/tools/quic/quic_client.cc
+++ b/net/tools/quic/quic_client.cc
@@ -70,7 +70,6 @@
           new QuicEpollAlarmFactory(epoll_server),
           std::move(proof_verifier)),
       epoll_server_(epoll_server),
-      initialized_(false),
       packets_dropped_(0),
       overflow_supported_(false),
       packet_reader_(new QuicPacketReader()) {
@@ -87,39 +86,9 @@
   CleanUpAllUDPSockets();
 }
 
-bool QuicClient::Initialize() {
-  QuicClientBase::Initialize();
-
-  set_num_sent_client_hellos(0);
-  set_num_stateless_rejects_received(0);
-  set_connection_error(QUIC_NO_ERROR);
-
-  // If an initial flow control window has not explicitly been set, then use the
-  // same values that Chrome uses.
-  const uint32_t kSessionMaxRecvWindowSize = 15 * 1024 * 1024;  // 15 MB
-  const uint32_t kStreamMaxRecvWindowSize = 6 * 1024 * 1024;    //  6 MB
-  if (config()->GetInitialStreamFlowControlWindowToSend() ==
-      kMinimumFlowControlSendWindow) {
-    config()->SetInitialStreamFlowControlWindowToSend(kStreamMaxRecvWindowSize);
-  }
-  if (config()->GetInitialSessionFlowControlWindowToSend() ==
-      kMinimumFlowControlSendWindow) {
-    config()->SetInitialSessionFlowControlWindowToSend(
-        kSessionMaxRecvWindowSize);
-  }
-
+bool QuicClient::CreateUDPSocketAndBind() {
   epoll_server_->set_timeout_in_us(50 * 1000);
 
-  if (!CreateUDPSocketAndBind()) {
-    return false;
-  }
-
-  epoll_server_->RegisterFD(GetLatestFD(), this, kEpollFlags);
-  initialized_ = true;
-  return true;
-}
-
-bool QuicClient::CreateUDPSocketAndBind() {
   int fd =
       QuicSocketUtils::CreateUDPSocket(server_address(), &overflow_supported_);
   if (fd < 0) {
@@ -155,85 +124,10 @@
 
   fd_address_map_[fd] = client_address;
 
+  epoll_server_->RegisterFD(fd, this, kEpollFlags);
   return true;
 }
 
-bool QuicClient::Connect() {
-  // Attempt multiple connects until the maximum number of client hellos have
-  // been sent.
-  while (!connected() &&
-         GetNumSentClientHellos() <= QuicCryptoClientStream::kMaxClientHellos) {
-    StartConnect();
-    while (EncryptionBeingEstablished()) {
-      WaitForEvents();
-    }
-    if (FLAGS_enable_quic_stateless_reject_support && connected()) {
-      // Resend any previously queued data.
-      ResendSavedData();
-    }
-    if (session() != nullptr &&
-        session()->error() != QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
-      // We've successfully created a session but we're not connected, and there
-      // is no stateless reject to recover from.  Give up trying.
-      break;
-    }
-  }
-  if (!connected() &&
-      GetNumSentClientHellos() > QuicCryptoClientStream::kMaxClientHellos &&
-      session() != nullptr &&
-      session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
-    // The overall connection failed due too many stateless rejects.
-    set_connection_error(QUIC_CRYPTO_TOO_MANY_REJECTS);
-  }
-  return session()->connection()->connected();
-}
-
-void QuicClient::StartConnect() {
-  DCHECK(initialized_);
-  DCHECK(!connected());
-
-  QuicPacketWriter* writer = CreateQuicPacketWriter();
-
-  if (connected_or_attempting_connect()) {
-    // If the last error was not a stateless reject, then the queued up data
-    // does not need to be resent.
-    if (session()->error() != QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
-      ClearDataToResend();
-    }
-    // Before we destroy the last session and create a new one, gather its stats
-    // and update the stats for the overall connection.
-    UpdateStats();
-  }
-
-  CreateQuicClientSession(new QuicConnection(
-      GetNextConnectionId(), server_address(), helper(), alarm_factory(),
-      writer,
-      /* owns_writer= */ false, Perspective::IS_CLIENT, supported_versions()));
-
-  // Reset |writer()| after |session()| so that the old writer outlives the old
-  // session.
-  set_writer(writer);
-  session()->Initialize();
-  session()->CryptoConnect();
-  set_connected_or_attempting_connect(true);
-}
-
-void QuicClient::Disconnect() {
-  DCHECK(initialized_);
-
-  if (connected()) {
-    session()->connection()->CloseConnection(
-        QUIC_PEER_GOING_AWAY, "Client disconnecting",
-        ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
-  }
-
-  ClearDataToResend();
-
-  CleanUpAllUDPSockets();
-
-  initialized_ = false;
-}
-
 void QuicClient::CleanUpUDPSocket(int fd) {
   CleanUpUDPSocketImpl(fd);
   fd_address_map_.erase(fd);
@@ -254,52 +148,6 @@
   }
 }
 
-void QuicClient::SendRequest(const SpdyHeaderBlock& headers,
-                             StringPiece body,
-                             bool fin) {
-  QuicClientPushPromiseIndex::TryHandle* handle;
-  QuicAsyncStatus rv = push_promise_index()->Try(headers, this, &handle);
-  if (rv == QUIC_SUCCESS)
-    return;
-
-  if (rv == QUIC_PENDING) {
-    // May need to retry request if asynchronous rendezvous fails.
-    AddPromiseDataToResend(headers, body, fin);
-    return;
-  }
-
-  QuicSpdyClientStream* stream = CreateReliableClientStream();
-  if (stream == nullptr) {
-    QUIC_BUG << "stream creation failed!";
-    return;
-  }
-  stream->SendRequest(headers.Clone(), body, fin);
-  // Record this in case we need to resend.
-  MaybeAddDataToResend(headers, body, fin);
-}
-
-void QuicClient::SendRequestAndWaitForResponse(const SpdyHeaderBlock& headers,
-                                               StringPiece body,
-                                               bool fin) {
-  SendRequest(headers, body, fin);
-  while (WaitForEvents()) {
-  }
-}
-
-void QuicClient::SendRequestsAndWaitForResponse(
-    const vector<string>& url_list) {
-  for (size_t i = 0; i < url_list.size(); ++i) {
-    SpdyHeaderBlock headers;
-    if (!SpdyUtils::PopulateHeaderBlockFromUrl(url_list[i], &headers)) {
-      QUIC_BUG << "Unable to create request";
-      continue;
-    }
-    SendRequest(headers, "", true);
-  }
-  while (WaitForEvents()) {
-  }
-}
-
 bool QuicClient::WaitForEvents() {
   DCHECK(connected());
 
@@ -330,7 +178,6 @@
     return false;
   }
 
-  epoll_server_->RegisterFD(GetLatestFD(), this, kEpollFlags);
   session()->connection()->SetSelfAddress(GetLatestClientAddress());
 
   QuicPacketWriter* writer = CreateQuicPacketWriter();
@@ -384,7 +231,7 @@
 void QuicClient::ProcessPacket(const IPEndPoint& self_address,
                                const IPEndPoint& peer_address,
                                const QuicReceivedPacket& packet) {
-  session()->connection()->ProcessUdpPacket(self_address, peer_address, packet);
+  session()->ProcessUdpPacket(self_address, peer_address, packet);
 }
 
 }  // namespace net
diff --git a/net/tools/quic/quic_client.h b/net/tools/quic/quic_client.h
index 6b88007..f85beaa 100644
--- a/net/tools/quic/quic_client.h
+++ b/net/tools/quic/quic_client.h
@@ -57,35 +57,8 @@
   ~QuicClient() override;
 
   // From QuicClientBase
-  bool Initialize() override;
   bool WaitForEvents() override;
 
-  // "Connect" to the QUIC server, including performing synchronous crypto
-  // handshake.
-  bool Connect();
-
-  // Start the crypto handshake.  This can be done in place of the synchronous
-  // Connect(), but callers are responsible for making sure the crypto handshake
-  // completes.
-  void StartConnect();
-
-  // Disconnects from the QUIC server.
-  void Disconnect();
-
-  // Sends an HTTP request and does not wait for response before returning.
-  void SendRequest(const SpdyHeaderBlock& headers,
-                   base::StringPiece body,
-                   bool fin) override;
-
-  // Sends an HTTP request and waits for response before returning.
-  void SendRequestAndWaitForResponse(const SpdyHeaderBlock& headers,
-                                     base::StringPiece body,
-                                     bool fin);
-
-  // Sends a request simple GET for each URL in |url_list|, and then waits for
-  // each to complete.
-  void SendRequestsAndWaitForResponse(const std::vector<std::string>& url_list);
-
   // Migrate to a new socket during an active connection.
   bool MigrateSocket(const IPAddress& new_host);
 
@@ -107,22 +80,21 @@
   // Otherwise, return -1.
   int GetLatestFD() const;
 
- protected:
   // Implements ProcessPacketInterface. This will be called for each received
   // packet.
   void ProcessPacket(const IPEndPoint& self_address,
                      const IPEndPoint& peer_address,
                      const QuicReceivedPacket& packet) override;
 
-  virtual QuicPacketWriter* CreateQuicPacketWriter();
+ protected:
+  QuicPacketWriter* CreateQuicPacketWriter() override;
+  bool CreateUDPSocketAndBind() override;
+  void CleanUpAllUDPSockets() override;
 
   // If |fd| is an open UDP socket, unregister and close it. Otherwise, do
   // nothing.
   virtual void CleanUpUDPSocket(int fd);
 
-  // Unregister and close all open UDP sockets.
-  virtual void CleanUpAllUDPSockets();
-
   EpollServer* epoll_server() { return epoll_server_; }
 
   const linked_hash_map<int, IPEndPoint>& fd_address_map() const {
@@ -132,10 +104,6 @@
  private:
   friend class net::test::QuicClientPeer;
 
-  // Used during initialization: creates the UDP socket FD, sets socket options,
-  // and binds the socket to our address.
-  bool CreateUDPSocketAndBind();
-
   // Actually clean up |fd|.
   void CleanUpUDPSocketImpl(int fd);
 
@@ -146,9 +114,6 @@
   // map, the order of socket creation can be recorded.
   linked_hash_map<int, IPEndPoint> fd_address_map_;
 
-  // Tracks if the client is initialized to connect.
-  bool initialized_;
-
   // If overflow_supported_ is true, this will be the number of packets dropped
   // during the lifetime of the server.
   QuicPacketCount packets_dropped_;
@@ -159,9 +124,6 @@
 
   // Point to a QuicPacketReader object on the heap. The reader allocates more
   // space than allowed on the stack.
-  //
-  // TODO(rtenneti): Chromium code doesn't use |packet_reader_|. Add support for
-  // QuicPacketReader
   std::unique_ptr<QuicPacketReader> packet_reader_;
 
   DISALLOW_COPY_AND_ASSIGN(QuicClient);
diff --git a/net/tools/quic/quic_client_base.cc b/net/tools/quic/quic_client_base.cc
index 23a09b4..356734e 100644
--- a/net/tools/quic/quic_client_base.cc
+++ b/net/tools/quic/quic_client_base.cc
@@ -7,10 +7,12 @@
 #include "base/strings/string_number_conversions.h"
 #include "net/quic/core/crypto/quic_random.h"
 #include "net/quic/core/quic_server_id.h"
+#include "net/quic/core/spdy_utils.h"
 
 using base::StringPiece;
 using base::StringToInt;
 using std::string;
+using std::vector;
 
 namespace net {
 
@@ -34,6 +36,7 @@
                                QuicAlarmFactory* alarm_factory,
                                std::unique_ptr<ProofVerifier> proof_verifier)
     : server_id_(server_id),
+      initialized_(false),
       local_port_(0),
       config_(config),
       crypto_config_(std::move(proof_verifier)),
@@ -69,6 +72,7 @@
       LOG(ERROR) << "Invalid response headers";
     }
     latest_response_headers_ = response_headers.DebugString();
+    latest_response_header_block_ = response_headers.Clone();
     latest_response_body_ = client_stream->data();
     latest_response_trailers_ =
         client_stream->received_trailers().DebugString();
@@ -80,9 +84,105 @@
   num_stateless_rejects_received_ = 0;
   connection_error_ = QUIC_NO_ERROR;
   connected_or_attempting_connect_ = false;
+
+  // If an initial flow control window has not explicitly been set, then use the
+  // same values that Chrome uses.
+  const uint32_t kSessionMaxRecvWindowSize = 15 * 1024 * 1024;  // 15 MB
+  const uint32_t kStreamMaxRecvWindowSize = 6 * 1024 * 1024;    //  6 MB
+  if (config()->GetInitialStreamFlowControlWindowToSend() ==
+      kMinimumFlowControlSendWindow) {
+    config()->SetInitialStreamFlowControlWindowToSend(kStreamMaxRecvWindowSize);
+  }
+  if (config()->GetInitialSessionFlowControlWindowToSend() ==
+      kMinimumFlowControlSendWindow) {
+    config()->SetInitialSessionFlowControlWindowToSend(
+        kSessionMaxRecvWindowSize);
+  }
+
+  if (!CreateUDPSocketAndBind()) {
+    return false;
+  }
+
+  initialized_ = true;
   return true;
 }
 
+bool QuicClientBase::Connect() {
+  // Attempt multiple connects until the maximum number of client hellos have
+  // been sent.
+  while (!connected() &&
+         GetNumSentClientHellos() <= QuicCryptoClientStream::kMaxClientHellos) {
+    StartConnect();
+    while (EncryptionBeingEstablished()) {
+      WaitForEvents();
+    }
+    if (FLAGS_enable_quic_stateless_reject_support && connected()) {
+      // Resend any previously queued data.
+      ResendSavedData();
+    }
+    if (session() != nullptr &&
+        session()->error() != QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
+      // We've successfully created a session but we're not connected, and there
+      // is no stateless reject to recover from.  Give up trying.
+      break;
+    }
+  }
+  if (!connected() &&
+      GetNumSentClientHellos() > QuicCryptoClientStream::kMaxClientHellos &&
+      session() != nullptr &&
+      session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
+    // The overall connection failed due too many stateless rejects.
+    set_connection_error(QUIC_CRYPTO_TOO_MANY_REJECTS);
+  }
+  return session()->connection()->connected();
+}
+
+void QuicClientBase::StartConnect() {
+  DCHECK(initialized_);
+  DCHECK(!connected());
+
+  QuicPacketWriter* writer = CreateQuicPacketWriter();
+
+  if (connected_or_attempting_connect()) {
+    // If the last error was not a stateless reject, then the queued up data
+    // does not need to be resent.
+    if (session()->error() != QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
+      ClearDataToResend();
+    }
+    // Before we destroy the last session and create a new one, gather its stats
+    // and update the stats for the overall connection.
+    UpdateStats();
+  }
+
+  CreateQuicClientSession(new QuicConnection(
+      GetNextConnectionId(), server_address(), helper(), alarm_factory(),
+      writer,
+      /* owns_writer= */ false, Perspective::IS_CLIENT, supported_versions()));
+
+  // Reset |writer()| after |session()| so that the old writer outlives the old
+  // session.
+  set_writer(writer);
+  session()->Initialize();
+  session()->CryptoConnect();
+  set_connected_or_attempting_connect(true);
+}
+
+void QuicClientBase::Disconnect() {
+  DCHECK(initialized_);
+
+  if (connected()) {
+    session()->connection()->CloseConnection(
+        QUIC_PEER_GOING_AWAY, "Client disconnecting",
+        ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+  }
+
+  ClearDataToResend();
+
+  CleanUpAllUDPSockets();
+
+  initialized_ = false;
+}
+
 ProofVerifier* QuicClientBase::proof_verifier() const {
   return crypto_config_.proof_verifier();
 }
@@ -102,6 +202,53 @@
          session_->connection()->connected();
 }
 
+void QuicClientBase::SendRequest(const SpdyHeaderBlock& headers,
+                                 StringPiece body,
+                                 bool fin) {
+  QuicClientPushPromiseIndex::TryHandle* handle;
+  QuicAsyncStatus rv = push_promise_index()->Try(headers, this, &handle);
+  if (rv == QUIC_SUCCESS)
+    return;
+
+  if (rv == QUIC_PENDING) {
+    // May need to retry request if asynchronous rendezvous fails.
+    AddPromiseDataToResend(headers, body, fin);
+    return;
+  }
+
+  QuicSpdyClientStream* stream = CreateReliableClientStream();
+  if (stream == nullptr) {
+    QUIC_BUG << "stream creation failed!";
+    return;
+  }
+  stream->SendRequest(headers.Clone(), body, fin);
+  // Record this in case we need to resend.
+  MaybeAddDataToResend(headers, body, fin);
+}
+
+void QuicClientBase::SendRequestAndWaitForResponse(
+    const SpdyHeaderBlock& headers,
+    StringPiece body,
+    bool fin) {
+  SendRequest(headers, body, fin);
+  while (WaitForEvents()) {
+  }
+}
+
+void QuicClientBase::SendRequestsAndWaitForResponse(
+    const vector<string>& url_list) {
+  for (size_t i = 0; i < url_list.size(); ++i) {
+    SpdyHeaderBlock headers;
+    if (!SpdyUtils::PopulateHeaderBlockFromUrl(url_list[i], &headers)) {
+      QUIC_BUG << "Unable to create request";
+      continue;
+    }
+    SendRequest(headers, "", true);
+  }
+  while (WaitForEvents()) {
+  }
+}
+
 QuicSpdyClientStream* QuicClientBase::CreateReliableClientStream() {
   if (!connected()) {
     return nullptr;
@@ -173,7 +320,7 @@
   if (connection_error_ != QUIC_NO_ERROR) {
     return connection_error_;
   }
-  if (session_.get() == nullptr) {
+  if (session_ == nullptr) {
     return QUIC_NO_ERROR;
   }
   return session_->error();
@@ -236,12 +383,11 @@
 void QuicClientBase::ResendSavedData() {
   // Calling Resend will re-enqueue the data, so swap out
   //  data_to_resend_on_connect_ before iterating.
-  std::vector<std::unique_ptr<QuicDataToResend>> old_data;
+  vector<std::unique_ptr<QuicDataToResend>> old_data;
   old_data.swap(data_to_resend_on_connect_);
   for (const auto& data : old_data) {
     data->Resend();
   }
-  data_to_resend_on_connect_.clear();
 }
 
 void QuicClientBase::AddPromiseDataToResend(const SpdyHeaderBlock& headers,
diff --git a/net/tools/quic/quic_client_base.h b/net/tools/quic/quic_client_base.h
index a5c8c5d..c4b735f 100644
--- a/net/tools/quic/quic_client_base.h
+++ b/net/tools/quic/quic_client_base.h
@@ -90,11 +90,37 @@
   // initialization succeeds, false otherwise.
   virtual bool Initialize();
 
+  // "Connect" to the QUIC server, including performing synchronous crypto
+  // handshake.
+  bool Connect();
+
+  // Start the crypto handshake.  This can be done in place of the synchronous
+  // Connect(), but callers are responsible for making sure the crypto handshake
+  // completes.
+  void StartConnect();
+
+  // Disconnects from the QUIC server.
+  void Disconnect();
+
   // Returns true if the crypto handshake has yet to establish encryption.
   // Returns false if encryption is active (even if the server hasn't confirmed
   // the handshake) or if the connection has been closed.
   bool EncryptionBeingEstablished();
 
+  // Sends an HTTP request and does not wait for response before returning.
+  void SendRequest(const SpdyHeaderBlock& headers,
+                   base::StringPiece body,
+                   bool fin);
+
+  // Sends an HTTP request and waits for response before returning.
+  void SendRequestAndWaitForResponse(const SpdyHeaderBlock& headers,
+                                     base::StringPiece body,
+                                     bool fin);
+
+  // Sends a request simple GET for each URL in |url_list|, and then waits for
+  // each to complete.
+  void SendRequestsAndWaitForResponse(const std::vector<std::string>& url_list);
+
   // Returns a newly created QuicSpdyClientStream, owned by the
   // QuicSimpleClient.
   virtual QuicSpdyClientStream* CreateReliableClientStream();
@@ -105,11 +131,6 @@
   // Wait for events until the handshake is confirmed.
   void WaitForCryptoHandshakeConfirmed();
 
-  // Sends an HTTP request and does not wait for response before returning.
-  virtual void SendRequest(const SpdyHeaderBlock& headers,
-                           base::StringPiece body,
-                           bool fin) = 0;
-
   // Wait up to 50ms, and handle any events which occur.
   // Returns true if there are any outstanding requests.
   virtual bool WaitForEvents() = 0;
@@ -261,6 +282,16 @@
   }
 
  protected:
+  // Creates a packet writer to be used for the next connection.
+  virtual QuicPacketWriter* CreateQuicPacketWriter() = 0;
+
+  // Used during initialization: creates the UDP socket FD, sets socket options,
+  // and binds the socket to our address.
+  virtual bool CreateUDPSocketAndBind() = 0;
+
+  // Unregister and close all open UDP sockets.
+  virtual void CleanUpAllUDPSockets() = 0;
+
   // Takes ownership of |connection|.
   virtual QuicClientSession* CreateQuicClientSession(
       QuicConnection* connection);
@@ -331,6 +362,9 @@
   // |server_id_| is a tuple (hostname, port, is_https) of the server.
   QuicServerId server_id_;
 
+  // Tracks if the client is initialized to connect.
+  bool initialized_;
+
   // Address of the server.
   IPEndPoint server_address_;
 
@@ -345,16 +379,18 @@
   QuicConfig config_;
   QuicCryptoClientConfig crypto_config_;
 
-  // Helper to be used by created connections. Needs to outlive |session_|.
+  // Helper to be used by created connections. Must outlive |session_|.
   std::unique_ptr<QuicConnectionHelperInterface> helper_;
 
-  // Helper to be used by created connections. Needs to outlive |session_|.
+  // Alarm factory to be used by created connections. Must outlive |session_|.
   std::unique_ptr<QuicAlarmFactory> alarm_factory_;
 
-  // Writer used to actually send packets to the wire. Needs to outlive
-  // |session_|.
+  // Writer used to actually send packets to the wire. Must outlive |session_|.
   std::unique_ptr<QuicPacketWriter> writer_;
 
+  // Index of pending promised streams. Must outlive |session_|.
+  QuicClientPushPromiseIndex push_promise_index_;
+
   // Session which manages streams.
   std::unique_ptr<QuicClientSession> session_;
 
@@ -390,8 +426,6 @@
   // to the previous client-level connection.
   bool connected_or_attempting_connect_;
 
-  QuicClientPushPromiseIndex push_promise_index_;
-
   // If true, store the latest response code, headers, and body.
   bool store_response_;
   // HTTP response code from most recent response.
diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc
index a88a2ead..1d7343f5 100644
--- a/net/tools/quic/quic_dispatcher_test.cc
+++ b/net/tools/quic/quic_dispatcher_test.cc
@@ -427,8 +427,8 @@
   packet.nonce_proof = 132232;
   std::unique_ptr<QuicEncryptedPacket> encrypted(
       QuicFramer::BuildPublicResetPacket(packet));
-  std::unique_ptr<QuicReceivedPacket> received(
-      ConstructReceivedPacket(*encrypted, helper_.GetClock()->Now()));
+  std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket(
+      *encrypted, session1_->connection()->clock()->Now()));
   EXPECT_CALL(*session1_, OnConnectionClosed(QUIC_PUBLIC_RESET, _,
                                              ConnectionCloseSource::FROM_PEER))
       .Times(1)
diff --git a/net/tools/quic/quic_simple_client.cc b/net/tools/quic/quic_simple_client.cc
index d7bb26f..9066ea93 100644
--- a/net/tools/quic/quic_simple_client.cc
+++ b/net/tools/quic/quic_simple_client.cc
@@ -37,17 +37,11 @@
     const QuicServerId& server_id,
     const QuicVersionVector& supported_versions,
     std::unique_ptr<ProofVerifier> proof_verifier)
-    : QuicClientBase(server_id,
-                     supported_versions,
-                     QuicConfig(),
-                     CreateQuicConnectionHelper(),
-                     CreateQuicAlarmFactory(),
-                     std::move(proof_verifier)),
-      initialized_(false),
-      packet_reader_started_(false),
-      weak_factory_(this) {
-  set_server_address(server_address);
-}
+    : QuicSimpleClient(server_address,
+                       server_id,
+                       supported_versions,
+                       QuicConfig(),
+                       std::move(proof_verifier)) {}
 
 QuicSimpleClient::QuicSimpleClient(
     IPEndPoint server_address,
@@ -75,20 +69,7 @@
   }
 }
 
-bool QuicSimpleClient::Initialize() {
-  DCHECK(!initialized_);
-
-  QuicClientBase::Initialize();
-
-  if (!CreateUDPSocket()) {
-    return false;
-  }
-
-  initialized_ = true;
-  return true;
-}
-
-bool QuicSimpleClient::CreateUDPSocket() {
+bool QuicSimpleClient::CreateUDPSocketAndBind() {
   std::unique_ptr<UDPClientSocket> socket(
       new UDPClientSocket(DatagramSocket::DEFAULT_BIND, RandIntCallback(),
                           &net_log_, NetLog::Source()));
@@ -139,6 +120,13 @@
   return true;
 }
 
+void QuicSimpleClient::CleanUpAllUDPSockets() {
+  reset_writer();
+  packet_reader_.reset();
+  packet_reader_started_ = false;
+
+}
+
 void QuicSimpleClient::StartPacketReaderIfNotStarted() {
   if (!packet_reader_started_) {
     packet_reader_->StartReading();
@@ -146,134 +134,10 @@
   }
 }
 
-bool QuicSimpleClient::Connect() {
-  // Attempt multiple connects until the maximum number of client hellos have
-  // been sent.
-  while (!connected() &&
-         GetNumSentClientHellos() <= QuicCryptoClientStream::kMaxClientHellos) {
-    StartConnect();
-    StartPacketReaderIfNotStarted();
-    while (EncryptionBeingEstablished()) {
-      WaitForEvents();
-    }
-    if (FLAGS_enable_quic_stateless_reject_support && connected()) {
-      // Resend any previously queued data.
-      ResendSavedData();
-    }
-    if (session() != nullptr &&
-        session()->error() != QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
-      // We've successfully created a session but we're not connected, and there
-      // is no stateless reject to recover from.  Give up trying.
-      break;
-    }
-  }
-  if (!connected() &&
-      GetNumSentClientHellos() > QuicCryptoClientStream::kMaxClientHellos &&
-      session() != nullptr &&
-      session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
-    // The overall connection failed due too many stateless rejects.
-    set_connection_error(QUIC_CRYPTO_TOO_MANY_REJECTS);
-  }
-  return session()->connection()->connected();
-}
-
-void QuicSimpleClient::StartConnect() {
-  DCHECK(initialized_);
-  DCHECK(!connected());
-
-  set_writer(CreateQuicPacketWriter());
-
-  if (connected_or_attempting_connect()) {
-    // If the last error was not a stateless reject, then the queued up data
-    // does not need to be resent.
-    if (session()->error() != QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
-      ClearDataToResend();
-    }
-    // Before we destroy the last session and create a new one, gather its stats
-    // and update the stats for the overall connection.
-    UpdateStats();
-  }
-
-  CreateQuicClientSession(new QuicConnection(
-      GetNextConnectionId(), server_address(), helper(), alarm_factory(),
-      writer(),
-      /* owns_writer= */ false, Perspective::IS_CLIENT, supported_versions()));
-
-  session()->Initialize();
-  session()->CryptoConnect();
-  set_connected_or_attempting_connect(true);
-}
-
-void QuicSimpleClient::Disconnect() {
-  DCHECK(initialized_);
-
-  if (connected()) {
-    session()->connection()->CloseConnection(
-        QUIC_PEER_GOING_AWAY, "Client disconnecting",
-        ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
-  }
-  ClearDataToResend();
-
-  reset_writer();
-  packet_reader_.reset();
-  packet_reader_started_ = false;
-
-  initialized_ = false;
-}
-
-void QuicSimpleClient::SendRequest(const SpdyHeaderBlock& headers,
-                                   StringPiece body,
-                                   bool fin) {
-  QuicClientPushPromiseIndex::TryHandle* handle;
-  QuicAsyncStatus rv = push_promise_index()->Try(headers, this, &handle);
-  if (rv == QUIC_SUCCESS)
-    return;
-
-  if (rv == QUIC_PENDING) {
-    // May need to retry request if asynchronous rendezvous fails.
-    AddPromiseDataToResend(headers, body, fin);
-    return;
-  }
-
-  QuicSpdyClientStream* stream = CreateReliableClientStream();
-  if (stream == nullptr) {
-    QUIC_BUG << "stream creation failed!";
-    return;
-  }
-  stream->set_visitor(this);
-  stream->SendRequest(headers.Clone(), body, fin);
-  // Record this in case we need to resend.
-  MaybeAddDataToResend(headers, body, fin);
-}
-
-void QuicSimpleClient::SendRequestAndWaitForResponse(
-    const SpdyHeaderBlock& headers,
-    base::StringPiece body,
-    bool fin) {
-  SendRequest(headers, body, fin);
-  while (WaitForEvents()) {
-  }
-}
-
-void QuicSimpleClient::SendRequestsAndWaitForResponse(
-    const base::CommandLine::StringVector& url_list) {
-  for (size_t i = 0; i < url_list.size(); ++i) {
-    string url = GURL(url_list[i]).spec();
-    SpdyHeaderBlock headers;
-    if (!SpdyUtils::PopulateHeaderBlockFromUrl(url, &headers)) {
-      QUIC_BUG << "Unable to create request";
-      continue;
-    }
-    SendRequest(headers, "", true);
-  }
-
-  while (WaitForEvents()) {
-  }
-}
-
 bool QuicSimpleClient::WaitForEvents() {
   DCHECK(connected());
 
+  StartPacketReaderIfNotStarted();
   base::RunLoop().RunUntilIdle();
 
   DCHECK(session() != nullptr);
@@ -294,7 +158,7 @@
   }
 
   set_bind_to_address(new_host);
-  if (!CreateUDPSocket()) {
+  if (!CreateUDPSocketAndBind()) {
     return false;
   }
 
@@ -307,10 +171,6 @@
   return true;
 }
 
-QuicConnectionId QuicSimpleClient::GenerateNewConnectionId() {
-  return helper()->GetRandomGenerator()->RandUint64();
-}
-
 QuicChromiumConnectionHelper* QuicSimpleClient::CreateQuicConnectionHelper() {
   return new QuicChromiumConnectionHelper(&clock_, QuicRandom::GetInstance());
 }
diff --git a/net/tools/quic/quic_simple_client.h b/net/tools/quic/quic_simple_client.h
index d538081..b67aa03 100644
--- a/net/tools/quic/quic_simple_client.h
+++ b/net/tools/quic/quic_simple_client.h
@@ -55,36 +55,7 @@
   ~QuicSimpleClient() override;
 
   // From QuicClientBase
-  bool Initialize() override;
   bool WaitForEvents() override;
-  QuicConnectionId GenerateNewConnectionId() override;
-
-  // "Connect" to the QUIC server, including performing synchronous crypto
-  // handshake.
-  bool Connect();
-
-  // Start the crypto handshake.  This can be done in place of the synchronous
-  // Connect(), but callers are responsible for making sure the crypto handshake
-  // completes.
-  void StartConnect();
-
-  // Disconnects from the QUIC server.
-  void Disconnect();
-
-  // Sends an HTTP request and does not wait for response before returning.
-  void SendRequest(const SpdyHeaderBlock& headers,
-                   base::StringPiece body,
-                   bool fin) override;
-
-  // Sends an HTTP request and waits for response before returning.
-  void SendRequestAndWaitForResponse(const SpdyHeaderBlock& headers,
-                                     base::StringPiece body,
-                                     bool fin);
-
-  // Sends a request simple GET for each URL in |args|, and then waits for
-  // each to complete.
-  void SendRequestsAndWaitForResponse(
-      const base::CommandLine::StringVector& url_list);
 
   // Migrate to a new socket during an active connection.
   bool MigrateSocket(const IPAddress& new_host);
@@ -96,16 +67,15 @@
                 IPEndPoint peer_address) override;
 
  protected:
-  virtual QuicChromiumAlarmFactory* CreateQuicAlarmFactory();
-  virtual QuicChromiumConnectionHelper* CreateQuicConnectionHelper();
-  virtual QuicPacketWriter* CreateQuicPacketWriter();
+  QuicPacketWriter* CreateQuicPacketWriter() override;
+  bool CreateUDPSocketAndBind() override;
+  void CleanUpAllUDPSockets() override;
 
  private:
   friend class net::test::QuicClientPeer;
 
-  // Used during initialization: creates the UDP socket FD, sets socket options,
-  // and binds the socket to our address.
-  bool CreateUDPSocket();
+  QuicChromiumAlarmFactory* CreateQuicAlarmFactory();
+  QuicChromiumConnectionHelper* CreateQuicConnectionHelper();
 
   // Read a UDP packet and hand it to the framer.
   bool ReadAndProcessPacket();
@@ -124,14 +94,6 @@
   // Tracks if the client is initialized to connect.
   bool initialized_;
 
-  // If overflow_supported_ is true, this will be the number of packets dropped
-  // during the lifetime of the server.
-  QuicPacketCount packets_dropped_;
-
-  // True if the kernel supports SO_RXQ_OVFL, the number of packets dropped
-  // because the socket would otherwise overflow.
-  bool overflow_supported_;
-
   // The log used for the sockets.
   NetLog net_log_;
 
diff --git a/ppapi/proxy/ppp_video_decoder_proxy.cc b/ppapi/proxy/ppp_video_decoder_proxy.cc
index 1980318..576ba95 100644
--- a/ppapi/proxy/ppp_video_decoder_proxy.cc
+++ b/ppapi/proxy/ppp_video_decoder_proxy.cc
@@ -25,10 +25,15 @@
   HostResource decoder_resource;
   decoder_resource.SetHostResource(instance, decoder);
 
-  HostDispatcher::GetForInstance(instance)->Send(
-      new PpapiMsg_PPPVideoDecoder_ProvidePictureBuffers(
-          API_ID_PPP_VIDEO_DECODER_DEV,
-          decoder_resource, req_num_of_bufs, *dimensions, texture_target));
+  // This is called by the graphics system in response to a message from the
+  // GPU process. These messages will not be synchronized with the lifetime
+  // of the plugin so we need to null-check here.
+  HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance);
+  if (dispatcher) {
+    dispatcher->Send(new PpapiMsg_PPPVideoDecoder_ProvidePictureBuffers(
+        API_ID_PPP_VIDEO_DECODER_DEV,
+        decoder_resource, req_num_of_bufs, *dimensions, texture_target));
+  }
 }
 
 void DismissPictureBuffer(PP_Instance instance, PP_Resource decoder,
@@ -36,10 +41,13 @@
   HostResource decoder_resource;
   decoder_resource.SetHostResource(instance, decoder);
 
-  HostDispatcher::GetForInstance(instance)->Send(
-      new PpapiMsg_PPPVideoDecoder_DismissPictureBuffer(
-          API_ID_PPP_VIDEO_DECODER_DEV,
-          decoder_resource, picture_buffer_id));
+  // Null check as in ProvidePictureBuffers above.
+  HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance);
+  if (dispatcher) {
+    dispatcher->Send(new PpapiMsg_PPPVideoDecoder_DismissPictureBuffer(
+        API_ID_PPP_VIDEO_DECODER_DEV,
+        decoder_resource, picture_buffer_id));
+  }
 }
 
 void PictureReady(PP_Instance instance, PP_Resource decoder,
@@ -47,9 +55,12 @@
   HostResource decoder_resource;
   decoder_resource.SetHostResource(instance, decoder);
 
-  HostDispatcher::GetForInstance(instance)->Send(
-      new PpapiMsg_PPPVideoDecoder_PictureReady(
-          API_ID_PPP_VIDEO_DECODER_DEV, decoder_resource, *picture));
+  // Null check as in ProvidePictureBuffers above.
+  HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance);
+  if (dispatcher) {
+    dispatcher->Send(new PpapiMsg_PPPVideoDecoder_PictureReady(
+        API_ID_PPP_VIDEO_DECODER_DEV, decoder_resource, *picture));
+  }
 }
 
 void NotifyError(PP_Instance instance, PP_Resource decoder,
diff --git a/remoting/android/client_java_tmpl.gni b/remoting/android/client_java_tmpl.gni
index 0a5e25d..71bad16 100644
--- a/remoting/android/client_java_tmpl.gni
+++ b/remoting/android/client_java_tmpl.gni
@@ -62,6 +62,7 @@
       "accountswitcher/AccountSwitcherFactory.java",
       "base/OAuthTokenFetcher.java",
       "help/CreditsActivity.java",
+      "help/FeedbackSender.java",
       "help/HelpActivity.java",
       "help/HelpAndFeedback.java",
       "help/HelpAndFeedbackBasic.java",
diff --git a/remoting/android/java/res/drawable-hdpi/ic_announcement.png b/remoting/android/java/res/drawable-hdpi/ic_announcement.png
new file mode 100644
index 0000000..9f5e03d
--- /dev/null
+++ b/remoting/android/java/res/drawable-hdpi/ic_announcement.png
Binary files differ
diff --git a/remoting/android/java/res/drawable-mdpi/ic_announcement.png b/remoting/android/java/res/drawable-mdpi/ic_announcement.png
new file mode 100644
index 0000000..e89907d
--- /dev/null
+++ b/remoting/android/java/res/drawable-mdpi/ic_announcement.png
Binary files differ
diff --git a/remoting/android/java/res/drawable-xhdpi/ic_announcement.png b/remoting/android/java/res/drawable-xhdpi/ic_announcement.png
new file mode 100644
index 0000000..ab7ff42f
--- /dev/null
+++ b/remoting/android/java/res/drawable-xhdpi/ic_announcement.png
Binary files differ
diff --git a/remoting/android/java/res/drawable-xxhdpi/ic_announcement.png b/remoting/android/java/res/drawable-xxhdpi/ic_announcement.png
new file mode 100644
index 0000000..333f9a3
--- /dev/null
+++ b/remoting/android/java/res/drawable-xxhdpi/ic_announcement.png
Binary files differ
diff --git a/remoting/android/java/res/drawable-xxxhdpi/ic_announcement.png b/remoting/android/java/res/drawable-xxxhdpi/ic_announcement.png
new file mode 100644
index 0000000..cfe3478
--- /dev/null
+++ b/remoting/android/java/res/drawable-xxxhdpi/ic_announcement.png
Binary files differ
diff --git a/remoting/android/java/res/menu/feedback_list_item.xml b/remoting/android/java/res/menu/feedback_list_item.xml
new file mode 100644
index 0000000..66c96ba
--- /dev/null
+++ b/remoting/android/java/res/menu/feedback_list_item.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- TODO(yuweih): Refactor list item XML's -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawablePadding="32dp"
+    android:drawableStart="@drawable/ic_announcement"
+    android:gravity="center_vertical"
+    android:layout_height="wrap_content"
+    android:layout_width="match_parent"
+    android:paddingStart="16dp"
+    android:paddingEnd="16dp"
+    android:paddingTop="16dp"
+    android:paddingBottom="20dp"
+    android:text="@string/actionbar_send_feedback"
+    style="@style/NavigationTextStyle"/>
\ No newline at end of file
diff --git a/remoting/android/java/src/org/chromium/chromoting/Chromoting.java b/remoting/android/java/src/org/chromium/chromoting/Chromoting.java
index 93e936463..4bc7cc3 100644
--- a/remoting/android/java/src/org/chromium/chromoting/Chromoting.java
+++ b/remoting/android/java/src/org/chromium/chromoting/Chromoting.java
@@ -33,11 +33,9 @@
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.Log;
-import org.chromium.chromoting.NavigationMenuAdapter.NavigationMenuItem;
 import org.chromium.chromoting.accountswitcher.AccountSwitcher;
 import org.chromium.chromoting.accountswitcher.AccountSwitcherFactory;
 import org.chromium.chromoting.base.OAuthTokenFetcher;
-import org.chromium.chromoting.help.CreditsActivity;
 import org.chromium.chromoting.help.HelpContext;
 import org.chromium.chromoting.help.HelpSingleton;
 import org.chromium.chromoting.jni.Client;
@@ -169,34 +167,6 @@
         mProgressView.setVisibility(View.GONE);
     }
 
-    private ListView createNavigationMenu() {
-        ListView navigationMenu = (ListView) getLayoutInflater()
-                .inflate(R.layout.navigation_list, null);
-
-        NavigationMenuItem helpItem = new NavigationMenuItem(R.menu.help_list_item,
-                new Runnable() {
-                    @Override
-                    public void run() {
-                        HelpSingleton.getInstance().launchHelp(Chromoting.this,
-                                HelpContext.HOST_LIST);
-                    }
-                });
-
-        NavigationMenuItem creditsItem = new NavigationMenuItem(R.menu.credits_list_item,
-                new Runnable() {
-                    @Override
-                    public void run() {
-                        startActivity(new Intent(Chromoting.this, CreditsActivity.class));
-                    }
-                });
-
-        NavigationMenuItem[] navigationMenuItems = { helpItem, creditsItem };
-        NavigationMenuAdapter adapter = new NavigationMenuAdapter(this, navigationMenuItems);
-        navigationMenu.setAdapter(adapter);
-        navigationMenu.setOnItemClickListener(adapter);
-        return navigationMenu;
-    }
-
     /**
      * Called when the activity is first created. Loads the native library and requests an
      * authentication token from the system.
@@ -268,7 +238,7 @@
         getSupportActionBar().setHomeAsUpIndicator(menuIcon);
 
         mAccountSwitcher = AccountSwitcherFactory.getInstance().createAccountSwitcher(this, this);
-        mAccountSwitcher.setNavigation(createNavigationMenu());
+        mAccountSwitcher.setNavigation(NavigationMenuAdapter.createNavigationMenu(this));
         LinearLayout navigationDrawer = (LinearLayout) findViewById(R.id.navigation_drawer);
         mAccountSwitcher.setDrawer(navigationDrawer);
         View switcherView = mAccountSwitcher.getView();
diff --git a/remoting/android/java/src/org/chromium/chromoting/NavigationMenuAdapter.java b/remoting/android/java/src/org/chromium/chromoting/NavigationMenuAdapter.java
index 79961b1..db07d2d 100644
--- a/remoting/android/java/src/org/chromium/chromoting/NavigationMenuAdapter.java
+++ b/remoting/android/java/src/org/chromium/chromoting/NavigationMenuAdapter.java
@@ -4,12 +4,20 @@
 
 package org.chromium.chromoting;
 
+import android.app.Activity;
 import android.content.Context;
+import android.content.Intent;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.AdapterView;
 import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+import org.chromium.chromoting.help.CreditsActivity;
+import org.chromium.chromoting.help.FeedbackSender;
+import org.chromium.chromoting.help.HelpContext;
+import org.chromium.chromoting.help.HelpSingleton;
 
 /**
  * Describes the appearance and behavior of the navigation menu. This also implements
@@ -29,6 +37,42 @@
         }
     }
 
+    public static ListView createNavigationMenu(final Activity activity) {
+        ListView navigationMenu = (ListView) activity.getLayoutInflater()
+                .inflate(R.layout.navigation_list, null);
+
+        NavigationMenuItem creditsItem = new NavigationMenuItem(R.menu.credits_list_item,
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        activity.startActivity(new Intent(activity, CreditsActivity.class));
+                    }
+                });
+
+        NavigationMenuItem feedbackItem = new NavigationMenuItem(R.menu.feedback_list_item,
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        FeedbackSender.sendFeedback(activity);
+                    }
+                });
+
+        NavigationMenuItem helpItem = new NavigationMenuItem(R.menu.help_list_item,
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        HelpSingleton.getInstance().launchHelp(activity,
+                                HelpContext.HOST_LIST);
+                    }
+                });
+
+        NavigationMenuItem[] navigationMenuItems = { creditsItem, feedbackItem, helpItem };
+        NavigationMenuAdapter adapter = new NavigationMenuAdapter(activity, navigationMenuItems);
+        navigationMenu.setAdapter(adapter);
+        navigationMenu.setOnItemClickListener(adapter);
+        return navigationMenu;
+    }
+
     public NavigationMenuAdapter(Context context, NavigationMenuItem[] objects) {
         super(context, -1, objects);
     }
diff --git a/remoting/android/java/src/org/chromium/chromoting/help/FeedbackSender.java b/remoting/android/java/src/org/chromium/chromoting/help/FeedbackSender.java
new file mode 100644
index 0000000..90316a1
--- /dev/null
+++ b/remoting/android/java/src/org/chromium/chromoting/help/FeedbackSender.java
@@ -0,0 +1,87 @@
+// 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.
+
+package org.chromium.chromoting.help;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.graphics.Bitmap;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.view.View;
+
+import org.chromium.base.Log;
+import org.chromium.ui.UiUtils;
+
+/**
+ * This is a helper class for sending feedback.
+ */
+public class FeedbackSender {
+    private static final String TAG = "Chromoting";
+
+    /**
+     * Maximum dimension for the screenshot to be sent to the Send Feedback handler.  This size
+     * ensures the size of bitmap < 1MB, which is a requirement of the handler.
+     */
+    private static final int MAX_FEEDBACK_SCREENSHOT_DIMENSION = 600;
+
+    private static final String FEEDBACK_PACKAGE = "com.google.android.gms";
+
+    private static final String FEEDBACK_CLASS =
+            "com.google.android.gms.feedback.LegacyBugReportService";
+
+    private static final int SEND_FEEDBACK_INFO = Binder.FIRST_CALL_TRANSACTION;
+
+    /**
+     * Opens the feedback activity with a generated screenshot.
+     * @param activity The activity for grabbing the screenshot and acting as the context.
+     */
+    public static void sendFeedback(Activity activity) {
+        View rootView = activity.getWindow().getDecorView().getRootView();
+        Bitmap screenshot = UiUtils.generateScaledScreenshot(rootView,
+                MAX_FEEDBACK_SCREENSHOT_DIMENSION,
+                Bitmap.Config.ARGB_8888);
+        sendFeedback(activity, screenshot);
+    }
+
+    /**
+     * Opens the feedback activity with the given screenshot image.
+     * @param context The context for resource.
+     * @param screenshot The screenshot image.
+     */
+    public static void sendFeedback(Context context, final Bitmap screenshot) {
+        Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
+        intent.setComponent(new ComponentName(FEEDBACK_PACKAGE, FEEDBACK_CLASS));
+        if (context.getPackageManager().resolveService(intent, 0) == null) {
+            Log.e(TAG, "Unable to resolve Feedback service.");
+            return;
+        }
+
+        ServiceConnection conn = new ServiceConnection() {
+            @Override
+            public void onServiceConnected(ComponentName name, IBinder service) {
+                try {
+                    Parcel parcel = Parcel.obtain();
+                    if (screenshot != null) {
+                        screenshot.writeToParcel(parcel, 0);
+                    }
+                    service.transact(SEND_FEEDBACK_INFO, parcel, null, 0);
+                    parcel.recycle();
+                } catch (RemoteException ex) {
+                    Log.e(TAG, "Unexpected error sending feedback: ", ex);
+                }
+            }
+
+            @Override
+            public void onServiceDisconnected(ComponentName name) {}
+        };
+
+        context.bindService(intent, conn, Context.BIND_AUTO_CREATE);
+    }
+}
diff --git a/remoting/android/java/src/org/chromium/chromoting/help/HelpActivity.java b/remoting/android/java/src/org/chromium/chromoting/help/HelpActivity.java
index 8026e3c2..45d4a87 100644
--- a/remoting/android/java/src/org/chromium/chromoting/help/HelpActivity.java
+++ b/remoting/android/java/src/org/chromium/chromoting/help/HelpActivity.java
@@ -5,18 +5,12 @@
 package org.chromium.chromoting.help;
 
 import android.app.Activity;
-import android.content.ComponentName;
 import android.content.Intent;
-import android.content.ServiceConnection;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
 import android.net.Uri;
-import android.os.Binder;
 import android.os.Bundle;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.RemoteException;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.widget.Toolbar;
 import android.text.TextUtils;
@@ -26,7 +20,6 @@
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
 
-import org.chromium.base.Log;
 import org.chromium.chromoting.ChromotingUtil;
 import org.chromium.chromoting.R;
 import org.chromium.ui.UiUtils;
@@ -35,15 +28,8 @@
  * The Activity for showing the Help screen.
  */
 public class HelpActivity extends AppCompatActivity {
-    private static final String TAG = "Chromoting";
-
     private static final String PLAY_STORE_URL = "market://details?id=";
 
-    private static final String FEEDBACK_PACKAGE = "com.google.android.gms";
-
-    private static final String FEEDBACK_CLASS =
-            "com.google.android.gms.feedback.LegacyBugReportService";
-
     /**
      * Maximum dimension for the screenshot to be sent to the Send Feedback handler.  This size
      * ensures the size of bitmap < 1MB, which is a requirement of the handler.
@@ -59,39 +45,6 @@
     /** WebView used to display help content. */
     private WebView mWebView;
 
-    /** Constant used to send the feedback parcel to the system feedback service. */
-    private static final int SEND_FEEDBACK_INFO = Binder.FIRST_CALL_TRANSACTION;
-
-    private void sendFeedback() {
-        Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
-        intent.setComponent(new ComponentName(FEEDBACK_PACKAGE, FEEDBACK_CLASS));
-        if (getPackageManager().resolveService(intent, 0) == null) {
-            Log.e(TAG, "Unable to resolve Feedback service.");
-            return;
-        }
-
-        ServiceConnection conn = new ServiceConnection() {
-            @Override
-            public void onServiceConnected(ComponentName name, IBinder service) {
-                try {
-                    Parcel parcel = Parcel.obtain();
-                    if (sScreenshot != null) {
-                        sScreenshot.writeToParcel(parcel, 0);
-                    }
-                    service.transact(SEND_FEEDBACK_INFO, parcel, null, 0);
-                    parcel.recycle();
-                } catch (RemoteException ex) {
-                    Log.e(TAG, "Unexpected error sending feedback: ", ex);
-                }
-            }
-
-            @Override
-            public void onServiceDisconnected(ComponentName name) {}
-        };
-
-        bindService(intent, conn, BIND_AUTO_CREATE);
-    }
-
     /** Launches the Help activity. */
     public static void launch(Activity activity, String helpUrl) {
         View rootView = activity.getWindow().getDecorView().getRootView();
@@ -164,7 +117,7 @@
             return true;
         }
         if (id == R.id.actionbar_feedback) {
-            sendFeedback();
+            FeedbackSender.sendFeedback(this, sScreenshot);
             return true;
         }
         if (id == R.id.actionbar_play_store) {
diff --git a/remoting/host/BUILD.gn b/remoting/host/BUILD.gn
index 51dcaada..fd03fdad 100644
--- a/remoting/host/BUILD.gn
+++ b/remoting/host/BUILD.gn
@@ -302,7 +302,6 @@
   deps = [
     "//base:i18n",
     "//components/policy/core/common",
-    "//content/public/common",
     "//crypto",
     "//device/power_save_blocker",
     "//google_apis",
diff --git a/remoting/host/chromoting_messages.h b/remoting/host/chromoting_messages.h
index 8a60aa1..db17927c 100644
--- a/remoting/host/chromoting_messages.h
+++ b/remoting/host/chromoting_messages.h
@@ -9,7 +9,6 @@
 
 #include "base/memory/shared_memory_handle.h"
 #include "ipc/ipc_platform_file.h"
-#include "net/base/ip_endpoint.h"
 #include "remoting/host/chromoting_param_traits.h"
 #include "remoting/host/screen_resolution.h"
 #include "remoting/protocol/errors.h"
@@ -89,8 +88,10 @@
 // Serialized remoting::protocol::TransportRoute structure.
 IPC_STRUCT_BEGIN(SerializedTransportRoute)
   IPC_STRUCT_MEMBER(remoting::protocol::TransportRoute::RouteType, type)
-  IPC_STRUCT_MEMBER(net::IPEndPoint, remote_address)
-  IPC_STRUCT_MEMBER(net::IPEndPoint, local_address)
+  IPC_STRUCT_MEMBER(std::vector<uint8_t>, remote_ip)
+  IPC_STRUCT_MEMBER(uint16_t, remote_port)
+  IPC_STRUCT_MEMBER(std::vector<uint8_t>, local_ip)
+  IPC_STRUCT_MEMBER(uint16_t, local_port)
 IPC_STRUCT_END()
 
 IPC_ENUM_TRAITS_MAX_VALUE(remoting::protocol::TransportRoute::RouteType,
diff --git a/remoting/host/daemon_process.cc b/remoting/host/daemon_process.cc
index 3482f978..ad00c95 100644
--- a/remoting/host/daemon_process.cc
+++ b/remoting/host/daemon_process.cc
@@ -334,8 +334,15 @@
 
   protocol::TransportRoute parsed_route;
   parsed_route.type = route.type;
-  parsed_route.remote_address = route.remote_address;
-  parsed_route.local_address = route.local_address;
+
+  net::IPAddress remote_ip(route.remote_ip);
+  CHECK(remote_ip.empty() || remote_ip.IsValid());
+  parsed_route.remote_address = net::IPEndPoint(remote_ip, route.remote_port);
+
+  net::IPAddress local_ip(route.local_ip);
+  CHECK(local_ip.empty() || local_ip.IsValid());
+  parsed_route.local_address = net::IPEndPoint(local_ip, route.local_port);
+
   FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
                     OnClientRouteChange(jid, channel_name, parsed_route));
 }
diff --git a/remoting/host/ipc_host_event_logger.cc b/remoting/host/ipc_host_event_logger.cc
index 24b04edc..3ebebc6 100644
--- a/remoting/host/ipc_host_event_logger.cc
+++ b/remoting/host/ipc_host_event_logger.cc
@@ -60,9 +60,10 @@
 
   SerializedTransportRoute serialized_route;
   serialized_route.type = route.type;
-  serialized_route.remote_address = route.remote_address;
-  serialized_route.local_address = route.local_address;
-
+  serialized_route.remote_ip = route.remote_address.address().bytes();
+  serialized_route.remote_port = route.remote_address.port();
+  serialized_route.local_ip = route.local_address.address().bytes();
+  serialized_route.local_port = route.local_address.port();
   daemon_channel_->Send(new ChromotingNetworkDaemonMsg_ClientRouteChange(
       jid, channel_name, serialized_route));
 }
diff --git a/remoting/host/win/BUILD.gn b/remoting/host/win/BUILD.gn
index dceee79bb..470e8e4 100644
--- a/remoting/host/win/BUILD.gn
+++ b/remoting/host/win/BUILD.gn
@@ -24,6 +24,8 @@
 
 # Reference this manifest to give the binary the uiAccess privilege.
 enable_uiaccess_manifest = "//remoting/host/win/enable_uiaccess.manifest"
+enable_uiaccess_require_admin_manifest =
+    "//remoting/host/win/enable_uiaccess_require_admin.manifest"
 
 # Depending on this target gives a default executable manifest with the addition
 # of the DPI aware tag.
@@ -61,6 +63,18 @@
   type = "exe"
 }
 
+# Depending on this target gives the executable a default manifest with the
+# addition of the DPI aware tag and enables uiAccess.
+windows_manifest("dpi_aware_uiaccess_require_admin_exe_manifest") {
+  sources = [
+    common_controls_manifest,
+    default_compatibility_manifest,
+    dpi_aware_manifest,
+    enable_uiaccess_require_admin_manifest,
+  ]
+  type = "exe"
+}
+
 source_set("win") {
   sources = [
     "com_imported_mstscax.tlh",
@@ -414,7 +428,7 @@
   ]
 
   if (is_official_build) {
-    deps += [ ":dpi_aware_elevated_exe_manifest" ]
+    deps += [ ":dpi_aware_uiaccess_require_admin_exe_manifest" ]
   } else {
     deps += [ ":dpi_aware_exe_manifest" ]
   }
diff --git a/remoting/host/win/enable_uiaccess_require_admin.manifest b/remoting/host/win/enable_uiaccess_require_admin.manifest
new file mode 100644
index 0000000..f9bf6d3cb
--- /dev/null
+++ b/remoting/host/win/enable_uiaccess_require_admin.manifest
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+    <security>
+      <requestedPrivileges>
+        <requestedExecutionLevel level="requireAdministrator" uiAccess="true"/>
+      </requestedPrivileges>
+    </security>
+  </trustInfo>
+</assembly>
\ No newline at end of file
diff --git a/remoting/resources/remoting_strings.grd b/remoting/resources/remoting_strings.grd
index 23f30395..505838b 100644
--- a/remoting/resources/remoting_strings.grd
+++ b/remoting/resources/remoting_strings.grd
@@ -586,11 +586,14 @@
         <message desc="Title of the authentication dialog" name="IDS_TITLE_AUTHENTICATE" formatter_data="android_java">
           Authenticate to host
         </message>
+        <message desc="Android application menu item for sending product feedback to the developers" name="IDS_ACTIONBAR_SEND_FEEDBACK" formatter_data="android_java">
+          Send Feedback
+        </message>
         <message desc="Title displayed in the action-bar for the Android Help screen" name="IDS_ACTIONBAR_HELP_TITLE" formatter_data="android_java">
           Help
         </message>
-        <message desc="Android action-bar menu item for showing the Help and Feedback screen" name="IDS_ACTIONBAR_HELP" formatter_data="android_java">
-          Help &amp; feedback
+        <message desc="Android application menu item for showing the Help screen" name="IDS_ACTIONBAR_HELP" formatter_data="android_java">
+          Help
         </message>
         <message desc="Android action-bar menu item for viewing the Play Store page for the application" name="IDS_ACTIONBAR_PLAY_STORE" formatter_data="android_java">
           View in Google Play Store
diff --git a/services/ui/public/cpp/property_type_converters.cc b/services/ui/public/cpp/property_type_converters.cc
index a70d68f..b88d4c1 100644
--- a/services/ui/public/cpp/property_type_converters.cc
+++ b/services/ui/public/cpp/property_type_converters.cc
@@ -95,6 +95,37 @@
 }
 
 // static
+std::vector<uint8_t> TypeConverter<std::vector<uint8_t>, int64_t>::Convert(
+    const int64_t& input) {
+  std::vector<uint8_t> vec(8);
+  vec[0] = (input >> 56) & 0xFF;
+  vec[1] = (input >> 48) & 0xFF;
+  vec[2] = (input >> 40) & 0xFF;
+  vec[3] = (input >> 32) & 0xFF;
+  vec[4] = (input >> 24) & 0xFF;
+  vec[5] = (input >> 16) & 0xFF;
+  vec[6] = (input >> 8) & 0xFF;
+  vec[7] = input & 0xFF;
+  return vec;
+}
+
+// static
+int64_t TypeConverter<int64_t, std::vector<uint8_t>>::Convert(
+    const std::vector<uint8_t>& input) {
+  if (input.size() < 8) {
+    NOTREACHED();
+    return 0;
+  }
+  return static_cast<int64_t>(input[0]) << 56 |
+         static_cast<int64_t>(input[1]) << 48 |
+         static_cast<int64_t>(input[2]) << 40 |
+         static_cast<int64_t>(input[3]) << 32 |
+         static_cast<int64_t>(input[4]) << 24 |
+         static_cast<int64_t>(input[5]) << 16 |
+         static_cast<int64_t>(input[6]) << 8 | static_cast<int64_t>(input[7]);
+}
+
+// static
 std::vector<uint8_t>
 TypeConverter<std::vector<uint8_t>, base::string16>::Convert(
     const base::string16& input) {
diff --git a/services/ui/public/cpp/property_type_converters.h b/services/ui/public/cpp/property_type_converters.h
index b249725..481dc14 100644
--- a/services/ui/public/cpp/property_type_converters.h
+++ b/services/ui/public/cpp/property_type_converters.h
@@ -54,6 +54,15 @@
 };
 
 template <>
+struct TypeConverter<std::vector<uint8_t>, int64_t> {
+  static std::vector<uint8_t> Convert(const int64_t& input);
+};
+template <>
+struct TypeConverter<int64_t, std::vector<uint8_t>> {
+  static int64_t Convert(const std::vector<uint8_t>& input);
+};
+
+template <>
 struct TypeConverter<std::vector<uint8_t>, base::string16> {
   static std::vector<uint8_t> Convert(const base::string16& input);
 };
diff --git a/services/ui/public/interfaces/window_manager.mojom b/services/ui/public/interfaces/window_manager.mojom
index fb103d2..9a2545f 100644
--- a/services/ui/public/interfaces/window_manager.mojom
+++ b/services/ui/public/interfaces/window_manager.mojom
@@ -32,6 +32,9 @@
   // Initial bounds to create the window at. If empty the WindowManager decides
   // the initial bounds.
   const string kInitialBounds_Property = "prop:initial_bounds";
+  // The id of the display (display::Display::id()) to create the window on.
+  // Type: int64.
+  const string kInitialDisplayId_Property = "prop:initial_display_id";
   // Internal window name. Useful for debugging. Type: mojom::String
   const string kName_Property = "prop:name";
   // The window's preferred size as defined by its content. Type: gfx::Size.
@@ -48,6 +51,11 @@
   const string kRestoreBounds_Property = "prop:restore-bounds";
   // Shadow style for the window. Type: mojom::ShadowStyle.
   const string kShadowStyle_Property = "prop:shadow-style";
+  // The image resource ID to be used as the shelf item's icon. Type: int
+  const string kShelfIconResourceId_Property = "prop:shelf-icon-resource-id";
+  // The type of item to be shown on the shelf for this window. Type: int
+  // A few ash::ShelfItemType values are supported; TYPE_UNKNOWN means no item.
+  const string kShelfItemType_Property = "prop:shelf-item-type";
   // The window's show state. Type: ShowState.
   const string kShowState_Property = "prop:show-state";
   // The window bounds as set by user input. Type: gfx::Rect.
diff --git a/services/ui/ws/BUILD.gn b/services/ui/ws/BUILD.gn
index e0585c2..975f5be 100644
--- a/services/ui/ws/BUILD.gn
+++ b/services/ui/ws/BUILD.gn
@@ -28,6 +28,7 @@
     "display_manager.h",
     "drag_controller.cc",
     "drag_controller.h",
+    "drag_cursor_updater.h",
     "drag_source.h",
     "drag_target_connection.h",
     "event_dispatcher.cc",
diff --git a/services/ui/ws/cursor_unittest.cc b/services/ui/ws/cursor_unittest.cc
index 2d8935f..44ac190 100644
--- a/services/ui/ws/cursor_unittest.cc
+++ b/services/ui/ws/cursor_unittest.cc
@@ -44,7 +44,7 @@
   TestWindowServerDelegate* window_server_delegate() {
     return ws_test_helper_.window_server_delegate();
   }
-  int32_t cursor_id() const { return ws_test_helper_.cursor_id(); }
+  mojom::Cursor cursor() const { return ws_test_helper_.cursor(); }
 
  protected:
   // testing::Test:
@@ -110,18 +110,17 @@
 TEST_F(CursorTest, ChangeByMouseMove) {
   ServerWindow* win = BuildServerWindow();
   win->SetPredefinedCursor(mojom::Cursor::IBEAM);
-  EXPECT_EQ(mojom::Cursor::IBEAM, mojom::Cursor(win->cursor()));
+  EXPECT_EQ(mojom::Cursor::IBEAM, win->cursor());
   win->SetNonClientCursor(mojom::Cursor::EAST_RESIZE);
-  EXPECT_EQ(mojom::Cursor::EAST_RESIZE,
-            mojom::Cursor(win->non_client_cursor()));
+  EXPECT_EQ(mojom::Cursor::EAST_RESIZE, win->non_client_cursor());
 
   // Non client area
   MoveCursorTo(gfx::Point(15, 15));
-  EXPECT_EQ(mojom::Cursor::EAST_RESIZE, mojom::Cursor(cursor_id()));
+  EXPECT_EQ(mojom::Cursor::EAST_RESIZE, cursor());
 
   // Client area
   MoveCursorTo(gfx::Point(25, 25));
-  EXPECT_EQ(mojom::Cursor::IBEAM, mojom::Cursor(cursor_id()));
+  EXPECT_EQ(mojom::Cursor::IBEAM, cursor());
 }
 
 TEST_F(CursorTest, ChangeByClientAreaChange) {
@@ -129,62 +128,58 @@
   win->SetPredefinedCursor(mojom::Cursor::IBEAM);
   EXPECT_EQ(mojom::Cursor::IBEAM, mojom::Cursor(win->cursor()));
   win->SetNonClientCursor(mojom::Cursor::EAST_RESIZE);
-  EXPECT_EQ(mojom::Cursor::EAST_RESIZE,
-            mojom::Cursor(win->non_client_cursor()));
+  EXPECT_EQ(mojom::Cursor::EAST_RESIZE, win->non_client_cursor());
 
   // Non client area before we move.
   MoveCursorTo(gfx::Point(15, 15));
-  EXPECT_EQ(mojom::Cursor::EAST_RESIZE, mojom::Cursor(cursor_id()));
+  EXPECT_EQ(mojom::Cursor::EAST_RESIZE, cursor());
 
   // Changing the client area should cause a change.
   win->SetClientArea(gfx::Insets(1, 1), std::vector<gfx::Rect>());
-  EXPECT_EQ(mojom::Cursor::IBEAM, mojom::Cursor(cursor_id()));
+  EXPECT_EQ(mojom::Cursor::IBEAM, cursor());
 }
 
 TEST_F(CursorTest, NonClientCursorChange) {
   ServerWindow* win = BuildServerWindow();
   win->SetPredefinedCursor(mojom::Cursor::IBEAM);
-  EXPECT_EQ(mojom::Cursor::IBEAM, mojom::Cursor(win->cursor()));
+  EXPECT_EQ(mojom::Cursor::IBEAM, win->cursor());
   win->SetNonClientCursor(mojom::Cursor::EAST_RESIZE);
-  EXPECT_EQ(mojom::Cursor::EAST_RESIZE,
-            mojom::Cursor(win->non_client_cursor()));
+  EXPECT_EQ(mojom::Cursor::EAST_RESIZE, win->non_client_cursor());
 
   MoveCursorTo(gfx::Point(15, 15));
-  EXPECT_EQ(mojom::Cursor::EAST_RESIZE, mojom::Cursor(cursor_id()));
+  EXPECT_EQ(mojom::Cursor::EAST_RESIZE, cursor());
 
   win->SetNonClientCursor(mojom::Cursor::WEST_RESIZE);
-  EXPECT_EQ(mojom::Cursor::WEST_RESIZE, mojom::Cursor(cursor_id()));
+  EXPECT_EQ(mojom::Cursor::WEST_RESIZE, cursor());
 }
 
 TEST_F(CursorTest, IgnoreClientCursorChangeInNonClientArea) {
   ServerWindow* win = BuildServerWindow();
   win->SetPredefinedCursor(mojom::Cursor::IBEAM);
-  EXPECT_EQ(mojom::Cursor::IBEAM, mojom::Cursor(win->cursor()));
+  EXPECT_EQ(mojom::Cursor::IBEAM, win->cursor());
   win->SetNonClientCursor(mojom::Cursor::EAST_RESIZE);
-  EXPECT_EQ(mojom::Cursor::EAST_RESIZE,
-            mojom::Cursor(win->non_client_cursor()));
+  EXPECT_EQ(mojom::Cursor::EAST_RESIZE, win->non_client_cursor());
 
   MoveCursorTo(gfx::Point(15, 15));
-  EXPECT_EQ(mojom::Cursor::EAST_RESIZE, mojom::Cursor(cursor_id()));
+  EXPECT_EQ(mojom::Cursor::EAST_RESIZE, cursor());
 
   win->SetPredefinedCursor(mojom::Cursor::HELP);
-  EXPECT_EQ(mojom::Cursor::EAST_RESIZE, mojom::Cursor(cursor_id()));
+  EXPECT_EQ(mojom::Cursor::EAST_RESIZE, cursor());
 }
 
 TEST_F(CursorTest, NonClientToClientByBoundsChange) {
   ServerWindow* win = BuildServerWindow();
   win->SetPredefinedCursor(mojom::Cursor::IBEAM);
-  EXPECT_EQ(mojom::Cursor::IBEAM, mojom::Cursor(win->cursor()));
+  EXPECT_EQ(mojom::Cursor::IBEAM, win->cursor());
   win->SetNonClientCursor(mojom::Cursor::EAST_RESIZE);
-  EXPECT_EQ(mojom::Cursor::EAST_RESIZE,
-            mojom::Cursor(win->non_client_cursor()));
+  EXPECT_EQ(mojom::Cursor::EAST_RESIZE, win->non_client_cursor());
 
   // Non client area before we move.
   MoveCursorTo(gfx::Point(15, 15));
-  EXPECT_EQ(mojom::Cursor::EAST_RESIZE, mojom::Cursor(cursor_id()));
+  EXPECT_EQ(mojom::Cursor::EAST_RESIZE, cursor());
 
   win->SetBounds(gfx::Rect(0, 0, 30, 30));
-  EXPECT_EQ(mojom::Cursor::IBEAM, mojom::Cursor(cursor_id()));
+  EXPECT_EQ(mojom::Cursor::IBEAM, cursor());
 }
 
 }  // namespace test
diff --git a/services/ui/ws/display.cc b/services/ui/ws/display.cc
index 9d8914a..f148f34 100644
--- a/services/ui/ws/display.cc
+++ b/services/ui/ws/display.cc
@@ -13,6 +13,7 @@
 #include "mojo/common/common_type_converters.h"
 #include "services/shell/public/interfaces/connector.mojom.h"
 #include "services/ui/common/types.h"
+#include "services/ui/public/interfaces/cursor.mojom.h"
 #include "services/ui/ws/display_binding.h"
 #include "services/ui/ws/display_manager.h"
 #include "services/ui/ws/focus_controller.h"
@@ -35,7 +36,7 @@
                  const PlatformDisplayInitParams& platform_display_init_params)
     : window_server_(window_server),
       platform_display_(PlatformDisplay::Create(platform_display_init_params)),
-      last_cursor_(ui::kCursorNone) {
+      last_cursor_(mojom::Cursor::CURSOR_NULL) {
   platform_display_->Init(this);
 
   window_server_->window_manager_window_tree_factory_set()->AddObserver(this);
@@ -220,7 +221,7 @@
   }
 }
 
-void Display::UpdateNativeCursor(int32_t cursor_id) {
+void Display::UpdateNativeCursor(mojom::Cursor cursor_id) {
   if (cursor_id != last_cursor_) {
     platform_display_->SetCursorById(cursor_id);
     last_cursor_ = cursor_id;
diff --git a/services/ui/ws/display.h b/services/ui/ws/display.h
index 0581e7e..027d12b 100644
--- a/services/ui/ws/display.h
+++ b/services/ui/ws/display.h
@@ -145,7 +145,7 @@
   // Called just before |tree| is destroyed.
   void OnWillDestroyTree(WindowTree* tree);
 
-  void UpdateNativeCursor(int32_t cursor_id);
+  void UpdateNativeCursor(mojom::Cursor cursor_id);
 
   // mojom::WindowTreeHost:
   void SetSize(const gfx::Size& size) override;
@@ -206,7 +206,7 @@
   std::unique_ptr<FocusController> focus_controller_;
 
   // The last cursor set. Used to track whether we need to change the cursor.
-  int32_t last_cursor_;
+  mojom::Cursor last_cursor_;
 
   ServerWindowTracker activation_parents_;
 
diff --git a/services/ui/ws/drag_controller.cc b/services/ui/ws/drag_controller.cc
index e6020d8..3e63b4e6 100644
--- a/services/ui/ws/drag_controller.cc
+++ b/services/ui/ws/drag_controller.cc
@@ -4,7 +4,11 @@
 
 #include "services/ui/ws/drag_controller.h"
 
+#include <utility>
+
 #include "base/logging.h"
+#include "services/ui/public/interfaces/cursor.mojom.h"
+#include "services/ui/ws/drag_cursor_updater.h"
 #include "services/ui/ws/drag_source.h"
 #include "services/ui/ws/drag_target_connection.h"
 #include "services/ui/ws/event_dispatcher.h"
@@ -22,30 +26,38 @@
 struct DragController::WindowState {
   // Set to true once we've observed the ServerWindow* that is the key to this
   // instance in |window_state_|.
-  bool observed;
+  bool observed = false;
 
-  // If we're waiting for a response, this is the type of message. TYPE_NONE
-  // means there's no outstanding
-  OperationType waiting_on_reply;
+  // If we're waiting for a response, this is the type of message. NONE means
+  // there's no outstanding
+  OperationType waiting_on_reply = OperationType::NONE;
 
-  // The operation that we'll send off if |waiting_on_reply| isn't TYPE_NONE.
-  Operation queued_operation;
+  // The operation that we'll send off if |waiting_on_reply| isn't NONE.
+  Operation queued_operation = {OperationType::NONE, 0, gfx::Point()};
+
+  // The current set of operations that this window accepts. This gets updated
+  // on each return message.
+  DropEffectBitmask bitmask = 0u;
 };
 
 DragController::DragController(
+    DragCursorUpdater* cursor_updater,
     DragSource* source,
     ServerWindow* source_window,
     DragTargetConnection* source_connection,
     int32_t drag_pointer,
     mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data,
-    uint32_t drag_operations)
+    DropEffectBitmask drag_operations)
     : source_(source),
+      cursor_updater_(cursor_updater),
       drag_operations_(drag_operations),
       drag_pointer_id_(drag_pointer),
+      current_cursor_(ui::mojom::Cursor::NO_DROP),
       source_window_(source_window),
       source_connection_(source_connection),
       mime_data_(std::move(mime_data)),
       weak_factory_(this) {
+  SetCurrentTargetWindow(nullptr);
   EnsureWindowObserved(source_window_);
 }
 
@@ -129,7 +141,8 @@
   called_on_drag_mime_types_.erase(connection);
 }
 
-void DragController::MessageDragCompleted(bool success, uint32_t action_taken) {
+void DragController::MessageDragCompleted(bool success,
+                                          DropEffect action_taken) {
   for (DragTargetConnection* connection : called_on_drag_mime_types_)
     connection->PerformOnDragDropDone();
   called_on_drag_mime_types_.clear();
@@ -149,8 +162,39 @@
   return 2u;
 }
 
+void DragController::SetWindowDropOperations(ServerWindow* window,
+                                             DropEffectBitmask bitmask) {
+  WindowState& state = window_state_[window];
+  state.bitmask = bitmask;
+
+  if (current_target_window_ == window) {
+    current_cursor_ = CursorForEffectBitmask(bitmask);
+    cursor_updater_->OnDragCursorUpdated();
+  }
+}
+
+ui::mojom::Cursor DragController::CursorForEffectBitmask(
+    DropEffectBitmask bitmask) {
+  DropEffectBitmask combined = bitmask & drag_operations_;
+  return combined == ui::mojom::kDropEffectNone
+             ? ui::mojom::Cursor::NO_DROP
+             : ui::mojom::Cursor::COPY;
+}
+
 void DragController::SetCurrentTargetWindow(ServerWindow* current_target) {
   current_target_window_ = current_target;
+
+  if (current_target_window_) {
+    // Immediately set the cursor to the last known set of operations (which
+    // could be none).
+    WindowState& state = window_state_[current_target_window_];
+    current_cursor_ = CursorForEffectBitmask(state.bitmask);
+  } else {
+    // Can't drop in empty areas.
+    current_cursor_ = ui::mojom::Cursor::NO_DROP;
+  }
+
+  cursor_updater_->OnDragCursorUpdated();
 }
 
 void DragController::EnsureWindowObserved(ServerWindow* window) {
@@ -241,7 +285,7 @@
 }
 
 void DragController::OnDragStatusCompleted(const WindowId& id,
-                                           uint32_t bitmask) {
+                                           DropEffectBitmask bitmask) {
   ServerWindow* window = source_->GetWindowById(id);
   if (!window) {
     // The window has been deleted and its queue is empty.
@@ -250,12 +294,11 @@
 
   // We must remove the completed item.
   OnRespondToOperation(window);
-
-  // TODO(erg): |bitmask| is the allowed drag actions at the mouse location. We
-  // should use this data to change the cursor.
+  SetWindowDropOperations(window, bitmask);
 }
 
-void DragController::OnDragDropCompleted(const WindowId& id, uint32_t action) {
+void DragController::OnDragDropCompleted(const WindowId& id,
+                                         DropEffect action) {
   ServerWindow* window = source_->GetWindowById(id);
   if (!window) {
     // The window has been deleted after we sent the drop message. It's really
@@ -277,7 +320,7 @@
   }
 
   if (current_target_window_ == window)
-    current_target_window_ = nullptr;
+    SetCurrentTargetWindow(nullptr);
 
   if (source_window_ == window) {
     source_window_ = nullptr;
diff --git a/services/ui/ws/drag_controller.h b/services/ui/ws/drag_controller.h
index 3b781a4..1517a510 100644
--- a/services/ui/ws/drag_controller.h
+++ b/services/ui/ws/drag_controller.h
@@ -5,8 +5,12 @@
 #ifndef SERVICES_UI_WS_DRAG_CONTROLLER_H_
 #define SERVICES_UI_WS_DRAG_CONTROLLER_H_
 
+#include <map>
+#include <set>
+
 #include "base/memory/weak_ptr.h"
 #include "services/ui/common/types.h"
+#include "services/ui/public/interfaces/cursor.mojom.h"
 #include "services/ui/ws/ids.h"
 #include "services/ui/ws/server_window_observer.h"
 
@@ -17,23 +21,33 @@
 class DragControllerTestApi;
 }
 
+class DragCursorUpdater;
 class DragSource;
 class DragTargetConnection;
 
+// A single ui::mojom::kDropEffect operation.
+using DropEffect = uint32_t;
+
+// A bitmask of ui::mojom::kDropEffect operations.
+using DropEffectBitmask = uint32_t;
+
 // Represents all the data around the current ongoing drag operation.
 //
 // There should only be one instance of this class per userid. The
 // WindowManagerState's EventDispatcher creates and owns this instance.
 class DragController : public ServerWindowObserver {
  public:
-  DragController(DragSource* source,
+  DragController(DragCursorUpdater* cursor_updater,
+                 DragSource* source,
                  ServerWindow* source_window,
                  DragTargetConnection* source_connection,
                  int32_t drag_pointer,
                  mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data,
-                 uint32_t drag_operations);
+                 DropEffectBitmask drag_operations);
   ~DragController() override;
 
+  ui::mojom::Cursor current_cursor() const { return current_cursor_; }
+
   // Cancels the current drag, ie, due to the user pressing Escape.
   void Cancel();
 
@@ -52,7 +66,7 @@
 
   // Notifies all windows we messaged that the drag is finished, and then tell
   // |source| the result.
-  void MessageDragCompleted(bool success, uint32_t action_taken);
+  void MessageDragCompleted(bool success, DropEffect action_taken);
 
   // Returns the number of events on |window|. A value of 1 means that there's
   // a single event outstanding that we're waiting for a response from the
@@ -64,6 +78,14 @@
   // and release ServerWindow observers correctly.
   void SetCurrentTargetWindow(ServerWindow* current_target);
 
+  // Updates the possible cursor effects for |window|. |bitmask| is a
+  // bitmask of the current valid drag operations.
+  void SetWindowDropOperations(ServerWindow* window, DropEffectBitmask bitmask);
+
+  // Returns the ui::mojom::Cursor for the window |bitmask|, adjusted for types
+  // that the drag source allows.
+  ui::mojom::Cursor CursorForEffectBitmask(DropEffectBitmask bitmask);
+
   // Ensure that |window| has an entry in |window_state_| and that we're an
   // observer.
   void EnsureWindowObserved(ServerWindow* window);
@@ -76,8 +98,8 @@
   void OnRespondToOperation(ServerWindow* window);
 
   // Callback methods.
-  void OnDragStatusCompleted(const WindowId& id, uint32_t bitmask);
-  void OnDragDropCompleted(const WindowId& id, uint32_t action);
+  void OnDragStatusCompleted(const WindowId& id, DropEffectBitmask bitmask);
+  void OnDragDropCompleted(const WindowId& id, DropEffect action);
 
   // ServerWindowObserver:
   void OnWindowDestroying(ServerWindow* window) override;
@@ -85,12 +107,18 @@
   // Our owner.
   DragSource* source_;
 
+  // Object to notify about all cursor changes.
+  DragCursorUpdater* cursor_updater_;
+
   // A bit-field of acceptable drag operations offered by the source.
-  const uint32_t drag_operations_;
+  const DropEffectBitmask drag_operations_;
 
   // Only act on pointer events that meet this id.
   const int32_t drag_pointer_id_;
 
+  // The current mouse cursor during the drag.
+  ui::mojom::Cursor current_cursor_;
+
   // Sending OnDragOver() to our |source_| destroys us; there is a period where
   // we have to continue to exist, but not process any more pointer events.
   bool waiting_for_final_drop_response_ = false;
diff --git a/services/ui/ws/drag_controller_unittest.cc b/services/ui/ws/drag_controller_unittest.cc
index 8b9360d..71df3b1 100644
--- a/services/ui/ws/drag_controller_unittest.cc
+++ b/services/ui/ws/drag_controller_unittest.cc
@@ -4,6 +4,12 @@
 
 #include "services/ui/ws/drag_controller.h"
 
+#include <map>
+#include <memory>
+#include <queue>
+#include <utility>
+
+#include "services/ui/public/interfaces/cursor.mojom.h"
 #include "services/ui/ws/drag_source.h"
 #include "services/ui/ws/drag_target_connection.h"
 #include "services/ui/ws/ids.h"
@@ -128,7 +134,9 @@
   std::queue<DragEvent> queued_callbacks_;
 };
 
-class DragControllerTest : public testing::Test, public DragSource {
+class DragControllerTest : public testing::Test,
+                           public DragCursorUpdater,
+                           public DragSource {
  public:
   std::unique_ptr<DragTestWindow> BuildWindow() {
     WindowId id(1, ++window_id_);
@@ -145,8 +153,13 @@
       uint32_t drag_operations) {
     window->PerformOnDragDropStart(mime_data.Clone());
     drag_operation_ = base::MakeUnique<DragController>(
-        this, window->window(), window, PointerEvent::kMousePointerId,
+        this, this, window->window(), window, PointerEvent::kMousePointerId,
         std::move(mime_data), drag_operations);
+
+    // It would be nice if we could just let the observer method fire, but it
+    // fires during the constructor when we haven't assigned the unique_ptr
+    // yet.
+    cursor_ = ui::mojom::Cursor(drag_operation_->current_cursor());
   }
 
   void DispatchDrag(DragTestWindow* window,
@@ -187,6 +200,8 @@
     return drag_completed_value_;
   }
 
+  ui::mojom::Cursor cursor() { return cursor_; }
+
  private:
   // Overridden from testing::Test:
   void SetUp() override {
@@ -210,6 +225,12 @@
     testing::Test::TearDown();
   }
 
+  // Overridden from DragCursorUpdater:
+  void OnDragCursorUpdated() override {
+    if (drag_operation_)
+      cursor_ = ui::mojom::Cursor(drag_operation_->current_cursor());
+  }
+
   // Overridden from DragControllerSource:
   void OnDragCompleted(bool success, uint32_t action_taken) override {
     drag_completed_action_ = action_taken;
@@ -233,6 +254,8 @@
 
   int window_id_ = 3;
 
+  ui::mojom::Cursor cursor_;
+
   std::map<WindowId, ServerWindow*> server_window_by_id_;
   std::map<ServerWindow*, DragTargetConnection*> connection_by_window_;
 
@@ -255,10 +278,15 @@
   StartDragOperation(std::move(mime_data), window.get(),
                      ui::mojom::kDropEffectMove);
 
+  EXPECT_EQ(ui::mojom::Cursor::NO_DROP, cursor());
+
   DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(1, 1));
   EXPECT_EQ(QueuedType::ENTER, window->queue_response_type());
   window->Respond(true);
 
+  // (Even though we're doing a move, the cursor name is COPY.)
+  EXPECT_EQ(ui::mojom::Cursor::COPY, cursor());
+
   DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(2, 2));
   EXPECT_EQ(QueuedType::OVER, window->queue_response_type());
   window->Respond(true);
@@ -522,6 +550,31 @@
   EXPECT_FALSE(drag_completed_value().has_value());
 }
 
+TEST_F(DragControllerTest, TargetWindowClosedResetsCursor) {
+  std::unique_ptr<DragTestWindow> window1 = BuildWindow();
+  std::unique_ptr<DragTestWindow> window2 = BuildWindow();
+  mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data;
+  StartDragOperation(std::move(mime_data), window1.get(),
+                     ui::mojom::kDropEffectMove);
+  EXPECT_EQ(ui::mojom::Cursor::NO_DROP, cursor());
+
+  // Send some events to |window|.
+  DispatchDrag(window2.get(), false, ui::EF_LEFT_MOUSE_BUTTON,
+               gfx::Point(1, 1));
+  EXPECT_EQ(QueuedType::ENTER, window2->queue_response_type());
+  window2->Respond(true);
+  DispatchDrag(window2.get(), false, ui::EF_LEFT_MOUSE_BUTTON,
+               gfx::Point(1, 1));
+  window2->Respond(true);
+  EXPECT_EQ(ui::mojom::Cursor::COPY, cursor());
+
+  // Force the destruction of |window.window|.
+  window2.reset();
+
+  // The cursor no loner indicates that it can drop on |window2|.
+  EXPECT_EQ(ui::mojom::Cursor::NO_DROP, cursor());
+}
+
 TEST_F(DragControllerTest, SourceWindowClosedWhileDrag) {
   std::unique_ptr<DragTestWindow> window1 = BuildWindow();
   std::unique_ptr<DragTestWindow> window2 = BuildWindow();
@@ -531,7 +584,7 @@
 
   test::DragControllerTestApi api(drag_operation());
 
-  // Send some events to |window|.
+  // Send some events to |windoww|.
   DispatchDrag(window2.get(), false, ui::EF_LEFT_MOUSE_BUTTON,
                gfx::Point(1, 1));
   EXPECT_EQ(QueuedType::ENTER, window2->queue_response_type());
@@ -540,7 +593,7 @@
 
   ServerWindow* server_window = window2->window();
 
-  // Ensure that DragController is waiting for a response from |window|.
+  // Ensure that DragController is waiting for a response from |window2|.
   EXPECT_EQ(2u, api.GetSizeOfQueueForWindow(server_window));
   EXPECT_EQ(server_window, api.GetCurrentTarget());
 
@@ -609,9 +662,58 @@
   ASSERT_EQ(0u, window->queue_size());
 }
 
-// TODO(erg): Add a test to ensure windows that the cursor isn't over
-// responding to messages don't change the cursor when we have cursor handling
-// code.
+TEST_F(DragControllerTest, RejectingWindowHasProperCursor) {
+  std::unique_ptr<DragTestWindow> window = BuildWindow();
+  mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data;
+  StartDragOperation(std::move(mime_data), window.get(),
+                     ui::mojom::kDropEffectMove);
+
+  EXPECT_EQ(ui::mojom::Cursor::NO_DROP, cursor());
+
+  DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(1, 1));
+  EXPECT_EQ(QueuedType::ENTER, window->queue_response_type());
+  window->Respond(true);
+
+  EXPECT_EQ(ui::mojom::Cursor::COPY, cursor());
+
+  DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(2, 2));
+  EXPECT_EQ(QueuedType::OVER, window->queue_response_type());
+
+  // At this point, we respond with no available drag actions at this pixel.
+  window->Respond(false);
+  EXPECT_EQ(ui::mojom::Cursor::NO_DROP, cursor());
+}
+
+TEST_F(DragControllerTest, ResopnseFromOtherWindowDoesntChangeCursor) {
+  std::unique_ptr<DragTestWindow> window1 = BuildWindow();
+  std::unique_ptr<DragTestWindow> window2 = BuildWindow();
+  mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data;
+  StartDragOperation(std::move(mime_data), window1.get(),
+                     ui::mojom::kDropEffectMove);
+
+  // Send some events to |window2|.
+  DispatchDrag(window2.get(), false, ui::EF_LEFT_MOUSE_BUTTON,
+               gfx::Point(1, 1));
+  EXPECT_EQ(QueuedType::ENTER, window2->queue_response_type());
+  DispatchDrag(window2.get(), false, ui::EF_LEFT_MOUSE_BUTTON,
+               gfx::Point(1, 1));
+
+  EXPECT_EQ(ui::mojom::Cursor::NO_DROP, cursor());
+
+  // Now enter |window1|, and respond.
+  DispatchDrag(window1.get(), false, ui::EF_LEFT_MOUSE_BUTTON,
+               gfx::Point(5, 5));
+  EXPECT_EQ(QueuedType::ENTER, window1->queue_response_type());
+  window1->Respond(true);
+
+  EXPECT_EQ(ui::mojom::Cursor::COPY, cursor());
+
+  // Window 2 responding negatively to its queued messages shouldn't change the
+  // cursor.
+  window2->Respond(false);
+
+  EXPECT_EQ(ui::mojom::Cursor::COPY, cursor());
+}
 
 }  // namespace ws
 }  // namespace ui
diff --git a/services/ui/ws/drag_cursor_updater.h b/services/ui/ws/drag_cursor_updater.h
new file mode 100644
index 0000000..dcc945a
--- /dev/null
+++ b/services/ui/ws/drag_cursor_updater.h
@@ -0,0 +1,23 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_UI_WS_DRAG_CURSOR_UPDATER_H_
+#define SERVICES_UI_WS_DRAG_CURSOR_UPDATER_H_
+
+namespace ui {
+namespace ws {
+
+// An interface for the DragController to signal that the cursor has changed.
+class DragCursorUpdater {
+ public:
+  virtual void OnDragCursorUpdated() = 0;
+
+ protected:
+  virtual ~DragCursorUpdater() {}
+};
+
+}  // namespace ws
+}  // namespace ui
+
+#endif  // SERVICES_UI_WS_DRAG_CURSOR_UPDATER_H_
diff --git a/services/ui/ws/event_dispatcher.cc b/services/ui/ws/event_dispatcher.cc
index fb554ee1..d6536cc 100644
--- a/services/ui/ws/event_dispatcher.cc
+++ b/services/ui/ws/event_dispatcher.cc
@@ -103,7 +103,12 @@
   delegate_->OnMouseCursorLocationChanged(screen_location);
 }
 
-bool EventDispatcher::GetCurrentMouseCursor(int32_t* cursor_out) {
+bool EventDispatcher::GetCurrentMouseCursor(ui::mojom::Cursor* cursor_out) {
+  if (drag_controller_) {
+    *cursor_out = drag_controller_->current_cursor();
+    return true;
+  }
+
   if (!mouse_cursor_source_window_)
     return false;
 
@@ -172,7 +177,7 @@
     uint32_t drag_operations) {
   CancelImplicitCaptureExcept(nullptr);
   drag_controller_ = base::MakeUnique<DragController>(
-      drag_source, window, source_connection, drag_pointer,
+      this, drag_source, window, source_connection, drag_pointer,
       std::move(mime_data), drag_operations);
 }
 
@@ -612,5 +617,9 @@
     mouse_cursor_source_window_ = nullptr;
 }
 
+void EventDispatcher::OnDragCursorUpdated() {
+  delegate_->UpdateNativeCursorFromDispatcher();
+}
+
 }  // namespace ws
 }  // namespace ui
diff --git a/services/ui/ws/event_dispatcher.h b/services/ui/ws/event_dispatcher.h
index aa144e90c..472a0c0 100644
--- a/services/ui/ws/event_dispatcher.h
+++ b/services/ui/ws/event_dispatcher.h
@@ -13,7 +13,9 @@
 
 #include "base/macros.h"
 #include "services/ui/common/types.h"
+#include "services/ui/public/interfaces/cursor.mojom.h"
 #include "services/ui/public/interfaces/event_matcher.mojom.h"
+#include "services/ui/ws/drag_cursor_updater.h"
 #include "services/ui/ws/modal_window_controller.h"
 #include "services/ui/ws/server_window_observer.h"
 #include "ui/gfx/geometry/rect_f.h"
@@ -38,7 +40,7 @@
 }
 
 // Handles dispatching events to the right location as well as updating focus.
-class EventDispatcher : public ServerWindowObserver {
+class EventDispatcher : public ServerWindowObserver, public DragCursorUpdater {
  public:
   enum class AcceleratorMatchPhase {
     // Both pre and post should be considered.
@@ -63,7 +65,7 @@
 
   // If we still have the window of the last mouse move, returns true and sets
   // the current cursor to use to |cursor_out|.
-  bool GetCurrentMouseCursor(int32_t* cursor_out);
+  bool GetCurrentMouseCursor(ui::mojom::Cursor* cursor_out);
 
   // |capture_window_| will receive all input. See window_tree.mojom for
   // details.
@@ -231,6 +233,9 @@
   void OnWindowVisibilityChanged(ServerWindow* window) override;
   void OnWindowDestroyed(ServerWindow* window) override;
 
+  // DragCursorUpdater:
+  void OnDragCursorUpdated() override;
+
   EventDispatcherDelegate* delegate_;
 
   ServerWindow* capture_window_;
diff --git a/services/ui/ws/event_dispatcher_delegate.h b/services/ui/ws/event_dispatcher_delegate.h
index 82a5216..eb0c51a 100644
--- a/services/ui/ws/event_dispatcher_delegate.h
+++ b/services/ui/ws/event_dispatcher_delegate.h
@@ -46,6 +46,10 @@
   // longer a ServerWindow holding capture.
   virtual void ReleaseNativeCapture() = 0;
 
+  // Called when EventDispatcher has a new value for the cursor and our
+  // delegate should perform the native updates.
+  virtual void UpdateNativeCursorFromDispatcher() = 0;
+
   // Called when |window| has lost capture. The native display may still be
   // holding capture. The delegate should not change native display capture.
   // ReleaseNativeCapture() is invoked if appropriate.
diff --git a/services/ui/ws/event_dispatcher_unittest.cc b/services/ui/ws/event_dispatcher_unittest.cc
index 898d91b..0348fea 100644
--- a/services/ui/ws/event_dispatcher_unittest.cc
+++ b/services/ui/ws/event_dispatcher_unittest.cc
@@ -120,6 +120,7 @@
     if (delegate_)
       delegate_->ReleaseCapture();
   }
+  void UpdateNativeCursorFromDispatcher() override {}
   void OnCaptureChanged(ServerWindow* new_capture_window,
                         ServerWindow* old_capture_window) override {
     lost_capture_window_ = old_capture_window;
diff --git a/services/ui/ws/platform_display.cc b/services/ui/ws/platform_display.cc
index a039209..367bdf7 100644
--- a/services/ui/ws/platform_display.cc
+++ b/services/ui/ws/platform_display.cc
@@ -132,14 +132,14 @@
   platform_window_->ReleaseCapture();
 }
 
-void DefaultPlatformDisplay::SetCursorById(int32_t cursor_id) {
+void DefaultPlatformDisplay::SetCursorById(mojom::Cursor cursor_id) {
 #if !defined(OS_ANDROID)
   // TODO(erg): This still isn't sufficient, and will only use native cursors
   // that chrome would use, not custom image cursors. For that, we should
   // delegate to the window manager to load images from resource packs.
   //
   // We probably also need to deal with different DPIs.
-  ui::Cursor cursor(cursor_id);
+  ui::Cursor cursor(static_cast<int32_t>(cursor_id));
   cursor_loader_->SetPlatformCursor(&cursor);
   platform_window_->SetCursor(cursor.platform());
 #endif
diff --git a/services/ui/ws/platform_display.h b/services/ui/ws/platform_display.h
index 633d9c6..27f96010 100644
--- a/services/ui/ws/platform_display.h
+++ b/services/ui/ws/platform_display.h
@@ -15,6 +15,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
 #include "build/build_config.h"
+#include "services/ui/public/interfaces/cursor.mojom.h"
 #include "services/ui/public/interfaces/window_manager.mojom.h"
 #include "services/ui/public/interfaces/window_manager_constants.mojom.h"
 #include "services/ui/public/interfaces/window_tree.mojom.h"
@@ -76,7 +77,7 @@
 
   virtual void ReleaseCapture() = 0;
 
-  virtual void SetCursorById(int32_t cursor) = 0;
+  virtual void SetCursorById(mojom::Cursor cursor) = 0;
 
   virtual display::Display::Rotation GetRotation() = 0;
 
@@ -129,7 +130,7 @@
   void SetTitle(const base::string16& title) override;
   void SetCapture() override;
   void ReleaseCapture() override;
-  void SetCursorById(int32_t cursor) override;
+  void SetCursorById(mojom::Cursor cursor) override;
   float GetDeviceScaleFactor() override;
   display::Display::Rotation GetRotation() override;
   void UpdateTextInputState(const ui::TextInputState& state) override;
diff --git a/services/ui/ws/server_window.cc b/services/ui/ws/server_window.cc
index d03a23b..8384022 100644
--- a/services/ui/ws/server_window.cc
+++ b/services/ui/ws/server_window.cc
@@ -288,7 +288,7 @@
   cursor_id_ = value;
   FOR_EACH_OBSERVER(
       ServerWindowObserver, observers_,
-      OnWindowPredefinedCursorChanged(this, static_cast<int32_t>(value)));
+      OnWindowPredefinedCursorChanged(this, value));
 }
 
 void ServerWindow::SetNonClientCursor(ui::mojom::Cursor value) {
@@ -297,7 +297,7 @@
   non_client_cursor_id_ = value;
   FOR_EACH_OBSERVER(
       ServerWindowObserver, observers_,
-      OnWindowNonClientCursorChanged(this, static_cast<int32_t>(value)));
+      OnWindowNonClientCursorChanged(this, value));
 }
 
 void ServerWindow::SetTransform(const gfx::Transform& transform) {
diff --git a/services/ui/ws/server_window.h b/services/ui/ws/server_window.h
index 4e0d9fc..89109599 100644
--- a/services/ui/ws/server_window.h
+++ b/services/ui/ws/server_window.h
@@ -89,9 +89,9 @@
   bool can_accept_drops() const { return accepts_drops_; }
   void SetCanAcceptDrops(bool accepts_drags);
 
-  int32_t cursor() const { return static_cast<int32_t>(cursor_id_); }
-  int32_t non_client_cursor() const {
-    return static_cast<int32_t>(non_client_cursor_id_);
+  ui::mojom::Cursor cursor() const { return cursor_id_; }
+  ui::mojom::Cursor non_client_cursor() const {
+    return non_client_cursor_id_;
   }
 
   const ServerWindow* parent() const { return parent_; }
diff --git a/services/ui/ws/server_window_observer.h b/services/ui/ws/server_window_observer.h
index 7ffae1f..f57f0df2 100644
--- a/services/ui/ws/server_window_observer.h
+++ b/services/ui/ws/server_window_observer.h
@@ -10,6 +10,7 @@
 #include <string>
 #include <vector>
 
+#include "services/ui/public/interfaces/cursor.mojom.h"
 #include "services/ui/public/interfaces/mus_constants.mojom.h"
 
 namespace gfx {
@@ -66,9 +67,9 @@
                                       float new_opacity) {}
 
   virtual void OnWindowPredefinedCursorChanged(ServerWindow* window,
-                                               int32_t cursor_id) {}
+                                               mojom::Cursor cursor_id) {}
   virtual void OnWindowNonClientCursorChanged(ServerWindow* window,
-                                              int32_t cursor_id) {}
+                                              mojom::Cursor cursor_id) {}
 
   virtual void OnWindowTextInputStateChanged(ServerWindow* window,
                                              const ui::TextInputState& state) {}
diff --git a/services/ui/ws/test_utils.cc b/services/ui/ws/test_utils.cc
index 6aac7a8..cc254c1 100644
--- a/services/ui/ws/test_utils.cc
+++ b/services/ui/ws/test_utils.cc
@@ -10,6 +10,7 @@
 #include "cc/output/copy_output_request.h"
 #include "gpu/ipc/client/gpu_channel_host.h"
 #include "services/shell/public/interfaces/connector.mojom.h"
+#include "services/ui/public/interfaces/cursor.mojom.h"
 #include "services/ui/surfaces/surfaces_state.h"
 #include "services/ui/ws/display_binding.h"
 #include "services/ui/ws/display_manager.h"
@@ -30,10 +31,10 @@
  public:
   explicit TestPlatformDisplay(int64_t id,
                                bool is_primary,
-                               int32_t* cursor_id_storage)
+                               mojom::Cursor* cursor_storage)
       : id_(id),
         is_primary_(is_primary),
-        cursor_id_storage_(cursor_id_storage) {
+        cursor_storage_(cursor_storage) {
     display_metrics_.bounds = gfx::Rect(0, 0, 400, 300);
     display_metrics_.device_scale_factor = 1.f;
   }
@@ -50,7 +51,9 @@
   void SetTitle(const base::string16& title) override {}
   void SetCapture() override {}
   void ReleaseCapture() override {}
-  void SetCursorById(int32_t cursor) override { *cursor_id_storage_ = cursor; }
+  void SetCursorById(mojom::Cursor cursor) override {
+    *cursor_storage_ = cursor;
+  }
   display::Display::Rotation GetRotation() override {
     return display::Display::Rotation::ROTATE_0;
   }
@@ -72,7 +75,7 @@
 
   int64_t id_;
   bool is_primary_;
-  int32_t* cursor_id_storage_;
+  mojom::Cursor* cursor_storage_;
 
   DISALLOW_COPY_AND_ASSIGN(TestPlatformDisplay);
 };
@@ -113,8 +116,8 @@
 const int64_t TestPlatformDisplayFactory::kFirstDisplayId = 1;
 
 TestPlatformDisplayFactory::TestPlatformDisplayFactory(
-    int32_t* cursor_id_storage)
-    : cursor_id_storage_(cursor_id_storage),
+    mojom::Cursor* cursor_storage)
+    : cursor_storage_(cursor_storage),
       next_display_id_(kFirstDisplayId) {}
 
 TestPlatformDisplayFactory::~TestPlatformDisplayFactory() {}
@@ -122,7 +125,7 @@
 PlatformDisplay* TestPlatformDisplayFactory::CreatePlatformDisplay() {
   bool is_primary = (next_display_id_ == kFirstDisplayId);
   return new TestPlatformDisplay(next_display_id_++, is_primary,
-                                 cursor_id_storage_);
+                                 cursor_storage_);
 }
 
 // TestFrameGeneratorDelegate -------------------------------------------------
@@ -464,7 +467,8 @@
 // WindowServerTestHelper  ---------------------------------------------------
 
 WindowServerTestHelper::WindowServerTestHelper()
-    : cursor_id_(0), platform_display_factory_(&cursor_id_) {
+    : cursor_id_(mojom::Cursor::CURSOR_NULL),
+      platform_display_factory_(&cursor_id_) {
   PlatformDisplay::set_factory_for_testing(&platform_display_factory_);
   window_server_ = base::MakeUnique<WindowServer>(&window_server_delegate_);
   window_server_delegate_.set_window_server(window_server_.get());
diff --git a/services/ui/ws/test_utils.h b/services/ui/ws/test_utils.h
index f1cf568..29112de7 100644
--- a/services/ui/ws/test_utils.h
+++ b/services/ui/ws/test_utils.h
@@ -261,14 +261,14 @@
  public:
   static const int64_t kFirstDisplayId;
 
-  explicit TestPlatformDisplayFactory(int32_t* cursor_id_storage);
+  explicit TestPlatformDisplayFactory(mojom::Cursor* cursor_storage);
   ~TestPlatformDisplayFactory();
 
   // PlatformDisplayFactory:
   PlatformDisplay* CreatePlatformDisplay() override;
 
  private:
-  int32_t* cursor_id_storage_;
+  mojom::Cursor* cursor_storage_;
   int64_t next_display_id_;
 
   DISALLOW_COPY_AND_ASSIGN(TestPlatformDisplayFactory);
@@ -575,7 +575,7 @@
   ~WindowServerTestHelper();
 
   WindowServer* window_server() { return window_server_.get(); }
-  int32_t cursor_id() const { return cursor_id_; }
+  mojom::Cursor cursor() const { return cursor_id_; }
 
   TestWindowServerDelegate* window_server_delegate() {
     return &window_server_delegate_;
@@ -583,7 +583,7 @@
   base::MessageLoop* message_loop() { return &message_loop_; }
 
  private:
-  int32_t cursor_id_;
+  mojom::Cursor cursor_id_;
   TestPlatformDisplayFactory platform_display_factory_;
   TestWindowServerDelegate window_server_delegate_;
   std::unique_ptr<WindowServer> window_server_;
@@ -617,7 +617,7 @@
   // Sets the task runner for |message_loop_|
   void SetTaskRunner(scoped_refptr<base::SingleThreadTaskRunner> task_runner);
 
-  int32_t cursor_id() const { return ws_test_helper_.cursor_id(); }
+  mojom::Cursor cursor() const { return ws_test_helper_.cursor(); }
   Display* display() { return display_; }
   TestWindowTreeBinding* last_binding() {
     return ws_test_helper_.window_server_delegate()->last_binding();
diff --git a/services/ui/ws/window_manager_state.cc b/services/ui/ws/window_manager_state.cc
index 698ccf1..9dfd741 100644
--- a/services/ui/ws/window_manager_state.cc
+++ b/services/ui/ws/window_manager_state.cc
@@ -189,6 +189,7 @@
 
 void WindowManagerState::EndDragDrop() {
   event_dispatcher_.EndDragDrop();
+  UpdateNativeCursorFromDispatcher();
 }
 
 void WindowManagerState::AddSystemModalWindow(ServerWindow* window) {
@@ -413,13 +414,7 @@
 
   if (event.IsMousePointerEvent()) {
     DCHECK(event_dispatcher_.mouse_cursor_source_window());
-
-    int32_t cursor_id = 0;
-    if (event_dispatcher_.GetCurrentMouseCursor(&cursor_id)) {
-      WindowManagerDisplayRoot* display_root =
-          display_manager()->GetWindowManagerDisplayRoot(target);
-      display_root->display()->UpdateNativeCursor(cursor_id);
-    }
+    UpdateNativeCursorFromDispatcher();
   }
 
   event_dispatch_phase_ = EventDispatchPhase::TARGET;
@@ -531,6 +526,14 @@
   platform_display_with_capture_ = nullptr;
 }
 
+void WindowManagerState::UpdateNativeCursorFromDispatcher() {
+  ui::mojom::Cursor cursor_id = mojom::Cursor::CURSOR_NULL;
+  if (event_dispatcher_.GetCurrentMouseCursor(&cursor_id)) {
+    for (Display* display : display_manager()->displays())
+      display->UpdateNativeCursor(cursor_id);
+  }
+}
+
 void WindowManagerState::OnCaptureChanged(ServerWindow* new_capture,
                                           ServerWindow* old_capture) {
   window_server()->ProcessCaptureChanged(new_capture, old_capture);
diff --git a/services/ui/ws/window_manager_state.h b/services/ui/ws/window_manager_state.h
index 95e6b1b1..13f803b 100644
--- a/services/ui/ws/window_manager_state.h
+++ b/services/ui/ws/window_manager_state.h
@@ -215,6 +215,7 @@
   ServerWindow* GetFocusedWindowForEventDispatcher() override;
   void SetNativeCapture(ServerWindow* window) override;
   void ReleaseNativeCapture() override;
+  void UpdateNativeCursorFromDispatcher() override;
   void OnCaptureChanged(ServerWindow* new_capture,
                         ServerWindow* old_capture) override;
   void OnMouseCursorLocationChanged(const gfx::Point& point) override;
diff --git a/services/ui/ws/window_server.cc b/services/ui/ws/window_server.cc
index 5224e06..1a878b9e 100644
--- a/services/ui/ws/window_server.cc
+++ b/services/ui/ws/window_server.cc
@@ -420,8 +420,8 @@
     pair.second->ProcessWindowDeleted(window, IsOperationSource(pair.first));
 }
 
-void WindowServer::ProcessWillChangeWindowPredefinedCursor(ServerWindow* window,
-                                                           int32_t cursor_id) {
+void WindowServer::ProcessWillChangeWindowPredefinedCursor(
+    ServerWindow* window, mojom::Cursor cursor_id) {
   for (auto& pair : tree_map_) {
     pair.second->ProcessCursorChanged(window, cursor_id,
                                       IsOperationSource(pair.first));
@@ -580,7 +580,7 @@
     EventDispatcher* event_dispatcher =
         display_root->window_manager_state()->event_dispatcher();
     event_dispatcher->UpdateCursorProviderByLastKnownLocation();
-    int32_t cursor_id = 0;
+    mojom::Cursor cursor_id = mojom::Cursor::CURSOR_NULL;
     if (event_dispatcher->GetCurrentMouseCursor(&cursor_id))
       display_root->display()->UpdateNativeCursor(cursor_id);
   }
@@ -598,7 +598,7 @@
     return;
 
   event_dispatcher->UpdateNonClientAreaForCurrentWindow();
-  int32_t cursor_id = 0;
+  mojom::Cursor cursor_id = mojom::Cursor::CURSOR_NULL;
   if (event_dispatcher->GetCurrentMouseCursor(&cursor_id))
     display_root->display()->UpdateNativeCursor(cursor_id);
 }
@@ -744,7 +744,7 @@
 }
 
 void WindowServer::OnWindowPredefinedCursorChanged(ServerWindow* window,
-                                                   int32_t cursor_id) {
+                                                   mojom::Cursor cursor_id) {
   if (in_destructor_)
     return;
 
@@ -754,7 +754,7 @@
 }
 
 void WindowServer::OnWindowNonClientCursorChanged(ServerWindow* window,
-                                                  int32_t cursor_id) {
+                                                  mojom::Cursor cursor_id) {
   if (in_destructor_)
     return;
 
diff --git a/services/ui/ws/window_server.h b/services/ui/ws/window_server.h
index 9eedec17..320bb3f 100644
--- a/services/ui/ws/window_server.h
+++ b/services/ui/ws/window_server.h
@@ -193,7 +193,7 @@
                             const mojom::OrderDirection direction);
   void ProcessWindowDeleted(ServerWindow* window);
   void ProcessWillChangeWindowPredefinedCursor(ServerWindow* window,
-                                               int32_t cursor_id);
+                                               mojom::Cursor cursor_id);
 
   // Sends an |event| to all WindowTrees belonging to |user_id| that might be
   // observing events. Skips |ignore_tree| if it is non-null. |target_window| is
@@ -320,9 +320,9 @@
       const std::string& name,
       const std::vector<uint8_t>* new_data) override;
   void OnWindowPredefinedCursorChanged(ServerWindow* window,
-                                       int32_t cursor_id) override;
+                                       mojom::Cursor cursor_id) override;
   void OnWindowNonClientCursorChanged(ServerWindow* window,
-                                      int32_t cursor_id) override;
+                                      mojom::Cursor cursor_id) override;
   void OnWindowTextInputStateChanged(ServerWindow* window,
                                      const ui::TextInputState& state) override;
   void OnTransientWindowAdded(ServerWindow* window,
diff --git a/services/ui/ws/window_tree.cc b/services/ui/ws/window_tree.cc
index 870e22b..c3bb743 100644
--- a/services/ui/ws/window_tree.cc
+++ b/services/ui/ws/window_tree.cc
@@ -699,7 +699,7 @@
 }
 
 void WindowTree::ProcessCursorChanged(const ServerWindow* window,
-                                      int32_t cursor_id,
+                                      mojom::Cursor cursor_id,
                                       bool originated_change) {
   if (originated_change)
     return;
@@ -707,8 +707,7 @@
   if (!IsWindowKnown(window, &client_window_id))
     return;
 
-  client()->OnWindowPredefinedCursorChanged(client_window_id.id,
-                                            mojom::Cursor(cursor_id));
+  client()->OnWindowPredefinedCursorChanged(client_window_id.id, cursor_id);
 }
 
 void WindowTree::ProcessFocusChanged(const ServerWindow* old_focused_window,
diff --git a/services/ui/ws/window_tree.h b/services/ui/ws/window_tree.h
index 8fdd7f8..4268d0e 100644
--- a/services/ui/ws/window_tree.h
+++ b/services/ui/ws/window_tree.h
@@ -243,7 +243,7 @@
                                    float new_opacity,
                                    bool originated_change);
   void ProcessCursorChanged(const ServerWindow* window,
-                            int32_t cursor_id,
+                            mojom::Cursor cursor_id,
                             bool originated_change);
   void ProcessFocusChanged(const ServerWindow* old_focused_window,
                            const ServerWindow* new_focused_window);
diff --git a/services/ui/ws/window_tree_unittest.cc b/services/ui/ws/window_tree_unittest.cc
index 9cddc174..b40f659 100644
--- a/services/ui/ws/window_tree_unittest.cc
+++ b/services/ui/ws/window_tree_unittest.cc
@@ -131,8 +131,7 @@
   ~WindowTreeTest() override {}
 
   ui::mojom::Cursor cursor_id() {
-    return static_cast<ui::mojom::Cursor>(
-        window_event_targeting_helper_.cursor_id());
+    return window_event_targeting_helper_.cursor();
   }
   Display* display() { return window_event_targeting_helper_.display(); }
   TestWindowTreeBinding* last_binding() {
diff --git a/services/video_capture/BUILD.gn b/services/video_capture/BUILD.gn
index 14ee313..1670a83 100644
--- a/services/video_capture/BUILD.gn
+++ b/services/video_capture/BUILD.gn
@@ -39,6 +39,8 @@
     "device_client_mojo_to_media_adapter.h",
     "device_mock_to_media_adapter.cc",
     "device_mock_to_media_adapter.h",
+    "mojo_media_conversions.cc",
+    "mojo_media_conversions.h",
     "video_capture_device_factory_impl.cc",
     "video_capture_device_factory_impl.h",
     "video_capture_device_proxy_impl.cc",
diff --git a/services/video_capture/mojo_media_conversions.cc b/services/video_capture/mojo_media_conversions.cc
new file mode 100644
index 0000000..276baf5a
--- /dev/null
+++ b/services/video_capture/mojo_media_conversions.cc
@@ -0,0 +1,68 @@
+// 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.
+
+#include "services/video_capture/mojo_media_conversions.h"
+
+namespace video_capture {
+
+media::VideoCaptureFormat ConvertFromMojoToMedia(
+    mojom::VideoCaptureFormatPtr format) {
+  media::VideoCaptureFormat result;
+  result.pixel_format = ConvertFromMojoToMedia(format->pixel_format);
+  result.pixel_storage = ConvertFromMojoToMedia(format->pixel_storage);
+  result.frame_size.SetSize(format->frame_size.width(),
+                            format->frame_size.height());
+  result.frame_rate = format->frame_rate;
+  return result;
+}
+
+media::VideoPixelFormat ConvertFromMojoToMedia(
+    media::mojom::VideoFormat format) {
+  // Since there are static_asserts in place in
+  // media/mojo/common/media_type_converters.cc to guarantee equality of the
+  // underlying representations, we can simply static_cast to convert.
+  return static_cast<media::VideoPixelFormat>(format);
+}
+
+media::VideoPixelStorage ConvertFromMojoToMedia(
+    mojom::VideoPixelStorage storage) {
+  switch (storage) {
+    case mojom::VideoPixelStorage::CPU:
+      return media::PIXEL_STORAGE_CPU;
+    case mojom::VideoPixelStorage::GPUMEMORYBUFFER:
+      return media::PIXEL_STORAGE_GPUMEMORYBUFFER;
+  }
+  NOTREACHED();
+  return media::PIXEL_STORAGE_CPU;
+}
+
+media::ResolutionChangePolicy ConvertFromMojoToMedia(
+    mojom::ResolutionChangePolicy policy) {
+  switch (policy) {
+    case mojom::ResolutionChangePolicy::FIXED_RESOLUTION:
+      return media::RESOLUTION_POLICY_FIXED_RESOLUTION;
+    case mojom::ResolutionChangePolicy::FIXED_ASPECT_RATIO:
+      return media::RESOLUTION_POLICY_FIXED_ASPECT_RATIO;
+    case mojom::ResolutionChangePolicy::ANY_WITHIN_LIMIT:
+      return media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT;
+  }
+  NOTREACHED();
+  return media::RESOLUTION_POLICY_FIXED_RESOLUTION;
+}
+
+media::PowerLineFrequency ConvertFromMojoToMedia(
+    mojom::PowerLineFrequency frequency) {
+  switch (frequency) {
+    case mojom::PowerLineFrequency::DEFAULT:
+      return media::PowerLineFrequency::FREQUENCY_DEFAULT;
+    case mojom::PowerLineFrequency::HZ_50:
+      return media::PowerLineFrequency::FREQUENCY_50HZ;
+    case mojom::PowerLineFrequency::HZ_60:
+      return media::PowerLineFrequency::FREQUENCY_60HZ;
+  }
+  NOTREACHED();
+  return media::PowerLineFrequency::FREQUENCY_DEFAULT;
+}
+
+}  // namespace video_capture
diff --git a/services/video_capture/mojo_media_conversions.h b/services/video_capture/mojo_media_conversions.h
new file mode 100644
index 0000000..f27819b
--- /dev/null
+++ b/services/video_capture/mojo_media_conversions.h
@@ -0,0 +1,31 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_VIDEO_CAPTURE_MOJO_MEDIA_CONVERSIONS_H_
+#define SERVICES_VIDEO_CAPTURE_MOJO_MEDIA_CONVERSIONS_H_
+
+#include "media/capture/video/video_capture_device.h"
+#include "services/video_capture/public/interfaces/video_capture_device_factory.mojom.h"
+#include "services/video_capture/public/interfaces/video_capture_device_proxy.mojom.h"
+#include "services/video_capture/public/interfaces/video_capture_format.mojom.h"
+
+namespace video_capture {
+
+// TODO(chfremer): Consider using Mojo type mapping instead of conversion
+// methods. https://crbug.com/642387
+
+media::VideoCaptureFormat ConvertFromMojoToMedia(
+    mojom::VideoCaptureFormatPtr format);
+media::VideoPixelFormat ConvertFromMojoToMedia(
+    media::mojom::VideoFormat format);
+media::VideoPixelStorage ConvertFromMojoToMedia(
+    mojom::VideoPixelStorage storage);
+media::ResolutionChangePolicy ConvertFromMojoToMedia(
+    mojom::ResolutionChangePolicy policy);
+media::PowerLineFrequency ConvertFromMojoToMedia(
+    mojom::PowerLineFrequency frequency);
+
+}  // namespace video_capture
+
+#endif  // SERVICES_VIDEO_CAPTURE_MOJO_MEDIA_CONVERSIONS_H_
diff --git a/services/video_capture/video_capture_device_proxy_impl.cc b/services/video_capture/video_capture_device_proxy_impl.cc
index bb134db..2fc33b17 100644
--- a/services/video_capture/video_capture_device_proxy_impl.cc
+++ b/services/video_capture/video_capture_device_proxy_impl.cc
@@ -4,6 +4,7 @@
 
 #include "base/logging.h"
 #include "services/video_capture/device_client_mojo_to_media_adapter.h"
+#include "services/video_capture/mojo_media_conversions.h"
 #include "services/video_capture/video_capture_device_proxy_impl.h"
 
 namespace video_capture {
@@ -45,69 +46,4 @@
   device_->StopAndDeAllocate();
 }
 
-// static
-media::VideoCaptureFormat VideoCaptureDeviceProxyImpl::ConvertFromMojoToMedia(
-    mojom::VideoCaptureFormatPtr format) {
-  media::VideoCaptureFormat result;
-  result.pixel_format = ConvertFromMojoToMedia(format->pixel_format);
-  result.pixel_storage = ConvertFromMojoToMedia(format->pixel_storage);
-  result.frame_size.SetSize(format->frame_size.width(),
-                            format->frame_size.height());
-  result.frame_rate = format->frame_rate;
-  return result;
-}
-
-// static
-media::VideoPixelFormat VideoCaptureDeviceProxyImpl::ConvertFromMojoToMedia(
-    media::mojom::VideoFormat format) {
-  // Since there are static_asserts in place in
-  // media/mojo/common/media_type_converters.cc to guarantee equality of the
-  // underlying representations, we can simply static_cast to convert.
-  return static_cast<media::VideoPixelFormat>(format);
-}
-
-// static
-media::VideoPixelStorage VideoCaptureDeviceProxyImpl::ConvertFromMojoToMedia(
-    mojom::VideoPixelStorage storage) {
-  switch (storage) {
-    case mojom::VideoPixelStorage::CPU:
-      return media::PIXEL_STORAGE_CPU;
-    case mojom::VideoPixelStorage::GPUMEMORYBUFFER:
-      return media::PIXEL_STORAGE_GPUMEMORYBUFFER;
-  }
-  NOTREACHED();
-  return media::PIXEL_STORAGE_CPU;
-}
-
-// static
-media::ResolutionChangePolicy
-VideoCaptureDeviceProxyImpl::ConvertFromMojoToMedia(
-    mojom::ResolutionChangePolicy policy) {
-  switch (policy) {
-    case mojom::ResolutionChangePolicy::FIXED_RESOLUTION:
-      return media::RESOLUTION_POLICY_FIXED_RESOLUTION;
-    case mojom::ResolutionChangePolicy::FIXED_ASPECT_RATIO:
-      return media::RESOLUTION_POLICY_FIXED_ASPECT_RATIO;
-    case mojom::ResolutionChangePolicy::ANY_WITHIN_LIMIT:
-      return media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT;
-  }
-  NOTREACHED();
-  return media::RESOLUTION_POLICY_FIXED_RESOLUTION;
-}
-
-// static
-media::PowerLineFrequency VideoCaptureDeviceProxyImpl::ConvertFromMojoToMedia(
-    mojom::PowerLineFrequency frequency) {
-  switch (frequency) {
-    case mojom::PowerLineFrequency::DEFAULT:
-      return media::PowerLineFrequency::FREQUENCY_DEFAULT;
-    case mojom::PowerLineFrequency::HZ_50:
-      return media::PowerLineFrequency::FREQUENCY_50HZ;
-    case mojom::PowerLineFrequency::HZ_60:
-      return media::PowerLineFrequency::FREQUENCY_60HZ;
-  }
-  NOTREACHED();
-  return media::PowerLineFrequency::FREQUENCY_DEFAULT;
-}
-
 }  // namespace video_capture
diff --git a/services/video_capture/video_capture_device_proxy_impl.h b/services/video_capture/video_capture_device_proxy_impl.h
index 3323a20..a2233f30 100644
--- a/services/video_capture/video_capture_device_proxy_impl.h
+++ b/services/video_capture/video_capture_device_proxy_impl.h
@@ -28,20 +28,6 @@
 
   void OnClientConnectionErrorOrClose();
 
-  // TODO(chfremer): Consider using Mojo type mapping instead of conversion
-  // methods.
-  // https://crbug.com/642387
-  static media::VideoCaptureFormat ConvertFromMojoToMedia(
-      mojom::VideoCaptureFormatPtr format);
-  static media::VideoPixelFormat ConvertFromMojoToMedia(
-      media::mojom::VideoFormat format);
-  static media::VideoPixelStorage ConvertFromMojoToMedia(
-      mojom::VideoPixelStorage storage);
-  static media::ResolutionChangePolicy ConvertFromMojoToMedia(
-      mojom::ResolutionChangePolicy policy);
-  static media::PowerLineFrequency ConvertFromMojoToMedia(
-      mojom::PowerLineFrequency frequency);
-
  private:
   std::unique_ptr<media::VideoCaptureDevice> device_;
   bool device_running_ = false;
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 7422d26a..d385de5d4 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -1780,6 +1780,16 @@
         "test": "content_unittests"
       },
       {
+        "args": [
+          "--enable-browser-side-navigation"
+        ],
+        "name": "browser_side_navigation_content_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_unittests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
diff --git a/testing/buildbot/filters/browser-side-navigation.linux.content_browsertests.filter b/testing/buildbot/filters/browser-side-navigation.linux.content_browsertests.filter
index 43711bb..dfcca38d 100644
--- a/testing/buildbot/filters/browser-side-navigation.linux.content_browsertests.filter
+++ b/testing/buildbot/filters/browser-side-navigation.linux.content_browsertests.filter
@@ -1,4 +1,3 @@
--DevToolsProtocolTest.ControlNavigationsMainFrame
 -IFrameZoomBrowserTest.RedirectToPageWithSubframeZoomsCorrectly
 -IFrameZoomBrowserTest.SubframesDontZoomIndependently
 -NavigationControllerBrowserTest.EnsureSamePageNavigationUpdatesFrameNavigationEntry
diff --git a/testing/libfuzzer/fuzzers/BUILD.gn b/testing/libfuzzer/fuzzers/BUILD.gn
index 7457c326..f919ec3 100644
--- a/testing/libfuzzer/fuzzers/BUILD.gn
+++ b/testing/libfuzzer/fuzzers/BUILD.gn
@@ -419,3 +419,14 @@
   ]
   libfuzzer_options = [ "max_len=1000" ]
 }
+
+fuzzer_test("openssl_bio_string_fuzzer") {
+  sources = [
+    "openssl_bio_string_fuzzer.cc",
+  ]
+  deps = [
+    "//crypto",
+    "//third_party/boringssl",
+  ]
+  libfuzzer_options = [ "max_len=512" ]
+}
diff --git a/testing/libfuzzer/fuzzers/openssl_bio_string_fuzzer.cc b/testing/libfuzzer/fuzzers/openssl_bio_string_fuzzer.cc
new file mode 100644
index 0000000..4eec5d8c
--- /dev/null
+++ b/testing/libfuzzer/fuzzers/openssl_bio_string_fuzzer.cc
@@ -0,0 +1,32 @@
+// 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.
+
+#include <stdint.h>
+
+#include "crypto/openssl_bio_string.h"
+#include "crypto/scoped_openssl_types.h"
+
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  if (size == 0) { return 0; }
+
+  std::string buffer;
+  std::string input(reinterpret_cast<const char*>(data), size);
+
+  std::size_t data_hash = std::hash<std::string>()(input);
+  uint8_t choice = data_hash % 3;
+
+  crypto::ScopedBIO bio(crypto::BIO_new_string(&buffer));
+  if (choice == 0) {
+    BIO_printf(bio.get(), "%s", input.c_str());
+  } else if (choice == 1) {
+    BIO_write(bio.get(), input.c_str(), size);
+  } else {
+    BIO_puts(bio.get(), input.c_str());
+  }
+  BIO_flush(bio.get());
+
+  return 0;
+}
+
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 0a9a9e3..6842444 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1776,9 +1776,9 @@
             ],
             "experiments": [
                 {
-                    "name": "Enable",
+                    "name": "Enable2",
                     "params": {
-                        "dismissal_threshold": "1"
+                        "dismissal_threshold": "2"
                     }
                 }
             ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation b/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
index 7e01827..38c793d1 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
@@ -168,16 +168,9 @@
   http/tests/inspector/service-workers/service-worker-manager.html [ Timeout ]
   http/tests/inspector/service-workers/service-workers-redundant.html [ Timeout ]
   http/tests/inspector/service-workers/user-agent-override.html [ Failure ]
-  http/tests/security/contentSecurityPolicy/service-worker-allowed.html [ Timeout ]
   http/tests/serviceworker/appcache-ordering-main.html [ Failure ]
-  http/tests/serviceworker/chromium/force-refresh-ready.html [ Timeout Failure ]
-  http/tests/serviceworker/chromium/force-refresh-registration.html [ Failure ]
   http/tests/serviceworker/chromium/register-link-header.html [ Timeout Failure ]
-  http/tests/serviceworker/chromium/registration-stress.html [ Failure ]
   http/tests/serviceworker/chromium/sandboxed-iframe-navigator-serviceworker.html [ Failure ]
-  http/tests/serviceworker/fetch-event.html [ Failure ]
   http/tests/serviceworker/fetch-request-fallback.html [ Failure ]
-  http/tests/serviceworker/foreign-fetch-cors.html [ Failure ]
   http/tests/serviceworker/navigation-redirect.html [ Failure ]
-  http/tests/serviceworker/referer.html [ Failure ]
   http/tests/serviceworker/request-end-to-end.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
index a01061f..2a934c6 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
@@ -114,8 +114,6 @@
 compositing/filters/sw-shadow-overlaps-hw-layer.html [ Failure ]
 compositing/filters/sw-shadow-overlaps-hw-shadow.html [ Failure ]
 compositing/fixed-background-after-style-recalc.html [ Failure ]
-compositing/fixed-background-composited-html.html [ Failure ]
-compositing/fixed-background-negative-z-index-fixed.html [ Failure ]
 compositing/fixed-body-background-positioned.html [ Failure ]
 compositing/fixed-position-changed-to-absolute.html [ Failure ]
 compositing/flat-with-transformed-child.html [ Failure ]
@@ -221,7 +219,6 @@
 compositing/iframes/composited-parent-iframe.html [ Failure ]
 compositing/iframes/connect-compositing-iframe2.html [ Failure ]
 compositing/iframes/connect-compositing-iframe3.html [ Failure ]
-compositing/iframes/floating-self-painting-frame.html [ Failure ]
 compositing/iframes/iframe-resize.html [ Failure ]
 compositing/iframes/iframe-size-from-zero.html [ Failure ]
 compositing/iframes/invisible-nested-iframe-hide.html [ Crash Failure ]
@@ -309,10 +306,10 @@
 compositing/overflow/opt-in-if-composited.html [ Failure ]
 compositing/overflow/overflow-compositing-descendant.html [ Failure ]
 compositing/overflow/overflow-scaled-descendant-overlapping.html [ Crash Timeout ]
-compositing/overflow/overflow-scroll-with-opaque-background.html [ Failure ]
-compositing/overflow/overflow-scroll-with-opaque-background-will-change.html [ Failure ]
-compositing/overflow/overflow-scroll-background-transparent-to-opaque.html [ Failure ]
 compositing/overflow/overflow-scroll-background-opaque-to-transparent.html [ Failure ]
+compositing/overflow/overflow-scroll-background-transparent-to-opaque.html [ Failure ]
+compositing/overflow/overflow-scroll-with-opaque-background-will-change.html [ Failure ]
+compositing/overflow/overflow-scroll-with-opaque-background.html [ Failure ]
 compositing/overflow/overflow-scroll-with-pointer-events-toggle.html [ Failure ]
 compositing/overflow/overflow-scroll-with-transparent-background.html [ Failure ]
 compositing/overflow/overflow-scrollbar-layers.html [ Failure ]
@@ -363,7 +360,6 @@
 compositing/reflections/transform-inside-reflection.html [ Failure ]
 compositing/rendering-contexts.html [ Failure ]
 compositing/root-scroller/basic-disable-ancestor-clipping.html [ Failure ]
-compositing/root-scroller/basic-reenable-ancestor-clipping.html [ Failure ]
 compositing/root-scroller/clipping-ancestor-is-composited-sibling.html [ Failure ]
 compositing/root-scroller/clipping-ancestor-is-non-composited-sibling.html [ Failure ]
 compositing/rtl/rtl-absolute-overflow-scrolled.html [ Failure Crash ]
@@ -528,6 +524,7 @@
 fast/borders/border-radius-mask-video-ratio.html [ Failure ]
 fast/borders/border-radius-mask-video-shadow.html [ Failure ]
 fast/borders/border-radius-mask-video.html [ Failure ]
+fast/borders/border-radius-with-box-shadow-01.html [ Failure Pass ]
 fast/borders/border-radius-with-composited-child.html [ Failure ]
 fast/borders/inline-mask-overlay-image-outset-vertical-rl.html [ Failure ]
 fast/borders/inline-mask-overlay-image-outset.html [ Failure ]
@@ -543,7 +540,6 @@
 fast/box-shadow/box-shadow-transformed.html [ Failure ]
 fast/box-shadow/box-shadow.html [ Failure ]
 fast/box-shadow/scaled-box-shadow.html [ Failure ]
-fast/box-shadow/single-pixel-shadow.html [ Failure ]
 fast/box-sizing/box-sizing.html [ Failure ]
 fast/box-sizing/panels-one.html [ Failure ]
 fast/box-sizing/panels-two.html [ Failure ]
@@ -569,10 +565,6 @@
 fast/css/border-height.html [ Failure ]
 fast/css/color-correction-backgrounds-and-text.html [ Failure ]
 fast/css/color-correction-on-background-image.html [ Failure ]
-fast/css/containment/paint-containment-with-absolute-position.html [ Failure ]
-fast/css/containment/paint-containment-with-box-shadow.html [ Failure ]
-fast/css/containment/paint-containment-with-fixed-position.html [ Failure ]
-fast/css/containment/paint-containment-with-transformed-descendant.html [ Failure ]
 fast/css/continuationCrash.html [ Failure ]
 fast/css/first-child-pseudo-class.html [ Failure ]
 fast/css/first-of-type-pseudo-class.html [ Failure ]
@@ -596,14 +588,12 @@
 fast/css/resize-corner-tracking-transformed-iframe.html [ Failure ]
 fast/css/resize-corner-tracking-transformed.html [ Failure ]
 fast/css/rtl-ordering.html [ Failure ]
-fast/css/text-overflow-ellipsis-block-with-border-and-padding.html [ Failure ]
 fast/css/text-overflow-ellipsis-multiple-shadows.html [ Failure ]
 fast/css/text-overflow-ellipsis-strict.html [ Failure ]
 fast/css/text-overflow-ellipsis-text-align-center.html [ Failure ]
 fast/css/text-overflow-ellipsis-text-align-justify.html [ Failure ]
 fast/css/text-overflow-ellipsis-text-align-left.html [ Failure ]
 fast/css/text-overflow-ellipsis-text-align-right.html [ Failure ]
-fast/css/text-overflow-ellipsis-vertical-select.html [ Failure ]
 fast/css/text-overflow-ellipsis.html [ Failure ]
 fast/css/text-overflow-input.html [ Failure ]
 fast/css/transformed-mask.html [ Crash Failure ]
@@ -611,8 +601,6 @@
 fast/css/vertical-text-overflow-ellipsis-text-align-justify.html [ Failure ]
 fast/css/vertical-text-overflow-ellipsis-text-align-left.html [ Failure ]
 fast/css/vertical-text-overflow-ellipsis-text-align-right.html [ Failure ]
-fast/deprecated-flexbox/009-horizontal.html [ Failure ]
-fast/deprecated-flexbox/009.html [ Failure ]
 fast/deprecated-flexbox/016.html [ Failure ]
 fast/dom/34176.html [ Failure ]
 fast/dom/52776.html [ Failure ]
@@ -857,7 +845,6 @@
 fast/html/details-add-summary-7-and-click.html [ Failure ]
 fast/html/details-add-summary-8-and-click.html [ Failure ]
 fast/html/details-add-summary-9-and-click.html [ Failure ]
-fast/html/details-position.html [ Failure ]
 fast/html/details-remove-summary-1-and-click.html [ Failure ]
 fast/html/details-remove-summary-2-and-click.html [ Failure ]
 fast/html/details-remove-summary-3-and-click.html [ Failure ]
@@ -1109,7 +1096,6 @@
 fast/multicol/vertical-rl/unsplittable-inline-block.html [ Failure ]
 fast/overflow/001.html [ Failure ]
 fast/overflow/002.html [ Failure ]
-fast/overflow/003.xml [ Failure ]
 fast/overflow/006.html [ Failure ]
 fast/overflow/007.html [ Failure ]
 fast/overflow/border-radius-clipping.html [ Failure ]
@@ -1220,6 +1206,7 @@
 fast/text/letter-spacing-negative-opacity.html [ Failure ]
 fast/text/selection-hard-linebreak.html [ Failure ]
 fast/text/softHyphen.html [ Failure ]
+fast/text/stroking-decorations.html [ Failure Pass ]
 fast/text/text-letter-spacing.html [ Failure ]
 fast/text/textIteratorNilRenderer.html [ Failure ]
 fast/text/unicode-fallback-font.html [ Failure ]
@@ -1245,7 +1232,6 @@
 fast/writing-mode/border-radius-clipping-vertical-lr.html [ Failure ]
 fast/writing-mode/fieldsets.html [ Failure ]
 fast/writing-mode/Kusa-Makura-background-canvas.html [ Failure Crash ]
-fast/xsl/xslt-mismatched-tags-in-xslt.xml [ Failure ]
 svg/animations/animateMotion-accumulate-1a.svg [ Failure ]
 svg/animations/animateMotion-accumulate-1b.svg [ Failure ]
 svg/animations/animateMotion-accumulate-1c.svg [ Failure ]
@@ -1303,15 +1289,7 @@
 svg/carto.net/slider.svg [ Failure ]
 svg/carto.net/textbox.svg [ Failure ]
 svg/clip-path/clip-in-clip.svg [ Failure ]
-svg/clip-path/clip-in-mask-objectBoundingBox.svg [ Failure ]
-svg/clip-path/clip-in-mask-userSpaceOnUse.svg [ Failure ]
-svg/clip-path/clip-in-mask.svg [ Failure ]
 svg/clip-path/clip-path-child-clipped.svg [ Failure ]
-svg/clip-path/clip-path-childs-clipped.svg [ Failure ]
-svg/clip-path/clip-path-clipped-evenodd-twice.svg [ Failure ]
-svg/clip-path/clip-path-clipped-no-content.svg [ Failure ]
-svg/clip-path/clip-path-clipped-nonzero.svg [ Failure ]
-svg/clip-path/clip-path-clipped.svg [ Failure ]
 svg/clip-path/clip-path-css-transform-1.svg [ Failure ]
 svg/clip-path/clip-path-css-transform-2.svg [ Failure ]
 svg/clip-path/clip-path-evenodd-nonzero.svg [ Failure ]
@@ -1327,30 +1305,13 @@
 svg/clip-path/clip-path-on-svg.svg [ Failure ]
 svg/clip-path/clip-path-pixelation.svg [ Failure ]
 svg/clip-path/clip-path-shape-ellipse-2.svg [ Failure ]
-svg/clip-path/clip-path-text-and-shape.svg [ Failure ]
-svg/clip-path/clip-path-text-and-stroke.svg [ Failure ]
-svg/clip-path/clip-path-text.svg [ Failure ]
 svg/clip-path/clip-path-transform-1.svg [ Failure ]
 svg/clip-path/clip-path-transform-2.svg [ Failure ]
-svg/clip-path/clip-path-tspan-and-stroke.svg [ Failure ]
 svg/clip-path/clip-path-use-as-child.svg [ Failure ]
-svg/clip-path/clip-path-use-as-child2.svg [ Failure ]
-svg/clip-path/clip-path-use-as-child3.svg [ Failure ]
-svg/clip-path/clip-path-use-as-child4.svg [ Failure ]
 svg/clip-path/clip-path-userSpaceOnUse.svg [ Failure ]
-svg/clip-path/clip-path-with-different-unittypes.svg [ Failure ]
-svg/clip-path/clip-path-with-different-unittypes2.svg [ Failure ]
-svg/clip-path/clip-path-with-text-clipped.svg [ Failure ]
 svg/clip-path/clipper-placement-issue.svg [ Failure ]
-svg/clip-path/deep-nested-clip-in-mask-different-unitTypes.svg [ Failure ]
 svg/clip-path/deep-nested-clip-in-mask-panning.svg [ Failure ]
-svg/clip-path/deep-nested-clip-in-mask.svg [ Failure ]
 svg/clip-path/multiple-nested-clip-paths-crash.html [ Failure ]
-svg/clip-path/nested-clip-in-mask-image-based-clipping.svg [ Failure ]
-svg/clip-path/nested-clip-in-mask-path-and-image-based-clipping.svg [ Failure ]
-svg/clip-path/nested-clip-in-mask-path-based-clipping.svg [ Failure ]
-svg/clip-path/opacity-assertion.svg [ Failure ]
-svg/clip-path/transformed-clip.svg [ Failure ]
 svg/css/text-shadow-multiple.xhtml [ Failure ]
 svg/custom/absolute-root-position-masking.xhtml [ Failure ]
 svg/custom/alignment-baseline-modes.svg [ Failure ]
@@ -1372,7 +1333,6 @@
 svg/custom/dominant-baseline-hanging.svg [ Failure ]
 svg/custom/dominant-baseline-modes.svg [ Failure ]
 svg/custom/dynamic-empty-path.svg [ Failure ]
-svg/custom/dynamic-viewBox.svg [ Failure ]
 svg/custom/embedding-external-svgs.xhtml [ Failure ]
 svg/custom/feComponentTransfer-Discrete.svg [ Failure ]
 svg/custom/feComponentTransfer-Gamma.svg [ Failure ]
@@ -1392,15 +1352,11 @@
 svg/custom/grayscale-gradient-mask-2.svg [ Failure ]
 svg/custom/grayscale-gradient-mask.svg [ Failure ]
 svg/custom/group-opacity.svg [ Failure ]
-svg/custom/image-parent-translation.xhtml [ Failure ]
 svg/custom/image-with-preserveAspectRatio-none.html [ Failure ]
-svg/custom/image-with-transform-clip-filter.svg [ Failure ]
 svg/custom/inline-svg-in-xhtml.xml [ Failure ]
 svg/custom/invalid-css.svg [ Failure ]
 svg/custom/invalid-stroke-hex.svg [ Failure ]
-svg/custom/invalid-xslt-crash.svg [ Failure ]
 svg/custom/junk-data.svg [ Failure ]
-svg/custom/lazy-attach-use.html [ Failure ]
 svg/custom/linking-a-03-b-all.svg [ Failure ]
 svg/custom/linking-a-03-b-transform.svg [ Failure ]
 svg/custom/linking-a-03-b-viewBox-transform.svg [ Failure ]
@@ -1411,10 +1367,8 @@
 svg/custom/marker-default-width-height.svg [ Failure ]
 svg/custom/marker-orient-auto.html [ Failure ]
 svg/custom/marker-referencePoint.svg [ Failure ]
-svg/custom/mask-changes.svg [ Failure ]
 svg/custom/mask-colorspace.svg [ Failure ]
 svg/custom/mask-inside-defs.svg [ Failure ]
-svg/custom/mask-on-multiple-objects.svg [ Failure ]
 svg/custom/mask-with-all-units.svg [ Failure ]
 svg/custom/mask-with-default-value.svg [ Failure ]
 svg/custom/masking-clipping-hidpi.svg [ Failure ]
@@ -1442,7 +1396,6 @@
 svg/custom/recursive-gradient.svg [ Failure ]
 svg/custom/recursive-mask.svg [ Failure ]
 svg/custom/root-container-opacity-clip-viewBox.svg [ Failure ]
-svg/custom/root-size-attribute-changes.html [ Failure ]
 svg/custom/shape-rendering.svg [ Failure ]
 svg/custom/shapes-supporting-markers.svg [ Failure ]
 svg/custom/stroke-width-large.svg [ Failure ]
@@ -1460,8 +1413,6 @@
 svg/custom/text-x-dy-lists.svg [ Failure ]
 svg/custom/transformed-outlines.svg [ Failure ]
 svg/custom/transformed-pattern-clamp-svg-root.svg [ Failure ]
-svg/custom/transformed-text-pattern.html [ Failure ]
-svg/custom/use-attribute-invalidations.html [ Failure ]
 svg/custom/use-css-no-effect-on-shadow-tree.svg [ Failure ]
 svg/custom/use-font-face-crash.svg [ Failure ]
 svg/custom/use-forward-refs.svg [ Failure ]
@@ -1489,9 +1440,6 @@
 svg/custom/use-transform.svg [ Failure ]
 svg/custom/viewBox-hit.svg [ Failure ]
 svg/custom/viewbox-syntax.svg [ Failure ]
-svg/custom/viewport-clip.svg [ Failure ]
-svg/custom/viewport-update2.svg [ Failure ]
-svg/custom/visibility-enable-on-svg-element-contained-viewport-size.html [ Failure ]
 svg/custom/visibility-override-clip.svg [ Failure ]
 svg/custom/visibility-override-mask.svg [ Failure ]
 svg/custom/visited-link-color.svg [ Failure ]
@@ -1523,27 +1471,10 @@
 svg/dynamic-updates/SVGFEColorMatrixElement-svgdom-in-prop.html [ Failure ]
 svg/dynamic-updates/SVGFEColorMatrixElement-svgdom-type-prop.html [ Failure ]
 svg/dynamic-updates/SVGFEColorMatrixElement-svgdom-values-prop.html [ Failure ]
-svg/dynamic-updates/SVGFECompositeElement-dom-in2-attr.html [ Failure ]
-svg/dynamic-updates/SVGFECompositeElement-dom-k1-attr.html [ Failure ]
-svg/dynamic-updates/SVGFECompositeElement-dom-k3-attr.html [ Failure ]
-svg/dynamic-updates/SVGFECompositeElement-svgdom-in2-prop.html [ Failure ]
-svg/dynamic-updates/SVGFECompositeElement-svgdom-k1-prop.html [ Failure ]
-svg/dynamic-updates/SVGFECompositeElement-svgdom-k3-prop.html [ Failure ]
 svg/dynamic-updates/SVGFEImageElement-dom-preserveAspectRatio-attr.html [ Failure ]
 svg/dynamic-updates/SVGFEImageElement-svgdom-preserveAspectRatio-prop.html [ Failure ]
 svg/dynamic-updates/SVGFEMergeNodeElement-dom-in-attr.html [ Failure ]
 svg/dynamic-updates/SVGFEMergeNodeElement-svgdom-in-prop.html [ Failure ]
-svg/dynamic-updates/SVGFESpotLightElement-dom-pointsAtZ-attr.html [ Failure ]
-svg/dynamic-updates/SVGFESpotLightElement-dom-specularExponent-attr.html [ Failure ]
-svg/dynamic-updates/SVGFESpotLightElement-dom-x-attr.html [ Failure ]
-svg/dynamic-updates/SVGFESpotLightElement-dom-y-attr.html [ Failure ]
-svg/dynamic-updates/SVGFESpotLightElement-dom-z-attr.html [ Failure ]
-svg/dynamic-updates/SVGFESpotLightElement-svgdom-pointsAtZ-prop.html [ Failure ]
-svg/dynamic-updates/SVGFESpotLightElement-svgdom-x-prop.html [ Failure ]
-svg/dynamic-updates/SVGFESpotLightElement-svgdom-y-prop.html [ Failure ]
-svg/dynamic-updates/SVGFESpotLightElement-svgdom-z-prop.html [ Failure ]
-svg/dynamic-updates/SVGFETileElement-dom-in-attr.html [ Failure ]
-svg/dynamic-updates/SVGFETileElement-svgdom-in-prop.html [ Failure ]
 svg/dynamic-updates/SVGForeignObjectElement-dom-x-attr.html [ Failure Crash ]
 svg/dynamic-updates/SVGForeignObjectElement-dom-y-attr.html [ Failure Crash ]
 svg/dynamic-updates/SVGForeignObjectElement-svgdom-x-prop.html [ Failure Crash ]
@@ -1589,9 +1520,7 @@
 svg/dynamic-updates/SVGTextElement-dom-lengthAdjust-attr.html [ Failure ]
 svg/dynamic-updates/SVGTextElement-dom-rotate-attr.html [ Failure ]
 svg/dynamic-updates/SVGTextElement-svgdom-lengthAdjust-prop.html [ Failure ]
-svg/filters/big-height-filter.svg [ Failure ]
 svg/filters/big-sized-filter.svg [ Failure ]
-svg/filters/big-width-filter.svg [ Failure ]
 svg/filters/feDropShadow.svg [ Failure ]
 svg/filters/feImage-filterUnits-objectBoundingBox-primitiveUnits-objectBoundingBox.svg [ Failure ]
 svg/filters/feImage-filterUnits-objectBoundingBox-primitiveUnits-userSpaceOnUse.svg [ Failure ]
@@ -1600,17 +1529,14 @@
 svg/filters/feImage-late-indirect-update.svg [ Failure ]
 svg/filters/feImage-preserveAspectRatio-all.svg [ Failure ]
 svg/filters/feImage-reference-svg-primitive.svg [ Failure ]
-svg/filters/feImage-scaled-viewport.svg [ Failure ]
 svg/filters/feImage-subregions-preseveAspectRatio-none-with-viewBox.svg [ Failure ]
 svg/filters/feImage-subregions-preseveAspectRatio-none.svg [ Failure ]
 svg/filters/feImage-subregions.svg [ Failure ]
 svg/filters/feLighting-crash.svg [ Failure ]
-svg/filters/feSpecularLight-premultiplied.svg [ Failure ]
 svg/filters/feTile.svg [ Failure ]
 svg/filters/filter-clip.svg [ Failure ]
 svg/filters/filter-huge-clamping.svg [ Failure ]
 svg/filters/filter-on-svg-root-w-layer.html [ Failure ]
-svg/filters/subRegion-in-userSpace.svg [ Failure ]
 svg/filters/subRegion-one-effect.svg [ Failure ]
 svg/filters/subRegion-two-effects.svg [ Failure ]
 svg/filters/svg-element-invalid-filter.html [ Failure ]
@@ -1620,9 +1546,7 @@
 svg/foreignObject/mask.html [ Failure ]
 svg/foreignObject/svg-document-as-direct-child.svg [ Failure ]
 svg/hixie/data-types/001.xml [ Failure ]
-svg/hixie/error/006.xml [ Failure ]
 svg/hixie/error/012.xml [ Failure ]
-svg/hixie/error/013.xml [ Failure ]
 svg/hixie/error/017.xml [ Failure ]
 svg/hixie/intrinsic/003.html [ Crash Failure ]
 svg/hixie/links/001.xml [ Failure ]
@@ -1640,22 +1564,15 @@
 svg/hixie/perf/006.xml [ Failure ]
 svg/hixie/perf/007.xml [ Failure ]
 svg/hixie/viewbox/preserveAspectRatio/001.xml [ Failure ]
-svg/hixie/viewbox/preserveAspectRatio/002.xml [ Failure ]
 svg/in-html/circle.html [ Failure ]
 svg/markers/marker-orientation-minus-one.html [ Failure ]
-svg/masking/mask-type-alpha.svg [ Failure ]
-svg/masking/mask-type-luminance.svg [ Failure ]
-svg/masking/mask-type-not-set.svg [ Failure ]
 svg/overflow/overflow-on-foreignObject.svg [ Failure Pass ]
 svg/overflow/overflow-on-inner-svg-element-defaults.svg [ Failure ]
 svg/overflow/overflow-on-inner-svg-element.svg [ Failure ]
 svg/overflow/overflow-on-outermost-svg-element-defaults.svg [ Failure ]
 svg/overflow/overflow-on-outermost-svg-element-ignore-attribute-2.svg [ Failure ]
 svg/overflow/overflow-on-outermost-svg-element-ignore-attribute-3.svg [ Failure ]
-svg/overflow/overflow-on-outermost-svg-element-in-xhtml-auto.xhtml [ Failure ]
 svg/overflow/overflow-on-outermost-svg-element-in-xhtml-defaults.xhtml [ Failure ]
-svg/overflow/overflow-on-outermost-svg-element-in-xhtml-hidden.xhtml [ Failure ]
-svg/overflow/overflow-on-outermost-svg-element-in-xhtml-scroll.xhtml [ Failure ]
 svg/stroke/non-scaling-stroke-zero-length-subpath-linecaps.html [ Failure ]
 svg/stroke/zero-length-arc-linecaps-rendering.svg [ Failure ]
 svg/stroke/zero-length-path-linecap-rendering.svg [ Failure ]
@@ -1706,7 +1623,6 @@
 svg/text/small-fonts.svg [ Crash Timeout Failure ]
 svg/text/surrogate-pair-queries.html [ Failure ]
 svg/text/text-fill-opacity.svg [ Failure ]
-svg/text/text-layout-crash.html [ Failure ]
 svg/text/text-repaint-rects.xhtml [ Failure ]
 svg/text/text-selection-align-01-b.svg [ Failure ]
 svg/text/text-selection-align-02-b.svg [ Failure ]
@@ -1738,7 +1654,6 @@
 svg/transforms/text-with-mask-with-svg-transform.svg [ Failure ]
 svg/transforms/text-with-pattern-inside-transformed-html.xhtml [ Failure ]
 svg/transforms/text-with-pattern-with-svg-transform.svg [ Failure ]
-svg/transforms/will-change-transform.svg [ Failure ]
 svg/W3C-I18N/g-dirLTR-ubNone.svg [ Failure ]
 svg/W3C-I18N/g-dirLTR-ubOverride.svg [ Failure ]
 svg/W3C-I18N/g-dirRTL-ubNone.svg [ Failure ]
@@ -2082,6 +1997,17 @@
 fast/scrolling/hover-during-scroll.html [ Timeout ]
 fast/scrolling/scrollbar-tickmarks-hittest.html [ Timeout ]
 
+crbug.com/651292 svg/dynamic-updates/SVGImageElement-dom-x-attr.html [ Pass Failure ]
+crbug.com/651292 svg/dynamic-updates/SVGImageElement-svgdom-height-prop.html [ Pass Failure ]
+crbug.com/651292 svg/dynamic-updates/SVGImageElement-svgdom-preserveAspectRatio-prop.html [ Pass Failure ]
+crbug.com/651292 svg/dynamic-updates/SVGImageElement-svgdom-width-prop.html [ Pass Failure ]
+crbug.com/651292 svg/dynamic-updates/SVGImageElement-svgdom-y-prop.html [ Pass Failure ]
+crbug.com/651292 svg/dynamic-updates/SVGImageElement-svgdom-x-prop.html [ Pass Failure ]
+crbug.com/651292 svg/custom/createImageElement2.xhtml [ Pass Failure ]
+crbug.com/651292 svg/dynamic-updates/SVGImageElement-dom-width-attr.html [ Pass Failure ]
+crbug.com/651292 svg/dynamic-updates/SVGImageElement-dom-preserveAspectRatio-attr.html [ Pass Failure ]
+crbug.com/651292 svg/dynamic-updates/SVGImageElement-dom-y-attr.html [ Pass Failure ]
+
 # Invisible pixel diffs caused by different methods of clipping.
 crbug.com/637316 svg/W3C-SVG-1.1-SE/color-prop-05-t.svg [ Failure ]
 crbug.com/637316 svg/W3C-SVG-1.1-SE/coords-dom-03-f.svg [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/LeakExpectations b/third_party/WebKit/LayoutTests/LeakExpectations
index 29abc30..90e3310a 100644
--- a/third_party/WebKit/LayoutTests/LeakExpectations
+++ b/third_party/WebKit/LayoutTests/LeakExpectations
@@ -81,6 +81,8 @@
 crbug.com/506754 http/tests/security/cross-origin-indexeddb-allowed.html [ Leak ]
 crbug.com/506754 http/tests/serviceworker/chromium/resolve-after-window-close.html [ Leak ]
 crbug.com/506754 http/tests/serviceworker/chromium/window-close-during-registration.html [ Leak ]
+crbug.com/506754 virtual/mojo-service-worker/http/tests/serviceworker/chromium/resolve-after-window-close.html [ Leak ]
+crbug.com/506754 virtual/mojo-service-worker/http/tests/serviceworker/chromium/window-close-during-registration.html [ Leak ]
 
 # -----------------------------------------------------------------
 # Untriaged but known leaks of ActiveDOMObject (Web Audio).
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 825e47f9..d262de8 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -264,36 +264,6 @@
 crbug.com/567837 virtual/scalefactor150/fast/hidpi/static/mousewheel-scroll-amount.html [ Skip ]
 crbug.com/567837 virtual/scalefactor150/fast/hidpi/static/gesture-scroll-amount.html [ Skip ]
 
-crbug.com/646176 paint/invalidation/4776765.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/caret-subpixel.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/caret-with-composited-scroll.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/compositing/iframe-inside-squashed-layer.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/delete-into-nested-block.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/inline-outline-repaint.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/invalidate-caret-in-composited-scrolling-container.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/invalidate-caret-in-non-composited-scrolling-container.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/line-flow-with-floats-2.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/line-flow-with-floats-8.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/line-flow-with-floats-9.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/overflow-scroll-body-appear.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/repaint-during-scroll-with-zoom.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/scrolled-iframe-scrollbar-change.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/selection-after-delete.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/shift-relative-positioned-container-with-image-addition.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/svg/deep-nested-embedded-svg-size-changes-no-layout-triggers-1.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/svg/deep-nested-embedded-svg-size-changes-no-layout-triggers-2.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-1.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-2.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/text-match-document-change.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/textarea-caret.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/window-resize-vertical-writing-mode.html [ NeedsRebaseline ]
-
-crbug.com/640256 [ Linux Win ] fast/forms/color/color-suggestion-picker-appearance-zoom125.html [ NeedsRebaseline ]
-crbug.com/640256 [ Linux Win ] fast/forms/color/color-suggestion-picker-appearance-zoom200.html [ NeedsRebaseline ]
-crbug.com/640256 [ Linux Win ] fast/forms/color/color-suggestion-picker-appearance.html [ NeedsRebaseline ]
-crbug.com/640256 [ Linux Win ] fast/forms/color/color-suggestion-picker-one-row-appearance.html [ NeedsRebaseline ]
-crbug.com/640256 [ Linux Win ] fast/forms/color/color-suggestion-picker-two-row-appearance.html [ NeedsRebaseline ]
-
 # TODO(ojan): These tests aren't flaky. See crbug.com/517144.
 # Release trybots run asserts, but the main waterfall ones don't. So, even
 # though this is a non-flaky assert failure, we need to mark it [ Pass Crash ].
@@ -370,33 +340,6 @@
 crbug.com/525889 imported/wpt/html/webappapis/scripting/processing-model-2/runtime-error-in-setInterval.html [ Failure ]
 crbug.com/525889 imported/wpt/html/webappapis/scripting/processing-model-2/runtime-error-in-setTimeout.html [ Failure ]
 
-crbug.com/648963 compositing/contents-opaque/overflow-hidden-child-layers.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/culling/scrolled-within-boxshadow.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/culling/translated-boxshadow.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/culling/unscrolled-within-boxshadow.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/geometry/foreground-layer.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/layer-creation/rotate3d-overlap.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/masks/masked-ancestor.html [ NeedsRebaseline ]
-crbug.com/648963 paint/invalidation/box-shadow-add-repaint.html [ NeedsRebaseline ]
-crbug.com/648963 paint/invalidation/box-shadow-change-repaint.html [ NeedsRebaseline ]
-crbug.com/648963 paint/invalidation/transform-replaced-shadows.html [ NeedsRebaseline ]
-crbug.com/648963 svg/css/text-gradient-shadow.svg [ NeedsRebaseline ]
-crbug.com/648963 svg/css/text-shadow-multiple.xhtml [ NeedsRebaseline ]
-crbug.com/648963 svg/zoom/page/zoom-background-images.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/masks/multiple-masks.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/masks/simple-composited-mask.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/iframes/scrolling-iframe.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/iframes/connect-compositing-iframe3.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/iframes/overlapped-iframe.html [ NeedsRebaseline ]
-crbug.com/648963 fast/borders/border-radius-mask-video-shadow.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/iframes/enter-compositing-iframe.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/iframes/iframe-resize.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/iframes/composited-parent-iframe.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/iframes/invisible-nested-iframe-show.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/iframes/connect-compositing-iframe-delayed.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/iframes/connect-compositing-iframe2.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/iframes/connect-compositing-iframe.html [ NeedsRebaseline ]
-
 crbug.com/636961 [ Linux Debug ] virtual/threaded/fast/scroll-behavior/smooth-scroll/ongoing-smooth-scroll-vertical-rl-anchors.html [ Pass Failure ]
 
 crbug.com/552532 [ Win10 ] fast/replaced/no-focus-ring-embed.html [ Pass Crash ]
@@ -701,11 +644,6 @@
 crbug.com/306222 fast/hidpi/image-srcset-relative-svg-canvas.html [ Skip ]
 crbug.com/306222 fast/hidpi/image-srcset-relative-svg-canvas-2x.html [ Skip ]
 
-crbug.com/647922 svg/zoom/page/zoom-img-preserveAspectRatio-support-1.html [ NeedsRebaseline ]
-crbug.com/647922 fast/borders/webkit-border-radius.html [ NeedsRebaseline ]
-crbug.com/647922 fast/borders/borderRadiusDotted04.html [ NeedsRebaseline ]
-crbug.com/647922 fast/borders/border-radius-different-width-001-double.html [ NeedsRebaseline ]
-
 # The failure in the next line is due to virtual/gpu bots using osmesa
 # Under osmesa, skia's filter quality doesn't work correctly. This test is expected to pass
 # when we swith to swiftshader.
@@ -1141,8 +1079,6 @@
 crbug.com/587779 [ Linux Mac10.9 Mac10.10 Mac10.11 Retina ] fast/dynamic/window-resize-scrollbars-test.html [ Timeout Failure Pass ]
 
 crbug.com/588103 fast/xmlhttprequest/xmlhttprequest-responsetype-arraybuffer.html [ Pass Failure ]
-crbug.com/649320 fast/forms/select/menulist-appearance-basic.html [ NeedsRebaseline ]
-crbug.com/649320 http/tests/webfont/popup-menu-load-webfont-after-open.html [ NeedsRebaseline ]
 crbug.com/594672 fast/events/iframe-object-onload.html [ Failure Pass ]
 crbug.com/594672 fast/events/scale-and-scroll-iframe-body.html [ Failure Pass ]
 crbug.com/594672 fast/events/updateLayoutForHitTest.html [ Failure Pass ]
@@ -1254,6 +1190,9 @@
 
 crbug.com/399507 [ Mac Linux Win10 ] virtual/threaded/inspector/tracing/timeline-paint/layer-tree.html [ Skip ]
 
+# Skip this test because it causes the next text to fail though the test itself passes.
+crbug.com/648785 paint/invalidation/fixed-right-bottom-in-page-scale.html [ Skip ]
+
 crbug.com/637245 [ Mac10.11 Retina ] fast/html/details-add-summary-5-and-click.html [ Pass Failure ]
 crbug.com/637245 [ Mac10.11 Retina ] fast/html/details-add-summary-8-and-click.html [ Pass Failure ]
 crbug.com/637245 [ Mac10.11 Retina ] fast/html/details-add-summary-1-and-click.html [ Pass Failure ]
@@ -1289,112 +1228,9 @@
 
 crbug.com/626703 [ Win10 ] imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-baseline-align-self-baseline-vert-001.html [ Failure ]
 
-crbug.com/492785 virtual/rootlayerscrolls/scrollbars/custom-scrollbar-reconstruction-on-inserting-style-sheet.html [ Failure ]
-
 crbug.com/646323 [ Mac ] editing/selection/modify_move/move_backward_line_import_crash.html [ Crash Timeout ]
 crbug.com/646323 [ Win Linux ] editing/selection/modify_move/move_backward_line_import_crash.html [ Crash ]
 
 crbug.com/645640 inspector/extensions/extensions-eval.html [ NeedsManualRebaseline ]
 
-crbug.com/649631 [ Win7 Win10 ] fast/borders/border-styles-split.html [ NeedsRebaseline ]
-crbug.com/649631 [ Win7 Win10 ] fast/backgrounds/border-radius-split-background.html [ NeedsRebaseline ]
-crbug.com/649631 [ Win7 Win10 ] fast/backgrounds/border-radius-split-background-image.html [ NeedsRebaseline ]
-
 crbug.com/650655 virtual/enable_wasm/http/tests/wasm/wasm_serialization_tests.html [ NeedsManualRebaseline ]
-
-crbug.com/649046 fast/forms/calendar-picker/calendar-picker-appearance-zoom125.html [ NeedsRebaseline ]
-crbug.com/649046 fast/images/color-profile-border-radius.html [ NeedsRebaseline ]
-crbug.com/649046 svg/custom/js-update-image-and-display3.svg [ NeedsRebaseline ]
-crbug.com/649046 tables/mozilla/bugs/bug1430.html [ NeedsRebaseline ]
-crbug.com/649046 paint/invalidation/svg/animated-path-inside-transformed-html.xhtml [ NeedsRebaseline ]
-crbug.com/649046 svg/custom/pointer-events-image-css-transform.svg [ NeedsRebaseline ]
-crbug.com/649046 css3/blending/background-blend-mode-tiled-gradient.html [ NeedsRebaseline ]
-crbug.com/649046 fast/borders/inline-mask-overlay-image-outset-vertical-rl.html [ NeedsRebaseline ]
-crbug.com/649046 svg/dynamic-updates/SVGImageElement-svgdom-preserveAspectRatio-prop.html [ NeedsRebaseline ]
-crbug.com/649046 css3/blending/background-blend-mode-image-svg.html [ NeedsRebaseline ]
-crbug.com/649046 svg/W3C-SVG-1.1/animate-elem-30-t.svg [ NeedsRebaseline ]
-crbug.com/649046 svg/carto.net/selectionlist.svg [ NeedsRebaseline ]
-crbug.com/649046 fast/images/color-profile-object.html [ NeedsRebaseline ]
-crbug.com/649046 tables/mozilla/bugs/bug4093.html [ NeedsRebaseline ]
-crbug.com/649046 svg/W3C-SVG-1.1/struct-symbol-01-b.svg [ NeedsRebaseline ]
-crbug.com/649046 css3/blending/mix-blend-mode-isolated-group-1.html [ NeedsRebaseline ]
-crbug.com/649046 svg/custom/use-on-g-containing-foreignObject-and-image.svg [ NeedsRebaseline ]
-crbug.com/649046 css3/blending/effect-background-blend-mode.html [ NeedsRebaseline ]
-crbug.com/649046 svg/W3C-SVG-1.1/struct-image-10-t.svg [ NeedsRebaseline ]
-crbug.com/649046 fast/images/color-profile-background-image-repeat.html [ NeedsRebaseline ]
-crbug.com/649046 svg/custom/image-small-width-height.svg [ NeedsRebaseline ]
-crbug.com/649046 svg/custom/pointer-events-image.svg [ NeedsRebaseline ]
-crbug.com/649046 svg/dynamic-updates/SVGImageElement-dom-y-attr.html [ NeedsRebaseline ]
-crbug.com/649046 svg/custom/js-update-image-and-display.svg [ NeedsRebaseline ]
-crbug.com/649046 svg/dynamic-updates/SVGImageElement-svgdom-y-prop.html [ NeedsRebaseline ]
-crbug.com/649046 svg/carto.net/scrollbar.svg [ NeedsRebaseline ]
-crbug.com/649046 svg/custom/js-update-image-and-display2.svg [ NeedsRebaseline ]
-crbug.com/649046 css3/blending/background-blend-mode-image-image.html [ NeedsRebaseline ]
-crbug.com/649046 fast/backgrounds/size/contain-and-cover-zoomed.html [ NeedsRebaseline ]
-crbug.com/649046 fast/images/exif-orientation-height-image-document.html [ NeedsRebaseline ]
-crbug.com/649046 svg/hixie/perf/004.xml [ NeedsRebaseline ]
-crbug.com/649046 svg/W3C-SVG-1.1/coords-viewattr-02-b.svg [ NeedsRebaseline ]
-crbug.com/649046 svg/W3C-SVG-1.1/animate-elem-39-t.svg [ NeedsRebaseline ]
-crbug.com/649046 tables/mozilla/core/col_widths_auto_autoFix.html [ NeedsRebaseline ]
-crbug.com/649046 fast/borders/inline-mask-overlay-image-outset.html [ NeedsRebaseline ]
-crbug.com/649046 fast/images/color-profile-image-profile-match.html [ NeedsRebaseline ]
-crbug.com/649046 tables/mozilla/bugs/bug4427.html [ NeedsRebaseline ]
-crbug.com/649046 svg/dynamic-updates/SVGImageElement-svgdom-width-prop.html [ NeedsRebaseline ]
-crbug.com/649046 svg/W3C-SVG-1.1/struct-image-02-b.svg [ NeedsRebaseline ]
-crbug.com/649046 tables/mozilla_expected_failures/bugs/bug6933.html [ NeedsRebaseline ]
-crbug.com/649046 fast/borders/border-image-side-reduction.html [ NeedsRebaseline ]
-crbug.com/649046 svg/custom/createImageElement2.xhtml [ NeedsRebaseline ]
-crbug.com/649046 tables/mozilla/other/cell_widths.html [ NeedsRebaseline ]
-crbug.com/649046 fast/images/ycbcr-with-cmyk-color-profile.html [ NeedsRebaseline ]
-crbug.com/649046 svg/W3C-SVG-1.1/struct-image-06-t.svg [ NeedsRebaseline ]
-crbug.com/649046 fast/images/color-profile-image-canvas.html [ NeedsRebaseline ]
-crbug.com/649046 tables/mozilla/bugs/bug1296.html [ NeedsRebaseline ]
-crbug.com/649046 fast/images/color-profile-image-filter-all.html [ NeedsRebaseline ]
-crbug.com/649046 svg/dynamic-updates/SVGImageElement-dom-x-attr.html [ NeedsRebaseline ]
-crbug.com/649046 tables/mozilla/bugs/bug11026.html [ NeedsRebaseline ]
-crbug.com/649046 svg/as-image/image-preserveAspectRatio-all.svg [ NeedsRebaseline ]
-crbug.com/649046 fast/text/emoji-web-font.html [ NeedsRebaseline ]
-crbug.com/649046 paint/invalidation/svg/js-update-image.svg [ NeedsRebaseline ]
-crbug.com/649046 svg/dynamic-updates/SVGImageElement-svgdom-x-prop.html [ NeedsRebaseline ]
-crbug.com/649046 tables/mozilla/core/bloomberg.html [ NeedsRebaseline ]
-crbug.com/649046 tables/mozilla/bugs/bug625.html [ NeedsRebaseline ]
-crbug.com/649046 fast/images/rgb-png-with-cmyk-color-profile.html [ NeedsRebaseline ]
-crbug.com/649046 tables/mozilla/bugs/bug1188.html [ NeedsRebaseline ]
-crbug.com/649046 fast/images/color-profile-image-canvas-pattern.html [ NeedsRebaseline ]
-crbug.com/649046 css3/blending/effect-background-blend-mode-stacking.html [ NeedsRebaseline ]
-crbug.com/649046 compositing/img-layer-object-fit.html [ NeedsRebaseline ]
-crbug.com/649046 svg/W3C-SVG-1.1/animate-elem-40-t.svg [ NeedsRebaseline ]
-crbug.com/649046 fast/css/absolute-child-with-percent-height-inside-relative-parent.html [ NeedsRebaseline ]
-crbug.com/649046 fast/images/color-profile-background-image-cover.html [ NeedsRebaseline ]
-crbug.com/649046 media/color-profile-video-poster-image.html [ NeedsRebaseline ]
-crbug.com/649046 tables/mozilla/bugs/bug4284.html [ NeedsRebaseline ]
-crbug.com/649046 svg/W3C-SVG-1.1/struct-image-08-t.svg [ NeedsRebaseline ]
-crbug.com/649046 tables/mozilla/bugs/bug56563.html [ NeedsRebaseline ]
-crbug.com/649046 media/video-poster-scale.html [ NeedsRebaseline ]
-crbug.com/649046 tables/mozilla/bugs/bug6404.html [ NeedsRebaseline ]
-crbug.com/649046 css3/blending/background-blend-mode-image-color.html [ NeedsRebaseline ]
-crbug.com/649046 fast/images/jpeg-yuv-progressive-image.html [ NeedsRebaseline ]
-crbug.com/649046 tables/mozilla/core/misc.html [ NeedsRebaseline ]
-crbug.com/649046 tables/mozilla/bugs/bug2981-2.html [ NeedsRebaseline ]
-crbug.com/649046 svg/dynamic-updates/SVGImageElement-dom-preserveAspectRatio-attr.html [ NeedsRebaseline ]
-crbug.com/649046 tables/mozilla/bugs/bug101674.html [ NeedsRebaseline ]
-crbug.com/649046 css3/blending/background-blend-mode-gradient-image.html [ NeedsRebaseline ]
-crbug.com/649046 svg/zoom/page/zoom-svg-through-object-with-percentage-size.xhtml [ NeedsRebaseline ]
-crbug.com/649046 fast/backgrounds/size/contain-and-cover.html [ NeedsRebaseline ]
-crbug.com/649046 svg/dynamic-updates/SVGImageElement-svgdom-height-prop.html [ NeedsRebaseline ]
-crbug.com/649046 fast/images/color-profile-mask-image-svg.html [ NeedsRebaseline ]
-crbug.com/649046 svg/custom/text-image-opacity.svg [ NeedsRebaseline ]
-crbug.com/649046 fast/forms/input-appearance-height.html [ NeedsRebaseline ]
-crbug.com/649046 svg/custom/image-parent-translation.xhtml [ NeedsRebaseline ]
-crbug.com/649046 svg/custom/createImageElement.svg [ NeedsRebaseline ]
-crbug.com/649046 fast/backgrounds/size/scaled-sprited-background.html [ NeedsRebaseline ]
-crbug.com/649046 [ Android Linux Mac Win10 ] fast/images/color-profile-background-image-space.html [ NeedsRebaseline ]
-crbug.com/649046 [ Android Linux Mac Win10 ] media/video-zoom-controls.html [ NeedsRebaseline ]
-crbug.com/649046 svg/dynamic-updates/SVGImageElement-dom-width-attr.html [ NeedsRebaseline ]
-crbug.com/649046 ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio.htm [ NeedsRebaseline ]
-crbug.com/649046 virtual/rootlayerscrolls/scrollbars/listbox-scrollbar-combinations.html [ NeedsRebaseline ]
-crbug.com/649046 scrollbars/listbox-scrollbar-combinations.html [ NeedsRebaseline ]
-crbug.com/649046 virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations.html [ NeedsRebaseline ]
-crbug.com/649046 [ Android Mac Win ] virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance.html [ NeedsRebaseline ]
-crbug.com/649046 [ Android Mac Win ] virtual/scalefactor150/fast/hidpi/static/data-suggestion-picker-appearance.html [ NeedsRebaseline ]
-crbug.com/649046 fast/text/international/thai-line-breaks.html [ NeedsRebaseline ]
diff --git a/third_party/WebKit/LayoutTests/VirtualTestSuites b/third_party/WebKit/LayoutTests/VirtualTestSuites
index ea0760b..6d75989 100644
--- a/third_party/WebKit/LayoutTests/VirtualTestSuites
+++ b/third_party/WebKit/LayoutTests/VirtualTestSuites
@@ -288,5 +288,10 @@
     "prefix": "enable_wasm",
     "base": "http/tests/wasm",
     "args": ["--enable-wasm"]
+  },
+  {
+    "prefix": "mojo-service-worker",
+    "base": "http/tests/serviceworker",
+    "args": ["--mojo-service-worker"]
   }
 ]
diff --git a/third_party/WebKit/LayoutTests/accessibility/bounds-calc.html b/third_party/WebKit/LayoutTests/accessibility/bounds-calc.html
index 2af241f..3f2a7813 100644
--- a/third_party/WebKit/LayoutTests/accessibility/bounds-calc.html
+++ b/third_party/WebKit/LayoutTests/accessibility/bounds-calc.html
@@ -51,6 +51,7 @@
     <svg id="svg" width="60" height="60">
       <circle role="button" id="svg_circle" r="25" cx="30" cy="30" stroke="blue" stroke-width="1"/>
     </svg>
+    <p id="twolines">First line<br>Second line</p>
 </div>
 
 <script>
@@ -71,22 +72,23 @@
     assert_approx_equals(axObject.boundsHeight, bounds.height, epsilon, id + " height");
 }
 
-function assertStaticTextChildDOMRectSameAsAXRect(id) {
+function assertStaticTextChildDOMRectSameAsAXRect(id, index) {
     var element = document.getElementById(id);
     var axObject = accessibilityController.accessibleElementById(id);
     var text = element.firstChild;
-    var axText = axObject.childAtIndex(0);
-    assert_equals(text.nodeType, Node.TEXT_NODE, id + " firstChild nodeType");
-    assert_equals(axText.role, "AXRole: AXStaticText", id + " AX first child role");
+    for (var i = 0; i < index; i++)
+        text = text.nextSibling;
+    var axText = axObject.childAtIndex(index);
+    assert_equals(text.nodeType, Node.TEXT_NODE, id + " child " + index + " nodeType");
+    assert_equals(axText.role, "AXRole: AXStaticText", id + " AX child " + index + " role");
     var range = document.createRange();
     range.selectNode(text);
     var bounds = range.getBoundingClientRect();
-    var axObject = accessibilityController.accessibleElementById(id);
     var epsilon = 1;
-    assert_approx_equals(axText.boundsX, bounds.left, epsilon, id + " left");
-    assert_approx_equals(axText.boundsY, bounds.top, epsilon, id + " left");
-    assert_approx_equals(axText.boundsWidth, bounds.width, epsilon, id + " left");
-    assert_approx_equals(axText.boundsHeight, bounds.height, epsilon, id + " left");
+    assert_approx_equals(axText.boundsX, bounds.left, epsilon, id + " child " + index + " left");
+    assert_approx_equals(axText.boundsY, bounds.top, epsilon, id + " child " + index + " top");
+    assert_approx_equals(axText.boundsWidth, bounds.width, epsilon, id + " child " + index + " width");
+    assert_approx_equals(axText.boundsHeight, bounds.height, epsilon, id + " child " + index + " height");
 }
 
 function assertOffsetContainerIs(id, containerId, opt_expectedResult) {
@@ -111,26 +113,31 @@
     assertDOMRectSameAsAXRect("radio");
     assertDOMRectSameAsAXRect("button");
     assertDOMRectSameAsAXRect("heading");
-    assertStaticTextChildDOMRectSameAsAXRect("heading");
+    assertStaticTextChildDOMRectSameAsAXRect("heading", 0);
     assertDOMRectSameAsAXRect("para");
-    assertStaticTextChildDOMRectSameAsAXRect("para");
+    assertStaticTextChildDOMRectSameAsAXRect("para", 0);
     assertDOMRectSameAsAXRect("span");
-    assertStaticTextChildDOMRectSameAsAXRect("span");
+    assertStaticTextChildDOMRectSameAsAXRect("span", 0);
     assertDOMRectSameAsAXRect("ul");
     assertDOMRectSameAsAXRect("li1");
     assertDOMRectSameAsAXRect("li2");
     assertDOMRectSameAsAXRect("div");
-    assertStaticTextChildDOMRectSameAsAXRect("div");
+    assertStaticTextChildDOMRectSameAsAXRect("div", 0);
     assertDOMRectSameAsAXRect("border");
-    assertStaticTextChildDOMRectSameAsAXRect("border");
+    assertStaticTextChildDOMRectSameAsAXRect("border", 0);
     assertDOMRectSameAsAXRect("padding");
-    assertStaticTextChildDOMRectSameAsAXRect("padding");
+    assertStaticTextChildDOMRectSameAsAXRect("padding", 0);
     assertDOMRectSameAsAXRect("margin");
-    assertStaticTextChildDOMRectSameAsAXRect("margin");
-    assertDOMRectSameAsAXRect("border_padding_margin");
-    assertStaticTextChildDOMRectSameAsAXRect("border_padding_margin");
+    assertStaticTextChildDOMRectSameAsAXRect("margin", 0);
+    assertDOMRectSameAsAXRect("border_padding_margin", 0);
+    assertStaticTextChildDOMRectSameAsAXRect("border_padding_margin", 0);
     assertDOMRectSameAsAXRect("svg");
     assertDOMRectSameAsAXRect("svg_circle");
+
+    // Test both static text elements in <p>First line<br>Second line</p>.
+    // We don't care about the bounding box of the <br> element in-between.
+    assertStaticTextChildDOMRectSameAsAXRect("twolines", 0);
+    assertStaticTextChildDOMRectSameAsAXRect("twolines", 2);
 }, "Test computed AX rect for some common objects");
 </script>
 
diff --git a/third_party/WebKit/LayoutTests/accessibility/inline-text-bounds-for-range-br.html b/third_party/WebKit/LayoutTests/accessibility/inline-text-bounds-for-range-br.html
new file mode 100644
index 0000000..843b49e6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/accessibility/inline-text-bounds-for-range-br.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+
+<p id="paragraph">Line 1<br>Line 2</p>
+
+<script>
+test(function(t) {
+    // Due to rounding we won't get identical bounds as getBoundingClientRect(),
+    // so allow the test to pass if we're within 1 pixel.
+    var epsilon = 1;
+
+    var axParagraph = accessibilityController.accessibleElementById("paragraph");
+    var axStaticText1 = axParagraph.childAtIndex(0);
+    eval("var axTextBounds1 = " + axStaticText1.boundsForRange(0, 6));
+
+    var paragraph = document.getElementById("paragraph");
+    var range = new Range();
+    range.setStart(paragraph.firstChild, 0);
+    range.setEnd(paragraph.firstChild, 6);
+    var rangeBounds = range.getBoundingClientRect();
+
+    assert_approx_equals(axTextBounds1.x, rangeBounds.left, epsilon, "Line 1 left");
+    assert_approx_equals(axTextBounds1.y, rangeBounds.top, epsilon, "Line 1 top");
+    assert_approx_equals(axTextBounds1.width, rangeBounds.width, epsilon, "Line 1 width");
+    assert_approx_equals(axTextBounds1.height, rangeBounds.height, epsilon, "Line 1 height");
+
+    var axStaticText2 = axParagraph.childAtIndex(2);
+    eval("var axTextBounds2 = " + axStaticText2.boundsForRange(0, 6));
+    range.setStart(paragraph.lastChild, 0);
+    range.setEnd(paragraph.lastChild, 6);
+    rangeBounds = range.getBoundingClientRect();
+
+    assert_approx_equals(axTextBounds2.x, rangeBounds.left, epsilon, "Line 2 left");
+    assert_approx_equals(axTextBounds2.y, rangeBounds.top, epsilon, "Line 2 top");
+    assert_approx_equals(axTextBounds2.width, rangeBounds.width, epsilon, "Line 2 width");
+    assert_approx_equals(axTextBounds2.height, rangeBounds.height, epsilon, "Line 2 height");
+}, "Check bounds of inline text boxes after line breaks");
+</script>
diff --git a/third_party/WebKit/LayoutTests/animations/add-keyframes-in-shadow-recalc.html b/third_party/WebKit/LayoutTests/animations/add-keyframes-in-shadow-recalc.html
new file mode 100644
index 0000000..ef481a3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/animations/add-keyframes-in-shadow-recalc.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<div id="host"></div>
+<div></div>
+<div></div>
+<div></div>
+<div></div>
+<script>
+    test(() => assert_not_equals(window.internals, undefined, "Needs window.internals for testing."), "Check that window.internals is defined");
+
+    var root = host.attachShadow({mode:"open"});
+    root.innerHTML = "<div></div><div></div><div></div>";
+    host.offsetTop;
+
+    test(() => {
+        var sheet = document.createElement("style");
+        sheet.appendChild(document.createTextNode(`
+            @keyframes unused {
+                from { color: pink }
+                to { color: orange }
+            }`));
+        root.appendChild(sheet);
+        // TODO(rune@opera.com): This count should be 1 when async stylesheet
+        // update with RuleSet invalidations land. Currently we always do a
+        // subtree recalc for stylesheet mutations in shadow trees.
+        assert_equals(internals.updateStyleAndReturnAffectedElementCount(), 5,
+            "Recalc for shadow tree, including host and inserted style element.");
+    }, "Check that adding @keyframes does not cause a style recalc of the host element when no animations are running.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/getCharacteristic/invalid-characteristic-name.html b/third_party/WebKit/LayoutTests/bluetooth/getCharacteristic/invalid-characteristic-name.html
index 7d30be3..ea1eada 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/getCharacteristic/invalid-characteristic-name.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/getCharacteristic/invalid-characteristic-name.html
@@ -24,8 +24,8 @@
           'https://developer.bluetooth.org/gatt/characteristics/' +
           'Pages/CharacteristicsHome.aspx' +
           ' e.g. \'aerobic_heart_rate_lower_limit\'.',
-          'SyntaxError'),
+          'TypeError'),
         'Wrong Characteristic name passed.');
     });
-}, 'Wrong Characteristic name. Reject with SyntaxError.');
+}, 'Wrong Characteristic name. Reject with TypeError.');
 </script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/getCharacteristics/invalid-characteristic-name.html b/third_party/WebKit/LayoutTests/bluetooth/getCharacteristics/invalid-characteristic-name.html
index 98f0469..79aef58 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/getCharacteristics/invalid-characteristic-name.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/getCharacteristics/invalid-characteristic-name.html
@@ -24,8 +24,8 @@
           'https://developer.bluetooth.org/gatt/characteristics/' +
           'Pages/CharacteristicsHome.aspx' +
           ' e.g. \'aerobic_heart_rate_lower_limit\'.',
-          'SyntaxError'),
+          'TypeError'),
         'Wrong Characteristic name passed.');
     });
-}, 'Invalid Characteristic name. Reject with SyntaxError.');
+}, 'Invalid Characteristic name. Reject with TypeError.');
 </script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/getPrimaryService/invalid-service-name.html b/third_party/WebKit/LayoutTests/bluetooth/getPrimaryService/invalid-service-name.html
index 53f9cc2..f2400b9 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/getPrimaryService/invalid-service-name.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/getPrimaryService/invalid-service-name.html
@@ -21,8 +21,8 @@
           'or recognized standard name from ' +
           'https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx' +
           ' e.g. \'alert_notification\'.',
-          'SyntaxError'),
+          'TypeError'),
         'Wrong Service name passed.');
     });
-}, 'Wrong Service name. Reject with SyntaxError.');
+}, 'Wrong Service name. Reject with TypeError.');
 </script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/getPrimaryServices/invalid-service-name.html b/third_party/WebKit/LayoutTests/bluetooth/getPrimaryServices/invalid-service-name.html
index 9c8d4e728..b74260fc 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/getPrimaryServices/invalid-service-name.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/getPrimaryServices/invalid-service-name.html
@@ -21,8 +21,8 @@
           'or recognized standard name from ' +
           'https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx' +
           ' e.g. \'alert_notification\'.',
-          'SyntaxError'),
+          'TypeError'),
         'Wrong Service name passed.');
     });
-}, 'Wrong Service name. Reject with SyntaxError.');
+}, 'Wrong Service name. Reject with TypeError.');
 </script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/idl-BluetoothUUID.html b/third_party/WebKit/LayoutTests/bluetooth/idl-BluetoothUUID.html
index 64d3d14..9a7252e 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/idl-BluetoothUUID.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/idl-BluetoothUUID.html
@@ -67,23 +67,23 @@
 
 test(() => {
   let all_caps_uuid = '1A2B3C4D-5E6F-7A8B-9C0D-1E2F3A4B5C6D';
-  assert_throws('SyntaxError', () => BluetoothUUID.getService(all_caps_uuid));
-  assert_throws('SyntaxError', () => BluetoothUUID.getCharacteristic(all_caps_uuid));
-  assert_throws('SyntaxError', () => BluetoothUUID.getDescriptor(all_caps_uuid));
+  assert_throws(TypeError(), () => BluetoothUUID.getService(all_caps_uuid));
+  assert_throws(TypeError(), () => BluetoothUUID.getCharacteristic(all_caps_uuid));
+  assert_throws(TypeError(), () => BluetoothUUID.getDescriptor(all_caps_uuid));
 }, 'A UUID String with uppercase letters is an invalid UUID.');
 
 test(() => {
   let string_alias = 'deadbeef';
-  assert_throws('SyntaxError', () => BluetoothUUID.getService(string_alias));
-  assert_throws('SyntaxError', () => BluetoothUUID.getCharacteristic(string_alias));
-  assert_throws('SyntaxError', () => BluetoothUUID.getDescriptor(string_alias));
+  assert_throws(TypeError(), () => BluetoothUUID.getService(string_alias));
+  assert_throws(TypeError(), () => BluetoothUUID.getCharacteristic(string_alias));
+  assert_throws(TypeError(), () => BluetoothUUID.getDescriptor(string_alias));
 }, 'A 32bit *String* alias is invalid.');
 
 test(() => {
   let invalid_character_uuid = '0000000g-0000-1000-8000-00805f9b34fb';
-  assert_throws('SyntaxError', () => BluetoothUUID.getService(invalid_character_uuid));
-  assert_throws('SyntaxError', () => BluetoothUUID.getCharacteristic(invalid_character_uuid));
-  assert_throws('SyntaxError', () => BluetoothUUID.getDescriptor(invalid_character_uuid));
+  assert_throws(TypeError(), () => BluetoothUUID.getService(invalid_character_uuid));
+  assert_throws(TypeError(), () => BluetoothUUID.getCharacteristic(invalid_character_uuid));
+  assert_throws(TypeError(), () => BluetoothUUID.getDescriptor(invalid_character_uuid));
 }, 'A UUID with invalid characters is an invalid UUID.');
 
 test(() => {
@@ -96,31 +96,31 @@
 }, 'A valid UUID from a name.');
 
 test(() => {
-  assert_throws('SyntaxError', () => {
+  assert_throws(TypeError(), () => {
     BluetoothUUID.getService('aerobic_heart_rate_lower_limit');
   });
-  assert_throws('SyntaxError', () => {
+  assert_throws(TypeError(), () => {
     BluetoothUUID.getService('gatt.characteristic_extended_properties');
   });
-  assert_throws('SyntaxError', () => {
+  assert_throws(TypeError(), () => {
     BluetoothUUID.getCharacteristic('alert_notification');
   });
-  assert_throws('SyntaxError', () => {
+  assert_throws(TypeError(), () => {
     BluetoothUUID.getCharacteristic('gatt.characteristic_extended_properties');
   });
-  assert_throws('SyntaxError', () => {
+  assert_throws(TypeError(), () => {
     BluetoothUUID.getDescriptor('alert_notification');
   });
-  assert_throws('SyntaxError', () => {
+  assert_throws(TypeError(), () => {
     BluetoothUUID.getDescriptor('aerobic_heart_rate_lower_limit');
   });
 }, 'Make sure attributes don\'t share a map');
 
 test(() => {
   let wrong_name = 'wrong_name';
-  assert_throws('SyntaxError', () => BluetoothUUID.getService(wrong_name));
-  assert_throws('SyntaxError', () => BluetoothUUID.getCharacteristic(wrong_name));
-  assert_throws('SyntaxError', () => BluetoothUUID.getDescriptor(wrong_name));
+  assert_throws(TypeError(), () => BluetoothUUID.getService(wrong_name));
+  assert_throws(TypeError(), () => BluetoothUUID.getCharacteristic(wrong_name));
+  assert_throws(TypeError(), () => BluetoothUUID.getDescriptor(wrong_name));
 }, 'Invalid Descriptor name');
 
 test(() => {
@@ -140,27 +140,27 @@
   assert_throws(new TypeError, () => BluetoothUUID.canonicalUUID(NaN));
 
   // getService
-  assert_throws('SyntaxError', () => BluetoothUUID.getService(object));
-  assert_throws('SyntaxError', () => BluetoothUUID.getService(array));
-  assert_throws('SyntaxError', () => BluetoothUUID.getService(func));
-  assert_throws('SyntaxError', () => BluetoothUUID.getService(undefined));
-  assert_throws('SyntaxError', () => BluetoothUUID.getService(null));
-  assert_throws('SyntaxError', () => BluetoothUUID.getService(false));
+  assert_throws(TypeError(), () => BluetoothUUID.getService(object));
+  assert_throws(TypeError(), () => BluetoothUUID.getService(array));
+  assert_throws(TypeError(), () => BluetoothUUID.getService(func));
+  assert_throws(TypeError(), () => BluetoothUUID.getService(undefined));
+  assert_throws(TypeError(), () => BluetoothUUID.getService(null));
+  assert_throws(TypeError(), () => BluetoothUUID.getService(false));
 
   // getCharacteristic
-  assert_throws('SyntaxError', () => BluetoothUUID.getCharacteristic(object));
-  assert_throws('SyntaxError', () => BluetoothUUID.getCharacteristic(array));
-  assert_throws('SyntaxError', () => BluetoothUUID.getCharacteristic(func));
-  assert_throws('SyntaxError', () => BluetoothUUID.getCharacteristic(undefined));
-  assert_throws('SyntaxError', () => BluetoothUUID.getCharacteristic(null));
-  assert_throws('SyntaxError', () => BluetoothUUID.getCharacteristic(false));
+  assert_throws(TypeError(), () => BluetoothUUID.getCharacteristic(object));
+  assert_throws(TypeError(), () => BluetoothUUID.getCharacteristic(array));
+  assert_throws(TypeError(), () => BluetoothUUID.getCharacteristic(func));
+  assert_throws(TypeError(), () => BluetoothUUID.getCharacteristic(undefined));
+  assert_throws(TypeError(), () => BluetoothUUID.getCharacteristic(null));
+  assert_throws(TypeError(), () => BluetoothUUID.getCharacteristic(false));
 
   // getDescriptor
-  assert_throws('SyntaxError', () => BluetoothUUID.getDescriptor(object));
-  assert_throws('SyntaxError', () => BluetoothUUID.getDescriptor(array));
-  assert_throws('SyntaxError', () => BluetoothUUID.getDescriptor(func));
-  assert_throws('SyntaxError', () => BluetoothUUID.getDescriptor(undefined));
-  assert_throws('SyntaxError', () => BluetoothUUID.getDescriptor(null));
-  assert_throws('SyntaxError', () => BluetoothUUID.getDescriptor(false));
+  assert_throws(TypeError(), () => BluetoothUUID.getDescriptor(object));
+  assert_throws(TypeError(), () => BluetoothUUID.getDescriptor(array));
+  assert_throws(TypeError(), () => BluetoothUUID.getDescriptor(func));
+  assert_throws(TypeError(), () => BluetoothUUID.getDescriptor(undefined));
+  assert_throws(TypeError(), () => BluetoothUUID.getDescriptor(null));
+  assert_throws(TypeError(), () => BluetoothUUID.getDescriptor(false));
 }, 'Non-number and non-strings');
 </script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/canonicalizeFilter/wrong-service-in-optionalServices-member.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/canonicalizeFilter/wrong-service-in-optionalServices-member.html
index 4a7c296..dadbb5e8 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/canonicalizeFilter/wrong-service-in-optionalServices-member.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/canonicalizeFilter/wrong-service-in-optionalServices-member.html
@@ -34,7 +34,7 @@
       let test_promises = Promise.resolve();
       test_specs.forEach(args => {
         test_promises = test_promises.then(() => promise_rejects(
-           t, 'SyntaxError', requestDeviceWithKeyDown(args)));
+           t, TypeError(), requestDeviceWithKeyDown(args)));
       });
       return test_promises;
     });
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/canonicalizeFilter/wrong-service-in-services-member.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/canonicalizeFilter/wrong-service-in-services-member.html
index d5d1511..5ae3c4e 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/canonicalizeFilter/wrong-service-in-services-member.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/canonicalizeFilter/wrong-service-in-services-member.html
@@ -9,7 +9,7 @@
       let test_promises = Promise.resolve();
       generateRequestDeviceArgsWithServices(['wrong_service']).forEach(args => {
         test_promises = test_promises.then(() => promise_rejects(
-          t, 'SyntaxError', requestDeviceWithKeyDown(args)));
+          t, TypeError(), requestDeviceWithKeyDown(args)));
       });
       return test_promises;
     });
diff --git a/third_party/WebKit/LayoutTests/compositing/contents-opaque/overflow-hidden-child-layers-expected.txt b/third_party/WebKit/LayoutTests/compositing/contents-opaque/overflow-hidden-child-layers-expected.txt
index c6a81d6..42fe6fb 100644
--- a/third_party/WebKit/LayoutTests/compositing/contents-opaque/overflow-hidden-child-layers-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/contents-opaque/overflow-hidden-child-layers-expected.txt
@@ -10,8 +10,8 @@
       "children": [
         {
           "name": "LayoutBlockFlow DIV class='box'",
-          "position": [38, 30],
-          "bounds": [140, 140],
+          "position": [39, 31],
+          "bounds": [138, 138],
           "drawsContent": true,
           "backgroundColor": "#0000FF"
         }
diff --git a/third_party/WebKit/LayoutTests/compositing/culling/scrolled-within-boxshadow-expected.png b/third_party/WebKit/LayoutTests/compositing/culling/scrolled-within-boxshadow-expected.png
index 5d81bdc8..35d9b26 100644
--- a/third_party/WebKit/LayoutTests/compositing/culling/scrolled-within-boxshadow-expected.png
+++ b/third_party/WebKit/LayoutTests/compositing/culling/scrolled-within-boxshadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/compositing/culling/translated-boxshadow-expected.png b/third_party/WebKit/LayoutTests/compositing/culling/translated-boxshadow-expected.png
index e1fb5a2..0b7ed078 100644
--- a/third_party/WebKit/LayoutTests/compositing/culling/translated-boxshadow-expected.png
+++ b/third_party/WebKit/LayoutTests/compositing/culling/translated-boxshadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/compositing/culling/unscrolled-within-boxshadow-expected.png b/third_party/WebKit/LayoutTests/compositing/culling/unscrolled-within-boxshadow-expected.png
index 5d81bdc8..35d9b26 100644
--- a/third_party/WebKit/LayoutTests/compositing/culling/unscrolled-within-boxshadow-expected.png
+++ b/third_party/WebKit/LayoutTests/compositing/culling/unscrolled-within-boxshadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/foreground-layer-expected.txt b/third_party/WebKit/LayoutTests/compositing/geometry/foreground-layer-expected.txt
index ea7e791f..e5bf5d70 100644
--- a/third_party/WebKit/LayoutTests/compositing/geometry/foreground-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/geometry/foreground-layer-expected.txt
@@ -11,14 +11,14 @@
       "children": [
         {
           "name": "LayoutBlockFlow (relative positioned) DIV class='main box'",
-          "position": [18, 88],
-          "bounds": [320, 320],
+          "position": [19, 89],
+          "bounds": [318, 318],
           "drawsContent": true,
           "backgroundColor": "#FF0000",
           "children": [
             {
               "name": "LayoutBlockFlow (positioned) DIV class='negative child'",
-              "position": [60, 60],
+              "position": [59, 59],
               "bounds": [50, 50],
               "transform": [
                 [1, 0, 0, 0],
@@ -29,21 +29,21 @@
             },
             {
               "name": "LayoutBlockFlow (relative positioned) DIV class='main box' (foreground) Layer",
-              "bounds": [320, 320],
+              "bounds": [318, 318],
               "drawsContent": true
             }
           ]
         },
         {
           "name": "LayoutBlockFlow (relative positioned) DIV class='main box'",
-          "position": [362, 18],
-          "bounds": [320, 320],
+          "position": [363, 19],
+          "bounds": [318, 318],
           "drawsContent": true,
           "backgroundColor": "#FF0000",
           "children": [
             {
               "name": "Child Containment Layer",
-              "position": [60, 60],
+              "position": [59, 59],
               "bounds": [200, 200],
               "children": [
                 {
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/composited-parent-iframe-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/composited-parent-iframe-expected.txt
index 0353e22a..98f85369 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/composited-parent-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/composited-parent-iframe-expected.txt
@@ -11,13 +11,13 @@
       "children": [
         {
           "name": "LayoutIFrame IFRAME",
-          "position": [-12, -12],
-          "bounds": [370, 220],
+          "position": [-11, -11],
+          "bounds": [368, 218],
           "drawsContent": true,
           "children": [
             {
               "name": "Frame Overflow Controls Host Layer",
-              "position": [35, 35],
+              "position": [34, 34],
               "bounds": [300, 150],
               "children": [
                 {
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe-delayed-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe-delayed-expected.txt
index 255528bb..81be0a1 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe-delayed-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe-delayed-expected.txt
@@ -13,13 +13,13 @@
       "children": [
         {
           "name": "LayoutIFrame IFRAME id='iframe'",
-          "position": [8, 108],
-          "bounds": [370, 220],
+          "position": [9, 109],
+          "bounds": [368, 218],
           "drawsContent": true,
           "children": [
             {
               "name": "Frame Overflow Controls Host Layer",
-              "position": [35, 35],
+              "position": [34, 34],
               "bounds": [300, 150],
               "children": [
                 {
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe-expected.txt
index 8d96c672..5eb9222 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe-expected.txt
@@ -11,13 +11,13 @@
       "children": [
         {
           "name": "LayoutIFrame IFRAME id='parent-iframe'",
-          "position": [8, 8],
-          "bounds": [370, 220],
+          "position": [9, 9],
+          "bounds": [368, 218],
           "drawsContent": true,
           "children": [
             {
               "name": "Frame Overflow Controls Host Layer",
-              "position": [35, 35],
+              "position": [34, 34],
               "bounds": [300, 150],
               "children": [
                 {
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe2-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe2-expected.txt
index 7543194..5651940 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe2-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe2-expected.txt
@@ -11,13 +11,13 @@
       "children": [
         {
           "name": "LayoutIFrame IFRAME id='iframe' class='composited'",
-          "position": [8, 8],
-          "bounds": [370, 220],
+          "position": [9, 9],
+          "bounds": [368, 218],
           "drawsContent": true,
           "children": [
             {
               "name": "Frame Overflow Controls Host Layer",
-              "position": [35, 35],
+              "position": [34, 34],
               "bounds": [300, 150],
               "children": [
                 {
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe3-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe3-expected.txt
index 5839791..13d3e635 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe3-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe3-expected.txt
@@ -11,13 +11,13 @@
       "children": [
         {
           "name": "LayoutIFrame IFRAME id='iframe' class='composited'",
-          "position": [8, 8],
-          "bounds": [370, 220],
+          "position": [9, 9],
+          "bounds": [368, 218],
           "drawsContent": true,
           "children": [
             {
               "name": "Frame Overflow Controls Host Layer",
-              "position": [35, 35],
+              "position": [34, 34],
               "bounds": [300, 150],
               "children": [
                 {
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/enter-compositing-iframe-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/enter-compositing-iframe-expected.txt
index 8d96c672..5eb9222 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/enter-compositing-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/enter-compositing-iframe-expected.txt
@@ -11,13 +11,13 @@
       "children": [
         {
           "name": "LayoutIFrame IFRAME id='parent-iframe'",
-          "position": [8, 8],
-          "bounds": [370, 220],
+          "position": [9, 9],
+          "bounds": [368, 218],
           "drawsContent": true,
           "children": [
             {
               "name": "Frame Overflow Controls Host Layer",
-              "position": [35, 35],
+              "position": [34, 34],
               "bounds": [300, 150],
               "children": [
                 {
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/iframe-resize-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/iframe-resize-expected.txt
index 3ae65e99..29b412e 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/iframe-resize-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/iframe-resize-expected.txt
@@ -11,13 +11,13 @@
       "children": [
         {
           "name": "LayoutIFrame IFRAME id='parent-iframe' class='bigger'",
-          "position": [8, 8],
-          "bounds": [470, 190],
+          "position": [9, 9],
+          "bounds": [468, 188],
           "drawsContent": true,
           "children": [
             {
               "name": "Frame Overflow Controls Host Layer",
-              "position": [35, 35],
+              "position": [34, 34],
               "bounds": [400, 120],
               "children": [
                 {
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/invisible-nested-iframe-show-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/invisible-nested-iframe-show-expected.txt
index 3fd5ca4b..71b75af 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/invisible-nested-iframe-show-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/invisible-nested-iframe-show-expected.txt
@@ -11,13 +11,13 @@
       "children": [
         {
           "name": "LayoutIFrame IFRAME",
-          "position": [-12, -12],
-          "bounds": [370, 220],
+          "position": [-11, -11],
+          "bounds": [368, 218],
           "drawsContent": true,
           "children": [
             {
               "name": "Frame Overflow Controls Host Layer",
-              "position": [35, 35],
+              "position": [34, 34],
               "bounds": [300, 150],
               "children": [
                 {
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/overlapped-iframe-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/overlapped-iframe-expected.txt
index 509057ba..86bc611d 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/overlapped-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/overlapped-iframe-expected.txt
@@ -11,13 +11,13 @@
       "children": [
         {
           "name": "LayoutIFrame IFRAME id='parent-iframe'",
-          "position": [8, 8],
-          "bounds": [370, 220],
+          "position": [9, 9],
+          "bounds": [368, 218],
           "drawsContent": true,
           "children": [
             {
               "name": "Frame Overflow Controls Host Layer",
-              "position": [35, 35],
+              "position": [34, 34],
               "bounds": [300, 150],
               "children": [
                 {
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/scrolling-iframe-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/scrolling-iframe-expected.txt
index 225aa06d..301b11b 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/scrolling-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/scrolling-iframe-expected.txt
@@ -11,13 +11,13 @@
       "children": [
         {
           "name": "LayoutIFrame IFRAME id='parent-iframe'",
-          "position": [8, 8],
-          "bounds": [370, 220],
+          "position": [9, 9],
+          "bounds": [368, 218],
           "drawsContent": true,
           "children": [
             {
               "name": "Frame Overflow Controls Host Layer",
-              "position": [35, 35],
+              "position": [34, 34],
               "bounds": [300, 150],
               "children": [
                 {
diff --git a/third_party/WebKit/LayoutTests/compositing/img-layer-object-fit-expected.png b/third_party/WebKit/LayoutTests/compositing/img-layer-object-fit-expected.png
index 9c9cc0c..b4f8cd3 100644
--- a/third_party/WebKit/LayoutTests/compositing/img-layer-object-fit-expected.png
+++ b/third_party/WebKit/LayoutTests/compositing/img-layer-object-fit-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/rotate3d-overlap-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/rotate3d-overlap-expected.txt
index 2adfdeb..4b65745 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/rotate3d-overlap-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/rotate3d-overlap-expected.txt
@@ -12,22 +12,34 @@
       "children": [
         {
           "name": "LayoutBlockFlow (relative positioned) DIV class='box translateZ'",
-          "position": [25, 25],
-          "bounds": [106, 106],
+          "position": [23, 23],
+          "bounds": [110, 110],
           "drawsContent": true,
           "backgroundColor": "#0000FF"
         },
         {
-          "name": "LayoutBlockFlow (relative positioned) DIV class='composited box rotate15'",
-          "position": [169, 25],
-          "bounds": [106, 106],
-          "drawsContent": true,
-          "backgroundColor": "#0000FF",
-          "transform": [
-            [0.965925826289068, 0.258819045102521, 0, 0],
-            [-0.258819045102521, 0.965925826289068, 0, 0],
-            [0, 0, 1, 0],
-            [0, 0, 0, 1]
+          "name": "Squashing Containment Layer",
+          "shouldFlattenTransform": false,
+          "children": [
+            {
+              "name": "LayoutBlockFlow (relative positioned) DIV class='composited box rotate15'",
+              "position": [167, 23],
+              "bounds": [110, 110],
+              "drawsContent": true,
+              "backgroundColor": "#0000FF",
+              "transform": [
+                [0.965925826289068, 0.258819045102521, 0, 0],
+                [-0.258819045102521, 0.965925826289068, 0, 0],
+                [0, 0, 1, 0],
+                [0, 0, 0, 1]
+              ]
+            },
+            {
+              "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (relative positioned) DIV class='box')",
+              "position": [167, 143],
+              "bounds": [110, 110],
+              "drawsContent": true
+            }
           ]
         },
         {
@@ -36,8 +48,8 @@
           "children": [
             {
               "name": "LayoutBlockFlow (relative positioned) DIV class='composited box rotate45'",
-              "position": [313, 25],
-              "bounds": [106, 106],
+              "position": [311, 23],
+              "bounds": [110, 110],
               "drawsContent": true,
               "backgroundColor": "#0000FF",
               "transform": [
@@ -49,8 +61,8 @@
             },
             {
               "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (relative positioned) DIV class='box')",
-              "position": [313, 145],
-              "bounds": [106, 106],
+              "position": [311, 143],
+              "bounds": [110, 110],
               "drawsContent": true
             }
           ]
diff --git a/third_party/WebKit/LayoutTests/css3/motion-path/offsetParent.html b/third_party/WebKit/LayoutTests/css3/motion-path/offsetParent.html
new file mode 100644
index 0000000..16dd515
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/motion-path/offsetParent.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<section id="container" style="will-change: transform">
+    <div id="d1" style="offset-position: 0% 0%">
+        <span id="s1"></span>
+    </div>
+    <div id="d2" style="offset-path: path('m 0 0 z')">
+        <span id="s2"></span>
+    </div>
+   <div id="d3" style="offset-distance: 100%">
+        <span id="s3"></span>
+    </div>
+   <div id="d4" style="offset-rotation: 360deg">
+        <span id="s4"></span>
+    </div>
+   <div id="d5" style="offset-anchor: bottom right">
+        <span id="s5"></span>
+    </div>
+</section>
+<script>
+'use strict';
+test(function() {
+    assert_equals(s1.offsetParent, d1);
+}, "inside offset-position");
+test(function() {
+    assert_equals(s2.offsetParent, d2);
+}, "inside offset-path");
+test(function() {
+    assert_equals(s3.offsetParent, container);
+}, "inside offset-distance");
+test(function() {
+    assert_equals(s4.offsetParent, container);
+}, "inside offset-rotation");
+test(function() {
+    assert_equals(s5.offsetParent, container);
+}, "inside offset-anchor");
+</script>
diff --git a/third_party/WebKit/LayoutTests/css3/motion-path/path-establishes-stacking-context-expected.html b/third_party/WebKit/LayoutTests/css3/motion-path/path-establishes-stacking-context-expected.html
index a5859ca..fd53222b 100644
--- a/third_party/WebKit/LayoutTests/css3/motion-path/path-establishes-stacking-context-expected.html
+++ b/third_party/WebKit/LayoutTests/css3/motion-path/path-establishes-stacking-context-expected.html
@@ -5,6 +5,7 @@
 
 div {
   width: 800px;
+  height: 300px;
 }
 
 span {
diff --git a/third_party/WebKit/LayoutTests/css3/motion-path/path-establishes-stacking-context.html b/third_party/WebKit/LayoutTests/css3/motion-path/path-establishes-stacking-context.html
index 07dfd60..02de5091 100644
--- a/third_party/WebKit/LayoutTests/css3/motion-path/path-establishes-stacking-context.html
+++ b/third_party/WebKit/LayoutTests/css3/motion-path/path-establishes-stacking-context.html
@@ -5,6 +5,7 @@
 
 div {
   width: 800px;
+  height: 300px;
 }
 
 span {
@@ -36,7 +37,7 @@
 }
 
 #div1 {
-  offset-path: path('M400,0');
+  offset-path: path('M400,150');
 }
 
 #div2 {
diff --git a/third_party/WebKit/LayoutTests/css3/motion-path/path-will-change-establishes-stacking-context-expected.html b/third_party/WebKit/LayoutTests/css3/motion-path/path-will-change-establishes-stacking-context-expected.html
new file mode 100644
index 0000000..b5909bf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/motion-path/path-will-change-establishes-stacking-context-expected.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+
+* {
+  margin: 0;
+  padding: 0;
+}
+
+div {
+  width: 800px;
+  height: 300px;
+}
+
+span {
+  position: absolute;
+  width: 120px;
+  line-height: 120px;
+  text-align: center;
+  color: yellow;
+}
+
+#span1 {
+  z-index: 2;
+  left: 50px;
+  top: 50px;
+  background: red;
+}
+
+#span2 {
+  z-index: 1;
+  left: 100px;
+  top: 100px;
+  background: green;
+}
+
+#span3 {
+  left: 150px;
+  top: 150px;
+  background: blue;
+}
+
+#div1 {
+  transform: rotate(0deg);
+}
+
+</style>
+</head>
+<body>
+
+<div id="div1">
+  <span id="span1">First</span>
+</div>
+<div id="div2">
+  <span id="span2">Second</span>
+</div>
+<div id="div3">
+  <span id="span3">Third</span>
+</div>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/css3/motion-path/path-will-change-establishes-stacking-context.html b/third_party/WebKit/LayoutTests/css3/motion-path/path-will-change-establishes-stacking-context.html
new file mode 100644
index 0000000..1a4390d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/motion-path/path-will-change-establishes-stacking-context.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+
+* {
+  margin: 0;
+  padding: 0;
+}
+
+div {
+  width: 800px;
+  height: 300px;
+}
+
+span {
+  position: absolute;
+  width: 120px;
+  line-height: 120px;
+  text-align: center;
+  color: yellow;
+}
+
+#span1 {
+  z-index: 2;
+  left: 50px;
+  top: 50px;
+  background: red;
+}
+
+#span2 {
+  z-index: 1;
+  left: 100px;
+  top: 100px;
+  background: green;
+}
+
+#span3 {
+  left: 150px;
+  top: 150px;
+  background: blue;
+}
+
+#div1 {
+  will-change: offset-path;
+}
+
+</style>
+</head>
+<body>
+
+<div id="div1">
+  <span id="span1">First</span>
+</div>
+<div id="div2">
+  <span id="span2">Second</span>
+</div>
+<div id="div3">
+  <span id="span3">Third</span>
+</div>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/css3/motion-path/position-establishes-stacking-context-expected.html b/third_party/WebKit/LayoutTests/css3/motion-path/position-establishes-stacking-context-expected.html
new file mode 100644
index 0000000..fd53222b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/motion-path/position-establishes-stacking-context-expected.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+
+div {
+  width: 800px;
+  height: 300px;
+}
+
+span {
+  position: absolute;
+  width: 120px;
+  line-height: 120px;
+  text-align: center;
+  color: yellow;
+}
+
+#span1 {
+  z-index: 2;
+  left: 50px;
+  top: 50px;
+  background: red;
+}
+
+#span2 {
+  z-index: 1;
+  left: 100px;
+  top: 100px;
+  background: green;
+}
+
+#span3 {
+  left: 150px;
+  top: 150px;
+  background: blue;
+}
+
+#div1 {
+  transform: rotate(0deg);
+}
+
+</style>
+</head>
+<body>
+
+<div id="div1">
+  <span id="span1">First</span>
+</div>
+<div id="div2">
+  <span id="span2">Second</span>
+</div>
+<div id="div3">
+  <span id="span3">Third</span>
+</div>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/css3/motion-path/position-establishes-stacking-context.html b/third_party/WebKit/LayoutTests/css3/motion-path/position-establishes-stacking-context.html
new file mode 100644
index 0000000..8ab99437
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/motion-path/position-establishes-stacking-context.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+
+div {
+  width: 800px;
+  height: 300px;
+}
+
+span {
+  position: absolute;
+  width: 120px;
+  line-height: 120px;
+  text-align: center;
+  color: yellow;
+}
+
+#span1 {
+  z-index: 2;
+  left: 50px;
+  top: 50px;
+  background: red;
+}
+
+#span2 {
+  z-index: 1;
+  left: 100px;
+  top: 100px;
+  background: green;
+}
+
+#span3 {
+  left: 150px;
+  top: 150px;
+  background: blue;
+}
+
+#div1 {
+  offset-position: 400px 150px;
+}
+
+#div2 {
+  offset-position: auto;
+}
+
+</style>
+</head>
+<body>
+
+<div id="div1">
+  <span id="span1">First</span>
+</div>
+<div id="div2">
+  <span id="span2">Second</span>
+</div>
+<div id="div3">
+  <span id="span3">Third</span>
+</div>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/css3/motion-path/position-will-change-establishes-stacking-context-expected.html b/third_party/WebKit/LayoutTests/css3/motion-path/position-will-change-establishes-stacking-context-expected.html
new file mode 100644
index 0000000..b5909bf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/motion-path/position-will-change-establishes-stacking-context-expected.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+
+* {
+  margin: 0;
+  padding: 0;
+}
+
+div {
+  width: 800px;
+  height: 300px;
+}
+
+span {
+  position: absolute;
+  width: 120px;
+  line-height: 120px;
+  text-align: center;
+  color: yellow;
+}
+
+#span1 {
+  z-index: 2;
+  left: 50px;
+  top: 50px;
+  background: red;
+}
+
+#span2 {
+  z-index: 1;
+  left: 100px;
+  top: 100px;
+  background: green;
+}
+
+#span3 {
+  left: 150px;
+  top: 150px;
+  background: blue;
+}
+
+#div1 {
+  transform: rotate(0deg);
+}
+
+</style>
+</head>
+<body>
+
+<div id="div1">
+  <span id="span1">First</span>
+</div>
+<div id="div2">
+  <span id="span2">Second</span>
+</div>
+<div id="div3">
+  <span id="span3">Third</span>
+</div>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/css3/motion-path/position-will-change-establishes-stacking-context.html b/third_party/WebKit/LayoutTests/css3/motion-path/position-will-change-establishes-stacking-context.html
new file mode 100644
index 0000000..12df334a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/motion-path/position-will-change-establishes-stacking-context.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+
+* {
+  margin: 0;
+  padding: 0;
+}
+
+div {
+  width: 800px;
+  height: 300px;
+}
+
+span {
+  position: absolute;
+  width: 120px;
+  line-height: 120px;
+  text-align: center;
+  color: yellow;
+}
+
+#span1 {
+  z-index: 2;
+  left: 50px;
+  top: 50px;
+  background: red;
+}
+
+#span2 {
+  z-index: 1;
+  left: 100px;
+  top: 100px;
+  background: green;
+}
+
+#span3 {
+  left: 150px;
+  top: 150px;
+  background: blue;
+}
+
+#div1 {
+  will-change: offset-position;
+}
+
+</style>
+</head>
+<body>
+
+<div id="div1">
+  <span id="span1">First</span>
+</div>
+<div id="div2">
+  <span id="span2">Second</span>
+</div>
+<div id="div3">
+  <span id="span3">Third</span>
+</div>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/custom-properties/registered-properties-inheritance.html b/third_party/WebKit/LayoutTests/custom-properties/registered-properties-inheritance.html
new file mode 100644
index 0000000..29c0714
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/custom-properties/registered-properties-inheritance.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<style>
+#outer {
+    --inherited-length-1: 10px;
+    --inherited-length-2: var(--non-inherited-length-1);
+    --inherited-length-3: 30px;
+    --non-inherited-length-1: 22px;
+    --non-inherited-length-3: calc(var(--non-inherited-length-2) * 10);
+}
+
+#inner {
+    --inherited-length-3: 15px;
+    --non-inherited-length-1: 40px;
+    --non-inherited-length-2: 90px;
+}
+</style>
+<div id=outer><div id=inner></div></div>
+<script>
+CSS.registerProperty({name: '--inherited-length-1', syntax: '<length>', initialValue: '1px', inherits: true});
+CSS.registerProperty({name: '--inherited-length-2', syntax: '<length>', initialValue: '2px', inherits: true});
+CSS.registerProperty({name: '--inherited-length-3', syntax: '<length>', initialValue: '3px', inherits: true});
+CSS.registerProperty({name: '--non-inherited-length-1', syntax: '<length>', initialValue: '4px'});
+CSS.registerProperty({name: '--non-inherited-length-2', syntax: '<length>', initialValue: '5px'});
+CSS.registerProperty({name: '--non-inherited-length-3', syntax: '<length>', initialValue: '6px'});
+
+test(function() {
+    outerComputedStyle = getComputedStyle(outer);
+    assert_equals(outerComputedStyle.getPropertyValue('--inherited-length-1'), '10px');
+    assert_equals(outerComputedStyle.getPropertyValue('--inherited-length-2'), '22px');
+    assert_equals(outerComputedStyle.getPropertyValue('--inherited-length-3'), '30px');
+    assert_equals(outerComputedStyle.getPropertyValue('--non-inherited-length-1'), '22px');
+    assert_equals(outerComputedStyle.getPropertyValue('--non-inherited-length-2'), '5px');
+    assert_equals(outerComputedStyle.getPropertyValue('--non-inherited-length-3'), '50px');
+
+    innerComputedStyle = getComputedStyle(inner);
+    assert_equals(innerComputedStyle.getPropertyValue('--inherited-length-1'), '10px');
+    assert_equals(innerComputedStyle.getPropertyValue('--inherited-length-2'), '22px');
+    assert_equals(innerComputedStyle.getPropertyValue('--inherited-length-3'), '15px');
+    assert_equals(innerComputedStyle.getPropertyValue('--non-inherited-length-1'), '40px');
+    assert_equals(innerComputedStyle.getPropertyValue('--non-inherited-length-2'), '90px');
+    assert_equals(innerComputedStyle.getPropertyValue('--non-inherited-length-3'), '6px');
+}, "Registered properties are correctly inherited (or not) depending on the inherits flag.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/editing/assert_selection.html b/third_party/WebKit/LayoutTests/editing/assert_selection.html
index 5a0796cd..60726aa 100644
--- a/third_party/WebKit/LayoutTests/editing/assert_selection.html
+++ b/third_party/WebKit/LayoutTests/editing/assert_selection.html
@@ -162,4 +162,22 @@
         '<div contenteditable>FOO|</div>',
         'set HTML fragment and text to clipboard and pasteAndMatchStyle');
 }, 'selection.setClipboardData');
+
+test(() => {
+    const sample1 = assert_selection('abc', '', 'abc',
+        {removeSampleIfSucceeded: false});
+    assert_equals(sample1.iframe_.parentNode, document.body,
+        'removeSampleIfSucceeded: false');
+
+    const sample2 = assert_selection('abc', '', 'abc',
+        {removeSampleIfSucceeded: true});
+    assert_equals(sample2.iframe_.parentNode, null,
+        'removeSampleIfSucceeded: true');
+
+    const sample3 = assert_selection('abc', '', 'abc');
+    assert_equals(sample3.iframe_.parentNode, null, 'with default options');
+
+    const sample4 = assert_selection('abc', '', 'abc', 'description');
+    assert_equals(sample4.iframe_.parentNode, null, 'with description');
+}, 'removeSampleIfSucceeded');
 </script>
diff --git a/third_party/WebKit/LayoutTests/editing/assert_selection.js b/third_party/WebKit/LayoutTests/editing/assert_selection.js
index 6597ccb..44ced1a 100644
--- a/third_party/WebKit/LayoutTests/editing/assert_selection.js
+++ b/third_party/WebKit/LayoutTests/editing/assert_selection.js
@@ -682,13 +682,22 @@
  * @param {string} inputText
  * @param {function(!Selection)|string}
  * @param {string} expectedText
- * @param {string=} opt_description
+ * @param {Object=} opt_options
+ * @return {!Sample}
  */
 function assertSelection(
-    inputText, tester, expectedText, opt_description = '') {
+    inputText, tester, expectedText, opt_options = {}) {
+  const kDescription = 'description';
+  const kRemoveSampleIfSucceeded = 'removeSampleIfSucceeded';
+  /** @type {!Object} */
+  const options = typeof(opt_options) === 'string'
+      ? {description: opt_options} : opt_options;
   /** @type {string} */
-  const description =
-      opt_description === '' ? assembleDescription() : opt_description;
+  const description = kDescription in options
+      ? options[kDescription] : assembleDescription();
+  /** @type {boolean} */
+  const removeSampleIfSucceeded = kRemoveSampleIfSucceeded in options
+      ? !!options[kRemoveSampleIfSucceeded] : true;
   checkExpectedText(expectedText);
   const sample = new Sample(inputText);
   if (typeof(tester) === 'function') {
@@ -704,8 +713,9 @@
   // We keep sample HTML when assertion is false for ease of debugging test
   // case.
   if (actualText === expectedText) {
-    sample.remove();
-    return;
+    if (removeSampleIfSucceeded)
+        sample.remove();
+    return sample;
   }
   throw new Error(`${description}\n` +
     `\t expected ${expectedText},\n` +
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/spellcheck-attribute-settings-default-expected.txt b/third_party/WebKit/LayoutTests/editing/spelling/spellcheck-attribute-settings-default-expected.txt
new file mode 100644
index 0000000..802dba7c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/editing/spelling/spellcheck-attribute-settings-default-expected.txt
@@ -0,0 +1,29 @@
+This tests that the spellcheck default value is as specified in internal blink settings. This allows embedders to specify spellchecking behavior when the spellcheck attribute is not explicitly set.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+id=test1_1 type=text spellcheck=true enabled_by_default=true
+PASS internals.hasSpellingMarker(document, 0, 2) became shouldBeMarked
+id=test1_2 type=text spellcheck=true enabled_by_default=true
+PASS internals.hasSpellingMarker(document, 0, 2) became shouldBeMarked
+id=test1_3 type=text spellcheck=false enabled_by_default=true
+PASS internals.hasSpellingMarker(document, 0, 2) became shouldBeMarked
+id=test1_4 type=text spellcheck=true enabled_by_default=true
+PASS internals.hasSpellingMarker(document, 0, 2) became shouldBeMarked
+id=test1_5 type=text spellcheck=true enabled_by_default=true
+PASS internals.hasSpellingMarker(document, 0, 2) became shouldBeMarked
+id=test1_1 type=text spellcheck=false enabled_by_default=false
+PASS internals.hasSpellingMarker(document, 0, 2) became shouldBeMarked
+id=test1_2 type=text spellcheck=true enabled_by_default=false
+PASS internals.hasSpellingMarker(document, 0, 2) became shouldBeMarked
+id=test1_3 type=text spellcheck=false enabled_by_default=false
+PASS internals.hasSpellingMarker(document, 0, 2) became shouldBeMarked
+id=test1_4 type=text spellcheck=false enabled_by_default=false
+PASS internals.hasSpellingMarker(document, 0, 2) became shouldBeMarked
+id=test1_5 type=text spellcheck=true enabled_by_default=false
+PASS internals.hasSpellingMarker(document, 0, 2) became shouldBeMarked
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/spellcheck-attribute-settings-default.html b/third_party/WebKit/LayoutTests/editing/spelling/spellcheck-attribute-settings-default.html
new file mode 100644
index 0000000..bdfc373
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/editing/spelling/spellcheck-attribute-settings-default.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Spellcheck Attribute Settings Default Test</title>
+<script src="../editing.js"></script>
+<script src="resources/util.js"></script>
+<script src="../../resources/js-test.js"></script>
+</head>
+<body>
+<div id="testRoot">
+<label>1.1.</label><input id="test1_1" type="text"></input><br/>
+<label>1.2.</label><input id="test1_2" type="text" spellcheck="true"></input><br/>
+<label>1.3.</label><input id="test1_3" type="text" spellcheck="false"></input><br/>
+<label>1.4.</label><input id="test1_4" type="text" spellcheck="InvalidValue"></input><br/>
+<label>1.5.</label><input id="test1_5" type="text" spellcheck></input><br/>
+</div>
+<script>
+description('This tests that the spellcheck default value is as specified in '
+    + 'internal blink settings. This allows embedders to specify spellchecking '
+    + 'behavior when the spellcheck attribute is not explicitly set.');
+
+jsTestIsAsync = true;
+if (window.testRunner)
+    testRunner.setMockSpellCheckerEnabled(true);
+
+// Type misspelling to all input elements.
+var inputs = document.getElementsByTagName('input');
+for (var i = 0; i < inputs.length; i++)
+    typeText(inputs[i], 'zz ');
+
+var shouldBeMarked;
+
+function testMarkerForMisspelledWord(id, isMisspelled, enabled_by_default) {
+    if (!window.internals)
+        return done();
+
+    internals.settings.setSpellCheckEnabledByDefault(enabled_by_default);
+
+    var inputElement = document.getElementById(id);
+    // Spelling markers for input will appear if it's focused.
+    inputElement.focus();
+
+    debug("id=" + id + " type=" + inputElement.type + " spellcheck=" + inputElement.spellcheck + " enabled_by_default=" + enabled_by_default);
+
+    shouldBeMarked = isMisspelled;
+    shouldBecomeEqual('internals.hasSpellingMarker(document, 0, 2)', 'shouldBeMarked', done);
+}
+
+var tests = [
+    // spellcheck enabled by default
+    function() { testMarkerForMisspelledWord('test1_1', true, true); },
+    function() { testMarkerForMisspelledWord('test1_2', true, true); },
+    function() { testMarkerForMisspelledWord('test1_3', false, true); },
+    function() { testMarkerForMisspelledWord('test1_4', true, true); },
+    function() { testMarkerForMisspelledWord('test1_5', true, true); },
+    // spellcheck disabled by default
+    function() { testMarkerForMisspelledWord('test1_1', false, false); },
+    function() { testMarkerForMisspelledWord('test1_2', true, false); },
+    function() { testMarkerForMisspelledWord('test1_3', false, false); },
+    function() { testMarkerForMisspelledWord('test1_4', false, false); },
+    function() { testMarkerForMisspelledWord('test1_5', false, false); },
+];
+
+function done()
+{
+    var next = tests.shift();
+    if (next)
+        return window.setTimeout(next, 0);
+
+    if (window.testRunner) {
+        // Cleaning up for expectation text if running on DRT.
+        document.getElementById("testRoot").style.display = "none";
+    }
+    finishJSTest();
+}
+done();
+
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-expected.png b/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-expected.png
index 0f97689..07d2d9b 100644
--- a/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-zoomed-expected.png b/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-zoomed-expected.png
index 1b692d4d..7c5b37c 100644
--- a/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-zoomed-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-zoomed-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/size/scaled-sprited-background-expected.png b/third_party/WebKit/LayoutTests/fast/backgrounds/size/scaled-sprited-background-expected.png
new file mode 100644
index 0000000..120f0429a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/size/scaled-sprited-background-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/size/scaled-sprited-background-expected.txt b/third_party/WebKit/LayoutTests/fast/backgrounds/size/scaled-sprited-background-expected.txt
new file mode 100644
index 0000000..42d7ff2c8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/size/scaled-sprited-background-expected.txt
@@ -0,0 +1,6 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x36
+  LayoutBlockFlow {HTML} at (0,0) size 800x36
+    LayoutBlockFlow {BODY} at (8,8) size 784x20
+      LayoutBlockFlow {DIV} at (0,0) size 108x20
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-image-side-reduction-expected.png b/third_party/WebKit/LayoutTests/fast/borders/border-image-side-reduction-expected.png
index 13249c7..529cc9ac 100644
--- a/third_party/WebKit/LayoutTests/fast/borders/border-image-side-reduction-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/borders/border-image-side-reduction-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-radius-different-width-001-double-expected.png b/third_party/WebKit/LayoutTests/fast/borders/border-radius-different-width-001-double-expected.png
index 103d4e3..eec840d3 100644
--- a/third_party/WebKit/LayoutTests/fast/borders/border-radius-different-width-001-double-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/borders/border-radius-different-width-001-double-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDotted04-expected.png b/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDotted04-expected.png
index 36476cb..d335492 100644
--- a/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDotted04-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDotted04-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/webkit-border-radius-expected.png b/third_party/WebKit/LayoutTests/fast/borders/webkit-border-radius-expected.png
index 2c885e6..05e118e 100644
--- a/third_party/WebKit/LayoutTests/fast/borders/webkit-border-radius-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/borders/webkit-border-radius-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/css/absolute-child-with-percent-height-inside-relative-parent-expected.png b/third_party/WebKit/LayoutTests/fast/css/absolute-child-with-percent-height-inside-relative-parent-expected.png
index 81d225c..6532482 100644
--- a/third_party/WebKit/LayoutTests/fast/css/absolute-child-with-percent-height-inside-relative-parent-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/css/absolute-child-with-percent-height-inside-relative-parent-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/dom/geometry-interfaces-dom-matrix-invert.html b/third_party/WebKit/LayoutTests/fast/dom/geometry-interfaces-dom-matrix-invert.html
index b4a8df5..cb0df9b 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/geometry-interfaces-dom-matrix-invert.html
+++ b/third_party/WebKit/LayoutTests/fast/dom/geometry-interfaces-dom-matrix-invert.html
@@ -3,32 +3,28 @@
 <script src="../../resources/testharnessreport.js"></script>
 <script src="./resources/geometry-interfaces-test-helpers.js"></script>
 <script>
-// TODO(hs1217.lee): create the DOMMatrix directly when the sequence constructor is supported.
-function initMatrix(values) {
-  return new DOMMatrixReadOnly(values);
-}
 
 test(function() {
-  var matrix2d = new DOMMatrix(initMatrix([1, 2, 3, 4, 5, 6]));
+  var matrix2d = new DOMMatrix([1, 2, 3, 4, 5, 6]);
   matrix2d.invertSelf();
   assert_2d_matrix_equals(matrix2d, [-2, 1, 1.5, -0.5, 1, -2]);
 }, "DOMMatrix invertSelf() - invertible - 2D matrix");
 
 test(function() {
-  var matrix2d = new DOMMatrix(initMatrix([1, 1, 1, 1, 1, 1]));
+  var matrix2d = new DOMMatrix([1, 1, 1, 1, 1, 1]);
   matrix2d.invertSelf();
   //when non invertible matrix execute invertSelf(), result matrix is not 2d.
   assert_3d_matrix_equals(matrix2d, [NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN]);
 }, "DOMMatrix invertSelf() - non-invertible - 2D matrix");
 
 test(function() {
-  var matrix3d = new DOMMatrix(initMatrix([10, 20, 30, 40, 40, 40, 30, 20, 10, 20, 40, 30, 20, 40, 50, 100]));
+  var matrix3d = new DOMMatrix([10, 20, 30, 40, 40, 40, 30, 20, 10, 20, 40, 30, 20, 40, 50, 100]);
   matrix3d.invertSelf();
   assert_3d_matrix_equals(matrix3d, [-1.6, 0.05, 0.6, 0.45, 2.05, -0.025, -0.8, -0.575, -0.4, 0, 0.2, 0.1, -0.3, 0, 0.1, 0.1]);
 }, "DOMMatrix invertSelf() - 3D matrix");
 
 test(function() {
-  var matrix3d = new DOMMatrix(initMatrix([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]));
+  var matrix3d = new DOMMatrix([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
   matrix3d.invertSelf();
   assert_3d_matrix_equals(matrix3d, [NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN]);
 }, "DOMMatrix invertSelf() - non-invertible - 3D matrix");
diff --git a/third_party/WebKit/LayoutTests/fast/dom/geometry-interfaces-dom-matrix-skew.html b/third_party/WebKit/LayoutTests/fast/dom/geometry-interfaces-dom-matrix-skew.html
index c96a8301..788d4258 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/geometry-interfaces-dom-matrix-skew.html
+++ b/third_party/WebKit/LayoutTests/fast/dom/geometry-interfaces-dom-matrix-skew.html
@@ -3,55 +3,51 @@
 <script src="../../resources/testharnessreport.js"></script>
 <script src="./resources/geometry-interfaces-test-helpers.js"></script>
 <script>
-// TODO(hs1217.lee): create the DOMMatrix directly when the sequence constructor is supported.
-function initMatrix(values) {
-  return new DOMMatrixReadOnly(values);
-}
 
 test(function() {
-  var matrix2d = new DOMMatrix(initMatrix([1, 2, 3, 3.1, 2, 1]));
+  var matrix2d = new DOMMatrix([1, 2, 3, 3.1, 2, 1]);
   matrix2d.skewXSelf();
   assert_2d_matrix_equals(matrix2d, [1, 2, 3, 3.1, 2, 1]);
 }, "DOMMatrix skewX() - 2D matrix");
 
 test(function() {
-  var matrix2d = new DOMMatrix(initMatrix([1, 2, 3, 3.1, 2, 1]));
+  var matrix2d = new DOMMatrix([1, 2, 3, 3.1, 2, 1]);
   matrix2d.skewXSelf(45);
   assert_2d_matrix_equals(matrix2d, [1, 2, 4, 5.1, 2, 1]);
 }, "DOMMatrix skewX(45) - 2D matrix");
 
 test(function() {
-  var matrix3d = new DOMMatrix(initMatrix([1, 2, 3, 4, 5, 6, 7, 8, 9, 10.1, 11, 12, 13, 14, 15, 16.6]));
+  var matrix3d = new DOMMatrix([1, 2, 3, 4, 5, 6, 7, 8, 9, 10.1, 11, 12, 13, 14, 15, 16.6]);
   matrix3d.skewXSelf();
   assert_3d_matrix_equals(matrix3d, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10.1, 11, 12, 13, 14, 15, 16.6]);
 }, "DOMMatrix skewX() - 3D matrix");
 
 test(function() {
-  var matrix3d = new DOMMatrix(initMatrix([1, 2, 3, 4, 5, 6, 7, 8, 9, 10.1, 11, 12, 13, 14, 15, 16.6]));
+  var matrix3d = new DOMMatrix([1, 2, 3, 4, 5, 6, 7, 8, 9, 10.1, 11, 12, 13, 14, 15, 16.6]);
   matrix3d.skewXSelf(45);
   assert_3d_matrix_equals(matrix3d, [1, 2, 3, 4, 6, 8, 10, 12, 9, 10.1, 11, 12, 13, 14, 15, 16.6]);
 }, "DOMMatrix skewX(45) - 3D matrix");
 
 test(function() {
-  var matrix2d = new DOMMatrix(initMatrix([1, 2, 3, 3.1, 2, 1]));
+  var matrix2d = new DOMMatrix([1, 2, 3, 3.1, 2, 1]);
   matrix2d.skewYSelf();
   assert_2d_matrix_equals(matrix2d, [1, 2, 3, 3.1, 2, 1]);
 }, "DOMMatrix skewY() - 2D matrix");
 
 test(function() {
-  var matrix2d = new DOMMatrix(initMatrix([2, 2, 2, 2, 2, 2]));
+  var matrix2d = new DOMMatrix([2, 2, 2, 2, 2, 2]);
   matrix2d.skewYSelf(45);
   assert_2d_matrix_equals(matrix2d, [4, 4, 2, 2, 2, 2]);
 }, "DOMMatrix skewY(45) - 2D matrix");
 
 test(function() {
-  var matrix3d = new DOMMatrix(initMatrix([1, 2, 3, 4, 5, 6, 7, 8, 9, 10.1, 11, 12, 13, 14, 15, 16.6]));
+  var matrix3d = new DOMMatrix([1, 2, 3, 4, 5, 6, 7, 8, 9, 10.1, 11, 12, 13, 14, 15, 16.6]);
   matrix3d.skewYSelf();
   assert_3d_matrix_equals(matrix3d, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10.1, 11, 12, 13, 14, 15, 16.6]);
 }, "DOMMatrix skewY() - 3D matrix");
 
 test(function() {
-  var matrix3d = new DOMMatrix(initMatrix([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]));
+  var matrix3d = new DOMMatrix([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
   matrix3d.skewYSelf(45);
   assert_3d_matrix_equals(matrix3d, [2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
 }, "DOMMatrix skewY(45) - 3D matrix");
diff --git a/third_party/WebKit/LayoutTests/fast/dom/geometry-interfaces-dom-matrix.html b/third_party/WebKit/LayoutTests/fast/dom/geometry-interfaces-dom-matrix.html
index f15bf58..3d230cb 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/geometry-interfaces-dom-matrix.html
+++ b/third_party/WebKit/LayoutTests/fast/dom/geometry-interfaces-dom-matrix.html
@@ -47,6 +47,16 @@
 }, "DOMMatrix fromFloat64Array - 3D matrix");
 
 test(() => {
+  var matrix = new DOMMatrix([1, 2, 3, 4, 5, 6]);
+  assert_2d_matrix_equals(matrix, [1, 2, 3, 4, 5, 6]);
+}, "DOMMatrix(numberSequence) constructor");
+
+test(() => {
+  var matrix = new DOMMatrix([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
+  assert_3d_matrix_equals(matrix, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
+}, "DOMMatrix(numberSequence) constructor");
+
+test(() => {
   var matrix = new DOMMatrix();
   matrix.a = 10;
   matrix.b = 20;
diff --git a/third_party/WebKit/LayoutTests/fast/forms/select/select-remove-option-single-expected.html b/third_party/WebKit/LayoutTests/fast/forms/select/select-remove-option-single-expected.html
new file mode 100644
index 0000000..ad280b0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/select/select-remove-option-single-expected.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<title>Test for HTMLSelectElement.remove() on an Options object</title>
+
+<style type="text/css">
+select {
+    min-width: 100px;
+} 
+</style>
+
+<select></select>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/select/select-remove-option-single.html b/third_party/WebKit/LayoutTests/fast/forms/select/select-remove-option-single.html
new file mode 100644
index 0000000..b07faaf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/select/select-remove-option-single.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<title>Test for HTMLSelectElement.remove() on an Options object</title>
+
+<style type="text/css">
+select {
+    min-width: 100px;
+}
+</style>
+
+<select>
+    <option selected>hello</option>
+</select>
+
+<script>
+window.addEventListener('load', function() {
+    document.querySelector('option').remove();
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/frames/sandboxed-iframe-navigation-parent-expected.txt b/third_party/WebKit/LayoutTests/fast/frames/sandboxed-iframe-navigation-parent-expected.txt
index 5b6e1b6..a79ddce 100644
--- a/third_party/WebKit/LayoutTests/fast/frames/sandboxed-iframe-navigation-parent-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/frames/sandboxed-iframe-navigation-parent-expected.txt
@@ -1,5 +1,6 @@
 CONSOLE ERROR: line 6: Unsafe JavaScript attempt to initiate navigation for frame with URL 'sandboxed-iframe-navigation-source.html'. The frame attempting navigation is sandboxed, and is therefore disallowed from navigating its ancestors.
 
+CONSOLE ERROR: line 6: Uncaught SecurityError: Failed to execute 'assign' on 'Location': The current window does not have permission to navigate the target frame to 'sandboxed-iframe-navigated.html'.
 This test verifies that a sandboxed IFrame cannot navigate an ancestor in the frame tree by assigning the location attribute.
 
 This is done by loading ten non-sandboxed IFrames, and a single sandboxed one. Expect ten frames to be navigated, but the sandboxed one to not be one of them.
diff --git a/third_party/WebKit/LayoutTests/fast/frames/sandboxed-iframe-navigation-top-denied-expected.txt b/third_party/WebKit/LayoutTests/fast/frames/sandboxed-iframe-navigation-top-denied-expected.txt
index 8813eb8..03950835 100644
--- a/third_party/WebKit/LayoutTests/fast/frames/sandboxed-iframe-navigation-top-denied-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/frames/sandboxed-iframe-navigation-top-denied-expected.txt
@@ -1,5 +1,6 @@
 CONSOLE ERROR: line 2: Unsafe JavaScript attempt to initiate navigation for frame with URL 'navigate-top-to-fail.html'. The frame attempting navigation of the top-level window is sandboxed, but the 'allow-top-navigation' flag is not set.
 
+CONSOLE ERROR: line 2: Uncaught SecurityError: Failed to set the 'location' property on 'Window': The current window does not have permission to navigate the target frame to 'fail-and-notify-done.html'.
 This test verifies that a sandboxed IFrame cannot navigate the top-level frame without allow-top-navigation. This test passes if the navigation does not occur.
 
 
diff --git a/third_party/WebKit/LayoutTests/fast/hidpi/image-srcset-density-and-width-descriptors-expected.txt b/third_party/WebKit/LayoutTests/fast/hidpi/image-srcset-density-and-width-descriptors-expected.txt
index 35c39d86..69dd52f 100644
--- a/third_party/WebKit/LayoutTests/fast/hidpi/image-srcset-density-and-width-descriptors-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/hidpi/image-srcset-density-and-width-descriptors-expected.txt
@@ -1,11 +1,11 @@
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'x' descriptors or a mix of 'x' and 'w'/'h' descriptors.
-CONSOLE ERROR: Dropped srcset candidate resources/green-400-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/green-400-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'x' descriptors or a mix of 'x' and 'w'/'h' descriptors.
-CONSOLE ERROR: Dropped srcset candidate resources/green-400-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/green-400-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'x' descriptors or a mix of 'x' and 'w'/'h' descriptors.
-CONSOLE ERROR: Dropped srcset candidate resources/green-400-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/green-400-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'x' descriptors or a mix of 'x' and 'w'/'h' descriptors.
-CONSOLE ERROR: Dropped srcset candidate resources/green-400-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/green-400-px-square.png"
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/fast/hidpi/image-srcset-ignore-double-descriptor-expected.txt b/third_party/WebKit/LayoutTests/fast/hidpi/image-srcset-ignore-double-descriptor-expected.txt
index b116aca..2098c459 100644
--- a/third_party/WebKit/LayoutTests/fast/hidpi/image-srcset-ignore-double-descriptor-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/hidpi/image-srcset-ignore-double-descriptor-expected.txt
@@ -1,11 +1,11 @@
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'x' descriptors or a mix of 'x' and 'w'/'h' descriptors.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'x' descriptors or a mix of 'x' and 'w'/'h' descriptors.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'x' descriptors or a mix of 'x' and 'w'/'h' descriptors.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'x' descriptors or a mix of 'x' and 'w'/'h' descriptors.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/fast/hidpi/image-srcset-invalid-descriptor-expected.txt b/third_party/WebKit/LayoutTests/fast/hidpi/image-srcset-invalid-descriptor-expected.txt
index b9ee6df..c8e944e 100644
--- a/third_party/WebKit/LayoutTests/fast/hidpi/image-srcset-invalid-descriptor-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/hidpi/image-srcset-invalid-descriptor-expected.txt
@@ -1,83 +1,83 @@
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has an unknown descriptor.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has an unknown descriptor.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has an unknown descriptor.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has an unknown descriptor.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'w' descriptors or a mix of 'x' and 'w' descriptors.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'w' descriptors or a mix of 'x' and 'w' descriptors.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'h' descriptors or a mix of 'x' and 'h' descriptors.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'h' descriptors or a mix of 'x' and 'h' descriptors.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'h' descriptors or a mix of 'x' and 'h' descriptors.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'h' descriptors or a mix of 'x' and 'h' descriptors.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'w' descriptors or a mix of 'x' and 'w' descriptors.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'w' descriptors or a mix of 'x' and 'w' descriptors.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since its 'w' descriptor is invalid.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since its 'w' descriptor is invalid.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since its 'h' descriptor is invalid.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since its 'h' descriptor is invalid.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since its 'x' descriptor is invalid.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since its 'x' descriptor is invalid.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has an 'h' descriptor and no 'w' descriptor.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has an 'h' descriptor and no 'w' descriptor.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has an unknown descriptor.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has an unknown descriptor.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has an unknown descriptor.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has an unknown descriptor.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'w' descriptors or a mix of 'x' and 'w' descriptors.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'w' descriptors or a mix of 'x' and 'w' descriptors.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'h' descriptors or a mix of 'x' and 'h' descriptors.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'h' descriptors or a mix of 'x' and 'h' descriptors.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'h' descriptors or a mix of 'x' and 'h' descriptors.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'h' descriptors or a mix of 'x' and 'h' descriptors.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'w' descriptors or a mix of 'x' and 'w' descriptors.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'w' descriptors or a mix of 'x' and 'w' descriptors.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since its 'w' descriptor is invalid.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since its 'w' descriptor is invalid.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since its 'h' descriptor is invalid.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since its 'h' descriptor is invalid.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since its 'x' descriptor is invalid.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since its 'x' descriptor is invalid.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has an 'h' descriptor and no 'w' descriptor.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has an 'h' descriptor and no 'w' descriptor.
-CONSOLE ERROR: Dropped srcset candidate resources/blue-100-px-square.png
+CONSOLE ERROR: Dropped srcset candidate "resources/blue-100-px-square.png"
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/fast/hidpi/image-srcset-invalid-inputs-except-one-expected.txt b/third_party/WebKit/LayoutTests/fast/hidpi/image-srcset-invalid-inputs-except-one-expected.txt
index e54c863c..563db1f 100644
--- a/third_party/WebKit/LayoutTests/fast/hidpi/image-srcset-invalid-inputs-except-one-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/hidpi/image-srcset-invalid-inputs-except-one-expected.txt
@@ -1,27 +1,27 @@
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'h' descriptors or a mix of 'x' and 'h' descriptors.
-CONSOLE ERROR: Dropped srcset candidate bar.jpg
+CONSOLE ERROR: Dropped srcset candidate "bar.jpg"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has an unknown descriptor.
-CONSOLE ERROR: Dropped srcset candidate foo.jpg
+CONSOLE ERROR: Dropped srcset candidate "foo.jpg"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since its 'x' descriptor is invalid.
-CONSOLE ERROR: Dropped srcset candidate bar.jpg
+CONSOLE ERROR: Dropped srcset candidate "bar.jpg"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'h' descriptors or a mix of 'x' and 'h' descriptors.
-CONSOLE ERROR: Dropped srcset candidate bar.jpg
+CONSOLE ERROR: Dropped srcset candidate "bar.jpg"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has an unknown descriptor.
-CONSOLE ERROR: Dropped srcset candidate foo.jpg
+CONSOLE ERROR: Dropped srcset candidate "foo.jpg"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since its 'x' descriptor is invalid.
-CONSOLE ERROR: Dropped srcset candidate bar.jpg
+CONSOLE ERROR: Dropped srcset candidate "bar.jpg"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'h' descriptors or a mix of 'x' and 'h' descriptors.
-CONSOLE ERROR: Dropped srcset candidate bar.jpg
+CONSOLE ERROR: Dropped srcset candidate "bar.jpg"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has an unknown descriptor.
-CONSOLE ERROR: Dropped srcset candidate foo.jpg
+CONSOLE ERROR: Dropped srcset candidate "foo.jpg"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since its 'x' descriptor is invalid.
-CONSOLE ERROR: Dropped srcset candidate bar.jpg
+CONSOLE ERROR: Dropped srcset candidate "bar.jpg"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'h' descriptors or a mix of 'x' and 'h' descriptors.
-CONSOLE ERROR: Dropped srcset candidate bar.jpg
+CONSOLE ERROR: Dropped srcset candidate "bar.jpg"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has an unknown descriptor.
-CONSOLE ERROR: Dropped srcset candidate foo.jpg
+CONSOLE ERROR: Dropped srcset candidate "foo.jpg"
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since its 'x' descriptor is invalid.
-CONSOLE ERROR: Dropped srcset candidate bar.jpg
+CONSOLE ERROR: Dropped srcset candidate "bar.jpg"
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/fast/images/color-profile-background-clip-text-expected.txt b/third_party/WebKit/LayoutTests/fast/images/color-profile-background-clip-text-expected.txt
index 10f9a06..481eb76 100644
--- a/third_party/WebKit/LayoutTests/fast/images/color-profile-background-clip-text-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/images/color-profile-background-clip-text-expected.txt
@@ -1,3 +1,3 @@
-▅▅▅▅
+ppp
 
-▅▅▅▅
+ppp
diff --git a/third_party/WebKit/LayoutTests/fast/images/color-profile-background-clip-text.html b/third_party/WebKit/LayoutTests/fast/images/color-profile-background-clip-text.html
index 4730124..b97cbffe 100644
--- a/third_party/WebKit/LayoutTests/fast/images/color-profile-background-clip-text.html
+++ b/third_party/WebKit/LayoutTests/fast/images/color-profile-background-clip-text.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <html>
+<script src="../../resources/ahem.js"></script>
 <script src="../../resources/run-after-layout-and-paint.js"></script>
 
 <style>
@@ -8,7 +9,7 @@
     background: url("resources/red-at-12-oclock-with-color-profile.jpg") -20px 100px;
     -webkit-background-clip: text;
 
-    font: 190px Ahem, sans-serif;
+    font: 220px Ahem, sans-serif;
     position: relative;
     top: -300px;
   }
@@ -20,7 +21,7 @@
 
 <!-- There should be no red on this page. -->
 <body style="overflow: hidden">
-  <p>&#9605;&#9605;&#9605;&#9605;</p><p>&#9605;&#9605;&#9605;&#9605;</p>
+  <p>ppp</p><p>ppp</p>
 </body>
 
 <script>
diff --git a/third_party/WebKit/LayoutTests/fast/images/exif-orientation-height-image-document-expected.png b/third_party/WebKit/LayoutTests/fast/images/exif-orientation-height-image-document-expected.png
index 3b94f24..1ce4eee 100644
--- a/third_party/WebKit/LayoutTests/fast/images/exif-orientation-height-image-document-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/images/exif-orientation-height-image-document-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/images/jpeg-yuv-progressive-image-expected.png b/third_party/WebKit/LayoutTests/fast/images/jpeg-yuv-progressive-image-expected.png
index 23438b0..fc85a45 100644
--- a/third_party/WebKit/LayoutTests/fast/images/jpeg-yuv-progressive-image-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/images/jpeg-yuv-progressive-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/images/rgb-png-with-cmyk-color-profile-expected.png b/third_party/WebKit/LayoutTests/fast/images/rgb-png-with-cmyk-color-profile-expected.png
index cf8f1246..a827e73 100644
--- a/third_party/WebKit/LayoutTests/fast/images/rgb-png-with-cmyk-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/images/rgb-png-with-cmyk-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/images/ycbcr-with-cmyk-color-profile-expected.png b/third_party/WebKit/LayoutTests/fast/images/ycbcr-with-cmyk-color-profile-expected.png
index 49ed6f80..b526c01 100644
--- a/third_party/WebKit/LayoutTests/fast/images/ycbcr-with-cmyk-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/images/ycbcr-with-cmyk-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/mediastream/argument-types-expected.txt b/third_party/WebKit/LayoutTests/fast/mediastream/argument-types-expected.txt
index 4b4b470..afd6e1b 100644
--- a/third_party/WebKit/LayoutTests/fast/mediastream/argument-types-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/mediastream/argument-types-expected.txt
@@ -9,15 +9,15 @@
 PASS navigator.webkitGetUserMedia({video: true}, emptyFunction, emptyFunction) did not throw exception.
 PASS navigator.webkitGetUserMedia({audio: true}, emptyFunction, emptyFunction) did not throw exception.
 PASS navigator.webkitGetUserMedia({audio: true, video: true}, emptyFunction, emptyFunction) did not throw exception.
-PASS navigator.webkitGetUserMedia(-Infinity, emptyFunction, emptyFunction) threw exception TypeError: Failed to execute 'webkitGetUserMedia' on 'Navigator': parameter 1 ('options') is not an object..
-PASS navigator.webkitGetUserMedia(42, emptyFunction, emptyFunction) threw exception TypeError: Failed to execute 'webkitGetUserMedia' on 'Navigator': parameter 1 ('options') is not an object..
-PASS navigator.webkitGetUserMedia(Infinity, emptyFunction, emptyFunction) threw exception TypeError: Failed to execute 'webkitGetUserMedia' on 'Navigator': parameter 1 ('options') is not an object..
-PASS navigator.webkitGetUserMedia(emptyFunction, emptyFunction, emptyFunction) threw exception SyntaxError: Failed to execute 'webkitGetUserMedia' on 'Navigator': At least one of audio and video must be requested.
-PASS navigator.webkitGetUserMedia(null, emptyFunction, emptyFunction) threw exception SyntaxError: Failed to execute 'webkitGetUserMedia' on 'Navigator': At least one of audio and video must be requested.
-PASS navigator.webkitGetUserMedia(true, emptyFunction, emptyFunction) threw exception TypeError: Failed to execute 'webkitGetUserMedia' on 'Navigator': parameter 1 ('options') is not an object..
-PASS navigator.webkitGetUserMedia(undefined, emptyFunction, emptyFunction) threw exception SyntaxError: Failed to execute 'webkitGetUserMedia' on 'Navigator': At least one of audio and video must be requested.
-PASS navigator.webkitGetUserMedia({ }, emptyFunction, emptyFunction) threw exception SyntaxError: Failed to execute 'webkitGetUserMedia' on 'Navigator': At least one of audio and video must be requested.
-PASS navigator.webkitGetUserMedia({foo: true }, emptyFunction, emptyFunction) threw exception SyntaxError: Failed to execute 'webkitGetUserMedia' on 'Navigator': At least one of audio and video must be requested.
+PASS navigator.webkitGetUserMedia(-Infinity, emptyFunction, emptyFunction) threw exception TypeError: Failed to execute 'webkitGetUserMedia' on 'Navigator': parameter 1 ('constraints') is not an object..
+PASS navigator.webkitGetUserMedia(42, emptyFunction, emptyFunction) threw exception TypeError: Failed to execute 'webkitGetUserMedia' on 'Navigator': parameter 1 ('constraints') is not an object..
+PASS navigator.webkitGetUserMedia(Infinity, emptyFunction, emptyFunction) threw exception TypeError: Failed to execute 'webkitGetUserMedia' on 'Navigator': parameter 1 ('constraints') is not an object..
+PASS navigator.webkitGetUserMedia(emptyFunction, emptyFunction, emptyFunction) threw exception TypeError: Failed to execute 'webkitGetUserMedia' on 'Navigator': At least one of audio and video must be requested.
+PASS navigator.webkitGetUserMedia(null, emptyFunction, emptyFunction) threw exception TypeError: Failed to execute 'webkitGetUserMedia' on 'Navigator': At least one of audio and video must be requested.
+PASS navigator.webkitGetUserMedia(true, emptyFunction, emptyFunction) threw exception TypeError: Failed to execute 'webkitGetUserMedia' on 'Navigator': parameter 1 ('constraints') is not an object..
+PASS navigator.webkitGetUserMedia(undefined, emptyFunction, emptyFunction) threw exception TypeError: Failed to execute 'webkitGetUserMedia' on 'Navigator': At least one of audio and video must be requested.
+PASS navigator.webkitGetUserMedia({ }, emptyFunction, emptyFunction) threw exception TypeError: Failed to execute 'webkitGetUserMedia' on 'Navigator': At least one of audio and video must be requested.
+PASS navigator.webkitGetUserMedia({foo: true }, emptyFunction, emptyFunction) threw exception TypeError: Failed to execute 'webkitGetUserMedia' on 'Navigator': At least one of audio and video must be requested.
 PASS navigator.webkitGetUserMedia({audio:true, video:true}, emptyFunction, undefined) threw exception TypeError: Failed to execute 'webkitGetUserMedia' on 'Navigator': The callback provided as parameter 3 is not a function..
 PASS navigator.webkitGetUserMedia({video: true}, "foobar", emptyFunction) threw exception TypeError: Failed to execute 'webkitGetUserMedia' on 'Navigator': The callback provided as parameter 2 is not a function..
 PASS navigator.webkitGetUserMedia({video: true}, -Infinity, emptyFunction) threw exception TypeError: Failed to execute 'webkitGetUserMedia' on 'Navigator': The callback provided as parameter 2 is not a function..
diff --git a/third_party/WebKit/LayoutTests/fast/mediastream/getusermedia-constraints.html b/third_party/WebKit/LayoutTests/fast/mediastream/getusermedia-constraints.html
index 0f5fb696..19b0048 100644
--- a/third_party/WebKit/LayoutTests/fast/mediastream/getusermedia-constraints.html
+++ b/third_party/WebKit/LayoutTests/fast/mediastream/getusermedia-constraints.html
@@ -16,7 +16,7 @@
         assert_unreached('getUserMedia should have failed');
       })
     .catch(function(e) {
-        assert_equals(e.name, 'SyntaxError');
+        assert_equals(e.name, 'TypeError');
       });
 }, 'getUserMedia() without any media types should fail');
 
diff --git a/third_party/WebKit/LayoutTests/fast/mediastream/getusermedia-expected.txt b/third_party/WebKit/LayoutTests/fast/mediastream/getusermedia-expected.txt
index cb553b4..1b7cf73 100644
--- a/third_party/WebKit/LayoutTests/fast/mediastream/getusermedia-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/mediastream/getusermedia-expected.txt
@@ -6,9 +6,9 @@
 
 PASS window.internals.isUseCounted(document, GetUserMediaPrefixed) is false
 PASS window.internals.isUseCounted(document, GetUserMediaLegacy) is false
-PASS navigator.webkitGetUserMedia({audio:false, video:false}, error, error); threw exception SyntaxError: Failed to execute 'webkitGetUserMedia' on 'Navigator': At least one of audio and video must be requested.
+PASS navigator.webkitGetUserMedia({audio:false, video:false}, error, error); threw exception TypeError: Failed to execute 'webkitGetUserMedia' on 'Navigator': At least one of audio and video must be requested.
 PASS navigator.webkitGetUserMedia({audio:true}, gotStreamNoMore, error); did not throw exception.
-PASS navigator.getUserMedia({audio:false, video:false}, error, error); threw exception SyntaxError: Failed to execute 'getUserMedia' on 'Navigator': At least one of audio and video must be requested.
+PASS navigator.getUserMedia({audio:false, video:false}, error, error); threw exception TypeError: Failed to execute 'getUserMedia' on 'Navigator': At least one of audio and video must be requested.
 PASS navigator.getUserMedia({audio:true}, gotStream1, error); did not throw exception.
 PASS window.internals.isUseCounted(document, GetUserMediaPrefixed) is true
 PASS window.internals.isUseCounted(document, GetUserMediaLegacy) is true
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/client-rects-crossing-boundaries-nested.html b/third_party/WebKit/LayoutTests/fast/multicol/client-rects-crossing-boundaries-nested.html
new file mode 100644
index 0000000..8539956
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/multicol/client-rects-crossing-boundaries-nested.html
@@ -0,0 +1,103 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<style>body { margin:0; }</style>
+<div style="columns:4; column-gap:10px; column-fill:auto; width:430px; height:100px; background:yellow;"> <!-- column width is 100px -->
+    <div style="height:80px;"></div>
+    <div id="middleMulticol" style="columns:2; column-gap:10px; background:lime;"> <!-- column width is 45px -->
+        <div style="height:80px;"></div>
+        <div id="innerMulticol" style="columns:2; column-gap:5px; background:cyan;"> <!-- column width is 20px -->
+            <div id="innerChild" style="height:500px; background:olive;"></div>
+        </div>
+        <div id="middleChild" style="height:200px; background:salmon;"></div>
+    </div>
+</div>
+<script>
+    test(function() {
+        var rects = document.getElementById("middleMulticol").getClientRects();
+        assert_equals(rects.length, 4);
+        assert_equals(rects[0].left, 0);
+        assert_equals(rects[0].top, 80);
+        assert_equals(rects[0].right, 100);
+        assert_equals(rects[0].bottom, 100);
+        assert_equals(rects[1].left, 110);
+        assert_equals(rects[1].top, 0);
+        assert_equals(rects[1].right, 210);
+        assert_equals(rects[1].bottom, 100);
+        assert_equals(rects[2].left, 220);
+        assert_equals(rects[2].top, 0);
+        assert_equals(rects[2].right, 320);
+        assert_equals(rects[2].bottom, 100);
+        assert_equals(rects[3].left, 330);
+        assert_equals(rects[3].top, 0);
+        assert_equals(rects[3].right, 430);
+        assert_equals(rects[3].bottom, 45);
+    }, "#middleMulticol");
+
+    test(function() {
+        var rects = document.getElementById("innerMulticol").getClientRects();
+        assert_equals(rects.length, 3);
+        assert_equals(rects[0].left, 110);
+        assert_equals(rects[0].top, 40);
+        assert_equals(rects[0].right, 155);
+        assert_equals(rects[0].bottom, 100);
+        assert_equals(rects[1].left, 165);
+        assert_equals(rects[1].top, 0);
+        assert_equals(rects[1].right, 210);
+        assert_equals(rects[1].bottom, 100);
+        assert_equals(rects[2].left, 220);
+        assert_equals(rects[2].top, 0);
+        assert_equals(rects[2].right, 265);
+        assert_equals(rects[2].bottom, 90);
+    }, "#innerMulticol");
+
+    test(function() {
+        var rects = document.getElementById("innerChild").getClientRects();
+        assert_equals(rects.length, 6);
+        assert_equals(rects[0].left, 110);
+        assert_equals(rects[0].top, 40);
+        assert_equals(rects[0].right, 130);
+        assert_equals(rects[0].bottom, 100);
+        assert_equals(rects[1].left, 135);
+        assert_equals(rects[1].top, 40);
+        assert_equals(rects[1].right, 155);
+        assert_equals(rects[1].bottom, 100);
+        assert_equals(rects[2].left, 165);
+        assert_equals(rects[2].top, 0);
+        assert_equals(rects[2].right, 185);
+        assert_equals(rects[2].bottom, 100);
+        assert_equals(rects[3].left, 190);
+        assert_equals(rects[3].top, 0);
+        assert_equals(rects[3].right, 210);
+        assert_equals(rects[3].bottom, 100);
+        assert_equals(rects[4].left, 220);
+        assert_equals(rects[4].top, 0);
+        assert_equals(rects[4].right, 240);
+        assert_equals(rects[4].bottom, 90);
+        assert_equals(rects[5].left, 245);
+        assert_equals(rects[5].top, 0);
+        assert_equals(rects[5].right, 265);
+        assert_equals(rects[5].bottom, 90);
+    }, "#innerChild");
+
+    test(function() {
+        var rects = document.getElementById("middleChild").getClientRects();
+        assert_equals(rects.length, 4);
+        assert_equals(rects[0].left, 220);
+        assert_equals(rects[0].top, 90);
+        assert_equals(rects[0].right, 265);
+        assert_equals(rects[0].bottom, 100);
+        assert_equals(rects[1].left, 275);
+        assert_equals(rects[1].top, 0);
+        assert_equals(rects[1].right, 320);
+        assert_equals(rects[1].bottom, 100);
+        assert_equals(rects[2].left, 330);
+        assert_equals(rects[2].top, 0);
+        assert_equals(rects[2].right, 375);
+        assert_equals(rects[2].bottom, 45);
+        assert_equals(rects[3].left, 385);
+        assert_equals(rects[3].top, 0);
+        assert_equals(rects[3].right, 430);
+        assert_equals(rects[3].bottom, 45);
+    }, "#middleChild");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/client-rects-crossing-boundaries.html b/third_party/WebKit/LayoutTests/fast/multicol/client-rects-crossing-boundaries.html
new file mode 100644
index 0000000..f8c3037
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/multicol/client-rects-crossing-boundaries.html
@@ -0,0 +1,87 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<style>body { margin:0; }</style>
+<div style="columns:4; column-gap:10px; column-fill:auto; width:430px; height:100px;">
+    <div id="outer" style="margin-top:10px; height:450px;">
+        <div style="height:10px;"></div>
+        <div id="first" style="height:100px;"></div>
+        <div id="rightFloat" style="float:right; width:50px; height:90px;"></div>
+        <div id="tableCell" style="display:table-cell; width:20px; height:180px;"></div>
+        <div id="fullSingleColumn" style="height:100px;"></div>
+    </div>
+</div>
+<script>
+    test(function() {
+        var rects = document.getElementById("outer").getClientRects();
+        assert_equals(rects.length, 5);
+        assert_equals(rects[0].left, 0);
+        assert_equals(rects[0].top, 10);
+        assert_equals(rects[0].right, 100);
+        assert_equals(rects[0].bottom, 100);
+        assert_equals(rects[1].left, 110);
+        assert_equals(rects[1].top, 0);
+        assert_equals(rects[1].right, 210);
+        assert_equals(rects[1].bottom, 100);
+        assert_equals(rects[2].left, 220);
+        assert_equals(rects[2].top, 0);
+        assert_equals(rects[2].right, 320);
+        assert_equals(rects[2].bottom, 100);
+        assert_equals(rects[3].left, 330);
+        assert_equals(rects[3].top, 0);
+        assert_equals(rects[3].right, 430);
+        assert_equals(rects[3].bottom, 100);
+        assert_equals(rects[4].left, 440);
+        assert_equals(rects[4].top, 0);
+        assert_equals(rects[4].right, 540);
+        assert_equals(rects[4].bottom, 60);
+    }, "#outer");
+
+    test(function() {
+        var rects = document.getElementById("first").getClientRects();
+        assert_equals(rects.length, 2);
+        assert_equals(rects[0].left, 0);
+        assert_equals(rects[0].top, 20);
+        assert_equals(rects[0].right, 100);
+        assert_equals(rects[0].bottom, 100);
+        assert_equals(rects[1].left, 110);
+        assert_equals(rects[1].top, 0);
+        assert_equals(rects[1].right, 210);
+        assert_equals(rects[1].bottom, 20);
+    }, "#first");
+
+    test(function() {
+        var rects = document.getElementById("rightFloat").getClientRects();
+        assert_equals(rects.length, 2);
+        assert_equals(rects[0].left, 160);
+        assert_equals(rects[0].top, 20);
+        assert_equals(rects[0].right, 210);
+        assert_equals(rects[0].bottom, 100);
+        assert_equals(rects[1].left, 270);
+        assert_equals(rects[1].top, 0);
+        assert_equals(rects[1].right, 320);
+        assert_equals(rects[1].bottom, 10);
+    }, "#rightFloat");
+
+    test(function() {
+        var rects = document.getElementById("tableCell").getClientRects();
+        assert_equals(rects.length, 2);
+        assert_equals(rects[0].left, 110);
+        assert_equals(rects[0].top, 20);
+        assert_equals(rects[0].right, 130);
+        assert_equals(rects[0].bottom, 100);
+        assert_equals(rects[1].left, 220);
+        assert_equals(rects[1].top, 0);
+        assert_equals(rects[1].right, 240);
+        assert_equals(rects[1].bottom, 100);
+    }, "#tableCell");
+
+    test(function() {
+        var rects = document.getElementById("fullSingleColumn").getClientRects();
+        assert_equals(rects.length, 1);
+        assert_equals(rects[0].left, 330);
+        assert_equals(rects[0].top, 0);
+        assert_equals(rects[0].right, 430);
+        assert_equals(rects[0].bottom, 100);
+    }, "#fullSingleColumn");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/client-rects-empty-element-boundary.html b/third_party/WebKit/LayoutTests/fast/multicol/client-rects-empty-element-boundary.html
new file mode 100644
index 0000000..3ff4973
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/multicol/client-rects-empty-element-boundary.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<style>body { margin:0; }</style>
+<div style="columns:4; column-gap:10px; column-fill:auto; width:430px; height:100px;">
+    <div style="height:100px;"></div>
+    <div id="empty" style="position:relative;"></div>
+    <div style="height:100px;"></div>
+</div>
+<script>
+    test(function() {
+        var rects = document.getElementById("empty").getClientRects();
+        assert_equals(rects.length, 1);
+        assert_equals(rects[0].left, 110);
+        assert_equals(rects[0].top, 0);
+        assert_equals(rects[0].right, 210);
+        assert_equals(rects[0].bottom, 0);
+    }, "Zero-height element at column boundary");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/client-rects-expected.html b/third_party/WebKit/LayoutTests/fast/multicol/client-rects-expected.html
index 3aae3b9..06e4243 100644
--- a/third_party/WebKit/LayoutTests/fast/multicol/client-rects-expected.html
+++ b/third_party/WebKit/LayoutTests/fast/multicol/client-rects-expected.html
@@ -30,22 +30,6 @@
         border: solid dodgerblue;
         box-sizing: border-box;
     }
-
-    .special > .left > span {
-        margin-top: 40px;
-        height: 10px;
-        border: none;
-    }
-    .special > .right span:first-child {
-        border-bottom: none;
-        height: 10px;
-        margin-top: -10px;
-        background-color: white;
-    }
-    .special > .right span:last-child {
-        border-top: none;
-        height: 15px;
-    }
 </style>
 <p>
     The blue borders should coincide with light blue squares, like this:
@@ -77,10 +61,7 @@
 <div class="columns">
     <div class="column right"><span></span></div>
 </div>
-<p>
-    Except here, where the blue border should be around the bigger slice of the blue square, on the right.
-</p>
-<div class="columns special">
-    <div class="column left"><span></span></div>
-    <div class="column right"><span></span><span></span></div>
-</div>
\ No newline at end of file
+<div class="columns">
+    <div class="column left"><br><span></span></div>
+    <div class="column right"><span></span></div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/client-rects-rtl-expected.html b/third_party/WebKit/LayoutTests/fast/multicol/client-rects-rtl-expected.html
index 8bfce09b..ece0071 100644
--- a/third_party/WebKit/LayoutTests/fast/multicol/client-rects-rtl-expected.html
+++ b/third_party/WebKit/LayoutTests/fast/multicol/client-rects-rtl-expected.html
@@ -30,22 +30,6 @@
         border: solid dodgerblue;
         box-sizing: border-box;
     }
-
-    .special > .first > span {
-        margin-top: 40px;
-        height: 10px;
-        border: none;
-    }
-    .special > .second span:first-child {
-        border-bottom: none;
-        height: 10px;
-        margin-top: -10px;
-        background-color: white;
-    }
-    .special > .second span:last-child {
-        border-top: none;
-        height: 15px;
-    }
 </style>
 <p>
     The blue borders should coincide with light blue squares, like this:
@@ -77,10 +61,7 @@
 <div class="columns">
     <div class="column second"><span></span></div>
 </div>
-<p>
-    Except here, where the blue border should be around the bigger slice of the blue square, on the left.
-</p>
-<div class="columns special">
-    <div class="column first"><span></span></div>
-    <div class="column second"><span></span><span></span></div>
+<div class="columns">
+    <div class="column first"><br><span></span></div>
+    <div class="column second"><span></span></div>
 </div>
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/client-rects-rtl.html b/third_party/WebKit/LayoutTests/fast/multicol/client-rects-rtl.html
index b6fa6d83..f2ccdac 100644
--- a/third_party/WebKit/LayoutTests/fast/multicol/client-rects-rtl.html
+++ b/third_party/WebKit/LayoutTests/fast/multicol/client-rects-rtl.html
@@ -71,12 +71,8 @@
     <br><div><br><img id="t6" style="width: 25px; height: 25px; background-color: lightblue;"></div>
 </div>
 
-<p>
-    Except here, where the blue border should be around the bigger slice of the blue square, on the left.
-</p>
-
 <div class="columns">
-    <div id="t7" style=" margin-top: 40px; width: 25px; height: 25px; background-color: lightblue;"></div>
+    <div id="t7" style=" margin-top: 25px; width: 25px; height: 50px; background-color: lightblue;"></div>
 </div>
 
 <script>
@@ -119,7 +115,8 @@
 
     var block = document.getElementById("t4");
     range.selectNode(block);
-    placeMarkersForRange(range, 1);
+    // Skip the rectangles for the two fragments established by the DIV.
+    placeMarkersForRange(range, 2);
 
     var slider = document.getElementById("t5");
     range.selectNode(slider);
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/client-rects.html b/third_party/WebKit/LayoutTests/fast/multicol/client-rects.html
index 156b3cb5..e0fad1d8 100644
--- a/third_party/WebKit/LayoutTests/fast/multicol/client-rects.html
+++ b/third_party/WebKit/LayoutTests/fast/multicol/client-rects.html
@@ -71,12 +71,8 @@
     <br><div><br><img id="t6" style="width: 25px; height: 25px; background-color: lightblue;"></div>
 </div>
 
-<p>
-    Except here, where the blue border should be around the bigger slice of the blue square, on the right.
-</p>
-
 <div class="columns">
-    <div id="t7" style=" margin-top: 40px; width: 25px; height: 25px; background-color: lightblue;"></div>
+    <div id="t7" style=" margin-top: 25px; width: 25px; height: 50px; background-color: lightblue;"></div>
 </div>
 
 <script>
@@ -119,7 +115,8 @@
 
     var block = document.getElementById("t4");
     range.selectNode(block);
-    placeMarkersForRange(range, 1);
+    // Skip the rectangles for the two fragments established by the DIV.
+    placeMarkersForRange(range, 2);
 
     var slider = document.getElementById("t5");
     range.selectNode(slider);
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/vertical-lr/client-rects-crossing-boundaries-nested.html b/third_party/WebKit/LayoutTests/fast/multicol/vertical-lr/client-rects-crossing-boundaries-nested.html
new file mode 100644
index 0000000..89c2bef
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/multicol/vertical-lr/client-rects-crossing-boundaries-nested.html
@@ -0,0 +1,103 @@
+<!DOCTYPE html>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<style>body { margin:0; }</style>
+<div style="writing-mode:vertical-lr; columns:4; column-gap:10px; column-fill:auto; height:430px; width:100px; background:yellow;"> <!-- column width is 100px -->
+    <div style="width:80px;"></div>
+    <div id="middleMulticol" style="columns:2; column-gap:10px; background:lime;"> <!-- column width is 45px -->
+        <div style="width:80px;"></div>
+        <div id="innerMulticol" style="columns:2; column-gap:5px; background:cyan;"> <!-- column width is 20px -->
+            <div id="innerChild" style="width:500px; background:olive;"></div>
+        </div>
+        <div id="middleChild" style="width:200px; background:salmon;"></div>
+    </div>
+</div>
+<script>
+    test(function() {
+        var rects = document.getElementById("middleMulticol").getClientRects();
+        assert_equals(rects.length, 4);
+        assert_equals(rects[0].top, 0);
+        assert_equals(rects[0].left, 80);
+        assert_equals(rects[0].bottom, 100);
+        assert_equals(rects[0].right, 100);
+        assert_equals(rects[1].top, 110);
+        assert_equals(rects[1].left, 0);
+        assert_equals(rects[1].bottom, 210);
+        assert_equals(rects[1].right, 100);
+        assert_equals(rects[2].top, 220);
+        assert_equals(rects[2].left, 0);
+        assert_equals(rects[2].bottom, 320);
+        assert_equals(rects[2].right, 100);
+        assert_equals(rects[3].top, 330);
+        assert_equals(rects[3].left, 0);
+        assert_equals(rects[3].bottom, 430);
+        assert_equals(rects[3].right, 45);
+    }, "#middleMulticol");
+
+    test(function() {
+        var rects = document.getElementById("innerMulticol").getClientRects();
+        assert_equals(rects.length, 3);
+        assert_equals(rects[0].top, 110);
+        assert_equals(rects[0].left, 40);
+        assert_equals(rects[0].bottom, 155);
+        assert_equals(rects[0].right, 100);
+        assert_equals(rects[1].top, 165);
+        assert_equals(rects[1].left, 0);
+        assert_equals(rects[1].bottom, 210);
+        assert_equals(rects[1].right, 100);
+        assert_equals(rects[2].top, 220);
+        assert_equals(rects[2].left, 0);
+        assert_equals(rects[2].bottom, 265);
+        assert_equals(rects[2].right, 90);
+    }, "#innerMulticol");
+
+    test(function() {
+        var rects = document.getElementById("innerChild").getClientRects();
+        assert_equals(rects.length, 6);
+        assert_equals(rects[0].top, 110);
+        assert_equals(rects[0].left, 40);
+        assert_equals(rects[0].bottom, 130);
+        assert_equals(rects[0].right, 100);
+        assert_equals(rects[1].top, 135);
+        assert_equals(rects[1].left, 40);
+        assert_equals(rects[1].bottom, 155);
+        assert_equals(rects[1].right, 100);
+        assert_equals(rects[2].top, 165);
+        assert_equals(rects[2].left, 0);
+        assert_equals(rects[2].bottom, 185);
+        assert_equals(rects[2].right, 100);
+        assert_equals(rects[3].top, 190);
+        assert_equals(rects[3].left, 0);
+        assert_equals(rects[3].bottom, 210);
+        assert_equals(rects[3].right, 100);
+        assert_equals(rects[4].top, 220);
+        assert_equals(rects[4].left, 0);
+        assert_equals(rects[4].bottom, 240);
+        assert_equals(rects[4].right, 90);
+        assert_equals(rects[5].top, 245);
+        assert_equals(rects[5].left, 0);
+        assert_equals(rects[5].bottom, 265);
+        assert_equals(rects[5].right, 90);
+    }, "#innerChild");
+
+    test(function() {
+        var rects = document.getElementById("middleChild").getClientRects();
+        assert_equals(rects.length, 4);
+        assert_equals(rects[0].top, 220);
+        assert_equals(rects[0].left, 90);
+        assert_equals(rects[0].bottom, 265);
+        assert_equals(rects[0].right, 100);
+        assert_equals(rects[1].top, 275);
+        assert_equals(rects[1].left, 0);
+        assert_equals(rects[1].bottom, 320);
+        assert_equals(rects[1].right, 100);
+        assert_equals(rects[2].top, 330);
+        assert_equals(rects[2].left, 0);
+        assert_equals(rects[2].bottom, 375);
+        assert_equals(rects[2].right, 45);
+        assert_equals(rects[3].top, 385);
+        assert_equals(rects[3].left, 0);
+        assert_equals(rects[3].bottom, 430);
+        assert_equals(rects[3].right, 45);
+    }, "#middleChild");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/vertical-rl/client-rects-crossing-boundaries-nested.html b/third_party/WebKit/LayoutTests/fast/multicol/vertical-rl/client-rects-crossing-boundaries-nested.html
new file mode 100644
index 0000000..c7fed1d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/multicol/vertical-rl/client-rects-crossing-boundaries-nested.html
@@ -0,0 +1,103 @@
+<!DOCTYPE html>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<style>body { margin:0; }</style>
+<div style="writing-mode:vertical-rl; columns:4; column-gap:10px; column-fill:auto; height:430px; width:100px; background:yellow;"> <!-- column width is 100px -->
+    <div style="width:80px;"></div>
+    <div id="middleMulticol" style="columns:2; column-gap:10px; background:lime;"> <!-- column width is 45px -->
+        <div style="width:80px;"></div>
+        <div id="innerMulticol" style="columns:2; column-gap:5px; background:cyan;"> <!-- column width is 20px -->
+            <div id="innerChild" style="width:500px; background:olive;"></div>
+        </div>
+        <div id="middleChild" style="width:200px; background:salmon;"></div>
+    </div>
+</div>
+<script>
+    test(function() {
+        var rects = document.getElementById("middleMulticol").getClientRects();
+        assert_equals(rects.length, 4);
+        assert_equals(rects[0].top, 0);
+        assert_equals(rects[0].left, 0);
+        assert_equals(rects[0].bottom, 100);
+        assert_equals(rects[0].right, 20);
+        assert_equals(rects[1].top, 110);
+        assert_equals(rects[1].left, 0);
+        assert_equals(rects[1].bottom, 210);
+        assert_equals(rects[1].right, 100);
+        assert_equals(rects[2].top, 220);
+        assert_equals(rects[2].left, 0);
+        assert_equals(rects[2].bottom, 320);
+        assert_equals(rects[2].right, 100);
+        assert_equals(rects[3].top, 330);
+        assert_equals(rects[3].left, 55);
+        assert_equals(rects[3].bottom, 430);
+        assert_equals(rects[3].right, 100);
+    }, "#middleMulticol");
+
+    test(function() {
+        var rects = document.getElementById("innerMulticol").getClientRects();
+        assert_equals(rects.length, 3);
+        assert_equals(rects[0].top, 110);
+        assert_equals(rects[0].left, 0);
+        assert_equals(rects[0].bottom, 155);
+        assert_equals(rects[0].right, 60);
+        assert_equals(rects[1].top, 165);
+        assert_equals(rects[1].left, 0);
+        assert_equals(rects[1].bottom, 210);
+        assert_equals(rects[1].right, 100);
+        assert_equals(rects[2].top, 220);
+        assert_equals(rects[2].left, 10);
+        assert_equals(rects[2].bottom, 265);
+        assert_equals(rects[2].right, 100);
+    }, "#innerMulticol");
+
+    test(function() {
+        var rects = document.getElementById("innerChild").getClientRects();
+        assert_equals(rects.length, 6);
+        assert_equals(rects[0].top, 110);
+        assert_equals(rects[0].left, 0);
+        assert_equals(rects[0].bottom, 130);
+        assert_equals(rects[0].right, 60);
+        assert_equals(rects[1].top, 135);
+        assert_equals(rects[1].left, 0);
+        assert_equals(rects[1].bottom, 155);
+        assert_equals(rects[1].right, 60);
+        assert_equals(rects[2].top, 165);
+        assert_equals(rects[2].left, 0);
+        assert_equals(rects[2].bottom, 185);
+        assert_equals(rects[2].right, 100);
+        assert_equals(rects[3].top, 190);
+        assert_equals(rects[3].left, 0);
+        assert_equals(rects[3].bottom, 210);
+        assert_equals(rects[3].right, 100);
+        assert_equals(rects[4].top, 220);
+        assert_equals(rects[4].left, 10);
+        assert_equals(rects[4].bottom, 240);
+        assert_equals(rects[4].right, 100);
+        assert_equals(rects[5].top, 245);
+        assert_equals(rects[5].left, 10);
+        assert_equals(rects[5].bottom, 265);
+        assert_equals(rects[5].right, 100);
+    }, "#innerChild");
+
+    test(function() {
+        var rects = document.getElementById("middleChild").getClientRects();
+        assert_equals(rects.length, 4);
+        assert_equals(rects[0].top, 220);
+        assert_equals(rects[0].left, 0);
+        assert_equals(rects[0].bottom, 265);
+        assert_equals(rects[0].right, 10);
+        assert_equals(rects[1].top, 275);
+        assert_equals(rects[1].left, 0);
+        assert_equals(rects[1].bottom, 320);
+        assert_equals(rects[1].right, 100);
+        assert_equals(rects[2].top, 330);
+        assert_equals(rects[2].left, 55);
+        assert_equals(rects[2].bottom, 375);
+        assert_equals(rects[2].right, 100);
+        assert_equals(rects[3].top, 385);
+        assert_equals(rects[3].left, 55);
+        assert_equals(rects[3].bottom, 430);
+        assert_equals(rects[3].right, 100);
+    }, "#middleChild");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/text/breaking-context-inline-crash.html b/third_party/WebKit/LayoutTests/fast/text/breaking-context-inline-crash.html
new file mode 100644
index 0000000..d3b96f8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/text/breaking-context-inline-crash.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<head>
+<script src="../../resources/ahem.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+window.onload = function() {
+    done();
+};
+</script>
+<style>
+div {
+    width: 135px;
+    font-family: Ahem;
+    font-size: 18px;
+    word-wrap: break-word;
+    word-break: break-all;
+    outline: solid 1px red;
+}
+</style>
+</head>
+<body>
+<div>abcdef <span>V<span>.net</div>
+Test passes if it does not CRASH in debug build.
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/compiler-script-mapping.html b/third_party/WebKit/LayoutTests/http/tests/inspector/compiler-script-mapping.html
index 528c6af..d9cbfb5 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/compiler-script-mapping.html
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/compiler-script-mapping.html
@@ -52,15 +52,13 @@
     function uiSourceCodeAdded(event)
     {
         var uiSourceCode = event.data;
-        var networkURL = InspectorTest.testNetworkMapping.networkURL(uiSourceCode);
-        InspectorTest.addResult("UISourceCodeAdded: [" + uiSourceCode.project().type() + "] " + networkURL);
+        InspectorTest.addResult("UISourceCodeAdded: [" + uiSourceCode.project().type() + "] " + uiSourceCode.url());
     }
 
     function uiSourceCodeRemoved(event)
     {
         var uiSourceCode = event.data;
-        var networkURL = InspectorTest.testNetworkMapping.networkURL(uiSourceCode);
-        InspectorTest.addResult("UISourceCodeRemoved: [" + uiSourceCode.project().type() + "] " + networkURL);
+        InspectorTest.addResult("UISourceCodeRemoved: [" + uiSourceCode.project().type() + "] " + uiSourceCode.url());
     }
 
     InspectorTest.runTestSuite([
@@ -254,21 +252,11 @@
 
             function firstUISourceCodeAdded(uiSourceCode)
             {
-                var networkURL = InspectorTest.testNetworkMapping.networkURL(uiSourceCode);
-                if (!networkURL) {
-                    InspectorTest.waitForWorkspaceUISourceCodeAddedEvent(firstUISourceCodeAdded);
-                    return;
-                }
                 InspectorTest.waitForWorkspaceUISourceCodeAddedEvent(secondUISourceCodeAdded);
             }
 
             function secondUISourceCodeAdded(uiSourceCode)
             {
-                var networkURL = InspectorTest.testNetworkMapping.networkURL(uiSourceCode);
-                if (!networkURL) {
-                    InspectorTest.waitForWorkspaceUISourceCodeAddedEvent(secondUISourceCodeAdded);
-                    return;
-                }
                 afterScriptAdded();
             }
 
@@ -330,12 +318,7 @@
 
             function firstUISourceCodeAdded(uiSourceCode)
             {
-                InspectorTest.waitForWorkspaceUISourceCodeAddedEvent(secondUISourceCodeAdded);
-            }
-
-            function secondUISourceCodeAdded(uiSourceCode)
-            {
-                afterScriptAdded();
+                InspectorTest.waitForWorkspaceUISourceCodeAddedEvent(afterScriptAdded);
             }
 
             function afterScriptAdded(uiSourceCode)
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/elements/styles/update-locations-on-filesystem-scss-load.html b/third_party/WebKit/LayoutTests/http/tests/inspector/elements/styles/update-locations-on-filesystem-scss-load.html
index 95c82d2..d654b4fa 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/elements/styles/update-locations-on-filesystem-scss-load.html
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/elements/styles/update-locations-on-filesystem-scss-load.html
@@ -54,8 +54,7 @@
             InspectorTest.addResult("Null uiLocation");
             return;
         }
-        var networkURL = WebInspector.networkMapping.networkURL(uiLocation.uiSourceCode);
-        InspectorTest.addResult(networkURL + ":" + uiLocation.lineNumber + ":" + uiLocation.columnNumber);
+        InspectorTest.addResult(uiLocation.uiSourceCode.url() + ":" + uiLocation.lineNumber + ":" + uiLocation.columnNumber);
     }
 };
 </script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js
index 58e5dba..b35419ad 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js
@@ -360,7 +360,17 @@
 
     function dumpNavigatorTreeElement(prefix, treeElement)
     {
-        InspectorTest.addResult(prefix + treeElement.title);
+        var titleText;
+        if (treeElement.title instanceof Element)
+            titleText = treeElement.title.firstChild.textContent + " [mapped]";
+        else
+            titleText = treeElement.title;
+        if (treeElement._nodeType === WebInspector.NavigatorView.Types.FileSystem || treeElement._nodeType === WebInspector.NavigatorView.Types.FileSystemFolder) {
+            var hasMappedFiles = treeElement.listItemElement.classList.contains("has-mapped-files");
+            if (!hasMappedFiles)
+                titleText += " [dimmed]";
+        }
+        InspectorTest.addResult(prefix + titleText);
         treeElement.expand();
         var children = treeElement.children();
         for (var i = 0; i < children.length; ++i)
@@ -938,6 +948,17 @@
     return target && !target.hasBrowserCapability() && !target.hasJSCapability() && target.hasNetworkCapability() && target.hasWorkerCapability();
 }
 
+InspectorTest.describeTargetType = function(target)
+{
+    if (InspectorTest.isDedicatedWorker(target))
+        return "worker";
+    if (InspectorTest.isServiceWorker(target))
+        return "service-worker";
+    if (!target.parentTarget())
+        return "page";
+    return "frame";
+}
+
     };  // initialize_InspectorTest
 
 var initializeCallId = 0;
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/persistence/persistence-navigator-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/persistence/persistence-navigator-expected.txt
index 78efa01..b453f8cd 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/persistence/persistence-navigator-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/persistence/persistence-navigator-expected.txt
@@ -16,8 +16,8 @@
       inspector-test.js
       isolated-filesystem-test.js
       workspace-test.js
-www
-  inspector/persistence/resources
+www [dimmed]
+  inspector/persistence/resources [dimmed]
     foo.js
 
 Running: addFileMapping
@@ -25,6 +25,8 @@
   127.0.0.1:8000
     inspector
       persistence
+        resources
+          foo.js [mapped]
         persistence-navigator.html
         persistence-test.js
       debugger-test.js
@@ -33,7 +35,7 @@
       workspace-test.js
 www
   inspector/persistence/resources
-    foo.js
+    foo.js [mapped]
 
 Running: removeFileMapping
 top
@@ -48,7 +50,7 @@
       inspector-test.js
       isolated-filesystem-test.js
       workspace-test.js
-www
-  inspector/persistence/resources
+www [dimmed]
+  inspector/persistence/resources [dimmed]
     foo.js
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/search/sources-search-scope-many-projects-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/search/sources-search-scope-many-projects-expected.txt
index 8076d42..b4a14dc 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/search/sources-search-scope-many-projects-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/search/sources-search-scope-many-projects-expected.txt
@@ -30,9 +30,9 @@
   search match #5: lineNumber = 11, lineContent = '    // SEARCHTestUniqueString();'
 
 Running: testDirtyFiles
-Search result #1: uiSourceCode.url = http://localhost/search.js
+Search result #1: uiSourceCode.url = file:///var/www/search.js
   search match #1: lineNumber = 0, lineContent = 'FOO searchTestUniqueString BAR'
-Search result #2: uiSourceCode.url = file:///var/www/search.js
+Search result #2: uiSourceCode.url = http://localhost/search.js
   search match #1: lineNumber = 0, lineContent = 'FOO searchTestUniqueString BAR'
 Search result #3: uiSourceCode.url = http://localhost/search.html
   search match #1: lineNumber = 4, lineContent = '<script>window.eval("function searchTestUniqueString() {}");</script>'
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-worker-agents-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-worker-agents-expected.txt
index fd456a2..eb80c90 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-worker-agents-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-worker-agents-expected.txt
@@ -2,9 +2,9 @@
 
 Debugger-related command should be issued: {
     "id": "<id>",
-    "method": "ServiceWorker.sendMessage",
+    "method": "Target.sendMessageToTarget",
     "params": {
-        "workerId": "<id>",
+        "targetId": "<id>",
         "message": {
             "id": "<id>",
             "method": "Worker.sendMessageToWorker",
@@ -22,9 +22,9 @@
 Resuming targets.
 Debugger-related command should be issued: {
     "id": "<id>",
-    "method": "ServiceWorker.sendMessage",
+    "method": "Target.sendMessageToTarget",
     "params": {
-        "workerId": "<id>",
+        "targetId": "<id>",
         "message": {
             "id": "<id>",
             "method": "Worker.sendMessageToWorker",
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-worker-agents.html b/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-worker-agents.html
index a039ae1..67c67d1 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-worker-agents.html
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-worker-agents.html
@@ -11,7 +11,7 @@
 
     InspectorTest.addSniffer(WebInspector.MainConnection.prototype, "sendMessage", function(message) {
         var messageString = JSON.stringify(message);
-        if (!messageString.includes("ServiceWorker.sendMessage"))
+        if (!messageString.includes("Target.sendMessageToTarget"))
             return;
         if (messageString.includes("DOM."))
             InspectorTest.addResult("DOM-related command should NOT be issued: " + messageString);
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-worker-manager-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-worker-manager-expected.txt
index 77790a8..552d1b95d 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-worker-manager-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-worker-manager-expected.txt
@@ -1,8 +1,8 @@
 Tests the way service worker manager manages targets.
 
-Target added: Main type: 1
-Target added: service-worker-empty.js type: 4
-Target added: service-worker-empty.js type: 2
-Target removed: service-worker-empty.js type: 2
-Target removed: service-worker-empty.js type: 4
+Target added: Main; type: page
+Target added: service-worker-empty.js; type: service-worker
+Target added: service-worker-empty.js; type: worker
+Target removed: service-worker-empty.js; type: worker
+Target removed: service-worker-empty.js; type: service-worker
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-worker-manager.html b/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-worker-manager.html
index 906a638..079e1b98 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-worker-manager.html
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-worker-manager.html
@@ -13,21 +13,24 @@
     WebInspector.targetManager.observeTargets({
         targetAdded: function(target)
         {
-            InspectorTest.addResult("Target added: " + target.name() + " type: " + target._type);
-            if (target.isDedicatedWorker()) {
+            InspectorTest.addResult("Target added: " + target.name() + "; type: " + InspectorTest.describeTargetType(target));
+            if (InspectorTest.isDedicatedWorker(target)) {
                 var serviceWorkerManager = WebInspector.targetManager.mainTarget().serviceWorkerManager;
                 // Allow agents to do rountrips.
                 InspectorTest.deprecatedRunAfterPendingDispatches(function() {
-                    for (var worker of serviceWorkerManager.workers())
-                        worker.stop();
+                    for (var registration of serviceWorkerManager.registrations().valuesArray()) {
+                        for (var version of registration.versions.valuesArray()) {
+                            serviceWorkerManager.stopWorker(version.id);
+                        }
+                    }
                 });
             }
         },
 
         targetRemoved: function(target)
         {
-            InspectorTest.addResult("Target removed: " + target.name() + " type: " + target._type);
-            if (target.isServiceWorker())
+            InspectorTest.addResult("Target removed: " + target.name() + "; type: " + InspectorTest.describeTargetType(target));
+            if (InspectorTest.isServiceWorker(target))
                 setTimeout(InspectorTest.completeTest);
         }
     });
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-workers-redundant-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-workers-redundant-expected.txt
index c13f9964..ea8fe199 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-workers-redundant-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-workers-redundant-expected.txt
@@ -2,75 +2,72 @@
 
 The first ServiceWorker is activated.
 ==== ServiceWorkersView ====
-127.0.0.1/inspector/service-workers/resources/service-worker-redundant-scope/
-State
-activated
-Worker
-running
-inspect
-Script URL
-/inspector/service-workers/resources/changing-worker.php
-Updated
-RESPONSE-TIME
-Last-Modified
-LAST-MODIFIED
-Recent messages
-RESPONSE-TIME
-
+http://127.0.0.1:8000/inspector/service-workers/resources/service-worker-redundant-scope/
+Update
+Push
+Sync
+Unregister
+Source
+Status
+#N installing
+12/31/1969, 4:00:00 PM
+Clients
+Errors
+0
+details
+clear
 ============================
 The second Serviceworker is installed.
 ==== ServiceWorkersView ====
-127.0.0.1/inspector/service-workers/resources/service-worker-redundant-scope/
-State
-activated
-Worker
-running
-inspect
-Script URL
-/inspector/service-workers/resources/changing-worker.php
-Updated
-RESPONSE-TIME
-Last-Modified
-LAST-MODIFIED
-Recent messages
-RESPONSE-TIME
-Controlled clients
-CLIENT
+http://127.0.0.1:8000/inspector/service-workers/resources/service-worker-redundant-scope/
+Update
+Push
+Sync
+Unregister
+Source
+changing-worker.php
+Received
+Status
+#N activated and is running
+stop
+#N installing
+12/31/1969, 4:00:00 PM
+Clients
+http://127.0.0.1:8000/inspector/service-workers/service-workers-redundant.html
+focus
+Errors
+0
+details
+clear
 ============================
 The first ServiceWorker worker became redundant and stopped.
 ==== ServiceWorkersView ====
-127.0.0.1/inspector/service-workers/resources/service-worker-redundant-scope/
-State
-activated
-Worker
-running
-inspect
-Script URL
-/inspector/service-workers/resources/changing-worker.php
-Updated
-RESPONSE-TIME
-Last-Modified
-LAST-MODIFIED
-Recent messages
-RESPONSE-TIME
-
+http://127.0.0.1:8000/inspector/service-workers/resources/service-worker-redundant-scope/
+Update
+Push
+Sync
+Unregister
+Source
+changing-worker.php
+Received
+Status
+#N activated and is running
+stop
+Clients
+Errors
+0
+details
+clear
 ============================
 DevTools frontend is reopened.
 ==== ServiceWorkersView ====
-127.0.0.1/inspector/service-workers/resources/service-worker-redundant-scope/
-State
-activated
-Worker
-running
-inspect
-Script URL
-/inspector/service-workers/resources/changing-worker.php
-Updated
-RESPONSE-TIME
-Last-Modified
-LAST-MODIFIED
-Recent messages
-RESPONSE-TIME
-
+Update
+Push
+Sync
+Unregister
+Source
+Status
+Clients
+Errors
 ============================
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-workers-redundant.html b/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-workers-redundant.html
index 30e4029a..6acddb6 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-workers-redundant.html
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-workers-redundant.html
@@ -40,13 +40,17 @@
                         ++step;
                         firstVersionId = version.id;
                         InspectorTest.addResult("The first ServiceWorker is activated.");
-                        InspectorTest.addResults(InspectorTest.dumpServiceWorkersView([scope]));
+                        InspectorTest.addResult("==== ServiceWorkersView ====");
+                        InspectorTest.addResult(InspectorTest.dumpServiceWorkersView([scope]));
+                        InspectorTest.addResult("============================");
                         InspectorTest.evaluateInPage("loadIframe(\"" + scope + "\");");
                     } else if (step == 1 && version.isRunning() && version.isInstalled()) {
                         ++step;
                         secondVersionId = version.id;
                         InspectorTest.addResult("The second Serviceworker is installed.");
-                        InspectorTest.addResults(InspectorTest.dumpServiceWorkersView([scope]));
+                        InspectorTest.addResult("==== ServiceWorkersView ====");
+                        InspectorTest.addResult(InspectorTest.dumpServiceWorkersView([scope]));
+                        InspectorTest.addResult("============================");
                         InspectorTest.evaluateInPage("unloadIframe();");
                     }
                 }
@@ -57,7 +61,9 @@
                 if ((!firstVersion || (firstVersion.isStopped() && firstVersion.isRedundant())) && secondVersion.isActivated() && secondVersion.isRunning()) {
                     ++step;
                     InspectorTest.addResult("The first ServiceWorker worker became redundant and stopped.");
-                    InspectorTest.addResults(InspectorTest.dumpServiceWorkersView([scope]));
+                    InspectorTest.addResult("==== ServiceWorkersView ====");
+                    InspectorTest.addResult(InspectorTest.dumpServiceWorkersView([scope]));
+                    InspectorTest.addResult("============================");
                     InspectorTest.flushResults();
                     InspectorTest.evaluateInPage("reopenFrontend()");
                 }
@@ -67,7 +73,9 @@
         } else {
             InspectorTest.addResult("DevTools frontend is reopened.");
             WebInspector.panels.resources.serviceWorkersTreeElement.select();
-            InspectorTest.addResults(InspectorTest.dumpServiceWorkersView([scope]));
+            InspectorTest.addResult("==== ServiceWorkersView ====");
+            InspectorTest.addResult(InspectorTest.dumpServiceWorkersView([scope]));
+            InspectorTest.addResult("============================");
             InspectorTest.deleteServiceWorkerRegistration(scope);
             InspectorTest.completeTest();
         }});
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/stylesheet-source-mapping.html b/third_party/WebKit/LayoutTests/http/tests/inspector/stylesheet-source-mapping.html
index 384fc0f..900197eb 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/stylesheet-source-mapping.html
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/stylesheet-source-mapping.html
@@ -25,10 +25,9 @@
     {
         var header = cssModel.styleSheetHeaderForId(styleSheetId);
         var uiLocation = InspectorTest.testCSSWorkspaceBinding.rawLocationToUILocation(new WebInspector.CSSLocation(header, 2, 3));
-        var networkURL = InspectorTest.testNetworkMapping.networkURL(uiLocation.uiSourceCode);
-        if (networkURL.indexOf(".scss") === -1)
+        if (uiLocation.uiSourceCode.url().indexOf(".scss") === -1)
             return;
-        finalMappedLocation = networkURL + ":" + uiLocation.lineNumber + ":" + uiLocation.columnNumber;
+        finalMappedLocation = uiLocation.uiSourceCode.url() + ":" + uiLocation.lineNumber + ":" + uiLocation.columnNumber;
         join();
     }
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/workspace-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/workspace-test.js
index ebb6b9e9..072b838 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/workspace-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/workspace-test.js
@@ -12,7 +12,7 @@
     InspectorTest.testWorkspace = new WebInspector.Workspace();
     InspectorTest.testFileSystemWorkspaceBinding = new WebInspector.FileSystemWorkspaceBinding(WebInspector.isolatedFileSystemManager, InspectorTest.testWorkspace);
     InspectorTest.testNetworkMapping = new WebInspector.NetworkMapping(InspectorTest.testTargetManager, InspectorTest.testWorkspace, InspectorTest.testFileSystemWorkspaceBinding, WebInspector.fileSystemMapping);
-    InspectorTest.testNetworkProjectManager = new WebInspector.NetworkProjectManager(InspectorTest.testTargetManager, InspectorTest.testWorkspace, InspectorTest.testNetworkMapping);
+    InspectorTest.testNetworkProjectManager = new WebInspector.NetworkProjectManager(InspectorTest.testTargetManager, InspectorTest.testWorkspace);
     InspectorTest.testDebuggerWorkspaceBinding = new WebInspector.DebuggerWorkspaceBinding(InspectorTest.testTargetManager, InspectorTest.testWorkspace, InspectorTest.testNetworkMapping);
     InspectorTest.testCSSWorkspaceBinding = new WebInspector.CSSWorkspaceBinding(InspectorTest.testTargetManager, InspectorTest.testWorkspace, InspectorTest.testNetworkMapping);
 
@@ -132,9 +132,6 @@
 InspectorTest._defaultWorkspaceEventHandler = function(event)
 {
     var uiSourceCode = event.data;
-    var networkURL = WebInspector.networkMapping.networkURL(uiSourceCode);
-    if (uiSourceCode.project().type() === WebInspector.projectTypes.Debugger && !networkURL)
-        return;
     if (uiSourceCode.project().type() === WebInspector.projectTypes.Service)
         return;
     InspectorTest.addResult(`Workspace event: ${event.type.toString()}: ${uiSourceCode.url()}.`);
diff --git a/third_party/WebKit/LayoutTests/http/tests/notifications/resources/serviceworker-notification-event.js b/third_party/WebKit/LayoutTests/http/tests/notifications/resources/serviceworker-notification-event.js
index 1610e9ab..7ed607e 100644
--- a/third_party/WebKit/LayoutTests/http/tests/notifications/resources/serviceworker-notification-event.js
+++ b/third_party/WebKit/LayoutTests/http/tests/notifications/resources/serviceworker-notification-event.js
@@ -10,33 +10,41 @@
 
 // Test body for the serviceworker-notification-event.html layout test.
 function runTest(notification) {
-    assert_true('NotificationEvent' in self);
+    const result = {
+      success: true,
+      message: null
+    }
+    try {
+      assert_true('NotificationEvent' in self);
 
-    assert_throws(null, () => new NotificationEvent('NotificationEvent'));
-    assert_throws(null, () => new NotificationEvent('NotificationEvent', {}));
-    assert_throws(null, () => new NotificationEvent('NotificationEvent', { notification: null }));
+      assert_throws(null, () => new NotificationEvent('NotificationEvent'));
+      assert_throws(null, () => new NotificationEvent('NotificationEvent', {}));
+      assert_throws(null, () => new NotificationEvent('NotificationEvent', { notification: null }));
 
-    const event = new NotificationEvent('NotificationEvent', { notification });
+      const event = new NotificationEvent('NotificationEvent', { notification });
 
-    assert_equals(event.type, 'NotificationEvent');
-    assert_idl_attribute(event, 'notification');
-    assert_idl_attribute(event, 'action');
-    assert_equals(event.cancelable, false);
-    assert_equals(event.bubbles, false);
-    assert_equals(event.notification, notification);
-    assert_equals(event.action, '');
-    assert_inherits(event, 'waitUntil');
+      assert_equals(event.type, 'NotificationEvent');
+      assert_idl_attribute(event, 'notification');
+      assert_idl_attribute(event, 'action');
+      assert_equals(event.cancelable, false);
+      assert_equals(event.bubbles, false);
+      assert_equals(event.notification, notification);
+      assert_equals(event.action, '');
+      assert_inherits(event, 'waitUntil');
 
-    const customEvent = new NotificationEvent('NotificationEvent', {
-                            notification: notification,
-                            bubbles: true,
-                            cancelable: true });
+      const customEvent = new NotificationEvent('NotificationEvent', {
+                              notification: notification,
+                              bubbles: true,
+                              cancelable: true });
 
-    assert_equals(customEvent.type, 'NotificationEvent');
-    assert_equals(customEvent.cancelable, true);
-    assert_equals(customEvent.bubbles, true);
-    assert_equals(customEvent.notification, notification);
-
+      assert_equals(customEvent.type, 'NotificationEvent');
+      assert_equals(customEvent.cancelable, true);
+      assert_equals(customEvent.bubbles, true);
+      assert_equals(customEvent.notification, notification);
+    } catch (e) {
+      result.success = false;
+      result.message = e.message + '\n' + e.stack;
+    }
     // Signal to the document that the test has finished running.
-    messagePort.postMessage(true /* success */);
+    messagePort.postMessage(result);
 }
diff --git a/third_party/WebKit/LayoutTests/http/tests/notifications/serviceworker-notification-event.html b/third_party/WebKit/LayoutTests/http/tests/notifications/serviceworker-notification-event.html
index 8c35b82..1889a40 100644
--- a/third_party/WebKit/LayoutTests/http/tests/notifications/serviceworker-notification-event.html
+++ b/third_party/WebKit/LayoutTests/http/tests/notifications/serviceworker-notification-event.html
@@ -36,13 +36,15 @@
               testRunner.simulateWebNotificationClick(scope, -1 /* action_index */);
 
               workerInfo.port.addEventListener('message', function(event) {
-                  if (typeof event.data != 'boolean') {
-                      assert_unreached('Received an invalid message from the Service Worker.');
-                      return;
+                  if (typeof event.data != 'object' || typeof event.data.success != 'boolean') {
+                    assert_unreached('Received an invalid message from the Service Worker.');
+                    return;
                   }
 
                   // (3) Verify that the tests were successful in the Service Worker.
-                  assert_true(event.data);
+                  assert_true(event.data.success,
+                      'Expected tests to pass, but assertion failed:' + '\n' +
+                      event.data.message + '\n');
 
                   test.done();
               });
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/sandbox-iframe-blocks-top-navigation-to-javascript.html b/third_party/WebKit/LayoutTests/http/tests/security/sandbox-iframe-blocks-top-navigation-to-javascript.html
new file mode 100644
index 0000000..7b534f5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/sandbox-iframe-blocks-top-navigation-to-javascript.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+    async_test(t => {
+        var i = document.createElement('iframe');
+        i.sandbox = "allow-scripts allow-same-origin allow-modals";
+        i.srcdoc = "<script>" +
+                   "  window.onerror = (m,f,l,c,e) => { top.postMessage(e.name, '*'); }" +
+                   "</scr" + "ipt>" +
+                   "<a href='javascript:top.location=\"/security/frameNavigation/resources/fail.html\";'>click</a>";
+
+        window.onmessage = t.step_func_done(e => {
+            assert_equals(e.data, "SecurityError", "The 'javascript:' navigation threw.");
+            assert_equals(i.contentDocument.body.innerText, "click", "The page contents did not change.");
+        });
+
+        var clicked = false;
+        i.onload = t.step_func(e => {
+            i.contentDocument.querySelector('a').click();
+            clicked = true;
+        });
+
+        document.body.appendChild(i);
+    }, "Sandboxed frames should throw when navigating the top-level window.");
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/sandbox-iframe-blocks-top-navigation.html b/third_party/WebKit/LayoutTests/http/tests/security/sandbox-iframe-blocks-top-navigation.html
new file mode 100644
index 0000000..7248e87
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/sandbox-iframe-blocks-top-navigation.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+    async_test(t => {
+        window.addEventListener("message", t.step_func_done(e => {
+            assert_equals(e.data.name, 'SecurityError', 'Should throw a security error.');
+            assert_equals(e.data.location, 'about:srcdoc', 'Exception is same-origin with the embedee.');
+        }));
+    }, "Sandboxed frames should throw when navigating the top-level window.");
+</script>
+<iframe sandbox="allow-scripts"
+        srcdoc="<script>
+                  try {
+                    top.location = '/security/frameNavigation/resources/fail.html';
+                    top.postMessage('No Exception', '*');
+                  } catch (e) {
+                    top.postMessage({
+                      'name': e.name,
+                      'location': e.constructor.constructor('return location.href')()
+                    }, '*');
+                  }
+                </script>"></iframe>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/secureContexts/authenticated_worker.https.html b/third_party/WebKit/LayoutTests/http/tests/security/secureContexts/authenticated_worker.https.html
new file mode 100644
index 0000000..a3885bd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/secureContexts/authenticated_worker.https.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/get-host-info.js"></script>
+<script>
+    test(function () {
+        assert_true(window.isSecureContext);
+    }, "Sanity-check the test runner.");
+
+    async_test(t => {
+        var w = new Worker("./resources/post-securecontext.js");
+        w.onmessage = t.step_func_done(e => {
+            assert_true(e.data.isSecureContext);
+        });
+    }, "Secure workers are secure.");
+
+    async_test(t => {
+        var url = URL.createObjectURL(new Blob(['postMessage({ "isSecureContext": self.isSecureContext });']));
+        var w = new Worker(url);
+        w.onmessage = t.step_func_done(e => {
+            assert_true(e.data.isSecureContext);
+        });
+    }, "Secure workers created from 'blob:' are secure.");
+
+    async_test(t => {
+        var w = new SharedWorker("./resources/post-securecontext-shared.js");
+        w.port.onmessage = t.step_func_done(e => {
+            assert_true(e.data.isSecureContext);
+        });
+    }, "Secure shared workers are secure.");
+
+    async_test(t => {
+        var url = URL.createObjectURL(new Blob(['self.onconnect = e => { e.ports[0].postMessage({ "isSecureContext": self.isSecureContext }); };']));
+        var w = new SharedWorker(url);
+        w.port.onmessage = t.step_func_done(e => {
+            assert_true(e.data.isSecureContext);
+        });
+    }, "Secure shared workers created from 'blob:' are secure.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/secureContexts/resources/post-securecontext-shared.js b/third_party/WebKit/LayoutTests/http/tests/security/secureContexts/resources/post-securecontext-shared.js
new file mode 100644
index 0000000..70f5563
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/secureContexts/resources/post-securecontext-shared.js
@@ -0,0 +1,3 @@
+self.onconnect = e => {
+    e.ports[0].postMessage({ "isSecureContext": self.isSecureContext });
+};
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/secureContexts/resources/post-securecontext.js b/third_party/WebKit/LayoutTests/http/tests/security/secureContexts/resources/post-securecontext.js
new file mode 100644
index 0000000..380da3b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/secureContexts/resources/post-securecontext.js
@@ -0,0 +1 @@
+postMessage({ "isSecureContext": self.isSecureContext });
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/secureContexts/unauthenticated_worker.html b/third_party/WebKit/LayoutTests/http/tests/security/secureContexts/unauthenticated_worker.html
new file mode 100644
index 0000000..0e715cc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/secureContexts/unauthenticated_worker.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/get-host-info.js"></script>
+<script>
+    if (window.location.origin != get_host_info().UNAUTHENTICATED_ORIGIN) {
+        window.location = get_host_info().UNAUTHENTICATED_ORIGIN +
+                          window.location.pathname;
+    } else {
+        test(function () {
+            assert_false(window.isSecureContext);
+        }, "Sanity-check the test runner.");
+
+        async_test(t => {
+            var w = new Worker("./resources/post-securecontext.js");
+            w.onmessage = t.step_func_done(e => {
+                assert_false(e.data.isSecureContext);
+            });
+        }, "Non-secure workers are non-secure.");
+
+        async_test(t => {
+            var url = URL.createObjectURL(new Blob(['postMessage({ "isSecureContext": self.isSecureContext });']));
+            var w = new Worker(url);
+            w.onmessage = t.step_func_done(e => {
+                assert_false(e.data.isSecureContext);
+            });
+        }, "Non-secure workers created from 'blob:' are non-secure.");
+
+        async_test(t => {
+            var w = new SharedWorker("./resources/post-securecontext-shared.js");
+            w.port.onmessage = t.step_func_done(e => {
+                assert_false(e.data.isSecureContext);
+            });
+        }, "Non-secure shared workers are non-secure.");
+
+        async_test(t => {
+            var url = URL.createObjectURL(new Blob(['self.onconnect = e => { e.ports[0].postMessage({ "isSecureContext": self.isSecureContext }); };']));
+            var w = new SharedWorker(url);
+            w.port.onmessage = t.step_func_done(e => {
+                assert_false(e.data.isSecureContext);
+            });
+        }, "Non-secure shared workers created from 'blob:' are non-secure.");
+    }
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-fetch-failure-output-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-fetch-failure-output-expected.txt
index 9cc9f97..b8be91b 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-fetch-failure-output-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-fetch-failure-output-expected.txt
@@ -1,6 +1,7 @@
-CONSOLE MESSAGE: line 12: If a Suborigin makes a request, a response without an Access-Control-Allow-Suborigin header should fail and should output a reasonable error message.
 CONSOLE ERROR: Fetch API cannot load http://127.0.0.1:8000/security/resources/cors-script.php?cors=false. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http-so://foobar.127.0.0.1:8000' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
-CONSOLE MESSAGE: line 18: PASS: Fetch correctly failed
 CONSOLE ERROR: Fetch API cannot load http://127.0.0.1:8000/security/resources/cors-script.php?cors=false. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http-so://foobar.127.0.0.1:8000' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
-CONSOLE MESSAGE: line 18: PASS: Fetch correctly failed
+This is a testharness.js-based test.
+PASS Custom headers causes preflight failure 
+PASS Lack of Access-Control-Allow-Suborigin on response causes failure 
+Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-fetch-failure-output.php b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-fetch-failure-output.php
index ddee8738..32ed050 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-fetch-failure-output.php
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-fetch-failure-output.php
@@ -5,32 +5,13 @@
 <html>
 <head>
 <meta charset="utf-8">
+<title>Fetches from suborigins require responses with valid Access-Control-Allow-Suborigin header</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 </head>
 <body>
 <script>
-if (window.testRunner) {
-  testRunner.waitUntilDone();
-  testRunner.dumpAsText();
-}
-console.log(
-  'If a Suborigin makes a request, a response without an ' +
-  'Access-Control-Allow-Suborigin header should fail and should output a ' +
-  'reasonable error message.');
-
-function success() {
-  console.log("PASS: Fetch correctly failed");
-  next();
-}
-
-function failure() {
-  console.log("FAIL: Fetch incorrectly succeeded");
-  next();
-}
-
-// First one should fail with preflight failure. Second one should
-// fail with access control header failure.
-var tests = [
-  function() {
+async_test(t => {
     var headers = new Headers();
     headers.append("x-custom-header", "foobar");
     var options = {
@@ -39,26 +20,16 @@
     fetch(
         "http://127.0.0.1:8000/security/resources/cors-script.php?cors=false",
         options)
-      .then(failure)
-      .catch(success);
-  },
-  function() {
+      .then(t.unreached_func('Fetch succeeded'))
+      .catch(t.step_func_done());
+  }, 'Custom headers causes preflight failure');
+
+async_test(t => {
       fetch(
         "http://127.0.0.1:8000/security/resources/cors-script.php?cors=false")
-      .then(failure)
-      .catch(success);
-  }
-];
-
-function next() {
-  if (tests.length !== 0) {
-    tests.shift()();
-  } else if (window.testRunner) {
-    testRunner.notifyDone();
-  }
-}
-
-next();
+      .then(t.unreached_func('Fetch succeeded'))
+      .catch(t.step_func_done());
+  }, 'Lack of Access-Control-Allow-Suborigin on response causes failure');
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-failure-output-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-failure-output-expected.txt
index 6937603..ed840e3b 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-failure-output-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-failure-output-expected.txt
@@ -1,6 +1,7 @@
-CONSOLE MESSAGE: line 12: If a Suborigin makes a request, a response without an Access-Control-Allow-Suborigin header should fail and should output a reasonable error message.
 CONSOLE ERROR: XMLHttpRequest cannot load http://127.0.0.1:8000/security/resources/cors-script.php?cors=false. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http-so://foobar.127.0.0.1:8000' is therefore not allowed access.
-ALERT: PASS: XHR correctly failed
 CONSOLE ERROR: XMLHttpRequest cannot load http://127.0.0.1:8000/security/resources/cors-script.php?cors=false. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http-so://foobar.127.0.0.1:8000' is therefore not allowed access.
-ALERT: PASS: XHR correctly failed
+This is a testharness.js-based test.
+PASS Custom headers causes preflight failure 
+PASS Lack of Access-Control-Allow-Suborigin on response causes failure 
+Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-failure-output.php b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-failure-output.php
index bae8eb3..7a4f9ad 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-failure-output.php
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-failure-output.php
@@ -5,59 +5,30 @@
 <html>
 <head>
 <meta charset="utf-8">
+<title>XHRs from suborigins require responses with valid Access-Control-Allow-Suborigin header</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 </head>
 <body>
 <script>
-if (window.testRunner) {
-  testRunner.waitUntilDone();
-  testRunner.dumpAsText();
-}
-console.log(
-    'If a Suborigin makes a request, a response without an ' +
-    'Access-Control-Allow-Suborigin header should fail and should ' +
-    'output a reasonable error message.');
-
-function success() {
-  alert('PASS: XHR correctly failed');
-  next();
-}
-
-function failure() {
-  alert('FAIL: XHR incorrectly succeeded');
-  next();
-}
-
-// First one should fail with preflight failure. Second one should
-// fail with access control header failure.
-var tests = [
-  function() {
+async_test(t => {
     var xhr = new XMLHttpRequest();
-    xhr.onerror = success;
-    xhr.onload = failure;
+    xhr.onerror = t.step_func_done();
+    xhr.onload = t.unreached_func('XHR succeeded');
     xhr.open('GET', 'http://127.0.0.1:8000/security/resources/' +
                     'cors-script.php?cors=false');
     xhr.setRequestHeader('x-custom-header', 'foobar');
     xhr.send();
-  },
-  function() {
+  }, 'Custom headers causes preflight failure');
+
+async_test(t => {
     var xhr = new XMLHttpRequest();
-    xhr.onerror = success;
-    xhr.onload = failure;
+    xhr.onerror = t.step_func_done();
+    xhr.onload = t.unreached_func();
     xhr.open('GET', 'http://127.0.0.1:8000/security/resources/' +
                     'cors-script.php?cors=false');
     xhr.send();
-  }
-];
-
-function next() {
-  if (tests.length !== 0) {
-    tests.shift()();
-  } else if (window.testRunner) {
-    testRunner.notifyDone();
-  }
-}
-
-next();
+  }, 'Lack of Access-Control-Allow-Suborigin on response causes failure');
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-preflight.php b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-preflight.php
index c7958f6..76ec18c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-preflight.php
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-preflight.php
@@ -19,28 +19,28 @@
 }
 
 SuboriginXHRTest.prototype.execute = function() {
-    var settings = this;
-    async_test(test => {
-        var xhr = new XMLHttpRequest();
+  var settings = this;
+  async_test(test => {
+      var xhr = new XMLHttpRequest();
 
-        if (settings.crossorigin_value === 'use-credentials') {
-          xhr.withCredentials = true;
-        }
+      if (settings.crossorigin_value === 'use-credentials') {
+        xhr.withCredentials = true;
+      }
 
-        if (settings.pass) {
-          xhr.onload = test.step_func_done();
-          xhr.onerror = test.unreached_func('Good XHR fired error handler.');
-        } else {
-          xhr.onload = test.unreached_func('Bad XHR successful.');
-          xhr.onerror = test.step_func_done();
-        }
+      if (settings.pass) {
+        xhr.onload = test.step_func_done();
+        xhr.onerror = test.unreached_func('Good XHR fired error handler.');
+      } else {
+        xhr.onload = test.unreached_func('Bad XHR successful.');
+        xhr.onerror = test.step_func_done();
+      }
 
-        xhr.open('GET', settings.src);
-        // Set a custom header to force a preflight. Even though the
-        // scheme/host/port of the source and destination origins are the same, the
-        // Suborigin should cause the request to be treated as cross-origin.
-        xhr.setRequestHeader('x-custom-header', 'foobar');
-        xhr.send();
+      xhr.open('GET', settings.src);
+      // Set a custom header to force a preflight. Even though the
+      // scheme/host/port of the source and destination origins are the same, the
+      // Suborigin should cause the request to be treated as cross-origin.
+      xhr.setRequestHeader('x-custom-header', 'foobar');
+      xhr.send();
     }, settings.name);
 };
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-cors-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-cors-expected.txt
index f95bb99..313696c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-cors-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-cors-expected.txt
@@ -1,15 +1,5 @@
 CONSOLE ERROR: line 1: Uncaught SomeError
-The Test passes if 'window.onerror' gets unsanitized information about an exception thrown in a script loaded with a 'crossorigin' attribute, and delivered with valid CORS headers.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS /SomeError/.test(msg) is true
-PASS url is "http://127.0.0.1:8000/security/resources/cors-script.php?fail=true&cors=http-so://foobar.127.0.0.1:8000"
-PASS line is 1
-PASS column is 1
-PASS window.errorObject is not null
-PASS successfullyParsed is true
-
-TEST COMPLETE
+This is a testharness.js-based test.
+PASS Verify that thrown exception is unsanitized when crossorigin script loaded with crossorigin attribute 
+Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-cors.php b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-cors.php
index cbe183e..fde9583 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-cors.php
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-cors.php
@@ -4,31 +4,24 @@
 <!DOCTYPE html>
 <head>
 <meta charset="utf-8">
+<title>Verify that thrown exception is unsanitized when crossorigin script loaded with crossorigin attribute</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 </head>
 <body>
-<script src="/js-test-resources/js-test.js"></script>
 <script>
-window.jsTestIsAsync = true;
-description(
-  'The Test passes if \'window.onerror\' gets unsanitized information about ' +
-  'an exception thrown in a script loaded with a \'crossorigin\' attribute, ' +
-  'and delivered with valid CORS headers.');
+setup({ allow_uncaught_exception: true });
 
 window.onerror = function(msg, url, line, column, error) {
-  window.msg = msg;
-  window.url = url;
-  window.line = line;
-  window.column = column;
-  window.errorObject = error;
-  shouldBeTrue('/SomeError/.test(msg)');
-  shouldBeEqualToString(
-    'url',
+  assert_true(/SomeError/.test(msg));
+  assert_equals(
+    url,
     'http://127.0.0.1:8000/security/resources/cors-script.php?' +
-    'fail=true&cors=http-so://foobar.127.0.0.1:8000');
-  shouldBe('line', '1');
-  shouldBe('column', '1');
-  shouldNotBe('window.errorObject', 'null');
-  finishJSTest();
+    'fail=true&cors=http-so://foobar.127.0.0.1:8000')
+  assert_equals(line, 1)
+  assert_equals(column, 1);
+  assert_not_equals(error, null);
+  done();
 }
 </script>
 <script crossorigin src="/security/resources/cors-script.php?fail=true&cors=http-so://foobar.127.0.0.1:8000"></script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-no-cors-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-no-cors-expected.txt
index 2886f0e..3bd5f8ae 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-no-cors-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-no-cors-expected.txt
@@ -1,15 +1,5 @@
 CONSOLE ERROR: line 1: Uncaught SomeError
-The test passes if 'window.onerror' gets sanitized information about an exception thrown in a script loaded from a suborigin.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS /SomeError/.test(msg) is false
-PASS url is ""
-PASS line is 0
-PASS column is 0
-PASS window.errorObject is null
-PASS successfullyParsed is true
-
-TEST COMPLETE
+This is a testharness.js-based test.
+PASS Verify that thrown exception is sanitized when crossorigin script loaded without crossorigin attribute 
+Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-no-cors.php b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-no-cors.php
index 7fac8ca1..901f8e42 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-no-cors.php
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-no-cors.php
@@ -4,27 +4,21 @@
 <!DOCTYPE html>
 <head>
 <meta charset="utf-8">
+<title>Verify that thrown exception is sanitized when crossorigin script loaded without crossorigin attribute</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 </head>
 <body>
-<script src="/js-test-resources/js-test.js"></script>
 <script>
-window.jsTestIsAsync = true;
-description(
-  'The test passes if \'window.onerror\' gets sanitized information about ' +
-  'an exception thrown in a script loaded from a suborigin.');
+setup({ allow_uncaught_exception: true });
 
 window.onerror = function(msg, url, line, column, error) {
-  window.msg = msg;
-  window.url = url;
-  window.line = line;
-  window.column = column;
-  window.errorObject = error;
-  shouldBeFalse('/SomeError/.test(msg)');
-  shouldBeEqualToString('url', '');
-  shouldBe('line', '0');
-  shouldBe('column', '0');
-  shouldBe('window.errorObject', 'null');
-  finishJSTest();
+  assert_false(/SomeError/.test(msg));
+  assert_equals(url, '');
+  assert_equals(line, 0);
+  assert_equals(column, 0);
+  assert_equals(error, null);
+  done();
 }
 </script>
 <script src="/security/resources/cors-script.php?fail=true&cors=false"></script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-window-event-exception-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-window-event-exception-expected.txt
deleted file mode 100644
index 8edc5066..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-window-event-exception-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-Cross-origin access to 'window.event' should throw a SecurityError.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS frame.contentWindow.event threw exception SecurityError: Blocked a frame with origin "http-so://foobar.127.0.0.1:8000" from accessing a cross-origin frame..
-PASS frame.contentWindow.event = 1; threw exception SecurityError: Blocked a frame with origin "http-so://foobar.127.0.0.1:8000" from accessing a cross-origin frame..
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-window-event-exception.php b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-window-event-exception.php
index 4406e3d4..59f462f 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-window-event-exception.php
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-window-event-exception.php
@@ -5,29 +5,24 @@
 <html>
 <head>
 <meta charset="utf-8">
+<title>Crossorigin access to window.event should throw a SecurityError</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 </head>
 <body>
-<iframe src="http://127.0.0.1:8000/"></iframe>
-<script src="/js-test-resources/js-test.js"></script>
 <script>
-window.jsTestIsAsync = true;
-description(
-  'Cross-origin access to \'window.event\' should throw a SecurityError.');
-
-var frame = document.querySelector('iframe');
-window.onload = function () {
-  shouldThrow(
-    'frame.contentWindow.event',
-    '"SecurityError: Blocked a frame with origin ' +
-    '\\"http-so://foobar.127.0.0.1:8000\\" from accessing a ' +
-    'cross-origin frame."');
-  shouldThrow(
-    'frame.contentWindow.event = 1;',
-    '"SecurityError: Blocked a frame with origin ' +
-    '\\"http-so://foobar.127.0.0.1:8000\\" from accessing a ' +
-    'cross-origin frame."');
-  finishJSTest();
+var iframe = document.createElement('iframe');
+iframe.src = 'http://127.0.0.1:8000/';
+iframe.onload = function() {
+  assert_throws('SecurityError', function() {
+      var e = iframe.contentWindow.event;
+    });
+  assert_throws('SecurityError', function() {
+      iframe.contentWindow.event = 1;
+    });
+  done();
 };
+document.body.appendChild(iframe);
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-window-open-exception-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-window-open-exception-expected.txt
deleted file mode 100644
index f116532..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-window-open-exception-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-Cross-origin access to 'window.open' and 'window.opener' should throw a SecurityError.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS frame.contentWindow.open() threw exception SecurityError: Blocked a frame with origin "http-so://foobar.127.0.0.1:8000" from accessing a cross-origin frame..
-PASS frame.contentWindow.opener = 1; threw exception SecurityError: Failed to set the 'opener' property on 'Window': Blocked a frame with origin "http-so://foobar.127.0.0.1:8000" from accessing a cross-origin frame..
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-window-open-exception.php b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-window-open-exception.php
index c711b62..2e66a68 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-window-open-exception.php
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-window-open-exception.php
@@ -5,30 +5,24 @@
 <html>
 <head>
 <meta charset="utf-8">
+<title>Crossorigin access to window.open and window.opener should throw a SecurityError</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 </head>
 <body>
-<iframe src="/"></iframe>
-<script src="/js-test-resources/js-test.js"></script>
 <script>
-window.jsTestIsAsync = true; 
-description(
-  'Cross-origin access to \'window.open\' and \'window.opener\' should ' +
-  'throw a SecurityError.');
-var frame = document.querySelector('iframe');
-window.onload = function () {
-  shouldThrow(
-    'frame.contentWindow.open()',
-    '"SecurityError: Blocked a frame with origin ' +
-    '\\"http-so://foobar.127.0.0.1:8000\\" from accessing a ' +
-    'cross-origin frame."');
-  shouldThrow(
-    'frame.contentWindow.opener = 1;',
-    '"SecurityError: Failed to set the \'opener\' property on ' +
-    '\'Window\': Blocked a frame with origin ' +
-    '\\"http-so://foobar.127.0.0.1:8000\\" from accessing a ' +
-    'cross-origin frame."');
-  finishJSTest();
+var iframe = document.createElement('iframe');
+iframe.src = '/';
+iframe.onload = function() {
+  assert_throws('SecurityError', function() {
+      iframe.contentWindow.open();
+    });
+  assert_throws('SecurityError', function() {
+      iframe.contentWindow.opener = 1;
+    });
+  done();
 };
+document.body.appendChild(iframe);
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-worker-onerror-no-cors-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-worker-onerror-no-cors-expected.txt
deleted file mode 100644
index 2c71315..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-worker-onerror-no-cors-expected.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-Ensure that scripts imported into a Worker from cross-origin hosts trigger sanitized onerror messages.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS worker = new Worker("/workers/resources/worker-importscripts-onerror-sameorigin.js") threw exception SecurityError: Failed to construct 'Worker': Script at 'http://127.0.0.1:8000/workers/resources/worker-importscripts-onerror-sameorigin.js' cannot be accessed from origin 'http-so://foobar.127.0.0.1:8000'..
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-worker-onerror-no-cors.php b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-worker-onerror-no-cors.php
index 43d0704..98eea6c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-worker-onerror-no-cors.php
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-worker-onerror-no-cors.php
@@ -5,25 +5,19 @@
 <html>
 <head>
 <meta charset="utf-8">
-<script>
-window.jsTestIsAsync = true;
-window.isOnErrorTest = true;
-</script>
-<script src="/js-test-resources/js-test.js"></script>
+<title>Scripts imported into a worker from crossorigin hosts throw SecurityError</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 </head>
 <body>
 <script>
-description('Ensure that scripts imported into a Worker from cross-origin hosts trigger sanitized onerror messages.');
-
 var worker;
 var worker_path =
-  '/workers/resources/worker-importscripts-onerror-sameorigin.js';
-shouldThrow(
-  'worker = new Worker("' + worker_path + '")',
-  '"SecurityError: Failed to construct \'Worker\': Script at ' +
-  '\'http://127.0.0.1:8000' + worker_path +
-  '\' cannot be accessed from origin \'http-so://foobar.127.0.0.1:8000\'."');
-finishJSTest();
+    '/workers/resources/worker-importscripts-onerror-sameorigin.js';
+assert_throws('SecurityError', function() {
+    worker = new Worker(worker_path);
+  });
+done();
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-allow-same-suborigin-access.html b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-allow-same-suborigin-access.html
index 4ad57b3f..7cbaebb 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-allow-same-suborigin-access.html
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-allow-same-suborigin-access.html
@@ -15,33 +15,29 @@
     test();
 }
 
-var tests = [
-  function() {
-    async_test(function(t) {
-        window.onmessage = t.step_func(function(event) {
-            assert_equals(event.data, 'I am a secret');
-            t.done();
-            next_test();
-          });
-        var iframe = document.createElement('iframe');
-        iframe.src = 'resources/iframe-reaches-into-parent.php?' +
-                     'suborigin=foobar&childsuborigin=foobar';
-        document.body.appendChild(iframe);
-      }, 'iframe reaches into parent')
-  },
-  function() {
-    async_test(function(t) {
-        window.onmessage = t.step_func(function(event) {
-            assert_equals(event.data, 'I am a secret');
-            t.done();
-            next_test();
-          });
-        var iframe = document.createElement('iframe');
-        iframe.src = 'resources/reach-into-iframe.php?' +
-                     'suborigin=foobar&childsuborigin=foobar';
-        document.body.appendChild(iframe);
-      }, 'Parent reaches into iframe')
+function make_iframe_test(test_name, resource) {
+  return function() {
+  async_test(t => {
+      window.onmessage = t.step_func(function(event) {
+          assert_equals(event.data, 'I am a secret');
+          // next_test() must be called before t.done() so that the next test,
+          // if one exists, is setup and the overall test doesn't end.
+          next_test();
+          t.done();
+        });
+      var iframe = document.createElement('iframe');
+      iframe.src = 'resources/' + resource + '?' +
+                   'suborigin=foobar&childsuborigin=foobar';
+      document.body.appendChild(iframe);
+    }, test_name);
   }
+}
+
+var tests = [
+  make_iframe_test(
+    'iframe reaches into parent', 'iframe-reaches-into-parent.php'),
+  make_iframe_test(
+    'parent reaches into iframe', 'reach-into-iframe.php')
 ];
 
 next_test();
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-in-meta-disallowed-console-warning-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-in-meta-disallowed-console-warning-expected.txt
deleted file mode 100644
index 86f98e4..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-in-meta-disallowed-console-warning-expected.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-CONSOLE ERROR: line 9: Error with Suborigin header: Suborigin header with value 'foobar' was delivered via a <meta> element and not an HTTP header, which is disallowed. The Suborigin has been ignored.
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-in-meta-disallowed-console-warning.html b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-in-meta-disallowed-console-warning.html
deleted file mode 100644
index f910829..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-in-meta-disallowed-console-warning.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="utf-8">
-<script>
-if (window.testRunner)
-  testRunner.dumpAsText();
-</script>
-<meta http-equiv="Suborigin" content="foobar">
-</head>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-in-meta-disallowed-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-in-meta-disallowed-expected.txt
new file mode 100644
index 0000000..910c60e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-in-meta-disallowed-expected.txt
@@ -0,0 +1,5 @@
+CONSOLE ERROR: line 5: Error with Suborigin header: Suborigin header with value 'foobar' was delivered via a <meta> element and not an HTTP header, which is disallowed. The Suborigin has been ignored.
+This is a testharness.js-based test.
+PASS The <meta> tag does not allow a page to enter a suborigin. 
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-invalid-names-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-invalid-names-expected.txt
index 8bc72a6..d390006 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-invalid-names-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-invalid-names-expected.txt
@@ -1,18 +1,12 @@
-ALERT: I am a secret
 CONSOLE ERROR: Error with Suborigin header: Invalid character ''' in suborigin.
-ALERT: I am a secret
 CONSOLE ERROR: Error with Suborigin header: Invalid character ''' in suborigin.
-ALERT: I am a secret
 CONSOLE ERROR: Error with Suborigin header: Invalid character ''' in suborigin.
-ALERT: I am a secret
 CONSOLE ERROR: Error with Suborigin header: Invalid character ''' in suborigin.
-ALERT: I am a secret
 CONSOLE ERROR: Error with Suborigin header: Invalid character '@' in suborigin.
-ALERT: I am a secret
 CONSOLE ERROR: Error with Suborigin header: Invalid character 'b' in suborigin policy. Suborigin policy options must start and end with a single quote.
-ALERT: I am a secret
 CONSOLE ERROR: Error with Suborigin header: Invalid character 'F' in suborigin.
-ALERT: I am a secret
 CONSOLE ERROR: Error with Suborigin header: Invalid character 'F' in suborigin.
-ALERT: I am a secret
+This is a testharness.js-based test.
+PASS Invalid suborigin names 
+Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-invalid-names.html b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-invalid-names.html
index 70c5a27..397484d0 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-invalid-names.html
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-invalid-names.html
@@ -3,19 +3,12 @@
 <head>
 <meta charset="utf-8">
 <title>Invalid suborigin names</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 </head>
 
+<body>
 <script>
-if (window.testRunner) {
-  testRunner.dumpAsText();
-  testRunner.waitUntilDone();
-}
-
-function finish() {
-  if (window.testRunner)
-    testRunner.notifyDone();
-}
-
 var test_suborigin_names = [
   '',
   '\'foobar\'',
@@ -28,24 +21,31 @@
   'FOOBAR',
 ];
 
-var iframe;
-var i = 0;
-function next() {
-  if (i >= test_suborigin_names.length)
-    finish();
-  document.getElementById('iframe').src = 'resources/reach-into-iframe.php?' +
-                                          'childsuborigin=' +
-                                          test_suborigin_names[i];
-  i++;
-}
+async_test(t => {
+    var i = 0;
 
-window.onmessage = function(event) {
-  alert(event.data);
-  next();
-};
+    window.onmessage = t.step_func(function(event) {
+        assert_equals(event.data, 'I am a secret');
+        next();
+      });
 
-window.onload = function() {
-  next();
-};
+    function next() {
+      if (i >= test_suborigin_names.length) {
+        t.done();
+        return;
+      }
+
+      var iframe = document.createElement('iframe');
+      iframe.src =
+        'resources/reach-into-iframe.php?childsuborigin=' +
+        test_suborigin_names[i];
+      document.body.appendChild(iframe);
+
+      i++;
+    }
+
+    next();
+  }, 'Invalid suborigin names');
 </script>
-<iframe id="iframe"></iframe>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-multiple-suborigins-disallowed-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-multiple-suborigins-disallowed-expected.txt
index b6f792d..f0f5ffd 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-multiple-suborigins-disallowed-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-multiple-suborigins-disallowed-expected.txt
@@ -1,2 +1,7 @@
 CONSOLE ERROR: Error with Suborigin header: Multiple Suborigin headers found. Ignoring all but the first.
+This is a testharness.js-based test.
+PASS 'foo' is the assigned suborigin 
+PASS 'bar' is not a valid suborigin 
+PASS Cannot access frame without suborigin 
+Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-multiple-suborigins-disallowed.php b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-multiple-suborigins-disallowed.php
index 1f61f72..166bc43 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-multiple-suborigins-disallowed.php
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-multiple-suborigins-disallowed.php
@@ -5,11 +5,58 @@
 <html>
 <head>
 <meta charset="utf-8">
+<title>Only first of multiple suborigins assigned</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 </head>
 <body>
 <script>
-if (window.testRunner)
-  testRunner.dumpAsText();
+async_test(t => {
+    window.secret = 'unchanged';
+    var iframe = document.createElement('iframe');
+    iframe.src = 'resources/post-to-parent.php?suborigin=foo';
+    iframe.onload = t.step_func(function() {
+        try {
+          var secret = iframe.contentWindow.secret;
+          t.done();
+        } catch (e) {
+          assert_unreached(
+            'Unable to read secret from iframe in same suborigin');
+        }
+      });
+    document.body.appendChild(iframe);
+  }, '\'foo\' is the assigned suborigin');
+
+async_test(t => {
+    window.secret = 'unchanged';
+    var iframe = document.createElement('iframe');
+    iframe.src = 'resources/post-to-parent.php?suborigin=bar';
+    iframe.onload = t.step_func(function() {
+        try {
+          var secret = iframe.contentWindow.secret;
+          assert_unreached(
+            'Successfully read secret from iframe in a suborigin');
+        } catch (e) {
+          t.done();
+        }
+      });
+    document.body.appendChild(iframe);
+  }, '\'bar\' is not a valid suborigin');
+
+async_test(t => {
+    window.secret = 'unchanged';
+    var iframe = document.createElement('iframe');
+    iframe.src = 'resources/post-to-parent.php';
+    iframe.onload = t.step_func(function() {
+        try {
+          var secret = iframe.contentWindow.secret;
+          assert_unreached('Able to read secret from iframe without suborigin');
+        } catch (e) {
+          t.done();
+        }
+      });
+    document.body.appendChild(iframe);
+  }, 'Cannot access frame without suborigin');
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-valid-names-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-valid-names-expected.txt
deleted file mode 100644
index 7f0c9b9..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-valid-names-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-ALERT: SecurityError: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame.
-ALERT: SecurityError: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame.
-ALERT: SecurityError: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame.
-ALERT: SecurityError: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame.
-ALERT: SecurityError: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame.
-ALERT: SecurityError: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame.
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-valid-names.html b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-valid-names.html
index 6572af7..fb264ab 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-valid-names.html
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-valid-names.html
@@ -3,19 +3,11 @@
 <head>
 <meta charset="utf-8">
 <title>Valid suborigin names</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 </head>
-
+<body>
 <script>
-if (window.testRunner) {
-  testRunner.dumpAsText();
-  testRunner.waitUntilDone();
-}
-
-function finish() {
-  if (window.testRunner)
-    testRunner.notifyDone();
-}
-
 var test_suborigin_names = [
   'foobar',
   'foob4r',
@@ -25,23 +17,33 @@
   'foobar-'
 ];
 
-var iframe;
-var i = 0;
-function next() {
-  if (i >= test_suborigin_names.length)
-    finish();
-  document.getElementById('iframe').src =
-    'resources/reach-into-iframe.php?childsuborigin=' + test_suborigin_names[i];
-  i++;
-}
+async_test(t => {
+    var i = 0;
 
-window.onmessage = function(event) {
-  alert(event.data);
-  next();
-};
+    window.onmessage = t.step_func(function(event) {
+        assert_equals(
+          event.data,
+          'SecurityError: Blocked a frame with origin ' +
+          '"http://127.0.0.1:8000" from accessing a cross-origin frame.');
+        next();
+      });
 
-window.onload = function() {
-  next();
-};
+    function next() {
+      if (i >= test_suborigin_names.length) {
+        t.done();
+        return;
+      }
+
+      var iframe = document.createElement('iframe');
+      iframe.src =
+        'resources/reach-into-iframe.php?childsuborigin=' +
+        test_suborigin_names[i];
+      document.body.appendChild(iframe);
+
+      i++;
+    }
+
+    next();
+  }, 'Valid suborigin names');
 </script>
-<iframe id="iframe"></iframe>
+</body>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 82a4757b..2e9340c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -1210,6 +1210,7 @@
     getter caches
     getter crypto
     getter indexedDB
+    getter isSecureContext
     getter location
     getter navigator
     getter onerror
diff --git a/third_party/WebKit/LayoutTests/http/tests/worklet/webexposed/global-interface-listing-paint-worklet-expected.txt b/third_party/WebKit/LayoutTests/http/tests/worklet/webexposed/global-interface-listing-paint-worklet-expected.txt
index f965d37..20d967e 100644
--- a/third_party/WebKit/LayoutTests/http/tests/worklet/webexposed/global-interface-listing-paint-worklet-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/worklet/webexposed/global-interface-listing-paint-worklet-expected.txt
@@ -91,7 +91,6 @@
 CONSOLE MESSAGE: line 137:     getter type
 CONSOLE MESSAGE: line 137:     getter value
 CONSOLE MESSAGE: line 137:     method constructor
-CONSOLE MESSAGE: line 137:     setter value
 CONSOLE MESSAGE: line 137: interface CSSSkew : CSSTransformComponent
 CONSOLE MESSAGE: line 137:     getter ax
 CONSOLE MESSAGE: line 137:     getter ay
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/html/browsers/history/the-location-interface/security_location_0.sub-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/html/browsers/history/the-location-interface/security_location_0.sub-expected.txt
new file mode 100644
index 0000000..055af33
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt/html/browsers/history/the-location-interface/security_location_0.sub-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Accessing location object from different origins doesn't raise SECURITY_ERR exception Failed to set the 'location' property on 'Window': 'http://www1.{{host}}:{{ports[http][0]}}/' is not a valid URL.
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/embedded-content/the-img-element/update-the-source-set-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/embedded-content/the-img-element/update-the-source-set-expected.txt
index a36e9d4..e74c2d35 100644
--- a/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/embedded-content/the-img-element/update-the-source-set-expected.txt
+++ b/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/embedded-content/the-img-element/update-the-source-set-expected.txt
@@ -1,8 +1,8 @@
 CONSOLE WARNING: <source src> with a <picture> parent is invalid and therefore ignored. Please use <source srcset> instead.
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'x' descriptors or a mix of 'x' and 'w'/'h' descriptors.
-CONSOLE ERROR: Dropped srcset candidate data:,b
+CONSOLE ERROR: Dropped srcset candidate "data:,b"
 CONSOLE ERROR: line 139: Failed parsing 'srcset' attribute value since it has multiple 'x' descriptors or a mix of 'x' and 'w'/'h' descriptors.
-CONSOLE ERROR: line 139: Dropped srcset candidate data:,b
+CONSOLE ERROR: line 139: Dropped srcset candidate "data:,b"
 This is a testharness.js-based test.
 PASS <img data-expect=""> 
 PASS <img src="" data-expect=""> 
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-dir-expected.txt b/third_party/WebKit/LayoutTests/inspector/console/console-dir-expected.txt
index a04d1d6..0019938 100644
--- a/third_party/WebKit/LayoutTests/inspector/console/console-dir-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/console/console-dir-expected.txt
@@ -33,7 +33,7 @@
     c d: "c d"
     negZero: -0
     __proto__: Object
-console-dir.html:19 anonymous()
+console-dir.html:19 function anonymous()
     arguments: null
     caller: null
     length: 0
@@ -50,7 +50,7 @@
     foo: Object
         No Properties
     __proto__: Object
-console-dir.html:29 get __proto__()
+console-dir.html:29 function get __proto__()
     arguments: null
     caller: null
     length: 0
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-dirxml-expected.txt b/third_party/WebKit/LayoutTests/inspector/console/console-dirxml-expected.txt
index 7333695..1598400 100644
--- a/third_party/WebKit/LayoutTests/inspector/console/console-dirxml-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/console/console-dirxml-expected.txt
@@ -9,5 +9,5 @@
 console-dirxml.html:13 #document-fragment
 console-dirxml.html:14 <p></p>
 console-dirxml.html:15 [p]
-console-dirxml.html:16 [#document, #document-fragment, <span></span>]
+console-dirxml.html:16 [document, document-fragment, span]
 
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-format-expected.txt b/third_party/WebKit/LayoutTests/inspector/console/console-format-expected.txt
index a1159cb4..12e3196a 100644
--- a/third_party/WebKit/LayoutTests/inspector/console/console-format-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/console/console-format-expected.txt
@@ -145,16 +145,16 @@
 console-format.html:8 [p#p]
 globals[7]
     <p id="p">Tests that console logging dumps proper messages.</p>
-console-format.html:7 () { return 1; }
+console-format.html:7 function () { return 1; }
 console-format.html:8 [function]
 globals[8]
-() { return 1; }
-console-format.html:7 () {
+function () { return 1; }
+console-format.html:7 function () {
         return 2;
     }
 console-format.html:8 [function]
 globals[9]
-() {
+function () {
         return 2;
     }
 console-format.html:7 0.12
@@ -237,19 +237,19 @@
 console-format.html:8 [Object]
 globals[28]
 Object {}
-console-format.html:7 Object() { [native code] }
+console-format.html:7 function Object() { [native code] }
 console-format.html:8 [function]
 globals[29]
-Object() { [native code] }
+function Object() { [native code] }
 console-format.html:7 Object {}
 console-format.html:8 [Object]
 globals[30]
 Object {}
-console-format.html:7 ( /**/ foo/**/, /*/**/bar,
+console-format.html:7 function ( /**/ foo/**/, /*/**/bar,
     /**/baz) {}
 console-format.html:8 [function]
 globals[31]
-( /**/ foo/**/, /*/**/bar,
+function ( /**/ foo/**/, /*/**/bar,
     /**/baz) {}
 console-format.html:7 Number {[[PrimitiveValue]]: 42}
 console-format.html:8 [Number]
@@ -368,14 +368,14 @@
     __proto__: Array[0]
 globals[7]
     <p id="p">Tests that console logging dumps proper messages.</p>
-console-format.html:7 () { return 1; }
+console-format.html:7 function () { return 1; }
 console-format.html:8 Array[1]
     0: ()
     length: 1
     __proto__: Array[0]
 globals[8]
-() { return 1; }
-console-format.html:7 () {
+function () { return 1; }
+console-format.html:7 function () {
         return 2;
     }
 console-format.html:8 Array[1]
@@ -383,7 +383,7 @@
     length: 1
     __proto__: Array[0]
 globals[9]
-() {
+function () {
         return 2;
     }
 console-format.html:7 0.12
@@ -565,13 +565,13 @@
 globals[28]
 Object
     No Properties
-console-format.html:7 Object() { [native code] }
+console-format.html:7 function Object() { [native code] }
 console-format.html:8 Array[1]
     0: Object()
     length: 1
     __proto__: Array[0]
 globals[29]
-Object() { [native code] }
+function Object() { [native code] }
 console-format.html:7 Object
     __defineGetter__: __defineGetter__()
     __defineSetter__: __defineSetter__()
@@ -605,14 +605,14 @@
     valueOf: valueOf()
     get __proto__: __proto__()
     set __proto__: __proto__()
-console-format.html:7 ( /**/ foo/**/, /*/**/bar,
+console-format.html:7 function ( /**/ foo/**/, /*/**/bar,
     /**/baz) {}
 console-format.html:8 Array[1]
     0: ( /**/ foo/**/, /*/**/bar,     /**/baz)
     length: 1
     __proto__: Array[0]
 globals[31]
-( /**/ foo/**/, /*/**/bar,
+function ( /**/ foo/**/, /*/**/bar,
     /**/baz) {}
 console-format.html:7 Number
     __proto__: Number
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-functions-expected.txt b/third_party/WebKit/LayoutTests/inspector/console/console-functions-expected.txt
new file mode 100644
index 0000000..67ad42c1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/console/console-functions-expected.txt
@@ -0,0 +1,51 @@
+CONSOLE MESSAGE: line 13: function simple() {}
+CONSOLE MESSAGE: line 14: function simple() {}
+CONSOLE MESSAGE: line 15: async function asyncSimple() {}
+CONSOLE MESSAGE: line 16: async function asyncSimple() {}
+CONSOLE MESSAGE: line 17: function* genSimple() {}
+CONSOLE MESSAGE: line 18: function* genSimple() {}
+CONSOLE MESSAGE: line 21: [object Object]
+CONSOLE MESSAGE: line 22: [object Object]
+Tests that console logging different types of functions correctly.
+
+console-functions.html:13 function simple() {}
+console-functions.html:14 function simple()
+    arguments: null
+    caller: null
+    length: 0
+    name: "simple"
+    prototype: Object
+    __proto__: ()
+    [[FunctionLocation]]: console-functions.html:9
+    [[Scopes]]: Scopes[1]
+console-functions.html:15 async function asyncSimple() {}
+console-functions.html:16 async function asyncSimple()
+    arguments: (...)
+    caller: (...)
+    length: 0
+    name: "asyncSimple"
+    __proto__: AsyncFunction
+    [[FunctionLocation]]: console-functions.html:10
+    [[Scopes]]: Scopes[1]
+console-functions.html:17 function* genSimple() {}
+console-functions.html:18 function* genSimple()
+    arguments: (...)
+    caller: (...)
+    length: 0
+    name: "genSimple"
+    prototype: Generator
+    __proto__: GeneratorFunction
+    [[FunctionLocation]]: console-functions.html:11
+    [[IsGenerator]]: true
+    [[Scopes]]: Scopes[1]
+console-functions.html:21 Object
+    func1: simple()
+    func2: asyncSimple()
+    func3: genSimple()
+    __proto__: Object
+console-functions.html:22 Object
+    func1: simple()
+    func2: asyncSimple()
+    func3: genSimple()
+    __proto__: Object
+
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-functions.html b/third_party/WebKit/LayoutTests/inspector/console/console-functions.html
new file mode 100644
index 0000000..4aa3c60
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/console/console-functions.html
@@ -0,0 +1,44 @@
+<html>
+<head>
+<script src="../../http/tests/inspector/inspector-test.js"></script>
+<script src="../../http/tests/inspector/console-test.js"></script>
+<script>
+
+function onload()
+{
+    function simple() {}
+    async function asyncSimple() {}
+    function* genSimple() {}
+
+    console.log(simple);
+    console.dir(simple);
+    console.log(asyncSimple);
+    console.dir(asyncSimple);
+    console.log(genSimple);
+    console.dir(genSimple);
+
+    var obj = { func1: simple, func2: asyncSimple, func3: genSimple };
+    console.log(obj);
+    console.dir(obj);
+
+    runTest();
+}
+
+function test()
+{
+    InspectorTest.expandConsoleMessages(dumpConsoleMessages);
+
+    function dumpConsoleMessages()
+    {
+        InspectorTest.dumpConsoleMessages(false, false, InspectorTest.textContentWithLineBreaks);
+        InspectorTest.completeTest();
+    }
+}
+
+</script>
+</head>
+
+<body onload="onload()">
+<p>Tests that console logging different types of functions correctly.</p>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-native-function-expected.txt b/third_party/WebKit/LayoutTests/inspector/console/console-native-function-expected.txt
index b1b6b62..a981380 100644
--- a/third_party/WebKit/LayoutTests/inspector/console/console-native-function-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/console/console-native-function-expected.txt
@@ -1,7 +1,7 @@
 Tests that console dumps native function without exception.
 
 Math.random
-random() { [native code] }
+function random() { [native code] }
 document.appendChild
-appendChild() { [native code] }
+function appendChild() { [native code] }
 
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-save-to-temp-var-expected.txt b/third_party/WebKit/LayoutTests/inspector/console/console-save-to-temp-var-expected.txt
index 21d3eae..db6a0d2e 100644
--- a/third_party/WebKit/LayoutTests/inspector/console/console-save-to-temp-var-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/console/console-save-to-temp-var-expected.txt
@@ -22,7 +22,7 @@
 temp14
 [1, 2, 3, 4]
 temp15
-func() {}
+function func() {}
 temp16
 Error: errr
 
diff --git a/third_party/WebKit/LayoutTests/inspector/extensions/extensions-panel.html b/third_party/WebKit/LayoutTests/inspector/extensions/extensions-panel.html
index 9e4b20a..82448a98 100644
--- a/third_party/WebKit/LayoutTests/inspector/extensions/extensions-panel.html
+++ b/third_party/WebKit/LayoutTests/inspector/extensions/extensions-panel.html
@@ -98,8 +98,7 @@
 
         function showUILocationHook(uiLocation)
         {
-            var networkURL = WebInspector.networkMapping.networkURL(uiLocation.uiSourceCode);
-            showURL("sources", networkURL, uiLocation.lineNumber);
+            showURL("sources", uiLocation.uiSourceCode.url(), uiLocation.lineNumber);
         }
 
         function showResourceHook(resource, lineNumber)
diff --git a/third_party/WebKit/LayoutTests/inspector/jump-to-previous-editing-location.html b/third_party/WebKit/LayoutTests/inspector/jump-to-previous-editing-location.html
index 4e293de7..ce777fb 100644
--- a/third_party/WebKit/LayoutTests/inspector/jump-to-previous-editing-location.html
+++ b/third_party/WebKit/LayoutTests/inspector/jump-to-previous-editing-location.html
@@ -221,7 +221,7 @@
             function onScriptSource(uiSourceCode)
             {
                 var linkifier = new WebInspector.Linkifier();
-                var anchorURI = WebInspector.networkMapping.networkURL(uiSourceCode);
+                var anchorURI = uiSourceCode.url();
                 var anchor = linkifier.linkifyScriptLocation(WebInspector.targetManager.mainTarget(), null, anchorURI, 10, 1);
                 WebInspector.Revealer.revealPromise(anchor[WebInspector.Linkifier._uiLocationSymbol]).then(function() {
                     InspectorTest.addResult("Selection: " + panel.visibleView.textEditor.selection().toString());
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-calculate-time.html b/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-calculate-time.html
index 82d8916..d65adbb 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-calculate-time.html
+++ b/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-calculate-time.html
@@ -93,6 +93,8 @@
         "endTime": 1375445601.070847,
         "samples": [ 1, 2 ]
     };
+    profileAndExpectations.root = profileAndExpectations.head;
+    WebInspector.ProfileTreeModel.prototype._assignDepthsAndParents.call(profileAndExpectations);
     WebInspector.ProfileTreeModel.prototype._calculateTotals(profileAndExpectations.head);
     function checkExpectations(node)
     {
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-breakpoints/breakpoint-manager.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-breakpoints/breakpoint-manager.html
index 6ee4708..a2a0d3b 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-breakpoints/breakpoint-manager.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-breakpoints/breakpoint-manager.html
@@ -187,8 +187,7 @@
 
                 uiLocationToRawLocation: function(uiSourceCode, lineNumber)
                 {
-                    var networkURL = InspectorTest.testNetworkMapping.networkURL(uiSourceCode);
-                    return new WebInspector.DebuggerModel.Location(mockTarget.debuggerModel, networkURL, lineNumber - 10, 0);
+                    return new WebInspector.DebuggerModel.Location(mockTarget.debuggerModel, uiSourceCode.url(), lineNumber - 10, 0);
                 },
 
                 isIdentity: function()
@@ -260,8 +259,7 @@
 
                     uiLocationToRawLocation: function(uiSourceCode, lineNumber)
                     {
-                        var networkURL = InspectorTest.testNetworkMapping.networkURL(uiSourceCodeA);
-                        return new WebInspector.DebuggerModel.Location(mockTarget.debuggerModel, networkURL, lineNumber - 10, 0);
+                        return new WebInspector.DebuggerModel.Location(mockTarget.debuggerModel, uiSourceCodeA.url(), lineNumber - 10, 0);
                     },
 
                     isIdentity: function()
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-breakpoints/breakpoint-manager.js b/third_party/WebKit/LayoutTests/inspector/sources/debugger-breakpoints/breakpoint-manager.js
index 5fcd616..0fba1bf 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-breakpoints/breakpoint-manager.js
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-breakpoints/breakpoint-manager.js
@@ -14,10 +14,9 @@
 
         uiLocationToRawLocation: function(uiSourceCode, lineNumber)
         {
-            var networkURL = InspectorTest.testNetworkMapping.networkURL(uiSourceCode);
-            if (!InspectorTest.uiSourceCodes[networkURL])
+            if (!InspectorTest.uiSourceCodes[uiSourceCode.url()])
                 return null;
-            return new WebInspector.DebuggerModel.Location(target.debuggerModel, networkURL, lineNumber, 0);
+            return new WebInspector.DebuggerModel.Location(target.debuggerModel, uiSourceCode.url(), lineNumber, 0);
         },
 
         isIdentity: function()
@@ -207,8 +206,7 @@
     var uiSourceCodes = breakpointManager._workspace.uiSourceCodesForProjectType(WebInspector.projectTypes.Debugger);
     for (var i = 0; i < uiSourceCodes.length; ++i) {
         var uiSourceCode = uiSourceCodes[i];
-        var networkURL = InspectorTest.testNetworkMapping.networkURL(uiSourceCode);
-        if (networkURL === url) {
+        if (uiSourceCode.url() === url) {
             breakpointManager._debuggerWorkspaceBinding.setSourceMapping(target, uiSourceCode, breakpointManager.defaultMapping);
             InspectorTest.uiSourceCodes[url] = uiSourceCode;
             return uiSourceCode;
@@ -275,7 +273,7 @@
             mappingForManager = targets[i].defaultMapping;
     }
 
-    var breakpointManager = new WebInspector.BreakpointManager(setting, debuggerWorkspaceBinding._workspace, debuggerWorkspaceBinding._networkMapping, targetManager, debuggerWorkspaceBinding);
+    var breakpointManager = new WebInspector.BreakpointManager(setting, debuggerWorkspaceBinding._workspace, targetManager, debuggerWorkspaceBinding);
     breakpointManager.defaultMapping = mappingForManager;
     breakpointManager.addEventListener(WebInspector.BreakpointManager.Events.BreakpointAdded, breakpointAdded);
     breakpointManager.addEventListener(WebInspector.BreakpointManager.Events.BreakpointRemoved, breakpointRemoved);
@@ -318,8 +316,7 @@
         locations.sort(function(a, b) {
             return a.lineNumber - b.lineNumber;
         });
-        var networkURL = InspectorTest.testNetworkMapping.networkURL(uiSourceCode);
-        InspectorTest.addResult("    UISourceCode (url='" + networkURL + "', uri='" + uiSourceCode.url() + "')");
+        InspectorTest.addResult("    UISourceCode (url='" + uiSourceCode.url() + "', uri='" + uiSourceCode.url() + "')");
         for (var i = 0; i < locations.length; ++i)
             InspectorTest.addResult("      Location: (" + locations[i].lineNumber + ", " + locations[i].columnNumber + ")");
     }
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/debugger-save-to-temp-var-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/debugger-save-to-temp-var-expected.txt
index d1a18ae..b642947 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/debugger-save-to-temp-var-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/debugger-save-to-temp-var-expected.txt
@@ -23,7 +23,7 @@
 temp14
 [1, 2, 3, 4]
 temp15
-func() {}
+function func() {}
 temp16
 Error: errr
 
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/show-function-definition-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/show-function-definition-expected.txt
index 4c3aad0f..679daad7 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/show-function-definition-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/show-function-definition-expected.txt
@@ -6,7 +6,7 @@
 
 Running: testDumpFunctionDefinition
 jumpToMe
-jumpToMe()
+function jumpToMe()
 {
     var result = 12345;
     return window.foo || result;
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/ui-source-code-display-name.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/ui-source-code-display-name.html
index 9fdef80..954c60f1 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/ui-source-code-display-name.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/ui-source-code-display-name.html
@@ -17,7 +17,7 @@
     }
 
     var workspace = new WebInspector.Workspace();
-    workspace.networkProject = new WebInspector.NetworkProject(InspectorTest.mainTarget, workspace, WebInspector.networkMapping);
+    workspace.networkProject = new WebInspector.NetworkProject(InspectorTest.mainTarget, workspace);
 
     function addNetworkFile(url)
     {
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger/file-system-project-mapping.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger/file-system-project-mapping.html
index c6568e4..f4c1bf9 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger/file-system-project-mapping.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger/file-system-project-mapping.html
@@ -33,8 +33,8 @@
         InspectorTest.addResult("UISourceCode uri to url mappings:");
         for (var uiSourceCode of uiSourceCodes) {
             var binding = persistence.binding(uiSourceCode);
-            var networkURL = binding ? binding.network.url() : "";
-            InspectorTest.addResult("    " + uiSourceCode.url() + " -> " + networkURL);
+            var url = binding ? binding.network.url() : "";
+            InspectorTest.addResult("    " + uiSourceCode.url() + " -> " + url);
         }
     }
 
@@ -94,8 +94,7 @@
                 InspectorTest.addMockUISourceCodeViaNetwork("http://localhost/bar.js", WebInspector.resourceTypes.Script, "<foo content>", target);
                 dumpFileSystemUISourceCodesMappings();
 
-                var networkURL = InspectorTest.testNetworkMapping.networkURL(networkUISourceCode);
-                WebInspector.fileSystemMapping.removeMappingForURL(networkURL);
+                WebInspector.fileSystemMapping.removeMappingForURL(networkUISourceCode.url());
                 fs.reportRemoved();
                 next();
             }
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger/properties-special-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger/properties-special-expected.txt
index 36d5ec9..59309433 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger/properties-special-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger/properties-special-expected.txt
@@ -7,7 +7,7 @@
 properties-special.html:10 Boolean
     __proto__: Boolean
     [[PrimitiveValue]]: true
-properties-special.html:11 anonymous(a, b)
+properties-special.html:11 function anonymous(a, b)
     arguments: null
     caller: null
     length: 2
@@ -16,7 +16,7 @@
     __proto__: ()
     [[FunctionLocation]]: properties-special.html:11
     [[Scopes]]: Scopes[1]
-properties-special.html:12 bound ()
+properties-special.html:12 function bound ()
     arguments: (...)
     caller: (...)
     length: 1
@@ -25,7 +25,7 @@
     [[TargetFunction]]: (a,b)
     [[BoundThis]]: Object
     [[BoundArgs]]: Array[1]
-properties-special.html:13 anonymous()
+properties-special.html:13 function* anonymous()
     arguments: (...)
     caller: (...)
     length: 0
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing-browser-thread-expected.txt b/third_party/WebKit/LayoutTests/inspector/tracing-browser-thread-expected.txt
new file mode 100644
index 0000000..31fb31b2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/tracing-browser-thread-expected.txt
@@ -0,0 +1,6 @@
+Test that tracing model correctly finds the main browser thread in the trace.
+
+chrome: main browser thread is CrBrowserMain (#4)
+headless: main browser thread is CrBrowserMain (#4)
+weird-names: main browser thread is Bar (#4)
+
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing-browser-thread.html b/third_party/WebKit/LayoutTests/inspector/tracing-browser-thread.html
new file mode 100644
index 0000000..9827e3e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/tracing-browser-thread.html
@@ -0,0 +1,55 @@
+<html>
+<head>
+<script src="../http/tests/inspector/inspector-test.js"></script>
+<script src="../http/tests/inspector/timeline-test.js"></script>
+<script>
+function test()
+{
+    var sessionId = 1;
+
+    var testCases = {
+        "chrome": [
+           { "cat": "__metadata", "name": "process_name", "ph": "M", "pid": 1, "tid": 2, "ts": 0, "args": { "name": "Renderer" } },
+           { "cat": "__metadata", "name": "thread_name", "ph": "M", "pid": 1, "tid": 2, "ts": 0, "args": { "name": "CrRendererMain" } },
+           { "cat": "disabled-by-default-devtools.timeline", "ph": "I", "name": "TracingStartedInPage", "pid": 1, "tid": 2, "ts": 100000, "tts": 606543, "args": { "sessionId": sessionId, "page": "0x4age111" } },
+           { "cat": "__metadata", "name": "process_name", "ph": "M", "pid": 3, "tid": 4, "ts": 0, "args": { "name": "Browser" } },
+           { "cat": "__metadata", "name": "thread_name", "ph": "M", "pid": 3, "tid": 4, "ts": 0, "args": { "name": "CrBrowserMain" } },
+           { "cat": "disabled-by-default-devtools.timeline", "ph": "I", "name": "TracingStartedInPage", "pid": 1, "tid": 2, "ts": 100000, "tts": 606543, "args": { "sessionId": sessionId, "page": "0x4age111" } },
+        ],
+        "headless": [
+           { "cat": "__metadata", "name": "process_name", "ph": "M", "pid": 1, "tid": 2, "ts": 0, "args": { "name": "Renderer" } },
+           { "cat": "__metadata", "name": "thread_name", "ph": "M", "pid": 1, "tid": 2, "ts": 0, "args": { "name": "CrRendererMain" } },
+           { "cat": "disabled-by-default-devtools.timeline", "ph": "I", "name": "TracingStartedInPage", "pid": 1, "tid": 2, "ts": 100000, "tts": 606543, "args": { "sessionId": sessionId, "page": "0x4age111" } },
+           { "cat": "__metadata", "name": "process_name", "ph": "M", "pid": 3, "tid": 4, "ts": 0, "args": { "name": "HeadlessBrowser" } },
+           { "cat": "__metadata", "name": "thread_name", "ph": "M", "pid": 3, "tid": 4, "ts": 0, "args": { "name": "CrBrowserMain" } },
+           { "cat": "disabled-by-default-devtools.timeline", "ph": "I", "name": "TracingStartedInPage", "pid": 1, "tid": 2, "ts": 100000, "tts": 606543, "args": { "sessionId": sessionId, "page": "0x4age111" } },
+        ],
+        "weird-names": [
+           { "cat": "__metadata", "name": "process_name", "ph": "M", "pid": 1, "tid": 2, "ts": 0, "args": { "name": "Renderer" } },
+           { "cat": "__metadata", "name": "thread_name", "ph": "M", "pid": 1, "tid": 2, "ts": 0, "args": { "name": "CrRendererMain" } },
+           { "cat": "disabled-by-default-devtools.timeline", "ph": "I", "name": "TracingStartedInPage", "pid": 1, "tid": 2, "ts": 100000, "tts": 606543, "args": { "sessionId": sessionId, "page": "0x4age111" } },
+           { "cat": "__metadata", "name": "process_name", "ph": "M", "pid": 3, "tid": 4, "ts": 0, "args": { "name": "Foo" } },
+           { "cat": "__metadata", "name": "thread_name", "ph": "M", "pid": 3, "tid": 4, "ts": 0, "args": { "name": "Bar" } },
+           { "cat": "disabled-by-default-devtools.timeline", "ph": "I", "name": "TracingStartedInBrowser", "pid": 3, "tid": 4, "ts": 100000, "tts": 606543, "args": { "frameTreeNodeId": 1234 } },
+        ]
+    };
+    for (var testCase of Object.keys(testCases)) {
+        var model = InspectorTest.createTracingModel();
+        model.setEventsForTest(testCases[testCase]);
+        var browserMain = WebInspector.TracingModel.browserMainThread(model);
+        if (!browserMain) {
+            InspectorTest.addResult(`${testCase} failed, no browser main thread found`);
+            continue;
+        }
+        InspectorTest.addResult(`${testCase}: main browser thread is ${browserMain.name()} (#${browserMain.id()})`);
+    }
+    InspectorTest.completeTest();
+}
+
+</script>
+</head>
+<body onload="runTest()">
+<p>Test that tracing model correctly finds the main browser thread in the trace.
+</p>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/media/overflow-menu.js b/third_party/WebKit/LayoutTests/media/overflow-menu.js
index 2b047c998..7f1b989 100644
--- a/third_party/WebKit/LayoutTests/media/overflow-menu.js
+++ b/third_party/WebKit/LayoutTests/media/overflow-menu.js
@@ -7,7 +7,7 @@
     "-internal-media-controls-cast-button",
     "-webkit-media-controls-toggle-closed-captions-button"];
 //  PseudoID for the overflow button
-var menuID = "-internal-overflow-menu-button";
+var menuID = "-internal-media-controls-overflow-button";
 //  PseudoID for the overflow list
 var listID = "-internal-media-controls-overflow-menu-list";
 
@@ -33,4 +33,3 @@
 
 // Default text within the overflow menu
 var overflowMenuText = ["Play", "Fullscreen", "Download", "Mute", "Cast", "Captions"];
-
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/box-shadow-add-repaint-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/box-shadow-add-repaint-expected.txt
index 9c13d858..8ec7014f 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/box-shadow-add-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/box-shadow-add-repaint-expected.txt
@@ -10,7 +10,7 @@
       "paintInvalidations": [
         {
           "object": "LayoutBlockFlow DIV id='test'",
-          "rect": [8, 8, 110, 110],
+          "rect": [7, 7, 112, 112],
           "reason": "style change"
         }
       ]
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/box-shadow-change-repaint-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/box-shadow-change-repaint-expected.txt
index 999c7fc..39056a8 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/box-shadow-change-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/box-shadow-change-repaint-expected.txt
@@ -10,7 +10,7 @@
       "paintInvalidations": [
         {
           "object": "LayoutBlockFlow DIV id='test'",
-          "rect": [8, 8, 120, 120],
+          "rect": [7, 7, 122, 122],
           "reason": "style change"
         }
       ]
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/scrolled-iframe-scrollbar-change-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/scrolled-iframe-scrollbar-change-expected.txt
index c09e9b57..ae41289 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/scrolled-iframe-scrollbar-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/scrolled-iframe-scrollbar-change-expected.txt
@@ -6,6 +6,10 @@
     },
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "style change"
     },
     {
@@ -23,10 +27,6 @@
     {
       "object": "LayoutBlockFlow (positioned) DIV id='overlay'",
       "reason": "layoutObject insertion"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt
index e460773d..8f194db3 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt
@@ -86,6 +86,10 @@
     },
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "location change"
     },
     {
@@ -95,10 +99,6 @@
     {
       "object": "LayoutBlockFlow BODY",
       "reason": "location change"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/svg/deep-nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/svg/deep-nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt
index 6eea390..3c1302f4 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/svg/deep-nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/svg/deep-nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt
@@ -21,6 +21,14 @@
       "reason": "scroll"
     },
     {
+      "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
       "object": "LayoutBlockFlow HTML",
       "reason": "location change"
     },
@@ -42,14 +50,6 @@
     },
     {
       "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "LayoutView #document",
       "reason": "location change"
     },
     {
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/svg/deep-nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/svg/deep-nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt
index 6eea390..3c1302f4 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/svg/deep-nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/svg/deep-nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt
@@ -21,6 +21,14 @@
       "reason": "scroll"
     },
     {
+      "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
       "object": "LayoutBlockFlow HTML",
       "reason": "location change"
     },
@@ -42,14 +50,6 @@
     },
     {
       "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "LayoutView #document",
       "reason": "location change"
     },
     {
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/svg/hairline-stroke-squarecap-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/svg/hairline-stroke-squarecap-expected.txt
new file mode 100644
index 0000000..cc5dd13c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/svg/hairline-stroke-squarecap-expected.txt
@@ -0,0 +1,45 @@
+{
+  "name": "Content Root Layer",
+  "bounds": [800, 600],
+  "children": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "paintInvalidations": [
+        {
+          "object": "LayoutSVGPath path id='path'",
+          "rect": [199, 199, 103, 103],
+          "reason": "full"
+        },
+        {
+          "object": "LayoutSVGPath path id='path'",
+          "rect": [99, 99, 102, 102],
+          "reason": "full"
+        },
+        {
+          "object": "LayoutSVGRoot svg",
+          "rect": [99, 99, 102, 102],
+          "reason": "bounds change"
+        },
+        {
+          "object": "LayoutSVGRoot svg",
+          "rect": [200, 200, 101, 101],
+          "reason": "bounds change"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutSVGRoot svg",
+      "reason": "bounds change"
+    },
+    {
+      "object": "LayoutSVGPath path id='path'",
+      "reason": "full"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/svg/hairline-stroke-squarecap.svg b/third_party/WebKit/LayoutTests/paint/invalidation/svg/hairline-stroke-squarecap.svg
new file mode 100644
index 0000000..bf5a50a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/svg/hairline-stroke-squarecap.svg
@@ -0,0 +1,11 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" onload="runRepaintTest()">
+<script xlink:href="../resources/text-based-repaint.js"></script>
+
+<path id="path" fill="none" stroke="green" stroke-width="0.8" stroke-linecap="square" d="M 100 100 h100 v100 h-100 z"/>
+
+<script>
+    function repaintTest() {
+        document.getElementById('path').setAttribute('transform', 'translate(100.5, 100.5)');
+    }
+</script>
+</svg>
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt
index 02dab6c..ffbf191 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt
@@ -108,6 +108,14 @@
       "reason": "scroll"
     },
     {
+      "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
       "object": "LayoutBlockFlow HTML",
       "reason": "location change"
     },
@@ -129,14 +137,6 @@
     },
     {
       "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "LayoutView #document",
       "reason": "location change"
     },
     {
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt
index 02dab6c..ffbf191 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt
@@ -108,6 +108,14 @@
       "reason": "scroll"
     },
     {
+      "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
       "object": "LayoutBlockFlow HTML",
       "reason": "location change"
     },
@@ -129,14 +137,6 @@
     },
     {
       "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "LayoutView #document",
       "reason": "location change"
     },
     {
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/transform-replaced-shadows-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/transform-replaced-shadows-expected.txt
index 6edfb4b..b0dece1 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/transform-replaced-shadows-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/transform-replaced-shadows-expected.txt
@@ -10,7 +10,7 @@
       "paintInvalidations": [
         {
           "object": "LayoutImage IMG id='box' class='smaller'",
-          "rect": [-12, 28, 280, 280],
+          "rect": [-10, 28, 276, 278],
           "reason": "subtree"
         }
       ]
diff --git a/third_party/WebKit/LayoutTests/platform/android/compositing/img-layer-object-fit-expected.png b/third_party/WebKit/LayoutTests/platform/android/compositing/img-layer-object-fit-expected.png
new file mode 100644
index 0000000..0f664d90
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/compositing/img-layer-object-fit-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/compositing/masks/masked-ancestor-expected.png b/third_party/WebKit/LayoutTests/platform/android/compositing/masks/masked-ancestor-expected.png
new file mode 100644
index 0000000..ce2c0e82
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/compositing/masks/masked-ancestor-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/borders/border-radius-different-width-001-double-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/borders/border-radius-different-width-001-double-expected.png
new file mode 100644
index 0000000..103d4e3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/borders/border-radius-different-width-001-double-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/borders/webkit-border-radius-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/borders/webkit-border-radius-expected.png
new file mode 100644
index 0000000..2c885e6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/borders/webkit-border-radius-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/images/color-profile-background-clip-text-expected.txt b/third_party/WebKit/LayoutTests/platform/android/fast/images/color-profile-background-clip-text-expected.txt
new file mode 100644
index 0000000..10f9a06
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/images/color-profile-background-clip-text-expected.txt
@@ -0,0 +1,3 @@
+▅▅▅▅
+
+▅▅▅▅
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/images/color-profile-image-profile-match-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/images/color-profile-image-profile-match-expected.png
new file mode 100644
index 0000000..ed764d06
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/images/color-profile-image-profile-match-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/images/jpeg-yuv-progressive-image-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/images/jpeg-yuv-progressive-image-expected.png
new file mode 100644
index 0000000..23438b0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/images/jpeg-yuv-progressive-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/caret-subpixel-expected.txt b/third_party/WebKit/LayoutTests/platform/android/paint/invalidation/caret-subpixel-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/paint/invalidation/caret-subpixel-expected.txt
rename to third_party/WebKit/LayoutTests/platform/android/paint/invalidation/caret-subpixel-expected.txt
diff --git a/third_party/WebKit/LayoutTests/platform/android/paint/invalidation/scrolled-iframe-scrollbar-change-expected.txt b/third_party/WebKit/LayoutTests/platform/android/paint/invalidation/scrolled-iframe-scrollbar-change-expected.txt
new file mode 100644
index 0000000..c09e9b57
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/paint/invalidation/scrolled-iframe-scrollbar-change-expected.txt
@@ -0,0 +1,33 @@
+{
+  "objectPaintInvalidations": [
+    {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutBlockFlow HTML",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutBlockFlow BODY class='noScroll'",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutBlockFlow DIV id='container'",
+      "reason": "incremental"
+    },
+    {
+      "object": "LayoutBlockFlow (positioned) DIV id='overlay'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutView #document",
+      "reason": "scroll"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/android/svg/css/text-gradient-shadow-expected.txt b/third_party/WebKit/LayoutTests/platform/android/svg/css/text-gradient-shadow-expected.txt
new file mode 100644
index 0000000..a861e517
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/svg/css/text-gradient-shadow-expected.txt
@@ -0,0 +1,11 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x600
+  LayoutSVGRoot {svg} at (200,20) size 439x265
+    LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
+      LayoutSVGResourceLinearGradient {linearGradient} [id="gradient"] [gradientUnits=objectBoundingBox] [start=(0,0)] [end=(1,0)]
+        LayoutSVGGradientStop {stop} [offset=0.00] [color=#FF0000]
+        LayoutSVGGradientStop {stop} [offset=1.00] [color=#0000FF]
+    LayoutSVGText {text} at (200,20) size 399x225 contains 1 chunk(s)
+      LayoutSVGInlineText {#text} at (0,0) size 399x225
+        chunk 1 text run 1 at (200.00,200.00) startOffset 0 endOffset 3 width 399.00: "SVG"
diff --git a/third_party/WebKit/LayoutTests/platform/android/svg/css/text-shadow-multiple-expected.txt b/third_party/WebKit/LayoutTests/platform/android/svg/css/text-shadow-multiple-expected.txt
new file mode 100644
index 0000000..30527e7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/svg/css/text-shadow-multiple-expected.txt
@@ -0,0 +1,87 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x414
+  LayoutBlockFlow {html} at (0,0) size 800x414
+    LayoutBlockFlow {body} at (0,16) size 800x398
+      LayoutBlockFlow {p} at (0,0) size 800x20
+        LayoutText {#text} at (0,0) size 425x19
+          text run at (0,0) width 425: "The first two texts should look identical, as there is no shadow applied."
+      LayoutBlockFlow (anonymous) at (0,36) size 800x155
+        LayoutSVGRoot {svg} at (20,122) size 720x58
+          LayoutSVGText {text} at (20,20) size 720x58 contains 1 chunk(s)
+            LayoutSVGTSpan {tspan} at (0,0) size 96x57
+              LayoutSVGInlineText {#text} at (0,0) size 96x57
+                chunk 1 text run 1 at (20.00,66.80) startOffset 0 endOffset 4 width 96.00: "This"
+            LayoutSVGInlineText {#text} at (96,0) size 14x57
+              chunk 1 text run 1 at (116.00,66.80) startOffset 0 endOffset 1 width 14.00: " "
+            LayoutSVGTSpan {tspan} at (0,0) size 80x57
+              LayoutSVGInlineText {#text} at (110,0) size 80x57
+                chunk 1 text run 1 at (130.00,66.80) startOffset 0 endOffset 4 width 80.00: "text"
+            LayoutSVGInlineText {#text} at (190,0) size 14x57
+              chunk 1 text run 1 at (210.00,66.80) startOffset 0 endOffset 1 width 14.00: " "
+            LayoutSVGTSpan {tspan} at (0,0) size 305x57
+              LayoutSVGInlineText {#text} at (204,0) size 305x57
+                chunk 1 text run 1 at (224.00,66.80) startOffset 0 endOffset 14 width 305.00: "casts multiple"
+            LayoutSVGInlineText {#text} at (509,0) size 211x57
+              chunk 1 text run 1 at (529.00,66.80) startOffset 0 endOffset 1 width 14.00: " "
+              chunk 1 text run 1 at (543.00,66.80) startOffset 0 endOffset 7 width 197.00: "shadows"
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {p} at (0,207) size 800x20
+        LayoutText {#text} at (0,0) size 530x19
+          text run at (0,0) width 530: "The next two texts have subtle differences, as the stroke/fill is painted seperated in SVG."
+      LayoutBlockFlow (anonymous) at (0,243) size 800x155
+        LayoutSVGRoot {svg} at (0,312) size 747x91
+          LayoutSVGText {text} at (20,20) size 720x58 contains 1 chunk(s)
+            LayoutSVGTSpan {tspan} at (0,0) size 96x57
+              LayoutSVGInlineText {#text} at (0,0) size 96x57
+                chunk 1 text run 1 at (20.00,66.80) startOffset 0 endOffset 4 width 96.00: "This"
+            LayoutSVGInlineText {#text} at (96,0) size 14x57
+              chunk 1 text run 1 at (116.00,66.80) startOffset 0 endOffset 1 width 14.00: " "
+            LayoutSVGTSpan {tspan} at (0,0) size 80x57
+              LayoutSVGInlineText {#text} at (110,0) size 80x57
+                chunk 1 text run 1 at (130.00,66.80) startOffset 0 endOffset 4 width 80.00: "text"
+            LayoutSVGInlineText {#text} at (190,0) size 14x57
+              chunk 1 text run 1 at (210.00,66.80) startOffset 0 endOffset 1 width 14.00: " "
+            LayoutSVGTSpan {tspan} at (0,0) size 305x57
+              LayoutSVGInlineText {#text} at (204,0) size 305x57
+                chunk 1 text run 1 at (224.00,66.80) startOffset 0 endOffset 14 width 305.00: "casts multiple"
+            LayoutSVGInlineText {#text} at (509,0) size 211x57
+              chunk 1 text run 1 at (529.00,66.80) startOffset 0 endOffset 1 width 14.00: " "
+              chunk 1 text run 1 at (543.00,66.80) startOffset 0 endOffset 7 width 197.00: "shadows"
+        LayoutText {#text} at (0,0) size 0x0
+layer at (20,52) size 720x59
+  LayoutBlockFlow (positioned) {div} at (20,52) size 720x59
+    LayoutInline {span} at (0,0) size 96x57 [textStrokeWidth=1.00]
+      LayoutText {#text} at (0,1) size 96x57
+        text run at (0,1) width 96: "This"
+    LayoutText {#text} at (96,1) size 14x57
+      text run at (96,1) width 14: " "
+    LayoutInline {span} at (0,0) size 80x57 [textFillColor=#FFFFFF] [textStrokeWidth=1.00]
+      LayoutText {#text} at (110,1) size 80x57
+        text run at (110,1) width 80: "text"
+    LayoutText {#text} at (190,1) size 14x57
+      text run at (190,1) width 14: " "
+    LayoutInline {span} at (0,0) size 305x57
+      LayoutText {#text} at (204,1) size 305x57
+        text run at (204,1) width 305: "casts multiple"
+    LayoutText {#text} at (509,1) size 211x57
+      text run at (509,1) width 14: " "
+      text run at (523,1) width 197: "shadows"
+layer at (20,259) size 720x59
+  LayoutBlockFlow (positioned) {div} at (20,259) size 720x59
+    LayoutInline {span} at (0,0) size 96x57 [textStrokeWidth=1.00]
+      LayoutText {#text} at (0,1) size 96x57
+        text run at (0,1) width 96: "This"
+    LayoutText {#text} at (96,1) size 14x57
+      text run at (96,1) width 14: " "
+    LayoutInline {span} at (0,0) size 80x57 [textFillColor=#FFFFFF] [textStrokeWidth=1.00]
+      LayoutText {#text} at (110,1) size 80x57
+        text run at (110,1) width 80: "text"
+    LayoutText {#text} at (190,1) size 14x57
+      text run at (190,1) width 14: " "
+    LayoutInline {span} at (0,0) size 305x57
+      LayoutText {#text} at (204,1) size 305x57
+        text run at (204,1) width 305: "casts multiple"
+    LayoutText {#text} at (509,1) size 211x57
+      text run at (509,1) width 14: " "
+      text run at (523,1) width 197: "shadows"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/iframes/invisible-nested-iframe-show-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/compositing/iframes/invisible-nested-iframe-show-expected.txt
index 21fa972..6c009c83 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/iframes/invisible-nested-iframe-show-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/iframes/invisible-nested-iframe-show-expected.txt
@@ -11,13 +11,13 @@
       "children": [
         {
           "name": "LayoutIFrame IFRAME",
-          "position": [-12, -12],
-          "bounds": [370, 220],
+          "position": [-11, -11],
+          "bounds": [368, 218],
           "drawsContent": true,
           "children": [
             {
               "name": "Frame Overflow Controls Host Layer",
-              "position": [35, 35],
+              "position": [34, 34],
               "bounds": [300, 150],
               "children": [
                 {
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/img-layer-object-fit-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/img-layer-object-fit-expected.png
index 0f664d90..0f98aad 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/img-layer-object-fit-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/img-layer-object-fit-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/masks/masked-ancestor-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/masks/masked-ancestor-expected.png
index ce2c0e82..809c0e4 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/masks/masked-ancestor-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/masks/masked-ancestor-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-side-reduction-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-side-reduction-expected.png
index b85cdf0f..77e52df1 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-side-reduction-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-side-reduction-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-mask-video-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-mask-video-shadow-expected.png
index 757dc64..fe36d178 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-mask-video-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-mask-video-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/inline-mask-overlay-image-outset-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/inline-mask-overlay-image-outset-expected.png
index d86da4e..454f212 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/inline-mask-overlay-image-outset-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/inline-mask-overlay-image-outset-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/inline-mask-overlay-image-outset-vertical-rl-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/inline-mask-overlay-image-outset-vertical-rl-expected.png
index 5301c05..d6dfd99 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/inline-mask-overlay-image-outset-vertical-rl-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/inline-mask-overlay-image-outset-vertical-rl-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
index 32d3770..32e42c5 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-expected.png
index 8b5411c..4f76bae 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
index 9714eab..aae43f1 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
index 853a1c3f..b15258f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
index adbd3b5..7037fe4 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
index 75c079b..09e0a08 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/input-appearance-height-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/input-appearance-height-expected.png
index fb8c5a3d..67045461 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/input-appearance-height-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/input-appearance-height-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select/menulist-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select/menulist-appearance-basic-expected.png
index fe30a20..78158860 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select/menulist-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select/menulist-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select/menulist-appearance-basic-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select/menulist-appearance-basic-expected.txt
index 1f99f133..708312da 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select/menulist-appearance-basic-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select/menulist-appearance-basic-expected.txt
@@ -87,7 +87,13 @@
             text run at (4,1) width 33: "foo"
       LayoutText {#text} at (187,186) size 4x19
         text run at (187,186) width 4: " "
-      LayoutBR {BR} at (191,186) size 0x19
+      LayoutMenuList {SELECT} at (195,186) size 126x20 [bgcolor=#DDDDDD] [border: (1px solid #A9A9A9)]
+        LayoutBlockFlow (anonymous) at (1,1) size 124x18
+          LayoutText (anonymous) at (4,1) size 102x16
+            text run at (4,1) width 102: "September 2016"
+      LayoutText {#text} at (325,186) size 4x19
+        text run at (325,186) width 4: " "
+      LayoutBR {BR} at (329,186) size 0x19
       LayoutMenuList {SELECT} at (6,230) size 63x27 [bgcolor=#DDDDDD] [border: (1px solid #A9A9A9)]
         LayoutBlockFlow (anonymous) at (1,1) size 61x26
           LayoutText (anonymous) at (6,1) size 28x23
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-background-clip-text-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-background-clip-text-expected.png
index 2a44ca3..f629c6b9 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-background-clip-text-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-background-clip-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-background-image-cover-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-background-image-cover-expected.png
index cb71a26b..12c34ff9 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-background-image-cover-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-background-image-cover-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-background-image-repeat-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-background-image-repeat-expected.png
index 2819d82..3d275385 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-background-image-repeat-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-background-image-repeat-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-background-image-space-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-background-image-space-expected.png
index 2f46faf9..9943a7d1 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-background-image-space-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-background-image-space-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-border-radius-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-border-radius-expected.png
index 8b1a3f9..623c4b7 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-border-radius-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-border-radius-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-image-canvas-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-image-canvas-expected.png
index 55b70a9..071d4fb 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-image-canvas-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-image-canvas-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-image-canvas-pattern-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-image-canvas-pattern-expected.png
index dd3d1857..937f739 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-image-canvas-pattern-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-image-canvas-pattern-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-image-filter-all-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-image-filter-all-expected.png
index 248ab15..72088c2 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-image-filter-all-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-image-filter-all-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-mask-image-svg-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-mask-image-svg-expected.png
index 2360f067..845b964 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-mask-image-svg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-mask-image-svg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-object-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-object-expected.png
index 2f11577..7fe9772 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-object-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-object-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/text/emoji-web-font-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/text/emoji-web-font-expected.png
index 0de8430..d0ced77e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/text/emoji-web-font-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/text/emoji-web-font-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png b/third_party/WebKit/LayoutTests/platform/linux/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
index ce087b8..9a997a4 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/color-profile-video-poster-image-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/color-profile-video-poster-image-expected.png
index efef52e..9f446dd 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/media/color-profile-video-poster-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/media/color-profile-video-poster-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/video-poster-scale-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/video-poster-scale-expected.png
index 4e0d310..0a10bdc0 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/media/video-poster-scale-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/media/video-poster-scale-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/video-zoom-controls-expected.png
index 3485b799..b95bf32 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/media/video-zoom-controls-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/media/video-zoom-controls-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/4776765-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/4776765-expected.txt
index eba788b..be5fc6e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/4776765-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/4776765-expected.txt
@@ -25,6 +25,16 @@
         },
         {
           "object": "LayoutBR BR",
+          "rect": [7, 83, 3, 21],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBR BR",
+          "rect": [7, 83, 3, 21],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBR BR",
           "rect": [7, 63, 3, 21],
           "reason": "invalidate paint rectangle"
         }
@@ -33,6 +43,14 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBlockFlow DIV",
       "reason": "outline"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/caret-with-composited-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/caret-with-composited-scroll-expected.txt
index 0b45783..d8d9c51 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/caret-with-composited-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/caret-with-composited-scroll-expected.txt
@@ -39,6 +39,16 @@
                       "object": "LayoutBlockFlow DIV id='inner-editor'",
                       "rect": [2, 1002, 3, 18],
                       "reason": "invalidate paint rectangle"
+                    },
+                    {
+                      "object": "LayoutBlockFlow DIV id='inner-editor'",
+                      "rect": [2, 1002, 3, 18],
+                      "reason": "invalidate paint rectangle"
+                    },
+                    {
+                      "object": "LayoutBlockFlow DIV id='inner-editor'",
+                      "rect": [2, 1002, 3, 18],
+                      "reason": "invalidate paint rectangle"
                     }
                   ]
                 }
@@ -69,6 +79,10 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutTextControl INPUT id='text'",
       "reason": "subtree"
     },
@@ -79,6 +93,10 @@
     {
       "object": "Caret",
       "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
index 40f794a..1cc6316 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
@@ -71,6 +71,14 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "style change"
     },
     {
@@ -92,14 +100,6 @@
     {
       "object": "InlineTextBox 'test1'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/delete-into-nested-block-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/delete-into-nested-block-expected.txt
index 81a9c37..1524af3 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/delete-into-nested-block-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/delete-into-nested-block-expected.txt
@@ -57,6 +57,16 @@
           "object": "LayoutText #text",
           "rect": [7, 126, 3, 22],
           "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [7, 126, 3, 22],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [7, 126, 3, 22],
+          "reason": "invalidate paint rectangle"
         }
       ]
     }
@@ -103,6 +113,10 @@
       "reason": "layoutObject removal"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBlockFlow DIV",
       "reason": "outline"
     },
@@ -119,6 +133,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutText #text",
       "reason": "layoutObject insertion"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/inline-outline-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/inline-outline-repaint-expected.txt
index f00316f..9930e77 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/inline-outline-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/inline-outline-repaint-expected.txt
@@ -27,6 +27,16 @@
           "object": "LayoutText #text",
           "rect": [43, 174, 3, 22],
           "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [43, 174, 3, 22],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [43, 174, 3, 22],
+          "reason": "invalidate paint rectangle"
         }
       ]
     }
@@ -37,6 +47,10 @@
       "reason": "layoutObject removal"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBlockFlow DIV",
       "reason": "forced by layout"
     },
@@ -49,6 +63,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutInline SPAN id='test'",
       "reason": "forced by layout"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
index c513249..926b8ea 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
@@ -80,12 +80,12 @@
   ],
   "objectPaintInvalidations": [
     {
-      "object": "LayoutTextControl INPUT id='root'",
-      "reason": "subtree"
-    },
-    {
       "object": "Caret",
       "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "LayoutTextControl INPUT id='root'",
+      "reason": "subtree"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
index cf039665..9d07cff7 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
@@ -39,6 +39,16 @@
               "object": "LayoutText #text",
               "rect": [60, 4, 3, 16],
               "reason": "invalidate paint rectangle"
+            },
+            {
+              "object": "LayoutText #text",
+              "rect": [60, 4, 3, 16],
+              "reason": "invalidate paint rectangle"
+            },
+            {
+              "object": "LayoutText #text",
+              "rect": [60, 4, 3, 16],
+              "reason": "invalidate paint rectangle"
             }
           ]
         }
@@ -47,6 +57,10 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutTextControl INPUT id='root'",
       "reason": "subtree"
     },
@@ -67,6 +81,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutText #text",
       "reason": "subtree"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/line-flow-with-floats-2-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/line-flow-with-floats-2-expected.txt
index 509cf12a..367df1f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/line-flow-with-floats-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/line-flow-with-floats-2-expected.txt
@@ -133,6 +133,10 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
       "object": "LayoutBlockFlow HTML",
       "reason": "forced by layout"
     },
@@ -387,10 +391,6 @@
     {
       "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/line-flow-with-floats-8-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/line-flow-with-floats-8-expected.txt
index 09598361..d0c8fc8 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/line-flow-with-floats-8-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/line-flow-with-floats-8-expected.txt
@@ -117,6 +117,10 @@
       "reason": "layoutObject removal"
     },
     {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
       "object": "LayoutBlockFlow HTML",
       "reason": "forced by layout"
     },
@@ -355,10 +359,6 @@
     {
       "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/overflow-scroll-body-appear-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/overflow-scroll-body-appear-expected.txt
index 0d733d16..7b67112 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/overflow-scroll-body-appear-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/overflow-scroll-body-appear-expected.txt
@@ -69,6 +69,14 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "style change"
     },
     {
@@ -122,14 +130,6 @@
     {
       "object": "InlineTextBox '.'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
index caf3769..bd7c8bb0 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
@@ -73,6 +73,14 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "HorizontalScrollbar",
+      "reason": "scroll"
+    },
+    {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
       "object": "LayoutView #document",
       "reason": "subtree"
     },
@@ -95,14 +103,6 @@
     {
       "object": "InlineTextBox 'scroll me'",
       "reason": "subtree"
-    },
-    {
-      "object": "HorizontalScrollbar",
-      "reason": "scroll"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/selection-after-delete-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/selection-after-delete-expected.txt
index f96b17e7..705bdb43 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/selection-after-delete-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/selection-after-delete-expected.txt
@@ -22,6 +22,16 @@
           "object": "LayoutBR BR",
           "rect": [38, 78, 3, 21],
           "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBR BR",
+          "rect": [38, 78, 3, 21],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBR BR",
+          "rect": [38, 78, 3, 21],
+          "reason": "invalidate paint rectangle"
         }
       ]
     }
@@ -32,6 +42,10 @@
       "reason": "layoutObject removal"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBlockFlow DIV id='test'",
       "reason": "forced by layout"
     },
@@ -44,6 +58,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBR BR",
       "reason": "forced by layout"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt
index 9b6e9c6..3ca55d73 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt
@@ -86,6 +86,10 @@
     },
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "location change"
     },
     {
@@ -95,10 +99,6 @@
     {
       "object": "LayoutBlockFlow BODY",
       "reason": "location change"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/animated-path-inside-transformed-html-expected.png b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/animated-path-inside-transformed-html-expected.png
index 8a7396d..e3185163 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/animated-path-inside-transformed-html-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/animated-path-inside-transformed-html-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/text-match-document-change-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/text-match-document-change-expected.txt
index e6eb689..70f4942e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/text-match-document-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/text-match-document-change-expected.txt
@@ -42,6 +42,10 @@
       "reason": "layoutObject removal"
     },
     {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
       "object": "LayoutBlockFlow HTML",
       "reason": "forced by layout"
     },
@@ -60,10 +64,6 @@
     {
       "object": "InlineTextBox 'After change'",
       "reason": "layoutObject insertion"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/window-resize-vertical-writing-mode-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
index da7216ee..327dde1 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
@@ -65,6 +65,10 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "bounds change"
     },
     {
@@ -134,10 +138,6 @@
     {
       "object": "InlineTextBox 'NNNN'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
@@ -203,6 +203,10 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "bounds change"
     },
     {
@@ -268,10 +272,6 @@
     {
       "object": "InlineTextBox 'NNNN'",
       "reason": "bounds change"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
@@ -341,6 +341,10 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "bounds change"
     },
     {
@@ -378,10 +382,6 @@
     {
       "object": "InlineTextBox 'NNNN'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/animate-elem-30-t-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/animate-elem-30-t-expected.png
index 8b29c39..af0b635b 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/animate-elem-30-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/animate-elem-30-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/animate-elem-39-t-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/animate-elem-39-t-expected.png
index 6709f94..a593249 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/animate-elem-39-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/animate-elem-39-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/animate-elem-40-t-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/animate-elem-40-t-expected.png
index ae95f3e7..fe62ac4 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/animate-elem-40-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/animate-elem-40-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/coords-viewattr-02-b-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/coords-viewattr-02-b-expected.png
index 88db620..61d87a5 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/coords-viewattr-02-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/coords-viewattr-02-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/struct-image-02-b-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/struct-image-02-b-expected.png
index c25c8c9..3ab06b8 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/struct-image-02-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/struct-image-02-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/struct-image-06-t-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/struct-image-06-t-expected.png
index b5c52132..1251d90 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/struct-image-06-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/struct-image-06-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/struct-image-08-t-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/struct-image-08-t-expected.png
index 03c2bfb..132a2f78 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/struct-image-08-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/struct-image-08-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/struct-image-10-t-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/struct-image-10-t-expected.png
index 31bb338..e278df0 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/struct-image-10-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/struct-image-10-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/struct-symbol-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/struct-symbol-01-b-expected.png
index 110f5cd0b..ab65d390 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/struct-symbol-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/struct-symbol-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/carto.net/scrollbar-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/carto.net/scrollbar-expected.png
index 010f3b0..8a63b0c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/carto.net/scrollbar-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/carto.net/scrollbar-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/carto.net/selectionlist-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/carto.net/selectionlist-expected.png
index d55b2346..5afc2e1 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/carto.net/selectionlist-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/carto.net/selectionlist-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/css/text-gradient-shadow-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/css/text-gradient-shadow-expected.txt
index a861e517..a77f2e55 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/css/text-gradient-shadow-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/css/text-gradient-shadow-expected.txt
@@ -1,7 +1,7 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
 layer at (0,0) size 800x600
-  LayoutSVGRoot {svg} at (200,20) size 439x265
+  LayoutSVGRoot {svg} at (200,20) size 438x264
     LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
       LayoutSVGResourceLinearGradient {linearGradient} [id="gradient"] [gradientUnits=objectBoundingBox] [start=(0,0)] [end=(1,0)]
         LayoutSVGGradientStop {stop} [offset=0.00] [color=#FF0000]
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/css/text-shadow-multiple-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/css/text-shadow-multiple-expected.txt
index 30527e7..f261d344 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/css/text-shadow-multiple-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/css/text-shadow-multiple-expected.txt
@@ -30,7 +30,7 @@
         LayoutText {#text} at (0,0) size 530x19
           text run at (0,0) width 530: "The next two texts have subtle differences, as the stroke/fill is painted seperated in SVG."
       LayoutBlockFlow (anonymous) at (0,243) size 800x155
-        LayoutSVGRoot {svg} at (0,312) size 747x91
+        LayoutSVGRoot {svg} at (0,311) size 747x94
           LayoutSVGText {text} at (20,20) size 720x58 contains 1 chunk(s)
             LayoutSVGTSpan {tspan} at (0,0) size 96x57
               LayoutSVGInlineText {#text} at (0,0) size 96x57
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/createImageElement2-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/createImageElement2-expected.png
index d02ffb2..f488ada 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/createImageElement2-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/createImageElement2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/image-parent-translation-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/image-parent-translation-expected.png
index 246454a3..d91f99d 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/image-parent-translation-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/image-parent-translation-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/image-small-width-height-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/image-small-width-height-expected.png
index 4df70e2..91c6be4 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/image-small-width-height-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/image-small-width-height-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/pointer-events-image-css-transform-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/pointer-events-image-css-transform-expected.png
index d9449ee4..554ac86 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/pointer-events-image-css-transform-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/pointer-events-image-css-transform-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/pointer-events-image-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/pointer-events-image-expected.png
index d9449ee4..554ac86 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/pointer-events-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/pointer-events-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/text-image-opacity-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/text-image-opacity-expected.png
index d986b76..8026c05 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/text-image-opacity-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/text-image-opacity-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/perf/004-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/perf/004-expected.png
index 809f01c..c8693421 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/perf/004-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/perf/004-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 2d9e85a..365566b 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-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 2fd91c1..a7bc83fa 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/tables/mozilla/bugs/bug101674-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug101674-expected.png
index 11c710d..3d26fa249 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug101674-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug101674-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug11026-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug11026-expected.png
index 9edbc4e..4aade58 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug11026-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug11026-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug1188-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug1188-expected.png
index f9d2549..21a63c2 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug1188-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug1188-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug1296-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug1296-expected.png
index c414416..d68e041 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug1296-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug1296-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug1430-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug1430-expected.png
index e414d5b..93d9563 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug1430-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug1430-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug2981-2-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug2981-2-expected.png
index bff4504..d60c108 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug2981-2-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug2981-2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug4093-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug4093-expected.png
index 37308ab..afca1b6 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug4093-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug4093-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug4284-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug4284-expected.png
index 174d8a4..d1fd204 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug4284-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug4284-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug4427-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug4427-expected.png
index e28d35c..69dc867 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug4427-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug4427-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug56563-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug56563-expected.png
index 028bde2..2e7b2e3 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug56563-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug56563-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug625-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug625-expected.png
index 48467eb..7a45644 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug625-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug625-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug6404-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug6404-expected.png
index 39c64c6e..cfad86a 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug6404-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug6404-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/core/bloomberg-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/core/bloomberg-expected.png
index b4d0a27..c2f52e9 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/core/bloomberg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/core/bloomberg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/core/col_widths_auto_autoFix-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/core/col_widths_auto_autoFix-expected.png
index 56da4c2..1280e83 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/core/col_widths_auto_autoFix-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/core/col_widths_auto_autoFix-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/core/misc-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/core/misc-expected.png
index f12ee875..e8e54fe 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/core/misc-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/core/misc-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/other/cell_widths-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/other/cell_widths-expected.png
index 59ffa9f..adf1d64 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/other/cell_widths-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/other/cell_widths-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla_expected_failures/bugs/bug6933-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla_expected_failures/bugs/bug6933-expected.png
index d1cd6368..1afee98 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla_expected_failures/bugs/bug6933-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla_expected_failures/bugs/bug6933-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/input-appearance-height-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/input-appearance-height-expected.png
index ff12e79..6371d5a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/input-appearance-height-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/input-appearance-height-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/select/menulist-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/select/menulist-appearance-basic-expected.png
index 0f690f79..b98822b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/select/menulist-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/select/menulist-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/select/menulist-appearance-basic-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/select/menulist-appearance-basic-expected.txt
index 330b364..abf5fdf 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/select/menulist-appearance-basic-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/select/menulist-appearance-basic-expected.txt
@@ -87,7 +87,13 @@
             text run at (8,1) width 36: "foo"
       LayoutText {#text} at (205,163) size 4x18
         text run at (205,163) width 4: " "
-      LayoutBR {BR} at (209,163) size 0x18
+      LayoutMenuList {SELECT} at (213,164) size 110x18 [bgcolor=#F8F8F8] [border: (1px solid #A6A6A6)]
+        LayoutBlockFlow (anonymous) at (1,1) size 108x16
+          LayoutText (anonymous) at (8,1) size 87x13
+            text run at (8,1) width 87: "September 2016"
+      LayoutText {#text} at (327,163) size 4x18
+        text run at (327,163) width 4: " "
+      LayoutBR {BR} at (331,163) size 0x18
       LayoutMenuList {SELECT} at (6,204) size 59x25 [bgcolor=#F8F8F8] [border: (1px solid #A6A6A6)]
         LayoutBlockFlow (anonymous) at (1,1) size 57x23
           LayoutText (anonymous) at (12,1) size 25x19
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/images/color-profile-background-clip-text-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/images/color-profile-background-clip-text-expected.png
deleted file mode 100644
index ca007d5..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/images/color-profile-background-clip-text-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/emoji-web-font-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/emoji-web-font-expected.png
index afb0065..ef95e0cf 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/emoji-web-font-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/emoji-web-font-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
index f8c9704..38a1039 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
index 0fa2451..ec8a0c3 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
@@ -80,12 +80,12 @@
   ],
   "objectPaintInvalidations": [
     {
-      "object": "LayoutTextControl INPUT id='root'",
-      "reason": "subtree"
-    },
-    {
       "object": "Caret",
       "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "LayoutTextControl INPUT id='root'",
+      "reason": "subtree"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/tables/mozilla/bugs/bug1188-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/tables/mozilla/bugs/bug1188-expected.png
index 9804770f..3b18a18b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/tables/mozilla/bugs/bug1188-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/tables/mozilla/bugs/bug1188-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
index b9c3a55..b875d523 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/input-appearance-height-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/input-appearance-height-expected.png
index b6ff0f2d..0d41500b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/input-appearance-height-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/input-appearance-height-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/select/menulist-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/select/menulist-appearance-basic-expected.png
index 67ae39d..9757171 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/select/menulist-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/select/menulist-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/select/menulist-appearance-basic-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/select/menulist-appearance-basic-expected.txt
index 1125f17..68a3095 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/select/menulist-appearance-basic-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/select/menulist-appearance-basic-expected.txt
@@ -87,7 +87,13 @@
             text run at (8,1) width 39: "foo"
       LayoutText {#text} at (212,163) size 4x18
         text run at (212,163) width 4: " "
-      LayoutBR {BR} at (216,163) size 0x18
+      LayoutMenuList {SELECT} at (220,164) size 116x18 [bgcolor=#F8F8F8] [border: (1px solid #A6A6A6)]
+        LayoutBlockFlow (anonymous) at (1,1) size 114x16
+          LayoutText (anonymous) at (8,1) size 93x13
+            text run at (8,1) width 93: "September 2016"
+      LayoutText {#text} at (340,163) size 4x18
+        text run at (340,163) width 4: " "
+      LayoutBR {BR} at (344,163) size 0x18
       LayoutMenuList {SELECT} at (6,204) size 61x25 [bgcolor=#F8F8F8] [border: (1px solid #A6A6A6)]
         LayoutBlockFlow (anonymous) at (1,1) size 59x23
           LayoutText (anonymous) at (12,1) size 27x19
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/images/color-profile-background-clip-text-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/images/color-profile-background-clip-text-expected.png
deleted file mode 100644
index 04aa11d..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/images/color-profile-background-clip-text-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/emoji-web-font-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/emoji-web-font-expected.png
index 3e7808b5..8ac4fbd 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/emoji-web-font-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/emoji-web-font-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
index c2540d5a..308f881 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio-expected.png
index 6b3f736..f01b341 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
index c9535f2a..90b7233 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
@@ -80,12 +80,12 @@
   ],
   "objectPaintInvalidations": [
     {
-      "object": "LayoutTextControl INPUT id='root'",
-      "reason": "subtree"
-    },
-    {
       "object": "Caret",
       "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "LayoutTextControl INPUT id='root'",
+      "reason": "subtree"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
index 967c98b..29b3fc345 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
@@ -39,6 +39,16 @@
               "object": "LayoutText #text",
               "rect": [45, 6, 3, 13],
               "reason": "invalidate paint rectangle"
+            },
+            {
+              "object": "LayoutText #text",
+              "rect": [45, 6, 3, 13],
+              "reason": "invalidate paint rectangle"
+            },
+            {
+              "object": "LayoutText #text",
+              "rect": [45, 6, 3, 13],
+              "reason": "invalidate paint rectangle"
             }
           ]
         }
@@ -47,6 +57,10 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutTextControl INPUT id='root'",
       "reason": "subtree"
     },
@@ -67,6 +81,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutText #text",
       "reason": "subtree"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/textarea-caret-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/textarea-caret-expected.txt
index 5805d97e..964bd06 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/textarea-caret-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/textarea-caret-expected.txt
@@ -42,12 +42,26 @@
           "object": "LayoutText #text",
           "rect": [151, 10, 2, 14],
           "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [151, 10, 2, 14],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [151, 10, 2, 14],
+          "reason": "invalidate paint rectangle"
         }
       ]
     }
   ],
   "objectPaintInvalidations": [
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutTextControl TEXTAREA id='editor'",
       "reason": "subtree"
     },
@@ -80,6 +94,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutText #text",
       "reason": "subtree"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/tables/mozilla/bugs/bug101674-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/tables/mozilla/bugs/bug101674-expected.png
index c420dddc..c5ba522 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/tables/mozilla/bugs/bug101674-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/tables/mozilla/bugs/bug101674-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/tables/mozilla/bugs/bug1188-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/tables/mozilla/bugs/bug1188-expected.png
index f435d93..8c7e192 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/tables/mozilla/bugs/bug1188-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/tables/mozilla/bugs/bug1188-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/tables/mozilla/core/bloomberg-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/tables/mozilla/core/bloomberg-expected.png
index 5e587be9..b4b35a8 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/tables/mozilla/core/bloomberg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/tables/mozilla/core/bloomberg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/tables/mozilla/other/cell_widths-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/tables/mozilla/other/cell_widths-expected.png
index 3295714..217b901 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/tables/mozilla/other/cell_widths-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/tables/mozilla/other/cell_widths-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
index 5a83912..96ee0c1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/masked-ancestor-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/masked-ancestor-expected.png
index 916eeb8d..af8a80b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/masked-ancestor-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/masked-ancestor-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/multiple-masks-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/multiple-masks-expected.png
index 996a5560..65651aa6 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/multiple-masks-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/multiple-masks-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/simple-composited-mask-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/simple-composited-mask-expected.png
index dca2a9ff..2f63d68 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/simple-composited-mask-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/simple-composited-mask-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-gradient-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-gradient-image-expected.png
index ef99ea98..724d88b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-gradient-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-gradient-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-image-color-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-image-color-expected.png
index c3b482e..94b6f3a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-image-color-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-image-color-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-image-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-image-image-expected.png
index aaee3a1..cf29f57 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-image-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-image-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-image-svg-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-image-svg-expected.png
index d95d0ad..5804785 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-image-svg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-image-svg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-tiled-gradient-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-tiled-gradient-expected.png
index f227c55..8f5f98ea 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-tiled-gradient-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-tiled-gradient-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/effect-background-blend-mode-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/effect-background-blend-mode-expected.png
index f4fcbe7..f6ab5f81 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/effect-background-blend-mode-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/effect-background-blend-mode-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/effect-background-blend-mode-stacking-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/effect-background-blend-mode-stacking-expected.png
index 3932296..c965c96 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/effect-background-blend-mode-stacking-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/effect-background-blend-mode-stacking-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/mix-blend-mode-isolated-group-1-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/mix-blend-mode-isolated-group-1-expected.png
index 92bc6a9..a41a7397 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/mix-blend-mode-isolated-group-1-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/mix-blend-mode-isolated-group-1-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-mask-video-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-mask-video-shadow-expected.png
index 57ad0929..93286fa88 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-mask-video-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-mask-video-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/input-appearance-height-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/input-appearance-height-expected.png
index bf77734e..5c7c88f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/input-appearance-height-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/input-appearance-height-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/select/menulist-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/select/menulist-appearance-basic-expected.png
index d841027..969d6fd9 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/select/menulist-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/select/menulist-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-background-clip-text-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-background-clip-text-expected.png
index 8bf8d78..f0882aa 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-background-clip-text-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-background-clip-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-background-image-cover-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-background-image-cover-expected.png
index e3a18b57..bd1a028 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-background-image-cover-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-background-image-cover-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-background-image-repeat-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-background-image-repeat-expected.png
index f7f4010..993f03b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-background-image-repeat-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-background-image-repeat-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-background-image-space-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-background-image-space-expected.png
index 78a2f6b2..6f3dae48 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-background-image-space-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-background-image-space-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-border-radius-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-border-radius-expected.png
index bee10c7..f2792737 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-border-radius-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-border-radius-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-image-canvas-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-image-canvas-expected.png
index 984597e..bbab876 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-image-canvas-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-image-canvas-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-image-canvas-pattern-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-image-canvas-pattern-expected.png
index 1e95b59..0466ce4e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-image-canvas-pattern-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-image-canvas-pattern-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-image-filter-all-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-image-filter-all-expected.png
index 8eb47624..aeb3624 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-image-filter-all-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-image-filter-all-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-image-profile-match-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-image-profile-match-expected.png
index c9bd99b..91ac349 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-image-profile-match-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-image-profile-match-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-mask-image-svg-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-mask-image-svg-expected.png
index 0aafd6d..1abbb366 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-mask-image-svg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-mask-image-svg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-object-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-object-expected.png
index e274945..c1f3db5 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-object-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-object-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/text/emoji-web-font-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/text/emoji-web-font-expected.png
index bf5945c7..0bdffab 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/text/emoji-web-font-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/text/emoji-web-font-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png b/third_party/WebKit/LayoutTests/platform/mac/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
index c7c5b25f..2418bca6 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio-expected.png b/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio-expected.png
index 2cc0b72..992dbb9 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/color-profile-video-poster-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/color-profile-video-poster-image-expected.png
index d06619e..c074384 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/media/color-profile-video-poster-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/media/color-profile-video-poster-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.png
index 41314df..e83eccd3 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/4776765-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/4776765-expected.txt
index 8988cbc..ec9bd476 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/4776765-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/4776765-expected.txt
@@ -25,6 +25,16 @@
         },
         {
           "object": "LayoutBR BR",
+          "rect": [7, 77, 3, 20],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBR BR",
+          "rect": [7, 77, 3, 20],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBR BR",
           "rect": [7, 59, 3, 20],
           "reason": "invalidate paint rectangle"
         }
@@ -33,6 +43,14 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBlockFlow DIV",
       "reason": "outline"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-subpixel-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-subpixel-expected.txt
index 60299d6..cb356a3 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-subpixel-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-subpixel-expected.txt
@@ -22,12 +22,26 @@
           "object": "LayoutBlockFlow DIV id='inner-editor'",
           "rect": [209, 10, 4, 15],
           "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBlockFlow DIV id='inner-editor'",
+          "rect": [209, 10, 4, 15],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBlockFlow DIV id='inner-editor'",
+          "rect": [209, 10, 4, 15],
+          "reason": "invalidate paint rectangle"
         }
       ]
     }
   ],
   "objectPaintInvalidations": [
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutTextControl INPUT id='target'",
       "reason": "subtree"
     },
@@ -38,6 +52,10 @@
     {
       "object": "Caret",
       "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-with-composited-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-with-composited-scroll-expected.txt
index 58a372b..5a9289a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-with-composited-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-with-composited-scroll-expected.txt
@@ -39,6 +39,16 @@
                       "object": "LayoutBlockFlow DIV id='inner-editor'",
                       "rect": [2, 1002, 3, 15],
                       "reason": "invalidate paint rectangle"
+                    },
+                    {
+                      "object": "LayoutBlockFlow DIV id='inner-editor'",
+                      "rect": [2, 1002, 3, 15],
+                      "reason": "invalidate paint rectangle"
+                    },
+                    {
+                      "object": "LayoutBlockFlow DIV id='inner-editor'",
+                      "rect": [2, 1002, 3, 15],
+                      "reason": "invalidate paint rectangle"
                     }
                   ]
                 }
@@ -69,6 +79,10 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutTextControl INPUT id='text'",
       "reason": "subtree"
     },
@@ -79,6 +93,10 @@
     {
       "object": "Caret",
       "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
index 01653d5..d4d2b19 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
@@ -71,6 +71,14 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "style change"
     },
     {
@@ -92,14 +100,6 @@
     {
       "object": "InlineTextBox 'test1'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/delete-into-nested-block-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/delete-into-nested-block-expected.txt
index 87390c9e..4e0bf06 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/delete-into-nested-block-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/delete-into-nested-block-expected.txt
@@ -57,6 +57,16 @@
           "object": "LayoutText #text",
           "rect": [7, 118, 3, 21],
           "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [7, 118, 3, 21],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [7, 118, 3, 21],
+          "reason": "invalidate paint rectangle"
         }
       ]
     }
@@ -103,6 +113,10 @@
       "reason": "layoutObject removal"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBlockFlow DIV",
       "reason": "outline"
     },
@@ -119,6 +133,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutText #text",
       "reason": "layoutObject insertion"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/inline-outline-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/inline-outline-repaint-expected.txt
index 969e6d6..05d34eae 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/inline-outline-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/inline-outline-repaint-expected.txt
@@ -27,6 +27,16 @@
           "object": "LayoutText #text",
           "rect": [45, 183, 3, 20],
           "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [45, 183, 3, 20],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [45, 183, 3, 20],
+          "reason": "invalidate paint rectangle"
         }
       ]
     }
@@ -37,6 +47,10 @@
       "reason": "layoutObject removal"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBlockFlow DIV",
       "reason": "forced by layout"
     },
@@ -49,6 +63,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutInline SPAN id='test'",
       "reason": "forced by layout"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
index 842ac69..fe8daf5 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
@@ -80,12 +80,12 @@
   ],
   "objectPaintInvalidations": [
     {
-      "object": "LayoutTextControl INPUT id='root'",
-      "reason": "subtree"
-    },
-    {
       "object": "Caret",
       "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "LayoutTextControl INPUT id='root'",
+      "reason": "subtree"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
index bb30929..72b8b765 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
@@ -39,6 +39,16 @@
               "object": "LayoutText #text",
               "rect": [38, 6, 3, 13],
               "reason": "invalidate paint rectangle"
+            },
+            {
+              "object": "LayoutText #text",
+              "rect": [38, 6, 3, 13],
+              "reason": "invalidate paint rectangle"
+            },
+            {
+              "object": "LayoutText #text",
+              "rect": [38, 6, 3, 13],
+              "reason": "invalidate paint rectangle"
             }
           ]
         }
@@ -47,6 +57,10 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutTextControl INPUT id='root'",
       "reason": "subtree"
     },
@@ -67,6 +81,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutText #text",
       "reason": "subtree"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/line-flow-with-floats-9-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/line-flow-with-floats-9-expected.txt
index 1fcd677..134678d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/line-flow-with-floats-9-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/line-flow-with-floats-9-expected.txt
@@ -113,6 +113,14 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
       "object": "LayoutBlockFlow HTML",
       "reason": "forced by layout"
     },
@@ -311,14 +319,6 @@
     {
       "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/overflow-scroll-body-appear-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/overflow-scroll-body-appear-expected.txt
index 37b2e39..4b7a749 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/overflow-scroll-body-appear-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/overflow-scroll-body-appear-expected.txt
@@ -69,6 +69,14 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "style change"
     },
     {
@@ -122,14 +130,6 @@
     {
       "object": "InlineTextBox '.'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
index b73c00d..7fc5d22 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
@@ -73,6 +73,14 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "HorizontalScrollbar",
+      "reason": "scroll"
+    },
+    {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
       "object": "LayoutView #document",
       "reason": "subtree"
     },
@@ -95,14 +103,6 @@
     {
       "object": "InlineTextBox 'scroll me'",
       "reason": "subtree"
-    },
-    {
-      "object": "HorizontalScrollbar",
-      "reason": "scroll"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/selection-after-delete-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/selection-after-delete-expected.txt
index 7da2a029..7b6f62d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/selection-after-delete-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/selection-after-delete-expected.txt
@@ -22,6 +22,16 @@
           "object": "LayoutBR BR",
           "rect": [38, 74, 3, 20],
           "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBR BR",
+          "rect": [38, 74, 3, 20],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBR BR",
+          "rect": [38, 74, 3, 20],
+          "reason": "invalidate paint rectangle"
         }
       ]
     }
@@ -32,6 +42,10 @@
       "reason": "layoutObject removal"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBlockFlow DIV id='test'",
       "reason": "forced by layout"
     },
@@ -44,6 +58,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBR BR",
       "reason": "forced by layout"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/animated-path-inside-transformed-html-expected.png b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/animated-path-inside-transformed-html-expected.png
index b8cb14f..ac1db4e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/animated-path-inside-transformed-html-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/animated-path-inside-transformed-html-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/js-update-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/js-update-image-expected.png
index dfe78b7..188ee4d8 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/js-update-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/js-update-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/text-match-document-change-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/text-match-document-change-expected.txt
index d0241ece..985885f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/text-match-document-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/text-match-document-change-expected.txt
@@ -42,6 +42,10 @@
       "reason": "layoutObject removal"
     },
     {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
       "object": "LayoutBlockFlow HTML",
       "reason": "forced by layout"
     },
@@ -60,10 +64,6 @@
     {
       "object": "InlineTextBox 'After change'",
       "reason": "layoutObject insertion"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/textarea-caret-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/textarea-caret-expected.txt
index 53aebf9..a763b5e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/textarea-caret-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/textarea-caret-expected.txt
@@ -42,12 +42,26 @@
           "object": "LayoutText #text",
           "rect": [131, 10, 2, 14],
           "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [131, 10, 2, 14],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [131, 10, 2, 14],
+          "reason": "invalidate paint rectangle"
         }
       ]
     }
   ],
   "objectPaintInvalidations": [
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutTextControl TEXTAREA id='editor'",
       "reason": "subtree"
     },
@@ -80,6 +94,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutText #text",
       "reason": "subtree"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/window-resize-vertical-writing-mode-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
index cb25b9a..76072b91 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
@@ -65,6 +65,10 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "bounds change"
     },
     {
@@ -134,10 +138,6 @@
     {
       "object": "InlineTextBox 'NNNN'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
@@ -203,6 +203,10 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "bounds change"
     },
     {
@@ -268,10 +272,6 @@
     {
       "object": "InlineTextBox 'NNNN'",
       "reason": "bounds change"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
@@ -341,6 +341,10 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "bounds change"
     },
     {
@@ -378,10 +382,6 @@
     {
       "object": "InlineTextBox 'NNNN'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/scrollbars/listbox-scrollbar-combinations-expected.png b/third_party/WebKit/LayoutTests/platform/mac/scrollbars/listbox-scrollbar-combinations-expected.png
index e1d8025..f0719d4 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/scrollbars/listbox-scrollbar-combinations-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/scrollbars/listbox-scrollbar-combinations-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/animate-elem-30-t-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/animate-elem-30-t-expected.png
index bdbf02f6..fb46d94 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/animate-elem-30-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/animate-elem-30-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/animate-elem-39-t-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/animate-elem-39-t-expected.png
index 2e4a4ed..9286522 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/animate-elem-39-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/animate-elem-39-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/animate-elem-40-t-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/animate-elem-40-t-expected.png
index 5365a41..0ea118e7 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/animate-elem-40-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/animate-elem-40-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/coords-viewattr-02-b-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/coords-viewattr-02-b-expected.png
index ac8bb4c4..6bd5f8b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/coords-viewattr-02-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/coords-viewattr-02-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/struct-image-02-b-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/struct-image-02-b-expected.png
index 25b0d1d8..9275b37 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/struct-image-02-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/struct-image-02-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/struct-image-06-t-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/struct-image-06-t-expected.png
index 7f2ee26..cbe125d72 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/struct-image-06-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/struct-image-06-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/struct-image-08-t-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/struct-image-08-t-expected.png
index ab2548f..432c90ea 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/struct-image-08-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/struct-image-08-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/struct-image-10-t-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/struct-image-10-t-expected.png
index faafdb3..e7c013a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/struct-image-10-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/struct-image-10-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/struct-symbol-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/struct-symbol-01-b-expected.png
index 9e3388f..55a5eced 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/struct-symbol-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/struct-symbol-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/carto.net/scrollbar-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/carto.net/scrollbar-expected.png
index e1a0d13..efdacda 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/carto.net/scrollbar-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/carto.net/scrollbar-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/carto.net/selectionlist-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/carto.net/selectionlist-expected.png
index bd6b6b94..95fae49 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/carto.net/selectionlist-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/carto.net/selectionlist-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/css/text-gradient-shadow-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/css/text-gradient-shadow-expected.txt
index 445aeed..1a35683 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/css/text-gradient-shadow-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/css/text-gradient-shadow-expected.txt
@@ -1,7 +1,7 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
 layer at (0,0) size 800x600
-  LayoutSVGRoot {svg} at (200,20) size 441x270
+  LayoutSVGRoot {svg} at (200,20) size 440x269
     LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
       LayoutSVGResourceLinearGradient {linearGradient} [id="gradient"] [gradientUnits=objectBoundingBox] [start=(0,0)] [end=(1,0)]
         LayoutSVGGradientStop {stop} [offset=0.00] [color=#FF0000]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/css/text-shadow-multiple-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/css/text-shadow-multiple-expected.txt
index 0d86443..2cc45e1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/css/text-shadow-multiple-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/css/text-shadow-multiple-expected.txt
@@ -30,7 +30,7 @@
         LayoutText {#text} at (0,0) size 567x18
           text run at (0,0) width 567: "The next two texts have subtle differences, as the stroke/fill is painted seperated in SVG."
       LayoutBlockFlow (anonymous) at (0,238) size 800x154
-        LayoutSVGRoot {svg} at (0,308) size 744x89
+        LayoutSVGRoot {svg} at (0,307) size 744x92
           LayoutSVGText {text} at (20,21) size 717x56 contains 1 chunk(s)
             LayoutSVGTSpan {tspan} at (0,0) size 95x56
               LayoutSVGInlineText {#text} at (0,0) size 95x56
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/createImageElement-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/createImageElement-expected.png
index 9cdb6ef..80294e1b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/createImageElement-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/createImageElement-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/createImageElement2-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/createImageElement2-expected.png
index 601fbfb0..b8998d4 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/createImageElement2-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/createImageElement2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/image-parent-translation-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/image-parent-translation-expected.png
index 9e614f9..0705a8de 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/image-parent-translation-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/image-parent-translation-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/image-small-width-height-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/image-small-width-height-expected.png
index 2f246f8..d96edf61 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/image-small-width-height-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/image-small-width-height-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/js-update-image-and-display-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/js-update-image-and-display-expected.png
index dfe78b7..188ee4d8 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/js-update-image-and-display-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/js-update-image-and-display-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/js-update-image-and-display2-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/js-update-image-and-display2-expected.png
index dfe78b7..188ee4d8 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/js-update-image-and-display2-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/js-update-image-and-display2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/js-update-image-and-display3-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/js-update-image-and-display3-expected.png
index dfe78b7..188ee4d8 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/js-update-image-and-display3-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/js-update-image-and-display3-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/pointer-events-image-css-transform-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/pointer-events-image-css-transform-expected.png
index 0e00e6e..394a60f8 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/pointer-events-image-css-transform-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/pointer-events-image-css-transform-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/pointer-events-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/pointer-events-image-expected.png
index 0e00e6e..394a60f8 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/pointer-events-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/pointer-events-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/text-image-opacity-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/text-image-opacity-expected.png
index e637d706..c7ce6a4a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/text-image-opacity-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/text-image-opacity-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-g-containing-foreignObject-and-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-g-containing-foreignObject-and-image-expected.png
index fd53a74..87e65a76 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-g-containing-foreignObject-and-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-g-containing-foreignObject-and-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-dom-preserveAspectRatio-attr-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-dom-preserveAspectRatio-attr-expected.png
index ea402df..ba544f94 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-dom-preserveAspectRatio-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-dom-preserveAspectRatio-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-dom-width-attr-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-dom-width-attr-expected.png
index 8568a13..e3715c1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-dom-width-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-dom-width-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-dom-x-attr-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-dom-x-attr-expected.png
index 8568a13..e3715c1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-dom-x-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-dom-x-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-dom-y-attr-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-dom-y-attr-expected.png
index 8568a13..e3715c1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-dom-y-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-dom-y-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-svgdom-height-prop-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-svgdom-height-prop-expected.png
index 8568a13..e3715c1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-svgdom-height-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-svgdom-height-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-svgdom-preserveAspectRatio-prop-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-svgdom-preserveAspectRatio-prop-expected.png
index 8568a13..e3715c1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-svgdom-preserveAspectRatio-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-svgdom-preserveAspectRatio-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-svgdom-width-prop-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-svgdom-width-prop-expected.png
index 8568a13..e3715c1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-svgdom-width-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-svgdom-width-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-svgdom-x-prop-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-svgdom-x-prop-expected.png
index 8568a13..e3715c1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-svgdom-x-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-svgdom-x-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-svgdom-y-prop-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-svgdom-y-prop-expected.png
index 8568a13..e3715c1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-svgdom-y-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGImageElement-svgdom-y-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/perf/004-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/perf/004-expected.png
index 670efed..663dd1f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/perf/004-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/perf/004-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-background-images-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-background-images-expected.png
index 1056d1e..62eb78f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-background-images-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-background-images-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.png b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png
index 4478d134..0b31a9e 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/tables/mozilla/bugs/bug101674-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug101674-expected.png
index 012df9a..ce370b4 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug101674-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug101674-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug11026-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug11026-expected.png
index 3efecfe8..6de314a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug11026-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug11026-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug1188-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug1188-expected.png
index 9ef6cf1..d945c22b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug1188-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug1188-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug1296-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug1296-expected.png
index f94a311..f20649c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug1296-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug1296-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug1430-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug1430-expected.png
index 1e1191d..65b85a4 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug1430-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug1430-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug2981-2-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug2981-2-expected.png
index 66dad59..dd2c074 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug2981-2-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug2981-2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug4093-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug4093-expected.png
index b48f8ce..3f94188 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug4093-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug4093-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug4284-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug4284-expected.png
index 8a919c51..8a86a2b5 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug4284-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug4284-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug4427-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug4427-expected.png
index cda97f4..57be0b28a6 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug4427-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug4427-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug56563-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug56563-expected.png
index dd59f22..0b77035 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug56563-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug56563-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug625-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug625-expected.png
index df8487a..2723623 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug625-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug625-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug6404-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug6404-expected.png
index f61db63f..4eee0ac 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug6404-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug6404-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/core/bloomberg-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/core/bloomberg-expected.png
index c854467..d85b6c7 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/core/bloomberg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/core/bloomberg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/core/col_widths_auto_autoFix-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/core/col_widths_auto_autoFix-expected.png
index bac2d566..0b87311 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/core/col_widths_auto_autoFix-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/core/col_widths_auto_autoFix-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/core/misc-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/core/misc-expected.png
index 2506c4f..d8647a62 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/core/misc-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/core/misc-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/other/cell_widths-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/other/cell_widths-expected.png
index c72bc42..b1fdb3a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/other/cell_widths-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/other/cell_widths-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla_expected_failures/bugs/bug6933-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla_expected_failures/bugs/bug6933-expected.png
index 23242d37..3975e0c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla_expected_failures/bugs/bug6933-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla_expected_failures/bugs/bug6933-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations-expected.png
index e1d8025..f0719d4 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/rootlayerscrolls/scrollbars/listbox-scrollbar-combinations-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/rootlayerscrolls/scrollbars/listbox-scrollbar-combinations-expected.png
index e1d8025..f0719d4 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/rootlayerscrolls/scrollbars/listbox-scrollbar-combinations-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/rootlayerscrolls/scrollbars/listbox-scrollbar-combinations-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
index a68f08e4..6865efb 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/masks/masked-ancestor-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/masks/masked-ancestor-expected.png
index 3c1b7dd6..e3e3cec9 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/masks/masked-ancestor-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/masks/masked-ancestor-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-gradient-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-gradient-image-expected.png
index 320a7c0..34bd34a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-gradient-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-gradient-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-image-color-expected.png b/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-image-color-expected.png
index 5b09550..b3a801c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-image-color-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-image-color-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-image-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-image-image-expected.png
index 78c3a5a..8c4b4e3 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-image-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-image-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-image-svg-expected.png b/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-image-svg-expected.png
index 34bda46..3929703 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-image-svg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-image-svg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-tiled-gradient-expected.png b/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-tiled-gradient-expected.png
index d9c54c36..2b0a110 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-tiled-gradient-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-tiled-gradient-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/blending/effect-background-blend-mode-expected.png b/third_party/WebKit/LayoutTests/platform/win/css3/blending/effect-background-blend-mode-expected.png
index 4c315bf..721ad31 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css3/blending/effect-background-blend-mode-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css3/blending/effect-background-blend-mode-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/blending/effect-background-blend-mode-stacking-expected.png b/third_party/WebKit/LayoutTests/platform/win/css3/blending/effect-background-blend-mode-stacking-expected.png
index aa24219a..4a0f6a0 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css3/blending/effect-background-blend-mode-stacking-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css3/blending/effect-background-blend-mode-stacking-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/blending/mix-blend-mode-isolated-group-1-expected.png b/third_party/WebKit/LayoutTests/platform/win/css3/blending/mix-blend-mode-isolated-group-1-expected.png
index 416453e..d260285 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css3/blending/mix-blend-mode-isolated-group-1-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css3/blending/mix-blend-mode-isolated-group-1-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/backgrounds/border-radius-split-background-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/backgrounds/border-radius-split-background-expected.png
index 5ac01f3..826e9b8 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/backgrounds/border-radius-split-background-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/backgrounds/border-radius-split-background-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/backgrounds/border-radius-split-background-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/backgrounds/border-radius-split-background-image-expected.png
index e64ac73..b0bc567 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/backgrounds/border-radius-split-background-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/backgrounds/border-radius-split-background-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-video-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-video-shadow-expected.png
index d01b6ab..8defd39 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-video-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-video-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-styles-split-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-styles-split-expected.png
index 34a8820f..2393034d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-styles-split-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-styles-split-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/inline-mask-overlay-image-outset-vertical-rl-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/inline-mask-overlay-image-outset-vertical-rl-expected.png
index 0101f08..ca402fe 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/inline-mask-overlay-image-outset-vertical-rl-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/inline-mask-overlay-image-outset-vertical-rl-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
index 4985b617..280c298 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-expected.png
index 6bc47b3..5501a0a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
index 132f3499..83921f9 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
index 076cda4e..74e46ab 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
index 99a8f81..2f7a58c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
index 99680dc..a78036d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/input-appearance-height-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/input-appearance-height-expected.png
index 3caaacc..187382d1 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/input-appearance-height-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/input-appearance-height-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/menulist-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/menulist-appearance-basic-expected.png
index f3177b8f..d5802e9c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/menulist-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/menulist-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/menulist-appearance-basic-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/menulist-appearance-basic-expected.txt
index 807a15e..8208717 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/menulist-appearance-basic-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/menulist-appearance-basic-expected.txt
@@ -87,7 +87,13 @@
             text run at (4,1) width 34: "foo"
       LayoutText {#text} at (189,188) size 4x17
         text run at (189,188) width 4: " "
-      LayoutBR {BR} at (193,188) size 0x17
+      LayoutMenuList {SELECT} at (197,187) size 126x20 [bgcolor=#FFFFFF] [border: (1px solid #A9A9A9)]
+        LayoutBlockFlow (anonymous) at (1,1) size 124x18
+          LayoutText (anonymous) at (4,1) size 102x16
+            text run at (4,1) width 102: "September 2016"
+      LayoutText {#text} at (327,188) size 4x17
+        text run at (327,188) width 4: " "
+      LayoutBR {BR} at (331,188) size 0x17
       LayoutMenuList {SELECT} at (6,229) size 63x26 [bgcolor=#FFFFFF] [border: (1px solid #A9A9A9)]
         LayoutBlockFlow (anonymous) at (1,1) size 61x25
           LayoutText (anonymous) at (6,1) size 28x22
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-background-clip-text-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-background-clip-text-expected.png
index 8de7d5e..8b79955d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-background-clip-text-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-background-clip-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-background-image-cover-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-background-image-cover-expected.png
index 69cd422..f643c47 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-background-image-cover-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-background-image-cover-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-background-image-repeat-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-background-image-repeat-expected.png
index 4d503f9..db9550b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-background-image-repeat-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-background-image-repeat-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-background-image-space-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-background-image-space-expected.png
index 026b025..e54bf41 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-background-image-space-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-background-image-space-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-border-radius-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-border-radius-expected.png
index 09f6a0d..07914ea 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-border-radius-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-border-radius-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-image-canvas-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-image-canvas-expected.png
index 77f79a1..b151e17 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-image-canvas-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-image-canvas-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-image-canvas-pattern-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-image-canvas-pattern-expected.png
index f38f9ee..d0e48568 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-image-canvas-pattern-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-image-canvas-pattern-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-image-filter-all-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-image-filter-all-expected.png
index d85af35..325e42c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-image-filter-all-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-image-filter-all-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-image-profile-match-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-image-profile-match-expected.png
index ed764d06..6fb562e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-image-profile-match-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-image-profile-match-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-mask-image-svg-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-mask-image-svg-expected.png
index 178c4353..2a25b15 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-mask-image-svg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-mask-image-svg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-object-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-object-expected.png
index c384be8..63c5625 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-object-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-object-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/text/emoji-web-font-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/text/emoji-web-font-expected.png
index 83884e9..d92526a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/text/emoji-web-font-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/text/emoji-web-font-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png b/third_party/WebKit/LayoutTests/platform/win/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
index 399e0c4..2eb35bf 100644
--- a/third_party/WebKit/LayoutTests/platform/win/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio-expected.png b/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio-expected.png
index 00782a9..1dcc45d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/color-profile-video-poster-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/color-profile-video-poster-image-expected.png
index 14099e454..f03e7338 100644
--- a/third_party/WebKit/LayoutTests/platform/win/media/color-profile-video-poster-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/media/color-profile-video-poster-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/video-zoom-controls-expected.png
index f8616a7..1ffce50a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/media/video-zoom-controls-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/media/video-zoom-controls-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/4776765-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/4776765-expected.txt
index f28a8d1..2404e86 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/4776765-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/4776765-expected.txt
@@ -25,6 +25,16 @@
         },
         {
           "object": "LayoutBR BR",
+          "rect": [7, 77, 3, 19],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBR BR",
+          "rect": [7, 77, 3, 19],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBR BR",
           "rect": [7, 59, 3, 19],
           "reason": "invalidate paint rectangle"
         }
@@ -33,6 +43,14 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBlockFlow DIV",
       "reason": "outline"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-subpixel-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-subpixel-expected.txt
new file mode 100644
index 0000000..c009fdc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-subpixel-expected.txt
@@ -0,0 +1,62 @@
+{
+  "name": "Content Root Layer",
+  "bounds": [800, 600],
+  "children": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "paintInvalidations": [
+        {
+          "object": "LayoutTextControl INPUT id='target'",
+          "rect": [8, 8, 224, 22],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutBlockFlow DIV id='inner-editor'",
+          "rect": [10, 11, 201, 16],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutBlockFlow DIV id='inner-editor'",
+          "rect": [208, 10, 4, 18],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBlockFlow DIV id='inner-editor'",
+          "rect": [208, 10, 4, 18],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBlockFlow DIV id='inner-editor'",
+          "rect": [208, 10, 4, 18],
+          "reason": "invalidate paint rectangle"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "LayoutTextControl INPUT id='target'",
+      "reason": "subtree"
+    },
+    {
+      "object": "LayoutBlockFlow DIV id='inner-editor'",
+      "reason": "subtree"
+    },
+    {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-with-composited-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-with-composited-scroll-expected.txt
index dff41bb..7f8cd0d4 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-with-composited-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-with-composited-scroll-expected.txt
@@ -39,6 +39,16 @@
                       "object": "LayoutBlockFlow DIV id='inner-editor'",
                       "rect": [2, 1002, 3, 18],
                       "reason": "invalidate paint rectangle"
+                    },
+                    {
+                      "object": "LayoutBlockFlow DIV id='inner-editor'",
+                      "rect": [2, 1002, 3, 18],
+                      "reason": "invalidate paint rectangle"
+                    },
+                    {
+                      "object": "LayoutBlockFlow DIV id='inner-editor'",
+                      "rect": [2, 1002, 3, 18],
+                      "reason": "invalidate paint rectangle"
                     }
                   ]
                 }
@@ -69,6 +79,10 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutTextControl INPUT id='text'",
       "reason": "subtree"
     },
@@ -79,6 +93,10 @@
     {
       "object": "Caret",
       "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
index a34ee3f..eec44b5 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
@@ -71,6 +71,14 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "style change"
     },
     {
@@ -92,14 +100,6 @@
     {
       "object": "InlineTextBox 'test1'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/delete-into-nested-block-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/delete-into-nested-block-expected.txt
index 68571ea..6b996e2 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/delete-into-nested-block-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/delete-into-nested-block-expected.txt
@@ -57,6 +57,16 @@
           "object": "LayoutText #text",
           "rect": [7, 118, 3, 20],
           "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [7, 118, 3, 20],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [7, 118, 3, 20],
+          "reason": "invalidate paint rectangle"
         }
       ]
     }
@@ -103,6 +113,10 @@
       "reason": "layoutObject removal"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBlockFlow DIV",
       "reason": "outline"
     },
@@ -119,6 +133,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutText #text",
       "reason": "layoutObject insertion"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/inline-outline-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/inline-outline-repaint-expected.txt
index 3f3ed422..fa91e45 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/inline-outline-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/inline-outline-repaint-expected.txt
@@ -27,6 +27,16 @@
           "object": "LayoutText #text",
           "rect": [45, 182, 3, 20],
           "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [45, 182, 3, 20],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [45, 182, 3, 20],
+          "reason": "invalidate paint rectangle"
         }
       ]
     }
@@ -37,6 +47,10 @@
       "reason": "layoutObject removal"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBlockFlow DIV",
       "reason": "forced by layout"
     },
@@ -49,6 +63,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutInline SPAN id='test'",
       "reason": "forced by layout"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
index 5c5cb52..e41c0d6a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
@@ -80,12 +80,12 @@
   ],
   "objectPaintInvalidations": [
     {
-      "object": "LayoutTextControl INPUT id='root'",
-      "reason": "subtree"
-    },
-    {
       "object": "Caret",
       "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "LayoutTextControl INPUT id='root'",
+      "reason": "subtree"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
index 2c09ac4..7be285e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
@@ -39,6 +39,16 @@
               "object": "LayoutText #text",
               "rect": [64, 4, 3, 16],
               "reason": "invalidate paint rectangle"
+            },
+            {
+              "object": "LayoutText #text",
+              "rect": [64, 4, 3, 16],
+              "reason": "invalidate paint rectangle"
+            },
+            {
+              "object": "LayoutText #text",
+              "rect": [64, 4, 3, 16],
+              "reason": "invalidate paint rectangle"
             }
           ]
         }
@@ -47,6 +57,10 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutTextControl INPUT id='root'",
       "reason": "subtree"
     },
@@ -67,6 +81,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutText #text",
       "reason": "subtree"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/line-flow-with-floats-9-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/line-flow-with-floats-9-expected.txt
index 49cb14a..f8dfd64 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/line-flow-with-floats-9-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/line-flow-with-floats-9-expected.txt
@@ -113,6 +113,14 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
       "object": "LayoutBlockFlow HTML",
       "reason": "forced by layout"
     },
@@ -311,14 +319,6 @@
     {
       "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/overflow-scroll-body-appear-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/overflow-scroll-body-appear-expected.txt
index 0047151..3bc8375 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/overflow-scroll-body-appear-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/overflow-scroll-body-appear-expected.txt
@@ -69,6 +69,14 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "style change"
     },
     {
@@ -122,14 +130,6 @@
     {
       "object": "InlineTextBox '.'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
index 8742ad9..e3747d8 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
@@ -73,6 +73,14 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "HorizontalScrollbar",
+      "reason": "scroll"
+    },
+    {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
       "object": "LayoutView #document",
       "reason": "subtree"
     },
@@ -95,14 +103,6 @@
     {
       "object": "InlineTextBox 'scroll me'",
       "reason": "subtree"
-    },
-    {
-      "object": "HorizontalScrollbar",
-      "reason": "scroll"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/selection-after-delete-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/selection-after-delete-expected.txt
index f8c6c013..fbafe7f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/selection-after-delete-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/selection-after-delete-expected.txt
@@ -22,6 +22,16 @@
           "object": "LayoutBR BR",
           "rect": [38, 74, 3, 19],
           "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBR BR",
+          "rect": [38, 74, 3, 19],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBR BR",
+          "rect": [38, 74, 3, 19],
+          "reason": "invalidate paint rectangle"
         }
       ]
     }
@@ -32,6 +42,10 @@
       "reason": "layoutObject removal"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBlockFlow DIV id='test'",
       "reason": "forced by layout"
     },
@@ -44,6 +58,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBR BR",
       "reason": "forced by layout"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/animated-path-inside-transformed-html-expected.png b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/animated-path-inside-transformed-html-expected.png
index 988119f..53cb58b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/animated-path-inside-transformed-html-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/animated-path-inside-transformed-html-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/js-update-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/js-update-image-expected.png
index e9338de..c4d87dd9 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/js-update-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/js-update-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/text-match-document-change-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/text-match-document-change-expected.txt
index 0545b834..373cb1a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/text-match-document-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/text-match-document-change-expected.txt
@@ -42,6 +42,10 @@
       "reason": "layoutObject removal"
     },
     {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
       "object": "LayoutBlockFlow HTML",
       "reason": "forced by layout"
     },
@@ -60,10 +64,6 @@
     {
       "object": "InlineTextBox 'After change'",
       "reason": "layoutObject insertion"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/textarea-caret-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/textarea-caret-expected.txt
index 65ad43a..abf1f3e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/textarea-caret-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/textarea-caret-expected.txt
@@ -37,12 +37,26 @@
           "object": "LayoutText #text",
           "rect": [186, 10, 2, 18],
           "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [186, 10, 2, 18],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [186, 10, 2, 18],
+          "reason": "invalidate paint rectangle"
         }
       ]
     }
   ],
   "objectPaintInvalidations": [
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutTextControl TEXTAREA id='editor'",
       "reason": "subtree"
     },
@@ -67,6 +81,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutText #text",
       "reason": "subtree"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/window-resize-vertical-writing-mode-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
index 1d5da92..2b513fb9a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
@@ -65,6 +65,10 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "bounds change"
     },
     {
@@ -134,10 +138,6 @@
     {
       "object": "InlineTextBox 'NNNN'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
@@ -203,6 +203,10 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "bounds change"
     },
     {
@@ -268,10 +272,6 @@
     {
       "object": "InlineTextBox 'NNNN'",
       "reason": "bounds change"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
@@ -341,6 +341,10 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "bounds change"
     },
     {
@@ -378,10 +382,6 @@
     {
       "object": "InlineTextBox 'NNNN'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/animate-elem-30-t-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/animate-elem-30-t-expected.png
index aaa4c472..ed59779 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/animate-elem-30-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/animate-elem-30-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/animate-elem-39-t-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/animate-elem-39-t-expected.png
index 4c0e9ad..df87a69e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/animate-elem-39-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/animate-elem-39-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/animate-elem-40-t-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/animate-elem-40-t-expected.png
index a95a99d..c98fadc 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/animate-elem-40-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/animate-elem-40-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/coords-viewattr-02-b-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/coords-viewattr-02-b-expected.png
index 233c894..8948e938 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/coords-viewattr-02-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/coords-viewattr-02-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/struct-image-02-b-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/struct-image-02-b-expected.png
index 68564720..d8ca06c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/struct-image-02-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/struct-image-02-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/struct-image-06-t-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/struct-image-06-t-expected.png
index a18d1db..b91362ac 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/struct-image-06-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/struct-image-06-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/struct-image-08-t-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/struct-image-08-t-expected.png
index a32d66e..b606c5e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/struct-image-08-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/struct-image-08-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/struct-image-10-t-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/struct-image-10-t-expected.png
index 83248ec..a31f82a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/struct-image-10-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/struct-image-10-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/struct-symbol-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/struct-symbol-01-b-expected.png
index 401d7fb..17e5e95 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/struct-symbol-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/struct-symbol-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/carto.net/scrollbar-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/carto.net/scrollbar-expected.png
index 83a9312..a54b38d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/carto.net/scrollbar-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/carto.net/scrollbar-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/carto.net/selectionlist-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/carto.net/selectionlist-expected.png
index 375557fc..7b20004 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/carto.net/selectionlist-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/carto.net/selectionlist-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/css/text-gradient-shadow-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/css/text-gradient-shadow-expected.txt
index 5a3f6bb..4dbbbd5 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/css/text-gradient-shadow-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/css/text-gradient-shadow-expected.txt
@@ -1,7 +1,7 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
 layer at (0,0) size 800x600
-  LayoutSVGRoot {svg} at (200,22) size 441x261
+  LayoutSVGRoot {svg} at (200,22) size 440x260
     LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
       LayoutSVGResourceLinearGradient {linearGradient} [id="gradient"] [gradientUnits=objectBoundingBox] [start=(0,0)] [end=(1,0)]
         LayoutSVGGradientStop {stop} [offset=0.00] [color=#FF0000]
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/css/text-shadow-multiple-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/css/text-shadow-multiple-expected.txt
index 3f0e8e4..ee2764c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/css/text-shadow-multiple-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/css/text-shadow-multiple-expected.txt
@@ -30,7 +30,7 @@
         LayoutText {#text} at (0,0) size 568x17
           text run at (0,0) width 568: "The next two texts have subtle differences, as the stroke/fill is painted seperated in SVG."
       LayoutBlockFlow (anonymous) at (0,238) size 800x154
-        LayoutSVGRoot {svg} at (0,308) size 744x89
+        LayoutSVGRoot {svg} at (0,307) size 744x92
           LayoutSVGText {text} at (20,21) size 717x56 contains 1 chunk(s)
             LayoutSVGTSpan {tspan} at (0,0) size 95x56
               LayoutSVGInlineText {#text} at (0,0) size 95x56
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/createImageElement-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/custom/createImageElement-expected.png
index 2b3b030..0413c06 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/createImageElement-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/createImageElement-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/createImageElement2-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/custom/createImageElement2-expected.png
index 7da1feb..c44da9e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/createImageElement2-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/createImageElement2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/image-parent-translation-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/custom/image-parent-translation-expected.png
index f7d12bfe..e79e0d0a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/image-parent-translation-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/image-parent-translation-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/image-small-width-height-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/custom/image-small-width-height-expected.png
index 756c7ec..0ff0f2e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/image-small-width-height-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/image-small-width-height-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/js-update-image-and-display-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/custom/js-update-image-and-display-expected.png
index e9338de..c4d87dd9 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/js-update-image-and-display-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/js-update-image-and-display-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/js-update-image-and-display2-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/custom/js-update-image-and-display2-expected.png
index e9338de..c4d87dd9 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/js-update-image-and-display2-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/js-update-image-and-display2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/js-update-image-and-display3-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/custom/js-update-image-and-display3-expected.png
index e9338de..c4d87dd9 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/js-update-image-and-display3-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/js-update-image-and-display3-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/pointer-events-image-css-transform-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/custom/pointer-events-image-css-transform-expected.png
index d27e8e3..11561fb 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/pointer-events-image-css-transform-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/pointer-events-image-css-transform-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/pointer-events-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/custom/pointer-events-image-expected.png
index d27e8e3..11561fb 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/pointer-events-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/pointer-events-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/text-image-opacity-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/custom/text-image-opacity-expected.png
index 3836b09..8edca86 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/text-image-opacity-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/text-image-opacity-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-g-containing-foreignObject-and-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-g-containing-foreignObject-and-image-expected.png
index 0f9e726..0f0d9cc 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-g-containing-foreignObject-and-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-g-containing-foreignObject-and-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-dom-preserveAspectRatio-attr-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-dom-preserveAspectRatio-attr-expected.png
index b3f7bda..16407cf1 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-dom-preserveAspectRatio-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-dom-preserveAspectRatio-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-dom-width-attr-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-dom-width-attr-expected.png
index 524bafc..d3a1f2e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-dom-width-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-dom-width-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-dom-x-attr-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-dom-x-attr-expected.png
index 524bafc..d3a1f2e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-dom-x-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-dom-x-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-dom-y-attr-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-dom-y-attr-expected.png
index 524bafc..d3a1f2e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-dom-y-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-dom-y-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-svgdom-height-prop-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-svgdom-height-prop-expected.png
index 524bafc..d3a1f2e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-svgdom-height-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-svgdom-height-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-svgdom-preserveAspectRatio-prop-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-svgdom-preserveAspectRatio-prop-expected.png
index 524bafc..d3a1f2e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-svgdom-preserveAspectRatio-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-svgdom-preserveAspectRatio-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-svgdom-width-prop-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-svgdom-width-prop-expected.png
index 524bafc..d3a1f2e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-svgdom-width-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-svgdom-width-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-svgdom-x-prop-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-svgdom-x-prop-expected.png
index 524bafc..d3a1f2e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-svgdom-x-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-svgdom-x-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-svgdom-y-prop-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-svgdom-y-prop-expected.png
index 524bafc..d3a1f2e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-svgdom-y-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGImageElement-svgdom-y-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/hixie/perf/004-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/hixie/perf/004-expected.png
index 70b7db1..6b70b3b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/hixie/perf/004-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/hixie/perf/004-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-background-images-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-background-images-expected.png
index 11caa10..b52fae9 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-background-images-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-background-images-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 084f6ba..7277c25d 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-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 8327b781..6ad7a19 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/tables/mozilla/bugs/bug101674-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug101674-expected.png
index a32840a..f8e4cc9 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug101674-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug101674-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug11026-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug11026-expected.png
index e0945aa..c0cb1e4 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug11026-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug11026-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug1188-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug1188-expected.png
index aa5b63f..08b3499 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug1188-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug1188-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug1296-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug1296-expected.png
index e5a2c21..47e6569 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug1296-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug1296-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug1430-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug1430-expected.png
index 440a920..86f584e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug1430-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug1430-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug2981-2-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug2981-2-expected.png
index e1d882daf..7af5292 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug2981-2-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug2981-2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug4093-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug4093-expected.png
index d6a7d36..84ef37bc 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug4093-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug4093-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug4284-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug4284-expected.png
index 31f46d1..3ad4424 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug4284-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug4284-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug4427-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug4427-expected.png
index 4713461..ca921ab 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug4427-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug4427-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug56563-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug56563-expected.png
index 9ded1d88..284ec77 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug56563-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug56563-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug625-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug625-expected.png
index 239c461..78b1c52 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug625-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug625-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug6404-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug6404-expected.png
index bdfd4c8..f65e03e6 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug6404-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug6404-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/core/bloomberg-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/core/bloomberg-expected.png
index 892dda4..3869af8 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/core/bloomberg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/core/bloomberg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/core/col_widths_auto_autoFix-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/core/col_widths_auto_autoFix-expected.png
index 389c6260..7a621b5 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/core/col_widths_auto_autoFix-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/core/col_widths_auto_autoFix-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/core/misc-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/core/misc-expected.png
index ccbf0a69..b0f5d643 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/core/misc-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/core/misc-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/other/cell_widths-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/other/cell_widths-expected.png
index e4ab778b..4caa084 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/other/cell_widths-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/other/cell_widths-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla_expected_failures/bugs/bug6933-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla_expected_failures/bugs/bug6933-expected.png
index d0505f8..c273c991 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla_expected_failures/bugs/bug6933-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla_expected_failures/bugs/bug6933-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
index 4cb14e4..0c4951c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/data-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/data-suggestion-picker-appearance-expected.png
index eed207b..9a93db44 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/data-suggestion-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/data-suggestion-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
index 0d350b2..22f245e 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/text/emoji-web-font-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/text/emoji-web-font-expected.png
index 4e6f1e2..efdb221f 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/text/emoji-web-font-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/text/emoji-web-font-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win7/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
index 2bb8b3e..3df6974 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/scrollbars/custom-scrollbar-reconstruction-on-setting-newstyle-expected.html b/third_party/WebKit/LayoutTests/scrollbars/custom-scrollbar-reconstruction-on-setting-newstyle-expected.html
new file mode 100644
index 0000000..98d94170
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/scrollbars/custom-scrollbar-reconstruction-on-setting-newstyle-expected.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<style>
+::-webkit-scrollbar {
+    width: 30px;
+    height: 30px;
+}
+::-webkit-scrollbar-thumb {
+    background: green;
+}
+#scroller {
+    overflow: scroll;
+    width: 400px;
+    height: 400px;
+}
+#space {
+    width: 1200px;
+    height: 900px;
+}
+</style>
+<div id="scroller"><div id="space"></div></div>
diff --git a/third_party/WebKit/LayoutTests/scrollbars/custom-scrollbar-reconstruction-on-setting-newstyle.html b/third_party/WebKit/LayoutTests/scrollbars/custom-scrollbar-reconstruction-on-setting-newstyle.html
new file mode 100644
index 0000000..22d46cc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/scrollbars/custom-scrollbar-reconstruction-on-setting-newstyle.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<style>
+#scroller {
+    overflow: scroll;
+    width: 400px;
+    height: 400px;
+}
+#space {
+    width: 1200px;
+    height: 900px;
+}
+</style>
+<div id="scroller"><div id="space"></div></div>
+<script src="../resources/run-after-layout-and-paint.js"></script>
+<script>
+    var styleElement = document.createElement("style");
+    var sheet = document.head.appendChild(styleElement).sheet;
+    runAfterLayoutAndPaint(function() {
+        sheet.insertRule("::-webkit-scrollbar { width: 30px; height: 30px; }", 0);
+        sheet.insertRule("::-webkit-scrollbar-thumb { background: green; }", 1);
+    }, true);
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/storage/websql/transaction-removed-context-crash-expected.txt b/third_party/WebKit/LayoutTests/storage/websql/transaction-removed-context-crash-expected.txt
new file mode 100644
index 0000000..b7ff4a9b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/storage/websql/transaction-removed-context-crash-expected.txt
@@ -0,0 +1 @@
+If it doesn't crash, this test has passed.
diff --git a/third_party/WebKit/LayoutTests/storage/websql/transaction-removed-context-crash.html b/third_party/WebKit/LayoutTests/storage/websql/transaction-removed-context-crash.html
new file mode 100644
index 0000000..b2c36f0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/storage/websql/transaction-removed-context-crash.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<title>Transaction from removed execution context</title>
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
+
+var script = `
+var db = openDatabase('db' + Math.random() + Date.now(), '1.0', 'test database', 2*1024);
+db.transaction(tx => {
+    tx.executeSql('DROP TABLE IF EXISTS TestTable');
+    tx.executeSql('CREATE TABLE IF NOT EXISTS TestTable (id unique,text)');
+    tx.executeSql('DELETE FROM TestTable WHERE id=?', [1]);
+    frameElement.parentNode.removeChild(frameElement);
+});
+`;
+
+window.addEventListener('DOMContentLoaded', e => {
+    var blob = new Blob(['<script>' + script +  '<\/script>'], {'type': 'text/html'});
+    var iframe = document.createElement('iframe');
+    document.body.appendChild(iframe);
+    iframe.src = URL.createObjectURL(blob);
+    if (window.testRunner)
+        window.setTimeout(() => { testRunner.notifyDone() }, 250);
+});
+</script>
+<body>
+If it doesn't crash, this test has passed.
+</body>
diff --git a/third_party/WebKit/LayoutTests/svg/as-image/image-preserveAspectRatio-all-expected.png b/third_party/WebKit/LayoutTests/svg/as-image/image-preserveAspectRatio-all-expected.png
index b7ce6ae8e..483e7f37 100644
--- a/third_party/WebKit/LayoutTests/svg/as-image/image-preserveAspectRatio-all-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/as-image/image-preserveAspectRatio-all-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/css/svgcursorelement-use-counter.html b/third_party/WebKit/LayoutTests/svg/css/svgcursorelement-use-counter.html
new file mode 100644
index 0000000..77bf86f1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/svg/css/svgcursorelement-use-counter.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<title>SVGCursorElement use counters</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<style>
+#target {
+  cursor: url(#mycursor), auto;
+}
+</style>
+<script>
+// From UseCounter.h
+const SVGCursorElement = 1587;
+const SVGCursorElementHasClient = 1588;
+
+test(function() {
+  assert_false(internals.isUseCounted(document, SVGCursorElement));
+  assert_false(internals.isUseCounted(document, SVGCursorElementHasClient));
+}, document.title + ', before element parsed');
+</script>
+<svg><cursor id="mycursor" href="data:image/png;base64,"></cursor></svg>
+<script>
+test(function() {
+  assert_true(internals.isUseCounted(document, SVGCursorElement));
+  assert_false(internals.isUseCounted(document, SVGCursorElementHasClient));
+}, document.title + ', after element parsed');
+</script>
+<svg id="target"></svg>
+<script>
+test(function() {
+  document.querySelector('#target').clientLeft;
+
+  assert_true(internals.isUseCounted(document, SVGCursorElement));
+  assert_true(internals.isUseCounted(document, SVGCursorElementHasClient));
+}, document.title + ', after style computed');
+</script>
diff --git a/third_party/WebKit/LayoutTests/svg/custom/getClientRects.html b/third_party/WebKit/LayoutTests/svg/custom/getClientRects.html
new file mode 100644
index 0000000..8b70017b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/svg/custom/getClientRects.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<title>Element.getClientRects() on an SVGElement</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<style>
+body {
+  margin-left:0px;
+  margin-top:0px;
+}
+</style>
+<body>
+<svg width="100px" height="100px">
+  <rect x="20" y="30" width="40" height="50" />
+</svg>
+<svg width="100px" height="100px">
+  <g>
+    <text x="10" y="10">svg text</text>
+    <foreignObject x="10" y="30" width="50" height="50"> foreign object text </foreignObject>
+  </g>
+</svg>
+<script>
+test(function() {
+  var list1 = document.querySelector("rect").getClientRects();
+  assert_equals(list1.length, 1);
+  var r = list1[0];
+  assert_equals(r.left, 20);
+  assert_equals(r.top, 30);
+  assert_equals(r.width, 40);
+  assert_equals(r.height, 50);
+  assert_equals(r.right, 60);
+  assert_equals(r.bottom, 80);
+
+  var gElem = document.querySelector("g");
+  var list2 = gElem.getClientRects();
+  assert_equals(list2.length, 1);
+  var r1 = list2[0];
+  var r2 = gElem.getBoundingClientRect();
+  assert_equals(r1.left, r2.left);
+  assert_equals(r1.top, r2.top);
+  assert_equals(r1.width, r2.width);
+  assert_equals(r1.height, r2.height);
+  assert_equals(r1.right, r2.right);
+  assert_equals(r1.bottom, r2.bottom);
+});
+</script>
+</body>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/virtual/mojo-service-worker/http/tests/serviceworker/README.txt b/third_party/WebKit/LayoutTests/virtual/mojo-service-worker/http/tests/serviceworker/README.txt
new file mode 100644
index 0000000..0310ec9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/mojo-service-worker/http/tests/serviceworker/README.txt
@@ -0,0 +1 @@
+This directory is for testing the service workers with mojo by using '--mojo-service-worker' flag.
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 3016850..e14cd2d 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -640,6 +640,7 @@
     getter caches
     getter crypto
     getter indexedDB
+    getter isSecureContext
     getter location
     getter navigator
     getter onerror
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/element-instance-property-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/element-instance-property-listing-expected.txt
index 2d39d0d8..fec7291 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/element-instance-property-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/element-instance-property-listing-expected.txt
@@ -75,6 +75,7 @@
     property hasAttributeNS
     property hasAttributes
     property hasChildNodes
+    property hasPointerCapture
     property hidden
     property id
     property innerHTML
@@ -136,6 +137,7 @@
     property onended
     property onerror
     property onfocus
+    property ongotpointercapture
     property oninput
     property oninvalid
     property onkeydown
@@ -145,6 +147,7 @@
     property onloadeddata
     property onloadedmetadata
     property onloadstart
+    property onlostpointercapture
     property onmousedown
     property onmouseenter
     property onmouseleave
@@ -157,6 +160,14 @@
     property onpause
     property onplay
     property onplaying
+    property onpointercancel
+    property onpointerdown
+    property onpointerenter
+    property onpointerleave
+    property onpointermove
+    property onpointerout
+    property onpointerover
+    property onpointerup
     property onprogress
     property onratechange
     property onreset
@@ -193,6 +204,7 @@
     property previousSibling
     property querySelector
     property querySelectorAll
+    property releasePointerCapture
     property remove
     property removeAttribute
     property removeAttributeNS
@@ -212,6 +224,7 @@
     property setAttributeNS
     property setAttributeNode
     property setAttributeNodeNS
+    property setPointerCapture
     property shadowRoot
     property slot
     property spellcheck
@@ -1141,6 +1154,7 @@
     property hasAttributeNS
     property hasAttributes
     property hasChildNodes
+    property hasPointerCapture
     property hidden
     property id
     property innerHTML
@@ -1202,6 +1216,7 @@
     property onended
     property onerror
     property onfocus
+    property ongotpointercapture
     property oninput
     property oninvalid
     property onkeydown
@@ -1211,6 +1226,7 @@
     property onloadeddata
     property onloadedmetadata
     property onloadstart
+    property onlostpointercapture
     property onmousedown
     property onmouseenter
     property onmouseleave
@@ -1223,6 +1239,14 @@
     property onpause
     property onplay
     property onplaying
+    property onpointercancel
+    property onpointerdown
+    property onpointerenter
+    property onpointerleave
+    property onpointermove
+    property onpointerout
+    property onpointerover
+    property onpointerup
     property onprogress
     property onratechange
     property onreset
@@ -1259,6 +1283,7 @@
     property previousSibling
     property querySelector
     property querySelectorAll
+    property releasePointerCapture
     property remove
     property removeAttribute
     property removeAttributeNS
@@ -1278,6 +1303,7 @@
     property setAttributeNS
     property setAttributeNode
     property setAttributeNodeNS
+    property setPointerCapture
     property shadowRoot
     property slot
     property spellcheck
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
index 46f582c..808944e 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -647,6 +647,7 @@
 [Worker]     getter caches
 [Worker]     getter crypto
 [Worker]     getter indexedDB
+[Worker]     getter isSecureContext
 [Worker]     getter location
 [Worker]     getter navigator
 [Worker]     getter onerror
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
index 319602f..69e03c91 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -814,8 +814,16 @@
     getter onpause
     getter onplay
     getter onplaying
+    getter onpointercancel
+    getter onpointerdown
+    getter onpointerenter
+    getter onpointerleave
     getter onpointerlockchange
     getter onpointerlockerror
+    getter onpointermove
+    getter onpointerout
+    getter onpointerover
+    getter onpointerup
     getter onprogress
     getter onratechange
     getter onreadystatechange
@@ -969,8 +977,16 @@
     setter onpause
     setter onplay
     setter onplaying
+    setter onpointercancel
+    setter onpointerdown
+    setter onpointerenter
+    setter onpointerleave
     setter onpointerlockchange
     setter onpointerlockerror
+    setter onpointermove
+    setter onpointerout
+    setter onpointerover
+    setter onpointerup
     setter onprogress
     setter onratechange
     setter onreadystatechange
@@ -1064,6 +1080,8 @@
     getter onbeforepaste
     getter oncopy
     getter oncut
+    getter ongotpointercapture
+    getter onlostpointercapture
     getter onpaste
     getter onsearch
     getter onselectstart
@@ -1101,6 +1119,7 @@
     method hasAttribute
     method hasAttributeNS
     method hasAttributes
+    method hasPointerCapture
     method insertAdjacentElement
     method insertAdjacentHTML
     method insertAdjacentText
@@ -1108,6 +1127,7 @@
     method prepend
     method querySelector
     method querySelectorAll
+    method releasePointerCapture
     method remove
     method removeAttribute
     method removeAttributeNS
@@ -1120,6 +1140,7 @@
     method setAttributeNS
     method setAttributeNode
     method setAttributeNodeNS
+    method setPointerCapture
     method webkitMatchesSelector
     method webkitRequestFullScreen
     method webkitRequestFullscreen
@@ -1132,6 +1153,8 @@
     setter onbeforepaste
     setter oncopy
     setter oncut
+    setter ongotpointercapture
+    setter onlostpointercapture
     setter onpaste
     setter onsearch
     setter onselectstart
@@ -1656,6 +1679,14 @@
     getter onpause
     getter onplay
     getter onplaying
+    getter onpointercancel
+    getter onpointerdown
+    getter onpointerenter
+    getter onpointerleave
+    getter onpointermove
+    getter onpointerout
+    getter onpointerover
+    getter onpointerup
     getter onprogress
     getter onratechange
     getter onreset
@@ -1738,6 +1769,14 @@
     setter onpause
     setter onplay
     setter onplaying
+    setter onpointercancel
+    setter onpointerdown
+    setter onpointerenter
+    setter onpointerleave
+    setter onpointermove
+    setter onpointerout
+    setter onpointerover
+    setter onpointerup
     setter onprogress
     setter onratechange
     setter onreset
@@ -3774,6 +3813,17 @@
     method item
     method namedItem
     method refresh
+interface PointerEvent : MouseEvent
+    attribute @@toStringTag
+    getter height
+    getter isPrimary
+    getter pointerId
+    getter pointerType
+    getter pressure
+    getter tiltX
+    getter tiltY
+    getter width
+    method constructor
 interface PopStateEvent : Event
     attribute @@toStringTag
     getter state
@@ -4174,6 +4224,14 @@
     getter onpause
     getter onplay
     getter onplaying
+    getter onpointercancel
+    getter onpointerdown
+    getter onpointerenter
+    getter onpointerleave
+    getter onpointermove
+    getter onpointerout
+    getter onpointerover
+    getter onpointerup
     getter onprogress
     getter onratechange
     getter onreset
@@ -4245,6 +4303,14 @@
     setter onpause
     setter onplay
     setter onplaying
+    setter onpointercancel
+    setter onpointerdown
+    setter onpointerenter
+    setter onpointerleave
+    setter onpointermove
+    setter onpointerout
+    setter onpointerover
+    setter onpointerup
     setter onprogress
     setter onratechange
     setter onreset
@@ -6630,6 +6696,14 @@
     attribute onpause
     attribute onplay
     attribute onplaying
+    attribute onpointercancel
+    attribute onpointerdown
+    attribute onpointerenter
+    attribute onpointerleave
+    attribute onpointermove
+    attribute onpointerout
+    attribute onpointerover
+    attribute onpointerup
     attribute onpopstate
     attribute onprogress
     attribute onratechange
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
index 8cb2736..9dbbb71 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -639,6 +639,7 @@
 [Worker]     getter caches
 [Worker]     getter crypto
 [Worker]     getter indexedDB
+[Worker]     getter isSecureContext
 [Worker]     getter location
 [Worker]     getter navigator
 [Worker]     getter onerror
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-fftsize-reset.html b/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-fftsize-reset.html
new file mode 100644
index 0000000..0f7666e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-fftsize-reset.html
@@ -0,0 +1,132 @@
+<!doctype html>
+<html>
+  <head>
+    <title>Test fftSize Changes Resetting AnalyserNode State </title>
+    <script src="../resources/testharness.js"></script>
+    <script src="../resources/testharnessreport.js"></script>
+    <script src="resources/audio-testing.js"></script>
+  </head>
+
+  <body>
+    <script>
+      // Fairly arbitrary sample rate.
+      var sampleRate = 24000;
+
+      var audit = Audit.createTaskRunner();
+
+      // Verify that setting the fftSize resets the memory for the FFT smoothing
+      // operation.  Only a few of the possible variations are tested.
+
+      audit.defineTask("128->1024", function (taskDone) {
+        testFFTSize({
+          initialFFTSize: 128,
+          finalFFTSize: 1024,
+          errorThreshold: {
+            relativeThreshold: 1.9095e-6
+          }
+        }).then(taskDone);
+      });
+
+      audit.defineTask("512->256", function (taskDone) {
+        testFFTSize({
+          initialFFTSize: 512,
+          finalFFTSize: 256,
+          errorThreshold: {
+            relativeThreshold: 1.8166e-6
+          }
+        }).then(taskDone);
+      });
+
+      function testFFTSize(options) {
+        var {
+          initialFFTSize, finalFFTSize, errorThreshold
+        } = options;
+
+        // The duration is fairly arbitrary as long as it's long enough for the
+        // FFT test.
+        var context = new OfflineAudioContext(1, sampleRate, sampleRate);
+
+        // Actual source doesn't matter but a sawtooth is a nice waveform with
+        // lots of harmonic content.
+        var osc = context.createOscillator();
+        osc.type = "sawtooth";
+
+        // The analyser under test.
+        var testAnalyser = context.createAnalyser();
+        testAnalyser.fftSize = initialFFTSize;
+
+        // The reference analyser.  The fftSize is fixed to the desired value,
+        // and we turn off smoothing so that we get the FFT of the current time
+        // data.
+        var refAnalyser = context.createAnalyser();
+        refAnalyser.fftSize = finalFFTSize;
+        refAnalyser.smoothingTimeConstant = 0;
+
+        // Setup the graph and start the oscillator.
+        osc.connect(testAnalyser)
+          .connect(context.destination);
+        osc.connect(refAnalyser)
+          .connect(context.destination);
+
+        osc.start();
+
+        // Let the analyser smooth a few FFTs (rather arbitrary, but should be
+        // more than one), then switch the size.
+
+        var suspendFrame = 4 * initialFFTSize;
+        context.suspend(suspendFrame / context.sampleRate)
+          .then(function () {
+            testAnalyser.fftSize = finalFFTSize;
+          })
+          .then(context.resume.bind(context));
+
+        // Wait some frames and grab the FFT data.  This is fairly arbitrary
+        // too, and can be independent of the FFT sizes.
+        suspendFrame += 1024;
+        context.suspend(suspendFrame / context.sampleRate)
+          .then(function () {
+            var testFFT = new Float32Array(testAnalyser.frequencyBinCount);
+            var refFFT = new Float32Array(refAnalyser.frequencyBinCount)
+            var testSignal = new Float32Array(testAnalyser.fftSize);
+            var refSignal = new Float32Array(refAnalyser.fftSize);
+
+            testAnalyser.getFloatTimeDomainData(testSignal);
+            refAnalyser.getFloatTimeDomainData(refSignal);
+
+            testAnalyser.getFloatFrequencyData(testFFT);
+            refAnalyser.getFloatFrequencyData(refFFT);
+
+            // Convert the FFT data from dB to linear
+            testFFT = testFFT.map(x => Math.pow(10, x / 20));
+            refFFT = refFFT.map(x => Math.pow(10, x / 20));
+
+            // The test data has smoothing applied, but the reference doesn't.
+            // Apply the smoothing factor to the reference data.
+            var smoothing = 1 - testAnalyser.smoothingTimeConstant;
+            refFFT = refFFT.map(x => x * smoothing);
+
+            var success = true;
+
+            // First a basic sanity check that the time domain signals are
+            // exactly the same for both analysers.
+            success = Should("Time data", testSignal)
+              .beCloseToArray(refSignal, 0) && success;
+
+            success = Should("Linear FFT data after setting fftSize = " + testAnalyser.fftSize,
+                testFFT)
+              .beCloseToArray(refFFT, errorThreshold) && success;
+
+            Should("*** Changing fftSize from " + initialFFTSize + " to " + finalFFTSize, success)
+              .summarize(
+                 "correctly reset the smoothing state",
+                "did not correctly reset the smoothing state");
+          })
+          .then(context.resume.bind(context));
+
+        return context.startRendering();
+      }
+
+      audit.runTasks();
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
index a188207..452060f 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -1223,6 +1223,7 @@
 [Worker]     getter caches
 [Worker]     getter crypto
 [Worker]     getter indexedDB
+[Worker]     getter isSecureContext
 [Worker]     getter location
 [Worker]     getter navigator
 [Worker]     getter onerror
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index acb1388..401c0797 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -567,7 +567,6 @@
     getter type
     getter value
     method constructor
-    setter value
 interface CSSSkew : CSSTransformComponent
     attribute @@toStringTag
     getter ax
@@ -4075,7 +4074,6 @@
     getter permissions
     getter platform
     getter plugins
-    getter pointerEnabled
     getter presentation
     getter product
     getter productSub
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
index ef47bfe8a..a62dbd9 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -1215,6 +1215,7 @@
 [Worker]     getter caches
 [Worker]     getter crypto
 [Worker]     getter indexedDB
+[Worker]     getter isSecureContext
 [Worker]     getter location
 [Worker]     getter navigator
 [Worker]     getter onerror
diff --git a/third_party/WebKit/PRESUBMIT.py b/third_party/WebKit/PRESUBMIT.py
index c385157..030099cc 100644
--- a/third_party/WebKit/PRESUBMIT.py
+++ b/third_party/WebKit/PRESUBMIT.py
@@ -22,7 +22,7 @@
     for f in input_api.AffectedFiles():
         for line_num, line in f.ChangedContents():
             m = pattern.match(line)
-            if m and m.group(1) != '-blink':
+            if m and m.group(1) != '-blink' and m.group(1) != '-shared':
                 errors.append('    %s:%d %s' % (
                     f.LocalPath(), line_num, line))
 
diff --git a/third_party/WebKit/Source/bindings/bindings.gni b/third_party/WebKit/Source/bindings/bindings.gni
index 8009e6b..b3b8906c 100644
--- a/third_party/WebKit/Source/bindings/bindings.gni
+++ b/third_party/WebKit/Source/bindings/bindings.gni
@@ -184,8 +184,6 @@
                     "core/v8/V8PagePopupControllerBinding.h",
                     "core/v8/V8PerContextData.cpp",
                     "core/v8/V8PerContextData.h",
-                    "core/v8/V8PerformanceObserverCallback.cpp",
-                    "core/v8/V8PerformanceObserverCallback.h",
                     "core/v8/V8PerIsolateData.cpp",
                     "core/v8/V8PerIsolateData.h",
                     "core/v8/V8PersistentValueVector.h",
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8PerformanceObserverCallback.cpp b/third_party/WebKit/Source/bindings/core/v8/V8PerformanceObserverCallback.cpp
deleted file mode 100644
index 10347a3..0000000
--- a/third_party/WebKit/Source/bindings/core/v8/V8PerformanceObserverCallback.cpp
+++ /dev/null
@@ -1,42 +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.
-
-// This file has been auto-generated by code_generator_v8.py. DO NOT MODIFY!
-
-#include "bindings/core/v8/V8PerformanceObserverCallback.h"
-
-#include "bindings/core/v8/ScriptController.h"
-#include "bindings/core/v8/V8Binding.h"
-#include "bindings/core/v8/V8PerformanceObserver.h"
-#include "bindings/core/v8/V8PerformanceObserverEntryList.h"
-#include "bindings/core/v8/V8PrivateProperty.h"
-#include "core/dom/ExecutionContext.h"
-#include "wtf/Assertions.h"
-
-namespace blink {
-
-V8PerformanceObserverCallback::V8PerformanceObserverCallback(v8::Local<v8::Function> callback, v8::Local<v8::Object> owner, ScriptState* scriptState)
-    : m_callback(V8PerformanceObserverInnerCallback::create(scriptState->isolate(), callback))
-    , m_scriptState(scriptState)
-{
-    V8PrivateProperty::getPerformanceObserverCallback(scriptState->isolate()).set(scriptState->context(), owner, m_callback->v8Value(scriptState->isolate()));
-}
-
-V8PerformanceObserverCallback::~V8PerformanceObserverCallback()
-{
-}
-
-void V8PerformanceObserverCallback::handleEvent(PerformanceObserverEntryList* entries, PerformanceObserver* observer)
-{
-    TrackExceptionState exceptionState;
-    m_callback->call(m_scriptState.get(), observer, exceptionState, entries, observer);
-}
-
-DEFINE_TRACE(V8PerformanceObserverCallback)
-{
-    visitor->trace(m_callback);
-    PerformanceObserverCallback::trace(visitor);
-}
-
-} // namespace blink
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8PerformanceObserverCallback.h b/third_party/WebKit/Source/bindings/core/v8/V8PerformanceObserverCallback.h
deleted file mode 100644
index 19d1d7e2..0000000
--- a/third_party/WebKit/Source/bindings/core/v8/V8PerformanceObserverCallback.h
+++ /dev/null
@@ -1,37 +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 V8PerformanceObserverCallback_h
-#define V8PerformanceObserverCallback_h
-
-#include "bindings/core/v8/ActiveDOMCallback.h"
-#include "bindings/core/v8/DOMWrapperWorld.h"
-#include "bindings/core/v8/ScopedPersistent.h"
-#include "bindings/core/v8/V8PerformanceObserverInnerCallback.h"
-#include "core/CoreExport.h"
-#include "core/timing/PerformanceObserverCallback.h"
-
-namespace blink {
-
-class V8PerformanceObserverCallback final : public PerformanceObserverCallback {
-public:
-    static V8PerformanceObserverCallback* create(v8::Local<v8::Function> callback, v8::Local<v8::Object> owner, ScriptState* scriptState)
-    {
-        return new V8PerformanceObserverCallback(callback, owner, scriptState);
-    }
-
-    ~V8PerformanceObserverCallback() override;
-
-    DECLARE_VIRTUAL_TRACE();
-
-    void handleEvent(PerformanceObserverEntryList*, PerformanceObserver*) override;
-private:
-    CORE_EXPORT V8PerformanceObserverCallback(v8::Local<v8::Function>, v8::Local<v8::Object>, ScriptState*);
-
-    Member<V8PerformanceObserverInnerCallback> m_callback;
-    RefPtr<ScriptState> m_scriptState;
-};
-
-} // namespace blink
-#endif // V8PerformanceObserverCallback_h
diff --git a/third_party/WebKit/Source/bindings/core/v8/custom/V8PerformanceObserverCustom.cpp b/third_party/WebKit/Source/bindings/core/v8/custom/V8PerformanceObserverCustom.cpp
index 03c0b8a..b006753 100644
--- a/third_party/WebKit/Source/bindings/core/v8/custom/V8PerformanceObserverCustom.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/custom/V8PerformanceObserverCustom.cpp
@@ -9,7 +9,7 @@
 #include "bindings/core/v8/V8DOMWrapper.h"
 #include "bindings/core/v8/V8GCController.h"
 #include "bindings/core/v8/V8Performance.h"
-#include "bindings/core/v8/V8PerformanceObserverCallback.h"
+#include "bindings/core/v8/V8PerformanceObserverInnerCallback.h"
 #include "core/timing/DOMWindowPerformance.h"
 #include "core/timing/PerformanceObserver.h"
 
@@ -33,14 +33,12 @@
     performance = DOMWindowPerformance::performance(*window);
     ASSERT(performance);
 
-    PerformanceObserverCallback* callback;
-    {
-        if (info.Length() <= 0 || !info[0]->IsFunction()) {
-            V8ThrowException::throwTypeError(info.GetIsolate(), ExceptionMessages::failedToConstruct("PerformanceObserver", "The callback provided as parameter 1 is not a function."));
-            return;
-        }
-        callback = V8PerformanceObserverCallback::create(v8::Local<v8::Function>::Cast(info[0]), wrapper, ScriptState::current(info.GetIsolate()));
+    if (info.Length() <= 0 || !info[0]->IsFunction()) {
+        V8ThrowException::throwTypeError(info.GetIsolate(), ExceptionMessages::failedToConstruct("PerformanceObserver", "The callback provided as parameter 1 is not a function."));
+        return;
     }
+    V8PerformanceObserverInnerCallback* callback = V8PerformanceObserverInnerCallback::create(info.GetIsolate(), v8::Local<v8::Function>::Cast(info[0]));
+
     PerformanceObserver* observer = PerformanceObserver::create(ScriptState::forReceiverObject(info), performance, callback);
 
     v8SetReturnValue(info, V8DOMWrapper::associateObjectWithWrapper(info.GetIsolate(), observer, &wrapperTypeInfo, wrapper));
diff --git a/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueDeserializer.cpp b/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueDeserializer.cpp
index a17ec2f5..7c3fc340 100644
--- a/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueDeserializer.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueDeserializer.cpp
@@ -5,6 +5,7 @@
 #include "bindings/core/v8/serialization/V8ScriptValueDeserializer.h"
 
 #include "bindings/core/v8/ToV8.h"
+#include "core/dom/CompositorProxy.h"
 #include "core/dom/DOMArrayBuffer.h"
 #include "core/dom/DOMSharedArrayBuffer.h"
 #include "core/dom/MessagePort.h"
@@ -13,6 +14,7 @@
 #include "core/html/ImageData.h"
 #include "core/offscreencanvas/OffscreenCanvas.h"
 #include "platform/RuntimeEnabledFeatures.h"
+#include "platform/graphics/CompositorMutableProperties.h"
 #include "public/platform/WebBlobInfo.h"
 #include "wtf/CheckedNumeric.h"
 
@@ -124,6 +126,18 @@
         const WebBlobInfo& info = (*m_blobInfoArray)[index];
         return Blob::create(getOrCreateBlobDataHandle(info.uuid(), info.type(), info.size()));
     }
+    case CompositorProxyTag: {
+        uint64_t element;
+        uint32_t properties;
+        const uint32_t validPropertiesMask = static_cast<uint32_t>(
+            (1u << CompositorMutableProperty::kNumProperties) - 1);
+        if (!RuntimeEnabledFeatures::compositorWorkerEnabled()
+            || !readUint64(&element)
+            || !readUint32(&properties)
+            || (properties & ~validPropertiesMask))
+            return nullptr;
+        return CompositorProxy::create(m_scriptState->getExecutionContext(), element, properties);
+    }
     case ImageBitmapTag: {
         uint32_t originClean = 0, isPremultiplied = 0, width = 0, height = 0, pixelLength = 0;
         const void* pixels = nullptr;
diff --git a/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueSerializer.cpp b/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueSerializer.cpp
index 5c2eab4a..6597301 100644
--- a/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueSerializer.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueSerializer.cpp
@@ -6,6 +6,7 @@
 
 #include "bindings/core/v8/ToV8.h"
 #include "bindings/core/v8/V8Blob.h"
+#include "bindings/core/v8/V8CompositorProxy.h"
 #include "bindings/core/v8/V8ImageBitmap.h"
 #include "bindings/core/v8/V8ImageData.h"
 #include "bindings/core/v8/V8MessagePort.h"
@@ -147,6 +148,22 @@
         }
         return true;
     }
+    if (wrapperTypeInfo == &V8CompositorProxy::wrapperTypeInfo) {
+        DCHECK(RuntimeEnabledFeatures::compositorWorkerEnabled());
+        CompositorProxy* proxy = wrappable->toImpl<CompositorProxy>();
+        if (!proxy->connected()) {
+            exceptionState.throwDOMException(DataCloneError,
+                "A CompositorProxy object has been disconnected, and could therefore not be cloned.");
+            return false;
+        }
+        // TODO(jbroman): This seems likely to break in cross-process or
+        // persistent scenarios. Keeping as-is for now because the successor
+        // does not use this approach (and this feature is unshipped).
+        writeTag(CompositorProxyTag);
+        writeUint64(proxy->elementId());
+        writeUint32(proxy->compositorMutableProperties());
+        return true;
+    }
     if (wrapperTypeInfo == &V8ImageBitmap::wrapperTypeInfo) {
         ImageBitmap* imageBitmap = wrappable->toImpl<ImageBitmap>();
         if (imageBitmap->isNeutered()) {
diff --git a/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueSerializerTest.cpp b/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueSerializerTest.cpp
index b8f04cc2..38e45a0 100644
--- a/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueSerializerTest.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueSerializerTest.cpp
@@ -9,6 +9,7 @@
 #include "bindings/core/v8/ScriptSourceCode.h"
 #include "bindings/core/v8/V8BindingForTesting.h"
 #include "bindings/core/v8/V8Blob.h"
+#include "bindings/core/v8/V8CompositorProxy.h"
 #include "bindings/core/v8/V8DOMException.h"
 #include "bindings/core/v8/V8ImageBitmap.h"
 #include "bindings/core/v8/V8ImageData.h"
@@ -16,12 +17,14 @@
 #include "bindings/core/v8/V8OffscreenCanvas.h"
 #include "bindings/core/v8/V8StringResource.h"
 #include "bindings/core/v8/serialization/V8ScriptValueDeserializer.h"
+#include "core/dom/CompositorProxy.h"
 #include "core/dom/MessagePort.h"
 #include "core/fileapi/Blob.h"
 #include "core/frame/LocalFrame.h"
 #include "core/html/ImageData.h"
 #include "core/offscreencanvas/OffscreenCanvas.h"
 #include "platform/RuntimeEnabledFeatures.h"
+#include "platform/graphics/CompositorMutableProperties.h"
 #include "platform/graphics/StaticBitmapImage.h"
 #include "public/platform/WebBlobInfo.h"
 #include "public/platform/WebMessagePortChannel.h"
@@ -598,5 +601,43 @@
     }
 }
 
+class ScopedEnableCompositorWorker {
+public:
+    ScopedEnableCompositorWorker()
+        : m_wasEnabled(RuntimeEnabledFeatures::compositorWorkerEnabled())
+    {
+        RuntimeEnabledFeatures::setCompositorWorkerEnabled(true);
+    }
+    ~ScopedEnableCompositorWorker()
+    {
+        RuntimeEnabledFeatures::setCompositorWorkerEnabled(m_wasEnabled);
+    }
+private:
+    bool m_wasEnabled;
+};
+
+TEST(V8ScriptValueSerializerTest, RoundTripCompositorProxy)
+{
+    ScopedEnableCompositorWorker enableCompositorWorker;
+    ScopedEnableV8BasedStructuredClone enable;
+    V8TestingScope scope;
+    HTMLElement* element = scope.document().body();
+    Vector<String> properties{"transform"};
+    CompositorProxy* proxy = CompositorProxy::create(scope.getExecutionContext(), element, properties, ASSERT_NO_EXCEPTION);
+    uint64_t elementId = proxy->elementId();
+
+    v8::Local<v8::Value> wrapper = toV8(proxy, scope.getScriptState());
+    v8::Local<v8::Value> result = roundTrip(wrapper, scope);
+    ASSERT_TRUE(V8CompositorProxy::hasInstance(result, scope.isolate()));
+    CompositorProxy* newProxy = V8CompositorProxy::toImpl(result.As<v8::Object>());
+    EXPECT_EQ(elementId, newProxy->elementId());
+    EXPECT_EQ(CompositorMutableProperty::kTransform, newProxy->compositorMutableProperties());
+}
+
+// Decode tests aren't included here because they're slightly non-trivial (an
+// element with the right ID must actually exist) and this feature is both
+// unshipped and likely to not use this mechanism when it does.
+// TODO(jbroman): Update this if that turns out not to be the case.
+
 } // namespace
 } // namespace blink
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 06db1cc..c5ccc7a 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
@@ -42,22 +42,37 @@
             'size',
             # Default value for field
             'default_value',
+            # Method names
+            'getter_method_name',
+            'setter_method_name',
+            'initial_method_name',
+            'resetter_method_name',
         ])
         self._fields = []
         for property in self._properties.values():
             if property['keyword_only']:
+                property_name = property['upper_camel_name']
+                if property['name_for_methods']:
+                    property_name = property['name_for_methods']
+                property_name_lower = property_name[0].lower() + property_name[1:]
+
                 # From the Blink style guide: Other data members should be prefixed by "m_". [names-data-members]
-                field_name = 'm_' + property['lower_camel_name']
+                field_name = 'm_' + property_name_lower
                 bits_needed = math.log(len(property['keywords']), 2)
                 type_name = property['type_name']
                 # For now, assume the default value is the first enum value.
                 default_value = type_name + '::' + self._computed_enums[type_name][0]
+
                 self._fields.append(Field(
                     name=field_name,
                     property=property,
                     type=type_name,
                     size=int(math.ceil(bits_needed)),
                     default_value=default_value,
+                    getter_method_name=property_name_lower,
+                    setter_method_name='set' + property_name,
+                    initial_method_name='initial' + property_name,
+                    resetter_method_name='reset' + property_name,
                 ))
 
     @template_expander.use_jinja('ComputedStyleBase.h.tmpl')
diff --git a/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.cpp.tmpl b/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.cpp.tmpl
index d73b9934..d3ac50f 100644
--- a/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.cpp.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.cpp.tmpl
@@ -12,4 +12,11 @@
     {% endfor %}
 }
 
+void ComputedStyleBase::copyNonInheritedFromCached(const ComputedStyleBase& other)
+{
+    {% for field in fields if not field.property['inherited'] %}
+    {{field.name}} = other.{{field.name}};
+    {% endfor %}
+}
+
 } // namespace blink
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 f71516fe..5c8bdb9f 100644
--- a/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.h.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.h.tmpl
@@ -83,7 +83,7 @@
     void setBitDefaults()
     {
         {% for field in fields %}
-        reset{{field.property['upper_camel_name']}}();
+        {{field.resetter_method_name}}();
         {% endfor %}
     }
 
@@ -93,15 +93,17 @@
     };
     void inheritFrom(const ComputedStyleBase& inheritParent, IsAtShadowBoundary isAtShadowBoundary = NotAtShadowBoundary);
 
+    void copyNonInheritedFromCached(const ComputedStyleBase& other);
+
     // Fields.
     // TODO(sashab): Remove initialFoo() static methods and update callers to
     // use resetFoo(), which can be more efficient.
     {% for field in fields %}
     // {{field.property['name']}}
-    inline static {{field.type}} initial{{field.property['upper_camel_name']}}() { return {{field.default_value}}; }
-    {{field.type}} {{field.property['lower_camel_name']}}() const { return static_cast<{{field.type}}>({{field.name}}); }
-    void set{{field.property['upper_camel_name']}}({{field.type}} v) { {{field.name}} = static_cast<unsigned>(v); }
-    inline void reset{{field.property['upper_camel_name']}}() { {{field.name}} = {{default_value(field)}}; }
+    inline static {{field.type}} {{field.initial_method_name}}() { return {{field.default_value}}; }
+    {{field.type}} {{field.getter_method_name}}() const { return static_cast<{{field.type}}>({{field.name}}); }
+    void {{field.setter_method_name}}({{field.type}} v) { {{field.name}} = static_cast<unsigned>(v); }
+    inline void {{field.resetter_method_name}}() { {{field.name}} = {{default_value(field)}}; }
 
     {% endfor %}
 protected:
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn
index f76ebcd..62b1e7b 100644
--- a/third_party/WebKit/Source/core/BUILD.gn
+++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -1206,6 +1206,7 @@
     "paint/VideoPainterTest.cpp",
     "streams/ReadableStreamOperationsTest.cpp",
     "style/ComputedStyleTest.cpp",
+    "style/FilterOperationsTest.cpp",
     "style/OutlineValueTest.cpp",
     "style/SVGComputedStyleTest.cpp",
     "svg/SVGPathParserTest.cpp",
diff --git a/third_party/WebKit/Source/core/animation/Animation.cpp b/third_party/WebKit/Source/core/animation/Animation.cpp
index b34fac99..09f13bd 100644
--- a/third_party/WebKit/Source/core/animation/Animation.cpp
+++ b/third_party/WebKit/Source/core/animation/Animation.cpp
@@ -33,6 +33,7 @@
 #include "core/animation/AnimationTimeline.h"
 #include "core/animation/CompositorPendingAnimations.h"
 #include "core/animation/KeyframeEffect.h"
+#include "core/animation/css/CSSAnimations.h"
 #include "core/dom/Document.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/dom/StyleChangeReason.h"
@@ -1086,12 +1087,15 @@
     cancelAnimationOnCompositor();
 }
 
-void Animation::invalidateKeyframeEffect()
+void Animation::invalidateKeyframeEffect(const TreeScope& treeScope)
 {
     if (!m_content || !m_content->isKeyframeEffect())
         return;
 
-    toKeyframeEffect(m_content.get())->target()->setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::StyleSheetChange));
+    Element& target = *toKeyframeEffect(m_content.get())->target();
+
+    if (CSSAnimations::isAffectedByKeyframesFromScope(target, treeScope))
+        target.setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::StyleSheetChange));
 }
 
 DEFINE_TRACE(Animation)
diff --git a/third_party/WebKit/Source/core/animation/Animation.h b/third_party/WebKit/Source/core/animation/Animation.h
index 72196c6..372d527 100644
--- a/third_party/WebKit/Source/core/animation/Animation.h
+++ b/third_party/WebKit/Source/core/animation/Animation.h
@@ -53,6 +53,7 @@
 class CompositorAnimationPlayer;
 class Element;
 class ExceptionState;
+class TreeScope;
 
 class CORE_EXPORT Animation final
     : public EventTargetWithInlineData
@@ -182,7 +183,7 @@
     bool effectSuppressed() const { return m_effectSuppressed; }
     void setEffectSuppressed(bool);
 
-    void invalidateKeyframeEffect();
+    void invalidateKeyframeEffect(const TreeScope&);
 
     DECLARE_VIRTUAL_TRACE();
 
diff --git a/third_party/WebKit/Source/core/animation/AnimationTimeline.cpp b/third_party/WebKit/Source/core/animation/AnimationTimeline.cpp
index b2c2c6a..52101b6d 100644
--- a/third_party/WebKit/Source/core/animation/AnimationTimeline.cpp
+++ b/third_party/WebKit/Source/core/animation/AnimationTimeline.cpp
@@ -331,10 +331,10 @@
     return m_playbackRate;
 }
 
-void AnimationTimeline::invalidateKeyframeEffects()
+void AnimationTimeline::invalidateKeyframeEffects(const TreeScope& treeScope)
 {
     for (const auto& animation : m_animations)
-        animation->invalidateKeyframeEffect();
+        animation->invalidateKeyframeEffect(treeScope);
 }
 
 DEFINE_TRACE(AnimationTimeline)
diff --git a/third_party/WebKit/Source/core/animation/AnimationTimeline.h b/third_party/WebKit/Source/core/animation/AnimationTimeline.h
index 196dedd..22f2200 100644
--- a/third_party/WebKit/Source/core/animation/AnimationTimeline.h
+++ b/third_party/WebKit/Source/core/animation/AnimationTimeline.h
@@ -90,7 +90,7 @@
     void clearOutdatedAnimation(Animation*);
     bool hasOutdatedAnimation() const { return m_outdatedAnimationCount > 0; }
     bool needsAnimationTimingUpdate();
-    void invalidateKeyframeEffects();
+    void invalidateKeyframeEffects(const TreeScope&);
 
     void setPlaybackRate(double);
     double playbackRate() const;
diff --git a/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp b/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp
index 65521bad..4e57eb8 100644
--- a/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp
+++ b/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp
@@ -42,13 +42,13 @@
 #include "core/animation/animatable/AnimatableValueTestHelper.h"
 #include "core/dom/Document.h"
 #include "core/layout/LayoutObject.h"
+#include "core/style/FilterOperations.h"
 #include "core/testing/DummyPageHolder.h"
 #include "platform/animation/CompositorAnimation.h"
 #include "platform/animation/CompositorFloatAnimationCurve.h"
 #include "platform/animation/CompositorFloatKeyframe.h"
 #include "platform/geometry/FloatBox.h"
 #include "platform/geometry/IntSize.h"
-#include "platform/graphics/filters/FilterOperations.h"
 #include "platform/transforms/TransformOperations.h"
 #include "platform/transforms/TranslateTransformOperation.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/third_party/WebKit/Source/core/animation/FilterInterpolationFunctions.cpp b/third_party/WebKit/Source/core/animation/FilterInterpolationFunctions.cpp
index bd64c09..5f2e8ec 100644
--- a/third_party/WebKit/Source/core/animation/FilterInterpolationFunctions.cpp
+++ b/third_party/WebKit/Source/core/animation/FilterInterpolationFunctions.cpp
@@ -10,8 +10,8 @@
 #include "core/css/CSSPrimitiveValue.h"
 #include "core/css/resolver/FilterOperationResolver.h"
 #include "core/css/resolver/StyleResolverState.h"
+#include "core/style/FilterOperations.h"
 #include "core/style/ShadowData.h"
-#include "platform/graphics/filters/FilterOperations.h"
 #include <memory>
 
 namespace blink {
diff --git a/third_party/WebKit/Source/core/animation/KeyframeEffect.cpp b/third_party/WebKit/Source/core/animation/KeyframeEffect.cpp
index a7ed1922..e57963ee4 100644
--- a/third_party/WebKit/Source/core/animation/KeyframeEffect.cpp
+++ b/third_party/WebKit/Source/core/animation/KeyframeEffect.cpp
@@ -162,7 +162,7 @@
         || animation()->affects(*m_target, CSSPropertyTranslate);
 
     if (animation()->hasActiveAnimationsOnCompositor()) {
-        if (m_target->computedStyle()->hasOffsetPath() && affectsTransform)
+        if (m_target->computedStyle()->hasOffset() && affectsTransform)
             return true;
         return hasMultipleTransformProperties();
     }
@@ -281,7 +281,7 @@
     // in computed style because they need to be explicitly ordered
     if (!model()
         || !m_target
-        || (m_target->computedStyle() && m_target->computedStyle()->hasOffsetPath())
+        || (m_target->computedStyle() && m_target->computedStyle()->hasOffset())
         || hasMultipleTransformProperties())
         return false;
 
diff --git a/third_party/WebKit/Source/core/animation/animatable/AnimatableFilterOperations.h b/third_party/WebKit/Source/core/animation/animatable/AnimatableFilterOperations.h
index a445085..ff3366b 100644
--- a/third_party/WebKit/Source/core/animation/animatable/AnimatableFilterOperations.h
+++ b/third_party/WebKit/Source/core/animation/animatable/AnimatableFilterOperations.h
@@ -32,7 +32,7 @@
 #define AnimatableFilterOperations_h
 
 #include "core/animation/animatable/AnimatableValue.h"
-#include "platform/graphics/filters/FilterOperations.h"
+#include "core/style/FilterOperations.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp b/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp
index 9de013e..5eff4e8 100644
--- a/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp
+++ b/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp
@@ -306,10 +306,8 @@
             timing.timingFunction = Timing::defaults().timingFunction;
 
             StyleRuleKeyframes* keyframesRule = resolver->findKeyframesRule(elementForScoping, name);
-            if (!keyframesRule) {
-                element.document().styleEngine().setHasUnresolvedKeyframesRule();
+            if (!keyframesRule)
                 continue; // Cancel the animation if there's no style rule for it.
-            }
 
             const RunningAnimation* existingAnimation = nullptr;
             size_t existingAnimationIndex = 0;
@@ -896,6 +894,19 @@
     }
 }
 
+bool CSSAnimations::isAffectedByKeyframesFromScope(const Element& element, const TreeScope& treeScope)
+{
+    // Animated elements are affected by @keyframes rules from the same scope
+    // and from their shadow sub-trees if they are shadow hosts.
+    if (element.treeScope() == treeScope)
+        return true;
+    if (!isShadowHost(element))
+        return false;
+    if (treeScope.rootNode() == treeScope.document())
+        return false;
+    return toShadowRoot(treeScope.rootNode()).host() == element;
+}
+
 DEFINE_TRACE(CSSAnimations)
 {
     visitor->trace(m_transitions);
diff --git a/third_party/WebKit/Source/core/animation/css/CSSAnimations.h b/third_party/WebKit/Source/core/animation/css/CSSAnimations.h
index f3bc9a7f..273f366 100644
--- a/third_party/WebKit/Source/core/animation/css/CSSAnimations.h
+++ b/third_party/WebKit/Source/core/animation/css/CSSAnimations.h
@@ -61,6 +61,7 @@
 
     static const StylePropertyShorthand& propertiesForTransitionAll();
     static bool isAnimatableProperty(CSSPropertyID);
+    static bool isAffectedByKeyframesFromScope(const Element&, const TreeScope&);
     static void calculateUpdate(const Element* animatingElement, Element&, const ComputedStyle&, ComputedStyle* parentStyle, CSSAnimationUpdate&, StyleResolver*);
     static void snapshotCompositorKeyframes(Element&, CSSAnimationUpdate&, const ComputedStyle&, const ComputedStyle* parentStyle);
 
diff --git a/third_party/WebKit/Source/core/css/CSSCustomPropertyDeclaration.h b/third_party/WebKit/Source/core/css/CSSCustomPropertyDeclaration.h
index 1b1aaf2d..8692cbbf 100644
--- a/third_party/WebKit/Source/core/css/CSSCustomPropertyDeclaration.h
+++ b/third_party/WebKit/Source/core/css/CSSCustomPropertyDeclaration.h
@@ -26,7 +26,10 @@
 
     const AtomicString& name() const { return m_name; }
     CSSVariableData* value() const { return m_value.get(); }
-    CSSValueID id() const { return m_valueId; }
+
+    bool isInherit(bool isInheritedProperty) const { return m_valueId == CSSValueInherit || (isInheritedProperty && m_valueId == CSSValueUnset); }
+    bool isInitial(bool isInheritedProperty) const { return m_valueId == CSSValueInitial || (!isInheritedProperty && m_valueId == CSSValueUnset); }
+
     String customCSSText() const;
 
     bool equals(const CSSCustomPropertyDeclaration& other) const { return this == &other; }
@@ -46,7 +49,7 @@
         : CSSValue(CustomPropertyDeclarationClass)
         , m_name(name)
         , m_value(value)
-        , m_valueId(CSSValueInternalVariableValue)
+        , m_valueId(CSSValueInvalid)
     {
     }
 
diff --git a/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h b/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
index bd68759..92a1774 100644
--- a/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
+++ b/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
@@ -466,10 +466,10 @@
         m_value.valueID = CSSValueInternalMediaSubtitlesIcon;
         break;
     case MediaOverflowMenuButtonPart:
-        m_value.valueID = CSSValueInternalOverflowMenuButton;
+        m_value.valueID = CSSValueInternalMediaOverflowButton;
         break;
     case MediaDownloadIconPart:
-        m_value.valueID = CSSValueInternalMediaDownloadIcon;
+        m_value.valueID = CSSValueInternalMediaDownloadButton;
         break;
     case MenulistPart:
         m_value.valueID = CSSValueMenulist;
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.in b/third_party/WebKit/Source/core/css/CSSProperties.in
index 3616995..7cc4bb4 100644
--- a/third_party/WebKit/Source/core/css/CSSProperties.in
+++ b/third_party/WebKit/Source/core/css/CSSProperties.in
@@ -225,7 +225,7 @@
 flex-grow interpolable, type_name=float
 flex-shrink interpolable, type_name=float
 flex-wrap
-float type_name=EFloat, name_for_methods=Floating
+float type_name=EFloat, name_for_methods=Floating, keyword_only, keywords=[none|left|right]
 flood-color interpolable, svg, converter=convertColor
 flood-opacity interpolable, svg, converter=convertNumberOrPercentage
 grid-auto-columns runtime_flag=CSSGridLayout, converter=convertGridTrackSizeList
diff --git a/third_party/WebKit/Source/core/css/CSSValueKeywords.in b/third_party/WebKit/Source/core/css/CSSValueKeywords.in
index 80fbeff..7bba082 100644
--- a/third_party/WebKit/Source/core/css/CSSValueKeywords.in
+++ b/third_party/WebKit/Source/core/css/CSSValueKeywords.in
@@ -648,8 +648,8 @@
 -internal-media-track-selection-checkmark
 -internal-media-closed-captions-icon
 -internal-media-subtitles-icon
--internal-overflow-menu-button
--internal-media-download-icon
+-internal-media-overflow-button
+-internal-media-download-button
 menulist
 menulist-button
 menulist-text
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
index d95f1f6..0201420 100644
--- a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
+++ b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
@@ -63,7 +63,8 @@
 #include "core/style/CursorData.h"
 #include "core/style/QuotesData.h"
 #include "core/style/ShadowList.h"
-#include "core/style/StyleVariableData.h"
+#include "core/style/StyleInheritedVariables.h"
+#include "core/style/StyleNonInheritedVariables.h"
 #include "platform/LengthFunctions.h"
 
 namespace blink {
@@ -1648,19 +1649,24 @@
 
 const CSSValue* ComputedStyleCSSValueMapping::get(const AtomicString customPropertyName, const ComputedStyle& style, const PropertyRegistry* registry)
 {
-    StyleVariableData* variables = style.variables();
     if (registry) {
         const PropertyRegistry::Registration* registration = registry->registration(customPropertyName);
         if (registration) {
-            if (variables) {
-                const CSSValue* result = variables->registeredInheritedProperty(customPropertyName);
-                if (result)
-                    return result;
+            const CSSValue* result = nullptr;
+            if (registration->inherits()) {
+                if (StyleInheritedVariables* variables = style.inheritedVariables())
+                    result = variables->registeredVariable(customPropertyName);
+            } else {
+                if (StyleNonInheritedVariables* variables = style.nonInheritedVariables())
+                    result = variables->registeredVariable(customPropertyName);
             }
+            if (result)
+                return result;
             return registration->initial();
         }
     }
 
+    StyleInheritedVariables* variables = style.inheritedVariables();
     if (!variables)
         return nullptr;
 
@@ -1673,7 +1679,8 @@
 
 std::unique_ptr<HashMap<AtomicString, RefPtr<CSSVariableData>>> ComputedStyleCSSValueMapping::getVariables(const ComputedStyle& style)
 {
-    StyleVariableData* variables = style.variables();
+    // TODO(timloh): Also return non-inherited variables
+    StyleInheritedVariables* variables = style.inheritedVariables();
     if (variables)
         return variables->getVariables();
     return nullptr;
diff --git a/third_party/WebKit/Source/core/css/PropertyRegistry.cpp b/third_party/WebKit/Source/core/css/PropertyRegistry.cpp
index c23bc11..e8d61870 100644
--- a/third_party/WebKit/Source/core/css/PropertyRegistry.cpp
+++ b/third_party/WebKit/Source/core/css/PropertyRegistry.cpp
@@ -9,8 +9,6 @@
 void PropertyRegistry::registerProperty(const AtomicString& name, const CSSSyntaxDescriptor& syntax, bool inherits, const CSSValue* initial, PassRefPtr<CSSVariableData> initialVariableData)
 {
     DCHECK(!registration(name));
-    // TODO(timloh): We only support inherited properties for now.
-    inherits = true;
     m_registrations.set(name, new Registration(syntax, inherits, initial, initialVariableData));
 }
 
diff --git a/third_party/WebKit/Source/core/css/StyleMedia.cpp b/third_party/WebKit/Source/core/css/StyleMedia.cpp
index 9fdbe32..3e0eb0d5 100644
--- a/third_party/WebKit/Source/core/css/StyleMedia.cpp
+++ b/third_party/WebKit/Source/core/css/StyleMedia.cpp
@@ -40,7 +40,7 @@
 
 AtomicString StyleMedia::type() const
 {
-    FrameView* view = m_frame ? m_frame->view() : nullptr;
+    FrameView* view = frame() ? frame()->view() : nullptr;
     if (view)
         return view->mediaType();
 
@@ -49,10 +49,10 @@
 
 bool StyleMedia::matchMedium(const String& query) const
 {
-    if (!m_frame)
+    if (!frame())
         return false;
 
-    Document* document = m_frame->document();
+    Document* document = frame()->document();
     ASSERT(document);
     Element* documentElement = document->documentElement();
     if (!documentElement)
@@ -62,7 +62,7 @@
     if (!media->set(query))
         return false;
 
-    MediaQueryEvaluator screenEval(m_frame);
+    MediaQueryEvaluator screenEval(frame());
     return screenEval.eval(media);
 }
 
diff --git a/third_party/WebKit/Source/core/css/StyleSheetContents.cpp b/third_party/WebKit/Source/core/css/StyleSheetContents.cpp
index 9ad89008..68cec61 100644
--- a/third_party/WebKit/Source/core/css/StyleSheetContents.cpp
+++ b/third_party/WebKit/Source/core/css/StyleSheetContents.cpp
@@ -32,6 +32,7 @@
 #include "core/fetch/CSSStyleSheetResource.h"
 #include "core/frame/UseCounter.h"
 #include "core/inspector/InspectorTraceEvents.h"
+#include "platform/Histogram.h"
 #include "platform/TraceEvent.h"
 #include "platform/weborigin/SecurityOrigin.h"
 
@@ -319,6 +320,7 @@
 void StyleSheetContents::parseAuthorStyleSheet(const CSSStyleSheetResource* cachedStyleSheet, const SecurityOrigin* securityOrigin)
 {
     TRACE_EVENT1("blink,devtools.timeline", "ParseAuthorStyleSheet", "data", InspectorParseAuthorStyleSheetEvent::data(cachedStyleSheet));
+    SCOPED_BLINK_UMA_HISTOGRAM_TIMER("Style.AuthorStyleSheet.ParseTime");
 
     bool isSameOriginRequest = securityOrigin && securityOrigin->canRequest(baseURL());
 
diff --git a/third_party/WebKit/Source/core/css/cssom/CSSCalcLength.cpp b/third_party/WebKit/Source/core/css/cssom/CSSCalcLength.cpp
index 878ed5b..b2455c6 100644
--- a/third_party/WebKit/Source/core/css/cssom/CSSCalcLength.cpp
+++ b/third_party/WebKit/Source/core/css/cssom/CSSCalcLength.cpp
@@ -4,6 +4,7 @@
 
 #include "core/css/cssom/CSSCalcLength.h"
 
+#include "bindings/core/v8/ExceptionState.h"
 #include "core/css/CSSCalculationValue.h"
 #include "core/css/CSSPrimitiveValue.h"
 #include "core/css/cssom/CSSCalcDictionary.h"
@@ -68,6 +69,12 @@
     return result;
 }
 
+CSSCalcLength* CSSCalcLength::fromCSSValue(const CSSPrimitiveValue&)
+{
+    // TODO(meade): Implement.
+    return nullptr;
+}
+
 bool CSSCalcLength::containsPercent() const
 {
     return has(CSSPrimitiveValue::UnitType::Percentage);
diff --git a/third_party/WebKit/Source/core/css/cssom/CSSCalcLength.h b/third_party/WebKit/Source/core/css/cssom/CSSCalcLength.h
index 0fdac83..8681572 100644
--- a/third_party/WebKit/Source/core/css/cssom/CSSCalcLength.h
+++ b/third_party/WebKit/Source/core/css/cssom/CSSCalcLength.h
@@ -22,6 +22,7 @@
     {
         return create(length);
     }
+    static CSSCalcLength* fromCSSValue(const CSSPrimitiveValue&);
 
 #define GETTER_MACRO(name, type) \
     double name(bool& isNull) \
diff --git a/third_party/WebKit/Source/core/css/cssom/CSSSimpleLength.cpp b/third_party/WebKit/Source/core/css/cssom/CSSSimpleLength.cpp
index 1520bee..286446a 100644
--- a/third_party/WebKit/Source/core/css/cssom/CSSSimpleLength.cpp
+++ b/third_party/WebKit/Source/core/css/cssom/CSSSimpleLength.cpp
@@ -4,15 +4,27 @@
 
 #include "core/css/cssom/CSSSimpleLength.h"
 
+#include "bindings/core/v8/ExceptionState.h"
 #include "core/css/CSSPrimitiveValue.h"
 #include "core/css/cssom/CSSCalcLength.h"
 #include "wtf/text/StringBuilder.h"
 
 namespace blink {
 
-CSSValue* CSSSimpleLength::toCSSValue() const
+CSSSimpleLength* CSSSimpleLength::create(double value, const String& type, ExceptionState& exceptionState)
 {
-    return CSSPrimitiveValue::create(m_value, m_unit);
+    CSSPrimitiveValue::UnitType unit = CSSLengthValue::unitFromName(type);
+    if (!CSSLengthValue::isSupportedLengthUnit(unit)) {
+        exceptionState.throwTypeError("Invalid unit for CSSSimpleLength: " + type);
+        return nullptr;
+    }
+    return new CSSSimpleLength(value, unit);
+}
+
+CSSSimpleLength* CSSSimpleLength::fromCSSValue(const CSSPrimitiveValue& value)
+{
+    DCHECK(value.isLength());
+    return new CSSSimpleLength(value.getDoubleValue(), value.typeWithCalcResolved());
 }
 
 bool CSSSimpleLength::containsPercent() const
@@ -45,4 +57,9 @@
     return create(m_value / x, m_unit);
 }
 
+CSSValue* CSSSimpleLength::toCSSValue() const
+{
+    return CSSPrimitiveValue::create(m_value, m_unit);
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/css/cssom/CSSSimpleLength.h b/third_party/WebKit/Source/core/css/cssom/CSSSimpleLength.h
index 7983f4e7..18ec13bf 100644
--- a/third_party/WebKit/Source/core/css/cssom/CSSSimpleLength.h
+++ b/third_party/WebKit/Source/core/css/cssom/CSSSimpleLength.h
@@ -5,31 +5,23 @@
 #ifndef CSSSimpleLength_h
 #define CSSSimpleLength_h
 
-#include "bindings/core/v8/ExceptionState.h"
 #include "core/css/cssom/CSSLengthValue.h"
 
 namespace blink {
 
 class CSSPrimitiveValue;
+class ExceptionState;
 
 class CORE_EXPORT CSSSimpleLength final : public CSSLengthValue {
     WTF_MAKE_NONCOPYABLE(CSSSimpleLength);
     DEFINE_WRAPPERTYPEINFO();
 public:
-    static CSSSimpleLength* create(double value, const String& type, ExceptionState& exceptionState)
-    {
-        CSSPrimitiveValue::UnitType unit = unitFromName(type);
-        if (!isSupportedLengthUnit(unit)) {
-            exceptionState.throwTypeError("Invalid unit for CSSSimpleLength: " + type);
-            return nullptr;
-        }
-        return new CSSSimpleLength(value, unit);
-    }
-
+    static CSSSimpleLength* create(double, const String& type, ExceptionState&);
     static CSSSimpleLength* create(double value, CSSPrimitiveValue::UnitType type)
     {
         return new CSSSimpleLength(value, type);
     }
+    static CSSSimpleLength* fromCSSValue(const CSSPrimitiveValue&);
 
     bool containsPercent() const override;
 
@@ -37,8 +29,6 @@
     String unit() const { return String(CSSPrimitiveValue::unitTypeToString(m_unit)); }
     CSSPrimitiveValue::UnitType lengthUnit() const { return m_unit; }
 
-    void setValue(double value) { m_value = value; }
-
     StyleValueType type() const override { return StyleValueType::SimpleLengthType; }
 
     CSSValue* toCSSValue() const override;
diff --git a/third_party/WebKit/Source/core/css/cssom/CSSSimpleLength.idl b/third_party/WebKit/Source/core/css/cssom/CSSSimpleLength.idl
index 62bc25de..5af5e3a 100644
--- a/third_party/WebKit/Source/core/css/cssom/CSSSimpleLength.idl
+++ b/third_party/WebKit/Source/core/css/cssom/CSSSimpleLength.idl
@@ -8,6 +8,6 @@
     RaisesException=Constructor,
     RuntimeEnabled=CSSTypedOM
 ] interface CSSSimpleLength : CSSLengthValue {
-    [EnforceRange] attribute double value;
+    [EnforceRange] readonly attribute double value;
     [ImplementedAs=unit] readonly attribute LengthType type;
 };
diff --git a/third_party/WebKit/Source/core/css/cssom/StyleValueFactory.cpp b/third_party/WebKit/Source/core/css/cssom/StyleValueFactory.cpp
index 301b9144..3dd43b3 100644
--- a/third_party/WebKit/Source/core/css/cssom/StyleValueFactory.cpp
+++ b/third_party/WebKit/Source/core/css/cssom/StyleValueFactory.cpp
@@ -19,6 +19,16 @@
 
 namespace {
 
+CSSStyleValue* styleValueForPrimitiveValue(const CSSPrimitiveValue& primitiveValue)
+{
+    if (primitiveValue.isNumber())
+        return CSSNumberValue::create(primitiveValue.getDoubleValue());
+    if (primitiveValue.isLength())
+        return CSSSimpleLength::fromCSSValue(primitiveValue);
+
+    return nullptr;
+}
+
 CSSStyleValue* styleValueForProperty(CSSPropertyID propertyID, const CSSValue& value)
 {
     switch (propertyID) {
@@ -29,22 +39,12 @@
         break;
     }
 
-    if (value.isPrimitiveValue()) {
-        const CSSPrimitiveValue& primitiveValue = toCSSPrimitiveValue(value);
-        if (primitiveValue.isLength() && !primitiveValue.isCalculated())
-            return CSSSimpleLength::create(primitiveValue.getDoubleValue(), primitiveValue.typeWithCalcResolved());
-        if (primitiveValue.isNumber())
-            return CSSNumberValue::create(primitiveValue.getDoubleValue());
-    }
-
-    if (value.isVariableReferenceValue()) {
+    if (value.isPrimitiveValue())
+        return styleValueForPrimitiveValue(toCSSPrimitiveValue(value));
+    if (value.isVariableReferenceValue())
         return CSSUnparsedValue::fromCSSValue(toCSSVariableReferenceValue(value));
-    }
-
-    if (value.isImageValue()) {
-        const CSSImageValue& imageValue = toCSSImageValue(value);
-        return CSSURLImageValue::create(imageValue.valueWithURLMadeAbsolute());
-    }
+    if (value.isImageValue())
+        return CSSURLImageValue::create(toCSSImageValue(value).valueWithURLMadeAbsolute());
 
     return nullptr;
 }
diff --git a/third_party/WebKit/Source/core/css/invalidation/StyleSheetInvalidationAnalysis.cpp b/third_party/WebKit/Source/core/css/invalidation/StyleSheetInvalidationAnalysis.cpp
index 7bf5a4f..1ce63da 100644
--- a/third_party/WebKit/Source/core/css/invalidation/StyleSheetInvalidationAnalysis.cpp
+++ b/third_party/WebKit/Source/core/css/invalidation/StyleSheetInvalidationAnalysis.cpp
@@ -28,6 +28,7 @@
 #include "core/css/CSSSelectorList.h"
 #include "core/css/StyleRuleImport.h"
 #include "core/css/StyleSheetContents.h"
+#include "core/css/resolver/ScopedStyleResolver.h"
 #include "core/dom/ContainerNode.h"
 #include "core/dom/Document.h"
 #include "core/dom/ElementTraversal.h"
@@ -166,7 +167,7 @@
     ASSERT(!m_dirtiesAllStyle);
 
     if (m_addsKeyframes)
-        m_treeScope->document().styleEngine().keyframesRulesAdded();
+        ScopedStyleResolver::keyframesRulesAdded(*m_treeScope);
 
     if (m_treeScope->rootNode().isShadowRoot()) {
         ContainerNode& shadowHost = toShadowRoot(m_treeScope->rootNode()).host();
diff --git a/third_party/WebKit/Source/core/css/mediaControlsNew.css b/third_party/WebKit/Source/core/css/mediaControlsNew.css
index 9c89f7c..4670dce 100644
--- a/third_party/WebKit/Source/core/css/mediaControlsNew.css
+++ b/third_party/WebKit/Source/core/css/mediaControlsNew.css
@@ -418,8 +418,8 @@
     vertical-align: middle;
 }
 
-video::-internal-overflow-menu-button, audio::-internal-overflow-menu-button {
-    -webkit-appearance: -internal-overflow-menu-button;
+video::-internal-media-controls-overflow-button, audio::-internal-media-controls-overflow-button {
+    -webkit-appearance: -internal-media-overflow-button;
     display: flex;
     flex: none;
     box-sizing: border-box;
@@ -434,7 +434,7 @@
 }
 
 video::-internal-media-controls-download-button, audio::-internal-media-controls-download-button {
-    -webkit-appearance: -internal-media-download-icon;
+    -webkit-appearance: -internal-media-download-button;
     display: flex;
     flex: none;
     box-sizing: border-box;
diff --git a/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.cpp b/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.cpp
index 13aa399..160e403 100644
--- a/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.cpp
@@ -19,7 +19,8 @@
 #include "core/css/resolver/StyleBuilder.h"
 #include "core/css/resolver/StyleBuilderConverter.h"
 #include "core/css/resolver/StyleResolverState.h"
-#include "core/style/StyleVariableData.h"
+#include "core/style/StyleInheritedVariables.h"
+#include "core/style/StyleNonInheritedVariables.h"
 #include "wtf/Vector.h"
 
 namespace blink {
@@ -44,31 +45,40 @@
     const PropertyRegistry::Registration* registration = m_registry ? m_registry->registration(name) : nullptr;
 
     CSSVariableData* variableData = nullptr;
-    if (m_styleVariableData)
-        variableData = m_styleVariableData->getVariable(name);
+    if (!registration || registration->inherits()) {
+        if (m_inheritedVariables)
+            variableData = m_inheritedVariables->getVariable(name);
+    } else {
+        variableData = m_nonInheritedVariables->getVariable(name);
+    }
     if (!variableData)
         return registration ? registration->initialVariableData() : nullptr;
     if (!variableData->needsVariableResolution())
         return variableData;
 
     RefPtr<CSSVariableData> newVariableData = resolveCustomProperty(name, *variableData);
-    if (registration) {
-        const CSSValue* parsedValue = nullptr;
-        if (newVariableData) {
-            parsedValue = newVariableData->parseForSyntax(registration->syntax());
-            if (parsedValue)
-                parsedValue = &StyleBuilderConverter::convertRegisteredPropertyValue(m_styleResolverState, *parsedValue);
-            else
-                newVariableData = nullptr;
-        }
-        m_styleVariableData->setVariable(name, newVariableData);
-        m_styleVariableData->setRegisteredInheritedProperty(name, parsedValue);
-        if (!newVariableData)
-            return registration->initialVariableData();
+    if (!registration) {
+        m_inheritedVariables->setVariable(name, newVariableData);
         return newVariableData.get();
     }
 
-    m_styleVariableData->setVariable(name, newVariableData);
+    const CSSValue* parsedValue = nullptr;
+    if (newVariableData) {
+        parsedValue = newVariableData->parseForSyntax(registration->syntax());
+        if (parsedValue)
+            parsedValue = &StyleBuilderConverter::convertRegisteredPropertyValue(m_styleResolverState, *parsedValue);
+        else
+            newVariableData = nullptr;
+    }
+    if (registration->inherits()) {
+        m_inheritedVariables->setVariable(name, newVariableData);
+        m_inheritedVariables->setRegisteredVariable(name, parsedValue);
+    } else {
+        m_nonInheritedVariables->setVariable(name, newVariableData);
+        m_nonInheritedVariables->setRegisteredVariable(name, parsedValue);
+    }
+    if (!newVariableData)
+        return registration->initialVariableData();
     return newVariableData.get();
 }
 
@@ -82,7 +92,7 @@
     m_variablesSeen.remove(name);
 
     // The old variable data holds onto the backing string the new resolved CSSVariableData
-    // relies on. Ensure it will live beyond us overwriting the RefPtr in StyleVariableData.
+    // relies on. Ensure it will live beyond us overwriting the RefPtr in StyleInheritedVariables.
     ASSERT(variableData.refCount() > 1);
 
     if (!success || !m_cycleStartPoints.isEmpty()) {
@@ -216,18 +226,26 @@
 
 void CSSVariableResolver::resolveVariableDefinitions(const StyleResolverState& state)
 {
-    StyleVariableData* variables = state.style()->variables();
-    if (!variables)
+    StyleInheritedVariables* inheritedVariables = state.style()->inheritedVariables();
+    StyleNonInheritedVariables* nonInheritedVariables = state.style()->nonInheritedVariables();
+    if (!inheritedVariables && !nonInheritedVariables)
         return;
 
     CSSVariableResolver resolver(state);
-    for (auto& variable : variables->m_data)
-        resolver.valueForCustomProperty(variable.key);
+    if (inheritedVariables) {
+        for (auto& variable : inheritedVariables->m_data)
+            resolver.valueForCustomProperty(variable.key);
+    }
+    if (nonInheritedVariables) {
+        for (auto& variable : nonInheritedVariables->m_data)
+            resolver.valueForCustomProperty(variable.key);
+    }
 }
 
 CSSVariableResolver::CSSVariableResolver(const StyleResolverState& state)
     : m_styleResolverState(state)
-    , m_styleVariableData(state.style()->variables())
+    , m_inheritedVariables(state.style()->inheritedVariables())
+    , m_nonInheritedVariables(state.style()->nonInheritedVariables())
     , m_registry(state.document().propertyRegistry())
 {
 }
diff --git a/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.h b/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.h
index ad83c73..3f3557d 100644
--- a/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.h
+++ b/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.h
@@ -19,7 +19,8 @@
 class CSSVariableReferenceValue;
 class PropertyRegistry;
 class StyleResolverState;
-class StyleVariableData;
+class StyleInheritedVariables;
+class StyleNonInheritedVariables;
 
 class CSSVariableResolver {
     STACK_ALLOCATED();
@@ -56,7 +57,8 @@
     PassRefPtr<CSSVariableData> resolveCustomProperty(AtomicString name, const CSSVariableData&);
 
     const StyleResolverState& m_styleResolverState;
-    StyleVariableData* m_styleVariableData;
+    StyleInheritedVariables* m_inheritedVariables;
+    StyleNonInheritedVariables* m_nonInheritedVariables;
     Member<const PropertyRegistry> m_registry;
     HashSet<AtomicString> m_variablesSeen;
     // Resolution doesn't finish when a cycle is detected. Fallbacks still
diff --git a/third_party/WebKit/Source/core/css/resolver/ElementStyleResources.cpp b/third_party/WebKit/Source/core/css/resolver/ElementStyleResources.cpp
index d3fd5a6..78c53352 100644
--- a/third_party/WebKit/Source/core/css/resolver/ElementStyleResources.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/ElementStyleResources.cpp
@@ -34,13 +34,13 @@
 #include "core/style/ContentData.h"
 #include "core/style/CursorData.h"
 #include "core/style/FillLayer.h"
+#include "core/style/FilterOperation.h"
 #include "core/style/StyleFetchedImage.h"
 #include "core/style/StyleFetchedImageSet.h"
 #include "core/style/StyleGeneratedImage.h"
 #include "core/style/StyleImage.h"
 #include "core/style/StyleInvalidImage.h"
 #include "core/style/StylePendingImage.h"
-#include "platform/graphics/filters/FilterOperation.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/css/resolver/FilterOperationResolver.h b/third_party/WebKit/Source/core/css/resolver/FilterOperationResolver.h
index 182ca395..6b0177a 100644
--- a/third_party/WebKit/Source/core/css/resolver/FilterOperationResolver.h
+++ b/third_party/WebKit/Source/core/css/resolver/FilterOperationResolver.h
@@ -23,7 +23,7 @@
 #define FilterOperationResolver_h
 
 #include "core/CSSValueKeywords.h"
-#include "platform/graphics/filters/FilterOperations.h"
+#include "core/style/FilterOperations.h"
 #include "platform/heap/Handle.h"
 
 namespace blink {
diff --git a/third_party/WebKit/Source/core/css/resolver/ScopedStyleResolver.cpp b/third_party/WebKit/Source/core/css/resolver/ScopedStyleResolver.cpp
index ede3e41e..62938aa 100644
--- a/third_party/WebKit/Source/core/css/resolver/ScopedStyleResolver.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/ScopedStyleResolver.cpp
@@ -27,6 +27,7 @@
 #include "core/css/resolver/ScopedStyleResolver.h"
 
 #include "core/HTMLNames.h"
+#include "core/animation/DocumentTimeline.h"
 #include "core/css/CSSFontSelector.h"
 #include "core/css/CSSStyleSheet.h"
 #include "core/css/FontFace.h"
@@ -37,6 +38,7 @@
 #include "core/css/resolver/MatchRequest.h"
 #include "core/css/resolver/ViewportStyleResolver.h"
 #include "core/dom/Document.h"
+#include "core/dom/StyleChangeReason.h"
 #include "core/dom/StyleEngine.h"
 #include "core/dom/shadow/ElementShadow.h"
 #include "core/dom/shadow/ShadowRoot.h"
@@ -144,6 +146,46 @@
     }
 }
 
+static Node& invalidationRootFor(const TreeScope& treeScope)
+{
+    if (treeScope.rootNode() == treeScope.document())
+        return treeScope.document();
+    return toShadowRoot(treeScope.rootNode()).host();
+}
+
+void ScopedStyleResolver::keyframesRulesAdded(const TreeScope& treeScope)
+{
+    // Called when @keyframes rules are about to be added/removed from a
+    // TreeScope. @keyframes rules may apply to animations on elements in the
+    // same TreeScope as the stylesheet, or the host element in the parent
+    // TreeScope if the TreeScope is a shadow tree.
+
+    ScopedStyleResolver* resolver = treeScope.scopedStyleResolver();
+    ScopedStyleResolver* parentResolver = treeScope.parentTreeScope() ? treeScope.parentTreeScope()->scopedStyleResolver() : nullptr;
+
+    bool hadUnresolvedKeyframes = false;
+    if (resolver && resolver->m_hasUnresolvedKeyframesRule) {
+        resolver->m_hasUnresolvedKeyframesRule = false;
+        hadUnresolvedKeyframes = true;
+    }
+    if (parentResolver && parentResolver->m_hasUnresolvedKeyframesRule) {
+        parentResolver->m_hasUnresolvedKeyframesRule = false;
+        hadUnresolvedKeyframes = true;
+    }
+
+    if (hadUnresolvedKeyframes) {
+        // If an animation ended up not being started because no @keyframes
+        // rules were found for the animation-name, we need to recalculate style
+        // for the elements in the scope, including its shadow host if
+        // applicable.
+        invalidationRootFor(treeScope).setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::StyleSheetChange));
+        return;
+    }
+
+    // If we have animations running, added/removed @keyframes may affect these.
+    treeScope.document().timeline().invalidateKeyframeEffects(treeScope);
+}
+
 void ScopedStyleResolver::collectMatchingAuthorRules(ElementRuleCollector& collector, CascadeOrder cascadeOrder)
 {
     for (size_t i = 0; i < m_authorStyleSheets.size(); ++i) {
diff --git a/third_party/WebKit/Source/core/css/resolver/ScopedStyleResolver.h b/third_party/WebKit/Source/core/css/resolver/ScopedStyleResolver.h
index 58f4e0b..8d4ba30 100644
--- a/third_party/WebKit/Source/core/css/resolver/ScopedStyleResolver.h
+++ b/third_party/WebKit/Source/core/css/resolver/ScopedStyleResolver.h
@@ -62,6 +62,8 @@
     void resetAuthorStyle();
     void collectViewportRulesTo(ViewportStyleResolver*) const;
     bool hasDeepOrShadowSelector() const { return m_hasDeepOrShadowSelector; }
+    void setHasUnresolvedKeyframesRule() { m_hasUnresolvedKeyframesRule = true; }
+    static void keyframesRulesAdded(const TreeScope&);
 
     DECLARE_TRACE();
 
@@ -108,6 +110,7 @@
 
     Member<CSSStyleSheetRuleSubSet> m_treeBoundaryCrossingRuleSet;
     bool m_hasDeepOrShadowSelector = false;
+    bool m_hasUnresolvedKeyframesRule = false;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp b/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp
index a9faee2..cdb4359 100644
--- a/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp
@@ -70,7 +70,8 @@
 #include "core/style/QuotesData.h"
 #include "core/style/SVGComputedStyle.h"
 #include "core/style/StyleGeneratedImage.h"
-#include "core/style/StyleVariableData.h"
+#include "core/style/StyleInheritedVariables.h"
+#include "core/style/StyleNonInheritedVariables.h"
 #include "platform/fonts/FontDescription.h"
 #include "wtf/MathExtras.h"
 #include "wtf/PtrUtil.h"
@@ -804,47 +805,73 @@
     if (registry)
         registration = registry->registration(name);
 
-    switch (declaration.id()) {
-    case CSSValueInitial:
-        state.style()->removeVariable(name);
-        break;
+    bool isInheritedProperty = !registration || registration->inherits();
+    bool initial = declaration.isInitial(isInheritedProperty);
+    bool inherit = declaration.isInherit(isInheritedProperty);
+    DCHECK(!(initial && inherit));
 
-    case CSSValueUnset:
-    case CSSValueInherit: {
-        state.style()->removeVariable(name);
-        StyleVariableData* parentVariables = state.parentStyle()->variables();
-        if (!parentVariables)
-            return;
-        CSSVariableData* value = parentVariables->getVariable(name);
-        if (!value)
-            return;
-        state.style()->setVariable(name, value);
-        if (registration)
-            state.style()->setRegisteredInheritedProperty(name, parentVariables->registeredInheritedProperty(name));
-        break;
-    }
-    case CSSValueInternalVariableValue:
-        if (registration) {
-            if (declaration.value()->needsVariableResolution()) {
-                state.style()->setVariable(name, declaration.value());
-                return;
-            }
-            const CSSValue* parsedValue = declaration.value()->parseForSyntax(registration->syntax());
-            if (!parsedValue) {
-                state.style()->setVariable(name, nullptr);
-                state.style()->setRegisteredInheritedProperty(name, nullptr);
-                return;
-            }
-            parsedValue = &StyleBuilderConverter::convertRegisteredPropertyValue(state, *parsedValue);
-            state.style()->setVariable(name, declaration.value());
-            state.style()->setRegisteredInheritedProperty(name, parsedValue);
+    if (!initial && !inherit) {
+        if (declaration.value()->needsVariableResolution()) {
+            if (isInheritedProperty)
+                state.style()->setUnresolvedInheritedVariable(name, declaration.value());
+            else
+                state.style()->setUnresolvedNonInheritedVariable(name, declaration.value());
             return;
         }
-        state.style()->setVariable(name, declaration.value());
-        break;
-    default:
-        NOTREACHED();
+
+        if (!registration) {
+            state.style()->setResolvedUnregisteredVariable(name, declaration.value());
+            return;
+        }
+
+        const CSSValue* parsedValue = declaration.value()->parseForSyntax(registration->syntax());
+        if (parsedValue) {
+            parsedValue = &StyleBuilderConverter::convertRegisteredPropertyValue(state, *parsedValue);
+            DCHECK(parsedValue);
+            if (isInheritedProperty)
+                state.style()->setResolvedInheritedVariable(name, declaration.value(), parsedValue);
+            else
+                state.style()->setResolvedNonInheritedVariable(name, declaration.value(), parsedValue);
+            return;
+        }
+        if (isInheritedProperty)
+            inherit = true;
+        else
+            initial = true;
     }
+
+    DCHECK(initial ^ inherit);
+
+    if (initial) {
+        if (isInheritedProperty)
+            state.style()->removeInheritedVariable(name);
+        else
+            state.style()->removeNonInheritedVariable(name);
+        return;
+    }
+
+    if (isInheritedProperty) {
+        state.style()->removeInheritedVariable(name);
+        StyleInheritedVariables* parentVariables = state.parentStyle()->inheritedVariables();
+        if (!parentVariables)
+            return;
+        CSSVariableData* parentValue = parentVariables->getVariable(name);
+        if (parentValue) {
+            if (!registration)
+                state.style()->setResolvedUnregisteredVariable(name, parentValue);
+            else
+                state.style()->setResolvedInheritedVariable(name, parentValue, parentVariables->registeredVariable(name));
+        }
+        return;
+    }
+
+    state.style()->removeNonInheritedVariable(name);
+    StyleNonInheritedVariables* parentVariables = state.parentStyle()->nonInheritedVariables();
+    if (!parentVariables)
+        return;
+    CSSVariableData* parentValue = parentVariables->getVariable(name);
+    if (parentValue)
+        state.style()->setResolvedNonInheritedVariable(name, parentValue, parentVariables->registeredVariable(name));
 }
 
 void StyleBuilderFunctions::applyInheritCSSPropertyBaselineShift(StyleResolverState& state)
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp b/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp
index ca4f2d9..3826ea0 100644
--- a/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp
@@ -86,7 +86,7 @@
 #include "core/inspector/InspectorInstrumentation.h"
 #include "core/layout/GeneratedChildren.h"
 #include "core/layout/api/LayoutViewItem.h"
-#include "core/style/StyleVariableData.h"
+#include "core/style/StyleInheritedVariables.h"
 #include "core/svg/SVGDocumentExtensions.h"
 #include "core/svg/SVGElement.h"
 #include "platform/RuntimeEnabledFeatures.h"
@@ -108,7 +108,8 @@
 bool cacheCustomPropertiesForApplyAtRules(StyleResolverState& state, const MatchedPropertiesRange& range)
 {
     bool ruleSetsCustomProperty = false;
-    if (!state.style()->variables())
+    // TODO(timloh): @apply should also work with properties registered as non-inherited.
+    if (!state.style()->inheritedVariables())
         return false;
     for (const auto& matchedProperties : range) {
         const StylePropertySet& properties = *matchedProperties.properties;
@@ -118,7 +119,7 @@
             if (current.id() != CSSPropertyApplyAtRule)
                 continue;
             AtomicString name(toCSSCustomIdentValue(current.value()).value());
-            CSSVariableData* variableData = state.style()->variables()->getVariable(name);
+            CSSVariableData* variableData = state.style()->inheritedVariables()->getVariable(name);
             if (!variableData)
                 continue;
             StylePropertySet* customPropertySet = variableData->propertySet();
@@ -1160,10 +1161,13 @@
     if (ScopedStyleResolver* scopedResolver = element->treeScope().scopedStyleResolver())
         resolvers.append(scopedResolver);
 
-    for (size_t i = 0; i < resolvers.size(); ++i) {
-        if (StyleRuleKeyframes* keyframesRule = resolvers[i]->keyframeStylesForAnimation(animationName.impl()))
+    for (auto& resolver : resolvers) {
+        if (StyleRuleKeyframes* keyframesRule = resolver->keyframeStylesForAnimation(animationName.impl()))
             return keyframesRule;
     }
+
+    for (auto& resolver : resolvers)
+        resolver->setHasUnresolvedKeyframesRule();
     return nullptr;
 }
 
@@ -1434,7 +1438,7 @@
 void StyleResolver::applyPropertiesForApplyAtRule(StyleResolverState& state, const CSSValue& value, bool isImportant, PropertyWhitelistType propertyWhitelistType)
 {
     state.style()->setHasVariableReferenceFromNonInheritedProperty();
-    if (!state.style()->variables())
+    if (!state.style()->inheritedVariables())
         return;
     const String& name = toCSSCustomIdentValue(value).value();
     const StylePropertySet* propertySet = state.customPropertySetForApplyAtRule(name);
diff --git a/third_party/WebKit/Source/core/dom/CompositorProxy.cpp b/third_party/WebKit/Source/core/dom/CompositorProxy.cpp
index c8abebf1..4b10123 100644
--- a/third_party/WebKit/Source/core/dom/CompositorProxy.cpp
+++ b/third_party/WebKit/Source/core/dom/CompositorProxy.cpp
@@ -204,7 +204,7 @@
         return nullptr;
     if (raiseExceptionIfNotMutable(CompositorMutableProperty::kTransform, exceptionState))
         return nullptr;
-    return DOMMatrix::create(m_state->transform());
+    return DOMMatrix::create(m_state->transform(), exceptionState);
 }
 
 void CompositorProxy::setOpacity(double opacity, ExceptionState& exceptionState)
diff --git a/third_party/WebKit/Source/core/dom/DOMMatrix.cpp b/third_party/WebKit/Source/core/dom/DOMMatrix.cpp
index eb1c68e5..73b06db 100644
--- a/third_party/WebKit/Source/core/dom/DOMMatrix.cpp
+++ b/third_party/WebKit/Source/core/dom/DOMMatrix.cpp
@@ -6,22 +6,31 @@
 
 namespace blink {
 
-DOMMatrix* DOMMatrix::create()
+DOMMatrix* DOMMatrix::create(ExceptionState& exceptionState)
 {
     return new DOMMatrix(TransformationMatrix());
 }
 
-DOMMatrix* DOMMatrix::create(DOMMatrixReadOnly* other)
+DOMMatrix* DOMMatrix::create(DOMMatrixReadOnly* other, ExceptionState& exceptionState)
 {
     return new DOMMatrix(other->matrix(), other->is2D());
 }
 
-DOMMatrix* DOMMatrix::create(const SkMatrix44& matrix)
+DOMMatrix* DOMMatrix::create(const SkMatrix44& matrix, ExceptionState& exceptionState)
 {
     TransformationMatrix transformationMatrix(matrix);
     return new DOMMatrix(transformationMatrix, transformationMatrix.isAffine());
 }
 
+DOMMatrix* DOMMatrix::create(Vector<double> sequence, ExceptionState& exceptionState)
+{
+    if (sequence.size() != 6 && sequence.size() != 16) {
+        exceptionState.throwTypeError("The sequence must contain 6 elements for a 2D matrix or 16 elements for a 3D matrix.");
+        return nullptr;
+    }
+    return new DOMMatrix(sequence, sequence.size());
+}
+
 DOMMatrix* DOMMatrix::fromFloat32Array(DOMFloat32Array* float32Array, ExceptionState& exceptionState)
 {
     if (float32Array->length() != 6 && float32Array->length() != 16) {
diff --git a/third_party/WebKit/Source/core/dom/DOMMatrix.h b/third_party/WebKit/Source/core/dom/DOMMatrix.h
index 1ad7fad..e960881 100644
--- a/third_party/WebKit/Source/core/dom/DOMMatrix.h
+++ b/third_party/WebKit/Source/core/dom/DOMMatrix.h
@@ -5,6 +5,7 @@
 #ifndef DOMMatrix_h
 #define DOMMatrix_h
 
+#include "bindings/core/v8/ExceptionStatePlaceholder.h"
 #include "core/dom/DOMMatrixInit.h"
 #include "core/dom/DOMMatrixReadOnly.h"
 
@@ -13,9 +14,10 @@
 class CORE_EXPORT DOMMatrix : public DOMMatrixReadOnly {
     DEFINE_WRAPPERTYPEINFO();
 public:
-    static DOMMatrix* create();
-    static DOMMatrix* create(DOMMatrixReadOnly*);
-    static DOMMatrix* create(const SkMatrix44&);
+    static DOMMatrix* create(ExceptionState&);
+    static DOMMatrix* create(DOMMatrixReadOnly*, ExceptionState& = ASSERT_NO_EXCEPTION);
+    static DOMMatrix* create(const SkMatrix44&, ExceptionState&);
+    static DOMMatrix* create(Vector<double>, ExceptionState&);
     static DOMMatrix* fromFloat32Array(DOMFloat32Array*, ExceptionState&);
     static DOMMatrix* fromFloat64Array(DOMFloat64Array*, ExceptionState&);
     static DOMMatrix* fromMatrix(DOMMatrixInit&, ExceptionState&);
diff --git a/third_party/WebKit/Source/core/dom/DOMMatrix.idl b/third_party/WebKit/Source/core/dom/DOMMatrix.idl
index db22f97..128831e5 100644
--- a/third_party/WebKit/Source/core/dom/DOMMatrix.idl
+++ b/third_party/WebKit/Source/core/dom/DOMMatrix.idl
@@ -7,6 +7,8 @@
 [
     Constructor,
     Constructor(DOMMatrixReadOnly other),
+    Constructor(sequence<unrestricted double> numberSequence),
+    RaisesException=Constructor,
     // FIXME: Should implement more constructors (See: crbug.com/388780)
     // FIXME: Exposed=(Window,Worker)
     RuntimeEnabled=GeometryInterfaces,
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index 5db0137..0db0b51 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -1779,6 +1779,8 @@
 {
     DCHECK(!view()->shouldThrottleRendering());
     TRACE_EVENT_BEGIN0("blink,blink_style", "Document::updateStyle");
+    SCOPED_BLINK_UMA_HISTOGRAM_TIMER("Style.UpdateTime");
+
     unsigned initialElementCount = styleEngine().styleForElementCount();
 
     HTMLFrameOwnerElement::UpdateSuspendScope suspendWidgetHierarchyUpdates;
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp
index eef8d64..79f4efb 100644
--- a/third_party/WebKit/Source/core/dom/Element.cpp
+++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -1034,39 +1034,43 @@
     return rect;
 }
 
-ClientRectList* Element::getClientRects()
+void Element::clientQuads(Vector<FloatQuad>& quads)
 {
     document().updateStyleAndLayoutIgnorePendingStylesheetsForNode(this);
 
     LayoutObject* elementLayoutObject = layoutObject();
-    if (!elementLayoutObject || (!elementLayoutObject->isBoxModelObject() && !elementLayoutObject->isBR()))
+    if (!elementLayoutObject)
+        return;
+
+    if (isSVGElement() && !elementLayoutObject->isSVGRoot()) {
+        // Get the bounding rectangle from the SVG model.
+        if (toSVGElement(this)->isSVGGraphicsElement())
+            quads.append(elementLayoutObject->localToAbsoluteQuad(elementLayoutObject->objectBoundingBox()));
+        return;
+    }
+
+    // FIXME: Handle table/inline-table with a caption.
+    if (elementLayoutObject->isBoxModelObject() || elementLayoutObject->isBR())
+        elementLayoutObject->absoluteQuads(quads);
+}
+
+ClientRectList* Element::getClientRects()
+{
+    Vector<FloatQuad> quads;
+    clientQuads(quads);
+    if (quads.isEmpty())
         return ClientRectList::create();
 
-    // FIXME: Handle SVG elements.
-    // FIXME: Handle table/inline-table with a caption.
-
-    Vector<FloatQuad> quads;
-    elementLayoutObject->absoluteQuads(quads);
+    LayoutObject* elementLayoutObject = layoutObject();
+    DCHECK(elementLayoutObject);
     document().adjustFloatQuadsForScrollAndAbsoluteZoom(quads, *elementLayoutObject);
     return ClientRectList::create(quads);
 }
 
 ClientRect* Element::getBoundingClientRect()
 {
-    document().updateStyleAndLayoutIgnorePendingStylesheetsForNode(this);
-
     Vector<FloatQuad> quads;
-    LayoutObject* elementLayoutObject = layoutObject();
-    if (elementLayoutObject) {
-        if (isSVGElement() && !elementLayoutObject->isSVGRoot()) {
-            // Get the bounding rectangle from the SVG model.
-            if (toSVGElement(this)->isSVGGraphicsElement())
-                quads.append(elementLayoutObject->localToAbsoluteQuad(elementLayoutObject->objectBoundingBox()));
-        } else if (elementLayoutObject->isBoxModelObject() || elementLayoutObject->isBR()) {
-            elementLayoutObject->absoluteQuads(quads);
-        }
-    }
-
+    clientQuads(quads);
     if (quads.isEmpty())
         return ClientRect::create();
 
@@ -1074,6 +1078,7 @@
     for (size_t i = 1; i < quads.size(); ++i)
         result.unite(quads[i].boundingBox());
 
+    LayoutObject* elementLayoutObject = layoutObject();
     DCHECK(elementLayoutObject);
     document().adjustFloatRectForScrollAndAbsoluteZoom(result, *elementLayoutObject);
     return ClientRect::create(result);
@@ -3218,7 +3223,10 @@
         }
     }
 
-    return true;
+    if (!document().page())
+        return true;
+
+    return document().page()->settings().spellCheckEnabledByDefault();
 }
 
 #if DCHECK_IS_ON()
diff --git a/third_party/WebKit/Source/core/dom/Element.h b/third_party/WebKit/Source/core/dom/Element.h
index 230db07..303639c 100644
--- a/third_party/WebKit/Source/core/dom/Element.h
+++ b/third_party/WebKit/Source/core/dom/Element.h
@@ -715,6 +715,8 @@
     void updateId(TreeScope&, const AtomicString& oldId, const AtomicString& newId);
     void updateName(const AtomicString& oldName, const AtomicString& newName);
 
+    void clientQuads(Vector<FloatQuad>& quads);
+
     NodeType getNodeType() const final;
     bool childTypeAllowed(NodeType) const final;
 
diff --git a/third_party/WebKit/Source/core/dom/Node.h b/third_party/WebKit/Source/core/dom/Node.h
index a86e928..0188a6a 100644
--- a/third_party/WebKit/Source/core/dom/Node.h
+++ b/third_party/WebKit/Source/core/dom/Node.h
@@ -700,10 +700,13 @@
         V0CustomElementFlag = 1 << 28,
         V0CustomElementUpgradedFlag = 1 << 29,
 
+        NeedsReattachLayoutTree = 1 << 30,
+        ChildNeedsReattachLayoutTree = 1 << 31,
+
         DefaultNodeFlags = IsFinishedParsingChildrenFlag | NeedsReattachStyleChange
     };
 
-    // 3 bits remaining.
+    // 0 bits remaining.
 
     bool getFlag(NodeFlags mask) const { return m_nodeFlags & mask; }
     void setFlag(bool f, NodeFlags mask) { m_nodeFlags = (m_nodeFlags & ~mask) | (-(int32_t)f & mask); }
diff --git a/third_party/WebKit/Source/core/dom/StyleEngine.cpp b/third_party/WebKit/Source/core/dom/StyleEngine.cpp
index 3a940d1..aebf643 100644
--- a/third_party/WebKit/Source/core/dom/StyleEngine.cpp
+++ b/third_party/WebKit/Source/core/dom/StyleEngine.cpp
@@ -28,7 +28,6 @@
 #include "core/dom/StyleEngine.h"
 
 #include "core/HTMLNames.h"
-#include "core/animation/DocumentTimeline.h"
 #include "core/css/CSSDefaultStyleSheets.h"
 #include "core/css/CSSFontSelector.h"
 #include "core/css/CSSStyleSheet.h"
@@ -882,17 +881,6 @@
         m_resolver->resetRuleFeatures();
 }
 
-void StyleEngine::keyframesRulesAdded()
-{
-    if (m_hasUnresolvedKeyframesRule) {
-        m_hasUnresolvedKeyframesRule = false;
-        document().setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::StyleSheetChange));
-        return;
-    }
-
-    document().timeline().invalidateKeyframeEffects();
-}
-
 DEFINE_TRACE(StyleEngine)
 {
     visitor->trace(m_document);
diff --git a/third_party/WebKit/Source/core/dom/StyleEngine.h b/third_party/WebKit/Source/core/dom/StyleEngine.h
index f2dd41c..aa3d278d 100644
--- a/third_party/WebKit/Source/core/dom/StyleEngine.h
+++ b/third_party/WebKit/Source/core/dom/StyleEngine.h
@@ -128,9 +128,6 @@
     void shadowRootRemovedFromDocument(ShadowRoot*);
     void appendActiveAuthorStyleSheets();
 
-    void setHasUnresolvedKeyframesRule() { m_hasUnresolvedKeyframesRule = true; }
-    void keyframesRulesAdded();
-
     StyleResolver* resolver() const
     {
         return m_resolver.get();
@@ -268,7 +265,6 @@
 
     bool m_ignorePendingStylesheets = false;
     bool m_didCalculateResolver = false;
-    bool m_hasUnresolvedKeyframesRule = false;
 
     Member<StyleResolver> m_resolver;
     StyleInvalidator m_styleInvalidator;
diff --git a/third_party/WebKit/Source/core/editing/DOMSelection.cpp b/third_party/WebKit/Source/core/editing/DOMSelection.cpp
index 4f688e4..85a0a77 100644
--- a/third_party/WebKit/Source/core/editing/DOMSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/DOMSelection.cpp
@@ -81,13 +81,13 @@
 
 bool DOMSelection::isAvailable() const
 {
-    return m_frame && m_frame->selection().isAvailable();
+    return frame() && frame()->selection().isAvailable();
 }
 
 const VisibleSelection& DOMSelection::visibleSelection() const
 {
-    DCHECK(m_frame);
-    return m_frame->selection().selection();
+    DCHECK(frame());
+    return frame()->selection().selection();
 }
 
 static Position anchorPosition(const VisibleSelection& selection)
@@ -178,9 +178,9 @@
 
 bool DOMSelection::isCollapsed() const
 {
-    if (!isAvailable() || selectionShadowAncestor(m_frame))
+    if (!isAvailable() || selectionShadowAncestor(frame()))
         return true;
-    return !m_frame->selection().isRange();
+    return !frame()->selection().isRange();
 }
 
 String DOMSelection::type() const
@@ -188,7 +188,7 @@
     if (!isAvailable())
         return String();
 
-    FrameSelection& selection = m_frame->selection();
+    FrameSelection& selection = frame()->selection();
 
     // This is a WebKit DOM extension, incompatible with an IE extension
     // IE has this same attribute, but returns "none", "text" and "control"
@@ -204,7 +204,7 @@
 {
     if (!isAvailable())
         return 0;
-    return m_frame->selection().isNone() ? 0 : 1;
+    return frame()->selection().isNone() ? 0 : 1;
 }
 
 void DOMSelection::collapse(Node* node, int offset, ExceptionState& exceptionState)
@@ -213,8 +213,8 @@
         return;
 
     if (!node) {
-        UseCounter::count(m_frame, UseCounter::SelectionCollapseNull);
-        m_frame->selection().clear();
+        UseCounter::count(frame(), UseCounter::SelectionCollapseNull);
+        frame()->selection().clear();
         return;
     }
 
@@ -228,7 +228,7 @@
     Range::checkNodeWOffset(node, offset, exceptionState);
     if (exceptionState.hadException())
         return;
-    m_frame->selection().setSelection(VisibleSelection(Position(node, offset), m_frame->selection().isDirectional()));
+    frame()->selection().setSelection(VisibleSelection(Position(node, offset), frame()->selection().isDirectional()));
 }
 
 void DOMSelection::collapseToEnd(ExceptionState& exceptionState)
@@ -236,14 +236,14 @@
     if (!isAvailable())
         return;
 
-    const VisibleSelection& selection = m_frame->selection().selection();
+    const VisibleSelection& selection = frame()->selection().selection();
 
     if (selection.isNone()) {
         exceptionState.throwDOMException(InvalidStateError, "there is no selection.");
         return;
     }
 
-    m_frame->selection().moveTo(selection.end(), SelDefaultAffinity);
+    frame()->selection().moveTo(selection.end(), SelDefaultAffinity);
 }
 
 void DOMSelection::collapseToStart(ExceptionState& exceptionState)
@@ -251,21 +251,21 @@
     if (!isAvailable())
         return;
 
-    const VisibleSelection& selection = m_frame->selection().selection();
+    const VisibleSelection& selection = frame()->selection().selection();
 
     if (selection.isNone()) {
         exceptionState.throwDOMException(InvalidStateError, "there is no selection.");
         return;
     }
 
-    m_frame->selection().moveTo(selection.start(), SelDefaultAffinity);
+    frame()->selection().moveTo(selection.start(), SelDefaultAffinity);
 }
 
 void DOMSelection::empty()
 {
     if (!isAvailable())
         return;
-    m_frame->selection().clear();
+    frame()->selection().clear();
 }
 
 void DOMSelection::setBaseAndExtent(Node* baseNode, int baseOffset, Node* extentNode, int extentOffset, ExceptionState& exceptionState)
@@ -284,7 +284,7 @@
     }
 
     if (!baseNode || !extentNode)
-        UseCounter::count(m_frame, UseCounter::SelectionSetBaseAndExtentNull);
+        UseCounter::count(frame(), UseCounter::SelectionSetBaseAndExtentNull);
 
     if (!isValidForPosition(baseNode) || !isValidForPosition(extentNode))
         return;
@@ -292,7 +292,7 @@
     Position base = createPosition(baseNode, baseOffset);
     Position extent = createPosition(extentNode, extentOffset);
     const bool selectionHasDirection = true;
-    m_frame->selection().setSelection(VisibleSelection(base, extent, SelDefaultAffinity, selectionHasDirection));
+    frame()->selection().setSelection(VisibleSelection(base, extent, SelDefaultAffinity, selectionHasDirection));
 }
 
 void DOMSelection::modify(const String& alterString, const String& directionString, const String& granularityString)
@@ -342,7 +342,7 @@
     else
         return;
 
-    m_frame->selection().modify(alter, direction, granularity);
+    frame()->selection().modify(alter, direction, granularity);
 }
 
 void DOMSelection::extend(Node* node, int offset, ExceptionState& exceptionState)
@@ -364,11 +364,11 @@
     if (!isValidForPosition(node))
         return;
 
-    const Position& base = m_frame->selection().base();
+    const Position& base = frame()->selection().base();
     const Position& extent = createPosition(node, offset);
     const bool selectionHasDirection = true;
     const VisibleSelection newSelection(base, extent, TextAffinity::Downstream, selectionHasDirection);
-    m_frame->selection().setSelection(newSelection);
+    frame()->selection().setSelection(newSelection);
 }
 
 Range* DOMSelection::getRangeAt(int index, ExceptionState& exceptionState)
@@ -386,7 +386,7 @@
 
     Position anchor = anchorPosition(visibleSelection());
     if (!anchor.anchorNode()->isInShadowTree())
-        return m_frame->selection().firstRange();
+        return frame()->selection().firstRange();
 
     Node* node = shadowAdjustedNode(anchor);
     if (!node) // crbug.com/595100
@@ -400,7 +400,7 @@
 {
     if (!isAvailable())
         return;
-    m_frame->selection().clear();
+    frame()->selection().clear();
 }
 
 void DOMSelection::addRange(Range* newRange)
@@ -410,7 +410,7 @@
     if (!isAvailable())
         return;
 
-    if (newRange->ownerDocument() != m_frame->document())
+    if (newRange->ownerDocument() != frame()->document())
         return;
 
     if (!newRange->isConnected()) {
@@ -418,7 +418,7 @@
         return;
     }
 
-    FrameSelection& selection = m_frame->selection();
+    FrameSelection& selection = frame()->selection();
 
     if (newRange->ownerDocument() != selection.document()) {
         // "editing/selection/selection-in-iframe-removed-crash.html" goes here.
@@ -464,7 +464,7 @@
     if (!isAvailable())
         return;
 
-    FrameSelection& selection = m_frame->selection();
+    FrameSelection& selection = frame()->selection();
 
     if (selection.isNone())
         return;
@@ -485,9 +485,9 @@
     if (!isAvailable())
         return false;
 
-    FrameSelection& selection = m_frame->selection();
+    FrameSelection& selection = frame()->selection();
 
-    if (m_frame->document() != n->document() || selection.isNone())
+    if (frame()->document() != n->document() || selection.isNone())
         return false;
 
     unsigned nodeIndex = n->nodeIndex();
@@ -531,11 +531,11 @@
 
     // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
     // needs to be audited.  See http://crbug.com/590369 for more details.
-    m_frame->document()->updateStyleAndLayoutIgnorePendingStylesheets();
+    frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets();
 
-    DocumentLifecycle::DisallowTransitionScope disallowTransition(m_frame->document()->lifecycle());
+    DocumentLifecycle::DisallowTransitionScope disallowTransition(frame()->document()->lifecycle());
 
-    const EphemeralRange range = m_frame->selection().selection().toNormalizedEphemeralRange();
+    const EphemeralRange range = frame()->selection().selection().toNormalizedEphemeralRange();
     return plainText(range, TextIteratorForSelectionToString);
 }
 
@@ -576,10 +576,10 @@
 
 bool DOMSelection::isValidForPosition(Node* node) const
 {
-    DCHECK(m_frame);
+    DCHECK(frame());
     if (!node)
         return true;
-    return node->document() == m_frame->document() && node->isConnected();
+    return node->document() == frame()->document() && node->isConnected();
 }
 
 void DOMSelection::addConsoleError(const String& message)
diff --git a/third_party/WebKit/Source/core/events/EventTarget.cpp b/third_party/WebKit/Source/core/events/EventTarget.cpp
index f273e0e..15f9906 100644
--- a/third_party/WebKit/Source/core/events/EventTarget.cpp
+++ b/third_party/WebKit/Source/core/events/EventTarget.cpp
@@ -547,16 +547,13 @@
     }
 
     // Only invoke the callback if event listeners were fired for this phase.
-    if (firedEventListeners)
+    if (firedEventListeners) {
         event->doneDispatchingEventAtCurrentTarget();
 
-    // TODO(dtapuska): Should we really do counting here for these events
-    // if we really didn't fire a listener? For example having a bubbling
-    // listener on an event that doesn't bubble likely records a UMA
-    // metric where it probably shouldn't because it was never fired.
-    // See https://crbug.com/612829
-    Editor::countEvent(getExecutionContext(), event);
-    countLegacyEvents(legacyTypeName, listenersVector, legacyListenersVector);
+        // Only count uma metrics if we really fired an event listener.
+        Editor::countEvent(getExecutionContext(), event);
+        countLegacyEvents(legacyTypeName, listenersVector, legacyListenersVector);
+    }
     return dispatchEventResult(*event);
 }
 
@@ -597,21 +594,10 @@
             if (event->isPointerEvent() && static_cast<PointerEvent*>(event)->pointerType() == "touch")
                 UseCounter::count(executingWindow->document(), UseCounter::PointerDownFiredForTouch);
         }
-    } else if (checkTypeThenUseCount(event, EventTypeNames::pointerenter, UseCounter::PointerEnterLeaveFired)
-        || checkTypeThenUseCount(event, EventTypeNames::pointerleave, UseCounter::PointerEnterLeaveFired)
-        || checkTypeThenUseCount(event, EventTypeNames::pointerover, UseCounter::PointerOverOutFired)
-        || checkTypeThenUseCount(event, EventTypeNames::pointerout, UseCounter::PointerOverOutFired)) {
-        LocalDOMWindow* executingWindow = this->executingWindow();
-        Node* node = toNode();
-        if (executingWindow && node && node->getNodeType() == Node::kElementNode && event->isPointerEvent()) {
-            const Element* element = static_cast<Element*>(node);
-            const PointerEvent* pointerEvent = static_cast<PointerEvent*>(event);
-            const UseCounter::Feature feature = (event->type() == EventTypeNames::pointerenter || event->type() == EventTypeNames::pointerleave)
-                ? UseCounter::PointerEnterLeaveFiredWhileCaptured
-                : UseCounter::PointerOverOutFiredWhileCaptured;
-            if (element->hasPointerCapture(pointerEvent->pointerId()) && element->hasProcessedPointerCapture(pointerEvent->pointerId()))
-                UseCounter::count(executingWindow->document(), feature);
-        }
+    } else if (checkTypeThenUseCount(event, EventTypeNames::pointerenter, UseCounter::PointerEnterLeaveFired)) {
+    } else if (checkTypeThenUseCount(event, EventTypeNames::pointerleave, UseCounter::PointerEnterLeaveFired)) {
+    } else if (checkTypeThenUseCount(event, EventTypeNames::pointerover, UseCounter::PointerOverOutFired)) {
+    } else if (checkTypeThenUseCount(event, EventTypeNames::pointerout, UseCounter::PointerOverOutFired)) {
     }
 
     ExecutionContext* context = getExecutionContext();
diff --git a/third_party/WebKit/Source/core/events/NavigatorEvents.cpp b/third_party/WebKit/Source/core/events/NavigatorEvents.cpp
index e2a419c..eba1769 100644
--- a/third_party/WebKit/Source/core/events/NavigatorEvents.cpp
+++ b/third_party/WebKit/Source/core/events/NavigatorEvents.cpp
@@ -46,9 +46,4 @@
     return 0;
 }
 
-bool NavigatorEvents::pointerEnabled(Navigator& navigator)
-{
-    return false;
-}
-
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/events/NavigatorEvents.h b/third_party/WebKit/Source/core/events/NavigatorEvents.h
index bc47673..787d16b 100644
--- a/third_party/WebKit/Source/core/events/NavigatorEvents.h
+++ b/third_party/WebKit/Source/core/events/NavigatorEvents.h
@@ -41,7 +41,6 @@
     STATIC_ONLY(NavigatorEvents);
 public:
     static long maxTouchPoints(Navigator&);
-    static bool pointerEnabled(Navigator&);
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/events/NavigatorEvents.idl b/third_party/WebKit/Source/core/events/NavigatorEvents.idl
index da729c9..433a944 100644
--- a/third_party/WebKit/Source/core/events/NavigatorEvents.idl
+++ b/third_party/WebKit/Source/core/events/NavigatorEvents.idl
@@ -32,10 +32,4 @@
 
 partial interface Navigator {
     readonly attribute long maxTouchPoints;
-
-    // TODO(mustaq): This is a non-standard attribute, added behind the
-    // PointerEvent flag only to estimate potential risks. This returns |false|
-    // even though PointerEvent support is there. The attribute will be removed
-    // once we have the UseCounter data. See crbug.com/631897.
-    [RuntimeEnabled=PointerEvent,DeprecateAs=NavigatorPointerEnabled,NotEnumerable] readonly attribute boolean pointerEnabled;
 };
diff --git a/third_party/WebKit/Source/core/fetch/FetchContext.h b/third_party/WebKit/Source/core/fetch/FetchContext.h
index b62e5e74..5940aa20c 100644
--- a/third_party/WebKit/Source/core/fetch/FetchContext.h
+++ b/third_party/WebKit/Source/core/fetch/FetchContext.h
@@ -79,6 +79,7 @@
     virtual WebCachePolicy resourceRequestCachePolicy(const ResourceRequest&, Resource::Type, FetchRequest::DeferOption) const;
 
     virtual void dispatchDidChangeResourcePriority(unsigned long identifier, ResourceLoadPriority, int intraPriorityValue);
+    // The last callback before a request is actually sent to the browser process.
     virtual void dispatchWillSendRequest(unsigned long identifier, ResourceRequest&, const ResourceResponse& redirectResponse, const FetchInitiatorInfo& = FetchInitiatorInfo());
     virtual void dispatchDidLoadResourceFromMemoryCache(unsigned long identifier, Resource*, WebURLRequest::FrameType, WebURLRequest::RequestContext);
     virtual void dispatchDidReceiveResponse(unsigned long identifier, const ResourceResponse&, WebURLRequest::FrameType, WebURLRequest::RequestContext, Resource*);
@@ -88,6 +89,7 @@
     virtual void dispatchDidFail(unsigned long identifier, const ResourceError&, bool isInternalRequest);
 
     virtual bool shouldLoadNewResource(Resource::Type) const { return false; }
+    // Called when a resource load is first requested, which may not be when the load actually begins.
     virtual void willStartLoadingResource(unsigned long identifier, ResourceRequest&, Resource::Type);
     virtual void didLoadResource(Resource*);
 
diff --git a/third_party/WebKit/Source/core/fetch/MemoryCache.cpp b/third_party/WebKit/Source/core/fetch/MemoryCache.cpp
index b1f05615..5d21d21 100644
--- a/third_party/WebKit/Source/core/fetch/MemoryCache.cpp
+++ b/third_party/WebKit/Source/core/fetch/MemoryCache.cpp
@@ -648,7 +648,7 @@
     }
 }
 
-void MemoryCache::prune(Resource* justReleasedResource)
+void MemoryCache::prune()
 {
     TRACE_EVENT0("renderer", "MemoryCache::prune()");
 
@@ -678,21 +678,6 @@
             m_prunePending = true;
         }
     }
-
-    if (m_prunePending && m_deadSize > m_maxDeferredPruneDeadCapacity && justReleasedResource) {
-        // The following eviction does not respect LRU order, but it can be done
-        // immediately in constant time, as opposed to pruneDeadResources, which
-        // we would rather defer because it is O(N), which would make tear-down of N
-        // objects O(N^2) if we pruned immediately. This immediate eviction is a
-        // safeguard against runaway memory consumption by dead resources
-        // while a prune is pending.
-        if (MemoryCacheEntry* entry = getEntryForResource(justReleasedResource))
-            evict(entry);
-
-        // As a last resort, prune immediately
-        if (m_deadSize > m_maxDeferredPruneDeadCapacity)
-            pruneNow(currentTime, AutomaticPrune);
-    }
 }
 
 void MemoryCache::willProcessTask()
diff --git a/third_party/WebKit/Source/core/fetch/MemoryCache.h b/third_party/WebKit/Source/core/fetch/MemoryCache.h
index f4891830..f14ae476 100644
--- a/third_party/WebKit/Source/core/fetch/MemoryCache.h
+++ b/third_party/WebKit/Source/core/fetch/MemoryCache.h
@@ -187,7 +187,7 @@
 
     void evictResources();
 
-    void prune(Resource* justReleasedResource = 0);
+    void prune();
 
     // Called to adjust a resource's size, lru list position, and access count.
     void update(Resource*, size_t oldSize, size_t newSize, bool wasAccessed = false);
diff --git a/third_party/WebKit/Source/core/fetch/MemoryCacheTest.cpp b/third_party/WebKit/Source/core/fetch/MemoryCacheTest.cpp
index 48c6394..251ca9c2 100644
--- a/third_party/WebKit/Source/core/fetch/MemoryCacheTest.cpp
+++ b/third_party/WebKit/Source/core/fetch/MemoryCacheTest.cpp
@@ -312,8 +312,7 @@
     EXPECT_EQ(0u, memoryCache()->deadSize());
     EXPECT_EQ(resource1->size() + resource2->size(), memoryCache()->liveSize());
 
-    // Removing the client from resource1 should result in all resources
-    // remaining in cache since the prune is deferred.
+    // Removing the client from resource1 should not trigger pruning.
     client1->removeAsClient();
     EXPECT_GT(resource1->decodedSize(), 0u);
     EXPECT_GT(resource2->decodedSize(), 0u);
@@ -322,15 +321,25 @@
     EXPECT_TRUE(memoryCache()->contains(resource1));
     EXPECT_TRUE(memoryCache()->contains(resource2));
 
-    // Removing the client from resource2 should result in immediate
-    // eviction of resource2 because we are over the prune deferral limit.
+    // Removing the client from resource2 should not trigger pruning.
     client2->removeAsClient();
     EXPECT_GT(resource1->decodedSize(), 0u);
     EXPECT_GT(resource2->decodedSize(), 0u);
-    EXPECT_EQ(resource1->size(), memoryCache()->deadSize());
+    EXPECT_EQ(resource1->size() + resource2->size(), memoryCache()->deadSize());
     EXPECT_EQ(0u, memoryCache()->liveSize());
     EXPECT_TRUE(memoryCache()->contains(resource1));
-    EXPECT_FALSE(memoryCache()->contains(resource2));
+    EXPECT_TRUE(memoryCache()->contains(resource2));
+
+    WeakPersistent<Resource> resource1Weak = resource1;
+    WeakPersistent<Resource> resource2Weak = resource2;
+
+    ThreadState::current()->collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithSweep, BlinkGC::ForcedGC);
+    // Resources are garbage-collected (WeakMemoryCache) and thus removed
+    // from MemoryCache.
+    EXPECT_FALSE(resource1Weak);
+    EXPECT_FALSE(resource2Weak);
+    EXPECT_EQ(0u, memoryCache()->deadSize());
+    EXPECT_EQ(0u, memoryCache()->liveSize());
 }
 
 TEST_F(MemoryCacheTest, ClientRemoval_Basic)
diff --git a/third_party/WebKit/Source/core/fetch/Resource.cpp b/third_party/WebKit/Source/core/fetch/Resource.cpp
index 579a366..919993c 100644
--- a/third_party/WebKit/Source/core/fetch/Resource.cpp
+++ b/third_party/WebKit/Source/core/fetch/Resource.cpp
@@ -729,14 +729,9 @@
         // "no-store: ... MUST make a best-effort attempt to remove the information from volatile storage as promptly as possible"
         // "... History buffers MAY store such responses as part of their normal operation."
         // We allow non-secure content to be reused in history, but we do not allow secure content to be reused.
-        if (hasCacheControlNoStoreHeader() && url().protocolIs("https")) {
+        if (hasCacheControlNoStoreHeader() && url().protocolIs("https"))
             memoryCache()->remove(this);
-            memoryCache()->prune();
-        } else {
-            memoryCache()->prune(this);
-        }
     }
-    // This object may be dead here.
 }
 
 void Resource::allClientsAndObserversRemoved()
diff --git a/third_party/WebKit/Source/core/frame/BarProp.cpp b/third_party/WebKit/Source/core/frame/BarProp.cpp
index e8143cb..43c4dfd 100644
--- a/third_party/WebKit/Source/core/frame/BarProp.cpp
+++ b/third_party/WebKit/Source/core/frame/BarProp.cpp
@@ -47,9 +47,9 @@
 
 bool BarProp::visible() const
 {
-    if (!m_frame)
+    if (!frame())
         return false;
-    FrameHost* host = m_frame->host();
+    FrameHost* host = frame()->host();
     if (!host)
         return false;
 
diff --git a/third_party/WebKit/Source/core/frame/DOMWindowProperty.h b/third_party/WebKit/Source/core/frame/DOMWindowProperty.h
index 607eca8..2bdece9 100644
--- a/third_party/WebKit/Source/core/frame/DOMWindowProperty.h
+++ b/third_party/WebKit/Source/core/frame/DOMWindowProperty.h
@@ -44,7 +44,7 @@
 
     DECLARE_VIRTUAL_TRACE();
 
-protected:
+private:
     Member<LocalFrame> m_frame;
 };
 
diff --git a/third_party/WebKit/Source/core/frame/Deprecation.cpp b/third_party/WebKit/Source/core/frame/Deprecation.cpp
index fefdbf5a..4470ec0a 100644
--- a/third_party/WebKit/Source/core/frame/Deprecation.cpp
+++ b/third_party/WebKit/Source/core/frame/Deprecation.cpp
@@ -380,9 +380,6 @@
     case UseCounter::V8SVGViewElement_ViewTarget_AttributeGetter:
         return willBeRemoved("SVGViewElement.viewTarget", M56, "5665473114931200");
 
-    case UseCounter::NavigatorPointerEnabled:
-        return "Navigator.pointerEnabled is a non-standard API added for experiments only. It will be removed in near future.";
-
     case UseCounter::WebAudioAutoplayCrossOriginIframe:
         return willBeRemoved("Web Audio autoplay (without user gesture) from cross-origin iframes", M55, "6406908126691328");
 
diff --git a/third_party/WebKit/Source/core/frame/History.cpp b/third_party/WebKit/Source/core/frame/History.cpp
index 313a4f0..0ef6ae1 100644
--- a/third_party/WebKit/Source/core/frame/History.cpp
+++ b/third_party/WebKit/Source/core/frame/History.cpp
@@ -68,9 +68,9 @@
 
 unsigned History::length() const
 {
-    if (!m_frame || !m_frame->loader().client())
+    if (!frame() || !frame()->loader().client())
         return 0;
-    return m_frame->loader().client()->backForwardLength();
+    return frame()->loader().client()->backForwardLength();
 }
 
 SerializedScriptValue* History::state()
@@ -81,10 +81,10 @@
 
 SerializedScriptValue* History::stateInternal() const
 {
-    if (!m_frame)
+    if (!frame())
         return 0;
 
-    if (HistoryItem* historyItem = m_frame->loader().currentItem())
+    if (HistoryItem* historyItem = frame()->loader().currentItem())
         return historyItem->stateObject();
 
     return 0;
@@ -93,16 +93,16 @@
 void History::setScrollRestoration(const String& value)
 {
     ASSERT(value == "manual"  || value == "auto");
-    if (!m_frame || !m_frame->loader().client())
+    if (!frame() || !frame()->loader().client())
         return;
 
     HistoryScrollRestorationType scrollRestoration = value == "manual" ? ScrollRestorationManual : ScrollRestorationAuto;
     if (scrollRestoration == scrollRestorationInternal())
         return;
 
-    if (HistoryItem* historyItem = m_frame->loader().currentItem()) {
+    if (HistoryItem* historyItem = frame()->loader().currentItem()) {
         historyItem->setScrollRestorationType(scrollRestoration);
-        m_frame->loader().client()->didUpdateCurrentHistoryItem();
+        frame()->loader().client()->didUpdateCurrentHistoryItem();
     }
 }
 
@@ -113,8 +113,8 @@
 
 HistoryScrollRestorationType History::scrollRestorationInternal() const
 {
-    if (m_frame) {
-        if (HistoryItem* historyItem = m_frame->loader().currentItem())
+    if (frame()) {
+        if (HistoryItem* historyItem = frame()->loader().currentItem())
             return historyItem->scrollRestorationType();
     }
 
@@ -143,7 +143,7 @@
 
 void History::go(ExecutionContext* context, int delta)
 {
-    if (!m_frame || !m_frame->loader().client())
+    if (!frame() || !frame()->loader().client())
         return;
 
     ASSERT(isMainThread());
@@ -151,7 +151,7 @@
     if (!activeDocument)
         return;
 
-    if (!activeDocument->frame() || !activeDocument->frame()->canNavigate(*m_frame))
+    if (!activeDocument->frame() || !activeDocument->frame()->canNavigate(*frame()))
         return;
     if (!NavigationDisablerForUnload::isNavigationAllowed())
         return;
@@ -161,14 +161,14 @@
     // This behavior is designed in the following spec.
     // https://html.spec.whatwg.org/multipage/browsers.html#dom-history-go
     if (delta)
-        m_frame->loader().client()->navigateBackForward(delta);
+        frame()->loader().client()->navigateBackForward(delta);
     else
-        m_frame->reload(FrameLoadTypeReload, ClientRedirectPolicy::ClientRedirect);
+        frame()->reload(FrameLoadTypeReload, ClientRedirectPolicy::ClientRedirect);
 }
 
 KURL History::urlForState(const String& urlString)
 {
-    Document* document = m_frame->document();
+    Document* document = frame()->document();
 
     if (urlString.isNull())
         return document->url();
@@ -204,17 +204,17 @@
 
 void History::stateObjectAdded(PassRefPtr<SerializedScriptValue> data, const String& /* title */, const String& urlString, HistoryScrollRestorationType restorationType, FrameLoadType type, ExceptionState& exceptionState)
 {
-    if (!m_frame || !m_frame->page() || !m_frame->loader().documentLoader())
+    if (!frame() || !frame()->page() || !frame()->loader().documentLoader())
         return;
 
     KURL fullURL = urlForState(urlString);
-    if (!canChangeToUrl(fullURL, m_frame->document()->getSecurityOrigin(), m_frame->document()->url())) {
+    if (!canChangeToUrl(fullURL, frame()->document()->getSecurityOrigin(), frame()->document()->url())) {
         // We can safely expose the URL to JavaScript, as a) no redirection takes place: JavaScript already had this URL, b) JavaScript can only access a same-origin History object.
-        exceptionState.throwSecurityError("A history state object with URL '" + fullURL.elidedString() + "' cannot be created in a document with origin '" + m_frame->document()->getSecurityOrigin()->toString() + "' and URL '" + m_frame->document()->url().elidedString() + "'.");
+        exceptionState.throwSecurityError("A history state object with URL '" + fullURL.elidedString() + "' cannot be created in a document with origin '" + frame()->document()->getSecurityOrigin()->toString() + "' and URL '" + frame()->document()->url().elidedString() + "'.");
         return;
     }
 
-    m_frame->loader().updateForSameDocumentNavigation(fullURL, SameDocumentNavigationHistoryApi, std::move(data), restorationType, type, m_frame->document());
+    frame()->loader().updateForSameDocumentNavigation(fullURL, SameDocumentNavigationHistoryApi, std::move(data), restorationType, type, frame()->document());
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/ImageBitmap.cpp b/third_party/WebKit/Source/core/frame/ImageBitmap.cpp
index 279710f..a44cfa7 100644
--- a/third_party/WebKit/Source/core/frame/ImageBitmap.cpp
+++ b/third_party/WebKit/Source/core/frame/ImageBitmap.cpp
@@ -673,7 +673,7 @@
     return m_image->height();
 }
 
-bool ImageBitmap::isTextureBacked() const
+bool ImageBitmap::isAccelerated() const
 {
     return m_image && (m_image->isTextureBacked() || m_image->hasMailbox());
 }
diff --git a/third_party/WebKit/Source/core/frame/ImageBitmap.h b/third_party/WebKit/Source/core/frame/ImageBitmap.h
index d61c418..384fbadb 100644
--- a/third_party/WebKit/Source/core/frame/ImageBitmap.h
+++ b/third_party/WebKit/Source/core/frame/ImageBitmap.h
@@ -68,7 +68,6 @@
     bool isPremultiplied() const { return m_image->isPremultiplied(); }
     PassRefPtr<StaticBitmapImage> transfer();
     void close();
-    bool isTextureBacked() const;
 
     ~ImageBitmap() override;
 
@@ -80,6 +79,7 @@
     bool isImageBitmap() const override { return true; }
     int sourceWidth() override { return m_image ? m_image->width() : 0; }
     int sourceHeight() override { return m_image ? m_image->height() : 0; }
+    bool isAccelerated() const override;
 
     // ImageBitmapSource implementation
     IntSize bitmapSourceSize() const override { return size(); }
diff --git a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
index 3b8e896d..d9132e3 100644
--- a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
@@ -487,6 +487,8 @@
 
 void LocalDOMWindow::reset()
 {
+    DCHECK(document());
+    document()->notifyContextDestroyed();
     frameDestroyed();
 
     m_screen = nullptr;
diff --git a/third_party/WebKit/Source/core/frame/Location.cpp b/third_party/WebKit/Source/core/frame/Location.cpp
index b83f6ff..c429d501 100644
--- a/third_party/WebKit/Source/core/frame/Location.cpp
+++ b/third_party/WebKit/Source/core/frame/Location.cpp
@@ -135,11 +135,11 @@
     return DOMURLUtilsReadOnly::hash(url());
 }
 
-void Location::setHref(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String& url)
+void Location::setHref(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String& url, ExceptionState& exceptionState)
 {
     if (!m_frame)
         return;
-    setLocation(url, currentWindow, enteredWindow);
+    setLocation(url, currentWindow, enteredWindow, &exceptionState);
 }
 
 void Location::setProtocol(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String& protocol, ExceptionState& exceptionState)
@@ -151,55 +151,55 @@
         exceptionState.throwDOMException(SyntaxError, "'" + protocol + "' is an invalid protocol.");
         return;
     }
-    setLocation(url.getString(), currentWindow, enteredWindow);
+    setLocation(url.getString(), currentWindow, enteredWindow, &exceptionState);
 }
 
-void Location::setHost(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String& host)
+void Location::setHost(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String& host, ExceptionState& exceptionState)
 {
     if (!m_frame)
         return;
     KURL url = toLocalFrame(m_frame)->document()->url();
     url.setHostAndPort(host);
-    setLocation(url.getString(), currentWindow, enteredWindow);
+    setLocation(url.getString(), currentWindow, enteredWindow, &exceptionState);
 }
 
-void Location::setHostname(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String& hostname)
+void Location::setHostname(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String& hostname, ExceptionState& exceptionState)
 {
     if (!m_frame)
         return;
     KURL url = toLocalFrame(m_frame)->document()->url();
     url.setHost(hostname);
-    setLocation(url.getString(), currentWindow, enteredWindow);
+    setLocation(url.getString(), currentWindow, enteredWindow, &exceptionState);
 }
 
-void Location::setPort(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String& portString)
+void Location::setPort(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String& portString, ExceptionState& exceptionState)
 {
     if (!m_frame)
         return;
     KURL url = toLocalFrame(m_frame)->document()->url();
     url.setPort(portString);
-    setLocation(url.getString(), currentWindow, enteredWindow);
+    setLocation(url.getString(), currentWindow, enteredWindow, &exceptionState);
 }
 
-void Location::setPathname(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String& pathname)
+void Location::setPathname(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String& pathname, ExceptionState& exceptionState)
 {
     if (!m_frame)
         return;
     KURL url = toLocalFrame(m_frame)->document()->url();
     url.setPath(pathname);
-    setLocation(url.getString(), currentWindow, enteredWindow);
+    setLocation(url.getString(), currentWindow, enteredWindow, &exceptionState);
 }
 
-void Location::setSearch(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String& search)
+void Location::setSearch(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String& search, ExceptionState& exceptionState)
 {
     if (!m_frame)
         return;
     KURL url = toLocalFrame(m_frame)->document()->url();
     url.setQuery(search);
-    setLocation(url.getString(), currentWindow, enteredWindow);
+    setLocation(url.getString(), currentWindow, enteredWindow, &exceptionState);
 }
 
-void Location::setHash(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String& hash)
+void Location::setHash(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String& hash, ExceptionState& exceptionState)
 {
     if (!m_frame)
         return;
@@ -214,7 +214,7 @@
     // cases where fragment identifiers are ignored or invalid.
     if (equalIgnoringNullity(oldFragmentIdentifier, url.fragmentIdentifier()))
         return;
-    setLocation(url.getString(), currentWindow, enteredWindow);
+    setLocation(url.getString(), currentWindow, enteredWindow, &exceptionState);
 }
 
 void Location::assign(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String& url, ExceptionState& exceptionState)
@@ -246,9 +246,15 @@
     if (!m_frame || !m_frame->host())
         return;
 
-    if (!currentWindow->frame() || !currentWindow->frame()->canNavigate(*m_frame))
+    if (!currentWindow->frame())
         return;
 
+    if (!currentWindow->frame()->canNavigate(*m_frame)) {
+        if (exceptionState)
+            exceptionState->throwSecurityError("The current window does not have permission to navigate the target frame to '" + url + "'.");
+        return;
+    }
+
     Document* enteredDocument = enteredWindow->document();
     if (!enteredDocument)
         return;
diff --git a/third_party/WebKit/Source/core/frame/Location.h b/third_party/WebKit/Source/core/frame/Location.h
index bd111664..83d7140 100644
--- a/third_party/WebKit/Source/core/frame/Location.h
+++ b/third_party/WebKit/Source/core/frame/Location.h
@@ -58,7 +58,7 @@
     Frame* frame() const { return m_frame.get(); }
     void reset() { m_frame = nullptr; }
 
-    void setHref(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String&);
+    void setHref(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String&, ExceptionState&);
     String href() const;
 
     void assign(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String&, ExceptionState&);
@@ -67,17 +67,17 @@
 
     void setProtocol(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String&, ExceptionState&);
     String protocol() const;
-    void setHost(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String&);
+    void setHost(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String&, ExceptionState&);
     String host() const;
-    void setHostname(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String&);
+    void setHostname(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String&, ExceptionState&);
     String hostname() const;
-    void setPort(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String&);
+    void setPort(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String&, ExceptionState&);
     String port() const;
-    void setPathname(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String&);
+    void setPathname(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String&, ExceptionState&);
     String pathname() const;
-    void setSearch(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String&);
+    void setSearch(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String&, ExceptionState&);
     String search() const;
-    void setHash(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String&);
+    void setHash(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String&, ExceptionState&);
     String hash() const;
     String origin() const;
 
diff --git a/third_party/WebKit/Source/core/frame/Location.idl b/third_party/WebKit/Source/core/frame/Location.idl
index 7f541ab..a2760f6 100644
--- a/third_party/WebKit/Source/core/frame/Location.idl
+++ b/third_party/WebKit/Source/core/frame/Location.idl
@@ -48,17 +48,17 @@
     // TODO(foolip): Per spec, Location implements URLUtils. The below is
     // mostly like the URLUtils interface, but with some members missing and
     // using DOMString instead of USVString.
-    [SetterCallWith=(CurrentWindow,EnteredWindow), DoNotCheckSecurity=Setter] attribute DOMString href;
+    [SetterCallWith=(CurrentWindow,EnteredWindow), DoNotCheckSecurity=Setter, RaisesException=Setter] attribute DOMString href;
     [NotEnumerable, ImplementedAs=href] DOMString toString();
     readonly attribute DOMString origin;
 
     [SetterCallWith=(CurrentWindow,EnteredWindow), RaisesException=Setter] attribute DOMString protocol;
-    [SetterCallWith=(CurrentWindow,EnteredWindow)] attribute DOMString host;
-    [SetterCallWith=(CurrentWindow,EnteredWindow)] attribute DOMString hostname;
-    [SetterCallWith=(CurrentWindow,EnteredWindow)] attribute DOMString port;
-    [SetterCallWith=(CurrentWindow,EnteredWindow)] attribute DOMString pathname;
-    [SetterCallWith=(CurrentWindow,EnteredWindow)] attribute DOMString search;
-    [SetterCallWith=(CurrentWindow,EnteredWindow)] attribute DOMString hash;
+    [SetterCallWith=(CurrentWindow,EnteredWindow), RaisesException=Setter] attribute DOMString host;
+    [SetterCallWith=(CurrentWindow,EnteredWindow), RaisesException=Setter] attribute DOMString hostname;
+    [SetterCallWith=(CurrentWindow,EnteredWindow), RaisesException=Setter] attribute DOMString port;
+    [SetterCallWith=(CurrentWindow,EnteredWindow), RaisesException=Setter] attribute DOMString pathname;
+    [SetterCallWith=(CurrentWindow,EnteredWindow), RaisesException=Setter] attribute DOMString search;
+    [SetterCallWith=(CurrentWindow,EnteredWindow), RaisesException=Setter] attribute DOMString hash;
 
     // TODO(foolip): Location does not have a valueOf() override in the spec.
     // See the comment in Location.h for the purpose of this.
diff --git a/third_party/WebKit/Source/core/frame/Navigator.cpp b/third_party/WebKit/Source/core/frame/Navigator.cpp
index c2461fb..fdfe0dd 100644
--- a/third_party/WebKit/Source/core/frame/Navigator.cpp
+++ b/third_party/WebKit/Source/core/frame/Navigator.cpp
@@ -62,34 +62,34 @@
 String Navigator::userAgent() const
 {
     // If the frame is already detached it no longer has a meaningful useragent.
-    if (!m_frame || !m_frame->page())
+    if (!frame() || !frame()->page())
         return String();
 
-    return m_frame->loader().userAgent();
+    return frame()->loader().userAgent();
 }
 
 bool Navigator::cookieEnabled() const
 {
-    if (!m_frame)
+    if (!frame())
         return false;
 
-    Settings* settings = m_frame->settings();
+    Settings* settings = frame()->settings();
     if (!settings || !settings->cookieEnabled())
         return false;
 
-    return cookiesEnabled(m_frame->document());
+    return cookiesEnabled(frame()->document());
 }
 
 Vector<String> Navigator::languages()
 {
     Vector<String> languages;
 
-    if (!m_frame || !m_frame->host()) {
+    if (!frame() || !frame()->host()) {
         languages.append(defaultLanguage());
         return languages;
     }
 
-    String acceptLanguages = m_frame->host()->chromeClient().acceptLanguages();
+    String acceptLanguages = frame()->host()->chromeClient().acceptLanguages();
     acceptLanguages.split(',', languages);
 
     // Sanitizing tokens. We could do that more extensively but we should assume
diff --git a/third_party/WebKit/Source/core/frame/Screen.cpp b/third_party/WebKit/Source/core/frame/Screen.cpp
index 49482215..9c042ae 100644
--- a/third_party/WebKit/Source/core/frame/Screen.cpp
+++ b/third_party/WebKit/Source/core/frame/Screen.cpp
@@ -46,9 +46,9 @@
 
 int Screen::height() const
 {
-    if (!m_frame)
+    if (!frame())
         return 0;
-    FrameHost* host = m_frame->host();
+    FrameHost* host = frame()->host();
     if (!host)
         return 0;
     if (host->settings().reportScreenSizeInPhysicalPixelsQuirk()) {
@@ -60,9 +60,9 @@
 
 int Screen::width() const
 {
-    if (!m_frame)
+    if (!frame())
         return 0;
-    FrameHost* host = m_frame->host();
+    FrameHost* host = frame()->host();
     if (!host)
         return 0;
     if (host->settings().reportScreenSizeInPhysicalPixelsQuirk()) {
@@ -74,23 +74,23 @@
 
 unsigned Screen::colorDepth() const
 {
-    if (!m_frame || !m_frame->host())
+    if (!frame() || !frame()->host())
         return 0;
-    return static_cast<unsigned>(m_frame->host()->chromeClient().screenInfo().depth);
+    return static_cast<unsigned>(frame()->host()->chromeClient().screenInfo().depth);
 }
 
 unsigned Screen::pixelDepth() const
 {
-    if (!m_frame)
+    if (!frame())
         return 0;
-    return static_cast<unsigned>(m_frame->host()->chromeClient().screenInfo().depth);
+    return static_cast<unsigned>(frame()->host()->chromeClient().screenInfo().depth);
 }
 
 int Screen::availLeft() const
 {
-    if (!m_frame)
+    if (!frame())
         return 0;
-    FrameHost* host = m_frame->host();
+    FrameHost* host = frame()->host();
     if (!host)
         return 0;
     if (host->settings().reportScreenSizeInPhysicalPixelsQuirk()) {
@@ -102,9 +102,9 @@
 
 int Screen::availTop() const
 {
-    if (!m_frame)
+    if (!frame())
         return 0;
-    FrameHost* host = m_frame->host();
+    FrameHost* host = frame()->host();
     if (!host)
         return 0;
     if (host->settings().reportScreenSizeInPhysicalPixelsQuirk()) {
@@ -116,9 +116,9 @@
 
 int Screen::availHeight() const
 {
-    if (!m_frame)
+    if (!frame())
         return 0;
-    FrameHost* host = m_frame->host();
+    FrameHost* host = frame()->host();
     if (!host)
         return 0;
     if (host->settings().reportScreenSizeInPhysicalPixelsQuirk()) {
@@ -130,9 +130,9 @@
 
 int Screen::availWidth() const
 {
-    if (!m_frame)
+    if (!frame())
         return 0;
-    FrameHost* host = m_frame->host();
+    FrameHost* host = frame()->host();
     if (!host)
         return 0;
     if (host->settings().reportScreenSizeInPhysicalPixelsQuirk()) {
diff --git a/third_party/WebKit/Source/core/frame/Settings.in b/third_party/WebKit/Source/core/frame/Settings.in
index 358dfe5b..2d94517 100644
--- a/third_party/WebKit/Source/core/frame/Settings.in
+++ b/third_party/WebKit/Source/core/frame/Settings.in
@@ -430,3 +430,7 @@
 forcePreloadNoneForMediaElements initial=false
 
 hideScrollbars initial=false
+
+# Spellchecking is enabled by default for elements that do not specify it explicitly
+# using the "spellcheck" attribute.
+spellCheckEnabledByDefault initial=true
\ No newline at end of file
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.h b/third_party/WebKit/Source/core/frame/UseCounter.h
index b0e493c..cebb189 100644
--- a/third_party/WebKit/Source/core/frame/UseCounter.h
+++ b/third_party/WebKit/Source/core/frame/UseCounter.h
@@ -347,18 +347,6 @@
         DocumentFonts = 440,
         MixedContentFormsSubmitted = 441,
         FormsSubmitted = 442,
-        TextInputEventOnInput = 443,
-        TextInputEventOnTextArea = 444,
-        TextInputEventOnContentEditable = 445,
-        TextInputEventOnNotNode = 446,
-        WebkitBeforeTextInsertedOnInput = 447,
-        WebkitBeforeTextInsertedOnTextArea = 448,
-        WebkitBeforeTextInsertedOnContentEditable = 449,
-        WebkitBeforeTextInsertedOnNotNode = 450,
-        WebkitEditableContentChangedOnInput = 451,
-        WebkitEditableContentChangedOnTextArea = 452,
-        WebkitEditableContentChangedOnContentEditable = 453,
-        WebkitEditableContentChangedOnNotNode = 454,
         HTMLImports = 455,
         ElementCreateShadowRoot = 456,
         DocumentRegisterElement = 457,
@@ -1026,9 +1014,6 @@
         ScrollAnchored = 1278,
         AddEventListenerFourArguments = 1279,
         RemoveEventListenerFourArguments = 1280,
-        InvalidReportUriDirectiveInMetaCSP = 1281,
-        InvalidSandboxDirectiveInMetaCSP = 1282,
-        InvalidFrameAncestorsDirectiveInMetaCSP = 1283,
         SVGCalcModeDiscrete = 1287,
         SVGCalcModeLinear = 1288,
         SVGCalcModePaced = 1289,
@@ -1254,7 +1239,6 @@
         RadioNameMatchingStrict = 1513,
         RadioNameMatchingASCIICaseless = 1514,
         RadioNameMatchingCaseFolding = 1515,
-        NavigatorPointerEnabled = 1516,
         InputSelectionGettersThrow = 1517,
         UsbGetDevices = 1519,
         UsbRequestDevice = 1520,
@@ -1276,8 +1260,6 @@
 
         PointerEnterLeaveFired = 1535,
         PointerOverOutFired = 1536,
-        PointerEnterLeaveFiredWhileCaptured = 1537,
-        PointerOverOutFiredWhileCaptured = 1538,
         DraggableAttribute = 1539,
         CleanScriptElementWithNonce = 1540,
         PotentiallyInjectedScriptElementWithNonce = 1541,
@@ -1326,6 +1308,21 @@
         XSSAuditorEnabledFilter = 1584,
         XSSAuditorEnabledBlock = 1585,
         XSSAuditorInvalid = 1586,
+        SVGCursorElement = 1587,
+        SVGCursorElementHasClient = 1588,
+        TextInputEventOnInput = 1589,
+        TextInputEventOnTextArea = 1590,
+        TextInputEventOnContentEditable = 1591,
+        TextInputEventOnNotNode = 1592,
+        WebkitBeforeTextInsertedOnInput = 1593,
+        WebkitBeforeTextInsertedOnTextArea = 1594,
+        WebkitBeforeTextInsertedOnContentEditable = 1595,
+        WebkitBeforeTextInsertedOnNotNode = 1596,
+        WebkitEditableContentChangedOnInput = 1597,
+        WebkitEditableContentChangedOnTextArea = 1598,
+        WebkitEditableContentChangedOnContentEditable = 1599,
+        WebkitEditableContentChangedOnNotNode = 1600,
+        V8NavigatorUserMediaError_ConstraintName_AttributeGetter = 1601,
 
         // Add new features immediately above this line. Don't change assigned
         // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp b/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp
index dcf86e3..1270d95b2 100644
--- a/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp
+++ b/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp
@@ -670,7 +670,6 @@
 
     // Remove report-uri in meta policies, per https://www.w3.org/TR/CSP2/#delivery-html-meta-element.
     if (m_headerSource == ContentSecurityPolicyHeaderSourceMeta) {
-        UseCounter::count(m_policy->document(), UseCounter::InvalidReportUriDirectiveInMetaCSP);
         m_policy->reportInvalidDirectiveInMeta(name);
         return;
     }
@@ -705,7 +704,6 @@
 
     // Remove frame-ancestors directives in meta policies, per https://www.w3.org/TR/CSP2/#delivery-html-meta-element.
     if (m_headerSource == ContentSecurityPolicyHeaderSourceMeta && name == ContentSecurityPolicy::FrameAncestors) {
-        UseCounter::count(m_policy->document(), UseCounter::InvalidFrameAncestorsDirectiveInMetaCSP);
         m_policy->reportInvalidDirectiveInMeta(name);
         return;
     }
@@ -717,7 +715,6 @@
 {
     // Remove sandbox directives in meta policies, per https://www.w3.org/TR/CSP2/#delivery-html-meta-element.
     if (m_headerSource == ContentSecurityPolicyHeaderSourceMeta) {
-        UseCounter::count(m_policy->document(), UseCounter::InvalidSandboxDirectiveInMetaCSP);
         m_policy->reportInvalidDirectiveInMeta(name);
         return;
     }
@@ -839,8 +836,6 @@
 {
     m_didSetReferrerPolicy = true;
 
-    UseCounter::count(m_policy->document(), UseCounter::CSPReferrerDirective);
-
     if (value.isEmpty()) {
         m_policy->reportInvalidReferrer(value);
         m_referrerPolicy = ReferrerPolicyNever;
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
index 863a5902d..b3af91e 100644
--- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
@@ -281,6 +281,11 @@
     return (m_context && m_context->isPaintable()) || ImageBuffer::canCreateImageBuffer(size());
 }
 
+bool HTMLCanvasElement::isAccelerated() const
+{
+    return m_context && m_context->isAccelerated();
+}
+
 void HTMLCanvasElement::didDraw(const FloatRect& rect)
 {
     if (rect.isEmpty())
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
index d7fab2e7..0e6c731 100644
--- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
@@ -162,6 +162,7 @@
     FloatSize elementSize(const FloatSize&) const override;
     bool isCanvasElement() const override { return true; }
     bool isOpaque() const override;
+    bool isAccelerated() const override;
     int sourceWidth() override { return m_size.width(); }
     int sourceHeight() override { return m_size.height(); }
 
diff --git a/third_party/WebKit/Source/core/html/HTMLImageElement.h b/third_party/WebKit/Source/core/html/HTMLImageElement.h
index fe5ea8d..f49bd2f 100644
--- a/third_party/WebKit/Source/core/html/HTMLImageElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLImageElement.h
@@ -103,6 +103,7 @@
     FloatSize elementSize(const FloatSize&) const override;
     FloatSize defaultDestinationSize(const FloatSize&) const override;
     const KURL& sourceURL() const override;
+    bool isAccelerated() const override { return false; }
     bool isOpaque() const override;
     int sourceWidth() override;
     int sourceHeight() override;
diff --git a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
index a344bcd..ca017d1 100644
--- a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
@@ -836,7 +836,7 @@
         }
         ++optionIndex;
     }
-    if (!lastSelectedOption && m_size <= 1 && firstEnabledOption && !firstEnabledOption->selected()) {
+    if (!lastSelectedOption && m_size <= 1 && (!firstEnabledOption || (firstEnabledOption && !firstEnabledOption->selected()))) {
         selectOption(firstEnabledOption, reason == ResetReasonSelectedOptionRemoved ? 0 : DeselectOtherOptions);
         lastSelectedOption = firstEnabledOption;
         didChange = true;
diff --git a/third_party/WebKit/Source/core/html/HTMLVideoElement.h b/third_party/WebKit/Source/core/html/HTMLVideoElement.h
index 7b99a2c..8bd09cc 100644
--- a/third_party/WebKit/Source/core/html/HTMLVideoElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLVideoElement.h
@@ -87,6 +87,7 @@
     bool isHTMLVideoElement() const override { return true; }
     int sourceWidth() override { return videoWidth(); }
     int sourceHeight() override { return videoHeight(); }
+    bool isAccelerated() const override { return false; } // Video elements currently always go through RAM when used as a canvas image source.
 
     // ImageBitmapSource implementation
     IntSize bitmapSourceSize() const override;
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasImageSource.h b/third_party/WebKit/Source/core/html/canvas/CanvasImageSource.h
index f38c8e22..4e3e2fa 100644
--- a/third_party/WebKit/Source/core/html/canvas/CanvasImageSource.h
+++ b/third_party/WebKit/Source/core/html/canvas/CanvasImageSource.h
@@ -68,6 +68,7 @@
     virtual FloatSize defaultDestinationSize(const FloatSize& defaultObjectSize) const { return elementSize(defaultObjectSize); }
     virtual const KURL& sourceURL() const { return blankURL(); }
     virtual bool isOpaque() const { return false; }
+    virtual bool isAccelerated() const = 0;
 
     virtual int sourceWidth() = 0;
     virtual int sourceHeight() = 0;
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLSrcsetParser.cpp b/third_party/WebKit/Source/core/html/parser/HTMLSrcsetParser.cpp
index d16dbf3..e51d1b77 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLSrcsetParser.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLSrcsetParser.cpp
@@ -39,6 +39,7 @@
 #include "core/frame/UseCounter.h"
 #include "core/html/parser/HTMLParserIdioms.h"
 #include "core/inspector/ConsoleMessage.h"
+#include "platform/json/JSONValues.h"
 #include "wtf/text/ParsingUtilities.h"
 #include "wtf/text/StringToNumber.h"
 #include <algorithm>
@@ -301,7 +302,7 @@
                 if (document) {
                     UseCounter::count(document, UseCounter::SrcsetDroppedCandidate);
                     if (document->frame())
-                        document->frame()->console().addMessage(ConsoleMessage::create(OtherMessageSource, ErrorMessageLevel, String("Dropped srcset candidate ") + String(imageURLStart, imageURLEnd - imageURLStart)));
+                        document->frame()->console().addMessage(ConsoleMessage::create(OtherMessageSource, ErrorMessageLevel, String("Dropped srcset candidate ") + JSONValue::quoteString(String(imageURLStart, imageURLEnd - imageURLStart))));
                 }
                 continue;
             }
diff --git a/third_party/WebKit/Source/core/html/shadow/MediaControlElements.cpp b/third_party/WebKit/Source/core/html/shadow/MediaControlElements.cpp
index 557e254..1e2d37e2 100644
--- a/third_party/WebKit/Source/core/html/shadow/MediaControlElements.cpp
+++ b/third_party/WebKit/Source/core/html/shadow/MediaControlElements.cpp
@@ -586,7 +586,7 @@
     MediaControlOverflowMenuButtonElement* button = new MediaControlOverflowMenuButtonElement(mediaControls);
     button->ensureUserAgentShadowRoot();
     button->setType(InputTypeNames::button);
-    button->setShadowPseudoId(AtomicString("-internal-overflow-menu-button"));
+    button->setShadowPseudoId(AtomicString("-internal-media-controls-overflow-button"));
     button->setIsWanted(false);
     return button;
 }
diff --git a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp
index 21efada..b88c8cf 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp
@@ -40,6 +40,7 @@
 #include "core/css/CSSRuleList.h"
 #include "core/css/CSSStyleRule.h"
 #include "core/css/CSSStyleSheet.h"
+#include "core/css/CSSVariableData.h"
 #include "core/css/MediaList.h"
 #include "core/css/MediaQuery.h"
 #include "core/css/MediaValues.h"
@@ -75,7 +76,6 @@
 #include "core/page/Page.h"
 #include "core/style/StyleGeneratedImage.h"
 #include "core/style/StyleImage.h"
-#include "core/style/StyleVariableData.h"
 #include "core/svg/SVGElement.h"
 #include "platform/fonts/Font.h"
 #include "platform/fonts/FontCache.h"
diff --git a/third_party/WebKit/Source/core/layout/FragmentainerIterator.cpp b/third_party/WebKit/Source/core/layout/FragmentainerIterator.cpp
index b78d9865..80ef939 100644
--- a/third_party/WebKit/Source/core/layout/FragmentainerIterator.cpp
+++ b/third_party/WebKit/Source/core/layout/FragmentainerIterator.cpp
@@ -45,8 +45,6 @@
         if (atEnd())
             return;
     }
-
-    updateOutput();
 }
 
 void FragmentainerIterator::advance()
@@ -62,7 +60,30 @@
         if (atEnd())
             return;
     }
-    updateOutput();
+}
+
+LayoutSize FragmentainerIterator::paginationOffset() const
+{
+    DCHECK(!atEnd());
+    const MultiColumnFragmentainerGroup& group = currentGroup();
+    LayoutUnit fragmentainerLogicalTopInFlowThread = group.logicalTopInFlowThread() + m_currentFragmentainerIndex * group.logicalHeight();
+    return group.flowThreadTranslationAtOffset(fragmentainerLogicalTopInFlowThread, LayoutBox::AssociateWithLatterPage, CoordinateSpaceConversion::Visual);
+}
+
+LayoutRect FragmentainerIterator::fragmentainerInFlowThread() const
+{
+    DCHECK(!atEnd());
+    LayoutRect fragmentainerInFlowThread = currentGroup().flowThreadPortionRectAt(m_currentFragmentainerIndex);
+    m_flowThread.flipForWritingMode(fragmentainerInFlowThread);
+    return fragmentainerInFlowThread;
+}
+
+LayoutRect FragmentainerIterator::clipRectInFlowThread() const
+{
+    DCHECK(!atEnd());
+    LayoutRect clipRect = currentGroup().flowThreadPortionOverflowRectAt(m_currentFragmentainerIndex);
+    m_flowThread.flipForWritingMode(clipRect);
+    return clipRect;
 }
 
 const MultiColumnFragmentainerGroup& FragmentainerIterator::currentGroup() const
@@ -99,39 +120,26 @@
     // might not have to walk the entire fragmentainer group.
     group.columnIntervalForBlockRangeInFlowThread(m_logicalTopInFlowThread, m_logicalBottomInFlowThread, m_currentFragmentainerIndex, m_endFragmentainerIndex);
 
-    // Now intersect with the fragmentainers that actually intersect with the visual clip rect, to
-    // narrow it down even further. The clip rect needs to be relative to the current fragmentainer
-    // group.
-    LayoutRect clipRect = m_clipRectInMulticolContainer;
-    LayoutSize offset = group.flowThreadTranslationAtOffset(group.logicalTopInFlowThread(), LayoutBox::AssociateWithFormerPage, CoordinateSpaceConversion::Visual);
-    clipRect.move(-offset);
-    unsigned firstFragmentainerInClipRect, lastFragmentainerInClipRect;
-    group.columnIntervalForVisualRect(clipRect, firstFragmentainerInClipRect, lastFragmentainerInClipRect);
-    // If the two fragmentainer intervals are disjoint, there's nothing of interest in this
-    // fragmentainer group.
-    if (firstFragmentainerInClipRect > m_endFragmentainerIndex || lastFragmentainerInClipRect < m_currentFragmentainerIndex)
-        return false;
-    if (m_currentFragmentainerIndex < firstFragmentainerInClipRect)
-        m_currentFragmentainerIndex = firstFragmentainerInClipRect;
-    if (m_endFragmentainerIndex > lastFragmentainerInClipRect)
-        m_endFragmentainerIndex = lastFragmentainerInClipRect;
+    if (hasClipRect()) {
+        // Now intersect with the fragmentainers that actually intersect with the visual clip rect, to
+        // narrow it down even further. The clip rect needs to be relative to the current fragmentainer
+        // group.
+        LayoutRect clipRect = m_clipRectInMulticolContainer;
+        LayoutSize offset = group.flowThreadTranslationAtOffset(group.logicalTopInFlowThread(), LayoutBox::AssociateWithFormerPage, CoordinateSpaceConversion::Visual);
+        clipRect.move(-offset);
+        unsigned firstFragmentainerInClipRect, lastFragmentainerInClipRect;
+        group.columnIntervalForVisualRect(clipRect, firstFragmentainerInClipRect, lastFragmentainerInClipRect);
+        // If the two fragmentainer intervals are disjoint, there's nothing of interest in this
+        // fragmentainer group.
+        if (firstFragmentainerInClipRect > m_endFragmentainerIndex || lastFragmentainerInClipRect < m_currentFragmentainerIndex)
+            return false;
+        if (m_currentFragmentainerIndex < firstFragmentainerInClipRect)
+            m_currentFragmentainerIndex = firstFragmentainerInClipRect;
+        if (m_endFragmentainerIndex > lastFragmentainerInClipRect)
+            m_endFragmentainerIndex = lastFragmentainerInClipRect;
+    }
     DCHECK(m_endFragmentainerIndex >= m_currentFragmentainerIndex);
     return true;
 }
 
-void FragmentainerIterator::updateOutput()
-{
-    const MultiColumnFragmentainerGroup& group = currentGroup();
-
-    // Set the physical translation offset.
-    LayoutUnit fragmentainerLogicalTopInFlowThread = group.logicalTopInFlowThread() + m_currentFragmentainerIndex * group.logicalHeight();
-    m_paginationOffset = group.flowThreadTranslationAtOffset(fragmentainerLogicalTopInFlowThread, LayoutBox::AssociateWithLatterPage, CoordinateSpaceConversion::Visual);
-
-    // Set the overflow clip rect that corresponds to the fragmentainer.
-    m_clipRectInFlowThread = group.flowThreadPortionOverflowRectAt(m_currentFragmentainerIndex);
-
-    // Flip it into a physical rectangle.
-    m_flowThread.flipForWritingMode(m_clipRectInFlowThread);
-}
-
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/FragmentainerIterator.h b/third_party/WebKit/Source/core/layout/FragmentainerIterator.h
index 43a6a07c..e5afcff87 100644
--- a/third_party/WebKit/Source/core/layout/FragmentainerIterator.h
+++ b/third_party/WebKit/Source/core/layout/FragmentainerIterator.h
@@ -16,7 +16,11 @@
 // in block direction order.
 class FragmentainerIterator {
 public:
-    FragmentainerIterator(const LayoutFlowThread&, const LayoutRect& physicalBoundingBoxInFlowThread, const LayoutRect& clipRectInMulticolContainer);
+    // Initialize the iterator, and move to the first fragmentainer of interest.
+    // The clip rectangle is optional. If it's empty, it means that no clipping will be performed,
+    // and that the only thing that can limit the set of fragmentainers to visit is
+    // |physicalBoundingBox|.
+    FragmentainerIterator(const LayoutFlowThread&, const LayoutRect& physicalBoundingBoxInFlowThread, const LayoutRect& clipRectInMulticolContainer = LayoutRect());
 
     // Advance to the next fragmentainer. Not allowed to call this if atEnd() is true.
     void advance();
@@ -26,10 +30,13 @@
 
     // The physical translation to apply to shift the box when converting from flowthread to visual
     // coordinates.
-    LayoutSize paginationOffset() const { DCHECK(!atEnd()); return m_paginationOffset; }
+    LayoutSize paginationOffset() const;
+
+    // Return the physical content box of the current fragmentainer, relative to the flow thread.
+    LayoutRect fragmentainerInFlowThread() const;
 
     // Return the physical clip rectangle of the current fragmentainer, relative to the flow thread.
-    LayoutRect clipRectInFlowThread() const { DCHECK(!atEnd()); return m_clipRectInFlowThread; }
+    LayoutRect clipRectInFlowThread() const;
 
 private:
     const LayoutFlowThread& m_flowThread;
@@ -43,14 +50,11 @@
     LayoutUnit m_logicalTopInFlowThread;
     LayoutUnit m_logicalBottomInFlowThread;
 
-    LayoutSize m_paginationOffset;
-    LayoutRect m_clipRectInFlowThread;
-
     const MultiColumnFragmentainerGroup& currentGroup() const;
     void moveToNextFragmentainerGroup();
     bool setFragmentainersOfInterest();
-    void updateOutput();
     void setAtEnd() { m_currentColumnSet = nullptr; }
+    bool hasClipRect() const { return !m_clipRectInMulticolContainer.isEmpty(); }
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
index 9f61797..ef054b92 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
@@ -726,7 +726,7 @@
         }
 
         if (!positionedObject->needsLayout())
-            positionedObject->markForPaginationRelayoutIfNeeded(layoutScope);
+            markChildForPaginationRelayoutIfNeeded(*positionedObject, layoutScope);
 
         // FIXME: We should be able to do a r->setNeedsPositionedMovementLayout() here instead of a full layout. Need
         // to investigate why it does not trigger the correct invalidations in that case. crbug.com/350756
@@ -759,16 +759,6 @@
     }
 }
 
-void LayoutBlock::markForPaginationRelayoutIfNeeded(SubtreeLayoutScope& layoutScope)
-{
-    ASSERT(!needsLayout());
-    if (needsLayout())
-        return;
-
-    if (view()->layoutState()->pageLogicalHeightChanged() || (view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(*this, logicalTop()) != pageLogicalOffset()))
-        layoutScope.setChildNeedsLayout(this);
-}
-
 void LayoutBlock::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) const
 {
     BlockPainter(*this).paint(paintInfo, paintOffset);
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.h b/third_party/WebKit/Source/core/layout/LayoutBlock.h
index 5332d65..87c9fba 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlock.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBlock.h
@@ -172,9 +172,6 @@
     bool hasMarginAfterQuirk(const LayoutBox* child) const;
 
     void markPositionedObjectsForLayout();
-    // FIXME: Do we really need this to be virtual? It's just so we can call this on
-    // LayoutBoxes without needed to check whether they're LayoutBlocks first.
-    void markForPaginationRelayoutIfNeeded(SubtreeLayoutScope&) final;
 
     LayoutUnit textIndentOffset() const;
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
index 843e56d..9b1fd96 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
@@ -667,7 +667,7 @@
             // item, its width can change (because it has more available width).
             layoutScope.setChildNeedsLayout(&child);
         } else {
-            child.markForPaginationRelayoutIfNeeded(layoutScope);
+            markChildForPaginationRelayoutIfNeeded(child, layoutScope);
         }
     }
 
@@ -3085,7 +3085,7 @@
 
         SubtreeLayoutScope layoutScope(*childBox);
         if (isPaginated && !childBox->needsLayout())
-            childBox->markForPaginationRelayoutIfNeeded(layoutScope);
+            markChildForPaginationRelayoutIfNeeded(*childBox, layoutScope);
 
         childBox->layoutIfNeeded();
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
index 5fd4d716..d19f443 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
@@ -626,6 +626,10 @@
 
 void LayoutBox::absoluteQuads(Vector<FloatQuad>& quads) const
 {
+    if (LayoutFlowThread* flowThread = flowThreadContainingBlock()) {
+        flowThread->absoluteQuadsForDescendant(*this, quads);
+        return;
+    }
     quads.append(localToAbsoluteQuad(FloatRect(0, 0, m_frameRect.width().toFloat(), m_frameRect.height().toFloat())));
 }
 
@@ -4049,13 +4053,15 @@
     return false;
 }
 
-void LayoutBox::markForPaginationRelayoutIfNeeded(SubtreeLayoutScope& layoutScope)
+void LayoutBox::markChildForPaginationRelayoutIfNeeded(LayoutBox& child, SubtreeLayoutScope& layoutScope)
 {
-    ASSERT(!needsLayout());
-    // If fragmentation height has changed, we need to lay out. No need to enter the layoutObject if it
-    // is childless, though.
-    if (view()->layoutState()->pageLogicalHeightChanged() && slowFirstChild())
-        layoutScope.setChildNeedsLayout(this);
+    DCHECK(!child.needsLayout());
+    LayoutState* layoutState = view()->layoutState();
+    if (!layoutState->isPaginated())
+        return;
+
+    if (layoutState->pageLogicalHeightChanged() || (layoutState->pageLogicalHeight() && layoutState->pageLogicalOffset(child, child.logicalTop()) != child.pageLogicalOffset()))
+        layoutScope.setChildNeedsLayout(&child);
 }
 
 void LayoutBox::markOrthogonalWritingModeRoot()
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.h b/third_party/WebKit/Source/core/layout/LayoutBox.h
index 23357c6..927a763 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBox.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBox.h
@@ -827,7 +827,7 @@
     bool shrinkToAvoidFloats() const;
     virtual bool avoidsFloats() const;
 
-    virtual void markForPaginationRelayoutIfNeeded(SubtreeLayoutScope&);
+    void markChildForPaginationRelayoutIfNeeded(LayoutBox& child, SubtreeLayoutScope&);
 
     bool isWritingModeRoot() const { return !parent() || parent()->style()->getWritingMode() != style()->getWritingMode(); }
     bool isOrthogonalWritingModeRoot() const { return parent() && parent()->isHorizontalWritingMode() != isHorizontalWritingMode(); }
diff --git a/third_party/WebKit/Source/core/layout/LayoutDeprecatedFlexibleBox.cpp b/third_party/WebKit/Source/core/layout/LayoutDeprecatedFlexibleBox.cpp
index bf3a2c98..ed81315 100644
--- a/third_party/WebKit/Source/core/layout/LayoutDeprecatedFlexibleBox.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutDeprecatedFlexibleBox.cpp
@@ -452,7 +452,7 @@
             child->computeAndSetBlockDirectionMargins(this);
 
             if (!child->needsLayout())
-                child->markForPaginationRelayoutIfNeeded(layoutScope);
+                markChildForPaginationRelayoutIfNeeded(*child, layoutScope);
 
             // Now do the layout.
             child->layoutIfNeeded();
@@ -526,7 +526,7 @@
                 layoutScope.setChildNeedsLayout(child);
 
             if (!child->needsLayout())
-                child->markForPaginationRelayoutIfNeeded(layoutScope);
+                markChildForPaginationRelayoutIfNeeded(*child, layoutScope);
 
             child->layoutIfNeeded();
 
@@ -762,7 +762,7 @@
             setHeight(size().height() + child->marginTop());
 
             if (!child->needsLayout())
-                child->markForPaginationRelayoutIfNeeded(layoutScope);
+                markChildForPaginationRelayoutIfNeeded(*child, layoutScope);
 
             // Now do a layout.
             child->layoutIfNeeded();
diff --git a/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.cpp b/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.cpp
index 478c3265..76d82b8 100644
--- a/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.cpp
@@ -1682,7 +1682,7 @@
         }
         updateBlockChildDirtyBitsBeforeLayout(forceChildRelayout, *child);
         if (!child->needsLayout())
-            child->markForPaginationRelayoutIfNeeded(layoutScope);
+            markChildForPaginationRelayoutIfNeeded(*child, layoutScope);
         if (child->needsLayout())
             m_relaidOutChildren.add(child);
         child->layoutIfNeeded();
diff --git a/third_party/WebKit/Source/core/layout/LayoutFlowThread.cpp b/third_party/WebKit/Source/core/layout/LayoutFlowThread.cpp
index 8b4bd67..1ddbf24 100644
--- a/third_party/WebKit/Source/core/layout/LayoutFlowThread.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutFlowThread.cpp
@@ -29,6 +29,7 @@
 
 #include "core/layout/LayoutFlowThread.h"
 
+#include "core/layout/FragmentainerIterator.h"
 #include "core/layout/LayoutMultiColumnSet.h"
 
 namespace blink {
@@ -121,6 +122,27 @@
     }
 }
 
+void LayoutFlowThread::absoluteQuadsForDescendant(const LayoutBox& descendant, Vector<FloatQuad>& quads)
+{
+    LayoutPoint offsetFromFlowThread;
+    for (const LayoutObject* object = &descendant; object != this;) {
+        const LayoutObject* container = object->container();
+        offsetFromFlowThread += object->offsetFromContainer(container);
+        object = container;
+    }
+    LayoutRect boundingRectInFlowThread(offsetFromFlowThread, descendant.frameRect().size());
+    // Set up a fragments relative to the descendant, in the flow thread coordinate space, and
+    // convert each of them, individually, to absolute coordinates.
+    for (FragmentainerIterator iterator(*this, boundingRectInFlowThread); !iterator.atEnd(); iterator.advance()) {
+        LayoutRect fragment = boundingRectInFlowThread;
+        // We use inclusiveIntersect() because intersect() would reset the coordinates for
+        // zero-height objects.
+        fragment.inclusiveIntersect(iterator.fragmentainerInFlowThread());
+        fragment.moveBy(-offsetFromFlowThread);
+        quads.append(descendant.localToAbsoluteQuad(FloatRect(fragment)));
+    }
+}
+
 bool LayoutFlowThread::nodeAtPoint(HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
 {
     if (hitTestAction == HitTestBlockBackground)
diff --git a/third_party/WebKit/Source/core/layout/LayoutFlowThread.h b/third_party/WebKit/Source/core/layout/LayoutFlowThread.h
index 1e61617..19e145ca 100644
--- a/third_party/WebKit/Source/core/layout/LayoutFlowThread.h
+++ b/third_party/WebKit/Source/core/layout/LayoutFlowThread.h
@@ -81,6 +81,8 @@
     virtual void flowThreadDescendantStyleWillChange(LayoutBox*, StyleDifference, const ComputedStyle& newStyle) { }
     virtual void flowThreadDescendantStyleDidChange(LayoutBox*, StyleDifference, const ComputedStyle& oldStyle) { }
 
+    void absoluteQuadsForDescendant(const LayoutBox& descendant, Vector<FloatQuad>&);
+
     bool nodeAtPoint(HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) final;
 
     virtual void addColumnSetToThread(LayoutMultiColumnSet*) = 0;
diff --git a/third_party/WebKit/Source/core/layout/LayoutTable.cpp b/third_party/WebKit/Source/core/layout/LayoutTable.cpp
index 8013404..432c270d 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTable.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTable.cpp
@@ -483,7 +483,7 @@
 
         for (LayoutObject* child = firstChild(); child; child = child->nextSibling()) {
             if (!child->needsLayout() && child->isBox())
-                toLayoutBox(child)->markForPaginationRelayoutIfNeeded(layouter);
+                markChildForPaginationRelayoutIfNeeded(*toLayoutBox(child), layouter);
             if (child->isTableSection()) {
                 LayoutTableSection* section = toLayoutTableSection(child);
                 if (m_columnLogicalWidthChanged)
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableRow.cpp b/third_party/WebKit/Source/core/layout/LayoutTableRow.cpp
index e51a52a..95d96e98 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableRow.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTableRow.cpp
@@ -180,7 +180,7 @@
     for (LayoutTableCell* cell = firstCell(); cell; cell = cell->nextCell()) {
         SubtreeLayoutScope layouter(*cell);
         if (!cell->needsLayout())
-            cell->markForPaginationRelayoutIfNeeded(layouter);
+            markChildForPaginationRelayoutIfNeeded(*cell, layouter);
         if (cell->needsLayout())
             cell->layout();
         // We're laying out each cell here to establish its raw logical height so it can be used to
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp b/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp
index 2edd3bc3..749707b 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp
@@ -849,7 +849,7 @@
 
         if (LayoutTableRow* rowLayoutObject = m_grid[r].rowLayoutObject) {
             if (!rowLayoutObject->needsLayout())
-                rowLayoutObject->markForPaginationRelayoutIfNeeded(layouter);
+                markChildForPaginationRelayoutIfNeeded(*rowLayoutObject, layouter);
             rowLayoutObject->layoutIfNeeded();
         }
     }
@@ -1087,7 +1087,7 @@
             setLogicalPositionForCell(cell, c);
 
             if (!cell->needsLayout())
-                cell->markForPaginationRelayoutIfNeeded(layouter);
+                markChildForPaginationRelayoutIfNeeded(*cell, layouter);
 
             cell->layoutIfNeeded();
 
diff --git a/third_party/WebKit/Source/core/layout/MultiColumnFragmentainerGroup.cpp b/third_party/WebKit/Source/core/layout/MultiColumnFragmentainerGroup.cpp
index b992f1b..0a8a79a2 100644
--- a/third_party/WebKit/Source/core/layout/MultiColumnFragmentainerGroup.cpp
+++ b/third_party/WebKit/Source/core/layout/MultiColumnFragmentainerGroup.cpp
@@ -437,7 +437,14 @@
     logicalBottomInFlowThread = std::min(logicalBottomInFlowThread, this->logicalBottomInFlowThread());
     ASSERT(logicalTopInFlowThread <= logicalBottomInFlowThread);
     firstColumn = columnIndexAtOffset(logicalTopInFlowThread, LayoutBox::AssociateWithLatterPage);
-    lastColumn = columnIndexAtOffset(logicalBottomInFlowThread, LayoutBox::AssociateWithFormerPage);
+    if (logicalBottomInFlowThread == logicalTopInFlowThread) {
+        // Zero-height block range. There'll be one column in the interval. Set it right away. This
+        // is important if we're at a column boundary, since calling columnIndexAtOffset() with the
+        // end-exclusive bottom offset would actually give us the *previous* column.
+        lastColumn = firstColumn;
+    } else {
+        lastColumn = columnIndexAtOffset(logicalBottomInFlowThread, LayoutBox::AssociateWithFormerPage);
+    }
 }
 
 void MultiColumnFragmentainerGroup::columnIntervalForVisualRect(const LayoutRect& rect, unsigned& firstColumn, unsigned& lastColumn) const
diff --git a/third_party/WebKit/Source/core/layout/MultiColumnFragmentainerGroup.h b/third_party/WebKit/Source/core/layout/MultiColumnFragmentainerGroup.h
index 343c8df3..fcf5a21 100644
--- a/third_party/WebKit/Source/core/layout/MultiColumnFragmentainerGroup.h
+++ b/third_party/WebKit/Source/core/layout/MultiColumnFragmentainerGroup.h
@@ -67,6 +67,7 @@
     LayoutPoint visualPointToFlowThreadPoint(const LayoutPoint& visualPoint) const;
     LayoutRect fragmentsBoundingBox(const LayoutRect& boundingBoxInFlowThread) const;
 
+    LayoutRect flowThreadPortionRectAt(unsigned columnIndex) const;
     LayoutRect flowThreadPortionOverflowRectAt(unsigned columnIndex) const;
 
     // Get the first and the last column intersecting the specified block range.
@@ -93,7 +94,6 @@
 
     LayoutRect columnRectAt(unsigned columnIndex) const;
     LayoutUnit logicalTopInFlowThreadAt(unsigned columnIndex) const { return m_logicalTopInFlowThread + columnIndex * m_columnHeight; }
-    LayoutRect flowThreadPortionRectAt(unsigned columnIndex) const;
 
     // Return the column that the specified visual point belongs to. Only the coordinate on the
     // column progression axis is relevant. Every point belongs to a column, even if said point is
diff --git a/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h b/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h
index c8f2fc6..68fc1c0b 100644
--- a/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h
+++ b/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h
@@ -1005,6 +1005,8 @@
         if (!hyphenated && isBreakAtSoftHyphen() && !disableSoftHyphen) {
             hyphenated = true;
             m_atEnd = true;
+        } else if (!m_ignoringSpaces && canBreakMidWord && m_width.committedWidth()) {
+            m_atEnd = true;
         }
     }
     return false;
diff --git a/third_party/WebKit/Source/core/layout/svg/ReferenceFilterBuilder.cpp b/third_party/WebKit/Source/core/layout/svg/ReferenceFilterBuilder.cpp
index d4fd250..4242c4bd 100644
--- a/third_party/WebKit/Source/core/layout/svg/ReferenceFilterBuilder.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/ReferenceFilterBuilder.cpp
@@ -29,9 +29,9 @@
 
 #include "core/dom/Element.h"
 #include "core/fetch/DocumentResource.h"
+#include "core/style/FilterOperation.h"
 #include "core/svg/SVGDocumentExtensions.h"
 #include "core/svg/SVGFilterElement.h"
-#include "platform/graphics/filters/FilterOperation.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/layout/svg/SVGLayoutSupport.cpp b/third_party/WebKit/Source/core/layout/svg/SVGLayoutSupport.cpp
index 3feec3e49..4de88e8 100644
--- a/third_party/WebKit/Source/core/layout/svg/SVGLayoutSupport.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/SVGLayoutSupport.cpp
@@ -95,8 +95,11 @@
             const FloatSize strokeSize = rootTransform.mapSize(
                 FloatSize(strokeWidthForHairlinePadding, strokeWidthForHairlinePadding));
             if (strokeSize.width() < 1 || strokeSize.height() < 1) {
-                const float pad = 0.5f - std::min(strokeSize.width(), strokeSize.height()) / 2;
-                ASSERT(pad > 0);
+                float pad = 0.5f - std::min(strokeSize.width(), strokeSize.height()) / 2;
+                DCHECK_GT(pad, 0);
+                // Additionally, square/round caps can potentially introduce an outset <= 0.5
+                if (object.styleRef().svgStyle().capStyle() != ButtCap)
+                    pad += 0.5f;
                 adjustedRect.inflate(pad);
             }
         }
diff --git a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
index aca2279..6364869 100644
--- a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
@@ -57,6 +57,7 @@
 #include "public/platform/WebURLRequest.h"
 #include "wtf/Assertions.h"
 #include "wtf/PtrUtil.h"
+#include "wtf/WeakPtr.h"
 #include <memory>
 
 namespace blink {
@@ -151,7 +152,6 @@
     , m_corsRedirectLimit(m_options.crossOriginRequestPolicy == UseAccessControl ? kMaxCORSRedirects : 0)
     , m_redirectMode(WebURLRequest::FetchRedirectModeFollow)
     , m_didRedirect(false)
-    , m_weakFactory(this)
 {
     DCHECK(client);
 }
@@ -434,10 +434,6 @@
     }
 
     if (m_redirectMode == WebURLRequest::FetchRedirectModeManual) {
-        // Keep |this| alive even if the client release a reference in
-        // responseReceived().
-        WeakPtr<DocumentThreadableLoader> self(m_weakFactory.createWeakPtr());
-
         // We use |m_redirectMode| to check the original redirect mode.
         // |request| is a new request for redirect. So we don't set the redirect
         // mode of it in WebURLLoaderImpl::Context::OnReceivedRedirect().
@@ -450,11 +446,6 @@
         // because it doesn't store the body of redirect responses.
         responseReceived(resource, redirectResponse, wrapUnique(new EmptyDataHandle()));
 
-        if (!self) {
-            request = ResourceRequest();
-            return;
-        }
-
         if (m_client) {
             DCHECK(m_actualRequest.isNull());
             notifyFinished(resource);
@@ -868,8 +859,6 @@
             newRequest.setOriginRestriction(FetchRequest::NoOriginRestriction);
         DCHECK(!resource());
 
-        WeakPtr<DocumentThreadableLoader> self(m_weakFactory.createWeakPtr());
-
         if (request.requestContext() == WebURLRequest::RequestContextVideo || request.requestContext() == WebURLRequest::RequestContextAudio)
             setResource(RawResource::fetchMedia(newRequest, document().fetcher()));
         else if (request.requestContext() == WebURLRequest::RequestContextManifest)
@@ -877,10 +866,6 @@
         else
             setResource(RawResource::fetch(newRequest, document().fetcher()));
 
-        // setResource() might call notifyFinished() synchronously, and thus
-        if (!self)
-            return;
-
         if (!resource()) {
             InspectorInstrumentation::documentThreadableLoaderFailedToStartLoadingForClient(m_document, m_client);
             ThreadableLoaderClient* client = m_client;
diff --git a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h
index fcd9c6a..190c165 100644
--- a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h
+++ b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h
@@ -42,7 +42,6 @@
 #include "platform/network/ResourceError.h"
 #include "platform/weborigin/Referrer.h"
 #include "wtf/Forward.h"
-#include "wtf/WeakPtr.h"
 #include "wtf/text/WTFString.h"
 #include <memory>
 
@@ -238,7 +237,6 @@
         Referrer m_referrerAfterRedirect;
 
         RawResourceClientStateChecker m_checker;
-        WeakPtrFactory<DocumentThreadableLoader> m_weakFactory;
     };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/loader/EmptyClients.h b/third_party/WebKit/Source/core/loader/EmptyClients.h
index 3ea5564..aef8ae9 100644
--- a/third_party/WebKit/Source/core/loader/EmptyClients.h
+++ b/third_party/WebKit/Source/core/loader/EmptyClients.h
@@ -210,7 +210,7 @@
 
     void dispatchDidHandleOnloadEvents() override {}
     void dispatchDidReceiveServerRedirectForProvisionalLoad() override {}
-    void dispatchWillClose() override {}
+    void dispatchWillCommitProvisionalLoad() override {}
     void dispatchDidStartProvisionalLoad(double triggeringEventTime) override {}
     void dispatchDidReceiveTitle(const String&) override {}
     void dispatchDidChangeIcons(IconType) override {}
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
index 84d16074..fca1a3c 100644
--- a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
@@ -346,6 +346,8 @@
     // That call doesn't exist for redirects, so call preareRequest() here.
     if (!redirectResponse.isNull())
         prepareRequest(request);
+    else
+        frame()->loader().progress().willStartLoading(identifier, request.priority());
     TRACE_EVENT_INSTANT1("devtools.timeline", "ResourceSendRequest", TRACE_EVENT_SCOPE_THREAD, "data", InspectorSendRequestEvent::data(identifier, frame(), request));
     InspectorInstrumentation::willSendRequest(frame(), identifier, masterDocumentLoader(), request, redirectResponse, initiatorInfo);
     if (frame()->frameScheduler())
@@ -431,7 +433,6 @@
 void FrameFetchContext::willStartLoadingResource(unsigned long identifier, ResourceRequest& request, Resource::Type type)
 {
     TRACE_EVENT_ASYNC_BEGIN1("blink.net", "Resource", identifier, "data", loadResourceTraceData(identifier, request.url(), request.priority()));
-    frame()->loader().progress().willStartLoading(identifier, request.priority());
     prepareRequest(request);
 
     if (!m_documentLoader || m_documentLoader->fetcher()->archive() || !request.url().isValid())
diff --git a/third_party/WebKit/Source/core/loader/FrameLoader.cpp b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
index af4d712..08f9cce 100644
--- a/third_party/WebKit/Source/core/loader/FrameLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
@@ -1115,7 +1115,7 @@
     // frame on a detached DOM tree, which is bad.
     SubframeLoadingDisabler disabler(m_frame->document());
     if (m_documentLoader) {
-        client()->dispatchWillClose();
+        client()->dispatchWillCommitProvisionalLoad();
         dispatchUnloadEvent();
     }
     m_frame->detachChildren();
diff --git a/third_party/WebKit/Source/core/loader/FrameLoaderClient.h b/third_party/WebKit/Source/core/loader/FrameLoaderClient.h
index b50fa6ed1..de1cafd4 100644
--- a/third_party/WebKit/Source/core/loader/FrameLoaderClient.h
+++ b/third_party/WebKit/Source/core/loader/FrameLoaderClient.h
@@ -97,7 +97,7 @@
     virtual void dispatchDidHandleOnloadEvents() = 0;
     virtual void dispatchDidReceiveServerRedirectForProvisionalLoad() = 0;
     virtual void dispatchDidNavigateWithinPage(HistoryItem*, HistoryCommitType, bool contentInitiated) { }
-    virtual void dispatchWillClose() = 0;
+    virtual void dispatchWillCommitProvisionalLoad() = 0;
     virtual void dispatchDidStartProvisionalLoad(double triggeringEventTime) = 0;
     virtual void dispatchDidReceiveTitle(const String&) = 0;
     virtual void dispatchDidChangeIcons(IconType) = 0;
diff --git a/third_party/WebKit/Source/core/loader/appcache/ApplicationCache.cpp b/third_party/WebKit/Source/core/loader/appcache/ApplicationCache.cpp
index 6cca281..71030e4 100644
--- a/third_party/WebKit/Source/core/loader/appcache/ApplicationCache.cpp
+++ b/third_party/WebKit/Source/core/loader/appcache/ApplicationCache.cpp
@@ -61,9 +61,9 @@
 
 ApplicationCacheHost* ApplicationCache::applicationCacheHost() const
 {
-    if (!m_frame || !m_frame->loader().documentLoader())
+    if (!frame() || !frame()->loader().documentLoader())
         return 0;
-    return m_frame->loader().documentLoader()->applicationCacheHost();
+    return frame()->loader().documentLoader()->applicationCacheHost();
 }
 
 unsigned short ApplicationCache::status() const
@@ -105,8 +105,8 @@
 
 ExecutionContext* ApplicationCache::getExecutionContext() const
 {
-    if (m_frame)
-        return m_frame->document();
+    if (frame())
+        return frame()->document();
     return 0;
 }
 
@@ -136,10 +136,10 @@
 
 void ApplicationCache::recordAPIUseType() const
 {
-    if (!m_frame)
+    if (!frame())
         return;
 
-    Document* document = m_frame->document();
+    Document* document = frame()->document();
 
     if (!document)
         return;
diff --git a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp
index e1f5804c..8d9427b 100644
--- a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp
+++ b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp
@@ -156,6 +156,11 @@
     return m_context->isPaintable();
 }
 
+bool OffscreenCanvas::isAccelerated() const
+{
+    return m_context && m_context->isAccelerated();
+}
+
 OffscreenCanvasFrameDispatcher* OffscreenCanvas::getOrCreateFrameDispatcher()
 {
     if (!m_frameDispatcher) {
diff --git a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.h b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.h
index c303aae..daed80b 100644
--- a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.h
+++ b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.h
@@ -69,6 +69,7 @@
     bool isOffscreenCanvas() const final { return true; }
     FloatSize elementSize(const FloatSize& defaultObjectSize) const final { return FloatSize(width(), height()); }
     bool isOpaque() const final;
+    bool isAccelerated() const final;
     int sourceWidth() final { return width(); }
     int sourceHeight() final { return height(); }
 
diff --git a/third_party/WebKit/Source/core/paint/FilterEffectBuilder.cpp b/third_party/WebKit/Source/core/paint/FilterEffectBuilder.cpp
index 11c6b575..22728385 100644
--- a/third_party/WebKit/Source/core/paint/FilterEffectBuilder.cpp
+++ b/third_party/WebKit/Source/core/paint/FilterEffectBuilder.cpp
@@ -27,6 +27,7 @@
 #include "core/paint/FilterEffectBuilder.h"
 
 #include "core/layout/svg/ReferenceFilterBuilder.h"
+#include "core/style/FilterOperations.h"
 #include "core/svg/SVGFilterElement.h"
 #include "core/svg/SVGLengthContext.h"
 #include "core/svg/graphics/filters/SVGFilterBuilder.h"
@@ -40,7 +41,6 @@
 #include "platform/graphics/filters/FEGaussianBlur.h"
 #include "platform/graphics/filters/Filter.h"
 #include "platform/graphics/filters/FilterEffect.h"
-#include "platform/graphics/filters/FilterOperations.h"
 #include "platform/graphics/filters/SkiaImageFilterBuilder.h"
 #include "platform/graphics/filters/SourceGraphic.h"
 #include "public/platform/WebPoint.h"
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerFilterInfo.cpp b/third_party/WebKit/Source/core/paint/PaintLayerFilterInfo.cpp
index 52b970e..17afcb2 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerFilterInfo.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerFilterInfo.cpp
@@ -30,8 +30,8 @@
 #include "core/paint/PaintLayerFilterInfo.h"
 
 #include "core/paint/PaintLayer.h"
+#include "core/style/FilterOperations.h"
 #include "platform/graphics/filters/FilterEffect.h"
-#include "platform/graphics/filters/FilterOperations.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
index 2673420..9be1b9a 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
@@ -218,8 +218,8 @@
 void PaintPropertyTreeBuilder::updateTransform(const LayoutObject& object, PaintPropertyTreeBuilderContext& context)
 {
     if (object.isSVG() && !object.isSVGRoot()) {
-        // SVG does not use paint offset internally.
-        DCHECK(context.current.paintOffset == LayoutPoint());
+        // SVG (other than SVGForeignObject) does not use paint offset internally.
+        DCHECK(object.isSVGForeignObject() || context.current.paintOffset == LayoutPoint());
 
         // FIXME(pdr): Check for the presence of a transform instead of the value. Checking for an
         // identity matrix will cause the property tree structure to change during animations if
@@ -438,19 +438,19 @@
 
 void PaintPropertyTreeBuilder::updateScrollAndScrollTranslation(const LayoutObject& object, PaintPropertyTreeBuilderContext& context)
 {
-    if (object.isBoxModelObject() && object.hasOverflowClip()) {
-        PaintLayer* layer = toLayoutBoxModelObject(object).layer();
-        DCHECK(layer);
-        DoubleSize scrollOffset = layer->getScrollableArea()->scrollOffset();
-        if (!scrollOffset.isZero() || layer->scrollsOverflow()) {
+    if (object.hasOverflowClip()) {
+        const LayoutBox& box = toLayoutBox(object);
+        const PaintLayerScrollableArea* scrollableArea = box.getScrollableArea();
+        DoubleSize scrollOffset = box.scrolledContentOffset();
+        if (!scrollOffset.isZero() || scrollableArea->scrollsOverflow()) {
             TransformationMatrix matrix = TransformationMatrix().translate(-scrollOffset.width(), -scrollOffset.height());
             context.current.transform = object.getMutableForPainting().ensureObjectPaintProperties().createOrUpdateScrollTranslation(
                 context.current.transform, matrix, FloatPoint3D(), context.current.shouldFlattenInheritedTransform, context.current.renderingContextID);
 
-            IntSize scrollClip = layer->getScrollableArea()->visibleContentRect().size();
-            IntSize scrollBounds = layer->getScrollableArea()->contentsSize();
-            bool userScrollableHorizontal = layer->getScrollableArea()->userInputScrollable(HorizontalScrollbar);
-            bool userScrollableVertical = layer->getScrollableArea()->userInputScrollable(VerticalScrollbar);
+            IntSize scrollClip = scrollableArea->visibleContentRect().size();
+            IntSize scrollBounds = scrollableArea->contentsSize();
+            bool userScrollableHorizontal = scrollableArea->userInputScrollable(HorizontalScrollbar);
+            bool userScrollableVertical = scrollableArea->userInputScrollable(VerticalScrollbar);
             context.current.scroll = object.getMutableForPainting().ensureObjectPaintProperties().createOrUpdateScroll(
                 context.current.scroll, context.current.transform, scrollClip, scrollBounds, userScrollableHorizontal, userScrollableVertical);
 
@@ -541,7 +541,10 @@
     default:
         ASSERT_NOT_REACHED();
     }
-    if (boxModelObject.isBox() && (!boxModelObject.isSVG() || boxModelObject.isSVGRoot())) {
+
+    // SVGForeignObject needs paint offset because its viewport offset is baked into its location(),
+    // while its localSVGTransform() doesn't contain the offset.
+    if (boxModelObject.isBox() && (!boxModelObject.isSVG() || boxModelObject.isSVGRoot() || boxModelObject.isSVGForeignObject())) {
         // TODO(pdr): Several calls in this function walk back up the tree to calculate containers
         // (e.g., topLeftLocation, offsetForInFlowPosition*). The containing block and other
         // containers can be stored on PaintPropertyTreeBuilderContext instead of recomputing them.
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinter.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinter.cpp
index 4d0ea458..4373aca 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinter.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinter.cpp
@@ -41,6 +41,20 @@
         return stringBuilder.toString();
     }
 
+    String pathAsString(const PropertyTreeNode* lastNode)
+    {
+        const PropertyTreeNode* node = lastNode;
+        while (!node->isRoot()) {
+            addPropertyNode(node, "");
+            node = node->parent();
+        }
+        addPropertyNode(node, "root");
+
+        StringBuilder stringBuilder;
+        addAllPropertyNodes(stringBuilder, node);
+        return stringBuilder.toString();
+    }
+
     void addPropertyNode(const PropertyTreeNode* node, String debugInfo)
     {
         m_nodeToDebugString.set(node, debugInfo);
@@ -548,6 +562,46 @@
     return blink::PropertyTreePrinter<blink::ScrollPaintPropertyNode>().treeAsString(rootFrame);
 }
 
+String transformPaintPropertyPathAsString(const blink::TransformPaintPropertyNode* node)
+{
+    return blink::PropertyTreePrinter<blink::TransformPaintPropertyNode>().pathAsString(node);
+}
+
+String clipPaintPropertyPathAsString(const blink::ClipPaintPropertyNode* node)
+{
+    return blink::PropertyTreePrinter<blink::ClipPaintPropertyNode>().pathAsString(node);
+}
+
+String effectPaintPropertyPathAsString(const blink::EffectPaintPropertyNode* node)
+{
+    return blink::PropertyTreePrinter<blink::EffectPaintPropertyNode>().pathAsString(node);
+}
+
+String scrollPaintPropertyPathAsString(const blink::ScrollPaintPropertyNode* node)
+{
+    return blink::PropertyTreePrinter<blink::ScrollPaintPropertyNode>().pathAsString(node);
+}
+
+void showPaintPropertyPath(const blink::TransformPaintPropertyNode* node)
+{
+    fprintf(stderr, "%s\n", transformPaintPropertyPathAsString(node).utf8().data());
+}
+
+void showPaintPropertyPath(const blink::ClipPaintPropertyNode* node)
+{
+    fprintf(stderr, "%s\n", clipPaintPropertyPathAsString(node).utf8().data());
+}
+
+void showPaintPropertyPath(const blink::EffectPaintPropertyNode* node)
+{
+    fprintf(stderr, "%s\n", effectPaintPropertyPathAsString(node).utf8().data());
+}
+
+void showPaintPropertyPath(const blink::ScrollPaintPropertyNode* node)
+{
+    fprintf(stderr, "%s\n", scrollPaintPropertyPathAsString(node).utf8().data());
+}
+
 String paintPropertyTreeGraph(const blink::FrameView& frameView)
 {
     blink::PaintPropertyTreeGraphBuilder builder;
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinter.h b/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinter.h
index ed1b82b5..f7e830f 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinter.h
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinter.h
@@ -26,12 +26,20 @@
 CORE_EXPORT void showClipPropertyTree(const blink::FrameView& rootFrame);
 CORE_EXPORT void showEffectPropertyTree(const blink::FrameView& rootFrame);
 CORE_EXPORT void showScrollPropertyTree(const blink::FrameView& rootFrame);
-
 CORE_EXPORT String transformPropertyTreeAsString(const blink::FrameView& rootFrame);
 CORE_EXPORT String clipPropertyTreeAsString(const blink::FrameView& rootFrame);
 CORE_EXPORT String effectPropertyTreeAsString(const blink::FrameView& rootFrame);
 CORE_EXPORT String scrollPropertyTreeAsString(const blink::FrameView& rootFrame);
 
+CORE_EXPORT void showPaintPropertyPath(const blink::TransformPaintPropertyNode*);
+CORE_EXPORT void showPaintPropertyPath(const blink::ClipPaintPropertyNode*);
+CORE_EXPORT void showPaintPropertyPath(const blink::EffectPaintPropertyNode*);
+CORE_EXPORT void showPaintPropertyPath(const blink::ScrollPaintPropertyNode*);
+CORE_EXPORT String transformPaintPropertyPathAsString(const blink::TransformPaintPropertyNode*);
+CORE_EXPORT String clipPaintPropertyPathAsString(const blink::ClipPaintPropertyNode*);
+CORE_EXPORT String effectPaintPropertyPathAsString(const blink::EffectPaintPropertyNode*);
+CORE_EXPORT String scrollPaintPropertyPathAsString(const blink::ScrollPaintPropertyNode*);
+
 CORE_EXPORT String paintPropertyTreeGraph(const blink::FrameView&);
 
 #endif // ifndef NDEBUG
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinterTest.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinterTest.cpp
index de04f711..ee82f21 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinterTest.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinterTest.cpp
@@ -4,6 +4,7 @@
 
 #include "core/paint/PaintPropertyTreePrinter.h"
 
+#include "core/layout/LayoutObject.h"
 #include "core/layout/LayoutTestHelper.h"
 #include "platform/testing/RuntimeEnabledFeaturesTestHelpers.h"
 #include "testing/gmock/include/gmock/gmock-matchers.h"
@@ -80,6 +81,55 @@
             "  Scroll \\(.*\\) .*"));
 }
 
+TEST_P(PaintPropertyTreePrinterTest, SimpleTransformTreePath)
+{
+    setBodyInnerHTML("<div id='transform' style='transform: translate3d(10px, 10px, 0px);'></div>");
+    LayoutObject* transformedObject = document().getElementById("transform")->layoutObject();
+    const ObjectPaintProperties* transformedObjectProperties = transformedObject->objectPaintProperties();
+    String transformPathAsString = transformPaintPropertyPathAsString(transformedObjectProperties->transform());
+    EXPECT_THAT(transformPathAsString.ascii().data(),
+        testing::MatchesRegex("root .* transform.*"
+            "  .* transform.*"
+            "    .* transform.*"
+            "       .* transform.*"));
+}
+
+TEST_P(PaintPropertyTreePrinterTest, SimpleClipTreePath)
+{
+    setBodyInnerHTML("<div id='clip' style='position: absolute; clip: rect(10px, 80px, 70px, 40px);'></div>");
+    LayoutObject* clippedObject = document().getElementById("clip")->layoutObject();
+    const ObjectPaintProperties* clippedObjectProperties = clippedObject->objectPaintProperties();
+    String clipPathAsString = clipPaintPropertyPathAsString(clippedObjectProperties->cssClip());
+    EXPECT_THAT(clipPathAsString.ascii().data(),
+        testing::MatchesRegex("root .* rect.*"
+            "  .* rect.*"
+            "    .* rect.*"));
+}
+
+TEST_P(PaintPropertyTreePrinterTest, SimpleEffectTreePath)
+{
+    setBodyInnerHTML("<div id='effect' style='opacity: 0.9;'></div>");
+    LayoutObject* effectObject = document().getElementById("effect")->layoutObject();
+    const ObjectPaintProperties* effectObjectProperties = effectObject->objectPaintProperties();
+    String effectPathAsString = effectPaintPropertyPathAsString(effectObjectProperties->effect());
+    EXPECT_THAT(effectPathAsString.ascii().data(),
+        testing::MatchesRegex("root .* opacity.*"
+            "  .* opacity.*"));
+}
+
+TEST_P(PaintPropertyTreePrinterTest, SimpleScrollTreePath)
+{
+    setBodyInnerHTML("<div id='scroll' style='overflow: scroll; height: 100px;'>"
+        "  <div id='forceScroll' style='height: 4000px;'></div>"
+        "</div>");
+    LayoutObject* scrollObject = document().getElementById("scroll")->layoutObject();
+    const ObjectPaintProperties* scrollObjectProperties = scrollObject->objectPaintProperties();
+    String scrollPathAsString = scrollPaintPropertyPathAsString(scrollObjectProperties->scroll());
+    EXPECT_THAT(scrollPathAsString.ascii().data(),
+        testing::MatchesRegex("root .* scroll.*"
+            "  .* scroll.*"));
+}
+
 } // namespace blink
 
 #endif
diff --git a/third_party/WebKit/Source/core/style/BUILD.gn b/third_party/WebKit/Source/core/style/BUILD.gn
index 292b948..c38190b 100644
--- a/third_party/WebKit/Source/core/style/BUILD.gn
+++ b/third_party/WebKit/Source/core/style/BUILD.gn
@@ -24,6 +24,10 @@
     "DataPersistent.h",
     "DataRef.h",
     "FillLayer.cpp",
+    "FilterOperation.cpp",
+    "FilterOperation.h",
+    "FilterOperations.cpp",
+    "FilterOperations.h",
     "GridArea.h",
     "GridPositionsResolver.cpp",
     "GridPositionsResolver.h",
@@ -47,10 +51,14 @@
     "StyleGridItemData.cpp",
     "StyleImage.cpp",
     "StyleInheritedData.cpp",
+    "StyleInheritedVariables.cpp",
+    "StyleInheritedVariables.h",
     "StyleInvalidImage.h",
     "StyleMotionData.cpp",
     "StyleMotionData.h",
     "StyleMultiColData.cpp",
+    "StyleNonInheritedVariables.cpp",
+    "StyleNonInheritedVariables.h",
     "StyleOffsetRotation.h",
     "StylePath.cpp",
     "StylePath.h",
@@ -62,8 +70,6 @@
     "StyleSelfAlignmentData.h",
     "StyleSurroundData.cpp",
     "StyleTransformData.cpp",
-    "StyleVariableData.cpp",
-    "StyleVariableData.h",
     "StyleVisualData.cpp",
     "StyleWillChangeData.cpp",
     "TextSizeAdjust.h",
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.cpp b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
index fca60578..430e45b 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.cpp
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
@@ -40,7 +40,8 @@
 #include "core/style/ShadowList.h"
 #include "core/style/StyleImage.h"
 #include "core/style/StyleInheritedData.h"
-#include "core/style/StyleVariableData.h"
+#include "core/style/StyleInheritedVariables.h"
+#include "core/style/StyleNonInheritedVariables.h"
 #include "platform/LengthFunctions.h"
 #include "platform/RuntimeEnabledFeatures.h"
 #include "platform/fonts/Font.h"
@@ -174,12 +175,11 @@
 
 static StyleRecalcChange diffPseudoStyles(const ComputedStyle& oldStyle, const ComputedStyle& newStyle)
 {
-    // If the pseudoStyles have changed, we want any StyleRecalcChange that is not NoChange
-    // because setStyle will do the right thing with anything else.
-    if (!oldStyle.hasAnyPublicPseudoStyles())
+    // If the pseudoStyles have changed, ensure layoutObject triggers setStyle.
+    if (!oldStyle.hasAnyPublicPseudoStyles() && !newStyle.hasAnyPublicPseudoStyles())
         return NoChange;
     for (PseudoId pseudoId = FirstPublicPseudoId; pseudoId < FirstInternalPseudoId; pseudoId = static_cast<PseudoId>(pseudoId + 1)) {
-        if (!oldStyle.hasPseudoStyle(pseudoId))
+        if (!oldStyle.hasPseudoStyle(pseudoId) && !newStyle.hasPseudoStyle(pseudoId))
             continue;
         const ComputedStyle* newPseudoStyle = newStyle.getCachedPseudoStyle(pseudoId);
         if (!newPseudoStyle)
@@ -329,6 +329,7 @@
 
 void ComputedStyle::copyNonInheritedFromCached(const ComputedStyle& other)
 {
+    ComputedStyleBase::copyNonInheritedFromCached(other);
     m_box = other.m_box;
     m_visual = other.m_visual;
     m_background = other.m_background;
@@ -345,7 +346,6 @@
     m_nonInheritedData.m_verticalAlign = other.m_nonInheritedData.m_verticalAlign;
     m_nonInheritedData.m_clear = other.m_nonInheritedData.m_clear;
     m_nonInheritedData.m_position = other.m_nonInheritedData.m_position;
-    m_nonInheritedData.m_floating = other.m_nonInheritedData.m_floating;
     m_nonInheritedData.m_tableLayout = other.m_nonInheritedData.m_tableLayout;
     m_nonInheritedData.m_unicodeBidi = other.m_nonInheritedData.m_unicodeBidi;
     m_nonInheritedData.m_hasViewportUnits = other.m_nonInheritedData.m_hasViewportUnits;
@@ -498,7 +498,8 @@
 bool ComputedStyle::nonInheritedEqual(const ComputedStyle& other) const
 {
     // compare everything except the pseudoStyle pointer
-    return m_nonInheritedData == other.m_nonInheritedData
+    return ComputedStyleBase::nonInheritedEqual(other)
+        && m_nonInheritedData == other.m_nonInheritedData
         && m_box == other.m_box
         && m_visual == other.m_visual
         && m_background == other.m_background
@@ -711,11 +712,11 @@
         || m_nonInheritedData.m_overflowY != other.m_nonInheritedData.m_overflowY
         || m_nonInheritedData.m_clear != other.m_nonInheritedData.m_clear
         || m_nonInheritedData.m_unicodeBidi != other.m_nonInheritedData.m_unicodeBidi
-        || m_nonInheritedData.m_floating != other.m_nonInheritedData.m_floating
+        || floating() != other.floating()
         || m_nonInheritedData.m_originalDisplay != other.m_nonInheritedData.m_originalDisplay)
         return true;
 
-    if (m_nonInheritedData.m_effectiveDisplay >= FIRST_TABLE_DISPLAY && m_nonInheritedData.m_effectiveDisplay <= LAST_TABLE_DISPLAY) {
+    if (isDisplayTableType(display())) {
         if (m_inheritedData.m_borderCollapse != other.m_inheritedData.m_borderCollapse
             || m_inheritedData.m_emptyCells != other.m_inheritedData.m_emptyCells
             || m_inheritedData.m_captionSide != other.m_inheritedData.m_captionSide
@@ -881,10 +882,10 @@
             return true;
     }
 
-    if (variables() || other.variables()) {
+    if (inheritedVariables() || other.inheritedVariables()) {
         for (const AtomicString& property : *value->customInvalidationProperties()) {
-            CSSVariableData* thisVar = variables() ? variables()->getVariable(property) : nullptr;
-            CSSVariableData* otherVar = other.variables() ? other.variables()->getVariable(property) : nullptr;
+            CSSVariableData* thisVar = inheritedVariables() ? inheritedVariables()->getVariable(property) : nullptr;
+            CSSVariableData* otherVar = other.inheritedVariables() ? other.inheritedVariables()->getVariable(property) : nullptr;
 
             if (!dataEquivalent(thisVar, otherVar))
                 return true;
@@ -988,6 +989,8 @@
         case CSSPropertyAliasWebkitTransformStyle:
         case CSSPropertyPerspective:
         case CSSPropertyAliasWebkitPerspective:
+        case CSSPropertyOffsetPath:
+        case CSSPropertyOffsetPosition:
         case CSSPropertyWebkitMask:
         case CSSPropertyWebkitMaskBoxImage:
         case CSSPropertyClipPath:
@@ -1109,7 +1112,7 @@
 
 void ComputedStyle::applyTransform(TransformationMatrix& result, const FloatRect& boundingBox, ApplyTransformOrigin applyOrigin, ApplyMotionPath applyMotionPath, ApplyIndependentTransformProperties applyIndependentTransformProperties) const
 {
-    if (!hasOffsetPath())
+    if (!hasOffset())
         applyMotionPath = ExcludeMotionPath;
     bool applyTransformOrigin = requireTransformOrigin(applyOrigin, applyMotionPath);
 
@@ -1154,7 +1157,10 @@
 void ComputedStyle::applyMotionPathTransform(float originX, float originY, TransformationMatrix& transform) const
 {
     const StyleMotionData& motionData = m_rareNonInheritedData->m_transform->m_motion;
-    ASSERT(motionData.m_path);
+    // TODO(ericwilligers): crbug.com/638055 Apply offset-position and offset-anchor.
+    if (!motionData.m_path) {
+        return;
+    }
     const StylePath& motionPath = *motionData.m_path;
     float pathLength = motionPath.length();
     float distance = floatValueForLength(motionData.m_distance, pathLength);
@@ -1440,42 +1446,80 @@
     return m_rareInheritedData->appliedTextDecorations->vector();
 }
 
-StyleVariableData* ComputedStyle::variables() const
+StyleInheritedVariables* ComputedStyle::inheritedVariables() const
 {
     return m_rareInheritedData->variables.get();
 }
 
-void ComputedStyle::setVariable(const AtomicString& name, PassRefPtr<CSSVariableData> value)
+StyleNonInheritedVariables* ComputedStyle::nonInheritedVariables() const
 {
-    RefPtr<StyleVariableData>& variables = m_rareInheritedData.access()->variables;
+    return m_rareNonInheritedData->m_variables.get();
+}
+
+StyleInheritedVariables& ComputedStyle::mutableInheritedVariables()
+{
+    RefPtr<StyleInheritedVariables>& variables = m_rareInheritedData.access()->variables;
     if (!variables)
-        variables = StyleVariableData::create();
+        variables = StyleInheritedVariables::create();
     else if (!variables->hasOneRef())
         variables = variables->copy();
-    variables->setVariable(name, std::move(value));
+    return *variables;
 }
 
-void ComputedStyle::setRegisteredInheritedProperty(const AtomicString& name, const CSSValue* parsedValue)
+StyleNonInheritedVariables& ComputedStyle::mutableNonInheritedVariables()
 {
-    RefPtr<StyleVariableData>& variables = m_rareInheritedData.access()->variables;
-    // The CSSVariableData needs to be set before calling this function
-    DCHECK(variables);
-    DCHECK(!!parsedValue == !!variables->getVariable(name));
-    DCHECK(!(variables->getVariable(name) && variables->getVariable(name)->needsVariableResolution()));
-
-    if (!variables->hasOneRef())
-        variables = variables->copy();
-    variables->setRegisteredInheritedProperty(name, parsedValue);
-}
-
-void ComputedStyle::removeVariable(const AtomicString& name)
-{
-    RefPtr<StyleVariableData>& variables = m_rareInheritedData.access()->variables;
+    std::unique_ptr<StyleNonInheritedVariables>& variables = m_rareNonInheritedData.access()->m_variables;
     if (!variables)
-        return;
-    if (!variables->hasOneRef())
-        variables = variables->copy();
-    variables->removeVariable(name);
+        variables = StyleNonInheritedVariables::create();
+    return *variables;
+}
+
+void ComputedStyle::setUnresolvedInheritedVariable(const AtomicString& name, PassRefPtr<CSSVariableData> value)
+{
+    DCHECK(value && value->needsVariableResolution());
+    mutableInheritedVariables().setVariable(name, std::move(value));
+}
+
+void ComputedStyle::setUnresolvedNonInheritedVariable(const AtomicString& name, PassRefPtr<CSSVariableData> value)
+{
+    DCHECK(value && value->needsVariableResolution());
+    mutableNonInheritedVariables().setVariable(name, std::move(value));
+}
+
+void ComputedStyle::setResolvedUnregisteredVariable(const AtomicString& name, PassRefPtr<CSSVariableData> value)
+{
+    DCHECK(value && !value->needsVariableResolution());
+    mutableInheritedVariables().setVariable(name, std::move(value));
+}
+
+void ComputedStyle::setResolvedInheritedVariable(const AtomicString& name, PassRefPtr<CSSVariableData> value, const CSSValue* parsedValue)
+{
+    DCHECK(!!value == !!parsedValue);
+    DCHECK(!(value && value->needsVariableResolution()));
+
+    StyleInheritedVariables& variables = mutableInheritedVariables();
+    variables.setVariable(name, std::move(value));
+    variables.setRegisteredVariable(name, parsedValue);
+}
+
+void ComputedStyle::setResolvedNonInheritedVariable(const AtomicString& name, PassRefPtr<CSSVariableData> value, const CSSValue* parsedValue)
+{
+    DCHECK(!!value == !!parsedValue);
+    DCHECK(!(value && value->needsVariableResolution()));
+
+    StyleNonInheritedVariables& variables = mutableNonInheritedVariables();
+    variables.setVariable(name, std::move(value));
+    variables.setRegisteredVariable(name, parsedValue);
+}
+
+void ComputedStyle::removeInheritedVariable(const AtomicString& name)
+{
+    mutableInheritedVariables().removeVariable(name);
+}
+
+void ComputedStyle::removeNonInheritedVariable(const AtomicString& name)
+{
+    mutableNonInheritedVariables().removeVariable(name);
 }
 
 float ComputedStyle::wordSpacing() const { return getFontDescription().wordSpacing(); }
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.h b/third_party/WebKit/Source/core/style/ComputedStyle.h
index d70c43f..733d4e4 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.h
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.h
@@ -251,7 +251,6 @@
                 && m_verticalAlign == other.m_verticalAlign
                 && m_clear == other.m_clear
                 && m_position == other.m_position
-                && m_floating == other.m_floating
                 && m_tableLayout == other.m_tableLayout
                 && m_unicodeBidi == other.m_unicodeBidi
                 // hasViewportUnits
@@ -281,7 +280,6 @@
         unsigned m_verticalAlign : 4; // EVerticalAlign
         unsigned m_clear : 2; // EClear
         unsigned m_position : 3; // EPosition
-        unsigned m_floating : 2; // EFloat
         unsigned m_tableLayout : 1; // ETableLayout
         unsigned m_unicodeBidi : 3; // EUnicodeBidi
 
@@ -368,7 +366,6 @@
         m_nonInheritedData.m_verticalAlign = initialVerticalAlign();
         m_nonInheritedData.m_clear = initialClear();
         m_nonInheritedData.m_position = initialPosition();
-        m_nonInheritedData.m_floating = static_cast<unsigned>(initialFloating());
         m_nonInheritedData.m_tableLayout = initialTableLayout();
         m_nonInheritedData.m_unicodeBidi = initialUnicodeBidi();
         m_nonInheritedData.m_breakBefore = initialBreakBefore();
@@ -829,11 +826,6 @@
             m_rareNonInheritedData.access()->m_boxReflect = reflect;
     }
 
-    // float
-    static EFloat initialFloating() { return EFloat::None; }
-    EFloat floating() const { return static_cast<EFloat>(m_nonInheritedData.m_floating); }
-    void setFloating(EFloat v) { m_nonInheritedData.m_floating = static_cast<unsigned>(v); }
-
     // Grid properties.
     static Vector<GridTrackSize> initialGridAutoRepeatTracks() { return Vector<GridTrackSize>(); /* none */ }
     static size_t initialGridAutoRepeatInsertionPoint() { return 0; }
@@ -1767,16 +1759,25 @@
     void clearResetDirectives();
 
     // Variables.
-    static StyleVariableData* initialVariables() { return nullptr; }
-    StyleVariableData* variables() const;
-    void setVariable(const AtomicString&, PassRefPtr<CSSVariableData>);
-    void removeVariable(const AtomicString&);
+    static StyleInheritedVariables* initialInheritedVariables() { return nullptr; }
+    static StyleNonInheritedVariables* initialNonInheritedVariables() { return nullptr; }
+
+    StyleInheritedVariables* inheritedVariables() const;
+    StyleNonInheritedVariables* nonInheritedVariables() const;
+
+    void setUnresolvedInheritedVariable(const AtomicString&, PassRefPtr<CSSVariableData>);
+    void setUnresolvedNonInheritedVariable(const AtomicString&, PassRefPtr<CSSVariableData>);
+
+    void setResolvedUnregisteredVariable(const AtomicString&, PassRefPtr<CSSVariableData>);
+    void setResolvedInheritedVariable(const AtomicString&, PassRefPtr<CSSVariableData>, const CSSValue*);
+    void setResolvedNonInheritedVariable(const AtomicString&, PassRefPtr<CSSVariableData>, const CSSValue*);
+
+    void removeInheritedVariable(const AtomicString&);
+    void removeNonInheritedVariable(const AtomicString&);
+
     void setHasVariableReferenceFromNonInheritedProperty() { m_nonInheritedData.m_variableReference = true; }
     bool hasVariableReferenceFromNonInheritedProperty() const { return m_nonInheritedData.m_variableReference; }
 
-    // Call these after setting the CSSVariableData
-    void setRegisteredInheritedProperty(const AtomicString&, const CSSValue*);
-
     // Animations.
     CSSAnimationData& accessAnimations();
     const CSSAnimationData* animations() const { return m_rareNonInheritedData->m_animations.get(); }
@@ -2149,7 +2150,7 @@
     bool hasBlendMode() const { return blendMode() != WebBlendModeNormal; }
 
     // Motion utility functions.
-    bool hasOffsetPath() const { return offsetPath(); }
+    bool hasOffset() const { return (offsetPosition().x() != Length(Auto)) || offsetPath(); }
 
     // Direction utility functions.
     bool isLeftToRightDirection() const { return direction() == LTR; }
@@ -2257,7 +2258,7 @@
 
     // Filter/transform utility functions.
     bool has3DTransform() const { return m_rareNonInheritedData->m_transform->has3DTransform(); }
-    bool hasTransform() const { return hasTransformOperations() || hasOffsetPath() || hasCurrentTransformAnimation() || translate() || rotate() || scale(); }
+    bool hasTransform() const { return hasTransformOperations() || hasOffset() || hasCurrentTransformAnimation() || translate() || rotate() || scale(); }
     bool hasTransformOperations() const { return !m_rareNonInheritedData->m_transform->m_operations.operations().isEmpty(); }
     ETransformStyle3D usedTransformStyle3D() const { return hasGroupingProperty() ? TransformStyle3DFlat : transformStyle3D(); }
     bool transformDataEquivalent(const ComputedStyle& otherStyle) const { return m_rareNonInheritedData->m_transform == otherStyle.m_rareNonInheritedData->m_transform; }
@@ -2467,27 +2468,35 @@
 
     void inheritUnicodeBidiFrom(const ComputedStyle& parent) { m_nonInheritedData.m_unicodeBidi = parent.m_nonInheritedData.m_unicodeBidi; }
 
-    bool isDisplayFlexibleBox(EDisplay display) const
+    static bool isDisplayFlexibleBox(EDisplay display)
     {
         return display == FLEX || display == INLINE_FLEX;
     }
 
-    bool isDisplayGridBox(EDisplay display) const
+    static bool isDisplayGridBox(EDisplay display)
     {
         return display == GRID || display == INLINE_GRID;
     }
 
-    bool isDisplayReplacedType(EDisplay display) const
+    static bool isDisplayReplacedType(EDisplay display)
     {
         return display == INLINE_BLOCK || display == INLINE_BOX || display == INLINE_FLEX
             || display == INLINE_TABLE || display == INLINE_GRID;
     }
 
-    bool isDisplayInlineType(EDisplay display) const
+    static bool isDisplayInlineType(EDisplay display)
     {
         return display == INLINE || isDisplayReplacedType(display);
     }
 
+    static bool isDisplayTableType(EDisplay display)
+    {
+        return display == TABLE || display == INLINE_TABLE || display == TABLE_ROW_GROUP
+            || display == TABLE_HEADER_GROUP || display == TABLE_FOOTER_GROUP || display == TABLE_ROW
+            || display == TABLE_COLUMN_GROUP || display == TABLE_COLUMN || display == TABLE_CELL
+            || display == TABLE_CAPTION;
+    }
+
     // Color accessors are all private to make sure callers use visitedDependentColor instead to access them.
     StyleColor borderLeftColor() const { return m_surround->border.left().color(); }
     StyleColor borderRightColor() const { return m_surround->border.right().color(); }
@@ -2533,6 +2542,9 @@
 
     bool requireTransformOrigin(ApplyTransformOrigin applyOrigin, ApplyMotionPath) const;
     static bool shadowListHasCurrentColor(const ShadowList*);
+
+    StyleInheritedVariables& mutableInheritedVariables();
+    StyleNonInheritedVariables& mutableNonInheritedVariables();
 };
 
 // FIXME: Reduce/remove the dependency on zoom adjusted int values.
diff --git a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
index e7305da..6046110 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
+++ b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
@@ -124,10 +124,6 @@
     FixedPosition = 6
 };
 
-enum class EFloat : unsigned {
-    None, Left, Right
-};
-
 enum EMarginCollapse { MarginCollapseCollapse, MarginCollapseSeparate, MarginCollapseDiscard };
 
 // Box decoration attributes. Not inherited.
@@ -455,9 +451,7 @@
     TABLE_CAPTION, BOX, INLINE_BOX,
     FLEX, INLINE_FLEX,
     GRID, INLINE_GRID,
-    NONE,
-    FIRST_TABLE_DISPLAY = TABLE,
-    LAST_TABLE_DISPLAY = TABLE_CAPTION
+    NONE
 };
 
 enum EInsideLink {
diff --git a/third_party/WebKit/Source/platform/graphics/filters/FilterOperation.cpp b/third_party/WebKit/Source/core/style/FilterOperation.cpp
similarity index 94%
rename from third_party/WebKit/Source/platform/graphics/filters/FilterOperation.cpp
rename to third_party/WebKit/Source/core/style/FilterOperation.cpp
index 84967f4..386a208 100644
--- a/third_party/WebKit/Source/platform/graphics/filters/FilterOperation.cpp
+++ b/third_party/WebKit/Source/core/style/FilterOperation.cpp
@@ -23,7 +23,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "platform/graphics/filters/FilterOperation.h"
+#include "core/style/FilterOperation.h"
 
 #include "platform/LengthFunctions.h"
 #include "platform/animation/AnimationUtilities.h"
@@ -45,7 +45,7 @@
 
 FilterOperation* FilterOperation::blend(const FilterOperation* from, const FilterOperation* to, double progress)
 {
-    ASSERT(from || to);
+    DCHECK(from || to);
     if (to)
         return to->blend(from, progress);
     return from->blend(0, 1 - progress);
@@ -69,7 +69,7 @@
 {
     double fromAmount;
     if (from) {
-        ASSERT_WITH_SECURITY_IMPLICATION(from->isSameType(*this));
+        SECURITY_DCHECK(from->isSameType(*this));
         fromAmount = toBasicColorMatrixFilterOperation(from)->amount();
     } else {
         switch (m_type) {
@@ -83,7 +83,7 @@
             break;
         default:
             fromAmount = 0;
-            ASSERT_NOT_REACHED();
+            NOTREACHED();
         }
     }
 
@@ -99,7 +99,7 @@
         result = clampTo<double>(result, 0);
         break;
     default:
-        ASSERT_NOT_REACHED();
+        NOTREACHED();
     }
     return BasicColorMatrixFilterOperation::create(result, m_type);
 }
@@ -108,7 +108,7 @@
 {
     double fromAmount;
     if (from) {
-        ASSERT_WITH_SECURITY_IMPLICATION(from->isSameType(*this));
+        SECURITY_DCHECK(from->isSameType(*this));
         fromAmount = toBasicComponentTransferFilterOperation(from)->amount();
     } else {
         switch (m_type) {
@@ -122,7 +122,7 @@
             break;
         default:
             fromAmount = 0;
-            ASSERT_NOT_REACHED();
+            NOTREACHED();
         }
     }
 
@@ -137,7 +137,7 @@
         result = clampTo<double>(result, 0, 1);
         break;
     default:
-        ASSERT_NOT_REACHED();
+        NOTREACHED();
     }
     return BasicComponentTransferFilterOperation::create(result, m_type);
 }
@@ -197,7 +197,7 @@
 
 FilterOperation* BoxReflectFilterOperation::blend(const FilterOperation* from, double progress) const
 {
-    ASSERT_NOT_REACHED();
+    NOTREACHED();
     return nullptr;
 }
 
diff --git a/third_party/WebKit/Source/platform/graphics/filters/FilterOperation.h b/third_party/WebKit/Source/core/style/FilterOperation.h
similarity index 94%
rename from third_party/WebKit/Source/platform/graphics/filters/FilterOperation.h
rename to third_party/WebKit/Source/core/style/FilterOperation.h
index 2d33ec1..342d3cd4 100644
--- a/third_party/WebKit/Source/platform/graphics/filters/FilterOperation.h
+++ b/third_party/WebKit/Source/core/style/FilterOperation.h
@@ -26,8 +26,8 @@
 #ifndef FilterOperation_h
 #define FilterOperation_h
 
+#include "core/CoreExport.h"
 #include "platform/Length.h"
-#include "platform/PlatformExport.h"
 #include "platform/graphics/BoxReflection.h"
 #include "platform/graphics/Color.h"
 #include "platform/graphics/filters/Filter.h"
@@ -39,7 +39,7 @@
 
 // CSS Filters
 
-class PLATFORM_EXPORT FilterOperation : public GarbageCollectedFinalized<FilterOperation> {
+class CORE_EXPORT FilterOperation : public GarbageCollectedFinalized<FilterOperation> {
     WTF_MAKE_NONCOPYABLE(FilterOperation);
 public:
     enum OperationType {
@@ -78,7 +78,7 @@
         case NONE:
             break;
         }
-        ASSERT_NOT_REACHED();
+        NOTREACHED();
         return false;
     }
 
@@ -117,7 +117,7 @@
 #define DEFINE_FILTER_OPERATION_TYPE_CASTS(thisType, operationType) \
     DEFINE_TYPE_CASTS(thisType, FilterOperation, op, op->type() == FilterOperation::operationType, op.type() == FilterOperation::operationType);
 
-class PLATFORM_EXPORT ReferenceFilterOperation : public FilterOperation {
+class CORE_EXPORT ReferenceFilterOperation : public FilterOperation {
 public:
     static ReferenceFilterOperation* create(const String& url, const AtomicString& fragment)
     {
@@ -139,7 +139,7 @@
 private:
     FilterOperation* blend(const FilterOperation* from, double progress) const override
     {
-        ASSERT_NOT_REACHED();
+        NOTREACHED();
         return nullptr;
     }
 
@@ -167,7 +167,7 @@
 
 // GRAYSCALE, SEPIA, SATURATE and HUE_ROTATE are variations on a basic color matrix effect.
 // For HUE_ROTATE, the angle of rotation is stored in m_amount.
-class PLATFORM_EXPORT BasicColorMatrixFilterOperation : public FilterOperation {
+class CORE_EXPORT BasicColorMatrixFilterOperation : public FilterOperation {
 public:
     static BasicColorMatrixFilterOperation* create(double amount, OperationType type)
     {
@@ -205,7 +205,7 @@
 DEFINE_TYPE_CASTS(BasicColorMatrixFilterOperation, FilterOperation, op, isBasicColorMatrixFilterOperation(*op), isBasicColorMatrixFilterOperation(op));
 
 // INVERT, BRIGHTNESS, CONTRAST and OPACITY are variations on a basic component transfer effect.
-class PLATFORM_EXPORT BasicComponentTransferFilterOperation : public FilterOperation {
+class CORE_EXPORT BasicComponentTransferFilterOperation : public FilterOperation {
 public:
     static BasicComponentTransferFilterOperation* create(double amount, OperationType type)
     {
@@ -244,7 +244,7 @@
 
 DEFINE_TYPE_CASTS(BasicComponentTransferFilterOperation, FilterOperation, op, isBasicComponentTransferFilterOperation(*op), isBasicComponentTransferFilterOperation(op));
 
-class PLATFORM_EXPORT BlurFilterOperation : public FilterOperation {
+class CORE_EXPORT BlurFilterOperation : public FilterOperation {
 public:
     static BlurFilterOperation* create(const Length& stdDeviation)
     {
@@ -278,7 +278,7 @@
 
 DEFINE_FILTER_OPERATION_TYPE_CASTS(BlurFilterOperation, BLUR);
 
-class PLATFORM_EXPORT DropShadowFilterOperation : public FilterOperation {
+class CORE_EXPORT DropShadowFilterOperation : public FilterOperation {
 public:
     static DropShadowFilterOperation* create(const IntPoint& location, int stdDeviation, Color color)
     {
@@ -320,7 +320,7 @@
 
 DEFINE_FILTER_OPERATION_TYPE_CASTS(DropShadowFilterOperation, DROP_SHADOW);
 
-class PLATFORM_EXPORT BoxReflectFilterOperation : public FilterOperation {
+class CORE_EXPORT BoxReflectFilterOperation : public FilterOperation {
 public:
     static BoxReflectFilterOperation* create(const BoxReflection& reflection)
     {
diff --git a/third_party/WebKit/Source/platform/graphics/filters/FilterOperations.cpp b/third_party/WebKit/Source/core/style/FilterOperations.cpp
similarity index 95%
rename from third_party/WebKit/Source/platform/graphics/filters/FilterOperations.cpp
rename to third_party/WebKit/Source/core/style/FilterOperations.cpp
index fa10f804..84d7c95 100644
--- a/third_party/WebKit/Source/platform/graphics/filters/FilterOperations.cpp
+++ b/third_party/WebKit/Source/core/style/FilterOperations.cpp
@@ -23,7 +23,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "platform/graphics/filters/FilterOperations.h"
+#include "core/style/FilterOperations.h"
 
 #include "platform/LengthFunctions.h"
 #include "platform/geometry/IntSize.h"
@@ -101,17 +101,19 @@
 
 bool FilterOperations::hasFilterThatAffectsOpacity() const
 {
-    for (size_t i = 0; i < m_operations.size(); ++i)
+    for (size_t i = 0; i < m_operations.size(); ++i) {
         if (m_operations[i]->affectsOpacity())
             return true;
+    }
     return false;
 }
 
 bool FilterOperations::hasFilterThatMovesPixels() const
 {
-    for (size_t i = 0; i < m_operations.size(); ++i)
+    for (size_t i = 0; i < m_operations.size(); ++i) {
         if (m_operations[i]->movesPixels())
             return true;
+    }
     return false;
 }
 
diff --git a/third_party/WebKit/Source/platform/graphics/filters/FilterOperations.h b/third_party/WebKit/Source/core/style/FilterOperations.h
similarity index 94%
rename from third_party/WebKit/Source/platform/graphics/filters/FilterOperations.h
rename to third_party/WebKit/Source/core/style/FilterOperations.h
index e5fc5551..0f91c68 100644
--- a/third_party/WebKit/Source/platform/graphics/filters/FilterOperations.h
+++ b/third_party/WebKit/Source/core/style/FilterOperations.h
@@ -26,15 +26,13 @@
 #ifndef FilterOperations_h
 #define FilterOperations_h
 
-#include "platform/PlatformExport.h"
-#include "platform/geometry/IntRectOutsets.h"
-#include "platform/graphics/filters/FilterOperation.h"
-#include "wtf/RefPtr.h"
+#include "core/CoreExport.h"
+#include "core/style/FilterOperation.h"
 #include "wtf/Vector.h"
 
 namespace blink {
 
-class PLATFORM_EXPORT FilterOperations {
+class CORE_EXPORT FilterOperations {
     DISALLOW_NEW();
 public:
     FilterOperations();
diff --git a/third_party/WebKit/Source/platform/graphics/filters/FilterOperationsTest.cpp b/third_party/WebKit/Source/core/style/FilterOperationsTest.cpp
similarity index 97%
rename from third_party/WebKit/Source/platform/graphics/filters/FilterOperationsTest.cpp
rename to third_party/WebKit/Source/core/style/FilterOperationsTest.cpp
index ecb4268..cd4ddf85 100644
--- a/third_party/WebKit/Source/platform/graphics/filters/FilterOperationsTest.cpp
+++ b/third_party/WebKit/Source/core/style/FilterOperationsTest.cpp
@@ -23,7 +23,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "platform/graphics/filters/FilterOperations.h"
+#include "core/style/FilterOperations.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/third_party/WebKit/Source/core/style/StyleFilterData.h b/third_party/WebKit/Source/core/style/StyleFilterData.h
index f779a19..b5ee753 100644
--- a/third_party/WebKit/Source/core/style/StyleFilterData.h
+++ b/third_party/WebKit/Source/core/style/StyleFilterData.h
@@ -26,7 +26,7 @@
 #ifndef StyleFilterData_h
 #define StyleFilterData_h
 
-#include "platform/graphics/filters/FilterOperations.h"
+#include "core/style/FilterOperations.h"
 #include "platform/heap/Handle.h"
 
 namespace blink {
diff --git a/third_party/WebKit/Source/core/style/StyleVariableData.cpp b/third_party/WebKit/Source/core/style/StyleInheritedVariables.cpp
similarity index 70%
rename from third_party/WebKit/Source/core/style/StyleVariableData.cpp
rename to third_party/WebKit/Source/core/style/StyleInheritedVariables.cpp
index 1a8128f..f1f9a874e 100644
--- a/third_party/WebKit/Source/core/style/StyleVariableData.cpp
+++ b/third_party/WebKit/Source/core/style/StyleInheritedVariables.cpp
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "core/style/StyleVariableData.h"
+#include "core/style/StyleInheritedVariables.h"
 
 #include "core/style/DataEquivalency.h"
 
 namespace blink {
 
-bool StyleVariableData::operator==(const StyleVariableData& other) const
+bool StyleInheritedVariables::operator==(const StyleInheritedVariables& other) const
 {
     // It's technically possible for divergent roots to be value-equal,
     // but unlikely. This equality operator is used for optimization purposes
@@ -30,7 +30,7 @@
     return true;
 }
 
-StyleVariableData::StyleVariableData(StyleVariableData& other)
+StyleInheritedVariables::StyleInheritedVariables(StyleInheritedVariables& other)
 {
     if (!other.m_root) {
         m_root = &other;
@@ -41,7 +41,7 @@
     }
 }
 
-CSSVariableData* StyleVariableData::getVariable(const AtomicString& name) const
+CSSVariableData* StyleInheritedVariables::getVariable(const AtomicString& name) const
 {
     auto result = m_data.find(name);
     if (result == m_data.end() && m_root)
@@ -51,12 +51,22 @@
     return result->value.get();
 }
 
-void StyleVariableData::setRegisteredInheritedProperty(const AtomicString& name, const CSSValue* parsedValue)
+void StyleInheritedVariables::setRegisteredVariable(const AtomicString& name, const CSSValue* parsedValue)
 {
     m_registeredData.set(name, const_cast<CSSValue*>(parsedValue));
 }
 
-void StyleVariableData::removeVariable(const AtomicString& name)
+CSSValue* StyleInheritedVariables::registeredVariable(const AtomicString& name) const
+{
+    auto result = m_registeredData.find(name);
+    if (result != m_registeredData.end())
+        return result->value.get();
+    if (m_root)
+        return m_root->registeredVariable(name);
+    return nullptr;
+}
+
+void StyleInheritedVariables::removeVariable(const AtomicString& name)
 {
     m_data.set(name, nullptr);
     auto iterator = m_registeredData.find(name);
@@ -64,7 +74,7 @@
         iterator->value = nullptr;
 }
 
-std::unique_ptr<HashMap<AtomicString, RefPtr<CSSVariableData>>> StyleVariableData::getVariables() const
+std::unique_ptr<HashMap<AtomicString, RefPtr<CSSVariableData>>> StyleInheritedVariables::getVariables() const
 {
     std::unique_ptr<HashMap<AtomicString, RefPtr<CSSVariableData>>> result;
     if (m_root) {
diff --git a/third_party/WebKit/Source/core/style/StyleInheritedVariables.h b/third_party/WebKit/Source/core/style/StyleInheritedVariables.h
new file mode 100644
index 0000000..b99dfa2
--- /dev/null
+++ b/third_party/WebKit/Source/core/style/StyleInheritedVariables.h
@@ -0,0 +1,52 @@
+// 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 StyleInheritedVariables_h
+#define StyleInheritedVariables_h
+
+#include "core/css/CSSValue.h"
+#include "core/css/CSSVariableData.h"
+#include "wtf/Forward.h"
+#include "wtf/HashMap.h"
+#include "wtf/RefCounted.h"
+#include "wtf/text/AtomicStringHash.h"
+
+namespace blink {
+
+class StyleInheritedVariables : public RefCounted<StyleInheritedVariables> {
+public:
+    static PassRefPtr<StyleInheritedVariables> create() { return adoptRef(new StyleInheritedVariables()); }
+
+    PassRefPtr<StyleInheritedVariables> copy() { return adoptRef(new StyleInheritedVariables(*this)); }
+
+    bool operator==(const StyleInheritedVariables& other) const;
+    bool operator!=(const StyleInheritedVariables& other) const { return !(*this == other); }
+
+    void setVariable(const AtomicString& name, PassRefPtr<CSSVariableData> value) { m_data.set(name, std::move(value)); }
+    CSSVariableData* getVariable(const AtomicString& name) const;
+    void removeVariable(const AtomicString&);
+
+    void setRegisteredVariable(const AtomicString&, const CSSValue*);
+    CSSValue* registeredVariable(const AtomicString&) const;
+
+    // This map will contain null pointers if variables are invalid due to
+    // cycles or referencing invalid variables without using a fallback.
+    // Note that this method is slow as a new map is constructed.
+    std::unique_ptr<HashMap<AtomicString, RefPtr<CSSVariableData>>> getVariables() const;
+private:
+    StyleInheritedVariables()
+        : m_root(nullptr)
+        { }
+    StyleInheritedVariables(StyleInheritedVariables& other);
+
+    friend class CSSVariableResolver;
+
+    HashMap<AtomicString, RefPtr<CSSVariableData>> m_data;
+    HashMap<AtomicString, Persistent<CSSValue>> m_registeredData;
+    RefPtr<StyleInheritedVariables> m_root;
+};
+
+} // namespace blink
+
+#endif // StyleInheritedVariables_h
diff --git a/third_party/WebKit/Source/core/style/StyleNonInheritedVariables.cpp b/third_party/WebKit/Source/core/style/StyleNonInheritedVariables.cpp
new file mode 100644
index 0000000..23a3cdcd
--- /dev/null
+++ b/third_party/WebKit/Source/core/style/StyleNonInheritedVariables.cpp
@@ -0,0 +1,47 @@
+// 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.
+
+#include "core/style/StyleNonInheritedVariables.h"
+
+#include "core/style/DataEquivalency.h"
+
+namespace blink {
+
+bool StyleNonInheritedVariables::operator==(const StyleNonInheritedVariables& other) const
+{
+    if (m_data.size() != other.m_data.size())
+        return false;
+
+    for (const auto& iter : m_data) {
+        RefPtr<CSSVariableData> otherData = other.m_data.get(iter.key);
+        if (!dataEquivalent(iter.value, otherData))
+            return false;
+    }
+
+    return true;
+}
+
+CSSVariableData* StyleNonInheritedVariables::getVariable(const AtomicString& name) const
+{
+    return m_data.get(name);
+}
+
+void StyleNonInheritedVariables::setRegisteredVariable(const AtomicString& name, const CSSValue* parsedValue)
+{
+    m_registeredData.set(name, const_cast<CSSValue*>(parsedValue));
+}
+
+void StyleNonInheritedVariables::removeVariable(const AtomicString& name)
+{
+    m_data.set(name, nullptr);
+    m_registeredData.set(name, nullptr);
+}
+
+StyleNonInheritedVariables::StyleNonInheritedVariables(StyleNonInheritedVariables& other)
+{
+    m_data = other.m_data;
+    m_registeredData = other.m_registeredData;
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/core/style/StyleNonInheritedVariables.h b/third_party/WebKit/Source/core/style/StyleNonInheritedVariables.h
new file mode 100644
index 0000000..6967313
--- /dev/null
+++ b/third_party/WebKit/Source/core/style/StyleNonInheritedVariables.h
@@ -0,0 +1,44 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef StyleNonInheritedVariables_h
+#define StyleNonInheritedVariables_h
+
+#include "core/css/CSSValue.h"
+#include "core/css/CSSVariableData.h"
+#include "wtf/Forward.h"
+#include "wtf/HashMap.h"
+#include "wtf/text/AtomicStringHash.h"
+
+namespace blink {
+
+class StyleNonInheritedVariables {
+public:
+    static std::unique_ptr<StyleNonInheritedVariables> create() { return wrapUnique(new StyleNonInheritedVariables); }
+
+    std::unique_ptr<StyleNonInheritedVariables> copy() { return wrapUnique(new StyleNonInheritedVariables(*this)); }
+
+    bool operator==(const StyleNonInheritedVariables& other) const;
+    bool operator!=(const StyleNonInheritedVariables& other) const { return !(*this == other); }
+
+    void setVariable(const AtomicString& name, PassRefPtr<CSSVariableData> value) { m_data.set(name, value); }
+    CSSVariableData* getVariable(const AtomicString& name) const;
+    void removeVariable(const AtomicString&);
+
+    void setRegisteredVariable(const AtomicString&, const CSSValue*);
+    CSSValue* registeredVariable(const AtomicString& name) const { return m_registeredData.get(name); }
+
+private:
+    StyleNonInheritedVariables() = default;
+    StyleNonInheritedVariables(StyleNonInheritedVariables&);
+
+    friend class CSSVariableResolver;
+
+    HashMap<AtomicString, RefPtr<CSSVariableData>> m_data;
+    HashMap<AtomicString, Persistent<CSSValue>> m_registeredData;
+};
+
+} // namespace blink
+
+#endif // StyleNonInheritedVariables_h
diff --git a/third_party/WebKit/Source/core/style/StyleRareInheritedData.cpp b/third_party/WebKit/Source/core/style/StyleRareInheritedData.cpp
index 36ac507..cae49ef 100644
--- a/third_party/WebKit/Source/core/style/StyleRareInheritedData.cpp
+++ b/third_party/WebKit/Source/core/style/StyleRareInheritedData.cpp
@@ -29,7 +29,7 @@
 #include "core/style/QuotesData.h"
 #include "core/style/ShadowList.h"
 #include "core/style/StyleImage.h"
-#include "core/style/StyleVariableData.h"
+#include "core/style/StyleInheritedVariables.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/style/StyleRareInheritedData.h b/third_party/WebKit/Source/core/style/StyleRareInheritedData.h
index b4515f6..a1e38022 100644
--- a/third_party/WebKit/Source/core/style/StyleRareInheritedData.h
+++ b/third_party/WebKit/Source/core/style/StyleRareInheritedData.h
@@ -44,7 +44,7 @@
 class QuotesData;
 class ShadowList;
 class StyleImage;
-class StyleVariableData;
+class StyleInheritedVariables;
 
 typedef RefVector<AppliedTextDecoration> AppliedTextDecorationList;
 typedef HeapVector<CursorData> CursorList;
@@ -160,7 +160,7 @@
     RefPtr<AppliedTextDecorationList> appliedTextDecorations;
     TabSize m_tabSize;
 
-    RefPtr<StyleVariableData> variables;
+    RefPtr<StyleInheritedVariables> variables;
     TextSizeAdjust m_textSizeAdjust;
 
 private:
diff --git a/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.cpp b/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.cpp
index cf23960..516f54a4 100644
--- a/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.cpp
+++ b/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.cpp
@@ -28,6 +28,7 @@
 #include "core/style/ComputedStyle.h"
 #include "core/style/ShadowList.h"
 #include "core/style/StyleFilterData.h"
+#include "core/style/StyleNonInheritedVariables.h"
 #include "core/style/StyleTransformData.h"
 #include "core/layout/svg/ReferenceFilterBuilder.h"
 
@@ -46,7 +47,7 @@
     DataPersistent<void*> dataPersistents[2];
     void* ownPtrs[4];
     Persistent<void*> persistentHandles[2];
-    void* refPtrs[2];
+    void* refPtrs[3];
     void* uniquePtrs[1];
 
     FillLayer fillLayers;
@@ -88,6 +89,7 @@
     , m_visitedLinkBorderRightColor(StyleColor::currentColor())
     , m_visitedLinkBorderTopColor(StyleColor::currentColor())
     , m_visitedLinkBorderBottomColor(StyleColor::currentColor())
+    , m_variables(ComputedStyle::initialNonInheritedVariables())
     , m_alignContent(ComputedStyle::initialContentAlignment())
     , m_alignItems(ComputedStyle::initialDefaultAlignment())
     , m_alignSelf(ComputedStyle::initialSelfAlignment())
@@ -169,6 +171,7 @@
     , m_visitedLinkBorderRightColor(o.m_visitedLinkBorderRightColor)
     , m_visitedLinkBorderTopColor(o.m_visitedLinkBorderTopColor)
     , m_visitedLinkBorderBottomColor(o.m_visitedLinkBorderBottomColor)
+    , m_variables(o.m_variables ? o.m_variables->copy() : nullptr)
     , m_alignContent(o.m_alignContent)
     , m_alignItems(o.m_alignItems)
     , m_alignSelf(o.m_alignSelf)
@@ -254,6 +257,7 @@
         && m_visitedLinkBorderTopColor == o.m_visitedLinkBorderTopColor
         && m_visitedLinkBorderBottomColor == o.m_visitedLinkBorderBottomColor
         && m_callbackSelectors == o.m_callbackSelectors
+        && dataEquivalent(m_variables, o.m_variables)
         && m_alignContent == o.m_alignContent
         && m_alignItems == o.m_alignItems
         && m_alignSelf == o.m_alignSelf
diff --git a/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.h b/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.h
index 64121913..c49db726 100644
--- a/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.h
+++ b/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.h
@@ -58,6 +58,7 @@
 class StyleGridData;
 class StyleGridItemData;
 class StyleMultiColData;
+class StyleNonInheritedVariables;
 class StyleReflection;
 class StyleTransformData;
 class StyleWillChangeData;
@@ -156,6 +157,8 @@
 
     std::unique_ptr<Vector<Persistent<StyleImage>>> m_paintImages;
 
+    std::unique_ptr<StyleNonInheritedVariables> m_variables;
+
     StyleContentAlignmentData m_alignContent;
     StyleSelfAlignmentData m_alignItems;
     StyleSelfAlignmentData m_alignSelf;
diff --git a/third_party/WebKit/Source/core/style/StyleVariableData.h b/third_party/WebKit/Source/core/style/StyleVariableData.h
deleted file mode 100644
index 7ae52c03..0000000
--- a/third_party/WebKit/Source/core/style/StyleVariableData.h
+++ /dev/null
@@ -1,52 +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 StyleVariableData_h
-#define StyleVariableData_h
-
-#include "core/css/CSSValue.h"
-#include "core/css/CSSVariableData.h"
-#include "wtf/Forward.h"
-#include "wtf/HashMap.h"
-#include "wtf/RefCounted.h"
-#include "wtf/text/AtomicStringHash.h"
-
-namespace blink {
-
-class StyleVariableData : public RefCounted<StyleVariableData> {
-public:
-    static PassRefPtr<StyleVariableData> create() { return adoptRef(new StyleVariableData()); }
-
-    PassRefPtr<StyleVariableData> copy() { return adoptRef(new StyleVariableData(*this)); }
-
-    bool operator==(const StyleVariableData& other) const;
-    bool operator!=(const StyleVariableData& other) const { return !(*this == other); }
-
-    void setVariable(const AtomicString& name, PassRefPtr<CSSVariableData> value) { m_data.set(name, std::move(value)); }
-    CSSVariableData* getVariable(const AtomicString& name) const;
-    void removeVariable(const AtomicString&);
-
-    void setRegisteredInheritedProperty(const AtomicString&, const CSSValue*);
-    CSSValue* registeredInheritedProperty(const AtomicString& name) const { return m_registeredData.get(name); }
-
-    // This map will contain null pointers if variables are invalid due to
-    // cycles or referencing invalid variables without using a fallback.
-    // Note that this method is slow as a new map is constructed.
-    std::unique_ptr<HashMap<AtomicString, RefPtr<CSSVariableData>>> getVariables() const;
-private:
-    StyleVariableData()
-        : m_root(nullptr)
-        { }
-    StyleVariableData(StyleVariableData& other);
-
-    friend class CSSVariableResolver;
-
-    HashMap<AtomicString, RefPtr<CSSVariableData>> m_data;
-    HashMap<AtomicString, Persistent<CSSValue>> m_registeredData;
-    RefPtr<StyleVariableData> m_root;
-};
-
-} // namespace blink
-
-#endif // StyleVariableData_h
diff --git a/third_party/WebKit/Source/core/svg/SVGCursorElement.cpp b/third_party/WebKit/Source/core/svg/SVGCursorElement.cpp
index 87116a0..4cfa5c1 100644
--- a/third_party/WebKit/Source/core/svg/SVGCursorElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGCursorElement.cpp
@@ -22,6 +22,7 @@
 
 #include "core/SVGNames.h"
 #include "core/dom/StyleChangeReason.h"
+#include "core/frame/UseCounter.h"
 
 namespace blink {
 
@@ -34,6 +35,8 @@
 {
     addToPropertyMap(m_x);
     addToPropertyMap(m_y);
+
+    UseCounter::count(document, UseCounter::SVGCursorElement);
 }
 
 DEFINE_NODE_FACTORY(SVGCursorElement)
@@ -44,6 +47,8 @@
 
 void SVGCursorElement::addClient(SVGElement* element)
 {
+    UseCounter::count(document(), UseCounter::SVGCursorElementHasClient);
+
     m_clients.add(element);
     element->setCursorElement(this);
 }
diff --git a/third_party/WebKit/Source/core/svg/graphics/SVGImageChromeClient.cpp b/third_party/WebKit/Source/core/svg/graphics/SVGImageChromeClient.cpp
index 8173387..83b8ab63 100644
--- a/third_party/WebKit/Source/core/svg/graphics/SVGImageChromeClient.cpp
+++ b/third_party/WebKit/Source/core/svg/graphics/SVGImageChromeClient.cpp
@@ -34,7 +34,7 @@
 
 namespace blink {
 
-static const double animationFrameDelay = 0.025;
+static const double animationFrameDelay = 1.0 / 60;
 
 SVGImageChromeClient::SVGImageChromeClient(SVGImage* image)
     : m_image(image)
diff --git a/third_party/WebKit/Source/core/timing/BUILD.gn b/third_party/WebKit/Source/core/timing/BUILD.gn
index 85aac45..ab0b7677 100644
--- a/third_party/WebKit/Source/core/timing/BUILD.gn
+++ b/third_party/WebKit/Source/core/timing/BUILD.gn
@@ -25,7 +25,6 @@
     "PerformanceNavigation.h",
     "PerformanceObserver.cpp",
     "PerformanceObserver.h",
-    "PerformanceObserverCallback.h",
     "PerformanceObserverEntryList.cpp",
     "PerformanceObserverEntryList.h",
     "PerformanceRenderTiming.cpp",
diff --git a/third_party/WebKit/Source/core/timing/Performance.cpp b/third_party/WebKit/Source/core/timing/Performance.cpp
index e584ca6b..4d7ebcc 100644
--- a/third_party/WebKit/Source/core/timing/Performance.cpp
+++ b/third_party/WebKit/Source/core/timing/Performance.cpp
@@ -81,7 +81,7 @@
 PerformanceNavigation* Performance::navigation() const
 {
     if (!m_navigation)
-        m_navigation = PerformanceNavigation::create(m_frame);
+        m_navigation = PerformanceNavigation::create(frame());
 
     return m_navigation.get();
 }
@@ -89,7 +89,7 @@
 PerformanceTiming* Performance::timing() const
 {
     if (!m_timing)
-        m_timing = PerformanceTiming::create(m_frame);
+        m_timing = PerformanceTiming::create(frame());
 
     return m_timing.get();
 }
diff --git a/third_party/WebKit/Source/core/timing/PerformanceBaseTest.cpp b/third_party/WebKit/Source/core/timing/PerformanceBaseTest.cpp
index 75de4ad..f3b01a1 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceBaseTest.cpp
+++ b/third_party/WebKit/Source/core/timing/PerformanceBaseTest.cpp
@@ -5,10 +5,10 @@
 #include "core/timing/Performance.h"
 
 #include "bindings/core/v8/V8BindingForTesting.h"
+#include "bindings/core/v8/V8PerformanceObserverInnerCallback.h"
 #include "core/timing/PerformanceBase.h"
 #include "core/timing/PerformanceLongTaskTiming.h"
 #include "core/timing/PerformanceObserver.h"
-#include "core/timing/PerformanceObserverCallback.h"
 #include "core/timing/PerformanceObserverInit.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -36,31 +36,19 @@
     }
 };
 
-class MockPerformanceObserverCallback : public PerformanceObserverCallback {
-public:
-    MockPerformanceObserverCallback() {}
-    ~MockPerformanceObserverCallback() {}
-
-    void handleEvent(PerformanceObserverEntryList*, PerformanceObserver*) override {}
-
-    DEFINE_INLINE_TRACE()
-    {
-        PerformanceObserverCallback::trace(visitor);
-    }
-};
-
 class PerformanceBaseTest : public ::testing::Test {
 protected:
     void initialize(ScriptState* scriptState)
     {
+        v8::Local<v8::Function> callback = v8::Function::New(scriptState->context(), nullptr).ToLocalChecked();
         m_base = new TestPerformanceBase();
-        m_cb = new MockPerformanceObserverCallback();
+        m_cb = V8PerformanceObserverInnerCallback::create(scriptState->isolate(), callback);
         m_observer = PerformanceObserver::create(scriptState, m_base, m_cb);
     }
 
     Persistent<TestPerformanceBase> m_base;
     Persistent<PerformanceObserver> m_observer;
-    Persistent<MockPerformanceObserverCallback> m_cb;
+    Persistent<V8PerformanceObserverInnerCallback> m_cb;
 };
 
 TEST_F(PerformanceBaseTest, Register)
diff --git a/third_party/WebKit/Source/core/timing/PerformanceNavigation.cpp b/third_party/WebKit/Source/core/timing/PerformanceNavigation.cpp
index 1fd51f9b..49745032 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceNavigation.cpp
+++ b/third_party/WebKit/Source/core/timing/PerformanceNavigation.cpp
@@ -43,10 +43,10 @@
 
 unsigned short PerformanceNavigation::type() const
 {
-    if (!m_frame)
+    if (!frame())
         return kTypeNavigate;
 
-    DocumentLoader* documentLoader = m_frame->loader().documentLoader();
+    DocumentLoader* documentLoader = frame()->loader().documentLoader();
     if (!documentLoader)
         return kTypeNavigate;
 
@@ -62,10 +62,10 @@
 
 unsigned short PerformanceNavigation::redirectCount() const
 {
-    if (!m_frame)
+    if (!frame())
         return 0;
 
-    DocumentLoader* loader = m_frame->loader().documentLoader();
+    DocumentLoader* loader = frame()->loader().documentLoader();
     if (!loader)
         return 0;
 
diff --git a/third_party/WebKit/Source/core/timing/PerformanceObserver.cpp b/third_party/WebKit/Source/core/timing/PerformanceObserver.cpp
index 8f2e1e66..425f113 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceObserver.cpp
+++ b/third_party/WebKit/Source/core/timing/PerformanceObserver.cpp
@@ -5,10 +5,10 @@
 #include "core/timing/PerformanceObserver.h"
 
 #include "bindings/core/v8/ExceptionState.h"
+#include "bindings/core/v8/V8PerformanceObserverInnerCallback.h"
 #include "core/dom/ExecutionContext.h"
 #include "core/timing/PerformanceBase.h"
 #include "core/timing/PerformanceEntry.h"
-#include "core/timing/PerformanceObserverCallback.h"
 #include "core/timing/PerformanceObserverEntryList.h"
 #include "core/timing/PerformanceObserverInit.h"
 #include "platform/Timer.h"
@@ -16,13 +16,13 @@
 
 namespace blink {
 
-PerformanceObserver* PerformanceObserver::create(ScriptState* scriptState, PerformanceBase* performance, PerformanceObserverCallback* callback)
+PerformanceObserver* PerformanceObserver::create(ScriptState* scriptState, PerformanceBase* performance, V8PerformanceObserverInnerCallback* callback)
 {
     ASSERT(isMainThread());
     return new PerformanceObserver(scriptState, performance, callback);
 }
 
-PerformanceObserver::PerformanceObserver(ScriptState* scriptState, PerformanceBase* performance, PerformanceObserverCallback* callback)
+PerformanceObserver::PerformanceObserver(ScriptState* scriptState, PerformanceBase* performance, V8PerformanceObserverInnerCallback* callback)
     : m_scriptState(scriptState)
     , m_callback(callback)
     , m_performance(performance)
@@ -87,9 +87,11 @@
 
     PerformanceEntryVector performanceEntries;
     performanceEntries.swap(m_performanceEntries);
-    Member<PerformanceObserverEntryList> entryList(new PerformanceObserverEntryList(performanceEntries));
+    PerformanceObserverEntryList* entryList = new PerformanceObserverEntryList(performanceEntries);
+    // TODO(bashi): Make sure that not throwing exception is OK.
+    TrackExceptionState exceptionState;
 
-    m_callback->handleEvent(entryList, this);
+    m_callback->call(m_scriptState.get(), this, exceptionState, entryList, this);
 }
 
 DEFINE_TRACE(PerformanceObserver)
diff --git a/third_party/WebKit/Source/core/timing/PerformanceObserver.h b/third_party/WebKit/Source/core/timing/PerformanceObserver.h
index 48ec11f..c10e1e1f 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceObserver.h
+++ b/third_party/WebKit/Source/core/timing/PerformanceObserver.h
@@ -15,10 +15,10 @@
 
 class ExceptionState;
 class PerformanceBase;
-class PerformanceObserverCallback;
 class PerformanceObserver;
 class PerformanceObserverInit;
 class ScriptState;
+class V8PerformanceObserverInnerCallback;
 
 using PerformanceEntryVector = HeapVector<Member<PerformanceEntry>>;
 
@@ -27,7 +27,7 @@
     friend class PerformanceBase;
     friend class PerformanceObserverTest;
 public:
-    static PerformanceObserver* create(ScriptState*, PerformanceBase*, PerformanceObserverCallback*);
+    static PerformanceObserver* create(ScriptState*, PerformanceBase*, V8PerformanceObserverInnerCallback*);
     static void resumeSuspendedObservers();
 
     void observe(const PerformanceObserverInit&, ExceptionState&);
@@ -38,12 +38,12 @@
     DECLARE_TRACE();
 
 private:
-    PerformanceObserver(ScriptState*, PerformanceBase*, PerformanceObserverCallback*);
+    PerformanceObserver(ScriptState*, PerformanceBase*, V8PerformanceObserverInnerCallback*);
     void deliver();
     bool shouldBeSuspended() const;
 
     RefPtr<ScriptState> m_scriptState;
-    Member<PerformanceObserverCallback> m_callback;
+    Member<V8PerformanceObserverInnerCallback> m_callback;
     WeakMember<PerformanceBase> m_performance;
     PerformanceEntryVector m_performanceEntries;
     PerformanceEntryTypeMask m_filterOptions;
diff --git a/third_party/WebKit/Source/core/timing/PerformanceObserver.idl b/third_party/WebKit/Source/core/timing/PerformanceObserver.idl
index 833c9790..fd86c33 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceObserver.idl
+++ b/third_party/WebKit/Source/core/timing/PerformanceObserver.idl
@@ -3,12 +3,11 @@
 // found in the LICENSE file.
 
 // http://w3c.github.io/performance-timeline/#idl-def-PerformanceObserverCallback
-callback PerformanceObserverCallback = void (PerformanceObserverEntryList entries, PerformanceObserver observer);
 [ExperimentalCallbackFunction] callback PerformanceObserverInnerCallback = void (PerformanceObserverEntryList entries, PerformanceObserver observer);
 
 // http://w3c.github.io/performance-timeline/#the-performance-observer-interface
 [
-    CustomConstructor(PerformanceObserverCallback callback),
+    CustomConstructor(PerformanceObserverInnerCallback callback),
     RuntimeEnabled=PerformanceObserver,
 ] interface PerformanceObserver {
     [RaisesException] void observe(PerformanceObserverInit options);
diff --git a/third_party/WebKit/Source/core/timing/PerformanceObserverCallback.h b/third_party/WebKit/Source/core/timing/PerformanceObserverCallback.h
deleted file mode 100644
index 12170a7..0000000
--- a/third_party/WebKit/Source/core/timing/PerformanceObserverCallback.h
+++ /dev/null
@@ -1,28 +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 PerformanceObserverCallback_h
-#define PerformanceObserverCallback_h
-
-#include "platform/heap/Handle.h"
-#include "wtf/RefPtr.h"
-
-namespace blink {
-
-class ExecutionContext;
-class PerformanceObserverEntryList;
-class PerformanceObserver;
-
-class PerformanceObserverCallback : public GarbageCollectedFinalized<PerformanceObserverCallback> {
-public:
-    virtual ~PerformanceObserverCallback() { }
-
-    virtual void handleEvent(PerformanceObserverEntryList*, PerformanceObserver*) = 0;
-
-    DEFINE_INLINE_VIRTUAL_TRACE() { }
-};
-
-} // namespace blink
-
-#endif // PerformanceObserverCallback_h
diff --git a/third_party/WebKit/Source/core/timing/PerformanceObserverTest.cpp b/third_party/WebKit/Source/core/timing/PerformanceObserverTest.cpp
index 0e3307d..6c8a4891 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceObserverTest.cpp
+++ b/third_party/WebKit/Source/core/timing/PerformanceObserverTest.cpp
@@ -5,23 +5,15 @@
 #include "core/timing/PerformanceObserver.h"
 
 #include "bindings/core/v8/V8BindingForTesting.h"
+#include "bindings/core/v8/V8PerformanceObserverInnerCallback.h"
 #include "core/timing/Performance.h"
 #include "core/timing/PerformanceBase.h"
 #include "core/timing/PerformanceMark.h"
-#include "core/timing/PerformanceObserverCallback.h"
 #include "core/timing/PerformanceObserverInit.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace blink {
 
-class MockPerformanceObserverCallback : public PerformanceObserverCallback {
-public:
-    MockPerformanceObserverCallback() {}
-    ~MockPerformanceObserverCallback() override {}
-
-    void handleEvent(PerformanceObserverEntryList*, PerformanceObserver*) override {}
-};
-
 class MockPerformanceBase : public PerformanceBase {
 public:
     MockPerformanceBase()
@@ -37,8 +29,9 @@
 protected:
     void initialize(ScriptState* scriptState)
     {
+        v8::Local<v8::Function> callback = v8::Function::New(scriptState->context(), nullptr).ToLocalChecked();
         m_base = new MockPerformanceBase();
-        m_cb = new MockPerformanceObserverCallback();
+        m_cb = V8PerformanceObserverInnerCallback::create(scriptState->isolate(), callback);
         m_observer = PerformanceObserver::create(scriptState, m_base, m_cb);
     }
 
@@ -56,7 +49,7 @@
     }
 
     Persistent<MockPerformanceBase> m_base;
-    Persistent<MockPerformanceObserverCallback> m_cb;
+    Persistent<V8PerformanceObserverInnerCallback> m_cb;
     Persistent<PerformanceObserver> m_observer;
 };
 
diff --git a/third_party/WebKit/Source/core/timing/PerformanceTiming.cpp b/third_party/WebKit/Source/core/timing/PerformanceTiming.cpp
index 3f69103..bbcbb4e 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceTiming.cpp
+++ b/third_party/WebKit/Source/core/timing/PerformanceTiming.cpp
@@ -426,18 +426,18 @@
 
 DocumentLoader* PerformanceTiming::documentLoader() const
 {
-    if (!m_frame)
+    if (!frame())
         return nullptr;
 
-    return m_frame->loader().documentLoader();
+    return frame()->loader().documentLoader();
 }
 
 const DocumentTiming* PerformanceTiming::documentTiming() const
 {
-    if (!m_frame)
+    if (!frame())
         return nullptr;
 
-    Document* document = m_frame->document();
+    Document* document = frame()->document();
     if (!document)
         return nullptr;
 
@@ -446,10 +446,10 @@
 
 const PaintTiming* PerformanceTiming::paintTiming() const
 {
-    if (!m_frame)
+    if (!frame())
         return nullptr;
 
-    Document* document = m_frame->document();
+    Document* document = frame()->document();
     if (!document)
         return nullptr;
 
@@ -458,10 +458,10 @@
 
 const DocumentParserTiming* PerformanceTiming::documentParserTiming() const
 {
-    if (!m_frame)
+    if (!frame())
         return nullptr;
 
-    Document* document = m_frame->document();
+    Document* document = frame()->document();
     if (!document)
         return nullptr;
 
diff --git a/third_party/WebKit/Source/core/workers/SharedWorkerThread.cpp b/third_party/WebKit/Source/core/workers/SharedWorkerThread.cpp
index d68b595..54cf81e 100644
--- a/third_party/WebKit/Source/core/workers/SharedWorkerThread.cpp
+++ b/third_party/WebKit/Source/core/workers/SharedWorkerThread.cpp
@@ -45,7 +45,7 @@
 
 SharedWorkerThread::SharedWorkerThread(const String& name, PassRefPtr<WorkerLoaderProxy> workerLoaderProxy, WorkerReportingProxy& workerReportingProxy)
     : WorkerThread(std::move(workerLoaderProxy), workerReportingProxy)
-    , m_workerBackingThread(WorkerBackingThread::create("SharedWorker Thread", BlinkGC::MainThreadHeapMode))
+    , m_workerBackingThread(WorkerBackingThread::create("SharedWorker Thread", BlinkGC::PerThreadHeapMode))
     , m_name(name.isolatedCopy())
 {
 }
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
index c3fb08da..a464524 100644
--- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
+++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
@@ -84,6 +84,7 @@
     WorkerLocation* location() const;
     WorkerNavigator* navigator() const;
     void close();
+    bool isSecureContextForBindings() const { return ExecutionContext::isSecureContext(StandardSecureContextCheck); }
 
     DEFINE_ATTRIBUTE_EVENT_LISTENER(error);
     DEFINE_ATTRIBUTE_EVENT_LISTENER(rejectionhandled);
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.idl b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.idl
index 811d8ba..116145c4 100644
--- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.idl
+++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.idl
@@ -44,6 +44,7 @@
     [RaisesException] void importScripts(DOMString... urls);
     readonly attribute WorkerNavigator navigator;
 
+
     // Console API
     // https://console.spec.whatwg.org/#console-interface
     // [Replaceable] readonly attribute Console console;
@@ -57,6 +58,10 @@
     // Unhandled Promise Rejection Events
     attribute EventHandler onrejectionhandled;
     attribute EventHandler onunhandledrejection;
+
+    // Secure Contexts
+    // https://w3c.github.io/webappsec-secure-contexts/#dom-windoworworkerglobalscope-issecurecontext
+    [ImplementedAs=isSecureContextForBindings] readonly attribute boolean isSecureContext;
 };
 
 WorkerGlobalScope implements WindowBase64;
diff --git a/third_party/WebKit/Source/devtools/BUILD.gn b/third_party/WebKit/Source/devtools/BUILD.gn
index fc9325d..34b3786 100644
--- a/third_party/WebKit/Source/devtools/BUILD.gn
+++ b/third_party/WebKit/Source/devtools/BUILD.gn
@@ -685,6 +685,13 @@
   "front_end/text_editor/CodeMirrorUtils.js",
   "front_end/text_editor/TextEditorAutocompleteController.js",
 ]
+devtools_terminal_js_files = [
+  "front_end/terminal/terminal.css",
+  "front_end/terminal/TerminalWidget.js",
+  "front_end/terminal/xterm.js/addons/fit/fit.js",
+  "front_end/terminal/xterm.js/build/xterm.css",
+  "front_end/terminal/xterm.js/build/xterm.js",
+]
 devtools_timeline_model_js_files = [
   "front_end/timeline_model/LayerTreeModel.js",
   "front_end/timeline_model/TimelineFrameModel.js",
@@ -861,9 +868,9 @@
     devtools_services_js_files + devtools_snippets_js_files +
     devtools_source_frame_js_files + devtools_sources_js_files +
     devtools_temp_storage_shared_worker_js_files +
-    devtools_text_editor_js_files + devtools_timeline_model_js_files +
-    devtools_timeline_js_files + devtools_ui_lazy_js_files +
-    devtools_layer_viewer_js_files
+    devtools_text_editor_js_files + devtools_terminal_js_files +
+    devtools_timeline_model_js_files + devtools_timeline_js_files +
+    devtools_ui_lazy_js_files + devtools_layer_viewer_js_files
 
 all_devtools_files = devtools_cm_css_files + devtools_cm_js_files +
                      devtools_core_files + devtools_module_json_files +
@@ -908,6 +915,7 @@
   "$resources_out_dir/snippets/snippets_module.js",
   "$resources_out_dir/source_frame/source_frame_module.js",
   "$resources_out_dir/sources/sources_module.js",
+  "$resources_out_dir/terminal/terminal_module.js",
   "$resources_out_dir/text_editor/text_editor_module.js",
   "$resources_out_dir/timeline_model/timeline_model_module.js",
   "$resources_out_dir/timeline/timeline_module.js",
diff --git a/third_party/WebKit/Source/devtools/front_end/Tests.js b/third_party/WebKit/Source/devtools/front_end/Tests.js
index 0089a70..6c63b29 100644
--- a/third_party/WebKit/Source/devtools/front_end/Tests.js
+++ b/third_party/WebKit/Source/devtools/front_end/Tests.js
@@ -357,9 +357,8 @@
     function checkNoDuplicates() {
         var uiSourceCodes = test.nonAnonymousUISourceCodes_();
         for (var i = 0; i < uiSourceCodes.length; i++) {
-            var scriptName = WebInspector.networkMapping.networkURL(uiSourceCodes[i]);
             for (var j = i + 1; j < uiSourceCodes.length; j++)
-                test.assertTrue(scriptName !== WebInspector.networkMapping.networkURL(uiSourceCodes[j]), "Found script duplicates: " + test.uiSourceCodesToString_(uiSourceCodes));
+                test.assertTrue(uiSourceCodes[i].url() !== uiSourceCodes[j].url(), "Found script duplicates: " + test.uiSourceCodesToString_(uiSourceCodes));
         }
     }
 
@@ -1070,7 +1069,7 @@
 {
     var names = [];
     for (var i = 0; i < uiSourceCodes.length; i++)
-        names.push('"' + WebInspector.networkMapping.networkURL(uiSourceCodes[i]) + '"');
+        names.push('"' + uiSourceCodes[i].url() + '"');
     return names.join(",");
 };
 
@@ -1081,19 +1080,16 @@
  */
 TestSuite.prototype.nonAnonymousUISourceCodes_ = function()
 {
-    function filterOutAnonymous(uiSourceCode)
-    {
-        return !!WebInspector.networkMapping.networkURL(uiSourceCode);
-    }
-
+    /**
+     * @param {!WebInspector.UISourceCode} uiSourceCode
+     */
     function filterOutService(uiSourceCode)
     {
         return !uiSourceCode.isFromServiceProject();
     }
 
     var uiSourceCodes = WebInspector.workspace.uiSourceCodes();
-    uiSourceCodes = uiSourceCodes.filter(filterOutService);
-    return uiSourceCodes.filter(filterOutAnonymous);
+    return uiSourceCodes.filter(filterOutService);
 };
 
 
diff --git a/third_party/WebKit/Source/devtools/front_end/audits/AuditsPanel.js b/third_party/WebKit/Source/devtools/front_end/audits/AuditsPanel.js
index 30de90b..c998c769 100644
--- a/third_party/WebKit/Source/devtools/front_end/audits/AuditsPanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/audits/AuditsPanel.js
@@ -129,6 +129,7 @@
         if (!categoryResults._resultLocation) {
             categoryResults.sort((a, b) => (a.title || "").localeCompare(b.title || ""));
             var resultView = WebInspector.viewManager.createStackLocation();
+            resultView.widget().element.classList.add("audit-result-view");
             for (var i = 0; i < categoryResults.length; ++i)
                 resultView.showView(new WebInspector.AuditCategoryResultPane(categoryResults[i]));
             categoryResults._resultLocation = resultView;
diff --git a/third_party/WebKit/Source/devtools/front_end/audits/auditsPanel.css b/third_party/WebKit/Source/devtools/front_end/audits/auditsPanel.css
index c9a78ba..75b9adf 100644
--- a/third_party/WebKit/Source/devtools/front_end/audits/auditsPanel.css
+++ b/third_party/WebKit/Source/devtools/front_end/audits/auditsPanel.css
@@ -77,6 +77,10 @@
     margin: 0 5px 0 0;
 }
 
+.audit-result-view {
+    overflow: auto;
+}
+
 .panel-enabler-view.audit-launcher-view label {
     padding: 0 0 5px 0;
     margin: 0;
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/BlackboxManager.js b/third_party/WebKit/Source/devtools/front_end/bindings/BlackboxManager.js
index 5f20ec6..e24342f8 100644
--- a/third_party/WebKit/Source/devtools/front_end/bindings/BlackboxManager.js
+++ b/third_party/WebKit/Source/devtools/front_end/bindings/BlackboxManager.js
@@ -5,13 +5,11 @@
 /**
  * @constructor
  * @param {!WebInspector.DebuggerWorkspaceBinding} debuggerWorkspaceBinding
- * @param {!WebInspector.NetworkMapping} networkMapping
  * @implements {WebInspector.TargetManager.Observer}
  */
-WebInspector.BlackboxManager = function(debuggerWorkspaceBinding, networkMapping)
+WebInspector.BlackboxManager = function(debuggerWorkspaceBinding)
 {
     this._debuggerWorkspaceBinding = debuggerWorkspaceBinding;
-    this._networkMapping = networkMapping;
 
     WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.ParsedScriptSource, this._parsedScriptSource, this);
     WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.GlobalObjectCleared, this._globalObjectCleared, this);
@@ -195,12 +193,7 @@
      */
     _uiSourceCodeURL: function(uiSourceCode)
     {
-        var networkURL = this._networkMapping.networkURL(uiSourceCode);
-        var projectType = uiSourceCode.project().type();
-        if (projectType === WebInspector.projectTypes.Debugger)
-            return null;
-        var url = projectType === WebInspector.projectTypes.Formatter ? uiSourceCode.url() : networkURL;
-        return url ? url : null;
+        return uiSourceCode.project().type() === WebInspector.projectTypes.Debugger ? null : uiSourceCode.url();
     },
 
     /**
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/BreakpointManager.js b/third_party/WebKit/Source/devtools/front_end/bindings/BreakpointManager.js
index 2ed225f..668ed72 100644
--- a/third_party/WebKit/Source/devtools/front_end/bindings/BreakpointManager.js
+++ b/third_party/WebKit/Source/devtools/front_end/bindings/BreakpointManager.js
@@ -34,15 +34,13 @@
  * @implements {WebInspector.TargetManager.Observer}
  * @param {?WebInspector.Setting} breakpointsSetting
  * @param {!WebInspector.Workspace} workspace
- * @param {!WebInspector.NetworkMapping} networkMapping
  * @param {!WebInspector.TargetManager} targetManager
  * @param {!WebInspector.DebuggerWorkspaceBinding} debuggerWorkspaceBinding
  */
-WebInspector.BreakpointManager = function(breakpointsSetting, workspace, networkMapping, targetManager, debuggerWorkspaceBinding)
+WebInspector.BreakpointManager = function(breakpointsSetting, workspace, targetManager, debuggerWorkspaceBinding)
 {
     this._storage = new WebInspector.BreakpointManager.Storage(this, breakpointsSetting);
     this._workspace = workspace;
-    this._networkMapping = networkMapping;
     this._targetManager = targetManager;
     this._debuggerWorkspaceBinding = debuggerWorkspaceBinding;
 
@@ -84,9 +82,7 @@
      */
     _sourceFileId: function(uiSourceCode)
     {
-        var networkURL = this._networkMapping.networkURL(uiSourceCode)
-        if (!networkURL)
-            return "";
+        // TODO(lushnikov): _sourceFileId is not needed any more.
         return uiSourceCode.url();
     },
 
@@ -510,9 +506,8 @@
         var debuggerModel = WebInspector.DebuggerModel.fromTarget(target);
         if (!debuggerModel)
             return;
-        var networkMapping = this._breakpointManager._networkMapping;
         var debuggerWorkspaceBinding = this._breakpointManager._debuggerWorkspaceBinding;
-        this._targetBreakpoints.set(target, new WebInspector.BreakpointManager.TargetBreakpoint(debuggerModel, this, networkMapping, debuggerWorkspaceBinding));
+        this._targetBreakpoints.set(target, new WebInspector.BreakpointManager.TargetBreakpoint(debuggerModel, this, debuggerWorkspaceBinding));
     },
 
     /**
@@ -732,15 +727,13 @@
  * @extends {WebInspector.SDKObject}
  * @param {!WebInspector.DebuggerModel} debuggerModel
  * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint
- * @param {!WebInspector.NetworkMapping} networkMapping
  * @param {!WebInspector.DebuggerWorkspaceBinding} debuggerWorkspaceBinding
  */
-WebInspector.BreakpointManager.TargetBreakpoint = function(debuggerModel, breakpoint, networkMapping, debuggerWorkspaceBinding)
+WebInspector.BreakpointManager.TargetBreakpoint = function(debuggerModel, breakpoint, debuggerWorkspaceBinding)
 {
     WebInspector.SDKObject.call(this, debuggerModel.target());
     this._debuggerModel = debuggerModel;
     this._breakpoint = breakpoint;
-    this._networkMapping = networkMapping;
     this._debuggerWorkspaceBinding = debuggerWorkspaceBinding;
 
     this._liveLocations = new WebInspector.LiveLocationPool();
@@ -830,9 +823,7 @@
             var position = this._breakpoint._currentState;
             newState = new WebInspector.BreakpointManager.Breakpoint.State(position.url, null, position.lineNumber, position.columnNumber, condition);
         } else if (uiSourceCode) {
-            var networkURL = this._networkMapping.networkURL(uiSourceCode);
-            if (networkURL)
-                newState = new WebInspector.BreakpointManager.Breakpoint.State(networkURL, null, lineNumber, columnNumber, condition);
+            newState = new WebInspector.BreakpointManager.Breakpoint.State(uiSourceCode.url(), null, lineNumber, columnNumber, condition);
         }
         if (this._debuggerId && WebInspector.BreakpointManager.Breakpoint.State.equals(newState, this._currentState)) {
             callback();
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/CompilerScriptMapping.js b/third_party/WebKit/Source/devtools/front_end/bindings/CompilerScriptMapping.js
index ca159e8..e08e7815 100644
--- a/third_party/WebKit/Source/devtools/front_end/bindings/CompilerScriptMapping.js
+++ b/third_party/WebKit/Source/devtools/front_end/bindings/CompilerScriptMapping.js
@@ -129,15 +129,12 @@
     {
         if (uiSourceCode.project().type() === WebInspector.projectTypes.Service)
             return null;
-        var networkURL = this._networkMapping.networkURL(uiSourceCode);
-        if (!networkURL)
-            return null;
-        var sourceMap = this._sourceMapForURL.get(networkURL);
+        var sourceMap = this._sourceMapForURL.get(uiSourceCode.url());
         if (!sourceMap)
             return null;
         var script = /** @type {!WebInspector.Script} */ (this._scriptForSourceMap.get(sourceMap));
         console.assert(script);
-        var entry = sourceMap.firstSourceLineMapping(networkURL, lineNumber);
+        var entry = sourceMap.firstSourceLineMapping(uiSourceCode.url(), lineNumber);
         if (!entry)
             return null;
         return this._debuggerModel.createRawLocation(script, entry.lineNumber, entry.columnNumber);
@@ -280,13 +277,10 @@
      */
     uiLineHasMapping: function(uiSourceCode, lineNumber)
     {
-        var networkURL = this._networkMapping.networkURL(uiSourceCode);
-        if (!networkURL)
-            return true;
-        var sourceMap = this._sourceMapForURL.get(networkURL);
+        var sourceMap = this._sourceMapForURL.get(uiSourceCode.url());
         if (!sourceMap)
             return true;
-        return !!sourceMap.firstSourceLineMapping(networkURL, lineNumber);
+        return !!sourceMap.firstSourceLineMapping(uiSourceCode.url(), lineNumber);
     },
 
     /**
@@ -311,8 +305,7 @@
     _uiSourceCodeAddedToWorkspace: function(event)
     {
         var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
-        var networkURL = this._networkMapping.networkURL(uiSourceCode);
-        if (!networkURL || !this._sourceMapForURL.get(networkURL))
+        if (!this._sourceMapForURL.get(uiSourceCode.url()))
             return;
         this._bindUISourceCode(uiSourceCode);
     },
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/NetworkMapping.js b/third_party/WebKit/Source/devtools/front_end/bindings/NetworkMapping.js
index 58752db..dff680f 100644
--- a/third_party/WebKit/Source/devtools/front_end/bindings/NetworkMapping.js
+++ b/third_party/WebKit/Source/devtools/front_end/bindings/NetworkMapping.js
@@ -77,17 +77,6 @@
     },
 
     /**
-     * @param {!WebInspector.UISourceCode} uiSourceCode
-     * @return {string}
-     */
-    networkURL: function(uiSourceCode)
-    {
-        if (uiSourceCode.project().type() === WebInspector.projectTypes.FileSystem)
-            return "";
-        return uiSourceCode.url();
-    },
-
-    /**
      * @param {!WebInspector.Target} target
      * @param {?WebInspector.ResourceTreeFrame} frame
      * @param {string} url
@@ -157,10 +146,8 @@
      */
     addMapping: function(networkUISourceCode, uiSourceCode)
     {
-        var url = this.networkURL(networkUISourceCode);
-        var path = uiSourceCode.url();
         var fileSystemPath = WebInspector.FileSystemWorkspaceBinding.fileSystemPath(uiSourceCode.project().id());
-        this._fileSystemMapping.addMappingForResource(url, fileSystemPath, path);
+        this._fileSystemMapping.addMappingForResource(networkUISourceCode.url(), fileSystemPath, uiSourceCode.url());
     },
 
     /**
@@ -168,8 +155,7 @@
      */
     removeMapping: function(uiSourceCode)
     {
-        var networkURL = this.networkURL(uiSourceCode);
-        this._fileSystemMapping.removeMappingForURL(networkURL);
+        this._fileSystemMapping.removeMappingForURL(uiSourceCode.url());
     },
 
     /**
@@ -194,7 +180,7 @@
         function listener(event)
         {
             var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
-            if (this.networkURL(uiSourceCode) === url) {
+            if (uiSourceCode.url() === url) {
                 WebInspector.Revealer.reveal(uiSourceCode.uiLocation(lineNumber, columnNumber));
                 this._workspace.removeEventListener(WebInspector.Workspace.Events.UISourceCodeAdded, listener, this);
             }
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/NetworkProject.js b/third_party/WebKit/Source/devtools/front_end/bindings/NetworkProject.js
index e2a6aa4..59d20d4 100644
--- a/third_party/WebKit/Source/devtools/front_end/bindings/NetworkProject.js
+++ b/third_party/WebKit/Source/devtools/front_end/bindings/NetworkProject.js
@@ -32,13 +32,11 @@
  * @constructor
  * @param {!WebInspector.TargetManager} targetManager
  * @param {!WebInspector.Workspace} workspace
- * @param {!WebInspector.NetworkMapping} networkMapping
  * @implements {WebInspector.TargetManager.Observer}
  */
-WebInspector.NetworkProjectManager = function(targetManager, workspace, networkMapping)
+WebInspector.NetworkProjectManager = function(targetManager, workspace)
 {
     this._workspace = workspace;
-    this._networkMapping = networkMapping;
     targetManager.observeTargets(this);
 }
 
@@ -49,7 +47,7 @@
      */
     targetAdded: function(target)
     {
-        new WebInspector.NetworkProject(target, this._workspace, this._networkMapping, WebInspector.ResourceTreeModel.fromTarget(target));
+        new WebInspector.NetworkProject(target, this._workspace, WebInspector.ResourceTreeModel.fromTarget(target));
     },
 
     /**
@@ -67,14 +65,12 @@
  * @extends {WebInspector.SDKObject}
  * @param {!WebInspector.Target} target
  * @param {!WebInspector.Workspace} workspace
- * @param {!WebInspector.NetworkMapping} networkMapping
  * @param {?WebInspector.ResourceTreeModel} resourceTreeModel
  */
-WebInspector.NetworkProject = function(target, workspace, networkMapping, resourceTreeModel)
+WebInspector.NetworkProject = function(target, workspace, resourceTreeModel)
 {
     WebInspector.SDKObject.call(this, target);
     this._workspace = workspace;
-    this._networkMapping = networkMapping;
     /** @type {!Map<string, !WebInspector.ContentProviderBasedProject>} */
     this._workspaceProjects = new Map();
     this._resourceTreeModel = resourceTreeModel;
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/ResourceScriptMapping.js b/third_party/WebKit/Source/devtools/front_end/bindings/ResourceScriptMapping.js
index d46a02d..04f8b130 100644
--- a/third_party/WebKit/Source/devtools/front_end/bindings/ResourceScriptMapping.js
+++ b/third_party/WebKit/Source/devtools/front_end/bindings/ResourceScriptMapping.js
@@ -42,8 +42,8 @@
     this._debuggerModel = debuggerModel;
     this._networkMapping = networkMapping;
     this._debuggerWorkspaceBinding = debuggerWorkspaceBinding;
-    /** @type {!Array.<!WebInspector.UISourceCode>} */
-    this._boundUISourceCodes = [];
+    /** @type {!Set<!WebInspector.UISourceCode>} */
+    this._boundUISourceCodes = new Set();
 
     /** @type {!Map.<!WebInspector.UISourceCode, !WebInspector.ResourceScriptFile>} */
     this._uiSourceCodeToScriptFile = new Map();
@@ -160,11 +160,8 @@
     _uiSourceCodeAdded: function(event)
     {
         var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
-        if (!this._networkMapping.networkURL(uiSourceCode))
-            return;
         if (uiSourceCode.isFromServiceProject())
             return;
-
         var scripts = this._scriptsForUISourceCode(uiSourceCode);
         if (!scripts.length)
             return;
@@ -178,9 +175,7 @@
     _uiSourceCodeRemoved: function(event)
     {
         var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
-        if (!this._networkMapping.networkURL(uiSourceCode))
-            return;
-        if (uiSourceCode.isFromServiceProject())
+        if (uiSourceCode.isFromServiceProject() || !this._boundUISourceCodes.has(uiSourceCode))
             return;
 
         this._unbindUISourceCode(uiSourceCode);
@@ -216,11 +211,9 @@
     _scriptsForUISourceCode: function(uiSourceCode)
     {
         var target = WebInspector.NetworkProject.targetForUISourceCode(uiSourceCode);
-        if (target && target !== this._debuggerModel.target())
+        if (target !== this._debuggerModel.target())
             return [];
-        if (!this._networkMapping.networkURL(uiSourceCode))
-            return [];
-        return this._debuggerModel.scriptsForSourceURL(this._networkMapping.networkURL(uiSourceCode));
+        return this._debuggerModel.scriptsForSourceURL(uiSourceCode.url());
     },
 
     /**
@@ -241,7 +234,7 @@
         for (var i = 0; i < scripts.length; ++i)
             this._debuggerWorkspaceBinding.updateLocations(scripts[i]);
         this._debuggerWorkspaceBinding.setSourceMapping(this._target, uiSourceCode, this);
-        this._boundUISourceCodes.push(uiSourceCode);
+        this._boundUISourceCodes.add(uiSourceCode);
     },
 
     /**
@@ -255,14 +248,14 @@
             this._setScriptFile(uiSourceCode, null);
         }
         this._debuggerWorkspaceBinding.setSourceMapping(this._target, uiSourceCode, null);
-        this._boundUISourceCodes.remove(uiSourceCode);
+        this._boundUISourceCodes.delete(uiSourceCode);
     },
 
     _debuggerReset: function()
     {
-        var sourceCodes = this._boundUISourceCodes;
-        this._boundUISourceCodes = [];
-        sourceCodes.forEach(this._unbindUISourceCode.bind(this));
+        for (var uiSourceCode of this._boundUISourceCodes.valuesArray())
+            this._unbindUISourceCode(uiSourceCode);
+        this._boundUISourceCodes.clear();
         console.assert(!this._uiSourceCodeToScriptFile.size);
     },
 
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/StylesSourceMapping.js b/third_party/WebKit/Source/devtools/front_end/bindings/StylesSourceMapping.js
index 4064f307..ec0347b 100644
--- a/third_party/WebKit/Source/devtools/front_end/bindings/StylesSourceMapping.js
+++ b/third_party/WebKit/Source/devtools/front_end/bindings/StylesSourceMapping.js
@@ -163,10 +163,9 @@
     _uiSourceCodeAddedToWorkspace: function(event)
     {
         var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
-        var networkURL = this._networkMapping.networkURL(uiSourceCode);
-        if (!networkURL || !this._urlToHeadersByFrameId.has(networkURL))
+        if (!this._urlToHeadersByFrameId.has(uiSourceCode.url()))
             return;
-        this._bindUISourceCode(uiSourceCode, this._urlToHeadersByFrameId.get(networkURL).valuesArray()[0].valuesArray()[0]);
+        this._bindUISourceCode(uiSourceCode, this._urlToHeadersByFrameId.get(uiSourceCode.url()).valuesArray()[0].valuesArray()[0]);
     },
 
     /**
@@ -209,10 +208,9 @@
      */
     _setStyleContent: function(uiSourceCode, content, majorChange)
     {
-        var networkURL = this._networkMapping.networkURL(uiSourceCode);
-        var styleSheetIds = this._cssModel.styleSheetIdsForURL(networkURL);
+        var styleSheetIds = this._cssModel.styleSheetIdsForURL(uiSourceCode.url());
         if (!styleSheetIds.length)
-            return Promise.resolve(/** @type {?string} */("No stylesheet found: " + networkURL));
+            return Promise.resolve(/** @type {?string} */("No stylesheet found: " + uiSourceCode.url()));
 
         this._isSettingContent = true;
 
diff --git a/third_party/WebKit/Source/devtools/front_end/components/Linkifier.js b/third_party/WebKit/Source/devtools/front_end/components/Linkifier.js
index b4a228f..f50328a3 100644
--- a/third_party/WebKit/Source/devtools/front_end/components/Linkifier.js
+++ b/third_party/WebKit/Source/devtools/front_end/components/Linkifier.js
@@ -300,8 +300,7 @@
                 return;
 
             event.consume(true);
-            var networkURL = WebInspector.networkMapping.networkURL(uiLocation.uiSourceCode);
-            if (WebInspector.Linkifier.handleLink(networkURL, uiLocation.lineNumber))
+            if (WebInspector.Linkifier.handleLink(uiLocation.uiSourceCode.url(), uiLocation.lineNumber))
                 return;
             WebInspector.Revealer.reveal(uiLocation);
         }
@@ -468,9 +467,10 @@
 {
     var container = createDocumentFragment();
     var linkStringRegEx = /(?:[a-zA-Z][a-zA-Z0-9+.-]{2,}:\/\/|data:|www\.)[\w$\-_+*'=\|\/\\(){}[\]^%@&#~,:;.!?]{2,}[\w$\-_+*=\|\/\\({^%@&#~]/;
+    var pathLineRegex = /(?:\/[\/\w\.-]+)+\:[\d]+/;
 
     while (string && string.length < WebInspector.Linkifier.MaxLengthToIgnoreLinkifier) {
-        var linkString = linkStringRegEx.exec(string);
+        var linkString = linkStringRegEx.exec(string) || pathLineRegex.exec(string);
         if (!linkString)
             break;
 
diff --git a/third_party/WebKit/Source/devtools/front_end/components/ObjectPropertiesSection.js b/third_party/WebKit/Source/devtools/front_end/components/ObjectPropertiesSection.js
index d2e364d..345a1b8 100644
--- a/third_party/WebKit/Source/devtools/front_end/components/ObjectPropertiesSection.js
+++ b/third_party/WebKit/Source/devtools/front_end/components/ObjectPropertiesSection.js
@@ -1051,6 +1051,8 @@
     return nameElement;
 }
 
+WebInspector.ObjectPropertiesSection._functionPrefixSource = /^(?:async\s)?function\*?\s/;
+
 /**
  * @param {?string=} description
  * @return {string} valueText
@@ -1058,7 +1060,8 @@
 WebInspector.ObjectPropertiesSection.valueTextForFunctionDescription = function(description)
 {
     var text = description.replace(/^function [gs]et /, "function ");
-    var matches = /^function\s([^)]*)/.exec(text);
+    var functionPrefixWithArguments = new RegExp(WebInspector.ObjectPropertiesSection._functionPrefixSource.source + "([^)]*)");
+    var matches = functionPrefixWithArguments.exec(text);
     if (!matches) {
         // process shorthand methods
         matches = /[^(]*(\([^)]*)/.exec(text);
@@ -1204,6 +1207,13 @@
             return;
         }
 
+        var matched = func.description.match(WebInspector.ObjectPropertiesSection._functionPrefixSource);
+        if (matched) {
+            var prefix = createElementWithClass("span", "object-value-function-prefix");
+            prefix.textContent = matched[0];
+            element.appendChild(prefix);
+        }
+
         if (linkify && response && response.location) {
             var anchor = createElement("span");
             element.classList.add("linkified");
@@ -1214,7 +1224,7 @@
 
         var text = func.description.substring(0, 200);
         if (includePreview) {
-            element.textContent = text.replace(/^function /, "") + (func.description.length > 200 ? "\u2026" : "");
+            element.createTextChild(text.replace(WebInspector.ObjectPropertiesSection._functionPrefixSource, "") + (func.description.length > 200 ? "\u2026" : ""));
             return;
         }
 
@@ -1231,7 +1241,7 @@
         {
             var tokenize = tokenizerFactory.createTokenizer("text/javascript");
             tokenize(text, processToken);
-            element.textContent = (functionName || "anonymous") + "(" + (params || []).join(", ") + ")";
+            element.createTextChild((functionName || "anonymous") + "(" + (params || []).join(", ") + ")");
         }
 
         var doneProcessing = false;
diff --git a/third_party/WebKit/Source/devtools/front_end/components/objectValue.css b/third_party/WebKit/Source/devtools/front_end/components/objectValue.css
index a6196c8..395cfcd 100644
--- a/third_party/WebKit/Source/devtools/front_end/components/objectValue.css
+++ b/third_party/WebKit/Source/devtools/front_end/components/objectValue.css
@@ -23,10 +23,8 @@
     background-color: rgba(56, 121, 217, 0.1);
 }
 
-.object-value-function::before {
-    content: "function";
+.object-value-function-prefix {
     color: rgb(170, 13, 145);
-    padding-right: 5px;
 }
 
 .object-value-function {
diff --git a/third_party/WebKit/Source/devtools/front_end/components_lazy/FilmStripModel.js b/third_party/WebKit/Source/devtools/front_end/components_lazy/FilmStripModel.js
index 7b41624..f953373 100644
--- a/third_party/WebKit/Source/devtools/front_end/components_lazy/FilmStripModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/components_lazy/FilmStripModel.js
@@ -33,15 +33,11 @@
 
         /** @type {!Array<!WebInspector.FilmStripModel.Frame>} */
         this._frames = [];
-
-        var browserProcess = tracingModel.processByName("Browser");
-        if (!browserProcess)
-            return;
-        var mainThread = browserProcess.threadByName("CrBrowserMain");
-        if (!mainThread)
+        var browserMain = WebInspector.TracingModel.browserMainThread(tracingModel);
+        if (!browserMain)
             return;
 
-        var events = mainThread.events();
+        var events = browserMain.events();
         for (var i = 0; i < events.length; ++i) {
             var event = events[i];
             if (event.startTime < this._zeroTime)
diff --git a/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js b/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js
index b5d8d190..ce85acf 100644
--- a/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js
+++ b/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js
@@ -705,10 +705,6 @@
      */
     _formatAsArrayEntry: function(output)
     {
-        if (this._message.type === WebInspector.ConsoleMessage.MessageType.DirXML) {
-            // Prevent infinite expansion of cross-referencing arrays.
-            return this._formatParameter(output, output.subtype === "array" || output.subtype === "typedarray", false);
-        }
         return this._previewFormatter.renderPropertyPreview(output.type, output.subtype, output.description);
     },
 
diff --git a/third_party/WebKit/Source/devtools/front_end/externs.js b/third_party/WebKit/Source/devtools/front_end/externs.js
index e28311f..799ea01 100644
--- a/third_party/WebKit/Source/devtools/front_end/externs.js
+++ b/third_party/WebKit/Source/devtools/front_end/externs.js
@@ -776,3 +776,18 @@
  * TODO(jsbell): DOMException should be a subclass of Error.
  */
 DOMException.prototype.message;
+
+/**
+ * @constructor
+ * @param {!Object} params
+ */
+var Terminal = function(params) { }
+
+Terminal.prototype = {
+    fit: function() { },
+    linkify: function() { },
+    /** @param {!Element} element */
+    open: function(element) { },
+    /** @param {string} eventName * @param {!Function} handler */
+    on: function(eventName, handler) { }
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/inspector.json b/third_party/WebKit/Source/devtools/front_end/inspector.json
index 529c6f0..1fc5ea73 100644
--- a/third_party/WebKit/Source/devtools/front_end/inspector.json
+++ b/third_party/WebKit/Source/devtools/front_end/inspector.json
@@ -34,6 +34,7 @@
         { "name": "layer_viewer", "condition": "!v8only" },
         { "name": "snippets" },
         { "name": "diff" },
+        { "name": "terminal", "type": "remote" },
         { "name": "sass", "condition": "!v8only" },
         { "name": "accessibility", "condition": "!v8only", "type": "remote" },
         { "name": "animation", "condition": "!v8only" },
diff --git a/third_party/WebKit/Source/devtools/front_end/main/Main.js b/third_party/WebKit/Source/devtools/front_end/main/Main.js
index cf8b62f..e5db6c5 100644
--- a/third_party/WebKit/Source/devtools/front_end/main/Main.js
+++ b/third_party/WebKit/Source/devtools/front_end/main/Main.js
@@ -98,6 +98,7 @@
         Runtime.experiments.register("timelineShowAllProcesses", "Show all processes on Timeline", true);
         Runtime.experiments.register("securityPanel", "Security panel");
         Runtime.experiments.register("sourceDiff", "Source diff");
+        Runtime.experiments.register("terminalInDrawer", "Terminal in drawer", true);
         Runtime.experiments.register("timelineFlowEvents", "Timeline flow events", true);
         Runtime.experiments.register("timelineInvalidationTracking", "Timeline invalidation tracking", true);
         Runtime.experiments.register("timelineRecordingPerspectives", "Timeline recording perspectives UI");
@@ -172,18 +173,18 @@
 
         var fileSystemWorkspaceBinding = new WebInspector.FileSystemWorkspaceBinding(WebInspector.isolatedFileSystemManager, WebInspector.workspace);
         WebInspector.networkMapping = new WebInspector.NetworkMapping(WebInspector.targetManager, WebInspector.workspace, fileSystemWorkspaceBinding, WebInspector.fileSystemMapping);
-        WebInspector.networkProjectManager = new WebInspector.NetworkProjectManager(WebInspector.targetManager, WebInspector.workspace, WebInspector.networkMapping);
+        WebInspector.networkProjectManager = new WebInspector.NetworkProjectManager(WebInspector.targetManager, WebInspector.workspace);
         WebInspector.presentationConsoleMessageHelper = new WebInspector.PresentationConsoleMessageHelper(WebInspector.workspace);
         WebInspector.cssWorkspaceBinding = new WebInspector.CSSWorkspaceBinding(WebInspector.targetManager, WebInspector.workspace, WebInspector.networkMapping);
         WebInspector.debuggerWorkspaceBinding = new WebInspector.DebuggerWorkspaceBinding(WebInspector.targetManager, WebInspector.workspace, WebInspector.networkMapping);
-        WebInspector.breakpointManager = new WebInspector.BreakpointManager(null, WebInspector.workspace, WebInspector.networkMapping, WebInspector.targetManager, WebInspector.debuggerWorkspaceBinding);
+        WebInspector.breakpointManager = new WebInspector.BreakpointManager(null, WebInspector.workspace, WebInspector.targetManager, WebInspector.debuggerWorkspaceBinding);
         WebInspector.extensionServer = new WebInspector.ExtensionServer();
 
         WebInspector.persistence = new WebInspector.Persistence(WebInspector.workspace, WebInspector.breakpointManager, WebInspector.fileSystemMapping);
 
         new WebInspector.OverlayController();
         new WebInspector.ExecutionContextSelector(WebInspector.targetManager, WebInspector.context);
-        WebInspector.blackboxManager = new WebInspector.BlackboxManager(WebInspector.debuggerWorkspaceBinding, WebInspector.networkMapping);
+        WebInspector.blackboxManager = new WebInspector.BlackboxManager(WebInspector.debuggerWorkspaceBinding);
 
         var autoselectPanel = WebInspector.UIString("auto");
         var openAnchorLocationSetting = WebInspector.settings.createSetting("openLinkHandler", autoselectPanel);
diff --git a/third_party/WebKit/Source/devtools/front_end/network/NetworkPanel.js b/third_party/WebKit/Source/devtools/front_end/network/NetworkPanel.js
index 4714f4c..aff3f168 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/NetworkPanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/network/NetworkPanel.js
@@ -525,7 +525,7 @@
         }
         if (target instanceof WebInspector.UISourceCode) {
             var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (target);
-            var resource = WebInspector.resourceForURL(WebInspector.networkMapping.networkURL(uiSourceCode));
+            var resource = WebInspector.resourceForURL(uiSourceCode.url());
             if (resource && resource.request)
                 appendRevealItem.call(this, resource.request);
             return;
diff --git a/third_party/WebKit/Source/devtools/front_end/persistence/Persistence.js b/third_party/WebKit/Source/devtools/front_end/persistence/Persistence.js
index 1f6948e8..7235e4c 100644
--- a/third_party/WebKit/Source/devtools/front_end/persistence/Persistence.js
+++ b/third_party/WebKit/Source/devtools/front_end/persistence/Persistence.js
@@ -17,6 +17,10 @@
     this._fileSystemMapping = fileSystemMapping;
     /** @type {!Set<!WebInspector.PersistenceBinding>} */
     this._bindings = new Set();
+
+    /** @type {!Map<string, number>} */
+    this._filePathPrefixesToBindingCount = new Map();
+
     this._eventListeners = [
         workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeAdded, this._onUISourceCodeAdded, this),
         workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeRemoved, this._onUISourceCodeRemoved, this),
@@ -123,6 +127,8 @@
         binding.fileSystem.addEventListener(WebInspector.UISourceCode.Events.WorkingCopyCommitted, this._onWorkingCopyCommitted, this);
         binding.fileSystem.addEventListener(WebInspector.UISourceCode.Events.TitleChanged, this._onFileSystemUISourceCodeRenamed, this);
 
+        this._addFilePathBindingPrefixes(binding.fileSystem.url());
+
         this._moveBreakpoints(binding.fileSystem, binding.network);
         this.dispatchEventToListeners(WebInspector.Persistence.Events.BindingCreated, binding);
     },
@@ -143,6 +149,8 @@
         binding.fileSystem.removeEventListener(WebInspector.UISourceCode.Events.WorkingCopyCommitted, this._onWorkingCopyCommitted, this);
         binding.fileSystem.removeEventListener(WebInspector.UISourceCode.Events.TitleChanged, this._onFileSystemUISourceCodeRenamed, this);
 
+        this._removeFilePathBindingPrefixes(binding.fileSystem.url());
+
         this._copyBreakpoints(binding.network, binding.fileSystem);
         this.dispatchEventToListeners(WebInspector.Persistence.Events.BindingRemoved, binding);
     },
@@ -256,6 +264,46 @@
         return uiSourceCode[WebInspector.Persistence._binding] || null;
     },
 
+    /**
+     * @param {string} filePath
+     */
+    _addFilePathBindingPrefixes: function(filePath)
+    {
+        var relative = "";
+        for (var token of filePath.split("/")) {
+            relative += token + "/";
+            var count = this._filePathPrefixesToBindingCount.get(relative) || 0;
+            this._filePathPrefixesToBindingCount.set(relative, count + 1);
+        }
+    },
+
+    /**
+     * @param {string} filePath
+     */
+    _removeFilePathBindingPrefixes: function(filePath)
+    {
+        var relative = "";
+        for (var token of filePath.split("/")) {
+            relative += token + "/";
+            var count = this._filePathPrefixesToBindingCount.get(relative);
+            if (count === 1)
+                this._filePathPrefixesToBindingCount.delete(relative);
+            else
+                this._filePathPrefixesToBindingCount.set(relative, count - 1);
+        }
+    },
+
+    /**
+     * @param {string} filePath
+     * @return {boolean}
+     */
+    filePathHasBindings: function(filePath)
+    {
+        if (!filePath.endsWith("/"))
+            filePath += "/";
+        return this._filePathPrefixesToBindingCount.has(filePath);
+    },
+
     dispose: function()
     {
         WebInspector.EventTarget.removeEventListeners(this._eventListeners);
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 9dd1a038..ce62d66 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/ResourcesPanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/ResourcesPanel.js
@@ -1043,8 +1043,6 @@
      */
     appendResource: function(resource)
     {
-        if (resource.isHidden())
-            return;
         var resourceType = resource.resourceType();
         var categoryName = resourceType.name();
         var categoryElement = resourceType === WebInspector.resourceTypes.Document ? this : this._categoryElements[categoryName];
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/ProfileTreeModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/ProfileTreeModel.js
index 5ceb738d..b8206f4e 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/ProfileTreeModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/ProfileTreeModel.js
@@ -73,8 +73,8 @@
 WebInspector.ProfileTreeModel = function(root)
 {
     this.root = root;
-    this.total = this._calculateTotals(this.root);
     this._assignDepthsAndParents();
+    this.total = this._calculateTotals(this.root);
 }
 
 WebInspector.ProfileTreeModel.prototype = {
@@ -103,12 +103,23 @@
     },
 
     /**
-     * @param {!WebInspector.ProfileNode} node
+     * @param {!WebInspector.ProfileNode} root
      * @return {number}
      */
-    _calculateTotals: function(node)
+    _calculateTotals: function(root)
     {
-        node.total = node.children.reduce((acc, child) => acc + this._calculateTotals(child), node.self);
-        return node.total;
+        var nodesToTraverse = [root];
+        var dfsList = [];
+        while (nodesToTraverse.length) {
+            var node = nodesToTraverse.pop();
+            node.total = node.self;
+            dfsList.push(node);
+            nodesToTraverse.push(...node.children);
+        }
+        while (dfsList.length > 1) {
+            var node = dfsList.pop();
+            node.parent.total += node.total;
+        }
+        return root.total;
     }
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/Resource.js b/third_party/WebKit/Source/devtools/front_end/sdk/Resource.js
index 1c4416dd..4db1ddc 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/Resource.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/Resource.js
@@ -38,9 +38,8 @@
  * @param {!NetworkAgent.LoaderId} loaderId
  * @param {!WebInspector.ResourceType} type
  * @param {string} mimeType
- * @param {boolean=} isHidden
  */
-WebInspector.Resource = function(target, request, url, documentURL, frameId, loaderId, type, mimeType, isHidden)
+WebInspector.Resource = function(target, request, url, documentURL, frameId, loaderId, type, mimeType)
 {
     WebInspector.SDKObject.call(this, target);
     this._request = request;
@@ -50,7 +49,6 @@
     this._loaderId = loaderId;
     this._type = type || WebInspector.resourceTypes.Other;
     this._mimeType = mimeType;
-    this._isHidden = isHidden;
 
     /** @type {?string} */ this._content;
     /** @type {boolean} */ this._contentEncoded;
@@ -316,15 +314,6 @@
     /**
      * @return {boolean}
      */
-    isHidden: function()
-    {
-        return !!this._isHidden;
-    },
-
-
-    /**
-     * @return {boolean}
-     */
     hasTextContent: function()
     {
         if (this._type.isTextType())
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/TracingModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/TracingModel.js
index 725e0e4..a5e281d 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/TracingModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/TracingModel.js
@@ -117,6 +117,35 @@
 }
 
 /**
+ * @param {!WebInspector.TracingModel} tracingModel
+ * @return {?WebInspector.TracingModel.Thread}
+ *
+ * TODO: Move this to a better place. This is here just for convenience o
+ * re-use between modules. This really belongs to a higher level, since it
+ * is specific to chrome's usage of tracing.
+ */
+WebInspector.TracingModel.browserMainThread = function(tracingModel)
+{
+    var processes = tracingModel.sortedProcesses();
+    var browserProcesses = [];
+    var crRendererMainThreads = [];
+    for (var process of processes) {
+        if (process.name().toLowerCase().endsWith("browser"))
+            browserProcesses.push(process);
+        crRendererMainThreads.push(...process.sortedThreads().filter(t => t.name() === "CrBrowserMain"));
+    }
+    if (crRendererMainThreads.length === 1)
+        return crRendererMainThreads[0];
+    if (browserProcesses.length === 1)
+        return browserProcesses[0].threadByName("CrBrowserMain");
+    var tracingStartedInBrowser = tracingModel.devToolsMetadataEvents().filter(e => e.name === "TracingStartedInBrowser");
+    if (tracingStartedInBrowser.length === 1)
+        return tracingStartedInBrowser[0].thread;
+    WebInspector.console.error("Failed to find browser main thread in trace, some timeline features may be unavailable");
+    return null;
+}
+
+/**
  * @interface
  */
 WebInspector.BackingStorage = function()
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/CallStackSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/sources/CallStackSidebarPane.js
index 50f07d4a..3b6b525f 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/CallStackSidebarPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/CallStackSidebarPane.js
@@ -281,6 +281,11 @@
      */
     appendBlackboxURLContextMenuItems: function(contextMenu, uiSourceCode)
     {
+        var binding = WebInspector.persistence.binding(uiSourceCode);
+        if (binding)
+            uiSourceCode = binding.network;
+        if (uiSourceCode.project().type() === WebInspector.projectTypes.FileSystem)
+            return;
         var canBlackbox = WebInspector.blackboxManager.canBlackboxUISourceCode(uiSourceCode);
         var isBlackboxed = WebInspector.blackboxManager.isBlackboxedUISourceCode(uiSourceCode);
         var isContentScript = uiSourceCode.project().type() === WebInspector.projectTypes.ContentScripts;
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
index 58aa5414..5766476 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
@@ -114,7 +114,7 @@
         infobar.createDetailsRowMessage(WebInspector.UIString("The content of this file on the file system:\u00a0")).appendChild(
             WebInspector.linkifyURLAsNode(fileURL, fileURL, "source-frame-infobar-details-url", true));
 
-        var scriptURL = WebInspector.networkMapping.networkURL(this.uiSourceCode());
+        var scriptURL = this.uiSourceCode().url();
         infobar.createDetailsRowMessage(WebInspector.UIString("does not match the loaded script:\u00a0")).appendChild(
             WebInspector.linkifyURLAsNode(scriptURL, scriptURL, "source-frame-infobar-details-url", true));
 
@@ -146,8 +146,6 @@
         var projectType = uiSourceCode.project().type();
         if (projectType === WebInspector.projectTypes.Snippets)
             return;
-        var networkURL = WebInspector.networkMapping.networkURL(uiSourceCode);
-        var url = projectType === WebInspector.projectTypes.Formatter ? uiSourceCode.url() : networkURL;
         if (!WebInspector.blackboxManager.isBlackboxedUISourceCode(uiSourceCode)) {
             this._hideBlackboxInfobar();
             return;
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js b/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
index a7debf6..4874ed8 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
@@ -60,9 +60,10 @@
     this._initGrouping();
     WebInspector.targetManager.addModelListener(WebInspector.ResourceTreeModel, WebInspector.ResourceTreeModel.Events.FrameNavigated, this._frameNavigated, this);
     WebInspector.targetManager.addModelListener(WebInspector.ResourceTreeModel, WebInspector.ResourceTreeModel.Events.FrameDetached, this._frameDetached, this);
+    WebInspector.persistence.addEventListener(WebInspector.Persistence.Events.BindingCreated, this._onBindingChanged, this);
+    WebInspector.persistence.addEventListener(WebInspector.Persistence.Events.BindingRemoved, this._onBindingChanged, this);
+
     WebInspector.targetManager.observeTargets(this);
-    WebInspector.persistence.addEventListener(WebInspector.Persistence.Events.BindingCreated, this._onBindingCreated, this);
-    WebInspector.persistence.addEventListener(WebInspector.Persistence.Events.BindingRemoved, this._onBindingRemoved, this);
     this._resetWorkspace(WebInspector.workspace);
 }
 
@@ -156,20 +157,34 @@
     /**
      * @param {!WebInspector.Event} event
      */
-    _onBindingCreated: function(event)
+    _onBindingChanged: function(event)
     {
         var binding = /** @type {!WebInspector.PersistenceBinding} */(event.data);
-        // TODO(lushnikov): show network UISourceCodes in navigator.
-        this._removeUISourceCode(binding.network);
-    },
 
-    /**
-     * @param {!WebInspector.Event} event
-     */
-    _onBindingRemoved: function(event)
-    {
-        var binding = /** @type {!WebInspector.PersistenceBinding} */(event.data);
-        this._addUISourceCode(binding.network);
+        // Update UISourceCode titles.
+        var networkNode = this._uiSourceCodeNodes.get(binding.network);
+        if (networkNode)
+            networkNode.updateTitle();
+        var fileSystemNode = this._uiSourceCodeNodes.get(binding.fileSystem);
+        if (fileSystemNode)
+            fileSystemNode.updateTitle();
+
+        // Update folder titles.
+        var pathTokens = WebInspector.FileSystemWorkspaceBinding.relativePath(binding.fileSystem);
+        var folderPath = "";
+        for (var i = 0; i < pathTokens.length - 1; ++i) {
+            folderPath += pathTokens[i];
+            var folderId = this._folderNodeId(binding.fileSystem.project(), null, null, binding.fileSystem.origin(), folderPath);
+            var folderNode = this._subfolderNodes.get(folderId);
+            if (folderNode)
+                folderNode.updateTitle();
+            folderPath += "/";
+        }
+
+        // Update fileSystem root title.
+        var fileSystemRoot = this._rootNode.child(binding.fileSystem.project().id());
+        if (fileSystemRoot)
+            fileSystemRoot.updateTitle();
     },
 
     /**
@@ -231,10 +246,6 @@
         if (!this.accept(uiSourceCode))
             return;
 
-        var binding = WebInspector.persistence.binding(uiSourceCode);
-        if (binding && binding.network === uiSourceCode)
-            return;
-
         var isFromSourceMap = uiSourceCode.contentType().isFromSourceMap();
         var path;
         if (uiSourceCode.project().type() === WebInspector.projectTypes.FileSystem)
@@ -831,9 +842,7 @@
         return 1;
     if (typeWeight1 < typeWeight2)
         return -1;
-    var title1 = /** @type {string} */(treeElement1.title);
-    var title2 = /** @type {string} */(treeElement2.title);
-    return title1.compareTo(title2);
+    return treeElement1.titleAsText().compareTo(treeElement2.titleAsText());
 }
 
 /**
@@ -1251,6 +1260,7 @@
     this._navigatorView = navigatorView;
     this._uiSourceCode = uiSourceCode;
     this._treeElement = null;
+    this._eventListeners = [];
 }
 
 WebInspector.NavigatorUISourceCodeTreeNode.prototype = {
@@ -1274,10 +1284,12 @@
         this._treeElement = new WebInspector.NavigatorSourceTreeElement(this._navigatorView, this._uiSourceCode, "");
         this.updateTitle();
 
-        this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.TitleChanged, this._titleChanged, this);
-        this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.WorkingCopyChanged, this._workingCopyChanged, this);
-        this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.WorkingCopyCommitted, this._workingCopyCommitted, this);
-
+        var updateTitleBound = this.updateTitle.bind(this, undefined);
+        this._eventListeners = [
+            this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.TitleChanged, updateTitleBound),
+            this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.WorkingCopyChanged, updateTitleBound),
+            this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.WorkingCopyCommitted, updateTitleBound)
+        ];
         return this._treeElement;
     },
 
@@ -1292,7 +1304,24 @@
         var titleText = this._uiSourceCode.displayName();
         if (!ignoreIsDirty && (this._uiSourceCode.isDirty() || WebInspector.persistence.hasUnsavedCommittedChanges(this._uiSourceCode)))
             titleText = "*" + titleText;
-        this._treeElement.title = titleText;
+
+        var binding = WebInspector.persistence.binding(this._uiSourceCode);
+        if (binding) {
+            var titleElement = createElement("span");
+            titleElement.textContent = titleText;
+            var status = titleElement.createChild("span");
+            status.classList.add("mapped-file-bubble");
+            status.textContent = "\u25C9";
+            if (this._uiSourceCode === binding.network)
+                status.title = WebInspector.UIString("Persisted to file system: %s", binding.fileSystem.url().trimMiddle(150));
+            else if (binding.network.contentType().isFromSourceMap())
+                status.title = WebInspector.UIString("Linked to source map: %s", binding.network.url().trimMiddle(150));
+            else
+                status.title = WebInspector.UIString("Linked to %s", binding.network.url().trimMiddle(150));
+            this._treeElement.title = titleElement;
+        } else {
+            this._treeElement.title = titleText;
+        }
 
         var tooltip = this._uiSourceCode.url();
         if (this._uiSourceCode.contentType().isFromSourceMap())
@@ -1309,28 +1338,12 @@
         return false;
     },
 
+    /**
+     * @override
+     */
     dispose: function()
     {
-        if (!this._treeElement)
-            return;
-        this._uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.TitleChanged, this._titleChanged, this);
-        this._uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.WorkingCopyChanged, this._workingCopyChanged, this);
-        this._uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.WorkingCopyCommitted, this._workingCopyCommitted, this);
-    },
-
-    _titleChanged: function(event)
-    {
-        this.updateTitle();
-    },
-
-    _workingCopyChanged: function(event)
-    {
-        this.updateTitle();
-    },
-
-    _workingCopyCommitted: function(event)
-    {
-        this.updateTitle();
+        WebInspector.EventTarget.removeEventListeners(this._eventListeners);
     },
 
     /**
@@ -1437,9 +1450,18 @@
         if (this._treeElement)
             return this._treeElement;
         this._treeElement = this._createTreeElement(this._title, this);
+        this.updateTitle();
         return this._treeElement;
     },
 
+    updateTitle: function()
+    {
+        if (!this._treeElement || this._project.type() !== WebInspector.projectTypes.FileSystem)
+            return;
+        var absoluteFileSystemPath = WebInspector.FileSystemWorkspaceBinding.fileSystemPath(this._project.id()) + "/" + this._folderPath;
+        this._treeElement.listItemElement.classList.toggle("has-mapped-files", WebInspector.persistence.filePathHasBindings(absoluteFileSystemPath));
+    },
+
     /**
      * @return {!TreeElement}
      */
@@ -1602,5 +1624,29 @@
         return this._treeElement;
     },
 
+    /**
+     * @override
+     */
+    onattach: function()
+    {
+        this.updateTitle();
+    },
+
+    updateTitle: function()
+    {
+        if (!this._treeElement || this._project.type() !== WebInspector.projectTypes.FileSystem)
+            return;
+        var fileSystemPath = WebInspector.FileSystemWorkspaceBinding.fileSystemPath(this._project.id());
+        var wasActive = this._treeElement.listItemElement.classList.contains("has-mapped-files");
+        var isActive = WebInspector.persistence.filePathHasBindings(fileSystemPath);
+        if (wasActive === isActive)
+            return;
+        this._treeElement.listItemElement.classList.toggle("has-mapped-files", isActive);
+        if (isActive)
+            this._treeElement.expand();
+        else
+            this._treeElement.collapse();
+    },
+
     __proto__: WebInspector.NavigatorTreeNode.prototype
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/ScriptFormatterEditorAction.js b/third_party/WebKit/Source/devtools/front_end/sources/ScriptFormatterEditorAction.js
index c707a6a..12f3aba 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/ScriptFormatterEditorAction.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/ScriptFormatterEditorAction.js
@@ -159,8 +159,7 @@
         this._updateButton(uiSourceCode);
 
         var path = uiSourceCode.project().id() + ":" + uiSourceCode.url();
-        var networkURL = WebInspector.networkMapping.networkURL(uiSourceCode);
-        if (this._isFormatableScript(uiSourceCode) && networkURL && this._pathsToFormatOnLoad.has(path) && !this._formattedPaths.get(path))
+        if (this._isFormatableScript(uiSourceCode) && this._pathsToFormatOnLoad.has(path) && !this._formattedPaths.get(path))
             this._formatUISourceCodeScript(uiSourceCode);
     },
 
@@ -323,10 +322,8 @@
         if (uiSourceCode.contentType() === WebInspector.resourceTypes.Document) {
             var scripts = [];
             var debuggerModels = WebInspector.DebuggerModel.instances();
-            for (var i = 0; i < debuggerModels.length; ++i) {
-                var networkURL = WebInspector.networkMapping.networkURL(uiSourceCode);
-                scripts.pushAll(debuggerModels[i].scriptsForSourceURL(networkURL));
-            }
+            for (var i = 0; i < debuggerModels.length; ++i)
+                scripts.pushAll(debuggerModels[i].scriptsForSourceURL(uiSourceCode.url()));
             return scripts.filter(isInlineScript);
         }
         if (uiSourceCode.contentType().isScript()) {
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/SourcesNavigator.js b/third_party/WebKit/Source/devtools/front_end/sources/SourcesNavigator.js
index 028527c..73f94fa7a 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/SourcesNavigator.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/SourcesNavigator.js
@@ -62,7 +62,7 @@
             return
         for (var node of this._uiSourceCodeNodes.valuesArray()) {
             var uiSourceCode = node.uiSourceCode();
-            if (WebInspector.networkMapping.networkURL(uiSourceCode) === inspectedURL)
+            if (uiSourceCode.url() === inspectedURL)
                 this.revealUISourceCode(uiSourceCode, true);
         }
     },
@@ -74,7 +74,7 @@
     uiSourceCodeAdded: function(uiSourceCode)
     {
         var inspectedPageURL = WebInspector.targetManager.mainTarget().inspectedURL();
-        if (inspectedPageURL && WebInspector.networkMapping.networkURL(uiSourceCode) === inspectedPageURL)
+        if (uiSourceCode.url() === inspectedPageURL)
             this.revealUISourceCode(uiSourceCode, true);
     },
 
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js b/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js
index c02ea12..b30b809 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js
@@ -78,7 +78,10 @@
     this._sourcesView.addEventListener(WebInspector.SourcesView.Events.EditorSelected, this._editorSelected.bind(this));
     this._sourcesView.addEventListener(WebInspector.SourcesView.Events.EditorClosed, this._editorClosed.bind(this));
     this._sourcesView.registerShortcuts(this.registerShortcuts.bind(this));
-    this.editorView.setMainWidget(this._sourcesView);
+
+    this._toggleNavigatorSidebarButton = this.editorView.createShowHideSidebarButton("navigator");
+    this._toggleDebuggerSidebarButton = this._splitWidget.createShowHideSidebarButton("debugger");
+    this._showSourcesViewInPanel();
     this._editorChanged(this._sourcesView.currentUISourceCode());
 
     this._threadsSidebarPane = null;
@@ -88,10 +91,6 @@
     this._callstackPane = self.runtime.sharedInstance(WebInspector.CallStackSidebarPane);
     this._callstackPane.registerShortcuts(this.registerShortcuts.bind(this));
 
-    this._sourcesView.leftToolbar().appendToolbarItem(this.editorView.createShowHideSidebarButton("navigator"));
-    this._toggleDebuggerSidebarButton = this._splitWidget.createShowHideSidebarButton("debugger");
-    this._sourcesView.rightToolbar().appendToolbarItem(this._toggleDebuggerSidebarButton);
-
     WebInspector.moduleSetting("sidebarPosition").addChangeListener(this._updateSidebarPosition.bind(this));
     this._updateSidebarPosition();
 
@@ -188,7 +187,7 @@
             WebInspector.inspectorView.setDrawerMinimized(true);
             WebInspector.SourcesPanel.updateResizer(this);
         }
-        this.editorView.setMainWidget(this._sourcesView);
+        this._showSourcesViewInPanel();
     },
 
     willHide: function()
@@ -202,6 +201,15 @@
         }
     },
 
+    _showSourcesViewInPanel: function()
+    {
+        this._sourcesView.leftToolbar().removeToolbarItems();
+        this._sourcesView.leftToolbar().appendToolbarItem(this._toggleNavigatorSidebarButton);
+        this._sourcesView.rightToolbar().removeToolbarItems();
+        this._sourcesView.rightToolbar().appendToolbarItem(this._toggleDebuggerSidebarButton);
+        this.editorView.setMainWidget(this._sourcesView);
+    },
+
     /**
      * @override
      * @param {string} locationName
@@ -791,11 +799,11 @@
     {
         WebInspector.NavigatorView.appendAddFolderItem(contextMenu);
         if (uiSourceCode.project().type() === WebInspector.projectTypes.FileSystem) {
-            var hasMappings = !!this._networkMapping.networkURL(uiSourceCode);
-            if (!hasMappings)
+            var binding = WebInspector.persistence.binding(uiSourceCode);
+            if (!binding)
                 contextMenu.appendItem(WebInspector.UIString.capitalize("Map to ^network ^resource\u2026"), this.mapFileSystemToNetwork.bind(this, uiSourceCode));
             else
-                contextMenu.appendItem(WebInspector.UIString.capitalize("Remove ^network ^mapping"), this._removeNetworkMapping.bind(this, uiSourceCode));
+                contextMenu.appendItem(WebInspector.UIString.capitalize("Remove ^network ^mapping"), this._removeNetworkMapping.bind(this, binding.network));
         }
 
         /**
@@ -809,8 +817,7 @@
         if (uiSourceCode.project().type() === WebInspector.projectTypes.Network || uiSourceCode.project().type() === WebInspector.projectTypes.ContentScripts) {
             if (!this._workspace.projects().filter(filterProject).length)
                 return;
-            var networkURL = this._networkMapping.networkURL(uiSourceCode);
-            if (this._networkMapping.uiSourceCodeForURLForAnyTarget(networkURL) === uiSourceCode)
+            if (this._networkMapping.uiSourceCodeForURLForAnyTarget(uiSourceCode.url()) === uiSourceCode)
                 contextMenu.appendItem(WebInspector.UIString.capitalize("Map to ^file ^system ^resource\u2026"), this.mapNetworkToFileSystem.bind(this, uiSourceCode));
         }
     },
@@ -1355,6 +1362,8 @@
 
     _showViewInWrapper: function()
     {
+        this._view.leftToolbar().removeToolbarItems();
+        this._view.rightToolbar().removeToolbarItems();
         this._view.show(this.element);
     },
 
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/SourcesSearchScope.js b/third_party/WebKit/Source/devtools/front_end/sources/SourcesSearchScope.js
index 6b1f77ff..85fb0a2 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/SourcesSearchScope.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/SourcesSearchScope.js
@@ -47,11 +47,11 @@
         return -1;
     if (!uiSourceCode1.isDirty() && uiSourceCode2.isDirty())
         return 1;
-    var networkURL1 = WebInspector.networkMapping.networkURL(uiSourceCode1);
-    var networkURL2 = WebInspector.networkMapping.networkURL(uiSourceCode2);
-    if (networkURL1 && !networkURL2)
+    var url1 = uiSourceCode1.url();
+    var url2 = uiSourceCode2.url();
+    if (url1 && !url2)
         return -1;
-    if (!networkURL1 && networkURL2)
+    if (!url1 && url2)
         return 1;
     return String.naturalOrderComparator(uiSourceCode1.fullDisplayName(), uiSourceCode2.fullDisplayName());
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/SourcesView.js b/third_party/WebKit/Source/devtools/front_end/sources/SourcesView.js
index e43f9510..b857a25 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/SourcesView.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/SourcesView.js
@@ -267,16 +267,6 @@
         if (uiSourceCode.isFromServiceProject())
             return;
         this._editorContainer.addUISourceCode(uiSourceCode);
-        // Replace debugger script-based uiSourceCode with a network-based one.
-        var currentUISourceCode = this._editorContainer.currentFile();
-        if (!currentUISourceCode)
-            return;
-        var networkURL = WebInspector.networkMapping.networkURL(uiSourceCode);
-        var currentNetworkURL = WebInspector.networkMapping.networkURL(currentUISourceCode);
-        if (currentUISourceCode.isFromServiceProject() && currentUISourceCode !== uiSourceCode && currentNetworkURL === networkURL && networkURL) {
-            this._editorContainer.showFile(uiSourceCode);
-            this._editorContainer.removeUISourceCode(currentUISourceCode);
-        }
     },
 
     _uiSourceCodeRemoved: function(event)
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/navigatorView.css b/third_party/WebKit/Source/devtools/front_end/sources/navigatorView.css
index 6072412..0f08792d 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/navigatorView.css
+++ b/third_party/WebKit/Source/devtools/front_end/sources/navigatorView.css
@@ -46,6 +46,17 @@
     background: linear-gradient(45deg, hsl(0, 0%, 50%), hsl(0, 0%, 70%));
 }
 
+.navigator-fs-tree-item:not(.has-mapped-files),
+.navigator-fs-folder-tree-item:not(.has-mapped-files) {
+    filter: grayscale(50%);
+    opacity: 0.5;
+}
+
+.mapped-file-bubble {
+    color: green;
+    margin-left: 2px;
+}
+
 :focus .navigator-file-tree-item.selected .icon {
     background: white !important;
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/terminal/TerminalWidget.js b/third_party/WebKit/Source/devtools/front_end/terminal/TerminalWidget.js
new file mode 100644
index 0000000..065f02c
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/terminal/TerminalWidget.js
@@ -0,0 +1,139 @@
+// 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.
+
+/**
+ * @constructor
+ * @extends {WebInspector.VBox}
+ */
+WebInspector.TerminalWidget = function()
+{
+    WebInspector.VBox.call(this, false);
+    this.registerRequiredCSS("terminal/xterm.js/build/xterm.css");
+    this.registerRequiredCSS("terminal/terminal.css");
+    this.element.classList.add("terminal-root");
+    this.element.addEventListener("mousemove", this._mouseMove.bind(this), false);
+    this._init();
+    this._linkifier = new WebInspector.Linkifier();
+    this._linkifyFunction = this._linkifyURL.bind(this);
+}
+
+WebInspector.TerminalWidget.prototype = {
+    _init: function()
+    {
+        WebInspector.serviceManager.createService("Terminal").then(this._initialized.bind(this));
+    },
+
+    /**
+     * @param {?WebInspector.ServiceManager.Service} backend
+     */
+    _initialized: function(backend)
+    {
+        if (!backend) {
+            if (!this._unavailableLabel) {
+                this._unavailableLabel = this.element.createChild("div", "terminal-error-message fill");
+                this._unavailableLabel.createChild("div").textContent = WebInspector.UIString("Terminal service is not available");
+            }
+            if (this.isShowing())
+                setTimeout(this._init.bind(this), 2000);
+            return;
+        }
+
+        if (this._unavailableLabel) {
+            this._unavailableLabel.remove();
+            delete this._unavailableLabel;
+        }
+
+        this._backend = backend;
+
+        if (!this._term) {
+            this._term = new Terminal({ cursorBlink: true });
+            this._term.open(this.contentElement);
+            this._term.on("data", data => {
+                this._backend.send("write", { data: data });
+            });
+            this._term.fit();
+            this._term.on("resize", size => {
+                this._backend.send("resize", { cols: size.cols, rows: size.rows });
+            });
+        }
+
+        this._backend.send("init", { cols: this._term.cols, rows: this._term.rows });
+        this._backend.on("data", result => {
+            this._term.write(result.data);
+            this._linkifyUpToDate = false;
+        });
+        this._backend.on("disposed", this._disposed.bind(this));
+    },
+
+    _mouseMove: function()
+    {
+        if (this._linkifyUpToDate)
+            return;
+        if (this._term)
+            this._linkify();
+        this._linkifyUpToDate = true;
+    },
+
+    onResize: function()
+    {
+        if (this._term)
+            this._term.fit();
+    },
+
+    _disposed: function()
+    {
+        this._initialized(null);
+    },
+
+    /**
+     * @override
+     */
+    wasDetachedFromHierarchy: function()
+    {
+        if (this._backend)
+            this._backend.dispose();
+    },
+
+    _linkify: function()
+    {
+        if (!this._term)
+            return;
+        this._linkifier.reset();
+        var rows = this._term.rowContainer.children;
+        for (var i = 0; i < rows.length; i++)
+            this._linkifyTerminalLine(rows[i]);
+    },
+
+    /**
+     * @param {!Node} line
+     */
+    _linkifyTerminalLine: function(line)
+    {
+        var node = line.firstChild;
+        while (node) {
+            if (node.nodeType !== Node.TEXT_NODE) {
+                node = node.nextSibling;
+                continue;
+            }
+            var nextNode = node.nextSibling;
+            node.remove();
+            var linkified = WebInspector.linkifyStringAsFragmentWithCustomLinkifier(node.textContent, this._linkifyFunction);
+            line.insertBefore(linkified, nextNode);
+            node = nextNode;
+        }
+    },
+
+    /**
+     * @param {string} title
+     * @param {string} url
+     * @param {number=} lineNumber
+     * @param {number=} columnNumber
+     */
+    _linkifyURL: function(title, url, lineNumber, columnNumber)
+    {
+        return this._linkifier.linkifyScriptLocation(null, null, url, lineNumber || 0, columnNumber || 0);
+    },
+
+    __proto__: WebInspector.VBox.prototype
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/terminal/module.json b/third_party/WebKit/Source/devtools/front_end/terminal/module.json
new file mode 100644
index 0000000..1c4dfc6
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/terminal/module.json
@@ -0,0 +1,32 @@
+{
+    "extensions": [
+        {
+            "type": "view",
+            "location": "drawer-view",
+            "id": "drawer.xterm",
+            "title": "Terminal",
+            "order": 10,
+            "persistence": "closeable",
+            "factoryName": "WebInspector.TerminalWidget"
+        }
+    ],
+    "dependencies": [
+        "components",
+        "ui",
+        "services"
+    ],
+    "experiment": "terminalInDrawer",
+    "scripts": [
+        "xterm.js/build/xterm.js",
+        "xterm.js/addons/fit/fit.js",
+        "TerminalWidget.js"
+    ],
+    "skip_compilation": [
+        "xterm.js/build/xterm.js",
+        "xterm.js/addons/fit/fit.js"
+    ],
+    "resources": [
+        "terminal.css",
+        "xterm.js/build/xterm.css"
+    ]
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/terminal/terminal.css b/third_party/WebKit/Source/devtools/front_end/terminal/terminal.css
new file mode 100644
index 0000000..3abe086
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/terminal/terminal.css
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+.terminal-root {
+    background-color: #111;
+    color: #fafafa;
+    padding: 2px;
+    -webkit-user-select: text;
+    white-space: nowrap;
+}
+
+.terminal:focus .terminal-cursor {
+    background-color: #fafafa;
+}
+
+.terminal-error-message {
+    display: flex;
+    align-items: center;
+    padding: 10px;
+    background-color: rgba(255, 255, 255, 0.8);
+    justify-content: center;
+    font-size: 16px;
+    color: #222;
+}
+
+.terminal-error-message div {
+    padding-right: 10px;
+}
+
+a.webkit-html-resource-link {
+    color: inherit;
+    text-decoration: inherit;
+}
+
+a.webkit-html-resource-link:hover {
+    text-decoration: underline;
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/AUTHORS b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/AUTHORS
new file mode 100644
index 0000000..0f1d6c31
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/AUTHORS
@@ -0,0 +1,23 @@
+List of xterm.js contributors. Updated before every release.
+
+Alessandro Nadalin <alessandro.nadalin@gmail.com>
+Alexander Olsson <noseglid@gmail.com>
+Antonis Kalipetis <akalipetis@sourcelair.com>
+Anton Skshidlevsky <meefik@gmail.com>
+Austin Robertson <austinrobertson@gmail.com>
+ayapi <colors.aya@gmail.com>
+Benjamin Fischer <benjamin.fischer@rwth-aachen.de>
+Carson Anderson <carson@betterservers.com>
+Christopher Jeffrey <chjjeffrey@gmail.com>
+Daniel Imms <daimms@microsoft.com>
+Daniel Risacher <drisacher@gmail.com>
+Dan Kaplun <dbkaplun@twitch.tv>
+Darin Morrison <freebroccolo@users.noreply.github.com>
+Jean Bruenn <himself@jeanbruenn.info>
+Jörg Breitbart <jerch@rockborn.de>
+Paris Kasidiaris <pariskasidiaris@gmail.com>
+Paris Kasidiaris <paris@sourcelair.com>
+runarberg <runar@greenqloud.com>
+Steven Silvester <steven.silvester@ieee.org>
+Thanasis Daglis <thanasis@sourcelair.com>
+Tine Jozelj <tine.jozelj@outlook.com>
diff --git a/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/CONTRIBUTING.md b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/CONTRIBUTING.md
new file mode 100644
index 0000000..8b33d18
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/CONTRIBUTING.md
@@ -0,0 +1,52 @@
+# How to contribute to xterm.js
+
+- [Opening issues for bug reports or feature requests](#opening-issues)
+- [Contributing code](#contributing-code)
+
+## Opening issues
+
+The preferred way to report bugs or request features is to use
+[GitHub issues](http://github.com/sourcelair/xterm.js/issues). Before
+opening an issue, read these pointers.
+
+### Opening issues effectively
+
+- Include information about **the browser in which the problem occurred**. Even
+  if you tested several browsers, and the problem occurred in all of them,
+  mention this fact in the bug report. Also include browser version numbers and
+  the operating system that you're on.
+
+- Mention which release of xterm.js you're using. Preferably, try also with
+  the current HEAD of the master branch, to ensure the problem has not already been
+  fixed.
+
+- Mention precisely what went wrong. What did you expect to happen? What happened instead? Describe the
+  exact steps a maintainer has to take to make the problem occur.
+
+- If the problem can not be reproduced in the [demo of xterm.js](README.md#demo), please provide an HTML document that demonstrates the problem.
+
+- Be polite. Issues with an indignant or belligerent tone tend to be moved to the
+  bottom of the pile.
+
+## Contributing code
+
+- Make sure you have a [GitHub account](https://github.com/join)
+- Fork [xterm.js](https://github.com/sourcelair/xterm.js/)
+  ([how to fork a repo](https://help.github.com/articles/fork-a-repo))
+- Make your changes
+- If your changes are easy to test or likely to regress, add tests. Tests go into `test`, directory.
+- Follow the general code style of the rest of the project (see below).
+- Submit a pull request
+([how to create a pull request](https://help.github.com/articles/fork-a-repo)).
+  Don't put more than one feature/fix in a single pull request.
+
+By contributing code to xterm.js you
+
+ - agree to license the contributed code under xterm.js' [MIT
+   license](LICENSE).
+
+ - confirm that you have the right to contribute and license the code
+   in question. (Either you hold all rights on the code, or the rights
+   holder has explicitly granted the right to use it like this,
+   through a compatible open source license or through a direct
+   agreement with you.)
diff --git a/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/Dockerfile b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/Dockerfile
new file mode 100644
index 0000000..105e997
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/Dockerfile
@@ -0,0 +1,4 @@
+FROM node:4-onbuild
+MAINTAINER Paris Kasidiaris <paris@sourcelair.com>
+
+EXPOSE 3000
diff --git a/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/LICENSE b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/LICENSE
new file mode 100644
index 0000000..1ed6f2a5
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2014, sourceLair Limited (https://github.com/sourcelair/)
+Copyright (c) 2012-2013, Christopher Jeffrey (https://github.com/chjj/)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/Procfile.dev b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/Procfile.dev
new file mode 100644
index 0000000..063b78f4
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/Procfile.dev
@@ -0,0 +1 @@
+web: npm start
diff --git a/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/README.chromium b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/README.chromium
new file mode 100644
index 0000000..662bc38
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/README.chromium
@@ -0,0 +1,7 @@
+Name: Xterm.js is a terminal front-end component written in JavaScript that works in the browser.
+Short Name: xterm.js
+URL: https://github.com/sourcelair/xterm.js
+License: MIT
+Security Critical: no
+
+This directory contains Chrome's version of xterm.js with tests, demo and some addons folders removed.
diff --git a/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/README.md b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/README.md
new file mode 100644
index 0000000..e45dd1d
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/README.md
@@ -0,0 +1,101 @@
+# xterm.js
+
+![xterm.js build status](https://api.travis-ci.org/sourcelair/xterm.js.svg) [![Gitter](https://badges.gitter.im/sourcelair/xterm.js.svg)](https://gitter.im/sourcelair/xterm.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
+
+Xterm.js is a terminal front-end component written in JavaScript that works in the browser.
+
+It enables applications to provide fully featured terminals to their users and create great development experiences.
+
+## Features
+- **Text-based application support**: Use xterm.js to work with applications like `bash`, `git` etc.
+- **Curses-based application support**: Use xterm.js to work with applications like `vim`, `tmux` etc.
+- **Mouse events support**: Xterm.js captures mouse events like click and scroll and passes them to the terminal's back-end controlling process
+- **CJK (Chinese, Japanese, Korean) character support**: Xterm.js renders CJK characters seamlessly
+- **IME support**: Insert international (including CJK) characters using IME input with your keyboard
+- **Self-contained library**: Xterm.js works on its own. It does not require any external libraries like jQuery or React to work
+- **Modular, event-based API**: Lets you build addons and themes with ease
+
+## What xterm.js is not
+- Xterm.js is not a terminal application that you can download and use on your computer
+- Xterm.js is not `bash`. Xterm.js can be connected to processes like `bash` and let you interact with them (provide input, receive output)
+
+## Real-world uses
+Xterm.js is used in several world-class applications to provide great terminal experiences.
+
+- [**SourceLair**](https://www.sourcelair.com/): In-browser IDE that provides its users with fully-featured Linux terminals based on xterm.js
+- [**Microsoft Visual Studio Code**](http://code.visualstudio.com/): Modern, versatile and powerful open source code editor that provides an integrated terminal based on xterm.js
+
+Do you use xterm.js in your application as well? Please [open a Pull Request](https://github.com/sourcelair/xterm.js/pulls) to include it here. We would love to have it in our list.
+
+## Browser Support
+
+Since xterm.js is typically implemented as a developer tool, only modern browsers are supported officially. Here is a list of the versions we aim to support:
+
+- Chrome 48+
+- Edge 13+
+- Firefox 44+
+- Internet Explorer 11+
+- Opera 35+
+- Safari 8+
+
+Xterm.js works seamlessly in Electron apps and may even work on earlier versions of the browsers but these are the browsers we strive to keep working.
+
+## Demo
+
+To launch the demo simply run:
+
+```
+npm install
+npm start
+```
+
+Then open http://0.0.0.0:3000 in a web browser (use http://127.0.0.1:3000 if running under Windows).
+
+## Addons
+
+Addons are JavaScript modules that attach functions to the `Terminal` prototype to extend its functionality. There are a handful available in the main repository in the `addons` directory, you can even write your own (though they may break when the internals of xterm.js change across versions).
+
+To use an addon, just include the JavaScript file after xterm.js and before the `Terminal` object has been instantiated. The function should then be exposed on the `Terminal` object:
+
+```html
+<script src="node_modules/dist/xterm.js"></script>
+<script src="node_modules/addons/fit/fit.js"></script>
+```
+
+```js
+var xterm = new Terminal();
+// init code...
+xterm.fit();
+```
+
+## Releases
+
+Xterm.js follows a monthly release cycle roughly.
+
+The existing releases are available at this GitHub repo's [Releases](https://github.com/sourcelair/xterm.js/releases), while the roadmap is available as [Milestones](https://github.com/sourcelair/xterm.js/milestones).
+
+## Development and Contribution
+
+Xterm.js is maintained by [SourceLair](https://www.sourcelair.com/) and a few external contributors, but we would love to receive contributions from everyone!
+
+To contribute either code, documentation or issues to xterm.js please read the [Contributing document](CONTRIBUTING.md) before.
+
+The development of xterm.js does not require any special tool. All you need is an editor that supports JavaScript and a browser (if you would like to run the demo you will need Node.js to get all features).
+
+It is recommended though to use a development tool that uses xterm.js internally, to develop for xterm.js. [Eating our own dogfood](https://en.wikipedia.org/wiki/Eating_your_own_dog_food) has been proved extremely beneficial for this project. Known tools that use xterm.js internally are:
+
+#### [SourceLair](https://www.sourcelair.com)
+
+Visit https://lair.io/sourcelair/xterm and follow the instructions. All development will happen in your browser.
+
+#### [Visual Studio Code](http://code.visualstudio.com/)
+
+[Download Visual Studio Code](http://code.visualstudio.com/Download), clone xterm.js and you are all set.
+
+## License Agreement
+
+If you contribute code to this project, you are implicitly allowing your code to be distributed under the MIT license. You are also implicitly verifying that all code is your original work.
+
+Copyright (c) 2014-2016, SourceLair, Private Company ([www.sourcelair.com](https://www.sourcelair.com/home)) (MIT License)
+
+Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
diff --git a/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/addons/fit/fit.js b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/addons/fit/fit.js
new file mode 100644
index 0000000..209e059
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/addons/fit/fit.js
@@ -0,0 +1,86 @@
+/*
+ *  Fit terminal columns and rows to the dimensions of its
+ *  DOM element.
+ *
+ *  Approach:
+ *    - Rows: Truncate the division of the terminal parent element height
+ *            by the terminal row height
+ *
+ *    - Columns: Truncate the division of the terminal parent element width by
+ *               the terminal character width (apply display: inline at the
+ *               terminal row and truncate its width with the current number
+ *               of columns)
+ */
+(function (fit) {
+  if (typeof exports === 'object' && typeof module === 'object') {
+    /*
+     * CommonJS environment
+     */
+    module.exports = fit(require('../../src/xterm'));
+  } else if (typeof define == 'function') {
+    /*
+     * Require.js is available
+     */
+    define(['../../src/xterm'], fit);
+  } else {
+    /*
+     * Plain browser environment
+     */
+    fit(window.Terminal);
+  }
+})(function (Xterm) {
+  /**
+   * This module provides methods for fitting a terminal's size to a parent container.
+   *
+   * @module xterm/addons/fit/fit
+   */
+  var exports = {};
+
+  exports.proposeGeometry = function (term) {
+    var parentElementStyle = window.getComputedStyle(term.element.parentElement),
+        parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height')),
+        parentElementWidth = parseInt(parentElementStyle.getPropertyValue('width')),
+        elementStyle = window.getComputedStyle(term.element),
+        elementPaddingVer = parseInt(elementStyle.getPropertyValue('padding-top')) + parseInt(elementStyle.getPropertyValue('padding-bottom')),
+        elementPaddingHor = parseInt(elementStyle.getPropertyValue('padding-right')) + parseInt(elementStyle.getPropertyValue('padding-left')),
+        availableHeight = parentElementHeight - elementPaddingVer,
+        availableWidth = parentElementWidth - elementPaddingHor,
+        container = term.rowContainer,
+        subjectRow = term.rowContainer.firstElementChild,
+        contentBuffer = subjectRow.innerHTML,
+        characterHeight,
+        rows,
+        characterWidth,
+        cols,
+        geometry;
+
+    subjectRow.style.display = 'inline';
+    subjectRow.innerHTML = 'W'; // Common character for measuring width, although on monospace
+    characterWidth = subjectRow.getBoundingClientRect().width;
+    subjectRow.style.display = ''; // Revert style before calculating height, since they differ.
+    characterHeight = parseInt(subjectRow.offsetHeight);
+    subjectRow.innerHTML = contentBuffer;
+
+    rows = parseInt(availableHeight / characterHeight);
+    cols = parseInt(availableWidth / characterWidth) - 1;
+
+    geometry = {cols: cols, rows: rows};
+    return geometry;
+  };
+
+  exports.fit = function (term) {
+    var geometry = exports.proposeGeometry(term);
+
+    term.resize(geometry.cols, geometry.rows);
+  };
+
+  Xterm.prototype.proposeGeometry = function () {
+    return exports.proposeGeometry(this);
+  };
+
+  Xterm.prototype.fit = function () {
+    return exports.fit(this);
+  };
+
+  return exports;
+});
diff --git a/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/addons/fit/package.json b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/addons/fit/package.json
new file mode 100644
index 0000000..f7cb5bc
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/addons/fit/package.json
@@ -0,0 +1,5 @@
+{
+  "name": "xterm.fit",
+  "main": "fit.js",
+  "private": true
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/bower.json b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/bower.json
new file mode 100644
index 0000000..9572135
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/bower.json
@@ -0,0 +1,5 @@
+{
+  "name": "xterm.js",
+  "version": "1.1.3",
+  "ignore": ["demo", "test", ".gitignore"]
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/build/xterm.css b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/build/xterm.css
new file mode 100644
index 0000000..8295eb65
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/build/xterm.css
@@ -0,0 +1,2196 @@
+/**
+ * xterm.js: xterm, in the browser
+ * Copyright (c) 2014, sourceLair Limited (www.sourcelair.com (MIT License)
+ * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
+ * https://github.com/chjj/term.js
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * Originally forked from (with the author's permission):
+ *   Fabrice Bellard's javascript vt100 for jslinux:
+ *   http://bellard.org/jslinux/
+ *   Copyright (c) 2011 Fabrice Bellard
+ *   The original design remains. The terminal itself
+ *   has been extended to include xterm CSI codes, among
+ *   other features.
+ */
+
+/*
+ *  Default style for xterm.js
+ */
+
+.terminal {
+    background-color: #000;
+    color: #fff;
+    font-family: courier-new, courier, monospace;
+    font-feature-settings: "liga" 0;
+    position: relative;
+}
+
+.terminal.focus,
+.terminal:focus {
+    outline: none;
+}
+
+.terminal .xterm-helpers {
+    position: absolute;
+    top: 0;
+}
+
+.terminal .xterm-helper-textarea {
+    position: absolute;
+    /*
+     * HACK: to fix IE's blinking cursor
+     * Move textarea out of the screen to the far left, so that the cursor is not visible.
+     */
+    left: -9999em;
+    opacity: 0;
+    width: 0;
+    height: 0;
+    z-index: -10;
+}
+
+.terminal .terminal-cursor {
+    background-color: #fff;
+    color: #000;
+}
+
+.terminal:not(.focus) .terminal-cursor {
+    outline: 1px solid #fff;
+    outline-offset: -1px;
+    background-color: transparent;
+}
+
+.terminal.focus .terminal-cursor.blinking {
+    animation: blink-cursor 1.2s infinite step-end;
+}
+
+@keyframes blink-cursor {
+    0% {
+        background-color: #fff;
+        color: #000;
+    }
+    50% {
+        background-color: transparent;
+        color: #FFF;
+    }
+}
+
+.terminal .composition-view {
+    background: #000;
+    color: #FFF;
+    display: none;
+    position: absolute;
+    white-space: nowrap;
+    z-index: 1;
+}
+
+.terminal .composition-view.active {
+    display: block;
+}
+
+.terminal .xterm-viewport {
+    /* On OS X this is required in order for the scroll bar to appear fully opaque */
+    background-color: #000;
+    overflow-y: scroll;
+}
+
+.terminal .xterm-rows {
+    position: absolute;
+    left: 0;
+    top: 0;
+}
+
+.terminal .xterm-scroll-area {
+    visibility: hidden;
+}
+
+.terminal .xterm-char-measure-element {
+    display: inline-block;
+    visibility: hidden;
+    position: absolute;
+    left: -9999em;
+}
+
+/*
+ *  Determine default colors for xterm.js
+ */
+.terminal .xterm-bold {
+    font-weight: bold;
+}
+
+.terminal .xterm-underline {
+    text-decoration: underline;
+}
+
+.terminal .xterm-blink {
+    text-decoration: blink;
+}
+
+.terminal .xterm-hidden {
+    visibility: hidden;
+}
+
+.terminal .xterm-color-0 {
+    color: #2e3436;
+}
+
+.terminal .xterm-bg-color-0 {
+    background-color: #2e3436;
+}
+
+.terminal .xterm-color-1 {
+    color: #cc0000;
+}
+
+.terminal .xterm-bg-color-1 {
+    background-color: #cc0000;
+}
+
+.terminal .xterm-color-2 {
+    color: #4e9a06;
+}
+
+.terminal .xterm-bg-color-2 {
+    background-color: #4e9a06;
+}
+
+.terminal .xterm-color-3 {
+    color: #c4a000;
+}
+
+.terminal .xterm-bg-color-3 {
+    background-color: #c4a000;
+}
+
+.terminal .xterm-color-4 {
+    color: #3465a4;
+}
+
+.terminal .xterm-bg-color-4 {
+    background-color: #3465a4;
+}
+
+.terminal .xterm-color-5 {
+    color: #75507b;
+}
+
+.terminal .xterm-bg-color-5 {
+    background-color: #75507b;
+}
+
+.terminal .xterm-color-6 {
+    color: #06989a;
+}
+
+.terminal .xterm-bg-color-6 {
+    background-color: #06989a;
+}
+
+.terminal .xterm-color-7 {
+    color: #d3d7cf;
+}
+
+.terminal .xterm-bg-color-7 {
+    background-color: #d3d7cf;
+}
+
+.terminal .xterm-color-8 {
+    color: #555753;
+}
+
+.terminal .xterm-bg-color-8 {
+    background-color: #555753;
+}
+
+.terminal .xterm-color-9 {
+    color: #ef2929;
+}
+
+.terminal .xterm-bg-color-9 {
+    background-color: #ef2929;
+}
+
+.terminal .xterm-color-10 {
+    color: #8ae234;
+}
+
+.terminal .xterm-bg-color-10 {
+    background-color: #8ae234;
+}
+
+.terminal .xterm-color-11 {
+    color: #fce94f;
+}
+
+.terminal .xterm-bg-color-11 {
+    background-color: #fce94f;
+}
+
+.terminal .xterm-color-12 {
+    color: #729fcf;
+}
+
+.terminal .xterm-bg-color-12 {
+    background-color: #729fcf;
+}
+
+.terminal .xterm-color-13 {
+    color: #ad7fa8;
+}
+
+.terminal .xterm-bg-color-13 {
+    background-color: #ad7fa8;
+}
+
+.terminal .xterm-color-14 {
+    color: #34e2e2;
+}
+
+.terminal .xterm-bg-color-14 {
+    background-color: #34e2e2;
+}
+
+.terminal .xterm-color-15 {
+    color: #eeeeec;
+}
+
+.terminal .xterm-bg-color-15 {
+    background-color: #eeeeec;
+}
+
+.terminal .xterm-color-16 {
+    color: #000000;
+}
+
+.terminal .xterm-bg-color-16 {
+    background-color: #000000;
+}
+
+.terminal .xterm-color-17 {
+    color: #00005f;
+}
+
+.terminal .xterm-bg-color-17 {
+    background-color: #00005f;
+}
+
+.terminal .xterm-color-18 {
+    color: #000087;
+}
+
+.terminal .xterm-bg-color-18 {
+    background-color: #000087;
+}
+
+.terminal .xterm-color-19 {
+    color: #0000af;
+}
+
+.terminal .xterm-bg-color-19 {
+    background-color: #0000af;
+}
+
+.terminal .xterm-color-20 {
+    color: #0000d7;
+}
+
+.terminal .xterm-bg-color-20 {
+    background-color: #0000d7;
+}
+
+.terminal .xterm-color-21 {
+    color: #0000ff;
+}
+
+.terminal .xterm-bg-color-21 {
+    background-color: #0000ff;
+}
+
+.terminal .xterm-color-22 {
+    color: #005f00;
+}
+
+.terminal .xterm-bg-color-22 {
+    background-color: #005f00;
+}
+
+.terminal .xterm-color-23 {
+    color: #005f5f;
+}
+
+.terminal .xterm-bg-color-23 {
+    background-color: #005f5f;
+}
+
+.terminal .xterm-color-24 {
+    color: #005f87;
+}
+
+.terminal .xterm-bg-color-24 {
+    background-color: #005f87;
+}
+
+.terminal .xterm-color-25 {
+    color: #005faf;
+}
+
+.terminal .xterm-bg-color-25 {
+    background-color: #005faf;
+}
+
+.terminal .xterm-color-26 {
+    color: #005fd7;
+}
+
+.terminal .xterm-bg-color-26 {
+    background-color: #005fd7;
+}
+
+.terminal .xterm-color-27 {
+    color: #005fff;
+}
+
+.terminal .xterm-bg-color-27 {
+    background-color: #005fff;
+}
+
+.terminal .xterm-color-28 {
+    color: #008700;
+}
+
+.terminal .xterm-bg-color-28 {
+    background-color: #008700;
+}
+
+.terminal .xterm-color-29 {
+    color: #00875f;
+}
+
+.terminal .xterm-bg-color-29 {
+    background-color: #00875f;
+}
+
+.terminal .xterm-color-30 {
+    color: #008787;
+}
+
+.terminal .xterm-bg-color-30 {
+    background-color: #008787;
+}
+
+.terminal .xterm-color-31 {
+    color: #0087af;
+}
+
+.terminal .xterm-bg-color-31 {
+    background-color: #0087af;
+}
+
+.terminal .xterm-color-32 {
+    color: #0087d7;
+}
+
+.terminal .xterm-bg-color-32 {
+    background-color: #0087d7;
+}
+
+.terminal .xterm-color-33 {
+    color: #0087ff;
+}
+
+.terminal .xterm-bg-color-33 {
+    background-color: #0087ff;
+}
+
+.terminal .xterm-color-34 {
+    color: #00af00;
+}
+
+.terminal .xterm-bg-color-34 {
+    background-color: #00af00;
+}
+
+.terminal .xterm-color-35 {
+    color: #00af5f;
+}
+
+.terminal .xterm-bg-color-35 {
+    background-color: #00af5f;
+}
+
+.terminal .xterm-color-36 {
+    color: #00af87;
+}
+
+.terminal .xterm-bg-color-36 {
+    background-color: #00af87;
+}
+
+.terminal .xterm-color-37 {
+    color: #00afaf;
+}
+
+.terminal .xterm-bg-color-37 {
+    background-color: #00afaf;
+}
+
+.terminal .xterm-color-38 {
+    color: #00afd7;
+}
+
+.terminal .xterm-bg-color-38 {
+    background-color: #00afd7;
+}
+
+.terminal .xterm-color-39 {
+    color: #00afff;
+}
+
+.terminal .xterm-bg-color-39 {
+    background-color: #00afff;
+}
+
+.terminal .xterm-color-40 {
+    color: #00d700;
+}
+
+.terminal .xterm-bg-color-40 {
+    background-color: #00d700;
+}
+
+.terminal .xterm-color-41 {
+    color: #00d75f;
+}
+
+.terminal .xterm-bg-color-41 {
+    background-color: #00d75f;
+}
+
+.terminal .xterm-color-42 {
+    color: #00d787;
+}
+
+.terminal .xterm-bg-color-42 {
+    background-color: #00d787;
+}
+
+.terminal .xterm-color-43 {
+    color: #00d7af;
+}
+
+.terminal .xterm-bg-color-43 {
+    background-color: #00d7af;
+}
+
+.terminal .xterm-color-44 {
+    color: #00d7d7;
+}
+
+.terminal .xterm-bg-color-44 {
+    background-color: #00d7d7;
+}
+
+.terminal .xterm-color-45 {
+    color: #00d7ff;
+}
+
+.terminal .xterm-bg-color-45 {
+    background-color: #00d7ff;
+}
+
+.terminal .xterm-color-46 {
+    color: #00ff00;
+}
+
+.terminal .xterm-bg-color-46 {
+    background-color: #00ff00;
+}
+
+.terminal .xterm-color-47 {
+    color: #00ff5f;
+}
+
+.terminal .xterm-bg-color-47 {
+    background-color: #00ff5f;
+}
+
+.terminal .xterm-color-48 {
+    color: #00ff87;
+}
+
+.terminal .xterm-bg-color-48 {
+    background-color: #00ff87;
+}
+
+.terminal .xterm-color-49 {
+    color: #00ffaf;
+}
+
+.terminal .xterm-bg-color-49 {
+    background-color: #00ffaf;
+}
+
+.terminal .xterm-color-50 {
+    color: #00ffd7;
+}
+
+.terminal .xterm-bg-color-50 {
+    background-color: #00ffd7;
+}
+
+.terminal .xterm-color-51 {
+    color: #00ffff;
+}
+
+.terminal .xterm-bg-color-51 {
+    background-color: #00ffff;
+}
+
+.terminal .xterm-color-52 {
+    color: #5f0000;
+}
+
+.terminal .xterm-bg-color-52 {
+    background-color: #5f0000;
+}
+
+.terminal .xterm-color-53 {
+    color: #5f005f;
+}
+
+.terminal .xterm-bg-color-53 {
+    background-color: #5f005f;
+}
+
+.terminal .xterm-color-54 {
+    color: #5f0087;
+}
+
+.terminal .xterm-bg-color-54 {
+    background-color: #5f0087;
+}
+
+.terminal .xterm-color-55 {
+    color: #5f00af;
+}
+
+.terminal .xterm-bg-color-55 {
+    background-color: #5f00af;
+}
+
+.terminal .xterm-color-56 {
+    color: #5f00d7;
+}
+
+.terminal .xterm-bg-color-56 {
+    background-color: #5f00d7;
+}
+
+.terminal .xterm-color-57 {
+    color: #5f00ff;
+}
+
+.terminal .xterm-bg-color-57 {
+    background-color: #5f00ff;
+}
+
+.terminal .xterm-color-58 {
+    color: #5f5f00;
+}
+
+.terminal .xterm-bg-color-58 {
+    background-color: #5f5f00;
+}
+
+.terminal .xterm-color-59 {
+    color: #5f5f5f;
+}
+
+.terminal .xterm-bg-color-59 {
+    background-color: #5f5f5f;
+}
+
+.terminal .xterm-color-60 {
+    color: #5f5f87;
+}
+
+.terminal .xterm-bg-color-60 {
+    background-color: #5f5f87;
+}
+
+.terminal .xterm-color-61 {
+    color: #5f5faf;
+}
+
+.terminal .xterm-bg-color-61 {
+    background-color: #5f5faf;
+}
+
+.terminal .xterm-color-62 {
+    color: #5f5fd7;
+}
+
+.terminal .xterm-bg-color-62 {
+    background-color: #5f5fd7;
+}
+
+.terminal .xterm-color-63 {
+    color: #5f5fff;
+}
+
+.terminal .xterm-bg-color-63 {
+    background-color: #5f5fff;
+}
+
+.terminal .xterm-color-64 {
+    color: #5f8700;
+}
+
+.terminal .xterm-bg-color-64 {
+    background-color: #5f8700;
+}
+
+.terminal .xterm-color-65 {
+    color: #5f875f;
+}
+
+.terminal .xterm-bg-color-65 {
+    background-color: #5f875f;
+}
+
+.terminal .xterm-color-66 {
+    color: #5f8787;
+}
+
+.terminal .xterm-bg-color-66 {
+    background-color: #5f8787;
+}
+
+.terminal .xterm-color-67 {
+    color: #5f87af;
+}
+
+.terminal .xterm-bg-color-67 {
+    background-color: #5f87af;
+}
+
+.terminal .xterm-color-68 {
+    color: #5f87d7;
+}
+
+.terminal .xterm-bg-color-68 {
+    background-color: #5f87d7;
+}
+
+.terminal .xterm-color-69 {
+    color: #5f87ff;
+}
+
+.terminal .xterm-bg-color-69 {
+    background-color: #5f87ff;
+}
+
+.terminal .xterm-color-70 {
+    color: #5faf00;
+}
+
+.terminal .xterm-bg-color-70 {
+    background-color: #5faf00;
+}
+
+.terminal .xterm-color-71 {
+    color: #5faf5f;
+}
+
+.terminal .xterm-bg-color-71 {
+    background-color: #5faf5f;
+}
+
+.terminal .xterm-color-72 {
+    color: #5faf87;
+}
+
+.terminal .xterm-bg-color-72 {
+    background-color: #5faf87;
+}
+
+.terminal .xterm-color-73 {
+    color: #5fafaf;
+}
+
+.terminal .xterm-bg-color-73 {
+    background-color: #5fafaf;
+}
+
+.terminal .xterm-color-74 {
+    color: #5fafd7;
+}
+
+.terminal .xterm-bg-color-74 {
+    background-color: #5fafd7;
+}
+
+.terminal .xterm-color-75 {
+    color: #5fafff;
+}
+
+.terminal .xterm-bg-color-75 {
+    background-color: #5fafff;
+}
+
+.terminal .xterm-color-76 {
+    color: #5fd700;
+}
+
+.terminal .xterm-bg-color-76 {
+    background-color: #5fd700;
+}
+
+.terminal .xterm-color-77 {
+    color: #5fd75f;
+}
+
+.terminal .xterm-bg-color-77 {
+    background-color: #5fd75f;
+}
+
+.terminal .xterm-color-78 {
+    color: #5fd787;
+}
+
+.terminal .xterm-bg-color-78 {
+    background-color: #5fd787;
+}
+
+.terminal .xterm-color-79 {
+    color: #5fd7af;
+}
+
+.terminal .xterm-bg-color-79 {
+    background-color: #5fd7af;
+}
+
+.terminal .xterm-color-80 {
+    color: #5fd7d7;
+}
+
+.terminal .xterm-bg-color-80 {
+    background-color: #5fd7d7;
+}
+
+.terminal .xterm-color-81 {
+    color: #5fd7ff;
+}
+
+.terminal .xterm-bg-color-81 {
+    background-color: #5fd7ff;
+}
+
+.terminal .xterm-color-82 {
+    color: #5fff00;
+}
+
+.terminal .xterm-bg-color-82 {
+    background-color: #5fff00;
+}
+
+.terminal .xterm-color-83 {
+    color: #5fff5f;
+}
+
+.terminal .xterm-bg-color-83 {
+    background-color: #5fff5f;
+}
+
+.terminal .xterm-color-84 {
+    color: #5fff87;
+}
+
+.terminal .xterm-bg-color-84 {
+    background-color: #5fff87;
+}
+
+.terminal .xterm-color-85 {
+    color: #5fffaf;
+}
+
+.terminal .xterm-bg-color-85 {
+    background-color: #5fffaf;
+}
+
+.terminal .xterm-color-86 {
+    color: #5fffd7;
+}
+
+.terminal .xterm-bg-color-86 {
+    background-color: #5fffd7;
+}
+
+.terminal .xterm-color-87 {
+    color: #5fffff;
+}
+
+.terminal .xterm-bg-color-87 {
+    background-color: #5fffff;
+}
+
+.terminal .xterm-color-88 {
+    color: #870000;
+}
+
+.terminal .xterm-bg-color-88 {
+    background-color: #870000;
+}
+
+.terminal .xterm-color-89 {
+    color: #87005f;
+}
+
+.terminal .xterm-bg-color-89 {
+    background-color: #87005f;
+}
+
+.terminal .xterm-color-90 {
+    color: #870087;
+}
+
+.terminal .xterm-bg-color-90 {
+    background-color: #870087;
+}
+
+.terminal .xterm-color-91 {
+    color: #8700af;
+}
+
+.terminal .xterm-bg-color-91 {
+    background-color: #8700af;
+}
+
+.terminal .xterm-color-92 {
+    color: #8700d7;
+}
+
+.terminal .xterm-bg-color-92 {
+    background-color: #8700d7;
+}
+
+.terminal .xterm-color-93 {
+    color: #8700ff;
+}
+
+.terminal .xterm-bg-color-93 {
+    background-color: #8700ff;
+}
+
+.terminal .xterm-color-94 {
+    color: #875f00;
+}
+
+.terminal .xterm-bg-color-94 {
+    background-color: #875f00;
+}
+
+.terminal .xterm-color-95 {
+    color: #875f5f;
+}
+
+.terminal .xterm-bg-color-95 {
+    background-color: #875f5f;
+}
+
+.terminal .xterm-color-96 {
+    color: #875f87;
+}
+
+.terminal .xterm-bg-color-96 {
+    background-color: #875f87;
+}
+
+.terminal .xterm-color-97 {
+    color: #875faf;
+}
+
+.terminal .xterm-bg-color-97 {
+    background-color: #875faf;
+}
+
+.terminal .xterm-color-98 {
+    color: #875fd7;
+}
+
+.terminal .xterm-bg-color-98 {
+    background-color: #875fd7;
+}
+
+.terminal .xterm-color-99 {
+    color: #875fff;
+}
+
+.terminal .xterm-bg-color-99 {
+    background-color: #875fff;
+}
+
+.terminal .xterm-color-100 {
+    color: #878700;
+}
+
+.terminal .xterm-bg-color-100 {
+    background-color: #878700;
+}
+
+.terminal .xterm-color-101 {
+    color: #87875f;
+}
+
+.terminal .xterm-bg-color-101 {
+    background-color: #87875f;
+}
+
+.terminal .xterm-color-102 {
+    color: #878787;
+}
+
+.terminal .xterm-bg-color-102 {
+    background-color: #878787;
+}
+
+.terminal .xterm-color-103 {
+    color: #8787af;
+}
+
+.terminal .xterm-bg-color-103 {
+    background-color: #8787af;
+}
+
+.terminal .xterm-color-104 {
+    color: #8787d7;
+}
+
+.terminal .xterm-bg-color-104 {
+    background-color: #8787d7;
+}
+
+.terminal .xterm-color-105 {
+    color: #8787ff;
+}
+
+.terminal .xterm-bg-color-105 {
+    background-color: #8787ff;
+}
+
+.terminal .xterm-color-106 {
+    color: #87af00;
+}
+
+.terminal .xterm-bg-color-106 {
+    background-color: #87af00;
+}
+
+.terminal .xterm-color-107 {
+    color: #87af5f;
+}
+
+.terminal .xterm-bg-color-107 {
+    background-color: #87af5f;
+}
+
+.terminal .xterm-color-108 {
+    color: #87af87;
+}
+
+.terminal .xterm-bg-color-108 {
+    background-color: #87af87;
+}
+
+.terminal .xterm-color-109 {
+    color: #87afaf;
+}
+
+.terminal .xterm-bg-color-109 {
+    background-color: #87afaf;
+}
+
+.terminal .xterm-color-110 {
+    color: #87afd7;
+}
+
+.terminal .xterm-bg-color-110 {
+    background-color: #87afd7;
+}
+
+.terminal .xterm-color-111 {
+    color: #87afff;
+}
+
+.terminal .xterm-bg-color-111 {
+    background-color: #87afff;
+}
+
+.terminal .xterm-color-112 {
+    color: #87d700;
+}
+
+.terminal .xterm-bg-color-112 {
+    background-color: #87d700;
+}
+
+.terminal .xterm-color-113 {
+    color: #87d75f;
+}
+
+.terminal .xterm-bg-color-113 {
+    background-color: #87d75f;
+}
+
+.terminal .xterm-color-114 {
+    color: #87d787;
+}
+
+.terminal .xterm-bg-color-114 {
+    background-color: #87d787;
+}
+
+.terminal .xterm-color-115 {
+    color: #87d7af;
+}
+
+.terminal .xterm-bg-color-115 {
+    background-color: #87d7af;
+}
+
+.terminal .xterm-color-116 {
+    color: #87d7d7;
+}
+
+.terminal .xterm-bg-color-116 {
+    background-color: #87d7d7;
+}
+
+.terminal .xterm-color-117 {
+    color: #87d7ff;
+}
+
+.terminal .xterm-bg-color-117 {
+    background-color: #87d7ff;
+}
+
+.terminal .xterm-color-118 {
+    color: #87ff00;
+}
+
+.terminal .xterm-bg-color-118 {
+    background-color: #87ff00;
+}
+
+.terminal .xterm-color-119 {
+    color: #87ff5f;
+}
+
+.terminal .xterm-bg-color-119 {
+    background-color: #87ff5f;
+}
+
+.terminal .xterm-color-120 {
+    color: #87ff87;
+}
+
+.terminal .xterm-bg-color-120 {
+    background-color: #87ff87;
+}
+
+.terminal .xterm-color-121 {
+    color: #87ffaf;
+}
+
+.terminal .xterm-bg-color-121 {
+    background-color: #87ffaf;
+}
+
+.terminal .xterm-color-122 {
+    color: #87ffd7;
+}
+
+.terminal .xterm-bg-color-122 {
+    background-color: #87ffd7;
+}
+
+.terminal .xterm-color-123 {
+    color: #87ffff;
+}
+
+.terminal .xterm-bg-color-123 {
+    background-color: #87ffff;
+}
+
+.terminal .xterm-color-124 {
+    color: #af0000;
+}
+
+.terminal .xterm-bg-color-124 {
+    background-color: #af0000;
+}
+
+.terminal .xterm-color-125 {
+    color: #af005f;
+}
+
+.terminal .xterm-bg-color-125 {
+    background-color: #af005f;
+}
+
+.terminal .xterm-color-126 {
+    color: #af0087;
+}
+
+.terminal .xterm-bg-color-126 {
+    background-color: #af0087;
+}
+
+.terminal .xterm-color-127 {
+    color: #af00af;
+}
+
+.terminal .xterm-bg-color-127 {
+    background-color: #af00af;
+}
+
+.terminal .xterm-color-128 {
+    color: #af00d7;
+}
+
+.terminal .xterm-bg-color-128 {
+    background-color: #af00d7;
+}
+
+.terminal .xterm-color-129 {
+    color: #af00ff;
+}
+
+.terminal .xterm-bg-color-129 {
+    background-color: #af00ff;
+}
+
+.terminal .xterm-color-130 {
+    color: #af5f00;
+}
+
+.terminal .xterm-bg-color-130 {
+    background-color: #af5f00;
+}
+
+.terminal .xterm-color-131 {
+    color: #af5f5f;
+}
+
+.terminal .xterm-bg-color-131 {
+    background-color: #af5f5f;
+}
+
+.terminal .xterm-color-132 {
+    color: #af5f87;
+}
+
+.terminal .xterm-bg-color-132 {
+    background-color: #af5f87;
+}
+
+.terminal .xterm-color-133 {
+    color: #af5faf;
+}
+
+.terminal .xterm-bg-color-133 {
+    background-color: #af5faf;
+}
+
+.terminal .xterm-color-134 {
+    color: #af5fd7;
+}
+
+.terminal .xterm-bg-color-134 {
+    background-color: #af5fd7;
+}
+
+.terminal .xterm-color-135 {
+    color: #af5fff;
+}
+
+.terminal .xterm-bg-color-135 {
+    background-color: #af5fff;
+}
+
+.terminal .xterm-color-136 {
+    color: #af8700;
+}
+
+.terminal .xterm-bg-color-136 {
+    background-color: #af8700;
+}
+
+.terminal .xterm-color-137 {
+    color: #af875f;
+}
+
+.terminal .xterm-bg-color-137 {
+    background-color: #af875f;
+}
+
+.terminal .xterm-color-138 {
+    color: #af8787;
+}
+
+.terminal .xterm-bg-color-138 {
+    background-color: #af8787;
+}
+
+.terminal .xterm-color-139 {
+    color: #af87af;
+}
+
+.terminal .xterm-bg-color-139 {
+    background-color: #af87af;
+}
+
+.terminal .xterm-color-140 {
+    color: #af87d7;
+}
+
+.terminal .xterm-bg-color-140 {
+    background-color: #af87d7;
+}
+
+.terminal .xterm-color-141 {
+    color: #af87ff;
+}
+
+.terminal .xterm-bg-color-141 {
+    background-color: #af87ff;
+}
+
+.terminal .xterm-color-142 {
+    color: #afaf00;
+}
+
+.terminal .xterm-bg-color-142 {
+    background-color: #afaf00;
+}
+
+.terminal .xterm-color-143 {
+    color: #afaf5f;
+}
+
+.terminal .xterm-bg-color-143 {
+    background-color: #afaf5f;
+}
+
+.terminal .xterm-color-144 {
+    color: #afaf87;
+}
+
+.terminal .xterm-bg-color-144 {
+    background-color: #afaf87;
+}
+
+.terminal .xterm-color-145 {
+    color: #afafaf;
+}
+
+.terminal .xterm-bg-color-145 {
+    background-color: #afafaf;
+}
+
+.terminal .xterm-color-146 {
+    color: #afafd7;
+}
+
+.terminal .xterm-bg-color-146 {
+    background-color: #afafd7;
+}
+
+.terminal .xterm-color-147 {
+    color: #afafff;
+}
+
+.terminal .xterm-bg-color-147 {
+    background-color: #afafff;
+}
+
+.terminal .xterm-color-148 {
+    color: #afd700;
+}
+
+.terminal .xterm-bg-color-148 {
+    background-color: #afd700;
+}
+
+.terminal .xterm-color-149 {
+    color: #afd75f;
+}
+
+.terminal .xterm-bg-color-149 {
+    background-color: #afd75f;
+}
+
+.terminal .xterm-color-150 {
+    color: #afd787;
+}
+
+.terminal .xterm-bg-color-150 {
+    background-color: #afd787;
+}
+
+.terminal .xterm-color-151 {
+    color: #afd7af;
+}
+
+.terminal .xterm-bg-color-151 {
+    background-color: #afd7af;
+}
+
+.terminal .xterm-color-152 {
+    color: #afd7d7;
+}
+
+.terminal .xterm-bg-color-152 {
+    background-color: #afd7d7;
+}
+
+.terminal .xterm-color-153 {
+    color: #afd7ff;
+}
+
+.terminal .xterm-bg-color-153 {
+    background-color: #afd7ff;
+}
+
+.terminal .xterm-color-154 {
+    color: #afff00;
+}
+
+.terminal .xterm-bg-color-154 {
+    background-color: #afff00;
+}
+
+.terminal .xterm-color-155 {
+    color: #afff5f;
+}
+
+.terminal .xterm-bg-color-155 {
+    background-color: #afff5f;
+}
+
+.terminal .xterm-color-156 {
+    color: #afff87;
+}
+
+.terminal .xterm-bg-color-156 {
+    background-color: #afff87;
+}
+
+.terminal .xterm-color-157 {
+    color: #afffaf;
+}
+
+.terminal .xterm-bg-color-157 {
+    background-color: #afffaf;
+}
+
+.terminal .xterm-color-158 {
+    color: #afffd7;
+}
+
+.terminal .xterm-bg-color-158 {
+    background-color: #afffd7;
+}
+
+.terminal .xterm-color-159 {
+    color: #afffff;
+}
+
+.terminal .xterm-bg-color-159 {
+    background-color: #afffff;
+}
+
+.terminal .xterm-color-160 {
+    color: #d70000;
+}
+
+.terminal .xterm-bg-color-160 {
+    background-color: #d70000;
+}
+
+.terminal .xterm-color-161 {
+    color: #d7005f;
+}
+
+.terminal .xterm-bg-color-161 {
+    background-color: #d7005f;
+}
+
+.terminal .xterm-color-162 {
+    color: #d70087;
+}
+
+.terminal .xterm-bg-color-162 {
+    background-color: #d70087;
+}
+
+.terminal .xterm-color-163 {
+    color: #d700af;
+}
+
+.terminal .xterm-bg-color-163 {
+    background-color: #d700af;
+}
+
+.terminal .xterm-color-164 {
+    color: #d700d7;
+}
+
+.terminal .xterm-bg-color-164 {
+    background-color: #d700d7;
+}
+
+.terminal .xterm-color-165 {
+    color: #d700ff;
+}
+
+.terminal .xterm-bg-color-165 {
+    background-color: #d700ff;
+}
+
+.terminal .xterm-color-166 {
+    color: #d75f00;
+}
+
+.terminal .xterm-bg-color-166 {
+    background-color: #d75f00;
+}
+
+.terminal .xterm-color-167 {
+    color: #d75f5f;
+}
+
+.terminal .xterm-bg-color-167 {
+    background-color: #d75f5f;
+}
+
+.terminal .xterm-color-168 {
+    color: #d75f87;
+}
+
+.terminal .xterm-bg-color-168 {
+    background-color: #d75f87;
+}
+
+.terminal .xterm-color-169 {
+    color: #d75faf;
+}
+
+.terminal .xterm-bg-color-169 {
+    background-color: #d75faf;
+}
+
+.terminal .xterm-color-170 {
+    color: #d75fd7;
+}
+
+.terminal .xterm-bg-color-170 {
+    background-color: #d75fd7;
+}
+
+.terminal .xterm-color-171 {
+    color: #d75fff;
+}
+
+.terminal .xterm-bg-color-171 {
+    background-color: #d75fff;
+}
+
+.terminal .xterm-color-172 {
+    color: #d78700;
+}
+
+.terminal .xterm-bg-color-172 {
+    background-color: #d78700;
+}
+
+.terminal .xterm-color-173 {
+    color: #d7875f;
+}
+
+.terminal .xterm-bg-color-173 {
+    background-color: #d7875f;
+}
+
+.terminal .xterm-color-174 {
+    color: #d78787;
+}
+
+.terminal .xterm-bg-color-174 {
+    background-color: #d78787;
+}
+
+.terminal .xterm-color-175 {
+    color: #d787af;
+}
+
+.terminal .xterm-bg-color-175 {
+    background-color: #d787af;
+}
+
+.terminal .xterm-color-176 {
+    color: #d787d7;
+}
+
+.terminal .xterm-bg-color-176 {
+    background-color: #d787d7;
+}
+
+.terminal .xterm-color-177 {
+    color: #d787ff;
+}
+
+.terminal .xterm-bg-color-177 {
+    background-color: #d787ff;
+}
+
+.terminal .xterm-color-178 {
+    color: #d7af00;
+}
+
+.terminal .xterm-bg-color-178 {
+    background-color: #d7af00;
+}
+
+.terminal .xterm-color-179 {
+    color: #d7af5f;
+}
+
+.terminal .xterm-bg-color-179 {
+    background-color: #d7af5f;
+}
+
+.terminal .xterm-color-180 {
+    color: #d7af87;
+}
+
+.terminal .xterm-bg-color-180 {
+    background-color: #d7af87;
+}
+
+.terminal .xterm-color-181 {
+    color: #d7afaf;
+}
+
+.terminal .xterm-bg-color-181 {
+    background-color: #d7afaf;
+}
+
+.terminal .xterm-color-182 {
+    color: #d7afd7;
+}
+
+.terminal .xterm-bg-color-182 {
+    background-color: #d7afd7;
+}
+
+.terminal .xterm-color-183 {
+    color: #d7afff;
+}
+
+.terminal .xterm-bg-color-183 {
+    background-color: #d7afff;
+}
+
+.terminal .xterm-color-184 {
+    color: #d7d700;
+}
+
+.terminal .xterm-bg-color-184 {
+    background-color: #d7d700;
+}
+
+.terminal .xterm-color-185 {
+    color: #d7d75f;
+}
+
+.terminal .xterm-bg-color-185 {
+    background-color: #d7d75f;
+}
+
+.terminal .xterm-color-186 {
+    color: #d7d787;
+}
+
+.terminal .xterm-bg-color-186 {
+    background-color: #d7d787;
+}
+
+.terminal .xterm-color-187 {
+    color: #d7d7af;
+}
+
+.terminal .xterm-bg-color-187 {
+    background-color: #d7d7af;
+}
+
+.terminal .xterm-color-188 {
+    color: #d7d7d7;
+}
+
+.terminal .xterm-bg-color-188 {
+    background-color: #d7d7d7;
+}
+
+.terminal .xterm-color-189 {
+    color: #d7d7ff;
+}
+
+.terminal .xterm-bg-color-189 {
+    background-color: #d7d7ff;
+}
+
+.terminal .xterm-color-190 {
+    color: #d7ff00;
+}
+
+.terminal .xterm-bg-color-190 {
+    background-color: #d7ff00;
+}
+
+.terminal .xterm-color-191 {
+    color: #d7ff5f;
+}
+
+.terminal .xterm-bg-color-191 {
+    background-color: #d7ff5f;
+}
+
+.terminal .xterm-color-192 {
+    color: #d7ff87;
+}
+
+.terminal .xterm-bg-color-192 {
+    background-color: #d7ff87;
+}
+
+.terminal .xterm-color-193 {
+    color: #d7ffaf;
+}
+
+.terminal .xterm-bg-color-193 {
+    background-color: #d7ffaf;
+}
+
+.terminal .xterm-color-194 {
+    color: #d7ffd7;
+}
+
+.terminal .xterm-bg-color-194 {
+    background-color: #d7ffd7;
+}
+
+.terminal .xterm-color-195 {
+    color: #d7ffff;
+}
+
+.terminal .xterm-bg-color-195 {
+    background-color: #d7ffff;
+}
+
+.terminal .xterm-color-196 {
+    color: #ff0000;
+}
+
+.terminal .xterm-bg-color-196 {
+    background-color: #ff0000;
+}
+
+.terminal .xterm-color-197 {
+    color: #ff005f;
+}
+
+.terminal .xterm-bg-color-197 {
+    background-color: #ff005f;
+}
+
+.terminal .xterm-color-198 {
+    color: #ff0087;
+}
+
+.terminal .xterm-bg-color-198 {
+    background-color: #ff0087;
+}
+
+.terminal .xterm-color-199 {
+    color: #ff00af;
+}
+
+.terminal .xterm-bg-color-199 {
+    background-color: #ff00af;
+}
+
+.terminal .xterm-color-200 {
+    color: #ff00d7;
+}
+
+.terminal .xterm-bg-color-200 {
+    background-color: #ff00d7;
+}
+
+.terminal .xterm-color-201 {
+    color: #ff00ff;
+}
+
+.terminal .xterm-bg-color-201 {
+    background-color: #ff00ff;
+}
+
+.terminal .xterm-color-202 {
+    color: #ff5f00;
+}
+
+.terminal .xterm-bg-color-202 {
+    background-color: #ff5f00;
+}
+
+.terminal .xterm-color-203 {
+    color: #ff5f5f;
+}
+
+.terminal .xterm-bg-color-203 {
+    background-color: #ff5f5f;
+}
+
+.terminal .xterm-color-204 {
+    color: #ff5f87;
+}
+
+.terminal .xterm-bg-color-204 {
+    background-color: #ff5f87;
+}
+
+.terminal .xterm-color-205 {
+    color: #ff5faf;
+}
+
+.terminal .xterm-bg-color-205 {
+    background-color: #ff5faf;
+}
+
+.terminal .xterm-color-206 {
+    color: #ff5fd7;
+}
+
+.terminal .xterm-bg-color-206 {
+    background-color: #ff5fd7;
+}
+
+.terminal .xterm-color-207 {
+    color: #ff5fff;
+}
+
+.terminal .xterm-bg-color-207 {
+    background-color: #ff5fff;
+}
+
+.terminal .xterm-color-208 {
+    color: #ff8700;
+}
+
+.terminal .xterm-bg-color-208 {
+    background-color: #ff8700;
+}
+
+.terminal .xterm-color-209 {
+    color: #ff875f;
+}
+
+.terminal .xterm-bg-color-209 {
+    background-color: #ff875f;
+}
+
+.terminal .xterm-color-210 {
+    color: #ff8787;
+}
+
+.terminal .xterm-bg-color-210 {
+    background-color: #ff8787;
+}
+
+.terminal .xterm-color-211 {
+    color: #ff87af;
+}
+
+.terminal .xterm-bg-color-211 {
+    background-color: #ff87af;
+}
+
+.terminal .xterm-color-212 {
+    color: #ff87d7;
+}
+
+.terminal .xterm-bg-color-212 {
+    background-color: #ff87d7;
+}
+
+.terminal .xterm-color-213 {
+    color: #ff87ff;
+}
+
+.terminal .xterm-bg-color-213 {
+    background-color: #ff87ff;
+}
+
+.terminal .xterm-color-214 {
+    color: #ffaf00;
+}
+
+.terminal .xterm-bg-color-214 {
+    background-color: #ffaf00;
+}
+
+.terminal .xterm-color-215 {
+    color: #ffaf5f;
+}
+
+.terminal .xterm-bg-color-215 {
+    background-color: #ffaf5f;
+}
+
+.terminal .xterm-color-216 {
+    color: #ffaf87;
+}
+
+.terminal .xterm-bg-color-216 {
+    background-color: #ffaf87;
+}
+
+.terminal .xterm-color-217 {
+    color: #ffafaf;
+}
+
+.terminal .xterm-bg-color-217 {
+    background-color: #ffafaf;
+}
+
+.terminal .xterm-color-218 {
+    color: #ffafd7;
+}
+
+.terminal .xterm-bg-color-218 {
+    background-color: #ffafd7;
+}
+
+.terminal .xterm-color-219 {
+    color: #ffafff;
+}
+
+.terminal .xterm-bg-color-219 {
+    background-color: #ffafff;
+}
+
+.terminal .xterm-color-220 {
+    color: #ffd700;
+}
+
+.terminal .xterm-bg-color-220 {
+    background-color: #ffd700;
+}
+
+.terminal .xterm-color-221 {
+    color: #ffd75f;
+}
+
+.terminal .xterm-bg-color-221 {
+    background-color: #ffd75f;
+}
+
+.terminal .xterm-color-222 {
+    color: #ffd787;
+}
+
+.terminal .xterm-bg-color-222 {
+    background-color: #ffd787;
+}
+
+.terminal .xterm-color-223 {
+    color: #ffd7af;
+}
+
+.terminal .xterm-bg-color-223 {
+    background-color: #ffd7af;
+}
+
+.terminal .xterm-color-224 {
+    color: #ffd7d7;
+}
+
+.terminal .xterm-bg-color-224 {
+    background-color: #ffd7d7;
+}
+
+.terminal .xterm-color-225 {
+    color: #ffd7ff;
+}
+
+.terminal .xterm-bg-color-225 {
+    background-color: #ffd7ff;
+}
+
+.terminal .xterm-color-226 {
+    color: #ffff00;
+}
+
+.terminal .xterm-bg-color-226 {
+    background-color: #ffff00;
+}
+
+.terminal .xterm-color-227 {
+    color: #ffff5f;
+}
+
+.terminal .xterm-bg-color-227 {
+    background-color: #ffff5f;
+}
+
+.terminal .xterm-color-228 {
+    color: #ffff87;
+}
+
+.terminal .xterm-bg-color-228 {
+    background-color: #ffff87;
+}
+
+.terminal .xterm-color-229 {
+    color: #ffffaf;
+}
+
+.terminal .xterm-bg-color-229 {
+    background-color: #ffffaf;
+}
+
+.terminal .xterm-color-230 {
+    color: #ffffd7;
+}
+
+.terminal .xterm-bg-color-230 {
+    background-color: #ffffd7;
+}
+
+.terminal .xterm-color-231 {
+    color: #ffffff;
+}
+
+.terminal .xterm-bg-color-231 {
+    background-color: #ffffff;
+}
+
+.terminal .xterm-color-232 {
+    color: #080808;
+}
+
+.terminal .xterm-bg-color-232 {
+    background-color: #080808;
+}
+
+.terminal .xterm-color-233 {
+    color: #121212;
+}
+
+.terminal .xterm-bg-color-233 {
+    background-color: #121212;
+}
+
+.terminal .xterm-color-234 {
+    color: #1c1c1c;
+}
+
+.terminal .xterm-bg-color-234 {
+    background-color: #1c1c1c;
+}
+
+.terminal .xterm-color-235 {
+    color: #262626;
+}
+
+.terminal .xterm-bg-color-235 {
+    background-color: #262626;
+}
+
+.terminal .xterm-color-236 {
+    color: #303030;
+}
+
+.terminal .xterm-bg-color-236 {
+    background-color: #303030;
+}
+
+.terminal .xterm-color-237 {
+    color: #3a3a3a;
+}
+
+.terminal .xterm-bg-color-237 {
+    background-color: #3a3a3a;
+}
+
+.terminal .xterm-color-238 {
+    color: #444444;
+}
+
+.terminal .xterm-bg-color-238 {
+    background-color: #444444;
+}
+
+.terminal .xterm-color-239 {
+    color: #4e4e4e;
+}
+
+.terminal .xterm-bg-color-239 {
+    background-color: #4e4e4e;
+}
+
+.terminal .xterm-color-240 {
+    color: #585858;
+}
+
+.terminal .xterm-bg-color-240 {
+    background-color: #585858;
+}
+
+.terminal .xterm-color-241 {
+    color: #626262;
+}
+
+.terminal .xterm-bg-color-241 {
+    background-color: #626262;
+}
+
+.terminal .xterm-color-242 {
+    color: #6c6c6c;
+}
+
+.terminal .xterm-bg-color-242 {
+    background-color: #6c6c6c;
+}
+
+.terminal .xterm-color-243 {
+    color: #767676;
+}
+
+.terminal .xterm-bg-color-243 {
+    background-color: #767676;
+}
+
+.terminal .xterm-color-244 {
+    color: #808080;
+}
+
+.terminal .xterm-bg-color-244 {
+    background-color: #808080;
+}
+
+.terminal .xterm-color-245 {
+    color: #8a8a8a;
+}
+
+.terminal .xterm-bg-color-245 {
+    background-color: #8a8a8a;
+}
+
+.terminal .xterm-color-246 {
+    color: #949494;
+}
+
+.terminal .xterm-bg-color-246 {
+    background-color: #949494;
+}
+
+.terminal .xterm-color-247 {
+    color: #9e9e9e;
+}
+
+.terminal .xterm-bg-color-247 {
+    background-color: #9e9e9e;
+}
+
+.terminal .xterm-color-248 {
+    color: #a8a8a8;
+}
+
+.terminal .xterm-bg-color-248 {
+    background-color: #a8a8a8;
+}
+
+.terminal .xterm-color-249 {
+    color: #b2b2b2;
+}
+
+.terminal .xterm-bg-color-249 {
+    background-color: #b2b2b2;
+}
+
+.terminal .xterm-color-250 {
+    color: #bcbcbc;
+}
+
+.terminal .xterm-bg-color-250 {
+    background-color: #bcbcbc;
+}
+
+.terminal .xterm-color-251 {
+    color: #c6c6c6;
+}
+
+.terminal .xterm-bg-color-251 {
+    background-color: #c6c6c6;
+}
+
+.terminal .xterm-color-252 {
+    color: #d0d0d0;
+}
+
+.terminal .xterm-bg-color-252 {
+    background-color: #d0d0d0;
+}
+
+.terminal .xterm-color-253 {
+    color: #dadada;
+}
+
+.terminal .xterm-bg-color-253 {
+    background-color: #dadada;
+}
+
+.terminal .xterm-color-254 {
+    color: #e4e4e4;
+}
+
+.terminal .xterm-bg-color-254 {
+    background-color: #e4e4e4;
+}
+
+.terminal .xterm-color-255 {
+    color: #eeeeee;
+}
+
+.terminal .xterm-bg-color-255 {
+    background-color: #eeeeee;
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/build/xterm.js b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/build/xterm.js
new file mode 100644
index 0000000..21abf82
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/build/xterm.js
@@ -0,0 +1,2020 @@
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Terminal = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+/**
+ * xterm.js: xterm, in the browser
+ * Copyright (c) 2016, SourceLair Limited <www.sourcelair.com> (MIT License)
+ */
+
+/**
+ * Encapsulates the logic for handling compositionstart, compositionupdate and compositionend
+ * events, displaying the in-progress composition to the UI and forwarding the final composition
+ * to the handler.
+ * @param {HTMLTextAreaElement} textarea The textarea that xterm uses for input.
+ * @param {HTMLElement} compositionView The element to display the in-progress composition in.
+ * @param {Terminal} terminal The Terminal to forward the finished composition to.
+ */
+function CompositionHelper(textarea, compositionView, terminal) {
+  this.textarea = textarea;
+  this.compositionView = compositionView;
+  this.terminal = terminal;
+
+  // Whether input composition is currently happening, eg. via a mobile keyboard, speech input
+  // or IME. This variable determines whether the compositionText should be displayed on the UI.
+  this.isComposing = false;
+
+  // The input currently being composed, eg. via a mobile keyboard, speech input or IME.
+  this.compositionText = null;
+
+  // The position within the input textarea's value of the current composition.
+  this.compositionPosition = { start: null, end: null };
+
+  // Whether a composition is in the process of being sent, setting this to false will cancel
+  // any in-progress composition.
+  this.isSendingComposition = false;
+}
+
+/**
+ * Handles the compositionstart event, activating the composition view.
+ */
+CompositionHelper.prototype.compositionstart = function () {
+  this.isComposing = true;
+  this.compositionPosition.start = this.textarea.value.length;
+  this.compositionView.textContent = '';
+  this.compositionView.classList.add('active');
+};
+
+/**
+ * Handles the compositionupdate event, updating the composition view.
+ * @param {CompositionEvent} ev The event.
+ */
+CompositionHelper.prototype.compositionupdate = function (ev) {
+  this.compositionView.textContent = ev.data;
+  this.updateCompositionElements();
+  var self = this;
+  setTimeout(function () {
+    self.compositionPosition.end = self.textarea.value.length;
+  }, 0);
+};
+
+/**
+ * Handles the compositionend event, hiding the composition view and sending the composition to
+ * the handler.
+ */
+CompositionHelper.prototype.compositionend = function () {
+  this.finalizeComposition(true);
+};
+
+/**
+ * Handles the keydown event, routing any necessary events to the CompositionHelper functions.
+ * @return Whether the Terminal should continue processing the keydown event.
+ */
+CompositionHelper.prototype.keydown = function (ev) {
+  if (this.isComposing || this.isSendingComposition) {
+    if (ev.keyCode === 229) {
+      // Continue composing if the keyCode is the "composition character"
+      return false;
+    } else if (ev.keyCode === 16 || ev.keyCode === 17 || ev.keyCode === 18) {
+      // Continue composing if the keyCode is a modifier key
+      return false;
+    } else {
+      // Finish composition immediately. This is mainly here for the case where enter is
+      // pressed and the handler needs to be triggered before the command is executed.
+      this.finalizeComposition(false);
+    }
+  }
+
+  if (ev.keyCode === 229) {
+    // If the "composition character" is used but gets to this point it means a non-composition
+    // character (eg. numbers and punctuation) was pressed when the IME was active.
+    this.handleAnyTextareaChanges();
+    return false;
+  }
+
+  return true;
+};
+
+/**
+ * Finalizes the composition, resuming regular input actions. This is called when a composition
+ * is ending.
+ * @param {boolean} waitForPropogation Whether to wait for events to propogate before sending
+ *   the input. This should be false if a non-composition keystroke is entered before the
+ *   compositionend event is triggered, such as enter, so that the composition is send before
+ *   the command is executed.
+ */
+CompositionHelper.prototype.finalizeComposition = function (waitForPropogation) {
+  this.compositionView.classList.remove('active');
+  this.isComposing = false;
+  this.clearTextareaPosition();
+
+  if (!waitForPropogation) {
+    // Cancel any delayed composition send requests and send the input immediately.
+    this.isSendingComposition = false;
+    var input = this.textarea.value.substring(this.compositionPosition.start, this.compositionPosition.end);
+    this.terminal.handler(input);
+  } else {
+    // Make a deep copy of the composition position here as a new compositionstart event may
+    // fire before the setTimeout executes.
+    var currentCompositionPosition = {
+      start: this.compositionPosition.start,
+      end: this.compositionPosition.end
+    };
+
+    // Since composition* events happen before the changes take place in the textarea on most
+    // browsers, use a setTimeout with 0ms time to allow the native compositionend event to
+    // complete. This ensures the correct character is retrieved, this solution was used
+    // because:
+    // - The compositionend event's data property is unreliable, at least on Chromium
+    // - The last compositionupdate event's data property does not always accurately describe
+    //   the character, a counter example being Korean where an ending consonsant can move to
+    //   the following character if the following input is a vowel.
+    var self = this;
+    this.isSendingComposition = true;
+    setTimeout(function () {
+      // Ensure that the input has not already been sent
+      if (self.isSendingComposition) {
+        self.isSendingComposition = false;
+        var input;
+        if (self.isComposing) {
+          // Use the end position to get the string if a new composition has started.
+          input = self.textarea.value.substring(currentCompositionPosition.start, currentCompositionPosition.end);
+        } else {
+          // Don't use the end position here in order to pick up any characters after the
+          // composition has finished, for example when typing a non-composition character
+          // (eg. 2) after a composition character.
+          input = self.textarea.value.substring(currentCompositionPosition.start);
+        }
+        self.terminal.handler(input);
+      }
+    }, 0);
+  }
+};
+
+/**
+ * Apply any changes made to the textarea after the current event chain is allowed to complete.
+ * This should be called when not currently composing but a keydown event with the "composition
+ * character" (229) is triggered, in order to allow non-composition text to be entered when an
+ * IME is active.
+ */
+CompositionHelper.prototype.handleAnyTextareaChanges = function () {
+  var oldValue = this.textarea.value;
+  var self = this;
+  setTimeout(function () {
+    // Ignore if a composition has started since the timeout
+    if (!self.isComposing) {
+      var newValue = self.textarea.value;
+      var diff = newValue.replace(oldValue, '');
+      if (diff.length > 0) {
+        self.terminal.handler(diff);
+      }
+    }
+  }, 0);
+};
+
+/**
+ * Positions the composition view on top of the cursor and the textarea just below it (so the
+ * IME helper dialog is positioned correctly).
+ */
+CompositionHelper.prototype.updateCompositionElements = function (dontRecurse) {
+  if (!this.isComposing) {
+    return;
+  }
+  var cursor = this.terminal.element.querySelector('.terminal-cursor');
+  if (cursor) {
+    this.compositionView.style.left = cursor.offsetLeft + 'px';
+    this.compositionView.style.top = cursor.offsetTop + 'px';
+    var compositionViewBounds = this.compositionView.getBoundingClientRect();
+    this.textarea.style.left = cursor.offsetLeft + compositionViewBounds.width + 'px';
+    this.textarea.style.top = cursor.offsetTop + cursor.offsetHeight + 'px';
+  }
+  if (!dontRecurse) {
+    setTimeout(this.updateCompositionElements.bind(this, true), 0);
+  }
+};
+
+/**
+ * Clears the textarea's position so that the cursor does not blink on IE.
+ * @private
+ */
+CompositionHelper.prototype.clearTextareaPosition = function () {
+  this.textarea.style.left = '';
+  this.textarea.style.top = '';
+};
+
+exports.CompositionHelper = CompositionHelper;
+
+},{}],2:[function(_dereq_,module,exports){
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+/**
+ * EventEmitter
+ */
+
+function EventEmitter() {
+  this._events = this._events || {};
+}
+
+EventEmitter.prototype.addListener = function (type, listener) {
+  this._events[type] = this._events[type] || [];
+  this._events[type].push(listener);
+};
+
+EventEmitter.prototype.on = EventEmitter.prototype.addListener;
+
+EventEmitter.prototype.removeListener = function (type, listener) {
+  if (!this._events[type]) return;
+
+  var obj = this._events[type],
+      i = obj.length;
+
+  while (i--) {
+    if (obj[i] === listener || obj[i].listener === listener) {
+      obj.splice(i, 1);
+      return;
+    }
+  }
+};
+
+EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
+
+EventEmitter.prototype.removeAllListeners = function (type) {
+  if (this._events[type]) delete this._events[type];
+};
+
+EventEmitter.prototype.once = function (type, listener) {
+  var self = this;
+  function on() {
+    var args = Array.prototype.slice.call(arguments);
+    this.removeListener(type, on);
+    return listener.apply(this, args);
+  }
+  on.listener = listener;
+  return this.on(type, on);
+};
+
+EventEmitter.prototype.emit = function (type) {
+  if (!this._events[type]) return;
+
+  var args = Array.prototype.slice.call(arguments, 1),
+      obj = this._events[type],
+      l = obj.length,
+      i = 0;
+
+  for (; i < l; i++) {
+    obj[i].apply(this, args);
+  }
+};
+
+EventEmitter.prototype.listeners = function (type) {
+  return this._events[type] = this._events[type] || [];
+};
+
+exports.EventEmitter = EventEmitter;
+
+},{}],3:[function(_dereq_,module,exports){
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+/**
+ * xterm.js: xterm, in the browser
+ * Copyright (c) 2016, SourceLair Limited <www.sourcelair.com> (MIT License)
+ */
+
+/**
+ * Represents the viewport of a terminal, the visible area within the larger buffer of output.
+ * Logic for the virtual scroll bar is included in this object.
+ * @param {Terminal} terminal The Terminal object.
+ * @param {HTMLElement} viewportElement The DOM element acting as the viewport
+ * @param {HTMLElement} charMeasureElement A DOM element used to measure the character size of
+ *   the terminal.
+ */
+function Viewport(terminal, viewportElement, scrollArea, charMeasureElement) {
+  this.terminal = terminal;
+  this.viewportElement = viewportElement;
+  this.scrollArea = scrollArea;
+  this.charMeasureElement = charMeasureElement;
+  this.currentRowHeight = 0;
+  this.lastRecordedBufferLength = 0;
+  this.lastRecordedViewportHeight = 0;
+
+  this.terminal.on('scroll', this.syncScrollArea.bind(this));
+  this.terminal.on('resize', this.syncScrollArea.bind(this));
+  this.viewportElement.addEventListener('scroll', this.onScroll.bind(this));
+
+  this.syncScrollArea();
+}
+
+/**
+ * Refreshes row height, setting line-height, viewport height and scroll area height if
+ * necessary.
+ * @param {number|undefined} charSize A character size measurement bounding rect object, if it
+ *   doesn't exist it will be created.
+ */
+Viewport.prototype.refresh = function (charSize) {
+  var size = charSize || this.charMeasureElement.getBoundingClientRect();
+  if (size.height > 0) {
+    var rowHeightChanged = size.height !== this.currentRowHeight;
+    if (rowHeightChanged) {
+      this.currentRowHeight = size.height;
+      this.viewportElement.style.lineHeight = size.height + 'px';
+      this.terminal.rowContainer.style.lineHeight = size.height + 'px';
+    }
+    var viewportHeightChanged = this.lastRecordedViewportHeight !== this.terminal.rows;
+    if (rowHeightChanged || viewportHeightChanged) {
+      this.lastRecordedViewportHeight = this.terminal.rows;
+      this.viewportElement.style.height = size.height * this.terminal.rows + 'px';
+    }
+    this.scrollArea.style.height = size.height * this.lastRecordedBufferLength + 'px';
+  }
+};
+
+/**
+ * Updates dimensions and synchronizes the scroll area if necessary.
+ */
+Viewport.prototype.syncScrollArea = function () {
+  if (this.lastRecordedBufferLength !== this.terminal.lines.length) {
+    // If buffer height changed
+    this.lastRecordedBufferLength = this.terminal.lines.length;
+    this.refresh();
+  } else if (this.lastRecordedViewportHeight !== this.terminal.rows) {
+    // If viewport height changed
+    this.refresh();
+  } else {
+    // If size has changed, refresh viewport
+    var size = this.charMeasureElement.getBoundingClientRect();
+    if (size.height !== this.currentRowHeight) {
+      this.refresh(size);
+    }
+  }
+
+  // Sync scrollTop
+  var scrollTop = this.terminal.ydisp * this.currentRowHeight;
+  if (this.viewportElement.scrollTop !== scrollTop) {
+    this.viewportElement.scrollTop = scrollTop;
+  }
+};
+
+/**
+ * Handles scroll events on the viewport, calculating the new viewport and requesting the
+ * terminal to scroll to it.
+ * @param {Event} ev The scroll event.
+ */
+Viewport.prototype.onScroll = function (ev) {
+  var newRow = Math.round(this.viewportElement.scrollTop / this.currentRowHeight);
+  var diff = newRow - this.terminal.ydisp;
+  this.terminal.scrollDisp(diff, true);
+};
+
+/**
+ * Handles mouse wheel events by adjusting the viewport's scrollTop and delegating the actual
+ * scrolling to `onScroll`, this event needs to be attached manually by the consumer of
+ * `Viewport`.
+ * @param {WheelEvent} ev The mouse wheel event.
+ */
+Viewport.prototype.onWheel = function (ev) {
+  if (ev.deltaY === 0) {
+    // Do nothing if it's not a vertical scroll event
+    return;
+  }
+  // Fallback to WheelEvent.DOM_DELTA_PIXEL
+  var multiplier = 1;
+  if (ev.deltaMode === WheelEvent.DOM_DELTA_LINE) {
+    multiplier = this.currentRowHeight;
+  } else if (ev.deltaMode === WheelEvent.DOM_DELTA_PAGE) {
+    multiplier = this.currentRowHeight * this.terminal.rows;
+  }
+  this.viewportElement.scrollTop += ev.deltaY * multiplier;
+  // Prevent the page from scrolling when the terminal scrolls
+  ev.preventDefault();
+};
+
+exports.Viewport = Viewport;
+
+},{}],4:[function(_dereq_,module,exports){
+(function (__dirname){
+'use strict';var _typeof=typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"?function(obj){return typeof obj;}:function(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol?"symbol":typeof obj;};/**
+ * xterm.js: xterm, in the browser
+ * Copyright (c) 2014, SourceLair Limited <www.sourcelair.com> (MIT License)
+ * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
+ * https://github.com/chjj/term.js
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * Originally forked from (with the author's permission):
+ *   Fabrice Bellard's javascript vt100 for jslinux:
+ *   http://bellard.org/jslinux/
+ *   Copyright (c) 2011 Fabrice Bellard
+ *   The original design remains. The terminal itself
+ *   has been extended to include xterm CSI codes, among
+ *   other features.
+ */var _CompositionHelper=_dereq_('./CompositionHelper.js');var _EventEmitter=_dereq_('./EventEmitter.js');var _Viewport=_dereq_('./Viewport.js');/**
+ * Terminal Emulation References:
+ *   http://vt100.net/
+ *   http://invisible-island.net/xterm/ctlseqs/ctlseqs.txt
+ *   http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
+ *   http://invisible-island.net/vttest/
+ *   http://www.inwap.com/pdp10/ansicode.txt
+ *   http://linux.die.net/man/4/console_codes
+ *   http://linux.die.net/man/7/urxvt
+ */// Let it work inside Node.js for automated testing purposes.
+var document=typeof window!='undefined'?window.document:null;/**
+ * States
+ */var normal=0,escaped=1,csi=2,osc=3,charset=4,dcs=5,ignore=6;/**
+ * Terminal
+ *//**
+ * Creates a new `Terminal` object.
+ *
+ * @param {object} options An object containing a set of options, the available options are:
+ *   - cursorBlink (boolean): Whether the terminal cursor blinks
+ *
+ * @public
+ * @class Xterm Xterm
+ * @alias module:xterm/src/xterm
+ */function Terminal(options){var self=this;if(!(this instanceof Terminal)){return new Terminal(arguments[0],arguments[1],arguments[2]);}self.cancel=Terminal.cancel;_EventEmitter.EventEmitter.call(this);if(typeof options==='number'){options={cols:arguments[0],rows:arguments[1],handler:arguments[2]};}options=options||{};Object.keys(Terminal.defaults).forEach(function(key){if(options[key]==null){options[key]=Terminal.options[key];if(Terminal[key]!==Terminal.defaults[key]){options[key]=Terminal[key];}}self[key]=options[key];});if(options.colors.length===8){options.colors=options.colors.concat(Terminal._colors.slice(8));}else if(options.colors.length===16){options.colors=options.colors.concat(Terminal._colors.slice(16));}else if(options.colors.length===10){options.colors=options.colors.slice(0,-2).concat(Terminal._colors.slice(8,-2),options.colors.slice(-2));}else if(options.colors.length===18){options.colors=options.colors.concat(Terminal._colors.slice(16,-2),options.colors.slice(-2));}this.colors=options.colors;this.options=options;// this.context = options.context || window;
+// this.document = options.document || document;
+this.parent=options.body||options.parent||(document?document.getElementsByTagName('body')[0]:null);this.cols=options.cols||options.geometry[0];this.rows=options.rows||options.geometry[1];if(options.handler){this.on('data',options.handler);}/**
+   * The scroll position of the y cursor, ie. ybase + y = the y position within the entire
+   * buffer
+   */this.ybase=0;/**
+   * The scroll position of the viewport
+   */this.ydisp=0;/**
+   * The cursor's x position after ybase
+   */this.x=0;/**
+   * The cursor's y position after ybase
+   */this.y=0;/**
+   * Used to debounce the refresh function
+   */this.isRefreshing=false;/**
+   * Whether there is a full terminal refresh queued
+   */this.cursorState=0;this.cursorHidden=false;this.convertEol;this.state=0;this.queue='';this.scrollTop=0;this.scrollBottom=this.rows-1;this.customKeydownHandler=null;// modes
+this.applicationKeypad=false;this.applicationCursor=false;this.originMode=false;this.insertMode=false;this.wraparoundMode=true;// defaults: xterm - true, vt100 - false
+this.normal=null;// charset
+this.charset=null;this.gcharset=null;this.glevel=0;this.charsets=[null];// mouse properties
+this.decLocator;this.x10Mouse;this.vt200Mouse;this.vt300Mouse;this.normalMouse;this.mouseEvents;this.sendFocus;this.utfMouse;this.sgrMouse;this.urxvtMouse;// misc
+this.element;this.children;this.refreshStart;this.refreshEnd;this.savedX;this.savedY;this.savedCols;// stream
+this.readable=true;this.writable=true;this.defAttr=0<<18|257<<9|256<<0;this.curAttr=this.defAttr;this.params=[];this.currentParam=0;this.prefix='';this.postfix='';// leftover surrogate high from previous write invocation
+this.surrogate_high='';/**
+   * An array of all lines in the entire buffer, including the prompt. The lines are array of
+   * characters which are 2-length arrays where [0] is an attribute and [1] is the character.
+   */this.lines=[];var i=this.rows;while(i--){this.lines.push(this.blankLine());}this.tabs;this.setupStops();}inherits(Terminal,_EventEmitter.EventEmitter);/**
+ * back_color_erase feature for xterm.
+ */Terminal.prototype.eraseAttr=function(){// if (this.is('screen')) return this.defAttr;
+return this.defAttr&~0x1ff|this.curAttr&0x1ff;};/**
+ * Colors
+ */// Colors 0-15
+Terminal.tangoColors=[// dark:
+'#2e3436','#cc0000','#4e9a06','#c4a000','#3465a4','#75507b','#06989a','#d3d7cf',// bright:
+'#555753','#ef2929','#8ae234','#fce94f','#729fcf','#ad7fa8','#34e2e2','#eeeeec'];// Colors 0-15 + 16-255
+// Much thanks to TooTallNate for writing this.
+Terminal.colors=function(){var colors=Terminal.tangoColors.slice(),r=[0x00,0x5f,0x87,0xaf,0xd7,0xff],i;// 16-231
+i=0;for(;i<216;i++){out(r[i/36%6|0],r[i/6%6|0],r[i%6]);}// 232-255 (grey)
+i=0;for(;i<24;i++){r=8+i*10;out(r,r,r);}function out(r,g,b){colors.push('#'+hex(r)+hex(g)+hex(b));}function hex(c){c=c.toString(16);return c.length<2?'0'+c:c;}return colors;}();Terminal._colors=Terminal.colors.slice();Terminal.vcolors=function(){var out=[],colors=Terminal.colors,i=0,color;for(;i<256;i++){color=parseInt(colors[i].substring(1),16);out.push([color>>16&0xff,color>>8&0xff,color&0xff]);}return out;}();/**
+ * Options
+ */Terminal.defaults={colors:Terminal.colors,theme:'default',convertEol:false,termName:'xterm',geometry:[80,24],cursorBlink:false,visualBell:false,popOnBell:false,scrollback:1000,screenKeys:false,debug:false,cancelEvents:false// programFeatures: false,
+// focusKeys: false,
+};Terminal.options={};Terminal.focus=null;each(keys(Terminal.defaults),function(key){Terminal[key]=Terminal.defaults[key];Terminal.options[key]=Terminal.defaults[key];});/**
+ * Focus the terminal. Delegates focus handling to the terminal's DOM element.
+ */Terminal.prototype.focus=function(){return this.textarea.focus();};/**
+ * Retrieves an option's value from the terminal.
+ * @param {string} key The option key.
+ */Terminal.prototype.getOption=function(key,value){if(!(key in Terminal.defaults)){throw new Error('No option with key "'+key+'"');}if(typeof this.options[key]!=='undefined'){return this.options[key];}return this[key];};/**
+ * Sets an option on the terminal.
+ * @param {string} key The option key.
+ * @param {string} value The option value.
+ */Terminal.prototype.setOption=function(key,value){if(!(key in Terminal.defaults)){throw new Error('No option with key "'+key+'"');}this[key]=value;this.options[key]=value;};/**
+ * Binds the desired focus behavior on a given terminal object.
+ *
+ * @static
+ */Terminal.bindFocus=function(term){on(term.textarea,'focus',function(ev){if(term.sendFocus){term.send('\x1b[I');}term.element.classList.add('focus');term.showCursor();Terminal.focus=term;term.emit('focus',{terminal:term});});};/**
+ * Blur the terminal. Delegates blur handling to the terminal's DOM element.
+ */Terminal.prototype.blur=function(){return this.textarea.blur();};/**
+ * Binds the desired blur behavior on a given terminal object.
+ *
+ * @static
+ */Terminal.bindBlur=function(term){on(term.textarea,'blur',function(ev){term.refresh(term.y,term.y);if(term.sendFocus){term.send('\x1b[O');}term.element.classList.remove('focus');Terminal.focus=null;term.emit('blur',{terminal:term});});};/**
+ * Initialize default behavior
+ */Terminal.prototype.initGlobal=function(){Terminal.bindPaste(this);Terminal.bindKeys(this);Terminal.bindCopy(this);Terminal.bindFocus(this);Terminal.bindBlur(this);};/**
+ * Bind to paste event and allow both keyboard and right-click pasting, without having the
+ * contentEditable value set to true.
+ */Terminal.bindPaste=function(term){on([term.textarea,term.element],'paste',function(ev){ev.stopPropagation();if(ev.clipboardData){var text=ev.clipboardData.getData('text/plain');term.handler(text);term.textarea.value='';return term.cancel(ev);}});};/**
+ * Prepares text copied from terminal selection, to be saved in the clipboard by:
+ *   1. stripping all trailing white spaces
+ *   2. converting all non-breaking spaces to regular spaces
+ * @param {string} text The copied text that needs processing for storing in clipboard
+ * @returns {string}
+ * @static
+ */Terminal.prepareCopiedTextForClipboard=function(text){var space=String.fromCharCode(32),nonBreakingSpace=String.fromCharCode(160),allNonBreakingSpaces=new RegExp(nonBreakingSpace,'g'),processedText=text.split('\n').map(function(line){/**
+         * Strip all trailing white spaces and convert all non-breaking spaces to regular
+         * spaces.
+         */var processedLine=line.replace(/\s+$/g,'').replace(allNonBreakingSpaces,space);return processedLine;}).join('\n');return processedText;};/**
+ * Apply key handling to the terminal
+ */Terminal.bindKeys=function(term){on(term.element,'keydown',function(ev){if(document.activeElement!=this){return;}term.keyDown(ev);},true);on(term.element,'keypress',function(ev){if(document.activeElement!=this){return;}term.keyPress(ev);},true);on(term.element,'keyup',term.focus.bind(term));on(term.textarea,'keydown',function(ev){term.keyDown(ev);},true);on(term.textarea,'keypress',function(ev){term.keyPress(ev);// Truncate the textarea's value, since it is not needed
+this.value='';},true);on(term.textarea,'compositionstart',term.compositionHelper.compositionstart.bind(term.compositionHelper));on(term.textarea,'compositionupdate',term.compositionHelper.compositionupdate.bind(term.compositionHelper));on(term.textarea,'compositionend',term.compositionHelper.compositionend.bind(term.compositionHelper));term.on('refresh',term.compositionHelper.updateCompositionElements.bind(term.compositionHelper));};/**
+ * Binds copy functionality to the given terminal.
+ * @static
+ */Terminal.bindCopy=function(term){on(term.element,'copy',function(ev){return;// temporary
+});};/**
+ * Insert the given row to the terminal or produce a new one
+ * if no row argument is passed. Return the inserted row.
+ * @param {HTMLElement} row (optional) The row to append to the terminal.
+ */Terminal.prototype.insertRow=function(row){if((typeof row==='undefined'?'undefined':_typeof(row))!='object'){row=document.createElement('div');}this.rowContainer.appendChild(row);this.children.push(row);return row;};/**
+ * Opens the terminal within an element.
+ *
+ * @param {HTMLElement} parent The element to create the terminal within.
+ */Terminal.prototype.open=function(parent){var self=this,i=0,div;this.parent=parent||this.parent;if(!this.parent){throw new Error('Terminal requires a parent element.');}// Grab global elements
+this.context=this.parent.ownerDocument.defaultView;this.document=this.parent.ownerDocument;this.body=this.document.getElementsByTagName('body')[0];// Parse User-Agent
+if(this.context.navigator&&this.context.navigator.userAgent){this.isMSIE=!!~this.context.navigator.userAgent.indexOf('MSIE');}// Find the users platform. We use this to interpret the meta key
+// and ISO third level shifts.
+// http://stackoverflow.com/q/19877924/577598
+if(this.context.navigator&&this.context.navigator.platform){this.isMac=contains(this.context.navigator.platform,['Macintosh','MacIntel','MacPPC','Mac68K']);this.isIpad=this.context.navigator.platform==='iPad';this.isIphone=this.context.navigator.platform==='iPhone';this.isMSWindows=contains(this.context.navigator.platform,['Windows','Win16','Win32','WinCE']);}//Create main element container
+this.element=this.document.createElement('div');this.element.classList.add('terminal');this.element.classList.add('xterm');this.element.classList.add('xterm-theme-'+this.theme);this.element.style.height;this.element.setAttribute('tabindex',0);this.viewportElement=document.createElement('div');this.viewportElement.classList.add('xterm-viewport');this.element.appendChild(this.viewportElement);this.viewportScrollArea=document.createElement('div');this.viewportScrollArea.classList.add('xterm-scroll-area');this.viewportElement.appendChild(this.viewportScrollArea);// Create the container that will hold the lines of the terminal and then
+// produce the lines the lines.
+this.rowContainer=document.createElement('div');this.rowContainer.classList.add('xterm-rows');this.element.appendChild(this.rowContainer);this.children=[];// Create the container that will hold helpers like the textarea for
+// capturing DOM Events. Then produce the helpers.
+this.helperContainer=document.createElement('div');this.helperContainer.classList.add('xterm-helpers');// TODO: This should probably be inserted once it's filled to prevent an additional layout
+this.element.appendChild(this.helperContainer);this.textarea=document.createElement('textarea');this.textarea.classList.add('xterm-helper-textarea');this.textarea.setAttribute('autocorrect','off');this.textarea.setAttribute('autocapitalize','off');this.textarea.setAttribute('spellcheck','false');this.textarea.tabIndex=0;this.textarea.addEventListener('focus',function(){self.emit('focus',{terminal:self});});this.textarea.addEventListener('blur',function(){self.emit('blur',{terminal:self});});this.helperContainer.appendChild(this.textarea);this.compositionView=document.createElement('div');this.compositionView.classList.add('composition-view');this.compositionHelper=new _CompositionHelper.CompositionHelper(this.textarea,this.compositionView,this);this.helperContainer.appendChild(this.compositionView);this.charMeasureElement=document.createElement('div');this.charMeasureElement.classList.add('xterm-char-measure-element');this.charMeasureElement.innerHTML='W';this.helperContainer.appendChild(this.charMeasureElement);for(;i<this.rows;i++){this.insertRow();}this.parent.appendChild(this.element);this.viewport=new _Viewport.Viewport(this,this.viewportElement,this.viewportScrollArea,this.charMeasureElement);// Draw the screen.
+this.refresh(0,this.rows-1);// Initialize global actions that
+// need to be taken on the document.
+this.initGlobal();// Ensure there is a Terminal.focus.
+this.focus();on(this.element,'click',function(){var selection=document.getSelection(),collapsed=selection.isCollapsed,isRange=typeof collapsed=='boolean'?!collapsed:selection.type=='Range';if(!isRange){self.focus();}});// Listen for mouse events and translate
+// them into terminal mouse protocols.
+this.bindMouse();// Figure out whether boldness affects
+// the character width of monospace fonts.
+if(Terminal.brokenBold==null){Terminal.brokenBold=isBoldBroken(this.document);}this.emit('open');};/**
+ * Attempts to load an add-on using CommonJS or RequireJS (whichever is available).
+ * @param {string} addon The name of the addon to load
+ * @static
+ */Terminal.loadAddon=function(addon,callback){if((typeof exports==='undefined'?'undefined':_typeof(exports))==='object'&&(typeof module==='undefined'?'undefined':_typeof(module))==='object'){// CommonJS
+return _dereq_(__dirname+'/../addons/'+addon);}else if(typeof define=='function'){// RequireJS
+return _dereq_(['../addons/'+addon+'/'+addon],callback);}else{console.error('Cannot load a module without a CommonJS or RequireJS environment.');return false;}};/**
+ * XTerm mouse events
+ * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking
+ * To better understand these
+ * the xterm code is very helpful:
+ * Relevant files:
+ *   button.c, charproc.c, misc.c
+ * Relevant functions in xterm/button.c:
+ *   BtnCode, EmitButtonCode, EditorButton, SendMousePosition
+ */Terminal.prototype.bindMouse=function(){var el=this.element,self=this,pressed=32;// mouseup, mousedown, wheel
+// left click: ^[[M 3<^[[M#3<
+// wheel up: ^[[M`3>
+function sendButton(ev){var button,pos;// get the xterm-style button
+button=getButton(ev);// get mouse coordinates
+pos=getCoords(ev);if(!pos)return;sendEvent(button,pos);switch(ev.overrideType||ev.type){case'mousedown':pressed=button;break;case'mouseup':// keep it at the left
+// button, just in case.
+pressed=32;break;case'wheel':// nothing. don't
+// interfere with
+// `pressed`.
+break;}}// motion example of a left click:
+// ^[[M 3<^[[M@4<^[[M@5<^[[M@6<^[[M@7<^[[M#7<
+function sendMove(ev){var button=pressed,pos;pos=getCoords(ev);if(!pos)return;// buttons marked as motions
+// are incremented by 32
+button+=32;sendEvent(button,pos);}// encode button and
+// position to characters
+function encode(data,ch){if(!self.utfMouse){if(ch===255)return data.push(0);if(ch>127)ch=127;data.push(ch);}else{if(ch===2047)return data.push(0);if(ch<127){data.push(ch);}else{if(ch>2047)ch=2047;data.push(0xC0|ch>>6);data.push(0x80|ch&0x3F);}}}// send a mouse event:
+// regular/utf8: ^[[M Cb Cx Cy
+// urxvt: ^[[ Cb ; Cx ; Cy M
+// sgr: ^[[ Cb ; Cx ; Cy M/m
+// vt300: ^[[ 24(1/3/5)~ [ Cx , Cy ] \r
+// locator: CSI P e ; P b ; P r ; P c ; P p & w
+function sendEvent(button,pos){// self.emit('mouse', {
+//   x: pos.x - 32,
+//   y: pos.x - 32,
+//   button: button
+// });
+if(self.vt300Mouse){// NOTE: Unstable.
+// http://www.vt100.net/docs/vt3xx-gp/chapter15.html
+button&=3;pos.x-=32;pos.y-=32;var data='\x1b[24';if(button===0)data+='1';else if(button===1)data+='3';else if(button===2)data+='5';else if(button===3)return;else data+='0';data+='~['+pos.x+','+pos.y+']\r';self.send(data);return;}if(self.decLocator){// NOTE: Unstable.
+button&=3;pos.x-=32;pos.y-=32;if(button===0)button=2;else if(button===1)button=4;else if(button===2)button=6;else if(button===3)button=3;self.send('\x1b['+button+';'+(button===3?4:0)+';'+pos.y+';'+pos.x+';'+(pos.page||0)+'&w');return;}if(self.urxvtMouse){pos.x-=32;pos.y-=32;pos.x++;pos.y++;self.send('\x1b['+button+';'+pos.x+';'+pos.y+'M');return;}if(self.sgrMouse){pos.x-=32;pos.y-=32;self.send('\x1b[<'+((button&3)===3?button&~3:button)+';'+pos.x+';'+pos.y+((button&3)===3?'m':'M'));return;}var data=[];encode(data,button);encode(data,pos.x);encode(data,pos.y);self.send('\x1b[M'+String.fromCharCode.apply(String,data));}function getButton(ev){var button,shift,meta,ctrl,mod;// two low bits:
+// 0 = left
+// 1 = middle
+// 2 = right
+// 3 = release
+// wheel up/down:
+// 1, and 2 - with 64 added
+switch(ev.overrideType||ev.type){case'mousedown':button=ev.button!=null?+ev.button:ev.which!=null?ev.which-1:null;if(self.isMSIE){button=button===1?0:button===4?1:button;}break;case'mouseup':button=3;break;case'DOMMouseScroll':button=ev.detail<0?64:65;break;case'wheel':button=ev.wheelDeltaY>0?64:65;break;}// next three bits are the modifiers:
+// 4 = shift, 8 = meta, 16 = control
+shift=ev.shiftKey?4:0;meta=ev.metaKey?8:0;ctrl=ev.ctrlKey?16:0;mod=shift|meta|ctrl;// no mods
+if(self.vt200Mouse){// ctrl only
+mod&=ctrl;}else if(!self.normalMouse){mod=0;}// increment to SP
+button=32+(mod<<2)+button;return button;}// mouse coordinates measured in cols/rows
+function getCoords(ev){var x,y,w,h,el;// ignore browsers without pageX for now
+if(ev.pageX==null)return;x=ev.pageX;y=ev.pageY;el=self.element;// should probably check offsetParent
+// but this is more portable
+while(el&&el!==self.document.documentElement){x-=el.offsetLeft;y-=el.offsetTop;el='offsetParent'in el?el.offsetParent:el.parentNode;}// convert to cols/rows
+w=self.element.clientWidth;h=self.element.clientHeight;x=Math.ceil(x/w*self.cols);y=Math.ceil(y/h*self.rows);// be sure to avoid sending
+// bad positions to the program
+if(x<0)x=0;if(x>self.cols)x=self.cols;if(y<0)y=0;if(y>self.rows)y=self.rows;// xterm sends raw bytes and
+// starts at 32 (SP) for each.
+x+=32;y+=32;return{x:x,y:y,type:'wheel'};}on(el,'mousedown',function(ev){if(!self.mouseEvents)return;// send the button
+sendButton(ev);// ensure focus
+self.focus();// fix for odd bug
+//if (self.vt200Mouse && !self.normalMouse) {
+if(self.vt200Mouse){ev.overrideType='mouseup';sendButton(ev);return self.cancel(ev);}// bind events
+if(self.normalMouse)on(self.document,'mousemove',sendMove);// x10 compatibility mode can't send button releases
+if(!self.x10Mouse){on(self.document,'mouseup',function up(ev){sendButton(ev);if(self.normalMouse)off(self.document,'mousemove',sendMove);off(self.document,'mouseup',up);return self.cancel(ev);});}return self.cancel(ev);});//if (self.normalMouse) {
+//  on(self.document, 'mousemove', sendMove);
+//}
+on(el,'wheel',function(ev){if(!self.mouseEvents)return;if(self.x10Mouse||self.vt300Mouse||self.decLocator)return;sendButton(ev);return self.cancel(ev);});// allow wheel scrolling in
+// the shell for example
+on(el,'wheel',function(ev){if(self.mouseEvents)return;self.viewport.onWheel(ev);return self.cancel(ev);});};/**
+ * Destroys the terminal.
+ */Terminal.prototype.destroy=function(){this.readable=false;this.writable=false;this._events={};this.handler=function(){};this.write=function(){};if(this.element.parentNode){this.element.parentNode.removeChild(this.element);}//this.emit('close');
+};/**
+ * Flags used to render terminal text properly
+ */Terminal.flags={BOLD:1,UNDERLINE:2,BLINK:4,INVERSE:8,INVISIBLE:16};/**
+ * Refreshes (re-renders) terminal content within two rows (inclusive)
+ *
+ * Rendering Engine:
+ *
+ * In the screen buffer, each character is stored as a an array with a character
+ * and a 32-bit integer:
+ *   - First value: a utf-16 character.
+ *   - Second value:
+ *   - Next 9 bits: background color (0-511).
+ *   - Next 9 bits: foreground color (0-511).
+ *   - Next 14 bits: a mask for misc. flags:
+ *     - 1=bold
+ *     - 2=underline
+ *     - 4=blink
+ *     - 8=inverse
+ *     - 16=invisible
+ *
+ * @param {number} start The row to start from (between 0 and terminal's height terminal - 1)
+ * @param {number} end The row to end at (between fromRow and terminal's height terminal - 1)
+ * @param {boolean} queue Whether the refresh should ran right now or be queued
+ */Terminal.prototype.refresh=function(start,end,queue){var self=this;// queue defaults to true
+queue=typeof queue=='undefined'?true:queue;/**
+   * The refresh queue allows refresh to execute only approximately 30 times a second. For
+   * commands that pass a significant amount of output to the write function, this prevents the
+   * terminal from maxing out the CPU and making the UI unresponsive. While commands can still
+   * run beyond what they do on the terminal, it is far better with a debounce in place as
+   * every single terminal manipulation does not need to be constructed in the DOM.
+   *
+   * A side-effect of this is that it makes ^C to interrupt a process seem more responsive.
+   */if(queue){// If refresh should be queued, order the refresh and return.
+if(this._refreshIsQueued){// If a refresh has already been queued, just order a full refresh next
+this._fullRefreshNext=true;}else{setTimeout(function(){self.refresh(start,end,false);},34);this._refreshIsQueued=true;}return;}// If refresh should be run right now (not be queued), release the lock
+this._refreshIsQueued=false;// If multiple refreshes were requested, make a full refresh.
+if(this._fullRefreshNext){start=0;end=this.rows-1;this._fullRefreshNext=false;// reset lock
+}var x,y,i,line,out,ch,ch_width,width,data,attr,bg,fg,flags,row,parent,focused=document.activeElement;// If this is a big refresh, remove the terminal rows from the DOM for faster calculations
+if(end-start>=this.rows/2){parent=this.element.parentNode;if(parent){this.element.removeChild(this.rowContainer);}}width=this.cols;y=start;if(end>=this.rows.length){this.log('`end` is too large. Most likely a bad CSR.');end=this.rows.length-1;}for(;y<=end;y++){row=y+this.ydisp;line=this.lines[row];out='';if(this.y===y-(this.ybase-this.ydisp)&&this.cursorState&&!this.cursorHidden){x=this.x;}else{x=-1;}attr=this.defAttr;i=0;for(;i<width;i++){data=line[i][0];ch=line[i][1];ch_width=line[i][2];if(!ch_width)continue;if(i===x)data=-1;if(data!==attr){if(attr!==this.defAttr){out+='</span>';}if(data!==this.defAttr){if(data===-1){out+='<span class="reverse-video terminal-cursor';if(this.cursorBlink){out+=' blinking';}out+='">';}else{var classNames=[];bg=data&0x1ff;fg=data>>9&0x1ff;flags=data>>18;if(flags&Terminal.flags.BOLD){if(!Terminal.brokenBold){classNames.push('xterm-bold');}// See: XTerm*boldColors
+if(fg<8)fg+=8;}if(flags&Terminal.flags.UNDERLINE){classNames.push('xterm-underline');}if(flags&Terminal.flags.BLINK){classNames.push('xterm-blink');}// If inverse flag is on, then swap the foreground and background variables.
+if(flags&Terminal.flags.INVERSE){/* One-line variable swap in JavaScript: http://stackoverflow.com/a/16201730 */bg=[fg,fg=bg][0];// Should inverse just be before the
+// above boldColors effect instead?
+if(flags&1&&fg<8)fg+=8;}if(flags&Terminal.flags.INVISIBLE){classNames.push('xterm-hidden');}/**
+             * Weird situation: Invert flag used black foreground and white background results
+             * in invalid background color, positioned at the 256 index of the 256 terminal
+             * color map. Pin the colors manually in such a case.
+             *
+             * Source: https://github.com/sourcelair/xterm.js/issues/57
+             */if(flags&Terminal.flags.INVERSE){if(bg==257){bg=15;}if(fg==256){fg=0;}}if(bg<256){classNames.push('xterm-bg-color-'+bg);}if(fg<256){classNames.push('xterm-color-'+fg);}out+='<span';if(classNames.length){out+=' class="'+classNames.join(' ')+'"';}out+='>';}}}switch(ch){case'&':out+='&amp;';break;case'<':out+='&lt;';break;case'>':out+='&gt;';break;default:if(ch<=' '){out+='&nbsp;';}else{out+=ch;}break;}attr=data;}if(attr!==this.defAttr){out+='</span>';}this.children[y].innerHTML=out;}if(parent){this.element.appendChild(this.rowContainer);}this.emit('refresh',{element:this.element,start:start,end:end});};/**
+ * Display the cursor element
+ */Terminal.prototype.showCursor=function(){if(!this.cursorState){this.cursorState=1;this.refresh(this.y,this.y);}};/**
+ * Scroll the terminal
+ */Terminal.prototype.scroll=function(){var row;if(++this.ybase===this.scrollback){this.ybase=this.ybase/2|0;this.lines=this.lines.slice(-(this.ybase+this.rows)+1);}this.ydisp=this.ybase;// last line
+row=this.ybase+this.rows-1;// subtract the bottom scroll region
+row-=this.rows-1-this.scrollBottom;if(row===this.lines.length){// potential optimization:
+// pushing is faster than splicing
+// when they amount to the same
+// behavior.
+this.lines.push(this.blankLine());}else{// add our new line
+this.lines.splice(row,0,this.blankLine());}if(this.scrollTop!==0){if(this.ybase!==0){this.ybase--;this.ydisp=this.ybase;}this.lines.splice(this.ybase+this.scrollTop,1);}// this.maxRange();
+this.updateRange(this.scrollTop);this.updateRange(this.scrollBottom);this.emit('scroll',this.ydisp);};/**
+ * Scroll the display of the terminal
+ * @param {number} disp The number of lines to scroll down (negatives scroll up).
+ * @param {boolean} suppressScrollEvent Don't emit the scroll event as scrollDisp. This is used
+ * to avoid unwanted events being handled by the veiwport when the event was triggered from the
+ * viewport originally.
+ */Terminal.prototype.scrollDisp=function(disp,suppressScrollEvent){this.ydisp+=disp;if(this.ydisp>this.ybase){this.ydisp=this.ybase;}else if(this.ydisp<0){this.ydisp=0;}if(!suppressScrollEvent){this.emit('scroll',this.ydisp);}this.refresh(0,this.rows-1);};/**
+ * Writes text to the terminal.
+ * @param {string} text The text to write to the terminal.
+ */Terminal.prototype.write=function(data){var l=data.length,i=0,j,cs,ch,code,low,ch_width,row;this.refreshStart=this.y;this.refreshEnd=this.y;if(this.ybase!==this.ydisp){this.ydisp=this.ybase;this.emit('scroll',this.ydisp);this.maxRange();}// apply leftover surrogate high from last write
+if(this.surrogate_high){data=this.surrogate_high+data;this.surrogate_high='';}for(;i<l;i++){ch=data[i];// FIXME: higher chars than 0xa0 are not allowed in escape sequences
+//        --> maybe move to default
+code=data.charCodeAt(i);if(0xD800<=code&&code<=0xDBFF){// we got a surrogate high
+// get surrogate low (next 2 bytes)
+low=data.charCodeAt(i+1);if(isNaN(low)){// end of data stream, save surrogate high
+this.surrogate_high=ch;continue;}code=(code-0xD800)*0x400+(low-0xDC00)+0x10000;ch+=data.charAt(i+1);}// surrogate low - already handled above
+if(0xDC00<=code&&code<=0xDFFF)continue;switch(this.state){case normal:switch(ch){case'\x07':this.bell();break;// '\n', '\v', '\f'
+case'\n':case'\x0b':case'\x0c':if(this.convertEol){this.x=0;}this.y++;if(this.y>this.scrollBottom){this.y--;this.scroll();}break;// '\r'
+case'\r':this.x=0;break;// '\b'
+case'\x08':if(this.x>0){this.x--;}break;// '\t'
+case'\t':this.x=this.nextStop();break;// shift out
+case'\x0e':this.setgLevel(1);break;// shift in
+case'\x0f':this.setgLevel(0);break;// '\e'
+case'\x1b':this.state=escaped;break;default:// ' '
+// calculate print space
+// expensive call, therefore we save width in line buffer
+ch_width=wcwidth(code);if(ch>=' '){if(this.charset&&this.charset[ch]){ch=this.charset[ch];}row=this.y+this.ybase;// insert combining char in last cell
+// FIXME: needs handling after cursor jumps
+if(!ch_width&&this.x){// dont overflow left
+if(this.lines[row][this.x-1]){if(!this.lines[row][this.x-1][2]){// found empty cell after fullwidth, need to go 2 cells back
+if(this.lines[row][this.x-2])this.lines[row][this.x-2][1]+=ch;}else{this.lines[row][this.x-1][1]+=ch;}this.updateRange(this.y);}break;}// goto next line if ch would overflow
+// TODO: needs a global min terminal width of 2
+if(this.x+ch_width-1>=this.cols){// autowrap - DECAWM
+if(this.wraparoundMode){this.x=0;this.y++;if(this.y>this.scrollBottom){this.y--;this.scroll();}}else{this.x=this.cols-1;if(ch_width===2)// FIXME: check for xterm behavior
+continue;}}row=this.y+this.ybase;// insert mode: move characters to right
+if(this.insertMode){// do this twice for a fullwidth char
+for(var moves=0;moves<ch_width;++moves){// remove last cell, if it's width is 0
+// we have to adjust the second last cell as well
+var removed=this.lines[this.y+this.ybase].pop();if(removed[2]===0&&this.lines[row][this.cols-2]&&this.lines[row][this.cols-2][2]===2)this.lines[row][this.cols-2]=[this.curAttr,' ',1];// insert empty cell at cursor
+this.lines[row].splice(this.x,0,[this.curAttr,' ',1]);}}this.lines[row][this.x]=[this.curAttr,ch,ch_width];this.x++;this.updateRange(this.y);// fullwidth char - set next cell width to zero and advance cursor
+if(ch_width===2){this.lines[row][this.x]=[this.curAttr,'',0];this.x++;}}break;}break;case escaped:switch(ch){// ESC [ Control Sequence Introducer ( CSI is 0x9b).
+case'[':this.params=[];this.currentParam=0;this.state=csi;break;// ESC ] Operating System Command ( OSC is 0x9d).
+case']':this.params=[];this.currentParam=0;this.state=osc;break;// ESC P Device Control String ( DCS is 0x90).
+case'P':this.params=[];this.currentParam=0;this.state=dcs;break;// ESC _ Application Program Command ( APC is 0x9f).
+case'_':this.state=ignore;break;// ESC ^ Privacy Message ( PM is 0x9e).
+case'^':this.state=ignore;break;// ESC c Full Reset (RIS).
+case'c':this.reset();break;// ESC E Next Line ( NEL is 0x85).
+// ESC D Index ( IND is 0x84).
+case'E':this.x=0;;case'D':this.index();break;// ESC M Reverse Index ( RI is 0x8d).
+case'M':this.reverseIndex();break;// ESC % Select default/utf-8 character set.
+// @ = default, G = utf-8
+case'%'://this.charset = null;
+this.setgLevel(0);this.setgCharset(0,Terminal.charsets.US);this.state=normal;i++;break;// ESC (,),*,+,-,. Designate G0-G2 Character Set.
+case'(':// <-- this seems to get all the attention
+case')':case'*':case'+':case'-':case'.':switch(ch){case'(':this.gcharset=0;break;case')':this.gcharset=1;break;case'*':this.gcharset=2;break;case'+':this.gcharset=3;break;case'-':this.gcharset=1;break;case'.':this.gcharset=2;break;}this.state=charset;break;// Designate G3 Character Set (VT300).
+// A = ISO Latin-1 Supplemental.
+// Not implemented.
+case'/':this.gcharset=3;this.state=charset;i--;break;// ESC N
+// Single Shift Select of G2 Character Set
+// ( SS2 is 0x8e). This affects next character only.
+case'N':break;// ESC O
+// Single Shift Select of G3 Character Set
+// ( SS3 is 0x8f). This affects next character only.
+case'O':break;// ESC n
+// Invoke the G2 Character Set as GL (LS2).
+case'n':this.setgLevel(2);break;// ESC o
+// Invoke the G3 Character Set as GL (LS3).
+case'o':this.setgLevel(3);break;// ESC |
+// Invoke the G3 Character Set as GR (LS3R).
+case'|':this.setgLevel(3);break;// ESC }
+// Invoke the G2 Character Set as GR (LS2R).
+case'}':this.setgLevel(2);break;// ESC ~
+// Invoke the G1 Character Set as GR (LS1R).
+case'~':this.setgLevel(1);break;// ESC 7 Save Cursor (DECSC).
+case'7':this.saveCursor();this.state=normal;break;// ESC 8 Restore Cursor (DECRC).
+case'8':this.restoreCursor();this.state=normal;break;// ESC # 3 DEC line height/width
+case'#':this.state=normal;i++;break;// ESC H Tab Set (HTS is 0x88).
+case'H':this.tabSet();break;// ESC = Application Keypad (DECKPAM).
+case'=':this.log('Serial port requested application keypad.');this.applicationKeypad=true;this.viewport.syncScrollArea();this.state=normal;break;// ESC > Normal Keypad (DECKPNM).
+case'>':this.log('Switching back to normal keypad.');this.applicationKeypad=false;this.viewport.syncScrollArea();this.state=normal;break;default:this.state=normal;this.error('Unknown ESC control: %s.',ch);break;}break;case charset:switch(ch){case'0':// DEC Special Character and Line Drawing Set.
+cs=Terminal.charsets.SCLD;break;case'A':// UK
+cs=Terminal.charsets.UK;break;case'B':// United States (USASCII).
+cs=Terminal.charsets.US;break;case'4':// Dutch
+cs=Terminal.charsets.Dutch;break;case'C':// Finnish
+case'5':cs=Terminal.charsets.Finnish;break;case'R':// French
+cs=Terminal.charsets.French;break;case'Q':// FrenchCanadian
+cs=Terminal.charsets.FrenchCanadian;break;case'K':// German
+cs=Terminal.charsets.German;break;case'Y':// Italian
+cs=Terminal.charsets.Italian;break;case'E':// NorwegianDanish
+case'6':cs=Terminal.charsets.NorwegianDanish;break;case'Z':// Spanish
+cs=Terminal.charsets.Spanish;break;case'H':// Swedish
+case'7':cs=Terminal.charsets.Swedish;break;case'=':// Swiss
+cs=Terminal.charsets.Swiss;break;case'/':// ISOLatin (actually /A)
+cs=Terminal.charsets.ISOLatin;i++;break;default:// Default
+cs=Terminal.charsets.US;break;}this.setgCharset(this.gcharset,cs);this.gcharset=null;this.state=normal;break;case osc:// OSC Ps ; Pt ST
+// OSC Ps ; Pt BEL
+//   Set Text Parameters.
+if(ch==='\x1b'||ch==='\x07'){if(ch==='\x1b')i++;this.params.push(this.currentParam);switch(this.params[0]){case 0:case 1:case 2:if(this.params[1]){this.title=this.params[1];this.handleTitle(this.title);}break;case 3:// set X property
+break;case 4:case 5:// change dynamic colors
+break;case 10:case 11:case 12:case 13:case 14:case 15:case 16:case 17:case 18:case 19:// change dynamic ui colors
+break;case 46:// change log file
+break;case 50:// dynamic font
+break;case 51:// emacs shell
+break;case 52:// manipulate selection data
+break;case 104:case 105:case 110:case 111:case 112:case 113:case 114:case 115:case 116:case 117:case 118:// reset colors
+break;}this.params=[];this.currentParam=0;this.state=normal;}else{if(!this.params.length){if(ch>='0'&&ch<='9'){this.currentParam=this.currentParam*10+ch.charCodeAt(0)-48;}else if(ch===';'){this.params.push(this.currentParam);this.currentParam='';}}else{this.currentParam+=ch;}}break;case csi:// '?', '>', '!'
+if(ch==='?'||ch==='>'||ch==='!'){this.prefix=ch;break;}// 0 - 9
+if(ch>='0'&&ch<='9'){this.currentParam=this.currentParam*10+ch.charCodeAt(0)-48;break;}// '$', '"', ' ', '\''
+if(ch==='$'||ch==='"'||ch===' '||ch==='\''){this.postfix=ch;break;}this.params.push(this.currentParam);this.currentParam=0;// ';'
+if(ch===';')break;this.state=normal;switch(ch){// CSI Ps A
+// Cursor Up Ps Times (default = 1) (CUU).
+case'A':this.cursorUp(this.params);break;// CSI Ps B
+// Cursor Down Ps Times (default = 1) (CUD).
+case'B':this.cursorDown(this.params);break;// CSI Ps C
+// Cursor Forward Ps Times (default = 1) (CUF).
+case'C':this.cursorForward(this.params);break;// CSI Ps D
+// Cursor Backward Ps Times (default = 1) (CUB).
+case'D':this.cursorBackward(this.params);break;// CSI Ps ; Ps H
+// Cursor Position [row;column] (default = [1,1]) (CUP).
+case'H':this.cursorPos(this.params);break;// CSI Ps J  Erase in Display (ED).
+case'J':this.eraseInDisplay(this.params);break;// CSI Ps K  Erase in Line (EL).
+case'K':this.eraseInLine(this.params);break;// CSI Pm m  Character Attributes (SGR).
+case'm':if(!this.prefix){this.charAttributes(this.params);}break;// CSI Ps n  Device Status Report (DSR).
+case'n':if(!this.prefix){this.deviceStatus(this.params);}break;/**
+             * Additions
+             */// CSI Ps @
+// Insert Ps (Blank) Character(s) (default = 1) (ICH).
+case'@':this.insertChars(this.params);break;// CSI Ps E
+// Cursor Next Line Ps Times (default = 1) (CNL).
+case'E':this.cursorNextLine(this.params);break;// CSI Ps F
+// Cursor Preceding Line Ps Times (default = 1) (CNL).
+case'F':this.cursorPrecedingLine(this.params);break;// CSI Ps G
+// Cursor Character Absolute  [column] (default = [row,1]) (CHA).
+case'G':this.cursorCharAbsolute(this.params);break;// CSI Ps L
+// Insert Ps Line(s) (default = 1) (IL).
+case'L':this.insertLines(this.params);break;// CSI Ps M
+// Delete Ps Line(s) (default = 1) (DL).
+case'M':this.deleteLines(this.params);break;// CSI Ps P
+// Delete Ps Character(s) (default = 1) (DCH).
+case'P':this.deleteChars(this.params);break;// CSI Ps X
+// Erase Ps Character(s) (default = 1) (ECH).
+case'X':this.eraseChars(this.params);break;// CSI Pm `  Character Position Absolute
+//   [column] (default = [row,1]) (HPA).
+case'`':this.charPosAbsolute(this.params);break;// 141 61 a * HPR -
+// Horizontal Position Relative
+case'a':this.HPositionRelative(this.params);break;// CSI P s c
+// Send Device Attributes (Primary DA).
+// CSI > P s c
+// Send Device Attributes (Secondary DA)
+case'c':this.sendDeviceAttributes(this.params);break;// CSI Pm d
+// Line Position Absolute  [row] (default = [1,column]) (VPA).
+case'd':this.linePosAbsolute(this.params);break;// 145 65 e * VPR - Vertical Position Relative
+case'e':this.VPositionRelative(this.params);break;// CSI Ps ; Ps f
+//   Horizontal and Vertical Position [row;column] (default =
+//   [1,1]) (HVP).
+case'f':this.HVPosition(this.params);break;// CSI Pm h  Set Mode (SM).
+// CSI ? Pm h - mouse escape codes, cursor escape codes
+case'h':this.setMode(this.params);break;// CSI Pm l  Reset Mode (RM).
+// CSI ? Pm l
+case'l':this.resetMode(this.params);break;// CSI Ps ; Ps r
+//   Set Scrolling Region [top;bottom] (default = full size of win-
+//   dow) (DECSTBM).
+// CSI ? Pm r
+case'r':this.setScrollRegion(this.params);break;// CSI s
+//   Save cursor (ANSI.SYS).
+case's':this.saveCursor(this.params);break;// CSI u
+//   Restore cursor (ANSI.SYS).
+case'u':this.restoreCursor(this.params);break;/**
+             * Lesser Used
+             */// CSI Ps I
+// Cursor Forward Tabulation Ps tab stops (default = 1) (CHT).
+case'I':this.cursorForwardTab(this.params);break;// CSI Ps S  Scroll up Ps lines (default = 1) (SU).
+case'S':this.scrollUp(this.params);break;// CSI Ps T  Scroll down Ps lines (default = 1) (SD).
+// CSI Ps ; Ps ; Ps ; Ps ; Ps T
+// CSI > Ps; Ps T
+case'T':// if (this.prefix === '>') {
+//   this.resetTitleModes(this.params);
+//   break;
+// }
+// if (this.params.length > 2) {
+//   this.initMouseTracking(this.params);
+//   break;
+// }
+if(this.params.length<2&&!this.prefix){this.scrollDown(this.params);}break;// CSI Ps Z
+// Cursor Backward Tabulation Ps tab stops (default = 1) (CBT).
+case'Z':this.cursorBackwardTab(this.params);break;// CSI Ps b  Repeat the preceding graphic character Ps times (REP).
+case'b':this.repeatPrecedingCharacter(this.params);break;// CSI Ps g  Tab Clear (TBC).
+case'g':this.tabClear(this.params);break;// CSI Pm i  Media Copy (MC).
+// CSI ? Pm i
+// case 'i':
+//   this.mediaCopy(this.params);
+//   break;
+// CSI Pm m  Character Attributes (SGR).
+// CSI > Ps; Ps m
+// case 'm': // duplicate
+//   if (this.prefix === '>') {
+//     this.setResources(this.params);
+//   } else {
+//     this.charAttributes(this.params);
+//   }
+//   break;
+// CSI Ps n  Device Status Report (DSR).
+// CSI > Ps n
+// case 'n': // duplicate
+//   if (this.prefix === '>') {
+//     this.disableModifiers(this.params);
+//   } else {
+//     this.deviceStatus(this.params);
+//   }
+//   break;
+// CSI > Ps p  Set pointer mode.
+// CSI ! p   Soft terminal reset (DECSTR).
+// CSI Ps$ p
+//   Request ANSI mode (DECRQM).
+// CSI ? Ps$ p
+//   Request DEC private mode (DECRQM).
+// CSI Ps ; Ps " p
+case'p':switch(this.prefix){// case '>':
+//   this.setPointerMode(this.params);
+//   break;
+case'!':this.softReset(this.params);break;// case '?':
+//   if (this.postfix === '$') {
+//     this.requestPrivateMode(this.params);
+//   }
+//   break;
+// default:
+//   if (this.postfix === '"') {
+//     this.setConformanceLevel(this.params);
+//   } else if (this.postfix === '$') {
+//     this.requestAnsiMode(this.params);
+//   }
+//   break;
+}break;// CSI Ps q  Load LEDs (DECLL).
+// CSI Ps SP q
+// CSI Ps " q
+// case 'q':
+//   if (this.postfix === ' ') {
+//     this.setCursorStyle(this.params);
+//     break;
+//   }
+//   if (this.postfix === '"') {
+//     this.setCharProtectionAttr(this.params);
+//     break;
+//   }
+//   this.loadLEDs(this.params);
+//   break;
+// CSI Ps ; Ps r
+//   Set Scrolling Region [top;bottom] (default = full size of win-
+//   dow) (DECSTBM).
+// CSI ? Pm r
+// CSI Pt; Pl; Pb; Pr; Ps$ r
+// case 'r': // duplicate
+//   if (this.prefix === '?') {
+//     this.restorePrivateValues(this.params);
+//   } else if (this.postfix === '$') {
+//     this.setAttrInRectangle(this.params);
+//   } else {
+//     this.setScrollRegion(this.params);
+//   }
+//   break;
+// CSI s     Save cursor (ANSI.SYS).
+// CSI ? Pm s
+// case 's': // duplicate
+//   if (this.prefix === '?') {
+//     this.savePrivateValues(this.params);
+//   } else {
+//     this.saveCursor(this.params);
+//   }
+//   break;
+// CSI Ps ; Ps ; Ps t
+// CSI Pt; Pl; Pb; Pr; Ps$ t
+// CSI > Ps; Ps t
+// CSI Ps SP t
+// case 't':
+//   if (this.postfix === '$') {
+//     this.reverseAttrInRectangle(this.params);
+//   } else if (this.postfix === ' ') {
+//     this.setWarningBellVolume(this.params);
+//   } else {
+//     if (this.prefix === '>') {
+//       this.setTitleModeFeature(this.params);
+//     } else {
+//       this.manipulateWindow(this.params);
+//     }
+//   }
+//   break;
+// CSI u     Restore cursor (ANSI.SYS).
+// CSI Ps SP u
+// case 'u': // duplicate
+//   if (this.postfix === ' ') {
+//     this.setMarginBellVolume(this.params);
+//   } else {
+//     this.restoreCursor(this.params);
+//   }
+//   break;
+// CSI Pt; Pl; Pb; Pr; Pp; Pt; Pl; Pp$ v
+// case 'v':
+//   if (this.postfix === '$') {
+//     this.copyRectagle(this.params);
+//   }
+//   break;
+// CSI Pt ; Pl ; Pb ; Pr ' w
+// case 'w':
+//   if (this.postfix === '\'') {
+//     this.enableFilterRectangle(this.params);
+//   }
+//   break;
+// CSI Ps x  Request Terminal Parameters (DECREQTPARM).
+// CSI Ps x  Select Attribute Change Extent (DECSACE).
+// CSI Pc; Pt; Pl; Pb; Pr$ x
+// case 'x':
+//   if (this.postfix === '$') {
+//     this.fillRectangle(this.params);
+//   } else {
+//     this.requestParameters(this.params);
+//     //this.__(this.params);
+//   }
+//   break;
+// CSI Ps ; Pu ' z
+// CSI Pt; Pl; Pb; Pr$ z
+// case 'z':
+//   if (this.postfix === '\'') {
+//     this.enableLocatorReporting(this.params);
+//   } else if (this.postfix === '$') {
+//     this.eraseRectangle(this.params);
+//   }
+//   break;
+// CSI Pm ' {
+// CSI Pt; Pl; Pb; Pr$ {
+// case '{':
+//   if (this.postfix === '\'') {
+//     this.setLocatorEvents(this.params);
+//   } else if (this.postfix === '$') {
+//     this.selectiveEraseRectangle(this.params);
+//   }
+//   break;
+// CSI Ps ' |
+// case '|':
+//   if (this.postfix === '\'') {
+//     this.requestLocatorPosition(this.params);
+//   }
+//   break;
+// CSI P m SP }
+// Insert P s Column(s) (default = 1) (DECIC), VT420 and up.
+// case '}':
+//   if (this.postfix === ' ') {
+//     this.insertColumns(this.params);
+//   }
+//   break;
+// CSI P m SP ~
+// Delete P s Column(s) (default = 1) (DECDC), VT420 and up
+// case '~':
+//   if (this.postfix === ' ') {
+//     this.deleteColumns(this.params);
+//   }
+//   break;
+default:this.error('Unknown CSI code: %s.',ch);break;}this.prefix='';this.postfix='';break;case dcs:if(ch==='\x1b'||ch==='\x07'){if(ch==='\x1b')i++;switch(this.prefix){// User-Defined Keys (DECUDK).
+case'':break;// Request Status String (DECRQSS).
+// test: echo -e '\eP$q"p\e\\'
+case'$q':var pt=this.currentParam,valid=false;switch(pt){// DECSCA
+case'"q':pt='0"q';break;// DECSCL
+case'"p':pt='61"p';break;// DECSTBM
+case'r':pt=''+(this.scrollTop+1)+';'+(this.scrollBottom+1)+'r';break;// SGR
+case'm':pt='0m';break;default:this.error('Unknown DCS Pt: %s.',pt);pt='';break;}this.send('\x1bP'+ +valid+'$r'+pt+'\x1b\\');break;// Set Termcap/Terminfo Data (xterm, experimental).
+case'+p':break;// Request Termcap/Terminfo String (xterm, experimental)
+// Regular xterm does not even respond to this sequence.
+// This can cause a small glitch in vim.
+// test: echo -ne '\eP+q6b64\e\\'
+case'+q':var pt=this.currentParam,valid=false;this.send('\x1bP'+ +valid+'+r'+pt+'\x1b\\');break;default:this.error('Unknown DCS prefix: %s.',this.prefix);break;}this.currentParam=0;this.prefix='';this.state=normal;}else if(!this.currentParam){if(!this.prefix&&ch!=='$'&&ch!=='+'){this.currentParam=ch;}else if(this.prefix.length===2){this.currentParam=ch;}else{this.prefix+=ch;}}else{this.currentParam+=ch;}break;case ignore:// For PM and APC.
+if(ch==='\x1b'||ch==='\x07'){if(ch==='\x1b')i++;this.state=normal;}break;}}this.updateRange(this.y);this.refresh(this.refreshStart,this.refreshEnd);};/**
+ * Writes text to the terminal, followed by a break line character (\n).
+ * @param {string} text The text to write to the terminal.
+ */Terminal.prototype.writeln=function(data){this.write(data+'\r\n');};/**
+ * Attaches a custom keydown handler which is run before keys are processed, giving consumers of
+ * xterm.js ultimate control as to what keys should be processed by the terminal and what keys
+ * should not.
+ * @param {function} customKeydownHandler The custom KeyboardEvent handler to attach. This is a
+ *   function that takes a KeyboardEvent, allowing consumers to stop propogation and/or prevent
+ *   the default action. The function returns whether the event should be processed by xterm.js.
+ */Terminal.prototype.attachCustomKeydownHandler=function(customKeydownHandler){this.customKeydownHandler=customKeydownHandler;};/**
+ * Handle a keydown event
+ * Key Resources:
+ *   - https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent
+ * @param {KeyboardEvent} ev The keydown event to be handled.
+ */Terminal.prototype.keyDown=function(ev){if(this.customKeydownHandler&&this.customKeydownHandler(ev)===false){return false;}if(!this.compositionHelper.keydown.bind(this.compositionHelper)(ev)){return false;}var self=this;var result=this.evaluateKeyEscapeSequence(ev);if(result.scrollDisp){this.scrollDisp(result.scrollDisp);return this.cancel(ev,true);}if(isThirdLevelShift(this,ev)){return true;}if(result.cancel){// The event is canceled at the end already, is this necessary?
+this.cancel(ev,true);}if(!result.key){return true;}this.emit('keydown',ev);this.emit('key',result.key,ev);this.showCursor();this.handler(result.key);return this.cancel(ev,true);};/**
+ * Returns an object that determines how a KeyboardEvent should be handled. The key of the
+ * returned value is the new key code to pass to the PTY.
+ *
+ * Reference: http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
+ * @param {KeyboardEvent} ev The keyboard event to be translated to key escape sequence.
+ */Terminal.prototype.evaluateKeyEscapeSequence=function(ev){var result={// Whether to cancel event propogation (NOTE: this may not be needed since the event is
+// canceled at the end of keyDown
+cancel:false,// The new key even to emit
+key:undefined,// The number of characters to scroll, if this is defined it will cancel the event
+scrollDisp:undefined};var modifiers=ev.shiftKey<<0|ev.altKey<<1|ev.ctrlKey<<2|ev.metaKey<<3;switch(ev.keyCode){case 8:// backspace
+if(ev.shiftKey){result.key='\x08';// ^H
+break;}result.key='\x7f';// ^?
+break;case 9:// tab
+if(ev.shiftKey){result.key='\x1b[Z';break;}result.key='\t';result.cancel=true;break;case 13:// return/enter
+result.key='\r';result.cancel=true;break;case 27:// escape
+result.key='\x1b';result.cancel=true;break;case 37:// left-arrow
+if(modifiers){result.key='\x1b[1;'+(modifiers+1)+'D';// HACK: Make Alt + left-arrow behave like Ctrl + left-arrow: move one word backwards
+// http://unix.stackexchange.com/a/108106
+if(result.key=='\x1b[1;3D'){result.key='\x1b[1;5D';}}else if(this.applicationCursor){result.key='\x1bOD';}else{result.key='\x1b[D';}break;case 39:// right-arrow
+if(modifiers){result.key='\x1b[1;'+(modifiers+1)+'C';// HACK: Make Alt + right-arrow behave like Ctrl + right-arrow: move one word forward
+// http://unix.stackexchange.com/a/108106
+if(result.key=='\x1b[1;3C'){result.key='\x1b[1;5C';}}else if(this.applicationCursor){result.key='\x1bOC';}else{result.key='\x1b[C';}break;case 38:// up-arrow
+if(modifiers){result.key='\x1b[1;'+(modifiers+1)+'A';// HACK: Make Alt + up-arrow behave like Ctrl + up-arrow
+// http://unix.stackexchange.com/a/108106
+if(result.key=='\x1b[1;3A'){result.key='\x1b[1;5A';}}else if(this.applicationCursor){result.key='\x1bOA';}else{result.key='\x1b[A';}break;case 40:// down-arrow
+if(modifiers){result.key='\x1b[1;'+(modifiers+1)+'B';// HACK: Make Alt + down-arrow behave like Ctrl + down-arrow
+// http://unix.stackexchange.com/a/108106
+if(result.key=='\x1b[1;3B'){result.key='\x1b[1;5B';}}else if(this.applicationCursor){result.key='\x1bOB';}else{result.key='\x1b[B';}break;case 45:// insert
+if(!ev.shiftKey&&!ev.ctrlKey){// <Ctrl> or <Shift> + <Insert> are used to
+// copy-paste on some systems.
+result.key='\x1b[2~';}break;case 46:// delete
+if(modifiers){result.key='\x1b[3;'+(modifiers+1)+'~';}else{result.key='\x1b[3~';}break;case 36:// home
+if(modifiers)result.key='\x1b[1;'+(modifiers+1)+'H';else if(this.applicationCursor)result.key='\x1bOH';else result.key='\x1b[H';break;case 35:// end
+if(modifiers)result.key='\x1b[1;'+(modifiers+1)+'F';else if(this.applicationCursor)result.key='\x1bOF';else result.key='\x1b[F';break;case 33:// page up
+if(ev.shiftKey){result.scrollDisp=-(this.rows-1);}else{result.key='\x1b[5~';}break;case 34:// page down
+if(ev.shiftKey){result.scrollDisp=this.rows-1;}else{result.key='\x1b[6~';}break;case 112:// F1-F12
+if(modifiers){result.key='\x1b[1;'+(modifiers+1)+'P';}else{result.key='\x1bOP';}break;case 113:if(modifiers){result.key='\x1b[1;'+(modifiers+1)+'Q';}else{result.key='\x1bOQ';}break;case 114:if(modifiers){result.key='\x1b[1;'+(modifiers+1)+'R';}else{result.key='\x1bOR';}break;case 115:if(modifiers){result.key='\x1b[1;'+(modifiers+1)+'S';}else{result.key='\x1bOS';}break;case 116:if(modifiers){result.key='\x1b[15;'+(modifiers+1)+'~';}else{result.key='\x1b[15~';}break;case 117:if(modifiers){result.key='\x1b[17;'+(modifiers+1)+'~';}else{result.key='\x1b[17~';}break;case 118:if(modifiers){result.key='\x1b[18;'+(modifiers+1)+'~';}else{result.key='\x1b[18~';}break;case 119:if(modifiers){result.key='\x1b[19;'+(modifiers+1)+'~';}else{result.key='\x1b[19~';}break;case 120:if(modifiers){result.key='\x1b[20;'+(modifiers+1)+'~';}else{result.key='\x1b[20~';}break;case 121:if(modifiers){result.key='\x1b[21;'+(modifiers+1)+'~';}else{result.key='\x1b[21~';}break;case 122:if(modifiers){result.key='\x1b[23;'+(modifiers+1)+'~';}else{result.key='\x1b[23~';}break;case 123:if(modifiers){result.key='\x1b[24;'+(modifiers+1)+'~';}else{result.key='\x1b[24~';}break;default:// a-z and space
+if(ev.ctrlKey&&!ev.shiftKey&&!ev.altKey&&!ev.metaKey){if(ev.keyCode>=65&&ev.keyCode<=90){result.key=String.fromCharCode(ev.keyCode-64);}else if(ev.keyCode===32){// NUL
+result.key=String.fromCharCode(0);}else if(ev.keyCode>=51&&ev.keyCode<=55){// escape, file sep, group sep, record sep, unit sep
+result.key=String.fromCharCode(ev.keyCode-51+27);}else if(ev.keyCode===56){// delete
+result.key=String.fromCharCode(127);}else if(ev.keyCode===219){// ^[ - escape
+result.key=String.fromCharCode(27);}else if(ev.keyCode===221){// ^] - group sep
+result.key=String.fromCharCode(29);}}else if(!this.isMac&&ev.altKey&&!ev.ctrlKey&&!ev.metaKey){// On Mac this is a third level shift. Use <Esc> instead.
+if(ev.keyCode>=65&&ev.keyCode<=90){result.key='\x1b'+String.fromCharCode(ev.keyCode+32);}else if(ev.keyCode===192){result.key='\x1b`';}else if(ev.keyCode>=48&&ev.keyCode<=57){result.key='\x1b'+(ev.keyCode-48);}}break;}return result;};/**
+ * Set the G level of the terminal
+ * @param g
+ */Terminal.prototype.setgLevel=function(g){this.glevel=g;this.charset=this.charsets[g];};/**
+ * Set the charset for the given G level of the terminal
+ * @param g
+ * @param charset
+ */Terminal.prototype.setgCharset=function(g,charset){this.charsets[g]=charset;if(this.glevel===g){this.charset=charset;}};/**
+ * Handle a keypress event.
+ * Key Resources:
+ *   - https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent
+ * @param {KeyboardEvent} ev The keypress event to be handled.
+ */Terminal.prototype.keyPress=function(ev){var key;this.cancel(ev);if(ev.charCode){key=ev.charCode;}else if(ev.which==null){key=ev.keyCode;}else if(ev.which!==0&&ev.charCode!==0){key=ev.which;}else{return false;}if(!key||(ev.altKey||ev.ctrlKey||ev.metaKey)&&!isThirdLevelShift(this,ev)){return false;}key=String.fromCharCode(key);this.emit('keypress',key,ev);this.emit('key',key,ev);this.showCursor();this.handler(key);return false;};/**
+ * Send data for handling to the terminal
+ * @param {string} data
+ */Terminal.prototype.send=function(data){var self=this;if(!this.queue){setTimeout(function(){self.handler(self.queue);self.queue='';},1);}this.queue+=data;};/**
+ * Ring the bell.
+ * Note: We could do sweet things with webaudio here
+ */Terminal.prototype.bell=function(){if(!this.visualBell)return;var self=this;this.element.style.borderColor='white';setTimeout(function(){self.element.style.borderColor='';},10);if(this.popOnBell)this.focus();};/**
+ * Log the current state to the console.
+ */Terminal.prototype.log=function(){if(!this.debug)return;if(!this.context.console||!this.context.console.log)return;var args=Array.prototype.slice.call(arguments);this.context.console.log.apply(this.context.console,args);};/**
+ * Log the current state as error to the console.
+ */Terminal.prototype.error=function(){if(!this.debug)return;if(!this.context.console||!this.context.console.error)return;var args=Array.prototype.slice.call(arguments);this.context.console.error.apply(this.context.console,args);};/**
+ * Resizes the terminal.
+ *
+ * @param {number} x The number of columns to resize to.
+ * @param {number} y The number of rows to resize to.
+ */Terminal.prototype.resize=function(x,y){var line,el,i,j,ch,addToY;if(x===this.cols&&y===this.rows){return;}if(x<1)x=1;if(y<1)y=1;// resize cols
+j=this.cols;if(j<x){ch=[this.defAttr,' ',1];// does xterm use the default attr?
+i=this.lines.length;while(i--){while(this.lines[i].length<x){this.lines[i].push(ch);}}}else{// (j > x)
+i=this.lines.length;while(i--){while(this.lines[i].length>x){this.lines[i].pop();}}}this.setupStops(j);this.cols=x;// resize rows
+j=this.rows;addToY=0;if(j<y){el=this.element;while(j++<y){// y is rows, not this.y
+if(this.lines.length<y+this.ybase){if(this.ybase>0&&this.lines.length<=this.ybase+this.y+addToY+1){// There is room above the buffer and there are no empty elements below the line,
+// scroll up
+this.ybase--;addToY++;if(this.ydisp>0){// Viewport is at the top of the buffer, must increase downwards
+this.ydisp--;}}else{// Add a blank line if there is no buffer left at the top to scroll to, or if there
+// are blank lines after the cursor
+this.lines.push(this.blankLine());}}if(this.children.length<y){this.insertRow();}}}else{// (j > y)
+while(j-->y){if(this.lines.length>y+this.ybase){if(this.lines.length>this.ybase+this.y+1){// The line is a blank line below the cursor, remove it
+this.lines.pop();}else{// The line is the cursor, scroll down
+this.ybase++;this.ydisp++;}}if(this.children.length>y){el=this.children.shift();if(!el)continue;el.parentNode.removeChild(el);}}}this.rows=y;// Make sure that the cursor stays on screen
+if(this.y>=y){this.y=y-1;}if(addToY){this.y+=addToY;}if(this.x>=x){this.x=x-1;}this.scrollTop=0;this.scrollBottom=y-1;this.refresh(0,this.rows-1);this.normal=null;this.emit('resize',{terminal:this,cols:x,rows:y});};/**
+ * Updates the range of rows to refresh
+ * @param {number} y The number of rows to refresh next.
+ */Terminal.prototype.updateRange=function(y){if(y<this.refreshStart)this.refreshStart=y;if(y>this.refreshEnd)this.refreshEnd=y;// if (y > this.refreshEnd) {
+//   this.refreshEnd = y;
+//   if (y > this.rows - 1) {
+//     this.refreshEnd = this.rows - 1;
+//   }
+// }
+};/**
+ * Set the range of refreshing to the maximyum value
+ */Terminal.prototype.maxRange=function(){this.refreshStart=0;this.refreshEnd=this.rows-1;};/**
+ * Setup the tab stops.
+ * @param {number} i
+ */Terminal.prototype.setupStops=function(i){if(i!=null){if(!this.tabs[i]){i=this.prevStop(i);}}else{this.tabs={};i=0;}for(;i<this.cols;i+=8){this.tabs[i]=true;}};/**
+ * Move the cursor to the previous tab stop from the given position (default is current).
+ * @param {number} x The position to move the cursor to the previous tab stop.
+ */Terminal.prototype.prevStop=function(x){if(x==null)x=this.x;while(!this.tabs[--x]&&x>0){}return x>=this.cols?this.cols-1:x<0?0:x;};/**
+ * Move the cursor one tab stop forward from the given position (default is current).
+ * @param {number} x The position to move the cursor one tab stop forward.
+ */Terminal.prototype.nextStop=function(x){if(x==null)x=this.x;while(!this.tabs[++x]&&x<this.cols){}return x>=this.cols?this.cols-1:x<0?0:x;};/**
+ * Erase in the identified line everything from "x" to the end of the line (right).
+ * @param {number} x The column from which to start erasing to the end of the line.
+ * @param {number} y The line in which to operate.
+ */Terminal.prototype.eraseRight=function(x,y){var line=this.lines[this.ybase+y],ch=[this.eraseAttr(),' ',1];// xterm
+for(;x<this.cols;x++){line[x]=ch;}this.updateRange(y);};/**
+ * Erase in the identified line everything from "x" to the start of the line (left).
+ * @param {number} x The column from which to start erasing to the start of the line.
+ * @param {number} y The line in which to operate.
+ */Terminal.prototype.eraseLeft=function(x,y){var line=this.lines[this.ybase+y],ch=[this.eraseAttr(),' ',1];// xterm
+x++;while(x--){line[x]=ch;}this.updateRange(y);};/**
+ * Clears the entire buffer, making the prompt line the new first line.
+ */Terminal.prototype.clear=function(){if(this.ybase===0&&this.y===0){// Don't clear if it's already clear
+return;}this.lines=[this.lines[this.ybase+this.y]];this.ydisp=0;this.ybase=0;this.y=0;for(var i=1;i<this.rows;i++){this.lines.push(this.blankLine());}this.refresh(0,this.rows-1);this.emit('scroll',this.ydisp);};/**
+ * Erase all content in the given line
+ * @param {number} y The line to erase all of its contents.
+ */Terminal.prototype.eraseLine=function(y){this.eraseRight(0,y);};/**
+ * Return the data array of a blank line/
+ * @param {number} cur First bunch of data for each "blank" character.
+ */Terminal.prototype.blankLine=function(cur){var attr=cur?this.eraseAttr():this.defAttr;var ch=[attr,' ',1]// width defaults to 1 halfwidth character
+,line=[],i=0;for(;i<this.cols;i++){line[i]=ch;}return line;};/**
+ * If cur return the back color xterm feature attribute. Else return defAttr.
+ * @param {object} cur
+ */Terminal.prototype.ch=function(cur){return cur?[this.eraseAttr(),' ',1]:[this.defAttr,' ',1];};/**
+ * Evaluate if the current erminal is the given argument.
+ * @param {object} term The terminal to evaluate
+ */Terminal.prototype.is=function(term){var name=this.termName;return(name+'').indexOf(term)===0;};/**
+     * Emit the 'data' event and populate the given data.
+     * @param {string} data The data to populate in the event.
+     */Terminal.prototype.handler=function(data){this.emit('data',data);};/**
+ * Emit the 'title' event and populate the given title.
+ * @param {string} title The title to populate in the event.
+ */Terminal.prototype.handleTitle=function(title){this.emit('title',title);};/**
+ * ESC
+ *//**
+ * ESC D Index (IND is 0x84).
+ */Terminal.prototype.index=function(){this.y++;if(this.y>this.scrollBottom){this.y--;this.scroll();}this.state=normal;};/**
+ * ESC M Reverse Index (RI is 0x8d).
+ */Terminal.prototype.reverseIndex=function(){var j;this.y--;if(this.y<this.scrollTop){this.y++;// possibly move the code below to term.reverseScroll();
+// test: echo -ne '\e[1;1H\e[44m\eM\e[0m'
+// blankLine(true) is xterm/linux behavior
+this.lines.splice(this.y+this.ybase,0,this.blankLine(true));j=this.rows-1-this.scrollBottom;this.lines.splice(this.rows-1+this.ybase-j+1,1);// this.maxRange();
+this.updateRange(this.scrollTop);this.updateRange(this.scrollBottom);}this.state=normal;};/**
+ * ESC c Full Reset (RIS).
+ */Terminal.prototype.reset=function(){this.options.rows=this.rows;this.options.cols=this.cols;var customKeydownHandler=this.customKeydownHandler;Terminal.call(this,this.options);this.customKeydownHandler=customKeydownHandler;this.refresh(0,this.rows-1);this.viewport.syncScrollArea();};/**
+ * ESC H Tab Set (HTS is 0x88).
+ */Terminal.prototype.tabSet=function(){this.tabs[this.x]=true;this.state=normal;};/**
+ * CSI
+ *//**
+ * CSI Ps A
+ * Cursor Up Ps Times (default = 1) (CUU).
+ */Terminal.prototype.cursorUp=function(params){var param=params[0];if(param<1)param=1;this.y-=param;if(this.y<0)this.y=0;};/**
+ * CSI Ps B
+ * Cursor Down Ps Times (default = 1) (CUD).
+ */Terminal.prototype.cursorDown=function(params){var param=params[0];if(param<1)param=1;this.y+=param;if(this.y>=this.rows){this.y=this.rows-1;}};/**
+ * CSI Ps C
+ * Cursor Forward Ps Times (default = 1) (CUF).
+ */Terminal.prototype.cursorForward=function(params){var param=params[0];if(param<1)param=1;this.x+=param;if(this.x>=this.cols){this.x=this.cols-1;}};/**
+ * CSI Ps D
+ * Cursor Backward Ps Times (default = 1) (CUB).
+ */Terminal.prototype.cursorBackward=function(params){var param=params[0];if(param<1)param=1;this.x-=param;if(this.x<0)this.x=0;};/**
+ * CSI Ps ; Ps H
+ * Cursor Position [row;column] (default = [1,1]) (CUP).
+ */Terminal.prototype.cursorPos=function(params){var row,col;row=params[0]-1;if(params.length>=2){col=params[1]-1;}else{col=0;}if(row<0){row=0;}else if(row>=this.rows){row=this.rows-1;}if(col<0){col=0;}else if(col>=this.cols){col=this.cols-1;}this.x=col;this.y=row;};/**
+ * CSI Ps J  Erase in Display (ED).
+ *     Ps = 0  -> Erase Below (default).
+ *     Ps = 1  -> Erase Above.
+ *     Ps = 2  -> Erase All.
+ *     Ps = 3  -> Erase Saved Lines (xterm).
+ * CSI ? Ps J
+ *   Erase in Display (DECSED).
+ *     Ps = 0  -> Selective Erase Below (default).
+ *     Ps = 1  -> Selective Erase Above.
+ *     Ps = 2  -> Selective Erase All.
+ */Terminal.prototype.eraseInDisplay=function(params){var j;switch(params[0]){case 0:this.eraseRight(this.x,this.y);j=this.y+1;for(;j<this.rows;j++){this.eraseLine(j);}break;case 1:this.eraseLeft(this.x,this.y);j=this.y;while(j--){this.eraseLine(j);}break;case 2:j=this.rows;while(j--){this.eraseLine(j);}break;case 3:;// no saved lines
+break;}};/**
+ * CSI Ps K  Erase in Line (EL).
+ *     Ps = 0  -> Erase to Right (default).
+ *     Ps = 1  -> Erase to Left.
+ *     Ps = 2  -> Erase All.
+ * CSI ? Ps K
+ *   Erase in Line (DECSEL).
+ *     Ps = 0  -> Selective Erase to Right (default).
+ *     Ps = 1  -> Selective Erase to Left.
+ *     Ps = 2  -> Selective Erase All.
+ */Terminal.prototype.eraseInLine=function(params){switch(params[0]){case 0:this.eraseRight(this.x,this.y);break;case 1:this.eraseLeft(this.x,this.y);break;case 2:this.eraseLine(this.y);break;}};/**
+ * CSI Pm m  Character Attributes (SGR).
+ *     Ps = 0  -> Normal (default).
+ *     Ps = 1  -> Bold.
+ *     Ps = 4  -> Underlined.
+ *     Ps = 5  -> Blink (appears as Bold).
+ *     Ps = 7  -> Inverse.
+ *     Ps = 8  -> Invisible, i.e., hidden (VT300).
+ *     Ps = 2 2  -> Normal (neither bold nor faint).
+ *     Ps = 2 4  -> Not underlined.
+ *     Ps = 2 5  -> Steady (not blinking).
+ *     Ps = 2 7  -> Positive (not inverse).
+ *     Ps = 2 8  -> Visible, i.e., not hidden (VT300).
+ *     Ps = 3 0  -> Set foreground color to Black.
+ *     Ps = 3 1  -> Set foreground color to Red.
+ *     Ps = 3 2  -> Set foreground color to Green.
+ *     Ps = 3 3  -> Set foreground color to Yellow.
+ *     Ps = 3 4  -> Set foreground color to Blue.
+ *     Ps = 3 5  -> Set foreground color to Magenta.
+ *     Ps = 3 6  -> Set foreground color to Cyan.
+ *     Ps = 3 7  -> Set foreground color to White.
+ *     Ps = 3 9  -> Set foreground color to default (original).
+ *     Ps = 4 0  -> Set background color to Black.
+ *     Ps = 4 1  -> Set background color to Red.
+ *     Ps = 4 2  -> Set background color to Green.
+ *     Ps = 4 3  -> Set background color to Yellow.
+ *     Ps = 4 4  -> Set background color to Blue.
+ *     Ps = 4 5  -> Set background color to Magenta.
+ *     Ps = 4 6  -> Set background color to Cyan.
+ *     Ps = 4 7  -> Set background color to White.
+ *     Ps = 4 9  -> Set background color to default (original).
+ *
+ *   If 16-color support is compiled, the following apply.  Assume
+ *   that xterm's resources are set so that the ISO color codes are
+ *   the first 8 of a set of 16.  Then the aixterm colors are the
+ *   bright versions of the ISO colors:
+ *     Ps = 9 0  -> Set foreground color to Black.
+ *     Ps = 9 1  -> Set foreground color to Red.
+ *     Ps = 9 2  -> Set foreground color to Green.
+ *     Ps = 9 3  -> Set foreground color to Yellow.
+ *     Ps = 9 4  -> Set foreground color to Blue.
+ *     Ps = 9 5  -> Set foreground color to Magenta.
+ *     Ps = 9 6  -> Set foreground color to Cyan.
+ *     Ps = 9 7  -> Set foreground color to White.
+ *     Ps = 1 0 0  -> Set background color to Black.
+ *     Ps = 1 0 1  -> Set background color to Red.
+ *     Ps = 1 0 2  -> Set background color to Green.
+ *     Ps = 1 0 3  -> Set background color to Yellow.
+ *     Ps = 1 0 4  -> Set background color to Blue.
+ *     Ps = 1 0 5  -> Set background color to Magenta.
+ *     Ps = 1 0 6  -> Set background color to Cyan.
+ *     Ps = 1 0 7  -> Set background color to White.
+ *
+ *   If xterm is compiled with the 16-color support disabled, it
+ *   supports the following, from rxvt:
+ *     Ps = 1 0 0  -> Set foreground and background color to
+ *     default.
+ *
+ *   If 88- or 256-color support is compiled, the following apply.
+ *     Ps = 3 8  ; 5  ; Ps -> Set foreground color to the second
+ *     Ps.
+ *     Ps = 4 8  ; 5  ; Ps -> Set background color to the second
+ *     Ps.
+ */Terminal.prototype.charAttributes=function(params){// Optimize a single SGR0.
+if(params.length===1&&params[0]===0){this.curAttr=this.defAttr;return;}var l=params.length,i=0,flags=this.curAttr>>18,fg=this.curAttr>>9&0x1ff,bg=this.curAttr&0x1ff,p;for(;i<l;i++){p=params[i];if(p>=30&&p<=37){// fg color 8
+fg=p-30;}else if(p>=40&&p<=47){// bg color 8
+bg=p-40;}else if(p>=90&&p<=97){// fg color 16
+p+=8;fg=p-90;}else if(p>=100&&p<=107){// bg color 16
+p+=8;bg=p-100;}else if(p===0){// default
+flags=this.defAttr>>18;fg=this.defAttr>>9&0x1ff;bg=this.defAttr&0x1ff;// flags = 0;
+// fg = 0x1ff;
+// bg = 0x1ff;
+}else if(p===1){// bold text
+flags|=1;}else if(p===4){// underlined text
+flags|=2;}else if(p===5){// blink
+flags|=4;}else if(p===7){// inverse and positive
+// test with: echo -e '\e[31m\e[42mhello\e[7mworld\e[27mhi\e[m'
+flags|=8;}else if(p===8){// invisible
+flags|=16;}else if(p===22){// not bold
+flags&=~1;}else if(p===24){// not underlined
+flags&=~2;}else if(p===25){// not blink
+flags&=~4;}else if(p===27){// not inverse
+flags&=~8;}else if(p===28){// not invisible
+flags&=~16;}else if(p===39){// reset fg
+fg=this.defAttr>>9&0x1ff;}else if(p===49){// reset bg
+bg=this.defAttr&0x1ff;}else if(p===38){// fg color 256
+if(params[i+1]===2){i+=2;fg=matchColor(params[i]&0xff,params[i+1]&0xff,params[i+2]&0xff);if(fg===-1)fg=0x1ff;i+=2;}else if(params[i+1]===5){i+=2;p=params[i]&0xff;fg=p;}}else if(p===48){// bg color 256
+if(params[i+1]===2){i+=2;bg=matchColor(params[i]&0xff,params[i+1]&0xff,params[i+2]&0xff);if(bg===-1)bg=0x1ff;i+=2;}else if(params[i+1]===5){i+=2;p=params[i]&0xff;bg=p;}}else if(p===100){// reset fg/bg
+fg=this.defAttr>>9&0x1ff;bg=this.defAttr&0x1ff;}else{this.error('Unknown SGR attribute: %d.',p);}}this.curAttr=flags<<18|fg<<9|bg;};/**
+ * CSI Ps n  Device Status Report (DSR).
+ *     Ps = 5  -> Status Report.  Result (``OK'') is
+ *   CSI 0 n
+ *     Ps = 6  -> Report Cursor Position (CPR) [row;column].
+ *   Result is
+ *   CSI r ; c R
+ * CSI ? Ps n
+ *   Device Status Report (DSR, DEC-specific).
+ *     Ps = 6  -> Report Cursor Position (CPR) [row;column] as CSI
+ *     ? r ; c R (assumes page is zero).
+ *     Ps = 1 5  -> Report Printer status as CSI ? 1 0  n  (ready).
+ *     or CSI ? 1 1  n  (not ready).
+ *     Ps = 2 5  -> Report UDK status as CSI ? 2 0  n  (unlocked)
+ *     or CSI ? 2 1  n  (locked).
+ *     Ps = 2 6  -> Report Keyboard status as
+ *   CSI ? 2 7  ;  1  ;  0  ;  0  n  (North American).
+ *   The last two parameters apply to VT400 & up, and denote key-
+ *   board ready and LK01 respectively.
+ *     Ps = 5 3  -> Report Locator status as
+ *   CSI ? 5 3  n  Locator available, if compiled-in, or
+ *   CSI ? 5 0  n  No Locator, if not.
+ */Terminal.prototype.deviceStatus=function(params){if(!this.prefix){switch(params[0]){case 5:// status report
+this.send('\x1b[0n');break;case 6:// cursor position
+this.send('\x1b['+(this.y+1)+';'+(this.x+1)+'R');break;}}else if(this.prefix==='?'){// modern xterm doesnt seem to
+// respond to any of these except ?6, 6, and 5
+switch(params[0]){case 6:// cursor position
+this.send('\x1b[?'+(this.y+1)+';'+(this.x+1)+'R');break;case 15:// no printer
+// this.send('\x1b[?11n');
+break;case 25:// dont support user defined keys
+// this.send('\x1b[?21n');
+break;case 26:// north american keyboard
+// this.send('\x1b[?27;1;0;0n');
+break;case 53:// no dec locator/mouse
+// this.send('\x1b[?50n');
+break;}}};/**
+ * Additions
+ *//**
+ * CSI Ps @
+ * Insert Ps (Blank) Character(s) (default = 1) (ICH).
+ */Terminal.prototype.insertChars=function(params){var param,row,j,ch;param=params[0];if(param<1)param=1;row=this.y+this.ybase;j=this.x;ch=[this.eraseAttr(),' ',1];// xterm
+while(param--&&j<this.cols){this.lines[row].splice(j++,0,ch);this.lines[row].pop();}};/**
+ * CSI Ps E
+ * Cursor Next Line Ps Times (default = 1) (CNL).
+ * same as CSI Ps B ?
+ */Terminal.prototype.cursorNextLine=function(params){var param=params[0];if(param<1)param=1;this.y+=param;if(this.y>=this.rows){this.y=this.rows-1;}this.x=0;};/**
+ * CSI Ps F
+ * Cursor Preceding Line Ps Times (default = 1) (CNL).
+ * reuse CSI Ps A ?
+ */Terminal.prototype.cursorPrecedingLine=function(params){var param=params[0];if(param<1)param=1;this.y-=param;if(this.y<0)this.y=0;this.x=0;};/**
+ * CSI Ps G
+ * Cursor Character Absolute  [column] (default = [row,1]) (CHA).
+ */Terminal.prototype.cursorCharAbsolute=function(params){var param=params[0];if(param<1)param=1;this.x=param-1;};/**
+ * CSI Ps L
+ * Insert Ps Line(s) (default = 1) (IL).
+ */Terminal.prototype.insertLines=function(params){var param,row,j;param=params[0];if(param<1)param=1;row=this.y+this.ybase;j=this.rows-1-this.scrollBottom;j=this.rows-1+this.ybase-j+1;while(param--){// test: echo -e '\e[44m\e[1L\e[0m'
+// blankLine(true) - xterm/linux behavior
+this.lines.splice(row,0,this.blankLine(true));this.lines.splice(j,1);}// this.maxRange();
+this.updateRange(this.y);this.updateRange(this.scrollBottom);};/**
+ * CSI Ps M
+ * Delete Ps Line(s) (default = 1) (DL).
+ */Terminal.prototype.deleteLines=function(params){var param,row,j;param=params[0];if(param<1)param=1;row=this.y+this.ybase;j=this.rows-1-this.scrollBottom;j=this.rows-1+this.ybase-j;while(param--){// test: echo -e '\e[44m\e[1M\e[0m'
+// blankLine(true) - xterm/linux behavior
+this.lines.splice(j+1,0,this.blankLine(true));this.lines.splice(row,1);}// this.maxRange();
+this.updateRange(this.y);this.updateRange(this.scrollBottom);};/**
+ * CSI Ps P
+ * Delete Ps Character(s) (default = 1) (DCH).
+ */Terminal.prototype.deleteChars=function(params){var param,row,ch;param=params[0];if(param<1)param=1;row=this.y+this.ybase;ch=[this.eraseAttr(),' ',1];// xterm
+while(param--){this.lines[row].splice(this.x,1);this.lines[row].push(ch);}};/**
+ * CSI Ps X
+ * Erase Ps Character(s) (default = 1) (ECH).
+ */Terminal.prototype.eraseChars=function(params){var param,row,j,ch;param=params[0];if(param<1)param=1;row=this.y+this.ybase;j=this.x;ch=[this.eraseAttr(),' ',1];// xterm
+while(param--&&j<this.cols){this.lines[row][j++]=ch;}};/**
+ * CSI Pm `  Character Position Absolute
+ *   [column] (default = [row,1]) (HPA).
+ */Terminal.prototype.charPosAbsolute=function(params){var param=params[0];if(param<1)param=1;this.x=param-1;if(this.x>=this.cols){this.x=this.cols-1;}};/**
+ * 141 61 a * HPR -
+ * Horizontal Position Relative
+ * reuse CSI Ps C ?
+ */Terminal.prototype.HPositionRelative=function(params){var param=params[0];if(param<1)param=1;this.x+=param;if(this.x>=this.cols){this.x=this.cols-1;}};/**
+ * CSI Ps c  Send Device Attributes (Primary DA).
+ *     Ps = 0  or omitted -> request attributes from terminal.  The
+ *     response depends on the decTerminalID resource setting.
+ *     -> CSI ? 1 ; 2 c  (``VT100 with Advanced Video Option'')
+ *     -> CSI ? 1 ; 0 c  (``VT101 with No Options'')
+ *     -> CSI ? 6 c  (``VT102'')
+ *     -> CSI ? 6 0 ; 1 ; 2 ; 6 ; 8 ; 9 ; 1 5 ; c  (``VT220'')
+ *   The VT100-style response parameters do not mean anything by
+ *   themselves.  VT220 parameters do, telling the host what fea-
+ *   tures the terminal supports:
+ *     Ps = 1  -> 132-columns.
+ *     Ps = 2  -> Printer.
+ *     Ps = 6  -> Selective erase.
+ *     Ps = 8  -> User-defined keys.
+ *     Ps = 9  -> National replacement character sets.
+ *     Ps = 1 5  -> Technical characters.
+ *     Ps = 2 2  -> ANSI color, e.g., VT525.
+ *     Ps = 2 9  -> ANSI text locator (i.e., DEC Locator mode).
+ * CSI > Ps c
+ *   Send Device Attributes (Secondary DA).
+ *     Ps = 0  or omitted -> request the terminal's identification
+ *     code.  The response depends on the decTerminalID resource set-
+ *     ting.  It should apply only to VT220 and up, but xterm extends
+ *     this to VT100.
+ *     -> CSI  > Pp ; Pv ; Pc c
+ *   where Pp denotes the terminal type
+ *     Pp = 0  -> ``VT100''.
+ *     Pp = 1  -> ``VT220''.
+ *   and Pv is the firmware version (for xterm, this was originally
+ *   the XFree86 patch number, starting with 95).  In a DEC termi-
+ *   nal, Pc indicates the ROM cartridge registration number and is
+ *   always zero.
+ * More information:
+ *   xterm/charproc.c - line 2012, for more information.
+ *   vim responds with ^[[?0c or ^[[?1c after the terminal's response (?)
+ */Terminal.prototype.sendDeviceAttributes=function(params){if(params[0]>0)return;if(!this.prefix){if(this.is('xterm')||this.is('rxvt-unicode')||this.is('screen')){this.send('\x1b[?1;2c');}else if(this.is('linux')){this.send('\x1b[?6c');}}else if(this.prefix==='>'){// xterm and urxvt
+// seem to spit this
+// out around ~370 times (?).
+if(this.is('xterm')){this.send('\x1b[>0;276;0c');}else if(this.is('rxvt-unicode')){this.send('\x1b[>85;95;0c');}else if(this.is('linux')){// not supported by linux console.
+// linux console echoes parameters.
+this.send(params[0]+'c');}else if(this.is('screen')){this.send('\x1b[>83;40003;0c');}}};/**
+ * CSI Pm d
+ * Line Position Absolute  [row] (default = [1,column]) (VPA).
+ */Terminal.prototype.linePosAbsolute=function(params){var param=params[0];if(param<1)param=1;this.y=param-1;if(this.y>=this.rows){this.y=this.rows-1;}};/**
+ * 145 65 e * VPR - Vertical Position Relative
+ * reuse CSI Ps B ?
+ */Terminal.prototype.VPositionRelative=function(params){var param=params[0];if(param<1)param=1;this.y+=param;if(this.y>=this.rows){this.y=this.rows-1;}};/**
+ * CSI Ps ; Ps f
+ *   Horizontal and Vertical Position [row;column] (default =
+ *   [1,1]) (HVP).
+ */Terminal.prototype.HVPosition=function(params){if(params[0]<1)params[0]=1;if(params[1]<1)params[1]=1;this.y=params[0]-1;if(this.y>=this.rows){this.y=this.rows-1;}this.x=params[1]-1;if(this.x>=this.cols){this.x=this.cols-1;}};/**
+ * CSI Pm h  Set Mode (SM).
+ *     Ps = 2  -> Keyboard Action Mode (AM).
+ *     Ps = 4  -> Insert Mode (IRM).
+ *     Ps = 1 2  -> Send/receive (SRM).
+ *     Ps = 2 0  -> Automatic Newline (LNM).
+ * CSI ? Pm h
+ *   DEC Private Mode Set (DECSET).
+ *     Ps = 1  -> Application Cursor Keys (DECCKM).
+ *     Ps = 2  -> Designate USASCII for character sets G0-G3
+ *     (DECANM), and set VT100 mode.
+ *     Ps = 3  -> 132 Column Mode (DECCOLM).
+ *     Ps = 4  -> Smooth (Slow) Scroll (DECSCLM).
+ *     Ps = 5  -> Reverse Video (DECSCNM).
+ *     Ps = 6  -> Origin Mode (DECOM).
+ *     Ps = 7  -> Wraparound Mode (DECAWM).
+ *     Ps = 8  -> Auto-repeat Keys (DECARM).
+ *     Ps = 9  -> Send Mouse X & Y on button press.  See the sec-
+ *     tion Mouse Tracking.
+ *     Ps = 1 0  -> Show toolbar (rxvt).
+ *     Ps = 1 2  -> Start Blinking Cursor (att610).
+ *     Ps = 1 8  -> Print form feed (DECPFF).
+ *     Ps = 1 9  -> Set print extent to full screen (DECPEX).
+ *     Ps = 2 5  -> Show Cursor (DECTCEM).
+ *     Ps = 3 0  -> Show scrollbar (rxvt).
+ *     Ps = 3 5  -> Enable font-shifting functions (rxvt).
+ *     Ps = 3 8  -> Enter Tektronix Mode (DECTEK).
+ *     Ps = 4 0  -> Allow 80 -> 132 Mode.
+ *     Ps = 4 1  -> more(1) fix (see curses resource).
+ *     Ps = 4 2  -> Enable Nation Replacement Character sets (DECN-
+ *     RCM).
+ *     Ps = 4 4  -> Turn On Margin Bell.
+ *     Ps = 4 5  -> Reverse-wraparound Mode.
+ *     Ps = 4 6  -> Start Logging.  This is normally disabled by a
+ *     compile-time option.
+ *     Ps = 4 7  -> Use Alternate Screen Buffer.  (This may be dis-
+ *     abled by the titeInhibit resource).
+ *     Ps = 6 6  -> Application keypad (DECNKM).
+ *     Ps = 6 7  -> Backarrow key sends backspace (DECBKM).
+ *     Ps = 1 0 0 0  -> Send Mouse X & Y on button press and
+ *     release.  See the section Mouse Tracking.
+ *     Ps = 1 0 0 1  -> Use Hilite Mouse Tracking.
+ *     Ps = 1 0 0 2  -> Use Cell Motion Mouse Tracking.
+ *     Ps = 1 0 0 3  -> Use All Motion Mouse Tracking.
+ *     Ps = 1 0 0 4  -> Send FocusIn/FocusOut events.
+ *     Ps = 1 0 0 5  -> Enable Extended Mouse Mode.
+ *     Ps = 1 0 1 0  -> Scroll to bottom on tty output (rxvt).
+ *     Ps = 1 0 1 1  -> Scroll to bottom on key press (rxvt).
+ *     Ps = 1 0 3 4  -> Interpret "meta" key, sets eighth bit.
+ *     (enables the eightBitInput resource).
+ *     Ps = 1 0 3 5  -> Enable special modifiers for Alt and Num-
+ *     Lock keys.  (This enables the numLock resource).
+ *     Ps = 1 0 3 6  -> Send ESC   when Meta modifies a key.  (This
+ *     enables the metaSendsEscape resource).
+ *     Ps = 1 0 3 7  -> Send DEL from the editing-keypad Delete
+ *     key.
+ *     Ps = 1 0 3 9  -> Send ESC  when Alt modifies a key.  (This
+ *     enables the altSendsEscape resource).
+ *     Ps = 1 0 4 0  -> Keep selection even if not highlighted.
+ *     (This enables the keepSelection resource).
+ *     Ps = 1 0 4 1  -> Use the CLIPBOARD selection.  (This enables
+ *     the selectToClipboard resource).
+ *     Ps = 1 0 4 2  -> Enable Urgency window manager hint when
+ *     Control-G is received.  (This enables the bellIsUrgent
+ *     resource).
+ *     Ps = 1 0 4 3  -> Enable raising of the window when Control-G
+ *     is received.  (enables the popOnBell resource).
+ *     Ps = 1 0 4 7  -> Use Alternate Screen Buffer.  (This may be
+ *     disabled by the titeInhibit resource).
+ *     Ps = 1 0 4 8  -> Save cursor as in DECSC.  (This may be dis-
+ *     abled by the titeInhibit resource).
+ *     Ps = 1 0 4 9  -> Save cursor as in DECSC and use Alternate
+ *     Screen Buffer, clearing it first.  (This may be disabled by
+ *     the titeInhibit resource).  This combines the effects of the 1
+ *     0 4 7  and 1 0 4 8  modes.  Use this with terminfo-based
+ *     applications rather than the 4 7  mode.
+ *     Ps = 1 0 5 0  -> Set terminfo/termcap function-key mode.
+ *     Ps = 1 0 5 1  -> Set Sun function-key mode.
+ *     Ps = 1 0 5 2  -> Set HP function-key mode.
+ *     Ps = 1 0 5 3  -> Set SCO function-key mode.
+ *     Ps = 1 0 6 0  -> Set legacy keyboard emulation (X11R6).
+ *     Ps = 1 0 6 1  -> Set VT220 keyboard emulation.
+ *     Ps = 2 0 0 4  -> Set bracketed paste mode.
+ * Modes:
+ *   http: *vt100.net/docs/vt220-rm/chapter4.html
+ */Terminal.prototype.setMode=function(params){if((typeof params==='undefined'?'undefined':_typeof(params))==='object'){var l=params.length,i=0;for(;i<l;i++){this.setMode(params[i]);}return;}if(!this.prefix){switch(params){case 4:this.insertMode=true;break;case 20://this.convertEol = true;
+break;}}else if(this.prefix==='?'){switch(params){case 1:this.applicationCursor=true;break;case 2:this.setgCharset(0,Terminal.charsets.US);this.setgCharset(1,Terminal.charsets.US);this.setgCharset(2,Terminal.charsets.US);this.setgCharset(3,Terminal.charsets.US);// set VT100 mode here
+break;case 3:// 132 col mode
+this.savedCols=this.cols;this.resize(132,this.rows);break;case 6:this.originMode=true;break;case 7:this.wraparoundMode=true;break;case 12:// this.cursorBlink = true;
+break;case 66:this.log('Serial port requested application keypad.');this.applicationKeypad=true;this.viewport.syncScrollArea();break;case 9:// X10 Mouse
+// no release, no motion, no wheel, no modifiers.
+case 1000:// vt200 mouse
+// no motion.
+// no modifiers, except control on the wheel.
+case 1002:// button event mouse
+case 1003:// any event mouse
+// any event - sends motion events,
+// even if there is no button held down.
+this.x10Mouse=params===9;this.vt200Mouse=params===1000;this.normalMouse=params>1000;this.mouseEvents=true;this.element.style.cursor='default';this.log('Binding to mouse events.');break;case 1004:// send focusin/focusout events
+// focusin: ^[[I
+// focusout: ^[[O
+this.sendFocus=true;break;case 1005:// utf8 ext mode mouse
+this.utfMouse=true;// for wide terminals
+// simply encodes large values as utf8 characters
+break;case 1006:// sgr ext mode mouse
+this.sgrMouse=true;// for wide terminals
+// does not add 32 to fields
+// press: ^[[<b;x;yM
+// release: ^[[<b;x;ym
+break;case 1015:// urxvt ext mode mouse
+this.urxvtMouse=true;// for wide terminals
+// numbers for fields
+// press: ^[[b;x;yM
+// motion: ^[[b;x;yT
+break;case 25:// show cursor
+this.cursorHidden=false;break;case 1049:// alt screen buffer cursor
+//this.saveCursor();
+;// FALL-THROUGH
+case 47:// alt screen buffer
+case 1047:// alt screen buffer
+if(!this.normal){var normal={lines:this.lines,ybase:this.ybase,ydisp:this.ydisp,x:this.x,y:this.y,scrollTop:this.scrollTop,scrollBottom:this.scrollBottom,tabs:this.tabs// XXX save charset(s) here?
+// charset: this.charset,
+// glevel: this.glevel,
+// charsets: this.charsets
+};this.reset();this.normal=normal;this.showCursor();}break;}}};/**
+ * CSI Pm l  Reset Mode (RM).
+ *     Ps = 2  -> Keyboard Action Mode (AM).
+ *     Ps = 4  -> Replace Mode (IRM).
+ *     Ps = 1 2  -> Send/receive (SRM).
+ *     Ps = 2 0  -> Normal Linefeed (LNM).
+ * CSI ? Pm l
+ *   DEC Private Mode Reset (DECRST).
+ *     Ps = 1  -> Normal Cursor Keys (DECCKM).
+ *     Ps = 2  -> Designate VT52 mode (DECANM).
+ *     Ps = 3  -> 80 Column Mode (DECCOLM).
+ *     Ps = 4  -> Jump (Fast) Scroll (DECSCLM).
+ *     Ps = 5  -> Normal Video (DECSCNM).
+ *     Ps = 6  -> Normal Cursor Mode (DECOM).
+ *     Ps = 7  -> No Wraparound Mode (DECAWM).
+ *     Ps = 8  -> No Auto-repeat Keys (DECARM).
+ *     Ps = 9  -> Don't send Mouse X & Y on button press.
+ *     Ps = 1 0  -> Hide toolbar (rxvt).
+ *     Ps = 1 2  -> Stop Blinking Cursor (att610).
+ *     Ps = 1 8  -> Don't print form feed (DECPFF).
+ *     Ps = 1 9  -> Limit print to scrolling region (DECPEX).
+ *     Ps = 2 5  -> Hide Cursor (DECTCEM).
+ *     Ps = 3 0  -> Don't show scrollbar (rxvt).
+ *     Ps = 3 5  -> Disable font-shifting functions (rxvt).
+ *     Ps = 4 0  -> Disallow 80 -> 132 Mode.
+ *     Ps = 4 1  -> No more(1) fix (see curses resource).
+ *     Ps = 4 2  -> Disable Nation Replacement Character sets (DEC-
+ *     NRCM).
+ *     Ps = 4 4  -> Turn Off Margin Bell.
+ *     Ps = 4 5  -> No Reverse-wraparound Mode.
+ *     Ps = 4 6  -> Stop Logging.  (This is normally disabled by a
+ *     compile-time option).
+ *     Ps = 4 7  -> Use Normal Screen Buffer.
+ *     Ps = 6 6  -> Numeric keypad (DECNKM).
+ *     Ps = 6 7  -> Backarrow key sends delete (DECBKM).
+ *     Ps = 1 0 0 0  -> Don't send Mouse X & Y on button press and
+ *     release.  See the section Mouse Tracking.
+ *     Ps = 1 0 0 1  -> Don't use Hilite Mouse Tracking.
+ *     Ps = 1 0 0 2  -> Don't use Cell Motion Mouse Tracking.
+ *     Ps = 1 0 0 3  -> Don't use All Motion Mouse Tracking.
+ *     Ps = 1 0 0 4  -> Don't send FocusIn/FocusOut events.
+ *     Ps = 1 0 0 5  -> Disable Extended Mouse Mode.
+ *     Ps = 1 0 1 0  -> Don't scroll to bottom on tty output
+ *     (rxvt).
+ *     Ps = 1 0 1 1  -> Don't scroll to bottom on key press (rxvt).
+ *     Ps = 1 0 3 4  -> Don't interpret "meta" key.  (This disables
+ *     the eightBitInput resource).
+ *     Ps = 1 0 3 5  -> Disable special modifiers for Alt and Num-
+ *     Lock keys.  (This disables the numLock resource).
+ *     Ps = 1 0 3 6  -> Don't send ESC  when Meta modifies a key.
+ *     (This disables the metaSendsEscape resource).
+ *     Ps = 1 0 3 7  -> Send VT220 Remove from the editing-keypad
+ *     Delete key.
+ *     Ps = 1 0 3 9  -> Don't send ESC  when Alt modifies a key.
+ *     (This disables the altSendsEscape resource).
+ *     Ps = 1 0 4 0  -> Do not keep selection when not highlighted.
+ *     (This disables the keepSelection resource).
+ *     Ps = 1 0 4 1  -> Use the PRIMARY selection.  (This disables
+ *     the selectToClipboard resource).
+ *     Ps = 1 0 4 2  -> Disable Urgency window manager hint when
+ *     Control-G is received.  (This disables the bellIsUrgent
+ *     resource).
+ *     Ps = 1 0 4 3  -> Disable raising of the window when Control-
+ *     G is received.  (This disables the popOnBell resource).
+ *     Ps = 1 0 4 7  -> Use Normal Screen Buffer, clearing screen
+ *     first if in the Alternate Screen.  (This may be disabled by
+ *     the titeInhibit resource).
+ *     Ps = 1 0 4 8  -> Restore cursor as in DECRC.  (This may be
+ *     disabled by the titeInhibit resource).
+ *     Ps = 1 0 4 9  -> Use Normal Screen Buffer and restore cursor
+ *     as in DECRC.  (This may be disabled by the titeInhibit
+ *     resource).  This combines the effects of the 1 0 4 7  and 1 0
+ *     4 8  modes.  Use this with terminfo-based applications rather
+ *     than the 4 7  mode.
+ *     Ps = 1 0 5 0  -> Reset terminfo/termcap function-key mode.
+ *     Ps = 1 0 5 1  -> Reset Sun function-key mode.
+ *     Ps = 1 0 5 2  -> Reset HP function-key mode.
+ *     Ps = 1 0 5 3  -> Reset SCO function-key mode.
+ *     Ps = 1 0 6 0  -> Reset legacy keyboard emulation (X11R6).
+ *     Ps = 1 0 6 1  -> Reset keyboard emulation to Sun/PC style.
+ *     Ps = 2 0 0 4  -> Reset bracketed paste mode.
+ */Terminal.prototype.resetMode=function(params){if((typeof params==='undefined'?'undefined':_typeof(params))==='object'){var l=params.length,i=0;for(;i<l;i++){this.resetMode(params[i]);}return;}if(!this.prefix){switch(params){case 4:this.insertMode=false;break;case 20://this.convertEol = false;
+break;}}else if(this.prefix==='?'){switch(params){case 1:this.applicationCursor=false;break;case 3:if(this.cols===132&&this.savedCols){this.resize(this.savedCols,this.rows);}delete this.savedCols;break;case 6:this.originMode=false;break;case 7:this.wraparoundMode=false;break;case 12:// this.cursorBlink = false;
+break;case 66:this.log('Switching back to normal keypad.');this.applicationKeypad=false;this.viewport.syncScrollArea();break;case 9:// X10 Mouse
+case 1000:// vt200 mouse
+case 1002:// button event mouse
+case 1003:// any event mouse
+this.x10Mouse=false;this.vt200Mouse=false;this.normalMouse=false;this.mouseEvents=false;this.element.style.cursor='';break;case 1004:// send focusin/focusout events
+this.sendFocus=false;break;case 1005:// utf8 ext mode mouse
+this.utfMouse=false;break;case 1006:// sgr ext mode mouse
+this.sgrMouse=false;break;case 1015:// urxvt ext mode mouse
+this.urxvtMouse=false;break;case 25:// hide cursor
+this.cursorHidden=true;break;case 1049:// alt screen buffer cursor
+;// FALL-THROUGH
+case 47:// normal screen buffer
+case 1047:// normal screen buffer - clearing it first
+if(this.normal){this.lines=this.normal.lines;this.ybase=this.normal.ybase;this.ydisp=this.normal.ydisp;this.x=this.normal.x;this.y=this.normal.y;this.scrollTop=this.normal.scrollTop;this.scrollBottom=this.normal.scrollBottom;this.tabs=this.normal.tabs;this.normal=null;// if (params === 1049) {
+//   this.x = this.savedX;
+//   this.y = this.savedY;
+// }
+this.refresh(0,this.rows-1);this.showCursor();}break;}}};/**
+ * CSI Ps ; Ps r
+ *   Set Scrolling Region [top;bottom] (default = full size of win-
+ *   dow) (DECSTBM).
+ * CSI ? Pm r
+ */Terminal.prototype.setScrollRegion=function(params){if(this.prefix)return;this.scrollTop=(params[0]||1)-1;this.scrollBottom=(params[1]||this.rows)-1;this.x=0;this.y=0;};/**
+ * CSI s
+ *   Save cursor (ANSI.SYS).
+ */Terminal.prototype.saveCursor=function(params){this.savedX=this.x;this.savedY=this.y;};/**
+ * CSI u
+ *   Restore cursor (ANSI.SYS).
+ */Terminal.prototype.restoreCursor=function(params){this.x=this.savedX||0;this.y=this.savedY||0;};/**
+ * Lesser Used
+ *//**
+ * CSI Ps I
+ *   Cursor Forward Tabulation Ps tab stops (default = 1) (CHT).
+ */Terminal.prototype.cursorForwardTab=function(params){var param=params[0]||1;while(param--){this.x=this.nextStop();}};/**
+ * CSI Ps S  Scroll up Ps lines (default = 1) (SU).
+ */Terminal.prototype.scrollUp=function(params){var param=params[0]||1;while(param--){this.lines.splice(this.ybase+this.scrollTop,1);this.lines.splice(this.ybase+this.scrollBottom,0,this.blankLine());}// this.maxRange();
+this.updateRange(this.scrollTop);this.updateRange(this.scrollBottom);};/**
+     * CSI Ps T  Scroll down Ps lines (default = 1) (SD).
+     */Terminal.prototype.scrollDown=function(params){var param=params[0]||1;while(param--){this.lines.splice(this.ybase+this.scrollBottom,1);this.lines.splice(this.ybase+this.scrollTop,0,this.blankLine());}// this.maxRange();
+this.updateRange(this.scrollTop);this.updateRange(this.scrollBottom);};/**
+ * CSI Ps ; Ps ; Ps ; Ps ; Ps T
+ *   Initiate highlight mouse tracking.  Parameters are
+ *   [func;startx;starty;firstrow;lastrow].  See the section Mouse
+ *   Tracking.
+ */Terminal.prototype.initMouseTracking=function(params){// Relevant: DECSET 1001
+};/**
+ * CSI > Ps; Ps T
+ *   Reset one or more features of the title modes to the default
+ *   value.  Normally, "reset" disables the feature.  It is possi-
+ *   ble to disable the ability to reset features by compiling a
+ *   different default for the title modes into xterm.
+ *     Ps = 0  -> Do not set window/icon labels using hexadecimal.
+ *     Ps = 1  -> Do not query window/icon labels using hexadeci-
+ *     mal.
+ *     Ps = 2  -> Do not set window/icon labels using UTF-8.
+ *     Ps = 3  -> Do not query window/icon labels using UTF-8.
+ *   (See discussion of "Title Modes").
+ */Terminal.prototype.resetTitleModes=function(params){;};/**
+ * CSI Ps Z  Cursor Backward Tabulation Ps tab stops (default = 1) (CBT).
+ */Terminal.prototype.cursorBackwardTab=function(params){var param=params[0]||1;while(param--){this.x=this.prevStop();}};/**
+ * CSI Ps b  Repeat the preceding graphic character Ps times (REP).
+ */Terminal.prototype.repeatPrecedingCharacter=function(params){var param=params[0]||1,line=this.lines[this.ybase+this.y],ch=line[this.x-1]||[this.defAttr,' ',1];while(param--){line[this.x++]=ch;}};/**
+ * CSI Ps g  Tab Clear (TBC).
+ *     Ps = 0  -> Clear Current Column (default).
+ *     Ps = 3  -> Clear All.
+ * Potentially:
+ *   Ps = 2  -> Clear Stops on Line.
+ *   http://vt100.net/annarbor/aaa-ug/section6.html
+ */Terminal.prototype.tabClear=function(params){var param=params[0];if(param<=0){delete this.tabs[this.x];}else if(param===3){this.tabs={};}};/**
+ * CSI Pm i  Media Copy (MC).
+ *     Ps = 0  -> Print screen (default).
+ *     Ps = 4  -> Turn off printer controller mode.
+ *     Ps = 5  -> Turn on printer controller mode.
+ * CSI ? Pm i
+ *   Media Copy (MC, DEC-specific).
+ *     Ps = 1  -> Print line containing cursor.
+ *     Ps = 4  -> Turn off autoprint mode.
+ *     Ps = 5  -> Turn on autoprint mode.
+ *     Ps = 1  0  -> Print composed display, ignores DECPEX.
+ *     Ps = 1  1  -> Print all pages.
+ */Terminal.prototype.mediaCopy=function(params){;};/**
+ * CSI > Ps; Ps m
+ *   Set or reset resource-values used by xterm to decide whether
+ *   to construct escape sequences holding information about the
+ *   modifiers pressed with a given key.  The first parameter iden-
+ *   tifies the resource to set/reset.  The second parameter is the
+ *   value to assign to the resource.  If the second parameter is
+ *   omitted, the resource is reset to its initial value.
+ *     Ps = 1  -> modifyCursorKeys.
+ *     Ps = 2  -> modifyFunctionKeys.
+ *     Ps = 4  -> modifyOtherKeys.
+ *   If no parameters are given, all resources are reset to their
+ *   initial values.
+ */Terminal.prototype.setResources=function(params){;};/**
+ * CSI > Ps n
+ *   Disable modifiers which may be enabled via the CSI > Ps; Ps m
+ *   sequence.  This corresponds to a resource value of "-1", which
+ *   cannot be set with the other sequence.  The parameter identi-
+ *   fies the resource to be disabled:
+ *     Ps = 1  -> modifyCursorKeys.
+ *     Ps = 2  -> modifyFunctionKeys.
+ *     Ps = 4  -> modifyOtherKeys.
+ *   If the parameter is omitted, modifyFunctionKeys is disabled.
+ *   When modifyFunctionKeys is disabled, xterm uses the modifier
+ *   keys to make an extended sequence of functions rather than
+ *   adding a parameter to each function key to denote the modi-
+ *   fiers.
+ */Terminal.prototype.disableModifiers=function(params){;};/**
+ * CSI > Ps p
+ *   Set resource value pointerMode.  This is used by xterm to
+ *   decide whether to hide the pointer cursor as the user types.
+ *   Valid values for the parameter:
+ *     Ps = 0  -> never hide the pointer.
+ *     Ps = 1  -> hide if the mouse tracking mode is not enabled.
+ *     Ps = 2  -> always hide the pointer.  If no parameter is
+ *     given, xterm uses the default, which is 1 .
+ */Terminal.prototype.setPointerMode=function(params){;};/**
+ * CSI ! p   Soft terminal reset (DECSTR).
+ * http://vt100.net/docs/vt220-rm/table4-10.html
+ */Terminal.prototype.softReset=function(params){this.cursorHidden=false;this.insertMode=false;this.originMode=false;this.wraparoundMode=false;// autowrap
+this.applicationKeypad=false;// ?
+this.viewport.syncScrollArea();this.applicationCursor=false;this.scrollTop=0;this.scrollBottom=this.rows-1;this.curAttr=this.defAttr;this.x=this.y=0;// ?
+this.charset=null;this.glevel=0;// ??
+this.charsets=[null];// ??
+};/**
+ * CSI Ps$ p
+ *   Request ANSI mode (DECRQM).  For VT300 and up, reply is
+ *     CSI Ps; Pm$ y
+ *   where Ps is the mode number as in RM, and Pm is the mode
+ *   value:
+ *     0 - not recognized
+ *     1 - set
+ *     2 - reset
+ *     3 - permanently set
+ *     4 - permanently reset
+ */Terminal.prototype.requestAnsiMode=function(params){;};/**
+ * CSI ? Ps$ p
+ *   Request DEC private mode (DECRQM).  For VT300 and up, reply is
+ *     CSI ? Ps; Pm$ p
+ *   where Ps is the mode number as in DECSET, Pm is the mode value
+ *   as in the ANSI DECRQM.
+ */Terminal.prototype.requestPrivateMode=function(params){;};/**
+ * CSI Ps ; Ps " p
+ *   Set conformance level (DECSCL).  Valid values for the first
+ *   parameter:
+ *     Ps = 6 1  -> VT100.
+ *     Ps = 6 2  -> VT200.
+ *     Ps = 6 3  -> VT300.
+ *   Valid values for the second parameter:
+ *     Ps = 0  -> 8-bit controls.
+ *     Ps = 1  -> 7-bit controls (always set for VT100).
+ *     Ps = 2  -> 8-bit controls.
+ */Terminal.prototype.setConformanceLevel=function(params){;};/**
+ * CSI Ps q  Load LEDs (DECLL).
+ *     Ps = 0  -> Clear all LEDS (default).
+ *     Ps = 1  -> Light Num Lock.
+ *     Ps = 2  -> Light Caps Lock.
+ *     Ps = 3  -> Light Scroll Lock.
+ *     Ps = 2  1  -> Extinguish Num Lock.
+ *     Ps = 2  2  -> Extinguish Caps Lock.
+ *     Ps = 2  3  -> Extinguish Scroll Lock.
+ */Terminal.prototype.loadLEDs=function(params){;};/**
+ * CSI Ps SP q
+ *   Set cursor style (DECSCUSR, VT520).
+ *     Ps = 0  -> blinking block.
+ *     Ps = 1  -> blinking block (default).
+ *     Ps = 2  -> steady block.
+ *     Ps = 3  -> blinking underline.
+ *     Ps = 4  -> steady underline.
+ */Terminal.prototype.setCursorStyle=function(params){;};/**
+ * CSI Ps " q
+ *   Select character protection attribute (DECSCA).  Valid values
+ *   for the parameter:
+ *     Ps = 0  -> DECSED and DECSEL can erase (default).
+ *     Ps = 1  -> DECSED and DECSEL cannot erase.
+ *     Ps = 2  -> DECSED and DECSEL can erase.
+ */Terminal.prototype.setCharProtectionAttr=function(params){;};/**
+ * CSI ? Pm r
+ *   Restore DEC Private Mode Values.  The value of Ps previously
+ *   saved is restored.  Ps values are the same as for DECSET.
+ */Terminal.prototype.restorePrivateValues=function(params){;};/**
+ * CSI Pt; Pl; Pb; Pr; Ps$ r
+ *   Change Attributes in Rectangular Area (DECCARA), VT400 and up.
+ *     Pt; Pl; Pb; Pr denotes the rectangle.
+ *     Ps denotes the SGR attributes to change: 0, 1, 4, 5, 7.
+ * NOTE: xterm doesn't enable this code by default.
+ */Terminal.prototype.setAttrInRectangle=function(params){var t=params[0],l=params[1],b=params[2],r=params[3],attr=params[4];var line,i;for(;t<b+1;t++){line=this.lines[this.ybase+t];for(i=l;i<r;i++){line[i]=[attr,line[i][1]];}}// this.maxRange();
+this.updateRange(params[0]);this.updateRange(params[2]);};/**
+ * CSI Pc; Pt; Pl; Pb; Pr$ x
+ *   Fill Rectangular Area (DECFRA), VT420 and up.
+ *     Pc is the character to use.
+ *     Pt; Pl; Pb; Pr denotes the rectangle.
+ * NOTE: xterm doesn't enable this code by default.
+ */Terminal.prototype.fillRectangle=function(params){var ch=params[0],t=params[1],l=params[2],b=params[3],r=params[4];var line,i;for(;t<b+1;t++){line=this.lines[this.ybase+t];for(i=l;i<r;i++){line[i]=[line[i][0],String.fromCharCode(ch)];}}// this.maxRange();
+this.updateRange(params[1]);this.updateRange(params[3]);};/**
+ * CSI Ps ; Pu ' z
+ *   Enable Locator Reporting (DECELR).
+ *   Valid values for the first parameter:
+ *     Ps = 0  -> Locator disabled (default).
+ *     Ps = 1  -> Locator enabled.
+ *     Ps = 2  -> Locator enabled for one report, then disabled.
+ *   The second parameter specifies the coordinate unit for locator
+ *   reports.
+ *   Valid values for the second parameter:
+ *     Pu = 0  <- or omitted -> default to character cells.
+ *     Pu = 1  <- device physical pixels.
+ *     Pu = 2  <- character cells.
+ */Terminal.prototype.enableLocatorReporting=function(params){var val=params[0]>0;//this.mouseEvents = val;
+//this.decLocator = val;
+};/**
+ * CSI Pt; Pl; Pb; Pr$ z
+ *   Erase Rectangular Area (DECERA), VT400 and up.
+ *     Pt; Pl; Pb; Pr denotes the rectangle.
+ * NOTE: xterm doesn't enable this code by default.
+ */Terminal.prototype.eraseRectangle=function(params){var t=params[0],l=params[1],b=params[2],r=params[3];var line,i,ch;ch=[this.eraseAttr(),' ',1];// xterm?
+for(;t<b+1;t++){line=this.lines[this.ybase+t];for(i=l;i<r;i++){line[i]=ch;}}// this.maxRange();
+this.updateRange(params[0]);this.updateRange(params[2]);};/**
+ * CSI P m SP }
+ * Insert P s Column(s) (default = 1) (DECIC), VT420 and up.
+ * NOTE: xterm doesn't enable this code by default.
+ */Terminal.prototype.insertColumns=function(){var param=params[0],l=this.ybase+this.rows,ch=[this.eraseAttr(),' ',1]// xterm?
+,i;while(param--){for(i=this.ybase;i<l;i++){this.lines[i].splice(this.x+1,0,ch);this.lines[i].pop();}}this.maxRange();};/**
+ * CSI P m SP ~
+ * Delete P s Column(s) (default = 1) (DECDC), VT420 and up
+ * NOTE: xterm doesn't enable this code by default.
+ */Terminal.prototype.deleteColumns=function(){var param=params[0],l=this.ybase+this.rows,ch=[this.eraseAttr(),' ',1]// xterm?
+,i;while(param--){for(i=this.ybase;i<l;i++){this.lines[i].splice(this.x,1);this.lines[i].push(ch);}}this.maxRange();};/**
+ * Character Sets
+ */Terminal.charsets={};// DEC Special Character and Line Drawing Set.
+// http://vt100.net/docs/vt102-ug/table5-13.html
+// A lot of curses apps use this if they see TERM=xterm.
+// testing: echo -e '\e(0a\e(B'
+// The xterm output sometimes seems to conflict with the
+// reference above. xterm seems in line with the reference
+// when running vttest however.
+// The table below now uses xterm's output from vttest.
+Terminal.charsets.SCLD={// (0
+'`':'◆',// '◆'
+'a':'▒',// '▒'
+'b':'\t',// '\t'
+'c':'\f',// '\f'
+'d':'\r',// '\r'
+'e':'\n',// '\n'
+'f':'°',// '°'
+'g':'±',// '±'
+'h':'␤',// '\u2424' (NL)
+'i':'\u000b',// '\v'
+'j':'┘',// '┘'
+'k':'┐',// '┐'
+'l':'┌',// '┌'
+'m':'└',// '└'
+'n':'┼',// '┼'
+'o':'⎺',// '⎺'
+'p':'⎻',// '⎻'
+'q':'─',// '─'
+'r':'⎼',// '⎼'
+'s':'⎽',// '⎽'
+'t':'├',// '├'
+'u':'┤',// '┤'
+'v':'┴',// '┴'
+'w':'┬',// '┬'
+'x':'│',// '│'
+'y':'≤',// '≤'
+'z':'≥',// '≥'
+'{':'π',// 'π'
+'|':'≠',// '≠'
+'}':'£',// '£'
+'~':'·'// '·'
+};Terminal.charsets.UK=null;// (A
+Terminal.charsets.US=null;// (B (USASCII)
+Terminal.charsets.Dutch=null;// (4
+Terminal.charsets.Finnish=null;// (C or (5
+Terminal.charsets.French=null;// (R
+Terminal.charsets.FrenchCanadian=null;// (Q
+Terminal.charsets.German=null;// (K
+Terminal.charsets.Italian=null;// (Y
+Terminal.charsets.NorwegianDanish=null;// (E or (6
+Terminal.charsets.Spanish=null;// (Z
+Terminal.charsets.Swedish=null;// (H or (7
+Terminal.charsets.Swiss=null;// (=
+Terminal.charsets.ISOLatin=null;// /A
+/**
+ * Helpers
+ */function contains(el,arr){for(var i=0;i<arr.length;i+=1){if(el===arr[i]){return true;}}return false;}function on(el,type,handler,capture){if(!Array.isArray(el)){el=[el];}el.forEach(function(element){element.addEventListener(type,handler,capture||false);});}function off(el,type,handler,capture){el.removeEventListener(type,handler,capture||false);}function cancel(ev,force){if(!this.cancelEvents&&!force){return;}ev.preventDefault();ev.stopPropagation();return false;}function inherits(child,parent){function f(){this.constructor=child;}f.prototype=parent.prototype;child.prototype=new f();}// if bold is broken, we can't
+// use it in the terminal.
+function isBoldBroken(document){var body=document.getElementsByTagName('body')[0];var el=document.createElement('span');el.innerHTML='hello world';body.appendChild(el);var w1=el.scrollWidth;el.style.fontWeight='bold';var w2=el.scrollWidth;body.removeChild(el);return w1!==w2;}function indexOf(obj,el){var i=obj.length;while(i--){if(obj[i]===el)return i;}return-1;}function isThirdLevelShift(term,ev){var thirdLevelKey=term.isMac&&ev.altKey&&!ev.ctrlKey&&!ev.metaKey||term.isMSWindows&&ev.altKey&&ev.ctrlKey&&!ev.metaKey;if(ev.type=='keypress'){return thirdLevelKey;}// Don't invoke for arrows, pageDown, home, backspace, etc. (on non-keypress events)
+return thirdLevelKey&&(!ev.keyCode||ev.keyCode>47);}function matchColor(r1,g1,b1){var hash=r1<<16|g1<<8|b1;if(matchColor._cache[hash]!=null){return matchColor._cache[hash];}var ldiff=Infinity,li=-1,i=0,c,r2,g2,b2,diff;for(;i<Terminal.vcolors.length;i++){c=Terminal.vcolors[i];r2=c[0];g2=c[1];b2=c[2];diff=matchColor.distance(r1,g1,b1,r2,g2,b2);if(diff===0){li=i;break;}if(diff<ldiff){ldiff=diff;li=i;}}return matchColor._cache[hash]=li;}matchColor._cache={};// http://stackoverflow.com/questions/1633828
+matchColor.distance=function(r1,g1,b1,r2,g2,b2){return Math.pow(30*(r1-r2),2)+Math.pow(59*(g1-g2),2)+Math.pow(11*(b1-b2),2);};function each(obj,iter,con){if(obj.forEach)return obj.forEach(iter,con);for(var i=0;i<obj.length;i++){iter.call(con,obj[i],i,obj);}}function keys(obj){if(Object.keys)return Object.keys(obj);var key,keys=[];for(key in obj){if(Object.prototype.hasOwnProperty.call(obj,key)){keys.push(key);}}return keys;}var wcwidth=function(opts){// extracted from https://www.cl.cam.ac.uk/%7Emgk25/ucs/wcwidth.c
+// combining characters
+var COMBINING=[[0x0300,0x036F],[0x0483,0x0486],[0x0488,0x0489],[0x0591,0x05BD],[0x05BF,0x05BF],[0x05C1,0x05C2],[0x05C4,0x05C5],[0x05C7,0x05C7],[0x0600,0x0603],[0x0610,0x0615],[0x064B,0x065E],[0x0670,0x0670],[0x06D6,0x06E4],[0x06E7,0x06E8],[0x06EA,0x06ED],[0x070F,0x070F],[0x0711,0x0711],[0x0730,0x074A],[0x07A6,0x07B0],[0x07EB,0x07F3],[0x0901,0x0902],[0x093C,0x093C],[0x0941,0x0948],[0x094D,0x094D],[0x0951,0x0954],[0x0962,0x0963],[0x0981,0x0981],[0x09BC,0x09BC],[0x09C1,0x09C4],[0x09CD,0x09CD],[0x09E2,0x09E3],[0x0A01,0x0A02],[0x0A3C,0x0A3C],[0x0A41,0x0A42],[0x0A47,0x0A48],[0x0A4B,0x0A4D],[0x0A70,0x0A71],[0x0A81,0x0A82],[0x0ABC,0x0ABC],[0x0AC1,0x0AC5],[0x0AC7,0x0AC8],[0x0ACD,0x0ACD],[0x0AE2,0x0AE3],[0x0B01,0x0B01],[0x0B3C,0x0B3C],[0x0B3F,0x0B3F],[0x0B41,0x0B43],[0x0B4D,0x0B4D],[0x0B56,0x0B56],[0x0B82,0x0B82],[0x0BC0,0x0BC0],[0x0BCD,0x0BCD],[0x0C3E,0x0C40],[0x0C46,0x0C48],[0x0C4A,0x0C4D],[0x0C55,0x0C56],[0x0CBC,0x0CBC],[0x0CBF,0x0CBF],[0x0CC6,0x0CC6],[0x0CCC,0x0CCD],[0x0CE2,0x0CE3],[0x0D41,0x0D43],[0x0D4D,0x0D4D],[0x0DCA,0x0DCA],[0x0DD2,0x0DD4],[0x0DD6,0x0DD6],[0x0E31,0x0E31],[0x0E34,0x0E3A],[0x0E47,0x0E4E],[0x0EB1,0x0EB1],[0x0EB4,0x0EB9],[0x0EBB,0x0EBC],[0x0EC8,0x0ECD],[0x0F18,0x0F19],[0x0F35,0x0F35],[0x0F37,0x0F37],[0x0F39,0x0F39],[0x0F71,0x0F7E],[0x0F80,0x0F84],[0x0F86,0x0F87],[0x0F90,0x0F97],[0x0F99,0x0FBC],[0x0FC6,0x0FC6],[0x102D,0x1030],[0x1032,0x1032],[0x1036,0x1037],[0x1039,0x1039],[0x1058,0x1059],[0x1160,0x11FF],[0x135F,0x135F],[0x1712,0x1714],[0x1732,0x1734],[0x1752,0x1753],[0x1772,0x1773],[0x17B4,0x17B5],[0x17B7,0x17BD],[0x17C6,0x17C6],[0x17C9,0x17D3],[0x17DD,0x17DD],[0x180B,0x180D],[0x18A9,0x18A9],[0x1920,0x1922],[0x1927,0x1928],[0x1932,0x1932],[0x1939,0x193B],[0x1A17,0x1A18],[0x1B00,0x1B03],[0x1B34,0x1B34],[0x1B36,0x1B3A],[0x1B3C,0x1B3C],[0x1B42,0x1B42],[0x1B6B,0x1B73],[0x1DC0,0x1DCA],[0x1DFE,0x1DFF],[0x200B,0x200F],[0x202A,0x202E],[0x2060,0x2063],[0x206A,0x206F],[0x20D0,0x20EF],[0x302A,0x302F],[0x3099,0x309A],[0xA806,0xA806],[0xA80B,0xA80B],[0xA825,0xA826],[0xFB1E,0xFB1E],[0xFE00,0xFE0F],[0xFE20,0xFE23],[0xFEFF,0xFEFF],[0xFFF9,0xFFFB],[0x10A01,0x10A03],[0x10A05,0x10A06],[0x10A0C,0x10A0F],[0x10A38,0x10A3A],[0x10A3F,0x10A3F],[0x1D167,0x1D169],[0x1D173,0x1D182],[0x1D185,0x1D18B],[0x1D1AA,0x1D1AD],[0x1D242,0x1D244],[0xE0001,0xE0001],[0xE0020,0xE007F],[0xE0100,0xE01EF]];// binary search
+function bisearch(ucs){var min=0;var max=COMBINING.length-1;var mid;if(ucs<COMBINING[0][0]||ucs>COMBINING[max][1])return false;while(max>=min){mid=Math.floor((min+max)/2);if(ucs>COMBINING[mid][1])min=mid+1;else if(ucs<COMBINING[mid][0])max=mid-1;else return true;}return false;}function wcwidth(ucs){// test for 8-bit control characters
+if(ucs===0)return opts.nul;if(ucs<32||ucs>=0x7f&&ucs<0xa0)return opts.control;// binary search in table of non-spacing characters
+if(bisearch(ucs))return 0;// if we arrive here, ucs is not a combining or C0/C1 control character
+return 1+(ucs>=0x1100&&(ucs<=0x115f||// Hangul Jamo init. consonants
+ucs==0x2329||ucs==0x232a||ucs>=0x2e80&&ucs<=0xa4cf&&ucs!=0x303f||// CJK..Yi
+ucs>=0xac00&&ucs<=0xd7a3||// Hangul Syllables
+ucs>=0xf900&&ucs<=0xfaff||// CJK Compat Ideographs
+ucs>=0xfe10&&ucs<=0xfe19||// Vertical forms
+ucs>=0xfe30&&ucs<=0xfe6f||// CJK Compat Forms
+ucs>=0xff00&&ucs<=0xff60||// Fullwidth Forms
+ucs>=0xffe0&&ucs<=0xffe6||ucs>=0x20000&&ucs<=0x2fffd||ucs>=0x30000&&ucs<=0x3fffd));}return wcwidth;}({nul:0,control:0});// configurable options
+/**
+ * Expose
+ */Terminal.EventEmitter=_EventEmitter.EventEmitter;Terminal.CompositionHelper=_CompositionHelper.CompositionHelper;Terminal.Viewport=_Viewport.Viewport;Terminal.inherits=inherits;/**
+ * Adds an event listener to the terminal.
+ *
+ * @param {string} event The name of the event. TODO: Document all event types
+ * @param {function} callback The function to call when the event is triggered.
+ */Terminal.on=on;Terminal.off=off;Terminal.cancel=cancel;module.exports=Terminal;
+
+}).call(this,"/src")
+
+},{"./CompositionHelper.js":1,"./EventEmitter.js":2,"./Viewport.js":3}]},{},[4])(4)
+});
+//# sourceMappingURL=xterm.js.map
diff --git a/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/jsdoc.json b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/jsdoc.json
new file mode 100644
index 0000000..66b174e
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/jsdoc.json
@@ -0,0 +1,26 @@
+{
+  "source": {
+    "include": [
+      "src/xterm.js",
+      "addons/attach/attach.js",
+      "addons/fit/fit.js",
+      "addons/fullscreen/fullscreen.js",
+      "addons/linkify/linkify.js"
+    ]
+  },
+  "opts": {
+    "readme": "README.md",
+    "template": "node_modules/docdash",
+    "encoding": "utf8",
+    "destination": "docs/",
+    "recurse": true,
+    "verbose": true
+  },
+  "plugins": [
+    "plugins/markdown"
+  ],
+  "templates": {
+    "cleverLinks": false,
+    "monospaceLinks": false
+  }
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/package.json b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/package.json
new file mode 100644
index 0000000..6b667dcc
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/package.json
@@ -0,0 +1,36 @@
+{
+  "name": "xterm",
+  "version": "1.1.3",
+  "ignore": [
+    "demo",
+    "test",
+    ".gitignore"
+  ],
+  "main": "src/xterm.js",
+  "repository": "https://github.com/sourcelair/xterm.js",
+  "license": "MIT",
+  "devDependencies": {
+    "babel-core": "6.14.0",
+    "babel-preset-es2015": "6.14.0",
+    "babelify": "^7.3.0",
+    "browserify": "^13.1.0",
+    "chai": "3.5.0",
+    "derequire": "^2.0.3",
+    "docdash": "0.4.0",
+    "exorcist": "^0.4.0",
+    "express": "4.13.4",
+    "express-ws": "2.0.0-rc.1",
+    "glob": "^7.0.5",
+    "jsdoc": "3.4.0",
+    "mocha": "2.5.3",
+    "nodemon": "1.10.2",
+    "pty.js": "0.3.1",
+    "sleep": "^3.0.1"
+  },
+  "scripts": {
+    "start": "nodemon --watch src --watch addons --exec bash -c './bin/build && node demo/app'",
+    "test": "mocha --recursive --compilers js:babel-core/register",
+    "build:docs": "jsdoc -c jsdoc.json",
+    "build": "./bin/build"
+  }
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/src/CompositionHelper.js b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/src/CompositionHelper.js
new file mode 100644
index 0000000..eeadd83a
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/src/CompositionHelper.js
@@ -0,0 +1,201 @@
+/**
+ * xterm.js: xterm, in the browser
+ * Copyright (c) 2016, SourceLair Limited <www.sourcelair.com> (MIT License)
+ */
+
+/**
+ * Encapsulates the logic for handling compositionstart, compositionupdate and compositionend
+ * events, displaying the in-progress composition to the UI and forwarding the final composition
+ * to the handler.
+ * @param {HTMLTextAreaElement} textarea The textarea that xterm uses for input.
+ * @param {HTMLElement} compositionView The element to display the in-progress composition in.
+ * @param {Terminal} terminal The Terminal to forward the finished composition to.
+ */
+function CompositionHelper(textarea, compositionView, terminal) {
+  this.textarea = textarea;
+  this.compositionView = compositionView;
+  this.terminal = terminal;
+
+  // Whether input composition is currently happening, eg. via a mobile keyboard, speech input
+  // or IME. This variable determines whether the compositionText should be displayed on the UI.
+  this.isComposing = false;
+
+  // The input currently being composed, eg. via a mobile keyboard, speech input or IME.
+  this.compositionText = null;
+
+  // The position within the input textarea's value of the current composition.
+  this.compositionPosition = { start: null, end: null };
+
+  // Whether a composition is in the process of being sent, setting this to false will cancel
+  // any in-progress composition.
+  this.isSendingComposition = false;
+}
+
+/**
+ * Handles the compositionstart event, activating the composition view.
+ */
+CompositionHelper.prototype.compositionstart = function() {
+  this.isComposing = true;
+  this.compositionPosition.start = this.textarea.value.length;
+  this.compositionView.textContent = '';
+  this.compositionView.classList.add('active');
+};
+
+/**
+ * Handles the compositionupdate event, updating the composition view.
+ * @param {CompositionEvent} ev The event.
+ */
+CompositionHelper.prototype.compositionupdate = function(ev) {
+  this.compositionView.textContent = ev.data;
+  this.updateCompositionElements();
+  var self = this;
+  setTimeout(function() {
+    self.compositionPosition.end = self.textarea.value.length;
+  }, 0);
+};
+
+/**
+ * Handles the compositionend event, hiding the composition view and sending the composition to
+ * the handler.
+ */
+CompositionHelper.prototype.compositionend = function() {
+  this.finalizeComposition(true);
+};
+
+/**
+ * Handles the keydown event, routing any necessary events to the CompositionHelper functions.
+ * @return Whether the Terminal should continue processing the keydown event.
+ */
+CompositionHelper.prototype.keydown = function(ev) {
+  if (this.isComposing || this.isSendingComposition) {
+    if (ev.keyCode === 229) {
+      // Continue composing if the keyCode is the "composition character"
+      return false;
+    } else if (ev.keyCode === 16 || ev.keyCode === 17 || ev.keyCode === 18) {
+      // Continue composing if the keyCode is a modifier key
+      return false;
+    } else {
+      // Finish composition immediately. This is mainly here for the case where enter is
+      // pressed and the handler needs to be triggered before the command is executed.
+      this.finalizeComposition(false);
+    }
+  }
+
+  if (ev.keyCode === 229) {
+    // If the "composition character" is used but gets to this point it means a non-composition
+    // character (eg. numbers and punctuation) was pressed when the IME was active.
+    this.handleAnyTextareaChanges();
+    return false;
+  }
+
+  return true;
+};
+
+/**
+ * Finalizes the composition, resuming regular input actions. This is called when a composition
+ * is ending.
+ * @param {boolean} waitForPropogation Whether to wait for events to propogate before sending
+ *   the input. This should be false if a non-composition keystroke is entered before the
+ *   compositionend event is triggered, such as enter, so that the composition is send before
+ *   the command is executed.
+ */
+CompositionHelper.prototype.finalizeComposition = function(waitForPropogation) {
+  this.compositionView.classList.remove('active');
+  this.isComposing = false;
+  this.clearTextareaPosition();
+
+  if (!waitForPropogation) {
+    // Cancel any delayed composition send requests and send the input immediately.
+    this.isSendingComposition = false;
+    var input = this.textarea.value.substring(this.compositionPosition.start, this.compositionPosition.end);
+    this.terminal.handler(input);
+  } else {
+    // Make a deep copy of the composition position here as a new compositionstart event may
+    // fire before the setTimeout executes.
+    var currentCompositionPosition = {
+      start: this.compositionPosition.start,
+      end: this.compositionPosition.end,
+    }
+
+    // Since composition* events happen before the changes take place in the textarea on most
+    // browsers, use a setTimeout with 0ms time to allow the native compositionend event to
+    // complete. This ensures the correct character is retrieved, this solution was used
+    // because:
+    // - The compositionend event's data property is unreliable, at least on Chromium
+    // - The last compositionupdate event's data property does not always accurately describe
+    //   the character, a counter example being Korean where an ending consonsant can move to
+    //   the following character if the following input is a vowel.
+    var self = this;
+    this.isSendingComposition = true;
+    setTimeout(function () {
+      // Ensure that the input has not already been sent
+      if (self.isSendingComposition) {
+        self.isSendingComposition = false;
+        var input;
+        if (self.isComposing) {
+          // Use the end position to get the string if a new composition has started.
+          input = self.textarea.value.substring(currentCompositionPosition.start, currentCompositionPosition.end);
+        } else {
+          // Don't use the end position here in order to pick up any characters after the
+          // composition has finished, for example when typing a non-composition character
+          // (eg. 2) after a composition character.
+          input = self.textarea.value.substring(currentCompositionPosition.start);
+        }
+        self.terminal.handler(input);
+      }
+    }, 0);
+  }
+};
+
+/**
+ * Apply any changes made to the textarea after the current event chain is allowed to complete.
+ * This should be called when not currently composing but a keydown event with the "composition
+ * character" (229) is triggered, in order to allow non-composition text to be entered when an
+ * IME is active.
+ */
+CompositionHelper.prototype.handleAnyTextareaChanges = function() {
+  var oldValue = this.textarea.value;
+  var self = this;
+  setTimeout(function() {
+    // Ignore if a composition has started since the timeout
+    if (!self.isComposing) {
+      var newValue = self.textarea.value;
+      var diff = newValue.replace(oldValue, '');
+      if (diff.length > 0) {
+        self.terminal.handler(diff);
+      }
+    }
+  }, 0);
+};
+
+/**
+ * Positions the composition view on top of the cursor and the textarea just below it (so the
+ * IME helper dialog is positioned correctly).
+ */
+CompositionHelper.prototype.updateCompositionElements = function(dontRecurse) {
+  if (!this.isComposing) {
+    return;
+  }
+  var cursor = this.terminal.element.querySelector('.terminal-cursor');
+  if (cursor) {
+    this.compositionView.style.left = cursor.offsetLeft + 'px';
+    this.compositionView.style.top = cursor.offsetTop + 'px';
+    var compositionViewBounds = this.compositionView.getBoundingClientRect();
+    this.textarea.style.left = cursor.offsetLeft + compositionViewBounds.width + 'px';
+    this.textarea.style.top = (cursor.offsetTop + cursor.offsetHeight) + 'px';
+  }
+  if (!dontRecurse) {
+    setTimeout(this.updateCompositionElements.bind(this, true), 0);
+  }
+};
+
+/**
+ * Clears the textarea's position so that the cursor does not blink on IE.
+ * @private
+ */
+CompositionHelper.prototype.clearTextareaPosition = function() {
+  this.textarea.style.left = '';
+  this.textarea.style.top = '';
+};
+
+export { CompositionHelper };
diff --git a/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/src/EventEmitter.js b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/src/EventEmitter.js
new file mode 100644
index 0000000..b17fbc7
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/src/EventEmitter.js
@@ -0,0 +1,64 @@
+/**
+ * EventEmitter
+ */
+
+function EventEmitter() {
+  this._events = this._events || {};
+}
+
+EventEmitter.prototype.addListener = function(type, listener) {
+  this._events[type] = this._events[type] || [];
+  this._events[type].push(listener);
+};
+
+EventEmitter.prototype.on = EventEmitter.prototype.addListener;
+
+EventEmitter.prototype.removeListener = function(type, listener) {
+  if (!this._events[type]) return;
+
+  var obj = this._events[type]
+  , i = obj.length;
+
+  while (i--) {
+    if (obj[i] === listener || obj[i].listener === listener) {
+      obj.splice(i, 1);
+      return;
+    }
+  }
+};
+
+EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
+
+EventEmitter.prototype.removeAllListeners = function(type) {
+  if (this._events[type]) delete this._events[type];
+};
+
+EventEmitter.prototype.once = function(type, listener) {
+  var self = this;
+  function on() {
+    var args = Array.prototype.slice.call(arguments);
+    this.removeListener(type, on);
+    return listener.apply(this, args);
+  }
+  on.listener = listener;
+  return this.on(type, on);
+};
+
+EventEmitter.prototype.emit = function(type) {
+  if (!this._events[type]) return;
+
+  var args = Array.prototype.slice.call(arguments, 1)
+  , obj = this._events[type]
+  , l = obj.length
+  , i = 0;
+
+  for (; i < l; i++) {
+    obj[i].apply(this, args);
+  }
+};
+
+EventEmitter.prototype.listeners = function(type) {
+  return this._events[type] = this._events[type] || [];
+};
+
+export { EventEmitter };
diff --git a/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/src/Viewport.js b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/src/Viewport.js
new file mode 100644
index 0000000..05f04f85
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/src/Viewport.js
@@ -0,0 +1,114 @@
+/**
+ * xterm.js: xterm, in the browser
+ * Copyright (c) 2016, SourceLair Limited <www.sourcelair.com> (MIT License)
+ */
+
+/**
+ * Represents the viewport of a terminal, the visible area within the larger buffer of output.
+ * Logic for the virtual scroll bar is included in this object.
+ * @param {Terminal} terminal The Terminal object.
+ * @param {HTMLElement} viewportElement The DOM element acting as the viewport
+ * @param {HTMLElement} charMeasureElement A DOM element used to measure the character size of
+ *   the terminal.
+ */
+function Viewport(terminal, viewportElement, scrollArea, charMeasureElement) {
+  this.terminal = terminal;
+  this.viewportElement = viewportElement;
+  this.scrollArea = scrollArea;
+  this.charMeasureElement = charMeasureElement;
+  this.currentRowHeight = 0;
+  this.lastRecordedBufferLength = 0;
+  this.lastRecordedViewportHeight = 0;
+
+  this.terminal.on('scroll', this.syncScrollArea.bind(this));
+  this.terminal.on('resize', this.syncScrollArea.bind(this));
+  this.viewportElement.addEventListener('scroll', this.onScroll.bind(this));
+
+  this.syncScrollArea();
+}
+
+/**
+ * Refreshes row height, setting line-height, viewport height and scroll area height if
+ * necessary.
+ * @param {number|undefined} charSize A character size measurement bounding rect object, if it
+ *   doesn't exist it will be created.
+ */
+Viewport.prototype.refresh = function(charSize) {
+  var size = charSize || this.charMeasureElement.getBoundingClientRect();
+  if (size.height > 0) {
+    var rowHeightChanged = size.height !== this.currentRowHeight;
+    if (rowHeightChanged) {
+      this.currentRowHeight = size.height;
+      this.viewportElement.style.lineHeight = size.height + 'px';
+      this.terminal.rowContainer.style.lineHeight = size.height + 'px';
+    }
+    var viewportHeightChanged = this.lastRecordedViewportHeight !== this.terminal.rows;
+    if (rowHeightChanged || viewportHeightChanged) {
+      this.lastRecordedViewportHeight = this.terminal.rows;
+      this.viewportElement.style.height = size.height * this.terminal.rows + 'px';
+    }
+    this.scrollArea.style.height = (size.height * this.lastRecordedBufferLength) + 'px';
+  }
+};
+
+/**
+ * Updates dimensions and synchronizes the scroll area if necessary.
+ */
+Viewport.prototype.syncScrollArea = function() {
+  if (this.lastRecordedBufferLength !== this.terminal.lines.length) {
+    // If buffer height changed
+    this.lastRecordedBufferLength = this.terminal.lines.length;
+    this.refresh();
+  } else if (this.lastRecordedViewportHeight !== this.terminal.rows) {
+    // If viewport height changed
+    this.refresh();
+  } else {
+    // If size has changed, refresh viewport
+    var size = this.charMeasureElement.getBoundingClientRect();
+    if (size.height !== this.currentRowHeight) {
+      this.refresh(size);
+    }
+  }
+
+  // Sync scrollTop
+  var scrollTop = this.terminal.ydisp * this.currentRowHeight;
+  if (this.viewportElement.scrollTop !== scrollTop) {
+    this.viewportElement.scrollTop = scrollTop;
+  }
+};
+
+/**
+ * Handles scroll events on the viewport, calculating the new viewport and requesting the
+ * terminal to scroll to it.
+ * @param {Event} ev The scroll event.
+ */
+Viewport.prototype.onScroll = function(ev) {
+  var newRow = Math.round(this.viewportElement.scrollTop / this.currentRowHeight);
+  var diff = newRow - this.terminal.ydisp;
+  this.terminal.scrollDisp(diff, true);
+};
+
+/**
+ * Handles mouse wheel events by adjusting the viewport's scrollTop and delegating the actual
+ * scrolling to `onScroll`, this event needs to be attached manually by the consumer of
+ * `Viewport`.
+ * @param {WheelEvent} ev The mouse wheel event.
+ */
+Viewport.prototype.onWheel = function(ev) {
+  if (ev.deltaY === 0) {
+    // Do nothing if it's not a vertical scroll event
+    return;
+  }
+  // Fallback to WheelEvent.DOM_DELTA_PIXEL
+  var multiplier = 1;
+  if (ev.deltaMode === WheelEvent.DOM_DELTA_LINE) {
+    multiplier = this.currentRowHeight;
+  } else if (ev.deltaMode === WheelEvent.DOM_DELTA_PAGE) {
+    multiplier = this.currentRowHeight * this.terminal.rows;
+  }
+  this.viewportElement.scrollTop += ev.deltaY * multiplier;
+  // Prevent the page from scrolling when the terminal scrolls
+  ev.preventDefault();
+};
+
+export { Viewport };
diff --git a/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/src/xterm.css b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/src/xterm.css
new file mode 100644
index 0000000..8295eb65
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/src/xterm.css
@@ -0,0 +1,2196 @@
+/**
+ * xterm.js: xterm, in the browser
+ * Copyright (c) 2014, sourceLair Limited (www.sourcelair.com (MIT License)
+ * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
+ * https://github.com/chjj/term.js
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * Originally forked from (with the author's permission):
+ *   Fabrice Bellard's javascript vt100 for jslinux:
+ *   http://bellard.org/jslinux/
+ *   Copyright (c) 2011 Fabrice Bellard
+ *   The original design remains. The terminal itself
+ *   has been extended to include xterm CSI codes, among
+ *   other features.
+ */
+
+/*
+ *  Default style for xterm.js
+ */
+
+.terminal {
+    background-color: #000;
+    color: #fff;
+    font-family: courier-new, courier, monospace;
+    font-feature-settings: "liga" 0;
+    position: relative;
+}
+
+.terminal.focus,
+.terminal:focus {
+    outline: none;
+}
+
+.terminal .xterm-helpers {
+    position: absolute;
+    top: 0;
+}
+
+.terminal .xterm-helper-textarea {
+    position: absolute;
+    /*
+     * HACK: to fix IE's blinking cursor
+     * Move textarea out of the screen to the far left, so that the cursor is not visible.
+     */
+    left: -9999em;
+    opacity: 0;
+    width: 0;
+    height: 0;
+    z-index: -10;
+}
+
+.terminal .terminal-cursor {
+    background-color: #fff;
+    color: #000;
+}
+
+.terminal:not(.focus) .terminal-cursor {
+    outline: 1px solid #fff;
+    outline-offset: -1px;
+    background-color: transparent;
+}
+
+.terminal.focus .terminal-cursor.blinking {
+    animation: blink-cursor 1.2s infinite step-end;
+}
+
+@keyframes blink-cursor {
+    0% {
+        background-color: #fff;
+        color: #000;
+    }
+    50% {
+        background-color: transparent;
+        color: #FFF;
+    }
+}
+
+.terminal .composition-view {
+    background: #000;
+    color: #FFF;
+    display: none;
+    position: absolute;
+    white-space: nowrap;
+    z-index: 1;
+}
+
+.terminal .composition-view.active {
+    display: block;
+}
+
+.terminal .xterm-viewport {
+    /* On OS X this is required in order for the scroll bar to appear fully opaque */
+    background-color: #000;
+    overflow-y: scroll;
+}
+
+.terminal .xterm-rows {
+    position: absolute;
+    left: 0;
+    top: 0;
+}
+
+.terminal .xterm-scroll-area {
+    visibility: hidden;
+}
+
+.terminal .xterm-char-measure-element {
+    display: inline-block;
+    visibility: hidden;
+    position: absolute;
+    left: -9999em;
+}
+
+/*
+ *  Determine default colors for xterm.js
+ */
+.terminal .xterm-bold {
+    font-weight: bold;
+}
+
+.terminal .xterm-underline {
+    text-decoration: underline;
+}
+
+.terminal .xterm-blink {
+    text-decoration: blink;
+}
+
+.terminal .xterm-hidden {
+    visibility: hidden;
+}
+
+.terminal .xterm-color-0 {
+    color: #2e3436;
+}
+
+.terminal .xterm-bg-color-0 {
+    background-color: #2e3436;
+}
+
+.terminal .xterm-color-1 {
+    color: #cc0000;
+}
+
+.terminal .xterm-bg-color-1 {
+    background-color: #cc0000;
+}
+
+.terminal .xterm-color-2 {
+    color: #4e9a06;
+}
+
+.terminal .xterm-bg-color-2 {
+    background-color: #4e9a06;
+}
+
+.terminal .xterm-color-3 {
+    color: #c4a000;
+}
+
+.terminal .xterm-bg-color-3 {
+    background-color: #c4a000;
+}
+
+.terminal .xterm-color-4 {
+    color: #3465a4;
+}
+
+.terminal .xterm-bg-color-4 {
+    background-color: #3465a4;
+}
+
+.terminal .xterm-color-5 {
+    color: #75507b;
+}
+
+.terminal .xterm-bg-color-5 {
+    background-color: #75507b;
+}
+
+.terminal .xterm-color-6 {
+    color: #06989a;
+}
+
+.terminal .xterm-bg-color-6 {
+    background-color: #06989a;
+}
+
+.terminal .xterm-color-7 {
+    color: #d3d7cf;
+}
+
+.terminal .xterm-bg-color-7 {
+    background-color: #d3d7cf;
+}
+
+.terminal .xterm-color-8 {
+    color: #555753;
+}
+
+.terminal .xterm-bg-color-8 {
+    background-color: #555753;
+}
+
+.terminal .xterm-color-9 {
+    color: #ef2929;
+}
+
+.terminal .xterm-bg-color-9 {
+    background-color: #ef2929;
+}
+
+.terminal .xterm-color-10 {
+    color: #8ae234;
+}
+
+.terminal .xterm-bg-color-10 {
+    background-color: #8ae234;
+}
+
+.terminal .xterm-color-11 {
+    color: #fce94f;
+}
+
+.terminal .xterm-bg-color-11 {
+    background-color: #fce94f;
+}
+
+.terminal .xterm-color-12 {
+    color: #729fcf;
+}
+
+.terminal .xterm-bg-color-12 {
+    background-color: #729fcf;
+}
+
+.terminal .xterm-color-13 {
+    color: #ad7fa8;
+}
+
+.terminal .xterm-bg-color-13 {
+    background-color: #ad7fa8;
+}
+
+.terminal .xterm-color-14 {
+    color: #34e2e2;
+}
+
+.terminal .xterm-bg-color-14 {
+    background-color: #34e2e2;
+}
+
+.terminal .xterm-color-15 {
+    color: #eeeeec;
+}
+
+.terminal .xterm-bg-color-15 {
+    background-color: #eeeeec;
+}
+
+.terminal .xterm-color-16 {
+    color: #000000;
+}
+
+.terminal .xterm-bg-color-16 {
+    background-color: #000000;
+}
+
+.terminal .xterm-color-17 {
+    color: #00005f;
+}
+
+.terminal .xterm-bg-color-17 {
+    background-color: #00005f;
+}
+
+.terminal .xterm-color-18 {
+    color: #000087;
+}
+
+.terminal .xterm-bg-color-18 {
+    background-color: #000087;
+}
+
+.terminal .xterm-color-19 {
+    color: #0000af;
+}
+
+.terminal .xterm-bg-color-19 {
+    background-color: #0000af;
+}
+
+.terminal .xterm-color-20 {
+    color: #0000d7;
+}
+
+.terminal .xterm-bg-color-20 {
+    background-color: #0000d7;
+}
+
+.terminal .xterm-color-21 {
+    color: #0000ff;
+}
+
+.terminal .xterm-bg-color-21 {
+    background-color: #0000ff;
+}
+
+.terminal .xterm-color-22 {
+    color: #005f00;
+}
+
+.terminal .xterm-bg-color-22 {
+    background-color: #005f00;
+}
+
+.terminal .xterm-color-23 {
+    color: #005f5f;
+}
+
+.terminal .xterm-bg-color-23 {
+    background-color: #005f5f;
+}
+
+.terminal .xterm-color-24 {
+    color: #005f87;
+}
+
+.terminal .xterm-bg-color-24 {
+    background-color: #005f87;
+}
+
+.terminal .xterm-color-25 {
+    color: #005faf;
+}
+
+.terminal .xterm-bg-color-25 {
+    background-color: #005faf;
+}
+
+.terminal .xterm-color-26 {
+    color: #005fd7;
+}
+
+.terminal .xterm-bg-color-26 {
+    background-color: #005fd7;
+}
+
+.terminal .xterm-color-27 {
+    color: #005fff;
+}
+
+.terminal .xterm-bg-color-27 {
+    background-color: #005fff;
+}
+
+.terminal .xterm-color-28 {
+    color: #008700;
+}
+
+.terminal .xterm-bg-color-28 {
+    background-color: #008700;
+}
+
+.terminal .xterm-color-29 {
+    color: #00875f;
+}
+
+.terminal .xterm-bg-color-29 {
+    background-color: #00875f;
+}
+
+.terminal .xterm-color-30 {
+    color: #008787;
+}
+
+.terminal .xterm-bg-color-30 {
+    background-color: #008787;
+}
+
+.terminal .xterm-color-31 {
+    color: #0087af;
+}
+
+.terminal .xterm-bg-color-31 {
+    background-color: #0087af;
+}
+
+.terminal .xterm-color-32 {
+    color: #0087d7;
+}
+
+.terminal .xterm-bg-color-32 {
+    background-color: #0087d7;
+}
+
+.terminal .xterm-color-33 {
+    color: #0087ff;
+}
+
+.terminal .xterm-bg-color-33 {
+    background-color: #0087ff;
+}
+
+.terminal .xterm-color-34 {
+    color: #00af00;
+}
+
+.terminal .xterm-bg-color-34 {
+    background-color: #00af00;
+}
+
+.terminal .xterm-color-35 {
+    color: #00af5f;
+}
+
+.terminal .xterm-bg-color-35 {
+    background-color: #00af5f;
+}
+
+.terminal .xterm-color-36 {
+    color: #00af87;
+}
+
+.terminal .xterm-bg-color-36 {
+    background-color: #00af87;
+}
+
+.terminal .xterm-color-37 {
+    color: #00afaf;
+}
+
+.terminal .xterm-bg-color-37 {
+    background-color: #00afaf;
+}
+
+.terminal .xterm-color-38 {
+    color: #00afd7;
+}
+
+.terminal .xterm-bg-color-38 {
+    background-color: #00afd7;
+}
+
+.terminal .xterm-color-39 {
+    color: #00afff;
+}
+
+.terminal .xterm-bg-color-39 {
+    background-color: #00afff;
+}
+
+.terminal .xterm-color-40 {
+    color: #00d700;
+}
+
+.terminal .xterm-bg-color-40 {
+    background-color: #00d700;
+}
+
+.terminal .xterm-color-41 {
+    color: #00d75f;
+}
+
+.terminal .xterm-bg-color-41 {
+    background-color: #00d75f;
+}
+
+.terminal .xterm-color-42 {
+    color: #00d787;
+}
+
+.terminal .xterm-bg-color-42 {
+    background-color: #00d787;
+}
+
+.terminal .xterm-color-43 {
+    color: #00d7af;
+}
+
+.terminal .xterm-bg-color-43 {
+    background-color: #00d7af;
+}
+
+.terminal .xterm-color-44 {
+    color: #00d7d7;
+}
+
+.terminal .xterm-bg-color-44 {
+    background-color: #00d7d7;
+}
+
+.terminal .xterm-color-45 {
+    color: #00d7ff;
+}
+
+.terminal .xterm-bg-color-45 {
+    background-color: #00d7ff;
+}
+
+.terminal .xterm-color-46 {
+    color: #00ff00;
+}
+
+.terminal .xterm-bg-color-46 {
+    background-color: #00ff00;
+}
+
+.terminal .xterm-color-47 {
+    color: #00ff5f;
+}
+
+.terminal .xterm-bg-color-47 {
+    background-color: #00ff5f;
+}
+
+.terminal .xterm-color-48 {
+    color: #00ff87;
+}
+
+.terminal .xterm-bg-color-48 {
+    background-color: #00ff87;
+}
+
+.terminal .xterm-color-49 {
+    color: #00ffaf;
+}
+
+.terminal .xterm-bg-color-49 {
+    background-color: #00ffaf;
+}
+
+.terminal .xterm-color-50 {
+    color: #00ffd7;
+}
+
+.terminal .xterm-bg-color-50 {
+    background-color: #00ffd7;
+}
+
+.terminal .xterm-color-51 {
+    color: #00ffff;
+}
+
+.terminal .xterm-bg-color-51 {
+    background-color: #00ffff;
+}
+
+.terminal .xterm-color-52 {
+    color: #5f0000;
+}
+
+.terminal .xterm-bg-color-52 {
+    background-color: #5f0000;
+}
+
+.terminal .xterm-color-53 {
+    color: #5f005f;
+}
+
+.terminal .xterm-bg-color-53 {
+    background-color: #5f005f;
+}
+
+.terminal .xterm-color-54 {
+    color: #5f0087;
+}
+
+.terminal .xterm-bg-color-54 {
+    background-color: #5f0087;
+}
+
+.terminal .xterm-color-55 {
+    color: #5f00af;
+}
+
+.terminal .xterm-bg-color-55 {
+    background-color: #5f00af;
+}
+
+.terminal .xterm-color-56 {
+    color: #5f00d7;
+}
+
+.terminal .xterm-bg-color-56 {
+    background-color: #5f00d7;
+}
+
+.terminal .xterm-color-57 {
+    color: #5f00ff;
+}
+
+.terminal .xterm-bg-color-57 {
+    background-color: #5f00ff;
+}
+
+.terminal .xterm-color-58 {
+    color: #5f5f00;
+}
+
+.terminal .xterm-bg-color-58 {
+    background-color: #5f5f00;
+}
+
+.terminal .xterm-color-59 {
+    color: #5f5f5f;
+}
+
+.terminal .xterm-bg-color-59 {
+    background-color: #5f5f5f;
+}
+
+.terminal .xterm-color-60 {
+    color: #5f5f87;
+}
+
+.terminal .xterm-bg-color-60 {
+    background-color: #5f5f87;
+}
+
+.terminal .xterm-color-61 {
+    color: #5f5faf;
+}
+
+.terminal .xterm-bg-color-61 {
+    background-color: #5f5faf;
+}
+
+.terminal .xterm-color-62 {
+    color: #5f5fd7;
+}
+
+.terminal .xterm-bg-color-62 {
+    background-color: #5f5fd7;
+}
+
+.terminal .xterm-color-63 {
+    color: #5f5fff;
+}
+
+.terminal .xterm-bg-color-63 {
+    background-color: #5f5fff;
+}
+
+.terminal .xterm-color-64 {
+    color: #5f8700;
+}
+
+.terminal .xterm-bg-color-64 {
+    background-color: #5f8700;
+}
+
+.terminal .xterm-color-65 {
+    color: #5f875f;
+}
+
+.terminal .xterm-bg-color-65 {
+    background-color: #5f875f;
+}
+
+.terminal .xterm-color-66 {
+    color: #5f8787;
+}
+
+.terminal .xterm-bg-color-66 {
+    background-color: #5f8787;
+}
+
+.terminal .xterm-color-67 {
+    color: #5f87af;
+}
+
+.terminal .xterm-bg-color-67 {
+    background-color: #5f87af;
+}
+
+.terminal .xterm-color-68 {
+    color: #5f87d7;
+}
+
+.terminal .xterm-bg-color-68 {
+    background-color: #5f87d7;
+}
+
+.terminal .xterm-color-69 {
+    color: #5f87ff;
+}
+
+.terminal .xterm-bg-color-69 {
+    background-color: #5f87ff;
+}
+
+.terminal .xterm-color-70 {
+    color: #5faf00;
+}
+
+.terminal .xterm-bg-color-70 {
+    background-color: #5faf00;
+}
+
+.terminal .xterm-color-71 {
+    color: #5faf5f;
+}
+
+.terminal .xterm-bg-color-71 {
+    background-color: #5faf5f;
+}
+
+.terminal .xterm-color-72 {
+    color: #5faf87;
+}
+
+.terminal .xterm-bg-color-72 {
+    background-color: #5faf87;
+}
+
+.terminal .xterm-color-73 {
+    color: #5fafaf;
+}
+
+.terminal .xterm-bg-color-73 {
+    background-color: #5fafaf;
+}
+
+.terminal .xterm-color-74 {
+    color: #5fafd7;
+}
+
+.terminal .xterm-bg-color-74 {
+    background-color: #5fafd7;
+}
+
+.terminal .xterm-color-75 {
+    color: #5fafff;
+}
+
+.terminal .xterm-bg-color-75 {
+    background-color: #5fafff;
+}
+
+.terminal .xterm-color-76 {
+    color: #5fd700;
+}
+
+.terminal .xterm-bg-color-76 {
+    background-color: #5fd700;
+}
+
+.terminal .xterm-color-77 {
+    color: #5fd75f;
+}
+
+.terminal .xterm-bg-color-77 {
+    background-color: #5fd75f;
+}
+
+.terminal .xterm-color-78 {
+    color: #5fd787;
+}
+
+.terminal .xterm-bg-color-78 {
+    background-color: #5fd787;
+}
+
+.terminal .xterm-color-79 {
+    color: #5fd7af;
+}
+
+.terminal .xterm-bg-color-79 {
+    background-color: #5fd7af;
+}
+
+.terminal .xterm-color-80 {
+    color: #5fd7d7;
+}
+
+.terminal .xterm-bg-color-80 {
+    background-color: #5fd7d7;
+}
+
+.terminal .xterm-color-81 {
+    color: #5fd7ff;
+}
+
+.terminal .xterm-bg-color-81 {
+    background-color: #5fd7ff;
+}
+
+.terminal .xterm-color-82 {
+    color: #5fff00;
+}
+
+.terminal .xterm-bg-color-82 {
+    background-color: #5fff00;
+}
+
+.terminal .xterm-color-83 {
+    color: #5fff5f;
+}
+
+.terminal .xterm-bg-color-83 {
+    background-color: #5fff5f;
+}
+
+.terminal .xterm-color-84 {
+    color: #5fff87;
+}
+
+.terminal .xterm-bg-color-84 {
+    background-color: #5fff87;
+}
+
+.terminal .xterm-color-85 {
+    color: #5fffaf;
+}
+
+.terminal .xterm-bg-color-85 {
+    background-color: #5fffaf;
+}
+
+.terminal .xterm-color-86 {
+    color: #5fffd7;
+}
+
+.terminal .xterm-bg-color-86 {
+    background-color: #5fffd7;
+}
+
+.terminal .xterm-color-87 {
+    color: #5fffff;
+}
+
+.terminal .xterm-bg-color-87 {
+    background-color: #5fffff;
+}
+
+.terminal .xterm-color-88 {
+    color: #870000;
+}
+
+.terminal .xterm-bg-color-88 {
+    background-color: #870000;
+}
+
+.terminal .xterm-color-89 {
+    color: #87005f;
+}
+
+.terminal .xterm-bg-color-89 {
+    background-color: #87005f;
+}
+
+.terminal .xterm-color-90 {
+    color: #870087;
+}
+
+.terminal .xterm-bg-color-90 {
+    background-color: #870087;
+}
+
+.terminal .xterm-color-91 {
+    color: #8700af;
+}
+
+.terminal .xterm-bg-color-91 {
+    background-color: #8700af;
+}
+
+.terminal .xterm-color-92 {
+    color: #8700d7;
+}
+
+.terminal .xterm-bg-color-92 {
+    background-color: #8700d7;
+}
+
+.terminal .xterm-color-93 {
+    color: #8700ff;
+}
+
+.terminal .xterm-bg-color-93 {
+    background-color: #8700ff;
+}
+
+.terminal .xterm-color-94 {
+    color: #875f00;
+}
+
+.terminal .xterm-bg-color-94 {
+    background-color: #875f00;
+}
+
+.terminal .xterm-color-95 {
+    color: #875f5f;
+}
+
+.terminal .xterm-bg-color-95 {
+    background-color: #875f5f;
+}
+
+.terminal .xterm-color-96 {
+    color: #875f87;
+}
+
+.terminal .xterm-bg-color-96 {
+    background-color: #875f87;
+}
+
+.terminal .xterm-color-97 {
+    color: #875faf;
+}
+
+.terminal .xterm-bg-color-97 {
+    background-color: #875faf;
+}
+
+.terminal .xterm-color-98 {
+    color: #875fd7;
+}
+
+.terminal .xterm-bg-color-98 {
+    background-color: #875fd7;
+}
+
+.terminal .xterm-color-99 {
+    color: #875fff;
+}
+
+.terminal .xterm-bg-color-99 {
+    background-color: #875fff;
+}
+
+.terminal .xterm-color-100 {
+    color: #878700;
+}
+
+.terminal .xterm-bg-color-100 {
+    background-color: #878700;
+}
+
+.terminal .xterm-color-101 {
+    color: #87875f;
+}
+
+.terminal .xterm-bg-color-101 {
+    background-color: #87875f;
+}
+
+.terminal .xterm-color-102 {
+    color: #878787;
+}
+
+.terminal .xterm-bg-color-102 {
+    background-color: #878787;
+}
+
+.terminal .xterm-color-103 {
+    color: #8787af;
+}
+
+.terminal .xterm-bg-color-103 {
+    background-color: #8787af;
+}
+
+.terminal .xterm-color-104 {
+    color: #8787d7;
+}
+
+.terminal .xterm-bg-color-104 {
+    background-color: #8787d7;
+}
+
+.terminal .xterm-color-105 {
+    color: #8787ff;
+}
+
+.terminal .xterm-bg-color-105 {
+    background-color: #8787ff;
+}
+
+.terminal .xterm-color-106 {
+    color: #87af00;
+}
+
+.terminal .xterm-bg-color-106 {
+    background-color: #87af00;
+}
+
+.terminal .xterm-color-107 {
+    color: #87af5f;
+}
+
+.terminal .xterm-bg-color-107 {
+    background-color: #87af5f;
+}
+
+.terminal .xterm-color-108 {
+    color: #87af87;
+}
+
+.terminal .xterm-bg-color-108 {
+    background-color: #87af87;
+}
+
+.terminal .xterm-color-109 {
+    color: #87afaf;
+}
+
+.terminal .xterm-bg-color-109 {
+    background-color: #87afaf;
+}
+
+.terminal .xterm-color-110 {
+    color: #87afd7;
+}
+
+.terminal .xterm-bg-color-110 {
+    background-color: #87afd7;
+}
+
+.terminal .xterm-color-111 {
+    color: #87afff;
+}
+
+.terminal .xterm-bg-color-111 {
+    background-color: #87afff;
+}
+
+.terminal .xterm-color-112 {
+    color: #87d700;
+}
+
+.terminal .xterm-bg-color-112 {
+    background-color: #87d700;
+}
+
+.terminal .xterm-color-113 {
+    color: #87d75f;
+}
+
+.terminal .xterm-bg-color-113 {
+    background-color: #87d75f;
+}
+
+.terminal .xterm-color-114 {
+    color: #87d787;
+}
+
+.terminal .xterm-bg-color-114 {
+    background-color: #87d787;
+}
+
+.terminal .xterm-color-115 {
+    color: #87d7af;
+}
+
+.terminal .xterm-bg-color-115 {
+    background-color: #87d7af;
+}
+
+.terminal .xterm-color-116 {
+    color: #87d7d7;
+}
+
+.terminal .xterm-bg-color-116 {
+    background-color: #87d7d7;
+}
+
+.terminal .xterm-color-117 {
+    color: #87d7ff;
+}
+
+.terminal .xterm-bg-color-117 {
+    background-color: #87d7ff;
+}
+
+.terminal .xterm-color-118 {
+    color: #87ff00;
+}
+
+.terminal .xterm-bg-color-118 {
+    background-color: #87ff00;
+}
+
+.terminal .xterm-color-119 {
+    color: #87ff5f;
+}
+
+.terminal .xterm-bg-color-119 {
+    background-color: #87ff5f;
+}
+
+.terminal .xterm-color-120 {
+    color: #87ff87;
+}
+
+.terminal .xterm-bg-color-120 {
+    background-color: #87ff87;
+}
+
+.terminal .xterm-color-121 {
+    color: #87ffaf;
+}
+
+.terminal .xterm-bg-color-121 {
+    background-color: #87ffaf;
+}
+
+.terminal .xterm-color-122 {
+    color: #87ffd7;
+}
+
+.terminal .xterm-bg-color-122 {
+    background-color: #87ffd7;
+}
+
+.terminal .xterm-color-123 {
+    color: #87ffff;
+}
+
+.terminal .xterm-bg-color-123 {
+    background-color: #87ffff;
+}
+
+.terminal .xterm-color-124 {
+    color: #af0000;
+}
+
+.terminal .xterm-bg-color-124 {
+    background-color: #af0000;
+}
+
+.terminal .xterm-color-125 {
+    color: #af005f;
+}
+
+.terminal .xterm-bg-color-125 {
+    background-color: #af005f;
+}
+
+.terminal .xterm-color-126 {
+    color: #af0087;
+}
+
+.terminal .xterm-bg-color-126 {
+    background-color: #af0087;
+}
+
+.terminal .xterm-color-127 {
+    color: #af00af;
+}
+
+.terminal .xterm-bg-color-127 {
+    background-color: #af00af;
+}
+
+.terminal .xterm-color-128 {
+    color: #af00d7;
+}
+
+.terminal .xterm-bg-color-128 {
+    background-color: #af00d7;
+}
+
+.terminal .xterm-color-129 {
+    color: #af00ff;
+}
+
+.terminal .xterm-bg-color-129 {
+    background-color: #af00ff;
+}
+
+.terminal .xterm-color-130 {
+    color: #af5f00;
+}
+
+.terminal .xterm-bg-color-130 {
+    background-color: #af5f00;
+}
+
+.terminal .xterm-color-131 {
+    color: #af5f5f;
+}
+
+.terminal .xterm-bg-color-131 {
+    background-color: #af5f5f;
+}
+
+.terminal .xterm-color-132 {
+    color: #af5f87;
+}
+
+.terminal .xterm-bg-color-132 {
+    background-color: #af5f87;
+}
+
+.terminal .xterm-color-133 {
+    color: #af5faf;
+}
+
+.terminal .xterm-bg-color-133 {
+    background-color: #af5faf;
+}
+
+.terminal .xterm-color-134 {
+    color: #af5fd7;
+}
+
+.terminal .xterm-bg-color-134 {
+    background-color: #af5fd7;
+}
+
+.terminal .xterm-color-135 {
+    color: #af5fff;
+}
+
+.terminal .xterm-bg-color-135 {
+    background-color: #af5fff;
+}
+
+.terminal .xterm-color-136 {
+    color: #af8700;
+}
+
+.terminal .xterm-bg-color-136 {
+    background-color: #af8700;
+}
+
+.terminal .xterm-color-137 {
+    color: #af875f;
+}
+
+.terminal .xterm-bg-color-137 {
+    background-color: #af875f;
+}
+
+.terminal .xterm-color-138 {
+    color: #af8787;
+}
+
+.terminal .xterm-bg-color-138 {
+    background-color: #af8787;
+}
+
+.terminal .xterm-color-139 {
+    color: #af87af;
+}
+
+.terminal .xterm-bg-color-139 {
+    background-color: #af87af;
+}
+
+.terminal .xterm-color-140 {
+    color: #af87d7;
+}
+
+.terminal .xterm-bg-color-140 {
+    background-color: #af87d7;
+}
+
+.terminal .xterm-color-141 {
+    color: #af87ff;
+}
+
+.terminal .xterm-bg-color-141 {
+    background-color: #af87ff;
+}
+
+.terminal .xterm-color-142 {
+    color: #afaf00;
+}
+
+.terminal .xterm-bg-color-142 {
+    background-color: #afaf00;
+}
+
+.terminal .xterm-color-143 {
+    color: #afaf5f;
+}
+
+.terminal .xterm-bg-color-143 {
+    background-color: #afaf5f;
+}
+
+.terminal .xterm-color-144 {
+    color: #afaf87;
+}
+
+.terminal .xterm-bg-color-144 {
+    background-color: #afaf87;
+}
+
+.terminal .xterm-color-145 {
+    color: #afafaf;
+}
+
+.terminal .xterm-bg-color-145 {
+    background-color: #afafaf;
+}
+
+.terminal .xterm-color-146 {
+    color: #afafd7;
+}
+
+.terminal .xterm-bg-color-146 {
+    background-color: #afafd7;
+}
+
+.terminal .xterm-color-147 {
+    color: #afafff;
+}
+
+.terminal .xterm-bg-color-147 {
+    background-color: #afafff;
+}
+
+.terminal .xterm-color-148 {
+    color: #afd700;
+}
+
+.terminal .xterm-bg-color-148 {
+    background-color: #afd700;
+}
+
+.terminal .xterm-color-149 {
+    color: #afd75f;
+}
+
+.terminal .xterm-bg-color-149 {
+    background-color: #afd75f;
+}
+
+.terminal .xterm-color-150 {
+    color: #afd787;
+}
+
+.terminal .xterm-bg-color-150 {
+    background-color: #afd787;
+}
+
+.terminal .xterm-color-151 {
+    color: #afd7af;
+}
+
+.terminal .xterm-bg-color-151 {
+    background-color: #afd7af;
+}
+
+.terminal .xterm-color-152 {
+    color: #afd7d7;
+}
+
+.terminal .xterm-bg-color-152 {
+    background-color: #afd7d7;
+}
+
+.terminal .xterm-color-153 {
+    color: #afd7ff;
+}
+
+.terminal .xterm-bg-color-153 {
+    background-color: #afd7ff;
+}
+
+.terminal .xterm-color-154 {
+    color: #afff00;
+}
+
+.terminal .xterm-bg-color-154 {
+    background-color: #afff00;
+}
+
+.terminal .xterm-color-155 {
+    color: #afff5f;
+}
+
+.terminal .xterm-bg-color-155 {
+    background-color: #afff5f;
+}
+
+.terminal .xterm-color-156 {
+    color: #afff87;
+}
+
+.terminal .xterm-bg-color-156 {
+    background-color: #afff87;
+}
+
+.terminal .xterm-color-157 {
+    color: #afffaf;
+}
+
+.terminal .xterm-bg-color-157 {
+    background-color: #afffaf;
+}
+
+.terminal .xterm-color-158 {
+    color: #afffd7;
+}
+
+.terminal .xterm-bg-color-158 {
+    background-color: #afffd7;
+}
+
+.terminal .xterm-color-159 {
+    color: #afffff;
+}
+
+.terminal .xterm-bg-color-159 {
+    background-color: #afffff;
+}
+
+.terminal .xterm-color-160 {
+    color: #d70000;
+}
+
+.terminal .xterm-bg-color-160 {
+    background-color: #d70000;
+}
+
+.terminal .xterm-color-161 {
+    color: #d7005f;
+}
+
+.terminal .xterm-bg-color-161 {
+    background-color: #d7005f;
+}
+
+.terminal .xterm-color-162 {
+    color: #d70087;
+}
+
+.terminal .xterm-bg-color-162 {
+    background-color: #d70087;
+}
+
+.terminal .xterm-color-163 {
+    color: #d700af;
+}
+
+.terminal .xterm-bg-color-163 {
+    background-color: #d700af;
+}
+
+.terminal .xterm-color-164 {
+    color: #d700d7;
+}
+
+.terminal .xterm-bg-color-164 {
+    background-color: #d700d7;
+}
+
+.terminal .xterm-color-165 {
+    color: #d700ff;
+}
+
+.terminal .xterm-bg-color-165 {
+    background-color: #d700ff;
+}
+
+.terminal .xterm-color-166 {
+    color: #d75f00;
+}
+
+.terminal .xterm-bg-color-166 {
+    background-color: #d75f00;
+}
+
+.terminal .xterm-color-167 {
+    color: #d75f5f;
+}
+
+.terminal .xterm-bg-color-167 {
+    background-color: #d75f5f;
+}
+
+.terminal .xterm-color-168 {
+    color: #d75f87;
+}
+
+.terminal .xterm-bg-color-168 {
+    background-color: #d75f87;
+}
+
+.terminal .xterm-color-169 {
+    color: #d75faf;
+}
+
+.terminal .xterm-bg-color-169 {
+    background-color: #d75faf;
+}
+
+.terminal .xterm-color-170 {
+    color: #d75fd7;
+}
+
+.terminal .xterm-bg-color-170 {
+    background-color: #d75fd7;
+}
+
+.terminal .xterm-color-171 {
+    color: #d75fff;
+}
+
+.terminal .xterm-bg-color-171 {
+    background-color: #d75fff;
+}
+
+.terminal .xterm-color-172 {
+    color: #d78700;
+}
+
+.terminal .xterm-bg-color-172 {
+    background-color: #d78700;
+}
+
+.terminal .xterm-color-173 {
+    color: #d7875f;
+}
+
+.terminal .xterm-bg-color-173 {
+    background-color: #d7875f;
+}
+
+.terminal .xterm-color-174 {
+    color: #d78787;
+}
+
+.terminal .xterm-bg-color-174 {
+    background-color: #d78787;
+}
+
+.terminal .xterm-color-175 {
+    color: #d787af;
+}
+
+.terminal .xterm-bg-color-175 {
+    background-color: #d787af;
+}
+
+.terminal .xterm-color-176 {
+    color: #d787d7;
+}
+
+.terminal .xterm-bg-color-176 {
+    background-color: #d787d7;
+}
+
+.terminal .xterm-color-177 {
+    color: #d787ff;
+}
+
+.terminal .xterm-bg-color-177 {
+    background-color: #d787ff;
+}
+
+.terminal .xterm-color-178 {
+    color: #d7af00;
+}
+
+.terminal .xterm-bg-color-178 {
+    background-color: #d7af00;
+}
+
+.terminal .xterm-color-179 {
+    color: #d7af5f;
+}
+
+.terminal .xterm-bg-color-179 {
+    background-color: #d7af5f;
+}
+
+.terminal .xterm-color-180 {
+    color: #d7af87;
+}
+
+.terminal .xterm-bg-color-180 {
+    background-color: #d7af87;
+}
+
+.terminal .xterm-color-181 {
+    color: #d7afaf;
+}
+
+.terminal .xterm-bg-color-181 {
+    background-color: #d7afaf;
+}
+
+.terminal .xterm-color-182 {
+    color: #d7afd7;
+}
+
+.terminal .xterm-bg-color-182 {
+    background-color: #d7afd7;
+}
+
+.terminal .xterm-color-183 {
+    color: #d7afff;
+}
+
+.terminal .xterm-bg-color-183 {
+    background-color: #d7afff;
+}
+
+.terminal .xterm-color-184 {
+    color: #d7d700;
+}
+
+.terminal .xterm-bg-color-184 {
+    background-color: #d7d700;
+}
+
+.terminal .xterm-color-185 {
+    color: #d7d75f;
+}
+
+.terminal .xterm-bg-color-185 {
+    background-color: #d7d75f;
+}
+
+.terminal .xterm-color-186 {
+    color: #d7d787;
+}
+
+.terminal .xterm-bg-color-186 {
+    background-color: #d7d787;
+}
+
+.terminal .xterm-color-187 {
+    color: #d7d7af;
+}
+
+.terminal .xterm-bg-color-187 {
+    background-color: #d7d7af;
+}
+
+.terminal .xterm-color-188 {
+    color: #d7d7d7;
+}
+
+.terminal .xterm-bg-color-188 {
+    background-color: #d7d7d7;
+}
+
+.terminal .xterm-color-189 {
+    color: #d7d7ff;
+}
+
+.terminal .xterm-bg-color-189 {
+    background-color: #d7d7ff;
+}
+
+.terminal .xterm-color-190 {
+    color: #d7ff00;
+}
+
+.terminal .xterm-bg-color-190 {
+    background-color: #d7ff00;
+}
+
+.terminal .xterm-color-191 {
+    color: #d7ff5f;
+}
+
+.terminal .xterm-bg-color-191 {
+    background-color: #d7ff5f;
+}
+
+.terminal .xterm-color-192 {
+    color: #d7ff87;
+}
+
+.terminal .xterm-bg-color-192 {
+    background-color: #d7ff87;
+}
+
+.terminal .xterm-color-193 {
+    color: #d7ffaf;
+}
+
+.terminal .xterm-bg-color-193 {
+    background-color: #d7ffaf;
+}
+
+.terminal .xterm-color-194 {
+    color: #d7ffd7;
+}
+
+.terminal .xterm-bg-color-194 {
+    background-color: #d7ffd7;
+}
+
+.terminal .xterm-color-195 {
+    color: #d7ffff;
+}
+
+.terminal .xterm-bg-color-195 {
+    background-color: #d7ffff;
+}
+
+.terminal .xterm-color-196 {
+    color: #ff0000;
+}
+
+.terminal .xterm-bg-color-196 {
+    background-color: #ff0000;
+}
+
+.terminal .xterm-color-197 {
+    color: #ff005f;
+}
+
+.terminal .xterm-bg-color-197 {
+    background-color: #ff005f;
+}
+
+.terminal .xterm-color-198 {
+    color: #ff0087;
+}
+
+.terminal .xterm-bg-color-198 {
+    background-color: #ff0087;
+}
+
+.terminal .xterm-color-199 {
+    color: #ff00af;
+}
+
+.terminal .xterm-bg-color-199 {
+    background-color: #ff00af;
+}
+
+.terminal .xterm-color-200 {
+    color: #ff00d7;
+}
+
+.terminal .xterm-bg-color-200 {
+    background-color: #ff00d7;
+}
+
+.terminal .xterm-color-201 {
+    color: #ff00ff;
+}
+
+.terminal .xterm-bg-color-201 {
+    background-color: #ff00ff;
+}
+
+.terminal .xterm-color-202 {
+    color: #ff5f00;
+}
+
+.terminal .xterm-bg-color-202 {
+    background-color: #ff5f00;
+}
+
+.terminal .xterm-color-203 {
+    color: #ff5f5f;
+}
+
+.terminal .xterm-bg-color-203 {
+    background-color: #ff5f5f;
+}
+
+.terminal .xterm-color-204 {
+    color: #ff5f87;
+}
+
+.terminal .xterm-bg-color-204 {
+    background-color: #ff5f87;
+}
+
+.terminal .xterm-color-205 {
+    color: #ff5faf;
+}
+
+.terminal .xterm-bg-color-205 {
+    background-color: #ff5faf;
+}
+
+.terminal .xterm-color-206 {
+    color: #ff5fd7;
+}
+
+.terminal .xterm-bg-color-206 {
+    background-color: #ff5fd7;
+}
+
+.terminal .xterm-color-207 {
+    color: #ff5fff;
+}
+
+.terminal .xterm-bg-color-207 {
+    background-color: #ff5fff;
+}
+
+.terminal .xterm-color-208 {
+    color: #ff8700;
+}
+
+.terminal .xterm-bg-color-208 {
+    background-color: #ff8700;
+}
+
+.terminal .xterm-color-209 {
+    color: #ff875f;
+}
+
+.terminal .xterm-bg-color-209 {
+    background-color: #ff875f;
+}
+
+.terminal .xterm-color-210 {
+    color: #ff8787;
+}
+
+.terminal .xterm-bg-color-210 {
+    background-color: #ff8787;
+}
+
+.terminal .xterm-color-211 {
+    color: #ff87af;
+}
+
+.terminal .xterm-bg-color-211 {
+    background-color: #ff87af;
+}
+
+.terminal .xterm-color-212 {
+    color: #ff87d7;
+}
+
+.terminal .xterm-bg-color-212 {
+    background-color: #ff87d7;
+}
+
+.terminal .xterm-color-213 {
+    color: #ff87ff;
+}
+
+.terminal .xterm-bg-color-213 {
+    background-color: #ff87ff;
+}
+
+.terminal .xterm-color-214 {
+    color: #ffaf00;
+}
+
+.terminal .xterm-bg-color-214 {
+    background-color: #ffaf00;
+}
+
+.terminal .xterm-color-215 {
+    color: #ffaf5f;
+}
+
+.terminal .xterm-bg-color-215 {
+    background-color: #ffaf5f;
+}
+
+.terminal .xterm-color-216 {
+    color: #ffaf87;
+}
+
+.terminal .xterm-bg-color-216 {
+    background-color: #ffaf87;
+}
+
+.terminal .xterm-color-217 {
+    color: #ffafaf;
+}
+
+.terminal .xterm-bg-color-217 {
+    background-color: #ffafaf;
+}
+
+.terminal .xterm-color-218 {
+    color: #ffafd7;
+}
+
+.terminal .xterm-bg-color-218 {
+    background-color: #ffafd7;
+}
+
+.terminal .xterm-color-219 {
+    color: #ffafff;
+}
+
+.terminal .xterm-bg-color-219 {
+    background-color: #ffafff;
+}
+
+.terminal .xterm-color-220 {
+    color: #ffd700;
+}
+
+.terminal .xterm-bg-color-220 {
+    background-color: #ffd700;
+}
+
+.terminal .xterm-color-221 {
+    color: #ffd75f;
+}
+
+.terminal .xterm-bg-color-221 {
+    background-color: #ffd75f;
+}
+
+.terminal .xterm-color-222 {
+    color: #ffd787;
+}
+
+.terminal .xterm-bg-color-222 {
+    background-color: #ffd787;
+}
+
+.terminal .xterm-color-223 {
+    color: #ffd7af;
+}
+
+.terminal .xterm-bg-color-223 {
+    background-color: #ffd7af;
+}
+
+.terminal .xterm-color-224 {
+    color: #ffd7d7;
+}
+
+.terminal .xterm-bg-color-224 {
+    background-color: #ffd7d7;
+}
+
+.terminal .xterm-color-225 {
+    color: #ffd7ff;
+}
+
+.terminal .xterm-bg-color-225 {
+    background-color: #ffd7ff;
+}
+
+.terminal .xterm-color-226 {
+    color: #ffff00;
+}
+
+.terminal .xterm-bg-color-226 {
+    background-color: #ffff00;
+}
+
+.terminal .xterm-color-227 {
+    color: #ffff5f;
+}
+
+.terminal .xterm-bg-color-227 {
+    background-color: #ffff5f;
+}
+
+.terminal .xterm-color-228 {
+    color: #ffff87;
+}
+
+.terminal .xterm-bg-color-228 {
+    background-color: #ffff87;
+}
+
+.terminal .xterm-color-229 {
+    color: #ffffaf;
+}
+
+.terminal .xterm-bg-color-229 {
+    background-color: #ffffaf;
+}
+
+.terminal .xterm-color-230 {
+    color: #ffffd7;
+}
+
+.terminal .xterm-bg-color-230 {
+    background-color: #ffffd7;
+}
+
+.terminal .xterm-color-231 {
+    color: #ffffff;
+}
+
+.terminal .xterm-bg-color-231 {
+    background-color: #ffffff;
+}
+
+.terminal .xterm-color-232 {
+    color: #080808;
+}
+
+.terminal .xterm-bg-color-232 {
+    background-color: #080808;
+}
+
+.terminal .xterm-color-233 {
+    color: #121212;
+}
+
+.terminal .xterm-bg-color-233 {
+    background-color: #121212;
+}
+
+.terminal .xterm-color-234 {
+    color: #1c1c1c;
+}
+
+.terminal .xterm-bg-color-234 {
+    background-color: #1c1c1c;
+}
+
+.terminal .xterm-color-235 {
+    color: #262626;
+}
+
+.terminal .xterm-bg-color-235 {
+    background-color: #262626;
+}
+
+.terminal .xterm-color-236 {
+    color: #303030;
+}
+
+.terminal .xterm-bg-color-236 {
+    background-color: #303030;
+}
+
+.terminal .xterm-color-237 {
+    color: #3a3a3a;
+}
+
+.terminal .xterm-bg-color-237 {
+    background-color: #3a3a3a;
+}
+
+.terminal .xterm-color-238 {
+    color: #444444;
+}
+
+.terminal .xterm-bg-color-238 {
+    background-color: #444444;
+}
+
+.terminal .xterm-color-239 {
+    color: #4e4e4e;
+}
+
+.terminal .xterm-bg-color-239 {
+    background-color: #4e4e4e;
+}
+
+.terminal .xterm-color-240 {
+    color: #585858;
+}
+
+.terminal .xterm-bg-color-240 {
+    background-color: #585858;
+}
+
+.terminal .xterm-color-241 {
+    color: #626262;
+}
+
+.terminal .xterm-bg-color-241 {
+    background-color: #626262;
+}
+
+.terminal .xterm-color-242 {
+    color: #6c6c6c;
+}
+
+.terminal .xterm-bg-color-242 {
+    background-color: #6c6c6c;
+}
+
+.terminal .xterm-color-243 {
+    color: #767676;
+}
+
+.terminal .xterm-bg-color-243 {
+    background-color: #767676;
+}
+
+.terminal .xterm-color-244 {
+    color: #808080;
+}
+
+.terminal .xterm-bg-color-244 {
+    background-color: #808080;
+}
+
+.terminal .xterm-color-245 {
+    color: #8a8a8a;
+}
+
+.terminal .xterm-bg-color-245 {
+    background-color: #8a8a8a;
+}
+
+.terminal .xterm-color-246 {
+    color: #949494;
+}
+
+.terminal .xterm-bg-color-246 {
+    background-color: #949494;
+}
+
+.terminal .xterm-color-247 {
+    color: #9e9e9e;
+}
+
+.terminal .xterm-bg-color-247 {
+    background-color: #9e9e9e;
+}
+
+.terminal .xterm-color-248 {
+    color: #a8a8a8;
+}
+
+.terminal .xterm-bg-color-248 {
+    background-color: #a8a8a8;
+}
+
+.terminal .xterm-color-249 {
+    color: #b2b2b2;
+}
+
+.terminal .xterm-bg-color-249 {
+    background-color: #b2b2b2;
+}
+
+.terminal .xterm-color-250 {
+    color: #bcbcbc;
+}
+
+.terminal .xterm-bg-color-250 {
+    background-color: #bcbcbc;
+}
+
+.terminal .xterm-color-251 {
+    color: #c6c6c6;
+}
+
+.terminal .xterm-bg-color-251 {
+    background-color: #c6c6c6;
+}
+
+.terminal .xterm-color-252 {
+    color: #d0d0d0;
+}
+
+.terminal .xterm-bg-color-252 {
+    background-color: #d0d0d0;
+}
+
+.terminal .xterm-color-253 {
+    color: #dadada;
+}
+
+.terminal .xterm-bg-color-253 {
+    background-color: #dadada;
+}
+
+.terminal .xterm-color-254 {
+    color: #e4e4e4;
+}
+
+.terminal .xterm-bg-color-254 {
+    background-color: #e4e4e4;
+}
+
+.terminal .xterm-color-255 {
+    color: #eeeeee;
+}
+
+.terminal .xterm-bg-color-255 {
+    background-color: #eeeeee;
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/src/xterm.js b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/src/xterm.js
new file mode 100644
index 0000000..3ccc99e5
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/terminal/xterm.js/src/xterm.js
@@ -0,0 +1,5146 @@
+/**
+ * xterm.js: xterm, in the browser
+ * Copyright (c) 2014, SourceLair Limited <www.sourcelair.com> (MIT License)
+ * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
+ * https://github.com/chjj/term.js
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * Originally forked from (with the author's permission):
+ *   Fabrice Bellard's javascript vt100 for jslinux:
+ *   http://bellard.org/jslinux/
+ *   Copyright (c) 2011 Fabrice Bellard
+ *   The original design remains. The terminal itself
+ *   has been extended to include xterm CSI codes, among
+ *   other features.
+ */
+
+import { CompositionHelper } from './CompositionHelper.js';
+import { EventEmitter } from './EventEmitter.js';
+import { Viewport } from './Viewport.js';
+
+/**
+ * Terminal Emulation References:
+ *   http://vt100.net/
+ *   http://invisible-island.net/xterm/ctlseqs/ctlseqs.txt
+ *   http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
+ *   http://invisible-island.net/vttest/
+ *   http://www.inwap.com/pdp10/ansicode.txt
+ *   http://linux.die.net/man/4/console_codes
+ *   http://linux.die.net/man/7/urxvt
+ */
+
+// Let it work inside Node.js for automated testing purposes.
+var document = (typeof window != 'undefined') ? window.document : null;
+
+/**
+ * States
+ */
+var normal = 0, escaped = 1, csi = 2, osc = 3, charset = 4, dcs = 5, ignore = 6;
+
+/**
+ * Terminal
+ */
+
+/**
+ * Creates a new `Terminal` object.
+ *
+ * @param {object} options An object containing a set of options, the available options are:
+ *   - cursorBlink (boolean): Whether the terminal cursor blinks
+ *
+ * @public
+ * @class Xterm Xterm
+ * @alias module:xterm/src/xterm
+ */
+function Terminal(options) {
+  var self = this;
+
+  if (!(this instanceof Terminal)) {
+    return new Terminal(arguments[0], arguments[1], arguments[2]);
+  }
+
+  self.cancel = Terminal.cancel;
+
+  EventEmitter.call(this);
+
+  if (typeof options === 'number') {
+    options = {
+      cols: arguments[0],
+      rows: arguments[1],
+      handler: arguments[2]
+    };
+  }
+
+  options = options || {};
+
+
+  Object.keys(Terminal.defaults).forEach(function(key) {
+    if (options[key] == null) {
+      options[key] = Terminal.options[key];
+
+      if (Terminal[key] !== Terminal.defaults[key]) {
+        options[key] = Terminal[key];
+      }
+    }
+    self[key] = options[key];
+  });
+
+  if (options.colors.length === 8) {
+    options.colors = options.colors.concat(Terminal._colors.slice(8));
+  } else if (options.colors.length === 16) {
+    options.colors = options.colors.concat(Terminal._colors.slice(16));
+  } else if (options.colors.length === 10) {
+    options.colors = options.colors.slice(0, -2).concat(
+      Terminal._colors.slice(8, -2), options.colors.slice(-2));
+  } else if (options.colors.length === 18) {
+    options.colors = options.colors.concat(
+      Terminal._colors.slice(16, -2), options.colors.slice(-2));
+  }
+  this.colors = options.colors;
+
+  this.options = options;
+
+  // this.context = options.context || window;
+  // this.document = options.document || document;
+  this.parent = options.body || options.parent || (
+    document ? document.getElementsByTagName('body')[0] : null
+  );
+
+  this.cols = options.cols || options.geometry[0];
+  this.rows = options.rows || options.geometry[1];
+
+  if (options.handler) {
+    this.on('data', options.handler);
+  }
+
+  /**
+   * The scroll position of the y cursor, ie. ybase + y = the y position within the entire
+   * buffer
+   */
+  this.ybase = 0;
+
+  /**
+   * The scroll position of the viewport
+   */
+  this.ydisp = 0;
+
+  /**
+   * The cursor's x position after ybase
+   */
+  this.x = 0;
+
+  /**
+   * The cursor's y position after ybase
+   */
+  this.y = 0;
+
+  /**
+   * Used to debounce the refresh function
+   */
+  this.isRefreshing = false;
+
+  /**
+   * Whether there is a full terminal refresh queued
+   */
+
+  this.cursorState = 0;
+  this.cursorHidden = false;
+  this.convertEol;
+  this.state = 0;
+  this.queue = '';
+  this.scrollTop = 0;
+  this.scrollBottom = this.rows - 1;
+  this.customKeydownHandler = null;
+
+  // modes
+  this.applicationKeypad = false;
+  this.applicationCursor = false;
+  this.originMode = false;
+  this.insertMode = false;
+  this.wraparoundMode = true; // defaults: xterm - true, vt100 - false
+  this.normal = null;
+
+  // charset
+  this.charset = null;
+  this.gcharset = null;
+  this.glevel = 0;
+  this.charsets = [null];
+
+  // mouse properties
+  this.decLocator;
+  this.x10Mouse;
+  this.vt200Mouse;
+  this.vt300Mouse;
+  this.normalMouse;
+  this.mouseEvents;
+  this.sendFocus;
+  this.utfMouse;
+  this.sgrMouse;
+  this.urxvtMouse;
+
+  // misc
+  this.element;
+  this.children;
+  this.refreshStart;
+  this.refreshEnd;
+  this.savedX;
+  this.savedY;
+  this.savedCols;
+
+  // stream
+  this.readable = true;
+  this.writable = true;
+
+  this.defAttr = (0 << 18) | (257 << 9) | (256 << 0);
+  this.curAttr = this.defAttr;
+
+  this.params = [];
+  this.currentParam = 0;
+  this.prefix = '';
+  this.postfix = '';
+
+  // leftover surrogate high from previous write invocation
+  this.surrogate_high = '';
+
+  /**
+   * An array of all lines in the entire buffer, including the prompt. The lines are array of
+   * characters which are 2-length arrays where [0] is an attribute and [1] is the character.
+   */
+  this.lines = [];
+  var i = this.rows;
+  while (i--) {
+    this.lines.push(this.blankLine());
+  }
+
+  this.tabs;
+  this.setupStops();
+}
+
+inherits(Terminal, EventEmitter);
+
+/**
+ * back_color_erase feature for xterm.
+ */
+Terminal.prototype.eraseAttr = function() {
+  // if (this.is('screen')) return this.defAttr;
+  return (this.defAttr & ~0x1ff) | (this.curAttr & 0x1ff);
+};
+
+/**
+ * Colors
+ */
+
+// Colors 0-15
+Terminal.tangoColors = [
+  // dark:
+  '#2e3436',
+  '#cc0000',
+  '#4e9a06',
+  '#c4a000',
+  '#3465a4',
+  '#75507b',
+  '#06989a',
+  '#d3d7cf',
+  // bright:
+  '#555753',
+  '#ef2929',
+  '#8ae234',
+  '#fce94f',
+  '#729fcf',
+  '#ad7fa8',
+  '#34e2e2',
+  '#eeeeec'
+];
+
+// Colors 0-15 + 16-255
+// Much thanks to TooTallNate for writing this.
+Terminal.colors = (function() {
+  var colors = Terminal.tangoColors.slice()
+  , r = [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff]
+  , i;
+
+  // 16-231
+  i = 0;
+  for (; i < 216; i++) {
+    out(r[(i / 36) % 6 | 0], r[(i / 6) % 6 | 0], r[i % 6]);
+  }
+
+  // 232-255 (grey)
+  i = 0;
+  for (; i < 24; i++) {
+    r = 8 + i * 10;
+    out(r, r, r);
+  }
+
+  function out(r, g, b) {
+    colors.push('#' + hex(r) + hex(g) + hex(b));
+  }
+
+  function hex(c) {
+    c = c.toString(16);
+    return c.length < 2 ? '0' + c : c;
+  }
+
+  return colors;
+})();
+
+Terminal._colors = Terminal.colors.slice();
+
+Terminal.vcolors = (function() {
+  var out = []
+  , colors = Terminal.colors
+  , i = 0
+  , color;
+
+  for (; i < 256; i++) {
+    color = parseInt(colors[i].substring(1), 16);
+    out.push([
+      (color >> 16) & 0xff,
+      (color >> 8) & 0xff,
+      color & 0xff
+    ]);
+  }
+
+  return out;
+})();
+
+/**
+ * Options
+ */
+
+Terminal.defaults = {
+  colors: Terminal.colors,
+  theme: 'default',
+  convertEol: false,
+  termName: 'xterm',
+  geometry: [80, 24],
+  cursorBlink: false,
+  visualBell: false,
+  popOnBell: false,
+  scrollback: 1000,
+  screenKeys: false,
+  debug: false,
+  cancelEvents: false
+  // programFeatures: false,
+  // focusKeys: false,
+};
+
+Terminal.options = {};
+
+Terminal.focus = null;
+
+each(keys(Terminal.defaults), function(key) {
+  Terminal[key] = Terminal.defaults[key];
+  Terminal.options[key] = Terminal.defaults[key];
+});
+
+/**
+ * Focus the terminal. Delegates focus handling to the terminal's DOM element.
+ */
+Terminal.prototype.focus = function() {
+  return this.textarea.focus();
+};
+
+/**
+ * Retrieves an option's value from the terminal.
+ * @param {string} key The option key.
+ */
+Terminal.prototype.getOption = function(key, value) {
+  if (!(key in Terminal.defaults)) {
+    throw new Error('No option with key "' + key + '"');
+  }
+
+  if (typeof this.options[key] !== 'undefined') {
+    return this.options[key];
+  }
+
+  return this[key];
+};
+
+/**
+ * Sets an option on the terminal.
+ * @param {string} key The option key.
+ * @param {string} value The option value.
+ */
+Terminal.prototype.setOption = function(key, value) {
+  if (!(key in Terminal.defaults)) {
+    throw new Error('No option with key "' + key + '"');
+  }
+  this[key] = value;
+  this.options[key] = value;
+};
+
+/**
+ * Binds the desired focus behavior on a given terminal object.
+ *
+ * @static
+ */
+Terminal.bindFocus = function (term) {
+  on(term.textarea, 'focus', function (ev) {
+    if (term.sendFocus) {
+      term.send('\x1b[I');
+    }
+    term.element.classList.add('focus');
+    term.showCursor();
+    Terminal.focus = term;
+    term.emit('focus', {terminal: term});
+  });
+};
+
+/**
+ * Blur the terminal. Delegates blur handling to the terminal's DOM element.
+ */
+Terminal.prototype.blur = function() {
+  return this.textarea.blur();
+};
+
+/**
+ * Binds the desired blur behavior on a given terminal object.
+ *
+ * @static
+ */
+Terminal.bindBlur = function (term) {
+  on(term.textarea, 'blur', function (ev) {
+    term.refresh(term.y, term.y);
+    if (term.sendFocus) {
+      term.send('\x1b[O');
+    }
+    term.element.classList.remove('focus');
+    Terminal.focus = null;
+    term.emit('blur', {terminal: term});
+  });
+};
+
+/**
+ * Initialize default behavior
+ */
+Terminal.prototype.initGlobal = function() {
+  Terminal.bindPaste(this);
+  Terminal.bindKeys(this);
+  Terminal.bindCopy(this);
+  Terminal.bindFocus(this);
+  Terminal.bindBlur(this);
+};
+
+/**
+ * Bind to paste event and allow both keyboard and right-click pasting, without having the
+ * contentEditable value set to true.
+ */
+Terminal.bindPaste = function(term) {
+  on([term.textarea, term.element], 'paste', function(ev) {
+    ev.stopPropagation();
+    if (ev.clipboardData) {
+      var text = ev.clipboardData.getData('text/plain');
+      term.handler(text);
+      term.textarea.value = '';
+      return term.cancel(ev);
+    }
+  });
+};
+
+/**
+ * Prepares text copied from terminal selection, to be saved in the clipboard by:
+ *   1. stripping all trailing white spaces
+ *   2. converting all non-breaking spaces to regular spaces
+ * @param {string} text The copied text that needs processing for storing in clipboard
+ * @returns {string}
+ * @static
+ */
+Terminal.prepareCopiedTextForClipboard = function (text) {
+  var space = String.fromCharCode(32),
+      nonBreakingSpace = String.fromCharCode(160),
+      allNonBreakingSpaces = new RegExp(nonBreakingSpace, 'g'),
+      processedText = text.split('\n').map(function (line) {
+        /**
+         * Strip all trailing white spaces and convert all non-breaking spaces to regular
+         * spaces.
+         */
+        var processedLine = line.replace(/\s+$/g, '').replace(allNonBreakingSpaces, space);
+
+        return processedLine;
+      }).join('\n');
+
+  return processedText;
+};
+
+/**
+ * Apply key handling to the terminal
+ */
+Terminal.bindKeys = function(term) {
+  on(term.element, 'keydown', function(ev) {
+    if (document.activeElement != this) {
+      return;
+    }
+    term.keyDown(ev);
+  }, true);
+
+  on(term.element, 'keypress', function(ev) {
+    if (document.activeElement != this) {
+      return;
+    }
+    term.keyPress(ev);
+  }, true);
+
+  on(term.element, 'keyup', term.focus.bind(term));
+
+  on(term.textarea, 'keydown', function(ev) {
+    term.keyDown(ev);
+  }, true);
+
+  on(term.textarea, 'keypress', function(ev) {
+    term.keyPress(ev);
+    // Truncate the textarea's value, since it is not needed
+    this.value = '';
+  }, true);
+
+  on(term.textarea, 'compositionstart', term.compositionHelper.compositionstart.bind(term.compositionHelper));
+  on(term.textarea, 'compositionupdate', term.compositionHelper.compositionupdate.bind(term.compositionHelper));
+  on(term.textarea, 'compositionend', term.compositionHelper.compositionend.bind(term.compositionHelper));
+  term.on('refresh', term.compositionHelper.updateCompositionElements.bind(term.compositionHelper));
+};
+
+/**
+ * Binds copy functionality to the given terminal.
+ * @static
+ */
+Terminal.bindCopy = function(term) {
+  on(term.element, 'copy', function(ev) {
+    return; // temporary
+  });
+};
+
+
+/**
+ * Insert the given row to the terminal or produce a new one
+ * if no row argument is passed. Return the inserted row.
+ * @param {HTMLElement} row (optional) The row to append to the terminal.
+ */
+Terminal.prototype.insertRow = function (row) {
+  if (typeof row != 'object') {
+    row = document.createElement('div');
+  }
+
+  this.rowContainer.appendChild(row);
+  this.children.push(row);
+
+  return row;
+};
+
+/**
+ * Opens the terminal within an element.
+ *
+ * @param {HTMLElement} parent The element to create the terminal within.
+ */
+Terminal.prototype.open = function(parent) {
+  var self=this, i=0, div;
+
+  this.parent = parent || this.parent;
+
+  if (!this.parent) {
+    throw new Error('Terminal requires a parent element.');
+  }
+
+  // Grab global elements
+  this.context = this.parent.ownerDocument.defaultView;
+  this.document = this.parent.ownerDocument;
+  this.body = this.document.getElementsByTagName('body')[0];
+
+  // Parse User-Agent
+  if (this.context.navigator && this.context.navigator.userAgent) {
+    this.isMSIE = !!~this.context.navigator.userAgent.indexOf('MSIE');
+  }
+
+  // Find the users platform. We use this to interpret the meta key
+  // and ISO third level shifts.
+  // http://stackoverflow.com/q/19877924/577598
+  if (this.context.navigator && this.context.navigator.platform) {
+    this.isMac = contains(
+      this.context.navigator.platform,
+      ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K']
+    );
+    this.isIpad = this.context.navigator.platform === 'iPad';
+    this.isIphone = this.context.navigator.platform === 'iPhone';
+    this.isMSWindows = contains(
+      this.context.navigator.platform,
+      ['Windows', 'Win16', 'Win32', 'WinCE']
+    );
+  }
+
+  //Create main element container
+  this.element = this.document.createElement('div');
+  this.element.classList.add('terminal');
+  this.element.classList.add('xterm');
+  this.element.classList.add('xterm-theme-' + this.theme);
+
+  this.element.style.height
+  this.element.setAttribute('tabindex', 0);
+
+  this.viewportElement = document.createElement('div');
+  this.viewportElement.classList.add('xterm-viewport');
+  this.element.appendChild(this.viewportElement);
+  this.viewportScrollArea = document.createElement('div');
+  this.viewportScrollArea.classList.add('xterm-scroll-area');
+  this.viewportElement.appendChild(this.viewportScrollArea);
+
+  // Create the container that will hold the lines of the terminal and then
+  // produce the lines the lines.
+  this.rowContainer = document.createElement('div');
+  this.rowContainer.classList.add('xterm-rows');
+  this.element.appendChild(this.rowContainer);
+  this.children = [];
+
+  // Create the container that will hold helpers like the textarea for
+  // capturing DOM Events. Then produce the helpers.
+  this.helperContainer = document.createElement('div');
+  this.helperContainer.classList.add('xterm-helpers');
+  // TODO: This should probably be inserted once it's filled to prevent an additional layout
+  this.element.appendChild(this.helperContainer);
+  this.textarea = document.createElement('textarea');
+  this.textarea.classList.add('xterm-helper-textarea');
+  this.textarea.setAttribute('autocorrect', 'off');
+  this.textarea.setAttribute('autocapitalize', 'off');
+  this.textarea.setAttribute('spellcheck', 'false');
+  this.textarea.tabIndex = 0;
+  this.textarea.addEventListener('focus', function() {
+    self.emit('focus', {terminal: self});
+  });
+  this.textarea.addEventListener('blur', function() {
+    self.emit('blur', {terminal: self});
+  });
+  this.helperContainer.appendChild(this.textarea);
+
+  this.compositionView = document.createElement('div');
+  this.compositionView.classList.add('composition-view');
+  this.compositionHelper = new CompositionHelper(this.textarea, this.compositionView, this);
+  this.helperContainer.appendChild(this.compositionView);
+
+  this.charMeasureElement = document.createElement('div');
+  this.charMeasureElement.classList.add('xterm-char-measure-element');
+  this.charMeasureElement.innerHTML = 'W';
+  this.helperContainer.appendChild(this.charMeasureElement);
+
+  for (; i < this.rows; i++) {
+    this.insertRow();
+  }
+  this.parent.appendChild(this.element);
+
+  this.viewport = new Viewport(this, this.viewportElement, this.viewportScrollArea, this.charMeasureElement);
+
+  // Draw the screen.
+  this.refresh(0, this.rows - 1);
+
+  // Initialize global actions that
+  // need to be taken on the document.
+  this.initGlobal();
+
+  // Ensure there is a Terminal.focus.
+  this.focus();
+
+  on(this.element, 'click', function() {
+    var selection = document.getSelection(),
+        collapsed = selection.isCollapsed,
+        isRange = typeof collapsed == 'boolean' ? !collapsed : selection.type == 'Range';
+    if (!isRange) {
+      self.focus();
+    }
+  });
+
+  // Listen for mouse events and translate
+  // them into terminal mouse protocols.
+  this.bindMouse();
+
+  // Figure out whether boldness affects
+  // the character width of monospace fonts.
+  if (Terminal.brokenBold == null) {
+    Terminal.brokenBold = isBoldBroken(this.document);
+  }
+
+  this.emit('open');
+};
+
+
+/**
+ * Attempts to load an add-on using CommonJS or RequireJS (whichever is available).
+ * @param {string} addon The name of the addon to load
+ * @static
+ */
+Terminal.loadAddon = function(addon, callback) {
+  if (typeof exports === 'object' && typeof module === 'object') {
+    // CommonJS
+    return require(__dirname + '/../addons/' + addon);
+  } else if (typeof define == 'function') {
+    // RequireJS
+    return require(['../addons/' + addon + '/' + addon], callback);
+  } else {
+    console.error('Cannot load a module without a CommonJS or RequireJS environment.');
+    return false;
+  }
+};
+
+
+/**
+ * XTerm mouse events
+ * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking
+ * To better understand these
+ * the xterm code is very helpful:
+ * Relevant files:
+ *   button.c, charproc.c, misc.c
+ * Relevant functions in xterm/button.c:
+ *   BtnCode, EmitButtonCode, EditorButton, SendMousePosition
+ */
+Terminal.prototype.bindMouse = function() {
+  var el = this.element, self = this, pressed = 32;
+
+  // mouseup, mousedown, wheel
+  // left click: ^[[M 3<^[[M#3<
+  // wheel up: ^[[M`3>
+  function sendButton(ev) {
+    var button
+    , pos;
+
+    // get the xterm-style button
+    button = getButton(ev);
+
+    // get mouse coordinates
+    pos = getCoords(ev);
+    if (!pos) return;
+
+    sendEvent(button, pos);
+
+    switch (ev.overrideType || ev.type) {
+      case 'mousedown':
+        pressed = button;
+        break;
+      case 'mouseup':
+        // keep it at the left
+        // button, just in case.
+        pressed = 32;
+        break;
+      case 'wheel':
+        // nothing. don't
+        // interfere with
+        // `pressed`.
+        break;
+    }
+  }
+
+  // motion example of a left click:
+  // ^[[M 3<^[[M@4<^[[M@5<^[[M@6<^[[M@7<^[[M#7<
+  function sendMove(ev) {
+    var button = pressed
+    , pos;
+
+    pos = getCoords(ev);
+    if (!pos) return;
+
+    // buttons marked as motions
+    // are incremented by 32
+    button += 32;
+
+    sendEvent(button, pos);
+  }
+
+  // encode button and
+  // position to characters
+  function encode(data, ch) {
+    if (!self.utfMouse) {
+      if (ch === 255) return data.push(0);
+      if (ch > 127) ch = 127;
+      data.push(ch);
+    } else {
+      if (ch === 2047) return data.push(0);
+      if (ch < 127) {
+        data.push(ch);
+      } else {
+        if (ch > 2047) ch = 2047;
+        data.push(0xC0 | (ch >> 6));
+        data.push(0x80 | (ch & 0x3F));
+      }
+    }
+  }
+
+  // send a mouse event:
+  // regular/utf8: ^[[M Cb Cx Cy
+  // urxvt: ^[[ Cb ; Cx ; Cy M
+  // sgr: ^[[ Cb ; Cx ; Cy M/m
+  // vt300: ^[[ 24(1/3/5)~ [ Cx , Cy ] \r
+  // locator: CSI P e ; P b ; P r ; P c ; P p & w
+  function sendEvent(button, pos) {
+    // self.emit('mouse', {
+    //   x: pos.x - 32,
+    //   y: pos.x - 32,
+    //   button: button
+    // });
+
+    if (self.vt300Mouse) {
+      // NOTE: Unstable.
+      // http://www.vt100.net/docs/vt3xx-gp/chapter15.html
+      button &= 3;
+      pos.x -= 32;
+      pos.y -= 32;
+      var data = '\x1b[24';
+      if (button === 0) data += '1';
+      else if (button === 1) data += '3';
+      else if (button === 2) data += '5';
+      else if (button === 3) return;
+      else data += '0';
+      data += '~[' + pos.x + ',' + pos.y + ']\r';
+      self.send(data);
+      return;
+    }
+
+    if (self.decLocator) {
+      // NOTE: Unstable.
+      button &= 3;
+      pos.x -= 32;
+      pos.y -= 32;
+      if (button === 0) button = 2;
+      else if (button === 1) button = 4;
+      else if (button === 2) button = 6;
+      else if (button === 3) button = 3;
+      self.send('\x1b['
+                + button
+                + ';'
+                + (button === 3 ? 4 : 0)
+                + ';'
+                + pos.y
+                + ';'
+                + pos.x
+                + ';'
+                + (pos.page || 0)
+                + '&w');
+      return;
+    }
+
+    if (self.urxvtMouse) {
+      pos.x -= 32;
+      pos.y -= 32;
+      pos.x++;
+      pos.y++;
+      self.send('\x1b[' + button + ';' + pos.x + ';' + pos.y + 'M');
+      return;
+    }
+
+    if (self.sgrMouse) {
+      pos.x -= 32;
+      pos.y -= 32;
+      self.send('\x1b[<'
+                + ((button & 3) === 3 ? button & ~3 : button)
+                + ';'
+                + pos.x
+                + ';'
+                + pos.y
+                + ((button & 3) === 3 ? 'm' : 'M'));
+      return;
+    }
+
+    var data = [];
+
+    encode(data, button);
+    encode(data, pos.x);
+    encode(data, pos.y);
+
+    self.send('\x1b[M' + String.fromCharCode.apply(String, data));
+  }
+
+  function getButton(ev) {
+    var button
+    , shift
+    , meta
+    , ctrl
+    , mod;
+
+    // two low bits:
+    // 0 = left
+    // 1 = middle
+    // 2 = right
+    // 3 = release
+    // wheel up/down:
+    // 1, and 2 - with 64 added
+    switch (ev.overrideType || ev.type) {
+      case 'mousedown':
+        button = ev.button != null
+          ? +ev.button
+        : ev.which != null
+          ? ev.which - 1
+        : null;
+
+        if (self.isMSIE) {
+          button = button === 1 ? 0 : button === 4 ? 1 : button;
+        }
+        break;
+      case 'mouseup':
+        button = 3;
+        break;
+      case 'DOMMouseScroll':
+        button = ev.detail < 0
+          ? 64
+        : 65;
+        break;
+      case 'wheel':
+        button = ev.wheelDeltaY > 0
+          ? 64
+        : 65;
+        break;
+    }
+
+    // next three bits are the modifiers:
+    // 4 = shift, 8 = meta, 16 = control
+    shift = ev.shiftKey ? 4 : 0;
+    meta = ev.metaKey ? 8 : 0;
+    ctrl = ev.ctrlKey ? 16 : 0;
+    mod = shift | meta | ctrl;
+
+    // no mods
+    if (self.vt200Mouse) {
+      // ctrl only
+      mod &= ctrl;
+    } else if (!self.normalMouse) {
+      mod = 0;
+    }
+
+    // increment to SP
+    button = (32 + (mod << 2)) + button;
+
+    return button;
+  }
+
+  // mouse coordinates measured in cols/rows
+  function getCoords(ev) {
+    var x, y, w, h, el;
+
+    // ignore browsers without pageX for now
+    if (ev.pageX == null) return;
+
+    x = ev.pageX;
+    y = ev.pageY;
+    el = self.element;
+
+    // should probably check offsetParent
+    // but this is more portable
+    while (el && el !== self.document.documentElement) {
+      x -= el.offsetLeft;
+      y -= el.offsetTop;
+      el = 'offsetParent' in el
+        ? el.offsetParent
+      : el.parentNode;
+    }
+
+    // convert to cols/rows
+    w = self.element.clientWidth;
+    h = self.element.clientHeight;
+    x = Math.ceil((x / w) * self.cols);
+    y = Math.ceil((y / h) * self.rows);
+
+    // be sure to avoid sending
+    // bad positions to the program
+    if (x < 0) x = 0;
+    if (x > self.cols) x = self.cols;
+    if (y < 0) y = 0;
+    if (y > self.rows) y = self.rows;
+
+    // xterm sends raw bytes and
+    // starts at 32 (SP) for each.
+    x += 32;
+    y += 32;
+
+    return {
+      x: x,
+      y: y,
+      type: 'wheel'
+    };
+  }
+
+  on(el, 'mousedown', function(ev) {
+    if (!self.mouseEvents) return;
+
+    // send the button
+    sendButton(ev);
+
+    // ensure focus
+    self.focus();
+
+    // fix for odd bug
+    //if (self.vt200Mouse && !self.normalMouse) {
+    if (self.vt200Mouse) {
+      ev.overrideType = 'mouseup';
+      sendButton(ev);
+      return self.cancel(ev);
+    }
+
+    // bind events
+    if (self.normalMouse) on(self.document, 'mousemove', sendMove);
+
+    // x10 compatibility mode can't send button releases
+    if (!self.x10Mouse) {
+      on(self.document, 'mouseup', function up(ev) {
+        sendButton(ev);
+        if (self.normalMouse) off(self.document, 'mousemove', sendMove);
+        off(self.document, 'mouseup', up);
+        return self.cancel(ev);
+      });
+    }
+
+    return self.cancel(ev);
+  });
+
+  //if (self.normalMouse) {
+  //  on(self.document, 'mousemove', sendMove);
+  //}
+
+  on(el, 'wheel', function(ev) {
+    if (!self.mouseEvents) return;
+    if (self.x10Mouse
+        || self.vt300Mouse
+        || self.decLocator) return;
+    sendButton(ev);
+    return self.cancel(ev);
+  });
+
+  // allow wheel scrolling in
+  // the shell for example
+  on(el, 'wheel', function(ev) {
+    if (self.mouseEvents) return;
+    self.viewport.onWheel(ev);
+    return self.cancel(ev);
+  });
+};
+
+/**
+ * Destroys the terminal.
+ */
+Terminal.prototype.destroy = function() {
+  this.readable = false;
+  this.writable = false;
+  this._events = {};
+  this.handler = function() {};
+  this.write = function() {};
+  if (this.element.parentNode) {
+    this.element.parentNode.removeChild(this.element);
+  }
+  //this.emit('close');
+};
+
+
+/**
+ * Flags used to render terminal text properly
+ */
+Terminal.flags = {
+  BOLD: 1,
+  UNDERLINE: 2,
+  BLINK: 4,
+  INVERSE: 8,
+  INVISIBLE: 16
+}
+
+/**
+ * Refreshes (re-renders) terminal content within two rows (inclusive)
+ *
+ * Rendering Engine:
+ *
+ * In the screen buffer, each character is stored as a an array with a character
+ * and a 32-bit integer:
+ *   - First value: a utf-16 character.
+ *   - Second value:
+ *   - Next 9 bits: background color (0-511).
+ *   - Next 9 bits: foreground color (0-511).
+ *   - Next 14 bits: a mask for misc. flags:
+ *     - 1=bold
+ *     - 2=underline
+ *     - 4=blink
+ *     - 8=inverse
+ *     - 16=invisible
+ *
+ * @param {number} start The row to start from (between 0 and terminal's height terminal - 1)
+ * @param {number} end The row to end at (between fromRow and terminal's height terminal - 1)
+ * @param {boolean} queue Whether the refresh should ran right now or be queued
+ */
+Terminal.prototype.refresh = function(start, end, queue) {
+  var self = this;
+
+  // queue defaults to true
+  queue = (typeof queue == 'undefined') ? true : queue;
+
+  /**
+   * The refresh queue allows refresh to execute only approximately 30 times a second. For
+   * commands that pass a significant amount of output to the write function, this prevents the
+   * terminal from maxing out the CPU and making the UI unresponsive. While commands can still
+   * run beyond what they do on the terminal, it is far better with a debounce in place as
+   * every single terminal manipulation does not need to be constructed in the DOM.
+   *
+   * A side-effect of this is that it makes ^C to interrupt a process seem more responsive.
+   */
+  if (queue) {
+    // If refresh should be queued, order the refresh and return.
+    if (this._refreshIsQueued) {
+      // If a refresh has already been queued, just order a full refresh next
+      this._fullRefreshNext = true;
+    } else {
+      setTimeout(function () {
+        self.refresh(start, end, false);
+      }, 34)
+      this._refreshIsQueued = true;
+    }
+    return;
+  }
+
+  // If refresh should be run right now (not be queued), release the lock
+  this._refreshIsQueued = false;
+
+  // If multiple refreshes were requested, make a full refresh.
+  if (this._fullRefreshNext) {
+    start = 0;
+    end = this.rows - 1;
+    this._fullRefreshNext = false // reset lock
+  }
+
+  var x, y, i, line, out, ch, ch_width, width, data, attr, bg, fg, flags, row, parent, focused = document.activeElement;
+
+  // If this is a big refresh, remove the terminal rows from the DOM for faster calculations
+  if (end - start >= this.rows / 2) {
+    parent = this.element.parentNode;
+    if (parent) {
+      this.element.removeChild(this.rowContainer);
+    }
+  }
+
+  width = this.cols;
+  y = start;
+
+  if (end >= this.rows.length) {
+    this.log('`end` is too large. Most likely a bad CSR.');
+    end = this.rows.length - 1;
+  }
+
+  for (; y <= end; y++) {
+    row = y + this.ydisp;
+
+    line = this.lines[row];
+    out = '';
+
+    if (this.y === y - (this.ybase - this.ydisp)
+        && this.cursorState
+        && !this.cursorHidden) {
+      x = this.x;
+    } else {
+      x = -1;
+    }
+
+    attr = this.defAttr;
+    i = 0;
+
+    for (; i < width; i++) {
+      data = line[i][0];
+      ch = line[i][1];
+      ch_width = line[i][2];
+      if (!ch_width)
+        continue;
+
+      if (i === x) data = -1;
+
+      if (data !== attr) {
+        if (attr !== this.defAttr) {
+          out += '</span>';
+        }
+        if (data !== this.defAttr) {
+          if (data === -1) {
+            out += '<span class="reverse-video terminal-cursor';
+            if (this.cursorBlink) {
+              out += ' blinking';
+            }
+            out += '">';
+          } else {
+            var classNames = [];
+
+            bg = data & 0x1ff;
+            fg = (data >> 9) & 0x1ff;
+            flags = data >> 18;
+
+            if (flags & Terminal.flags.BOLD) {
+              if (!Terminal.brokenBold) {
+                classNames.push('xterm-bold');
+              }
+              // See: XTerm*boldColors
+              if (fg < 8) fg += 8;
+            }
+
+            if (flags & Terminal.flags.UNDERLINE) {
+              classNames.push('xterm-underline');
+            }
+
+            if (flags & Terminal.flags.BLINK) {
+              classNames.push('xterm-blink');
+            }
+
+            // If inverse flag is on, then swap the foreground and background variables.
+            if (flags & Terminal.flags.INVERSE) {
+              /* One-line variable swap in JavaScript: http://stackoverflow.com/a/16201730 */
+              bg = [fg, fg = bg][0];
+              // Should inverse just be before the
+              // above boldColors effect instead?
+              if ((flags & 1) && fg < 8) fg += 8;
+            }
+
+            if (flags & Terminal.flags.INVISIBLE) {
+              classNames.push('xterm-hidden');
+            }
+
+            /**
+             * Weird situation: Invert flag used black foreground and white background results
+             * in invalid background color, positioned at the 256 index of the 256 terminal
+             * color map. Pin the colors manually in such a case.
+             *
+             * Source: https://github.com/sourcelair/xterm.js/issues/57
+             */
+            if (flags & Terminal.flags.INVERSE) {
+              if (bg == 257) {
+                bg = 15;
+              }
+              if (fg == 256) {
+                fg = 0;
+              }
+            }
+
+            if (bg < 256) {
+              classNames.push('xterm-bg-color-' + bg);
+            }
+
+            if (fg < 256) {
+              classNames.push('xterm-color-' + fg);
+            }
+
+            out += '<span';
+            if (classNames.length) {
+              out += ' class="' + classNames.join(' ') + '"';
+            }
+            out += '>';
+          }
+        }
+      }
+
+      switch (ch) {
+        case '&':
+          out += '&amp;';
+          break;
+        case '<':
+          out += '&lt;';
+          break;
+        case '>':
+          out += '&gt;';
+          break;
+        default:
+          if (ch <= ' ') {
+            out += '&nbsp;';
+          } else {
+            out += ch;
+          }
+          break;
+      }
+
+      attr = data;
+    }
+
+    if (attr !== this.defAttr) {
+      out += '</span>';
+    }
+
+    this.children[y].innerHTML = out;
+  }
+
+  if (parent) {
+    this.element.appendChild(this.rowContainer);
+  }
+
+  this.emit('refresh', {element: this.element, start: start, end: end});
+};
+
+/**
+ * Display the cursor element
+ */
+Terminal.prototype.showCursor = function() {
+  if (!this.cursorState) {
+    this.cursorState = 1;
+    this.refresh(this.y, this.y);
+  }
+};
+
+/**
+ * Scroll the terminal
+ */
+Terminal.prototype.scroll = function() {
+  var row;
+
+  if (++this.ybase === this.scrollback) {
+    this.ybase = this.ybase / 2 | 0;
+    this.lines = this.lines.slice(-(this.ybase + this.rows) + 1);
+  }
+
+  this.ydisp = this.ybase;
+
+  // last line
+  row = this.ybase + this.rows - 1;
+
+  // subtract the bottom scroll region
+  row -= this.rows - 1 - this.scrollBottom;
+
+  if (row === this.lines.length) {
+    // potential optimization:
+    // pushing is faster than splicing
+    // when they amount to the same
+    // behavior.
+    this.lines.push(this.blankLine());
+  } else {
+    // add our new line
+    this.lines.splice(row, 0, this.blankLine());
+  }
+
+  if (this.scrollTop !== 0) {
+    if (this.ybase !== 0) {
+      this.ybase--;
+      this.ydisp = this.ybase;
+    }
+    this.lines.splice(this.ybase + this.scrollTop, 1);
+  }
+
+  // this.maxRange();
+  this.updateRange(this.scrollTop);
+  this.updateRange(this.scrollBottom);
+
+  this.emit('scroll', this.ydisp);
+};
+
+/**
+ * Scroll the display of the terminal
+ * @param {number} disp The number of lines to scroll down (negatives scroll up).
+ * @param {boolean} suppressScrollEvent Don't emit the scroll event as scrollDisp. This is used
+ * to avoid unwanted events being handled by the veiwport when the event was triggered from the
+ * viewport originally.
+ */
+Terminal.prototype.scrollDisp = function(disp, suppressScrollEvent) {
+  this.ydisp += disp;
+
+  if (this.ydisp > this.ybase) {
+    this.ydisp = this.ybase;
+  } else if (this.ydisp < 0) {
+    this.ydisp = 0;
+  }
+
+  if (!suppressScrollEvent) {
+    this.emit('scroll', this.ydisp);
+  }
+
+  this.refresh(0, this.rows - 1);
+};
+
+/**
+ * Writes text to the terminal.
+ * @param {string} text The text to write to the terminal.
+ */
+Terminal.prototype.write = function(data) {
+  var l = data.length, i = 0, j, cs, ch, code, low, ch_width, row;
+
+  this.refreshStart = this.y;
+  this.refreshEnd = this.y;
+
+  if (this.ybase !== this.ydisp) {
+    this.ydisp = this.ybase;
+    this.emit('scroll', this.ydisp);
+    this.maxRange();
+  }
+
+  // apply leftover surrogate high from last write
+  if (this.surrogate_high) {
+    data = this.surrogate_high + data;
+    this.surrogate_high = '';
+  }
+
+  for (; i < l; i++) {
+    ch = data[i];
+
+    // FIXME: higher chars than 0xa0 are not allowed in escape sequences
+    //        --> maybe move to default
+    code = data.charCodeAt(i);
+    if (0xD800 <= code && code <= 0xDBFF) {
+      // we got a surrogate high
+      // get surrogate low (next 2 bytes)
+      low = data.charCodeAt(i+1);
+      if (isNaN(low)) {
+        // end of data stream, save surrogate high
+        this.surrogate_high = ch;
+        continue;
+      }
+      code = ((code - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000;
+      ch += data.charAt(i+1);
+    }
+    // surrogate low - already handled above
+    if (0xDC00 <= code && code <= 0xDFFF)
+      continue;
+
+    switch (this.state) {
+      case normal:
+        switch (ch) {
+          case '\x07':
+            this.bell();
+            break;
+
+          // '\n', '\v', '\f'
+          case '\n':
+          case '\x0b':
+          case '\x0c':
+            if (this.convertEol) {
+              this.x = 0;
+            }
+            this.y++;
+            if (this.y > this.scrollBottom) {
+              this.y--;
+              this.scroll();
+            }
+            break;
+
+          // '\r'
+          case '\r':
+            this.x = 0;
+            break;
+
+          // '\b'
+          case '\x08':
+            if (this.x > 0) {
+              this.x--;
+            }
+            break;
+
+          // '\t'
+          case '\t':
+            this.x = this.nextStop();
+            break;
+
+          // shift out
+          case '\x0e':
+            this.setgLevel(1);
+            break;
+
+          // shift in
+          case '\x0f':
+            this.setgLevel(0);
+            break;
+
+          // '\e'
+          case '\x1b':
+            this.state = escaped;
+            break;
+
+          default:
+            // ' '
+            // calculate print space
+            // expensive call, therefore we save width in line buffer
+            ch_width = wcwidth(code);
+
+            if (ch >= ' ') {
+              if (this.charset && this.charset[ch]) {
+                ch = this.charset[ch];
+              }
+
+              row = this.y + this.ybase;
+
+              // insert combining char in last cell
+              // FIXME: needs handling after cursor jumps
+              if (!ch_width && this.x) {
+
+                // dont overflow left
+                if (this.lines[row][this.x-1]) {
+                  if (!this.lines[row][this.x-1][2]) {
+
+                    // found empty cell after fullwidth, need to go 2 cells back
+                    if (this.lines[row][this.x-2])
+                      this.lines[row][this.x-2][1] += ch;
+
+                  } else {
+                    this.lines[row][this.x-1][1] += ch;
+                  }
+                  this.updateRange(this.y);
+                }
+                break;
+              }
+
+              // goto next line if ch would overflow
+              // TODO: needs a global min terminal width of 2
+              if (this.x+ch_width-1 >= this.cols) {
+                // autowrap - DECAWM
+                if (this.wraparoundMode) {
+                  this.x = 0;
+                  this.y++;
+                  if (this.y > this.scrollBottom) {
+                    this.y--;
+                    this.scroll();
+                  }
+                } else {
+                  this.x = this.cols-1;
+                  if(ch_width===2)  // FIXME: check for xterm behavior
+                    continue;
+                }
+              }
+              row = this.y + this.ybase;
+
+              // insert mode: move characters to right
+              if (this.insertMode) {
+                // do this twice for a fullwidth char
+                for (var moves=0; moves<ch_width; ++moves) {
+                  // remove last cell, if it's width is 0
+                  // we have to adjust the second last cell as well
+                  var removed = this.lines[this.y + this.ybase].pop();
+                  if (removed[2]===0
+                      && this.lines[row][this.cols-2]
+                      && this.lines[row][this.cols-2][2]===2)
+                    this.lines[row][this.cols-2] = [this.curAttr, ' ', 1];
+
+                  // insert empty cell at cursor
+                  this.lines[row].splice(this.x, 0, [this.curAttr, ' ', 1]);
+                }
+              }
+
+              this.lines[row][this.x] = [this.curAttr, ch, ch_width];
+              this.x++;
+              this.updateRange(this.y);
+
+              // fullwidth char - set next cell width to zero and advance cursor
+              if (ch_width===2) {
+                this.lines[row][this.x] = [this.curAttr, '', 0];
+                this.x++;
+              }
+            }
+            break;
+        }
+        break;
+      case escaped:
+        switch (ch) {
+          // ESC [ Control Sequence Introducer ( CSI is 0x9b).
+          case '[':
+            this.params = [];
+            this.currentParam = 0;
+            this.state = csi;
+            break;
+
+          // ESC ] Operating System Command ( OSC is 0x9d).
+          case ']':
+            this.params = [];
+            this.currentParam = 0;
+            this.state = osc;
+            break;
+
+          // ESC P Device Control String ( DCS is 0x90).
+          case 'P':
+            this.params = [];
+            this.currentParam = 0;
+            this.state = dcs;
+            break;
+
+          // ESC _ Application Program Command ( APC is 0x9f).
+          case '_':
+            this.state = ignore;
+            break;
+
+          // ESC ^ Privacy Message ( PM is 0x9e).
+          case '^':
+            this.state = ignore;
+            break;
+
+          // ESC c Full Reset (RIS).
+          case 'c':
+            this.reset();
+            break;
+
+          // ESC E Next Line ( NEL is 0x85).
+          // ESC D Index ( IND is 0x84).
+          case 'E':
+            this.x = 0;
+            ;
+          case 'D':
+            this.index();
+            break;
+
+          // ESC M Reverse Index ( RI is 0x8d).
+          case 'M':
+            this.reverseIndex();
+            break;
+
+          // ESC % Select default/utf-8 character set.
+          // @ = default, G = utf-8
+          case '%':
+            //this.charset = null;
+            this.setgLevel(0);
+            this.setgCharset(0, Terminal.charsets.US);
+            this.state = normal;
+            i++;
+            break;
+
+          // ESC (,),*,+,-,. Designate G0-G2 Character Set.
+          case '(': // <-- this seems to get all the attention
+          case ')':
+          case '*':
+          case '+':
+          case '-':
+          case '.':
+            switch (ch) {
+              case '(':
+                this.gcharset = 0;
+                break;
+              case ')':
+                this.gcharset = 1;
+                break;
+              case '*':
+                this.gcharset = 2;
+                break;
+              case '+':
+                this.gcharset = 3;
+                break;
+              case '-':
+                this.gcharset = 1;
+                break;
+              case '.':
+                this.gcharset = 2;
+                break;
+            }
+            this.state = charset;
+            break;
+
+          // Designate G3 Character Set (VT300).
+          // A = ISO Latin-1 Supplemental.
+          // Not implemented.
+          case '/':
+            this.gcharset = 3;
+            this.state = charset;
+            i--;
+            break;
+
+          // ESC N
+          // Single Shift Select of G2 Character Set
+          // ( SS2 is 0x8e). This affects next character only.
+          case 'N':
+            break;
+          // ESC O
+          // Single Shift Select of G3 Character Set
+          // ( SS3 is 0x8f). This affects next character only.
+          case 'O':
+            break;
+          // ESC n
+          // Invoke the G2 Character Set as GL (LS2).
+          case 'n':
+            this.setgLevel(2);
+            break;
+          // ESC o
+          // Invoke the G3 Character Set as GL (LS3).
+          case 'o':
+            this.setgLevel(3);
+            break;
+          // ESC |
+          // Invoke the G3 Character Set as GR (LS3R).
+          case '|':
+            this.setgLevel(3);
+            break;
+          // ESC }
+          // Invoke the G2 Character Set as GR (LS2R).
+          case '}':
+            this.setgLevel(2);
+            break;
+          // ESC ~
+          // Invoke the G1 Character Set as GR (LS1R).
+          case '~':
+            this.setgLevel(1);
+            break;
+
+          // ESC 7 Save Cursor (DECSC).
+          case '7':
+            this.saveCursor();
+            this.state = normal;
+            break;
+
+          // ESC 8 Restore Cursor (DECRC).
+          case '8':
+            this.restoreCursor();
+            this.state = normal;
+            break;
+
+          // ESC # 3 DEC line height/width
+          case '#':
+            this.state = normal;
+            i++;
+            break;
+
+          // ESC H Tab Set (HTS is 0x88).
+          case 'H':
+            this.tabSet();
+            break;
+
+          // ESC = Application Keypad (DECKPAM).
+          case '=':
+            this.log('Serial port requested application keypad.');
+            this.applicationKeypad = true;
+            this.viewport.syncScrollArea();
+            this.state = normal;
+            break;
+
+          // ESC > Normal Keypad (DECKPNM).
+          case '>':
+            this.log('Switching back to normal keypad.');
+            this.applicationKeypad = false;
+            this.viewport.syncScrollArea();
+            this.state = normal;
+            break;
+
+          default:
+            this.state = normal;
+            this.error('Unknown ESC control: %s.', ch);
+            break;
+        }
+        break;
+
+      case charset:
+        switch (ch) {
+          case '0': // DEC Special Character and Line Drawing Set.
+            cs = Terminal.charsets.SCLD;
+            break;
+          case 'A': // UK
+            cs = Terminal.charsets.UK;
+            break;
+          case 'B': // United States (USASCII).
+            cs = Terminal.charsets.US;
+            break;
+          case '4': // Dutch
+            cs = Terminal.charsets.Dutch;
+            break;
+          case 'C': // Finnish
+          case '5':
+            cs = Terminal.charsets.Finnish;
+            break;
+          case 'R': // French
+            cs = Terminal.charsets.French;
+            break;
+          case 'Q': // FrenchCanadian
+            cs = Terminal.charsets.FrenchCanadian;
+            break;
+          case 'K': // German
+            cs = Terminal.charsets.German;
+            break;
+          case 'Y': // Italian
+            cs = Terminal.charsets.Italian;
+            break;
+          case 'E': // NorwegianDanish
+          case '6':
+            cs = Terminal.charsets.NorwegianDanish;
+            break;
+          case 'Z': // Spanish
+            cs = Terminal.charsets.Spanish;
+            break;
+          case 'H': // Swedish
+          case '7':
+            cs = Terminal.charsets.Swedish;
+            break;
+          case '=': // Swiss
+            cs = Terminal.charsets.Swiss;
+            break;
+          case '/': // ISOLatin (actually /A)
+            cs = Terminal.charsets.ISOLatin;
+            i++;
+            break;
+          default: // Default
+            cs = Terminal.charsets.US;
+            break;
+        }
+        this.setgCharset(this.gcharset, cs);
+        this.gcharset = null;
+        this.state = normal;
+        break;
+
+      case osc:
+        // OSC Ps ; Pt ST
+        // OSC Ps ; Pt BEL
+        //   Set Text Parameters.
+        if (ch === '\x1b' || ch === '\x07') {
+          if (ch === '\x1b') i++;
+
+          this.params.push(this.currentParam);
+
+          switch (this.params[0]) {
+            case 0:
+            case 1:
+            case 2:
+              if (this.params[1]) {
+                this.title = this.params[1];
+                this.handleTitle(this.title);
+              }
+              break;
+            case 3:
+              // set X property
+              break;
+            case 4:
+            case 5:
+              // change dynamic colors
+              break;
+            case 10:
+            case 11:
+            case 12:
+            case 13:
+            case 14:
+            case 15:
+            case 16:
+            case 17:
+            case 18:
+            case 19:
+              // change dynamic ui colors
+              break;
+            case 46:
+              // change log file
+              break;
+            case 50:
+              // dynamic font
+              break;
+            case 51:
+              // emacs shell
+              break;
+            case 52:
+              // manipulate selection data
+              break;
+            case 104:
+            case 105:
+            case 110:
+            case 111:
+            case 112:
+            case 113:
+            case 114:
+            case 115:
+            case 116:
+            case 117:
+            case 118:
+              // reset colors
+              break;
+          }
+
+          this.params = [];
+          this.currentParam = 0;
+          this.state = normal;
+        } else {
+          if (!this.params.length) {
+            if (ch >= '0' && ch <= '9') {
+              this.currentParam =
+                this.currentParam * 10 + ch.charCodeAt(0) - 48;
+            } else if (ch === ';') {
+              this.params.push(this.currentParam);
+              this.currentParam = '';
+            }
+          } else {
+            this.currentParam += ch;
+          }
+        }
+        break;
+
+      case csi:
+        // '?', '>', '!'
+        if (ch === '?' || ch === '>' || ch === '!') {
+          this.prefix = ch;
+          break;
+        }
+
+        // 0 - 9
+        if (ch >= '0' && ch <= '9') {
+          this.currentParam = this.currentParam * 10 + ch.charCodeAt(0) - 48;
+          break;
+        }
+
+        // '$', '"', ' ', '\''
+        if (ch === '$' || ch === '"' || ch === ' ' || ch === '\'') {
+          this.postfix = ch;
+          break;
+        }
+
+        this.params.push(this.currentParam);
+        this.currentParam = 0;
+
+        // ';'
+        if (ch === ';') break;
+
+        this.state = normal;
+
+        switch (ch) {
+          // CSI Ps A
+          // Cursor Up Ps Times (default = 1) (CUU).
+          case 'A':
+            this.cursorUp(this.params);
+            break;
+
+          // CSI Ps B
+          // Cursor Down Ps Times (default = 1) (CUD).
+          case 'B':
+            this.cursorDown(this.params);
+            break;
+
+          // CSI Ps C
+          // Cursor Forward Ps Times (default = 1) (CUF).
+          case 'C':
+            this.cursorForward(this.params);
+            break;
+
+          // CSI Ps D
+          // Cursor Backward Ps Times (default = 1) (CUB).
+          case 'D':
+            this.cursorBackward(this.params);
+            break;
+
+          // CSI Ps ; Ps H
+          // Cursor Position [row;column] (default = [1,1]) (CUP).
+          case 'H':
+            this.cursorPos(this.params);
+            break;
+
+          // CSI Ps J  Erase in Display (ED).
+          case 'J':
+            this.eraseInDisplay(this.params);
+            break;
+
+          // CSI Ps K  Erase in Line (EL).
+          case 'K':
+            this.eraseInLine(this.params);
+            break;
+
+          // CSI Pm m  Character Attributes (SGR).
+          case 'm':
+            if (!this.prefix) {
+              this.charAttributes(this.params);
+            }
+            break;
+
+          // CSI Ps n  Device Status Report (DSR).
+          case 'n':
+            if (!this.prefix) {
+              this.deviceStatus(this.params);
+            }
+            break;
+
+            /**
+             * Additions
+             */
+
+          // CSI Ps @
+          // Insert Ps (Blank) Character(s) (default = 1) (ICH).
+          case '@':
+            this.insertChars(this.params);
+            break;
+
+          // CSI Ps E
+          // Cursor Next Line Ps Times (default = 1) (CNL).
+          case 'E':
+            this.cursorNextLine(this.params);
+            break;
+
+          // CSI Ps F
+          // Cursor Preceding Line Ps Times (default = 1) (CNL).
+          case 'F':
+            this.cursorPrecedingLine(this.params);
+            break;
+
+          // CSI Ps G
+          // Cursor Character Absolute  [column] (default = [row,1]) (CHA).
+          case 'G':
+            this.cursorCharAbsolute(this.params);
+            break;
+
+          // CSI Ps L
+          // Insert Ps Line(s) (default = 1) (IL).
+          case 'L':
+            this.insertLines(this.params);
+            break;
+
+          // CSI Ps M
+          // Delete Ps Line(s) (default = 1) (DL).
+          case 'M':
+            this.deleteLines(this.params);
+            break;
+
+          // CSI Ps P
+          // Delete Ps Character(s) (default = 1) (DCH).
+          case 'P':
+            this.deleteChars(this.params);
+            break;
+
+          // CSI Ps X
+          // Erase Ps Character(s) (default = 1) (ECH).
+          case 'X':
+            this.eraseChars(this.params);
+            break;
+
+          // CSI Pm `  Character Position Absolute
+          //   [column] (default = [row,1]) (HPA).
+          case '`':
+            this.charPosAbsolute(this.params);
+            break;
+
+          // 141 61 a * HPR -
+          // Horizontal Position Relative
+          case 'a':
+            this.HPositionRelative(this.params);
+            break;
+
+          // CSI P s c
+          // Send Device Attributes (Primary DA).
+          // CSI > P s c
+          // Send Device Attributes (Secondary DA)
+          case 'c':
+            this.sendDeviceAttributes(this.params);
+            break;
+
+          // CSI Pm d
+          // Line Position Absolute  [row] (default = [1,column]) (VPA).
+          case 'd':
+            this.linePosAbsolute(this.params);
+            break;
+
+          // 145 65 e * VPR - Vertical Position Relative
+          case 'e':
+            this.VPositionRelative(this.params);
+            break;
+
+          // CSI Ps ; Ps f
+          //   Horizontal and Vertical Position [row;column] (default =
+          //   [1,1]) (HVP).
+          case 'f':
+            this.HVPosition(this.params);
+            break;
+
+          // CSI Pm h  Set Mode (SM).
+          // CSI ? Pm h - mouse escape codes, cursor escape codes
+          case 'h':
+            this.setMode(this.params);
+            break;
+
+          // CSI Pm l  Reset Mode (RM).
+          // CSI ? Pm l
+          case 'l':
+            this.resetMode(this.params);
+            break;
+
+          // CSI Ps ; Ps r
+          //   Set Scrolling Region [top;bottom] (default = full size of win-
+          //   dow) (DECSTBM).
+          // CSI ? Pm r
+          case 'r':
+            this.setScrollRegion(this.params);
+            break;
+
+          // CSI s
+          //   Save cursor (ANSI.SYS).
+          case 's':
+            this.saveCursor(this.params);
+            break;
+
+          // CSI u
+          //   Restore cursor (ANSI.SYS).
+          case 'u':
+            this.restoreCursor(this.params);
+            break;
+
+            /**
+             * Lesser Used
+             */
+
+          // CSI Ps I
+          // Cursor Forward Tabulation Ps tab stops (default = 1) (CHT).
+          case 'I':
+            this.cursorForwardTab(this.params);
+            break;
+
+          // CSI Ps S  Scroll up Ps lines (default = 1) (SU).
+          case 'S':
+            this.scrollUp(this.params);
+            break;
+
+          // CSI Ps T  Scroll down Ps lines (default = 1) (SD).
+          // CSI Ps ; Ps ; Ps ; Ps ; Ps T
+          // CSI > Ps; Ps T
+          case 'T':
+            // if (this.prefix === '>') {
+            //   this.resetTitleModes(this.params);
+            //   break;
+            // }
+            // if (this.params.length > 2) {
+            //   this.initMouseTracking(this.params);
+            //   break;
+            // }
+            if (this.params.length < 2 && !this.prefix) {
+              this.scrollDown(this.params);
+            }
+            break;
+
+          // CSI Ps Z
+          // Cursor Backward Tabulation Ps tab stops (default = 1) (CBT).
+          case 'Z':
+            this.cursorBackwardTab(this.params);
+            break;
+
+          // CSI Ps b  Repeat the preceding graphic character Ps times (REP).
+          case 'b':
+            this.repeatPrecedingCharacter(this.params);
+            break;
+
+          // CSI Ps g  Tab Clear (TBC).
+          case 'g':
+            this.tabClear(this.params);
+            break;
+
+            // CSI Pm i  Media Copy (MC).
+            // CSI ? Pm i
+            // case 'i':
+            //   this.mediaCopy(this.params);
+            //   break;
+
+            // CSI Pm m  Character Attributes (SGR).
+            // CSI > Ps; Ps m
+            // case 'm': // duplicate
+            //   if (this.prefix === '>') {
+            //     this.setResources(this.params);
+            //   } else {
+            //     this.charAttributes(this.params);
+            //   }
+            //   break;
+
+            // CSI Ps n  Device Status Report (DSR).
+            // CSI > Ps n
+            // case 'n': // duplicate
+            //   if (this.prefix === '>') {
+            //     this.disableModifiers(this.params);
+            //   } else {
+            //     this.deviceStatus(this.params);
+            //   }
+            //   break;
+
+            // CSI > Ps p  Set pointer mode.
+            // CSI ! p   Soft terminal reset (DECSTR).
+            // CSI Ps$ p
+            //   Request ANSI mode (DECRQM).
+            // CSI ? Ps$ p
+            //   Request DEC private mode (DECRQM).
+            // CSI Ps ; Ps " p
+          case 'p':
+            switch (this.prefix) {
+                // case '>':
+                //   this.setPointerMode(this.params);
+                //   break;
+              case '!':
+                this.softReset(this.params);
+                break;
+                // case '?':
+                //   if (this.postfix === '$') {
+                //     this.requestPrivateMode(this.params);
+                //   }
+                //   break;
+                // default:
+                //   if (this.postfix === '"') {
+                //     this.setConformanceLevel(this.params);
+                //   } else if (this.postfix === '$') {
+                //     this.requestAnsiMode(this.params);
+                //   }
+                //   break;
+            }
+            break;
+
+            // CSI Ps q  Load LEDs (DECLL).
+            // CSI Ps SP q
+            // CSI Ps " q
+            // case 'q':
+            //   if (this.postfix === ' ') {
+            //     this.setCursorStyle(this.params);
+            //     break;
+            //   }
+            //   if (this.postfix === '"') {
+            //     this.setCharProtectionAttr(this.params);
+            //     break;
+            //   }
+            //   this.loadLEDs(this.params);
+            //   break;
+
+            // CSI Ps ; Ps r
+            //   Set Scrolling Region [top;bottom] (default = full size of win-
+            //   dow) (DECSTBM).
+            // CSI ? Pm r
+            // CSI Pt; Pl; Pb; Pr; Ps$ r
+            // case 'r': // duplicate
+            //   if (this.prefix === '?') {
+            //     this.restorePrivateValues(this.params);
+            //   } else if (this.postfix === '$') {
+            //     this.setAttrInRectangle(this.params);
+            //   } else {
+            //     this.setScrollRegion(this.params);
+            //   }
+            //   break;
+
+            // CSI s     Save cursor (ANSI.SYS).
+            // CSI ? Pm s
+            // case 's': // duplicate
+            //   if (this.prefix === '?') {
+            //     this.savePrivateValues(this.params);
+            //   } else {
+            //     this.saveCursor(this.params);
+            //   }
+            //   break;
+
+            // CSI Ps ; Ps ; Ps t
+            // CSI Pt; Pl; Pb; Pr; Ps$ t
+            // CSI > Ps; Ps t
+            // CSI Ps SP t
+            // case 't':
+            //   if (this.postfix === '$') {
+            //     this.reverseAttrInRectangle(this.params);
+            //   } else if (this.postfix === ' ') {
+            //     this.setWarningBellVolume(this.params);
+            //   } else {
+            //     if (this.prefix === '>') {
+            //       this.setTitleModeFeature(this.params);
+            //     } else {
+            //       this.manipulateWindow(this.params);
+            //     }
+            //   }
+            //   break;
+
+            // CSI u     Restore cursor (ANSI.SYS).
+            // CSI Ps SP u
+            // case 'u': // duplicate
+            //   if (this.postfix === ' ') {
+            //     this.setMarginBellVolume(this.params);
+            //   } else {
+            //     this.restoreCursor(this.params);
+            //   }
+            //   break;
+
+            // CSI Pt; Pl; Pb; Pr; Pp; Pt; Pl; Pp$ v
+            // case 'v':
+            //   if (this.postfix === '$') {
+            //     this.copyRectagle(this.params);
+            //   }
+            //   break;
+
+            // CSI Pt ; Pl ; Pb ; Pr ' w
+            // case 'w':
+            //   if (this.postfix === '\'') {
+            //     this.enableFilterRectangle(this.params);
+            //   }
+            //   break;
+
+            // CSI Ps x  Request Terminal Parameters (DECREQTPARM).
+            // CSI Ps x  Select Attribute Change Extent (DECSACE).
+            // CSI Pc; Pt; Pl; Pb; Pr$ x
+            // case 'x':
+            //   if (this.postfix === '$') {
+            //     this.fillRectangle(this.params);
+            //   } else {
+            //     this.requestParameters(this.params);
+            //     //this.__(this.params);
+            //   }
+            //   break;
+
+            // CSI Ps ; Pu ' z
+            // CSI Pt; Pl; Pb; Pr$ z
+            // case 'z':
+            //   if (this.postfix === '\'') {
+            //     this.enableLocatorReporting(this.params);
+            //   } else if (this.postfix === '$') {
+            //     this.eraseRectangle(this.params);
+            //   }
+            //   break;
+
+            // CSI Pm ' {
+            // CSI Pt; Pl; Pb; Pr$ {
+            // case '{':
+            //   if (this.postfix === '\'') {
+            //     this.setLocatorEvents(this.params);
+            //   } else if (this.postfix === '$') {
+            //     this.selectiveEraseRectangle(this.params);
+            //   }
+            //   break;
+
+            // CSI Ps ' |
+            // case '|':
+            //   if (this.postfix === '\'') {
+            //     this.requestLocatorPosition(this.params);
+            //   }
+            //   break;
+
+            // CSI P m SP }
+            // Insert P s Column(s) (default = 1) (DECIC), VT420 and up.
+            // case '}':
+            //   if (this.postfix === ' ') {
+            //     this.insertColumns(this.params);
+            //   }
+            //   break;
+
+            // CSI P m SP ~
+            // Delete P s Column(s) (default = 1) (DECDC), VT420 and up
+            // case '~':
+            //   if (this.postfix === ' ') {
+            //     this.deleteColumns(this.params);
+            //   }
+            //   break;
+
+          default:
+            this.error('Unknown CSI code: %s.', ch);
+            break;
+        }
+
+        this.prefix = '';
+        this.postfix = '';
+        break;
+
+      case dcs:
+        if (ch === '\x1b' || ch === '\x07') {
+          if (ch === '\x1b') i++;
+
+          switch (this.prefix) {
+            // User-Defined Keys (DECUDK).
+            case '':
+              break;
+
+            // Request Status String (DECRQSS).
+            // test: echo -e '\eP$q"p\e\\'
+            case '$q':
+              var pt = this.currentParam
+              , valid = false;
+
+              switch (pt) {
+                // DECSCA
+                case '"q':
+                  pt = '0"q';
+                  break;
+
+                // DECSCL
+                case '"p':
+                  pt = '61"p';
+                  break;
+
+                // DECSTBM
+                case 'r':
+                  pt = ''
+                    + (this.scrollTop + 1)
+                    + ';'
+                    + (this.scrollBottom + 1)
+                    + 'r';
+                  break;
+
+                // SGR
+                case 'm':
+                  pt = '0m';
+                  break;
+
+                default:
+                  this.error('Unknown DCS Pt: %s.', pt);
+                  pt = '';
+                  break;
+              }
+
+              this.send('\x1bP' + +valid + '$r' + pt + '\x1b\\');
+              break;
+
+            // Set Termcap/Terminfo Data (xterm, experimental).
+            case '+p':
+              break;
+
+            // Request Termcap/Terminfo String (xterm, experimental)
+            // Regular xterm does not even respond to this sequence.
+            // This can cause a small glitch in vim.
+            // test: echo -ne '\eP+q6b64\e\\'
+            case '+q':
+              var pt = this.currentParam
+              , valid = false;
+
+              this.send('\x1bP' + +valid + '+r' + pt + '\x1b\\');
+              break;
+
+            default:
+              this.error('Unknown DCS prefix: %s.', this.prefix);
+              break;
+          }
+
+          this.currentParam = 0;
+          this.prefix = '';
+          this.state = normal;
+        } else if (!this.currentParam) {
+          if (!this.prefix && ch !== '$' && ch !== '+') {
+            this.currentParam = ch;
+          } else if (this.prefix.length === 2) {
+            this.currentParam = ch;
+          } else {
+            this.prefix += ch;
+          }
+        } else {
+          this.currentParam += ch;
+        }
+        break;
+
+      case ignore:
+        // For PM and APC.
+        if (ch === '\x1b' || ch === '\x07') {
+          if (ch === '\x1b') i++;
+          this.state = normal;
+        }
+        break;
+    }
+  }
+
+  this.updateRange(this.y);
+  this.refresh(this.refreshStart, this.refreshEnd);
+};
+
+/**
+ * Writes text to the terminal, followed by a break line character (\n).
+ * @param {string} text The text to write to the terminal.
+ */
+Terminal.prototype.writeln = function(data) {
+  this.write(data + '\r\n');
+};
+
+/**
+ * Attaches a custom keydown handler which is run before keys are processed, giving consumers of
+ * xterm.js ultimate control as to what keys should be processed by the terminal and what keys
+ * should not.
+ * @param {function} customKeydownHandler The custom KeyboardEvent handler to attach. This is a
+ *   function that takes a KeyboardEvent, allowing consumers to stop propogation and/or prevent
+ *   the default action. The function returns whether the event should be processed by xterm.js.
+ */
+Terminal.prototype.attachCustomKeydownHandler = function(customKeydownHandler) {
+  this.customKeydownHandler = customKeydownHandler;
+}
+
+/**
+ * Handle a keydown event
+ * Key Resources:
+ *   - https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent
+ * @param {KeyboardEvent} ev The keydown event to be handled.
+ */
+Terminal.prototype.keyDown = function(ev) {
+  if (this.customKeydownHandler && this.customKeydownHandler(ev) === false) {
+    return false;
+  }
+
+  if (!this.compositionHelper.keydown.bind(this.compositionHelper)(ev)) {
+    return false;
+  }
+
+  var self = this;
+  var result = this.evaluateKeyEscapeSequence(ev);
+
+  if (result.scrollDisp) {
+    this.scrollDisp(result.scrollDisp);
+    return this.cancel(ev, true);
+  }
+
+  if (isThirdLevelShift(this, ev)) {
+    return true;
+  }
+
+  if (result.cancel) {
+    // The event is canceled at the end already, is this necessary?
+    this.cancel(ev, true);
+  }
+
+  if (!result.key) {
+    return true;
+  }
+
+  this.emit('keydown', ev);
+  this.emit('key', result.key, ev);
+  this.showCursor();
+  this.handler(result.key);
+
+  return this.cancel(ev, true);
+};
+
+/**
+ * Returns an object that determines how a KeyboardEvent should be handled. The key of the
+ * returned value is the new key code to pass to the PTY.
+ *
+ * Reference: http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
+ * @param {KeyboardEvent} ev The keyboard event to be translated to key escape sequence.
+ */
+Terminal.prototype.evaluateKeyEscapeSequence = function(ev) {
+  var result = {
+    // Whether to cancel event propogation (NOTE: this may not be needed since the event is
+    // canceled at the end of keyDown
+    cancel: false,
+    // The new key even to emit
+    key: undefined,
+    // The number of characters to scroll, if this is defined it will cancel the event
+    scrollDisp: undefined
+  };
+  var modifiers = ev.shiftKey << 0 | ev.altKey << 1 | ev.ctrlKey << 2 | ev.metaKey << 3;
+  switch (ev.keyCode) {
+    case 8:
+      // backspace
+      if (ev.shiftKey) {
+        result.key = '\x08'; // ^H
+        break;
+      }
+      result.key = '\x7f'; // ^?
+      break;
+    case 9:
+      // tab
+      if (ev.shiftKey) {
+        result.key = '\x1b[Z';
+        break;
+      }
+      result.key = '\t';
+      result.cancel = true;
+      break;
+    case 13:
+      // return/enter
+      result.key = '\r';
+      result.cancel = true;
+      break;
+    case 27:
+      // escape
+      result.key = '\x1b';
+      result.cancel = true;
+      break;
+    case 37:
+      // left-arrow
+      if (modifiers) {
+        result.key = '\x1b[1;' + (modifiers + 1) + 'D';
+        // HACK: Make Alt + left-arrow behave like Ctrl + left-arrow: move one word backwards
+        // http://unix.stackexchange.com/a/108106
+        if (result.key == '\x1b[1;3D') {
+          result.key = '\x1b[1;5D';
+        }
+      } else if (this.applicationCursor) {
+        result.key = '\x1bOD';
+      } else {
+        result.key = '\x1b[D';
+      }
+      break;
+    case 39:
+      // right-arrow
+      if (modifiers) {
+        result.key = '\x1b[1;' + (modifiers + 1) + 'C';
+        // HACK: Make Alt + right-arrow behave like Ctrl + right-arrow: move one word forward
+        // http://unix.stackexchange.com/a/108106
+        if (result.key == '\x1b[1;3C') {
+          result.key = '\x1b[1;5C';
+        }
+      } else if (this.applicationCursor) {
+        result.key = '\x1bOC';
+      } else {
+        result.key = '\x1b[C';
+      }
+      break;
+    case 38:
+      // up-arrow
+      if (modifiers) {
+        result.key = '\x1b[1;' + (modifiers + 1) + 'A';
+        // HACK: Make Alt + up-arrow behave like Ctrl + up-arrow
+        // http://unix.stackexchange.com/a/108106
+        if (result.key == '\x1b[1;3A') {
+          result.key = '\x1b[1;5A';
+        }
+      } else if (this.applicationCursor) {
+        result.key = '\x1bOA';
+      } else {
+        result.key = '\x1b[A';
+      }
+      break;
+    case 40:
+      // down-arrow
+      if (modifiers) {
+        result.key = '\x1b[1;' + (modifiers + 1) + 'B';
+        // HACK: Make Alt + down-arrow behave like Ctrl + down-arrow
+        // http://unix.stackexchange.com/a/108106
+        if (result.key == '\x1b[1;3B') {
+          result.key = '\x1b[1;5B';
+        }
+      } else if (this.applicationCursor) {
+        result.key = '\x1bOB';
+      } else {
+        result.key = '\x1b[B';
+      }
+      break;
+    case 45:
+      // insert
+      if (!ev.shiftKey && !ev.ctrlKey) {
+        // <Ctrl> or <Shift> + <Insert> are used to
+        // copy-paste on some systems.
+        result.key = '\x1b[2~';
+      }
+      break;
+    case 46:
+      // delete
+      if (modifiers) {
+        result.key = '\x1b[3;' + (modifiers + 1) + '~';
+      } else {
+        result.key = '\x1b[3~';
+      }
+      break;
+    case 36:
+      // home
+      if (modifiers)
+        result.key = '\x1b[1;' + (modifiers + 1) + 'H';
+      else if (this.applicationCursor)
+        result.key = '\x1bOH';
+      else
+        result.key = '\x1b[H';
+      break;
+    case 35:
+      // end
+      if (modifiers)
+        result.key = '\x1b[1;' + (modifiers + 1) + 'F';
+      else if (this.applicationCursor)
+        result.key = '\x1bOF';
+      else
+        result.key = '\x1b[F';
+      break;
+    case 33:
+      // page up
+      if (ev.shiftKey) {
+        result.scrollDisp = -(this.rows - 1);
+      } else {
+        result.key = '\x1b[5~';
+      }
+      break;
+    case 34:
+      // page down
+      if (ev.shiftKey) {
+        result.scrollDisp = this.rows - 1;
+      } else {
+        result.key = '\x1b[6~';
+      }
+      break;
+    case 112:
+      // F1-F12
+      if (modifiers) {
+        result.key = '\x1b[1;' + (modifiers + 1) + 'P';
+      } else {
+        result.key = '\x1bOP';
+      }
+      break;
+    case 113:
+      if (modifiers) {
+        result.key = '\x1b[1;' + (modifiers + 1) + 'Q';
+      } else {
+        result.key = '\x1bOQ';
+      }
+      break;
+    case 114:
+      if (modifiers) {
+        result.key = '\x1b[1;' + (modifiers + 1) + 'R';
+      } else {
+        result.key = '\x1bOR';
+      }
+      break;
+    case 115:
+      if (modifiers) {
+        result.key = '\x1b[1;' + (modifiers + 1) + 'S';
+      } else {
+        result.key = '\x1bOS';
+      }
+      break;
+    case 116:
+      if (modifiers) {
+        result.key = '\x1b[15;' + (modifiers + 1) + '~';
+      } else {
+        result.key = '\x1b[15~';
+      }
+      break;
+    case 117:
+      if (modifiers) {
+        result.key = '\x1b[17;' + (modifiers + 1) + '~';
+      } else {
+        result.key = '\x1b[17~';
+      }
+      break;
+    case 118:
+      if (modifiers) {
+        result.key = '\x1b[18;' + (modifiers + 1) + '~';
+      } else {
+        result.key = '\x1b[18~';
+      }
+      break;
+    case 119:
+      if (modifiers) {
+        result.key = '\x1b[19;' + (modifiers + 1) + '~';
+      } else {
+        result.key = '\x1b[19~';
+      }
+      break;
+    case 120:
+      if (modifiers) {
+        result.key = '\x1b[20;' + (modifiers + 1) + '~';
+      } else {
+        result.key = '\x1b[20~';
+      }
+      break;
+    case 121:
+      if (modifiers) {
+        result.key = '\x1b[21;' + (modifiers + 1) + '~';
+      } else {
+        result.key = '\x1b[21~';
+      }
+      break;
+    case 122:
+      if (modifiers) {
+        result.key = '\x1b[23;' + (modifiers + 1) + '~';
+      } else {
+        result.key = '\x1b[23~';
+      }
+      break;
+    case 123:
+      if (modifiers) {
+        result.key = '\x1b[24;' + (modifiers + 1) + '~';
+      } else {
+        result.key = '\x1b[24~';
+      }
+      break;
+    default:
+      // a-z and space
+      if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) {
+        if (ev.keyCode >= 65 && ev.keyCode <= 90) {
+          result.key = String.fromCharCode(ev.keyCode - 64);
+        } else if (ev.keyCode === 32) {
+          // NUL
+          result.key = String.fromCharCode(0);
+        } else if (ev.keyCode >= 51 && ev.keyCode <= 55) {
+          // escape, file sep, group sep, record sep, unit sep
+          result.key = String.fromCharCode(ev.keyCode - 51 + 27);
+        } else if (ev.keyCode === 56) {
+          // delete
+          result.key = String.fromCharCode(127);
+        } else if (ev.keyCode === 219) {
+          // ^[ - escape
+          result.key = String.fromCharCode(27);
+        } else if (ev.keyCode === 221) {
+          // ^] - group sep
+          result.key = String.fromCharCode(29);
+        }
+      } else if (!this.isMac && ev.altKey && !ev.ctrlKey && !ev.metaKey) {
+        // On Mac this is a third level shift. Use <Esc> instead.
+        if (ev.keyCode >= 65 && ev.keyCode <= 90) {
+          result.key = '\x1b' + String.fromCharCode(ev.keyCode + 32);
+        } else if (ev.keyCode === 192) {
+          result.key = '\x1b`';
+        } else if (ev.keyCode >= 48 && ev.keyCode <= 57) {
+          result.key = '\x1b' + (ev.keyCode - 48);
+        }
+      }
+      break;
+  }
+  return result;
+};
+
+/**
+ * Set the G level of the terminal
+ * @param g
+ */
+Terminal.prototype.setgLevel = function(g) {
+  this.glevel = g;
+  this.charset = this.charsets[g];
+};
+
+/**
+ * Set the charset for the given G level of the terminal
+ * @param g
+ * @param charset
+ */
+Terminal.prototype.setgCharset = function(g, charset) {
+  this.charsets[g] = charset;
+  if (this.glevel === g) {
+    this.charset = charset;
+  }
+};
+
+/**
+ * Handle a keypress event.
+ * Key Resources:
+ *   - https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent
+ * @param {KeyboardEvent} ev The keypress event to be handled.
+ */
+Terminal.prototype.keyPress = function(ev) {
+  var key;
+
+  this.cancel(ev);
+
+  if (ev.charCode) {
+    key = ev.charCode;
+  } else if (ev.which == null) {
+    key = ev.keyCode;
+  } else if (ev.which !== 0 && ev.charCode !== 0) {
+    key = ev.which;
+  } else {
+    return false;
+  }
+
+  if (!key || (
+    (ev.altKey || ev.ctrlKey || ev.metaKey) && !isThirdLevelShift(this, ev)
+  )) {
+    return false;
+  }
+
+  key = String.fromCharCode(key);
+
+  this.emit('keypress', key, ev);
+  this.emit('key', key, ev);
+  this.showCursor();
+  this.handler(key);
+
+  return false;
+};
+
+/**
+ * Send data for handling to the terminal
+ * @param {string} data
+ */
+Terminal.prototype.send = function(data) {
+  var self = this;
+
+  if (!this.queue) {
+    setTimeout(function() {
+      self.handler(self.queue);
+      self.queue = '';
+    }, 1);
+  }
+
+  this.queue += data;
+};
+
+/**
+ * Ring the bell.
+ * Note: We could do sweet things with webaudio here
+ */
+Terminal.prototype.bell = function() {
+  if (!this.visualBell) return;
+  var self = this;
+  this.element.style.borderColor = 'white';
+  setTimeout(function() {
+    self.element.style.borderColor = '';
+  }, 10);
+  if (this.popOnBell) this.focus();
+};
+
+/**
+ * Log the current state to the console.
+ */
+Terminal.prototype.log = function() {
+  if (!this.debug) return;
+  if (!this.context.console || !this.context.console.log) return;
+  var args = Array.prototype.slice.call(arguments);
+  this.context.console.log.apply(this.context.console, args);
+};
+
+/**
+ * Log the current state as error to the console.
+ */
+Terminal.prototype.error = function() {
+  if (!this.debug) return;
+  if (!this.context.console || !this.context.console.error) return;
+  var args = Array.prototype.slice.call(arguments);
+  this.context.console.error.apply(this.context.console, args);
+};
+
+/**
+ * Resizes the terminal.
+ *
+ * @param {number} x The number of columns to resize to.
+ * @param {number} y The number of rows to resize to.
+ */
+Terminal.prototype.resize = function(x, y) {
+  var line
+  , el
+  , i
+  , j
+  , ch
+  , addToY;
+
+  if (x === this.cols && y === this.rows) {
+    return;
+  }
+
+  if (x < 1) x = 1;
+  if (y < 1) y = 1;
+
+  // resize cols
+  j = this.cols;
+  if (j < x) {
+    ch = [this.defAttr, ' ', 1]; // does xterm use the default attr?
+    i = this.lines.length;
+    while (i--) {
+      while (this.lines[i].length < x) {
+        this.lines[i].push(ch);
+      }
+    }
+  } else { // (j > x)
+    i = this.lines.length;
+    while (i--) {
+      while (this.lines[i].length > x) {
+        this.lines[i].pop();
+      }
+    }
+  }
+  this.setupStops(j);
+  this.cols = x;
+
+  // resize rows
+  j = this.rows;
+  addToY = 0;
+  if (j < y) {
+    el = this.element;
+    while (j++ < y) {
+      // y is rows, not this.y
+      if (this.lines.length < y + this.ybase) {
+        if (this.ybase > 0 && this.lines.length <= this.ybase + this.y + addToY + 1) {
+          // There is room above the buffer and there are no empty elements below the line,
+          // scroll up
+          this.ybase--;
+          addToY++
+          if (this.ydisp > 0) {
+            // Viewport is at the top of the buffer, must increase downwards
+            this.ydisp--;
+          }
+        } else {
+          // Add a blank line if there is no buffer left at the top to scroll to, or if there
+          // are blank lines after the cursor
+          this.lines.push(this.blankLine());
+        }
+      }
+      if (this.children.length < y) {
+        this.insertRow();
+      }
+    }
+  } else { // (j > y)
+    while (j-- > y) {
+      if (this.lines.length > y + this.ybase) {
+        if (this.lines.length > this.ybase + this.y + 1) {
+          // The line is a blank line below the cursor, remove it
+          this.lines.pop();
+        } else {
+          // The line is the cursor, scroll down
+          this.ybase++;
+          this.ydisp++;
+        }
+      }
+      if (this.children.length > y) {
+        el = this.children.shift();
+        if (!el) continue;
+        el.parentNode.removeChild(el);
+      }
+    }
+  }
+  this.rows = y;
+
+  // Make sure that the cursor stays on screen
+  if (this.y >= y) {
+    this.y = y - 1;
+  }
+  if (addToY) {
+    this.y += addToY;
+  }
+
+  if (this.x >= x) {
+    this.x = x - 1;
+  }
+
+  this.scrollTop = 0;
+  this.scrollBottom = y - 1;
+
+  this.refresh(0, this.rows - 1);
+
+  this.normal = null;
+
+  this.emit('resize', {terminal: this, cols: x, rows: y});
+};
+
+/**
+ * Updates the range of rows to refresh
+ * @param {number} y The number of rows to refresh next.
+ */
+Terminal.prototype.updateRange = function(y) {
+  if (y < this.refreshStart) this.refreshStart = y;
+  if (y > this.refreshEnd) this.refreshEnd = y;
+  // if (y > this.refreshEnd) {
+  //   this.refreshEnd = y;
+  //   if (y > this.rows - 1) {
+  //     this.refreshEnd = this.rows - 1;
+  //   }
+  // }
+};
+
+/**
+ * Set the range of refreshing to the maximyum value
+ */
+Terminal.prototype.maxRange = function() {
+  this.refreshStart = 0;
+  this.refreshEnd = this.rows - 1;
+};
+
+
+
+/**
+ * Setup the tab stops.
+ * @param {number} i
+ */
+Terminal.prototype.setupStops = function(i) {
+  if (i != null) {
+    if (!this.tabs[i]) {
+      i = this.prevStop(i);
+    }
+  } else {
+    this.tabs = {};
+    i = 0;
+  }
+
+  for (; i < this.cols; i += 8) {
+    this.tabs[i] = true;
+  }
+};
+
+
+/**
+ * Move the cursor to the previous tab stop from the given position (default is current).
+ * @param {number} x The position to move the cursor to the previous tab stop.
+ */
+Terminal.prototype.prevStop = function(x) {
+  if (x == null) x = this.x;
+  while (!this.tabs[--x] && x > 0);
+  return x >= this.cols
+    ? this.cols - 1
+  : x < 0 ? 0 : x;
+};
+
+
+/**
+ * Move the cursor one tab stop forward from the given position (default is current).
+ * @param {number} x The position to move the cursor one tab stop forward.
+ */
+Terminal.prototype.nextStop = function(x) {
+  if (x == null) x = this.x;
+  while (!this.tabs[++x] && x < this.cols);
+  return x >= this.cols
+    ? this.cols - 1
+  : x < 0 ? 0 : x;
+};
+
+
+/**
+ * Erase in the identified line everything from "x" to the end of the line (right).
+ * @param {number} x The column from which to start erasing to the end of the line.
+ * @param {number} y The line in which to operate.
+ */
+Terminal.prototype.eraseRight = function(x, y) {
+  var line = this.lines[this.ybase + y]
+  , ch = [this.eraseAttr(), ' ', 1]; // xterm
+
+
+  for (; x < this.cols; x++) {
+    line[x] = ch;
+  }
+
+  this.updateRange(y);
+};
+
+
+
+/**
+ * Erase in the identified line everything from "x" to the start of the line (left).
+ * @param {number} x The column from which to start erasing to the start of the line.
+ * @param {number} y The line in which to operate.
+ */
+Terminal.prototype.eraseLeft = function(x, y) {
+  var line = this.lines[this.ybase + y]
+  , ch = [this.eraseAttr(), ' ', 1]; // xterm
+
+  x++;
+  while (x--) line[x] = ch;
+
+  this.updateRange(y);
+};
+
+/**
+ * Clears the entire buffer, making the prompt line the new first line.
+ */
+Terminal.prototype.clear = function() {
+  if (this.ybase === 0 && this.y === 0) {
+    // Don't clear if it's already clear
+    return;
+  }
+  this.lines = [this.lines[this.ybase + this.y]];
+  this.ydisp = 0;
+  this.ybase = 0;
+  this.y = 0;
+  for (var i = 1; i < this.rows; i++) {
+    this.lines.push(this.blankLine());
+  }
+  this.refresh(0, this.rows - 1);
+  this.emit('scroll', this.ydisp);
+};
+
+/**
+ * Erase all content in the given line
+ * @param {number} y The line to erase all of its contents.
+ */
+Terminal.prototype.eraseLine = function(y) {
+  this.eraseRight(0, y);
+};
+
+
+/**
+ * Return the data array of a blank line/
+ * @param {number} cur First bunch of data for each "blank" character.
+ */
+Terminal.prototype.blankLine = function(cur) {
+  var attr = cur
+  ? this.eraseAttr()
+  : this.defAttr;
+
+  var ch = [attr, ' ', 1]  // width defaults to 1 halfwidth character
+  , line = []
+  , i = 0;
+
+  for (; i < this.cols; i++) {
+    line[i] = ch;
+  }
+
+  return line;
+};
+
+
+/**
+ * If cur return the back color xterm feature attribute. Else return defAttr.
+ * @param {object} cur
+ */
+Terminal.prototype.ch = function(cur) {
+  return cur
+    ? [this.eraseAttr(), ' ', 1]
+  : [this.defAttr, ' ', 1];
+};
+
+
+/**
+ * Evaluate if the current erminal is the given argument.
+ * @param {object} term The terminal to evaluate
+ */
+Terminal.prototype.is = function(term) {
+  var name = this.termName;
+  return (name + '').indexOf(term) === 0;
+};
+
+
+/**
+     * Emit the 'data' event and populate the given data.
+     * @param {string} data The data to populate in the event.
+     */
+Terminal.prototype.handler = function(data) {
+  this.emit('data', data);
+};
+
+
+/**
+ * Emit the 'title' event and populate the given title.
+ * @param {string} title The title to populate in the event.
+ */
+Terminal.prototype.handleTitle = function(title) {
+  this.emit('title', title);
+};
+
+
+/**
+ * ESC
+ */
+
+/**
+ * ESC D Index (IND is 0x84).
+ */
+Terminal.prototype.index = function() {
+  this.y++;
+  if (this.y > this.scrollBottom) {
+    this.y--;
+    this.scroll();
+  }
+  this.state = normal;
+};
+
+
+/**
+ * ESC M Reverse Index (RI is 0x8d).
+ */
+Terminal.prototype.reverseIndex = function() {
+  var j;
+  this.y--;
+  if (this.y < this.scrollTop) {
+    this.y++;
+    // possibly move the code below to term.reverseScroll();
+    // test: echo -ne '\e[1;1H\e[44m\eM\e[0m'
+    // blankLine(true) is xterm/linux behavior
+    this.lines.splice(this.y + this.ybase, 0, this.blankLine(true));
+    j = this.rows - 1 - this.scrollBottom;
+    this.lines.splice(this.rows - 1 + this.ybase - j + 1, 1);
+    // this.maxRange();
+    this.updateRange(this.scrollTop);
+    this.updateRange(this.scrollBottom);
+  }
+  this.state = normal;
+};
+
+
+/**
+ * ESC c Full Reset (RIS).
+ */
+Terminal.prototype.reset = function() {
+  this.options.rows = this.rows;
+  this.options.cols = this.cols;
+  var customKeydownHandler = this.customKeydownHandler;
+  Terminal.call(this, this.options);
+  this.customKeydownHandler = customKeydownHandler;
+  this.refresh(0, this.rows - 1);
+  this.viewport.syncScrollArea();
+};
+
+
+/**
+ * ESC H Tab Set (HTS is 0x88).
+ */
+Terminal.prototype.tabSet = function() {
+  this.tabs[this.x] = true;
+  this.state = normal;
+};
+
+
+/**
+ * CSI
+ */
+
+/**
+ * CSI Ps A
+ * Cursor Up Ps Times (default = 1) (CUU).
+ */
+Terminal.prototype.cursorUp = function(params) {
+  var param = params[0];
+  if (param < 1) param = 1;
+  this.y -= param;
+  if (this.y < 0) this.y = 0;
+};
+
+
+/**
+ * CSI Ps B
+ * Cursor Down Ps Times (default = 1) (CUD).
+ */
+Terminal.prototype.cursorDown = function(params) {
+  var param = params[0];
+  if (param < 1) param = 1;
+  this.y += param;
+  if (this.y >= this.rows) {
+    this.y = this.rows - 1;
+  }
+};
+
+
+/**
+ * CSI Ps C
+ * Cursor Forward Ps Times (default = 1) (CUF).
+ */
+Terminal.prototype.cursorForward = function(params) {
+  var param = params[0];
+  if (param < 1) param = 1;
+  this.x += param;
+  if (this.x >= this.cols) {
+    this.x = this.cols - 1;
+  }
+};
+
+
+/**
+ * CSI Ps D
+ * Cursor Backward Ps Times (default = 1) (CUB).
+ */
+Terminal.prototype.cursorBackward = function(params) {
+  var param = params[0];
+  if (param < 1) param = 1;
+  this.x -= param;
+  if (this.x < 0) this.x = 0;
+};
+
+
+/**
+ * CSI Ps ; Ps H
+ * Cursor Position [row;column] (default = [1,1]) (CUP).
+ */
+Terminal.prototype.cursorPos = function(params) {
+  var row, col;
+
+  row = params[0] - 1;
+
+  if (params.length >= 2) {
+    col = params[1] - 1;
+  } else {
+    col = 0;
+  }
+
+  if (row < 0) {
+    row = 0;
+  } else if (row >= this.rows) {
+    row = this.rows - 1;
+  }
+
+  if (col < 0) {
+    col = 0;
+  } else if (col >= this.cols) {
+    col = this.cols - 1;
+  }
+
+  this.x = col;
+  this.y = row;
+};
+
+
+/**
+ * CSI Ps J  Erase in Display (ED).
+ *     Ps = 0  -> Erase Below (default).
+ *     Ps = 1  -> Erase Above.
+ *     Ps = 2  -> Erase All.
+ *     Ps = 3  -> Erase Saved Lines (xterm).
+ * CSI ? Ps J
+ *   Erase in Display (DECSED).
+ *     Ps = 0  -> Selective Erase Below (default).
+ *     Ps = 1  -> Selective Erase Above.
+ *     Ps = 2  -> Selective Erase All.
+ */
+Terminal.prototype.eraseInDisplay = function(params) {
+  var j;
+  switch (params[0]) {
+    case 0:
+      this.eraseRight(this.x, this.y);
+      j = this.y + 1;
+      for (; j < this.rows; j++) {
+        this.eraseLine(j);
+      }
+      break;
+    case 1:
+      this.eraseLeft(this.x, this.y);
+      j = this.y;
+      while (j--) {
+        this.eraseLine(j);
+      }
+      break;
+    case 2:
+      j = this.rows;
+      while (j--) this.eraseLine(j);
+      break;
+    case 3:
+      ; // no saved lines
+      break;
+  }
+};
+
+
+/**
+ * CSI Ps K  Erase in Line (EL).
+ *     Ps = 0  -> Erase to Right (default).
+ *     Ps = 1  -> Erase to Left.
+ *     Ps = 2  -> Erase All.
+ * CSI ? Ps K
+ *   Erase in Line (DECSEL).
+ *     Ps = 0  -> Selective Erase to Right (default).
+ *     Ps = 1  -> Selective Erase to Left.
+ *     Ps = 2  -> Selective Erase All.
+ */
+Terminal.prototype.eraseInLine = function(params) {
+  switch (params[0]) {
+    case 0:
+      this.eraseRight(this.x, this.y);
+      break;
+    case 1:
+      this.eraseLeft(this.x, this.y);
+      break;
+    case 2:
+      this.eraseLine(this.y);
+      break;
+  }
+};
+
+
+/**
+ * CSI Pm m  Character Attributes (SGR).
+ *     Ps = 0  -> Normal (default).
+ *     Ps = 1  -> Bold.
+ *     Ps = 4  -> Underlined.
+ *     Ps = 5  -> Blink (appears as Bold).
+ *     Ps = 7  -> Inverse.
+ *     Ps = 8  -> Invisible, i.e., hidden (VT300).
+ *     Ps = 2 2  -> Normal (neither bold nor faint).
+ *     Ps = 2 4  -> Not underlined.
+ *     Ps = 2 5  -> Steady (not blinking).
+ *     Ps = 2 7  -> Positive (not inverse).
+ *     Ps = 2 8  -> Visible, i.e., not hidden (VT300).
+ *     Ps = 3 0  -> Set foreground color to Black.
+ *     Ps = 3 1  -> Set foreground color to Red.
+ *     Ps = 3 2  -> Set foreground color to Green.
+ *     Ps = 3 3  -> Set foreground color to Yellow.
+ *     Ps = 3 4  -> Set foreground color to Blue.
+ *     Ps = 3 5  -> Set foreground color to Magenta.
+ *     Ps = 3 6  -> Set foreground color to Cyan.
+ *     Ps = 3 7  -> Set foreground color to White.
+ *     Ps = 3 9  -> Set foreground color to default (original).
+ *     Ps = 4 0  -> Set background color to Black.
+ *     Ps = 4 1  -> Set background color to Red.
+ *     Ps = 4 2  -> Set background color to Green.
+ *     Ps = 4 3  -> Set background color to Yellow.
+ *     Ps = 4 4  -> Set background color to Blue.
+ *     Ps = 4 5  -> Set background color to Magenta.
+ *     Ps = 4 6  -> Set background color to Cyan.
+ *     Ps = 4 7  -> Set background color to White.
+ *     Ps = 4 9  -> Set background color to default (original).
+ *
+ *   If 16-color support is compiled, the following apply.  Assume
+ *   that xterm's resources are set so that the ISO color codes are
+ *   the first 8 of a set of 16.  Then the aixterm colors are the
+ *   bright versions of the ISO colors:
+ *     Ps = 9 0  -> Set foreground color to Black.
+ *     Ps = 9 1  -> Set foreground color to Red.
+ *     Ps = 9 2  -> Set foreground color to Green.
+ *     Ps = 9 3  -> Set foreground color to Yellow.
+ *     Ps = 9 4  -> Set foreground color to Blue.
+ *     Ps = 9 5  -> Set foreground color to Magenta.
+ *     Ps = 9 6  -> Set foreground color to Cyan.
+ *     Ps = 9 7  -> Set foreground color to White.
+ *     Ps = 1 0 0  -> Set background color to Black.
+ *     Ps = 1 0 1  -> Set background color to Red.
+ *     Ps = 1 0 2  -> Set background color to Green.
+ *     Ps = 1 0 3  -> Set background color to Yellow.
+ *     Ps = 1 0 4  -> Set background color to Blue.
+ *     Ps = 1 0 5  -> Set background color to Magenta.
+ *     Ps = 1 0 6  -> Set background color to Cyan.
+ *     Ps = 1 0 7  -> Set background color to White.
+ *
+ *   If xterm is compiled with the 16-color support disabled, it
+ *   supports the following, from rxvt:
+ *     Ps = 1 0 0  -> Set foreground and background color to
+ *     default.
+ *
+ *   If 88- or 256-color support is compiled, the following apply.
+ *     Ps = 3 8  ; 5  ; Ps -> Set foreground color to the second
+ *     Ps.
+ *     Ps = 4 8  ; 5  ; Ps -> Set background color to the second
+ *     Ps.
+ */
+Terminal.prototype.charAttributes = function(params) {
+  // Optimize a single SGR0.
+  if (params.length === 1 && params[0] === 0) {
+    this.curAttr = this.defAttr;
+    return;
+  }
+
+  var l = params.length
+  , i = 0
+  , flags = this.curAttr >> 18
+  , fg = (this.curAttr >> 9) & 0x1ff
+  , bg = this.curAttr & 0x1ff
+  , p;
+
+  for (; i < l; i++) {
+    p = params[i];
+    if (p >= 30 && p <= 37) {
+      // fg color 8
+      fg = p - 30;
+    } else if (p >= 40 && p <= 47) {
+      // bg color 8
+      bg = p - 40;
+    } else if (p >= 90 && p <= 97) {
+      // fg color 16
+      p += 8;
+      fg = p - 90;
+    } else if (p >= 100 && p <= 107) {
+      // bg color 16
+      p += 8;
+      bg = p - 100;
+    } else if (p === 0) {
+      // default
+      flags = this.defAttr >> 18;
+      fg = (this.defAttr >> 9) & 0x1ff;
+      bg = this.defAttr & 0x1ff;
+      // flags = 0;
+      // fg = 0x1ff;
+      // bg = 0x1ff;
+    } else if (p === 1) {
+      // bold text
+      flags |= 1;
+    } else if (p === 4) {
+      // underlined text
+      flags |= 2;
+    } else if (p === 5) {
+      // blink
+      flags |= 4;
+    } else if (p === 7) {
+      // inverse and positive
+      // test with: echo -e '\e[31m\e[42mhello\e[7mworld\e[27mhi\e[m'
+      flags |= 8;
+    } else if (p === 8) {
+      // invisible
+      flags |= 16;
+    } else if (p === 22) {
+      // not bold
+      flags &= ~1;
+    } else if (p === 24) {
+      // not underlined
+      flags &= ~2;
+    } else if (p === 25) {
+      // not blink
+      flags &= ~4;
+    } else if (p === 27) {
+      // not inverse
+      flags &= ~8;
+    } else if (p === 28) {
+      // not invisible
+      flags &= ~16;
+    } else if (p === 39) {
+      // reset fg
+      fg = (this.defAttr >> 9) & 0x1ff;
+    } else if (p === 49) {
+      // reset bg
+      bg = this.defAttr & 0x1ff;
+    } else if (p === 38) {
+      // fg color 256
+      if (params[i + 1] === 2) {
+        i += 2;
+        fg = matchColor(
+          params[i] & 0xff,
+          params[i + 1] & 0xff,
+          params[i + 2] & 0xff);
+        if (fg === -1) fg = 0x1ff;
+        i += 2;
+      } else if (params[i + 1] === 5) {
+        i += 2;
+        p = params[i] & 0xff;
+        fg = p;
+      }
+    } else if (p === 48) {
+      // bg color 256
+      if (params[i + 1] === 2) {
+        i += 2;
+        bg = matchColor(
+          params[i] & 0xff,
+          params[i + 1] & 0xff,
+          params[i + 2] & 0xff);
+        if (bg === -1) bg = 0x1ff;
+        i += 2;
+      } else if (params[i + 1] === 5) {
+        i += 2;
+        p = params[i] & 0xff;
+        bg = p;
+      }
+    } else if (p === 100) {
+      // reset fg/bg
+      fg = (this.defAttr >> 9) & 0x1ff;
+      bg = this.defAttr & 0x1ff;
+    } else {
+      this.error('Unknown SGR attribute: %d.', p);
+    }
+  }
+
+  this.curAttr = (flags << 18) | (fg << 9) | bg;
+};
+
+
+/**
+ * CSI Ps n  Device Status Report (DSR).
+ *     Ps = 5  -> Status Report.  Result (``OK'') is
+ *   CSI 0 n
+ *     Ps = 6  -> Report Cursor Position (CPR) [row;column].
+ *   Result is
+ *   CSI r ; c R
+ * CSI ? Ps n
+ *   Device Status Report (DSR, DEC-specific).
+ *     Ps = 6  -> Report Cursor Position (CPR) [row;column] as CSI
+ *     ? r ; c R (assumes page is zero).
+ *     Ps = 1 5  -> Report Printer status as CSI ? 1 0  n  (ready).
+ *     or CSI ? 1 1  n  (not ready).
+ *     Ps = 2 5  -> Report UDK status as CSI ? 2 0  n  (unlocked)
+ *     or CSI ? 2 1  n  (locked).
+ *     Ps = 2 6  -> Report Keyboard status as
+ *   CSI ? 2 7  ;  1  ;  0  ;  0  n  (North American).
+ *   The last two parameters apply to VT400 & up, and denote key-
+ *   board ready and LK01 respectively.
+ *     Ps = 5 3  -> Report Locator status as
+ *   CSI ? 5 3  n  Locator available, if compiled-in, or
+ *   CSI ? 5 0  n  No Locator, if not.
+ */
+Terminal.prototype.deviceStatus = function(params) {
+  if (!this.prefix) {
+    switch (params[0]) {
+      case 5:
+        // status report
+        this.send('\x1b[0n');
+        break;
+      case 6:
+        // cursor position
+        this.send('\x1b['
+                  + (this.y + 1)
+                  + ';'
+                  + (this.x + 1)
+                  + 'R');
+        break;
+    }
+  } else if (this.prefix === '?') {
+    // modern xterm doesnt seem to
+    // respond to any of these except ?6, 6, and 5
+    switch (params[0]) {
+      case 6:
+        // cursor position
+        this.send('\x1b[?'
+                  + (this.y + 1)
+                  + ';'
+                  + (this.x + 1)
+                  + 'R');
+        break;
+      case 15:
+        // no printer
+        // this.send('\x1b[?11n');
+        break;
+      case 25:
+        // dont support user defined keys
+        // this.send('\x1b[?21n');
+        break;
+      case 26:
+        // north american keyboard
+        // this.send('\x1b[?27;1;0;0n');
+        break;
+      case 53:
+        // no dec locator/mouse
+        // this.send('\x1b[?50n');
+        break;
+    }
+  }
+};
+
+
+/**
+ * Additions
+ */
+
+/**
+ * CSI Ps @
+ * Insert Ps (Blank) Character(s) (default = 1) (ICH).
+ */
+Terminal.prototype.insertChars = function(params) {
+  var param, row, j, ch;
+
+  param = params[0];
+  if (param < 1) param = 1;
+
+  row = this.y + this.ybase;
+  j = this.x;
+  ch = [this.eraseAttr(), ' ', 1]; // xterm
+
+  while (param-- && j < this.cols) {
+    this.lines[row].splice(j++, 0, ch);
+    this.lines[row].pop();
+  }
+};
+
+/**
+ * CSI Ps E
+ * Cursor Next Line Ps Times (default = 1) (CNL).
+ * same as CSI Ps B ?
+ */
+Terminal.prototype.cursorNextLine = function(params) {
+  var param = params[0];
+  if (param < 1) param = 1;
+  this.y += param;
+  if (this.y >= this.rows) {
+    this.y = this.rows - 1;
+  }
+  this.x = 0;
+};
+
+
+/**
+ * CSI Ps F
+ * Cursor Preceding Line Ps Times (default = 1) (CNL).
+ * reuse CSI Ps A ?
+ */
+Terminal.prototype.cursorPrecedingLine = function(params) {
+  var param = params[0];
+  if (param < 1) param = 1;
+  this.y -= param;
+  if (this.y < 0) this.y = 0;
+  this.x = 0;
+};
+
+
+/**
+ * CSI Ps G
+ * Cursor Character Absolute  [column] (default = [row,1]) (CHA).
+ */
+Terminal.prototype.cursorCharAbsolute = function(params) {
+  var param = params[0];
+  if (param < 1) param = 1;
+  this.x = param - 1;
+};
+
+
+/**
+ * CSI Ps L
+ * Insert Ps Line(s) (default = 1) (IL).
+ */
+Terminal.prototype.insertLines = function(params) {
+  var param, row, j;
+
+  param = params[0];
+  if (param < 1) param = 1;
+  row = this.y + this.ybase;
+
+  j = this.rows - 1 - this.scrollBottom;
+  j = this.rows - 1 + this.ybase - j + 1;
+
+  while (param--) {
+    // test: echo -e '\e[44m\e[1L\e[0m'
+    // blankLine(true) - xterm/linux behavior
+    this.lines.splice(row, 0, this.blankLine(true));
+    this.lines.splice(j, 1);
+  }
+
+  // this.maxRange();
+  this.updateRange(this.y);
+  this.updateRange(this.scrollBottom);
+};
+
+
+/**
+ * CSI Ps M
+ * Delete Ps Line(s) (default = 1) (DL).
+ */
+Terminal.prototype.deleteLines = function(params) {
+  var param, row, j;
+
+  param = params[0];
+  if (param < 1) param = 1;
+  row = this.y + this.ybase;
+
+  j = this.rows - 1 - this.scrollBottom;
+  j = this.rows - 1 + this.ybase - j;
+
+  while (param--) {
+    // test: echo -e '\e[44m\e[1M\e[0m'
+    // blankLine(true) - xterm/linux behavior
+    this.lines.splice(j + 1, 0, this.blankLine(true));
+    this.lines.splice(row, 1);
+  }
+
+  // this.maxRange();
+  this.updateRange(this.y);
+  this.updateRange(this.scrollBottom);
+};
+
+
+/**
+ * CSI Ps P
+ * Delete Ps Character(s) (default = 1) (DCH).
+ */
+Terminal.prototype.deleteChars = function(params) {
+  var param, row, ch;
+
+  param = params[0];
+  if (param < 1) param = 1;
+
+  row = this.y + this.ybase;
+  ch = [this.eraseAttr(), ' ', 1]; // xterm
+
+  while (param--) {
+    this.lines[row].splice(this.x, 1);
+    this.lines[row].push(ch);
+  }
+};
+
+/**
+ * CSI Ps X
+ * Erase Ps Character(s) (default = 1) (ECH).
+ */
+Terminal.prototype.eraseChars = function(params) {
+  var param, row, j, ch;
+
+  param = params[0];
+  if (param < 1) param = 1;
+
+  row = this.y + this.ybase;
+  j = this.x;
+  ch = [this.eraseAttr(), ' ', 1]; // xterm
+
+  while (param-- && j < this.cols) {
+    this.lines[row][j++] = ch;
+  }
+};
+
+/**
+ * CSI Pm `  Character Position Absolute
+ *   [column] (default = [row,1]) (HPA).
+ */
+Terminal.prototype.charPosAbsolute = function(params) {
+  var param = params[0];
+  if (param < 1) param = 1;
+  this.x = param - 1;
+  if (this.x >= this.cols) {
+    this.x = this.cols - 1;
+  }
+};
+
+
+/**
+ * 141 61 a * HPR -
+ * Horizontal Position Relative
+ * reuse CSI Ps C ?
+ */
+Terminal.prototype.HPositionRelative = function(params) {
+  var param = params[0];
+  if (param < 1) param = 1;
+  this.x += param;
+  if (this.x >= this.cols) {
+    this.x = this.cols - 1;
+  }
+};
+
+
+/**
+ * CSI Ps c  Send Device Attributes (Primary DA).
+ *     Ps = 0  or omitted -> request attributes from terminal.  The
+ *     response depends on the decTerminalID resource setting.
+ *     -> CSI ? 1 ; 2 c  (``VT100 with Advanced Video Option'')
+ *     -> CSI ? 1 ; 0 c  (``VT101 with No Options'')
+ *     -> CSI ? 6 c  (``VT102'')
+ *     -> CSI ? 6 0 ; 1 ; 2 ; 6 ; 8 ; 9 ; 1 5 ; c  (``VT220'')
+ *   The VT100-style response parameters do not mean anything by
+ *   themselves.  VT220 parameters do, telling the host what fea-
+ *   tures the terminal supports:
+ *     Ps = 1  -> 132-columns.
+ *     Ps = 2  -> Printer.
+ *     Ps = 6  -> Selective erase.
+ *     Ps = 8  -> User-defined keys.
+ *     Ps = 9  -> National replacement character sets.
+ *     Ps = 1 5  -> Technical characters.
+ *     Ps = 2 2  -> ANSI color, e.g., VT525.
+ *     Ps = 2 9  -> ANSI text locator (i.e., DEC Locator mode).
+ * CSI > Ps c
+ *   Send Device Attributes (Secondary DA).
+ *     Ps = 0  or omitted -> request the terminal's identification
+ *     code.  The response depends on the decTerminalID resource set-
+ *     ting.  It should apply only to VT220 and up, but xterm extends
+ *     this to VT100.
+ *     -> CSI  > Pp ; Pv ; Pc c
+ *   where Pp denotes the terminal type
+ *     Pp = 0  -> ``VT100''.
+ *     Pp = 1  -> ``VT220''.
+ *   and Pv is the firmware version (for xterm, this was originally
+ *   the XFree86 patch number, starting with 95).  In a DEC termi-
+ *   nal, Pc indicates the ROM cartridge registration number and is
+ *   always zero.
+ * More information:
+ *   xterm/charproc.c - line 2012, for more information.
+ *   vim responds with ^[[?0c or ^[[?1c after the terminal's response (?)
+ */
+Terminal.prototype.sendDeviceAttributes = function(params) {
+  if (params[0] > 0) return;
+
+  if (!this.prefix) {
+    if (this.is('xterm')
+        || this.is('rxvt-unicode')
+        || this.is('screen')) {
+      this.send('\x1b[?1;2c');
+    } else if (this.is('linux')) {
+      this.send('\x1b[?6c');
+    }
+  } else if (this.prefix === '>') {
+    // xterm and urxvt
+    // seem to spit this
+    // out around ~370 times (?).
+    if (this.is('xterm')) {
+      this.send('\x1b[>0;276;0c');
+    } else if (this.is('rxvt-unicode')) {
+      this.send('\x1b[>85;95;0c');
+    } else if (this.is('linux')) {
+      // not supported by linux console.
+      // linux console echoes parameters.
+      this.send(params[0] + 'c');
+    } else if (this.is('screen')) {
+      this.send('\x1b[>83;40003;0c');
+    }
+  }
+};
+
+
+/**
+ * CSI Pm d
+ * Line Position Absolute  [row] (default = [1,column]) (VPA).
+ */
+Terminal.prototype.linePosAbsolute = function(params) {
+  var param = params[0];
+  if (param < 1) param = 1;
+  this.y = param - 1;
+  if (this.y >= this.rows) {
+    this.y = this.rows - 1;
+  }
+};
+
+
+/**
+ * 145 65 e * VPR - Vertical Position Relative
+ * reuse CSI Ps B ?
+ */
+Terminal.prototype.VPositionRelative = function(params) {
+  var param = params[0];
+  if (param < 1) param = 1;
+  this.y += param;
+  if (this.y >= this.rows) {
+    this.y = this.rows - 1;
+  }
+};
+
+
+/**
+ * CSI Ps ; Ps f
+ *   Horizontal and Vertical Position [row;column] (default =
+ *   [1,1]) (HVP).
+ */
+Terminal.prototype.HVPosition = function(params) {
+  if (params[0] < 1) params[0] = 1;
+  if (params[1] < 1) params[1] = 1;
+
+  this.y = params[0] - 1;
+  if (this.y >= this.rows) {
+    this.y = this.rows - 1;
+  }
+
+  this.x = params[1] - 1;
+  if (this.x >= this.cols) {
+    this.x = this.cols - 1;
+  }
+};
+
+
+/**
+ * CSI Pm h  Set Mode (SM).
+ *     Ps = 2  -> Keyboard Action Mode (AM).
+ *     Ps = 4  -> Insert Mode (IRM).
+ *     Ps = 1 2  -> Send/receive (SRM).
+ *     Ps = 2 0  -> Automatic Newline (LNM).
+ * CSI ? Pm h
+ *   DEC Private Mode Set (DECSET).
+ *     Ps = 1  -> Application Cursor Keys (DECCKM).
+ *     Ps = 2  -> Designate USASCII for character sets G0-G3
+ *     (DECANM), and set VT100 mode.
+ *     Ps = 3  -> 132 Column Mode (DECCOLM).
+ *     Ps = 4  -> Smooth (Slow) Scroll (DECSCLM).
+ *     Ps = 5  -> Reverse Video (DECSCNM).
+ *     Ps = 6  -> Origin Mode (DECOM).
+ *     Ps = 7  -> Wraparound Mode (DECAWM).
+ *     Ps = 8  -> Auto-repeat Keys (DECARM).
+ *     Ps = 9  -> Send Mouse X & Y on button press.  See the sec-
+ *     tion Mouse Tracking.
+ *     Ps = 1 0  -> Show toolbar (rxvt).
+ *     Ps = 1 2  -> Start Blinking Cursor (att610).
+ *     Ps = 1 8  -> Print form feed (DECPFF).
+ *     Ps = 1 9  -> Set print extent to full screen (DECPEX).
+ *     Ps = 2 5  -> Show Cursor (DECTCEM).
+ *     Ps = 3 0  -> Show scrollbar (rxvt).
+ *     Ps = 3 5  -> Enable font-shifting functions (rxvt).
+ *     Ps = 3 8  -> Enter Tektronix Mode (DECTEK).
+ *     Ps = 4 0  -> Allow 80 -> 132 Mode.
+ *     Ps = 4 1  -> more(1) fix (see curses resource).
+ *     Ps = 4 2  -> Enable Nation Replacement Character sets (DECN-
+ *     RCM).
+ *     Ps = 4 4  -> Turn On Margin Bell.
+ *     Ps = 4 5  -> Reverse-wraparound Mode.
+ *     Ps = 4 6  -> Start Logging.  This is normally disabled by a
+ *     compile-time option.
+ *     Ps = 4 7  -> Use Alternate Screen Buffer.  (This may be dis-
+ *     abled by the titeInhibit resource).
+ *     Ps = 6 6  -> Application keypad (DECNKM).
+ *     Ps = 6 7  -> Backarrow key sends backspace (DECBKM).
+ *     Ps = 1 0 0 0  -> Send Mouse X & Y on button press and
+ *     release.  See the section Mouse Tracking.
+ *     Ps = 1 0 0 1  -> Use Hilite Mouse Tracking.
+ *     Ps = 1 0 0 2  -> Use Cell Motion Mouse Tracking.
+ *     Ps = 1 0 0 3  -> Use All Motion Mouse Tracking.
+ *     Ps = 1 0 0 4  -> Send FocusIn/FocusOut events.
+ *     Ps = 1 0 0 5  -> Enable Extended Mouse Mode.
+ *     Ps = 1 0 1 0  -> Scroll to bottom on tty output (rxvt).
+ *     Ps = 1 0 1 1  -> Scroll to bottom on key press (rxvt).
+ *     Ps = 1 0 3 4  -> Interpret "meta" key, sets eighth bit.
+ *     (enables the eightBitInput resource).
+ *     Ps = 1 0 3 5  -> Enable special modifiers for Alt and Num-
+ *     Lock keys.  (This enables the numLock resource).
+ *     Ps = 1 0 3 6  -> Send ESC   when Meta modifies a key.  (This
+ *     enables the metaSendsEscape resource).
+ *     Ps = 1 0 3 7  -> Send DEL from the editing-keypad Delete
+ *     key.
+ *     Ps = 1 0 3 9  -> Send ESC  when Alt modifies a key.  (This
+ *     enables the altSendsEscape resource).
+ *     Ps = 1 0 4 0  -> Keep selection even if not highlighted.
+ *     (This enables the keepSelection resource).
+ *     Ps = 1 0 4 1  -> Use the CLIPBOARD selection.  (This enables
+ *     the selectToClipboard resource).
+ *     Ps = 1 0 4 2  -> Enable Urgency window manager hint when
+ *     Control-G is received.  (This enables the bellIsUrgent
+ *     resource).
+ *     Ps = 1 0 4 3  -> Enable raising of the window when Control-G
+ *     is received.  (enables the popOnBell resource).
+ *     Ps = 1 0 4 7  -> Use Alternate Screen Buffer.  (This may be
+ *     disabled by the titeInhibit resource).
+ *     Ps = 1 0 4 8  -> Save cursor as in DECSC.  (This may be dis-
+ *     abled by the titeInhibit resource).
+ *     Ps = 1 0 4 9  -> Save cursor as in DECSC and use Alternate
+ *     Screen Buffer, clearing it first.  (This may be disabled by
+ *     the titeInhibit resource).  This combines the effects of the 1
+ *     0 4 7  and 1 0 4 8  modes.  Use this with terminfo-based
+ *     applications rather than the 4 7  mode.
+ *     Ps = 1 0 5 0  -> Set terminfo/termcap function-key mode.
+ *     Ps = 1 0 5 1  -> Set Sun function-key mode.
+ *     Ps = 1 0 5 2  -> Set HP function-key mode.
+ *     Ps = 1 0 5 3  -> Set SCO function-key mode.
+ *     Ps = 1 0 6 0  -> Set legacy keyboard emulation (X11R6).
+ *     Ps = 1 0 6 1  -> Set VT220 keyboard emulation.
+ *     Ps = 2 0 0 4  -> Set bracketed paste mode.
+ * Modes:
+ *   http: *vt100.net/docs/vt220-rm/chapter4.html
+ */
+Terminal.prototype.setMode = function(params) {
+  if (typeof params === 'object') {
+    var l = params.length
+    , i = 0;
+
+    for (; i < l; i++) {
+      this.setMode(params[i]);
+    }
+
+    return;
+  }
+
+  if (!this.prefix) {
+    switch (params) {
+      case 4:
+        this.insertMode = true;
+        break;
+      case 20:
+        //this.convertEol = true;
+        break;
+    }
+  } else if (this.prefix === '?') {
+    switch (params) {
+      case 1:
+        this.applicationCursor = true;
+        break;
+      case 2:
+        this.setgCharset(0, Terminal.charsets.US);
+        this.setgCharset(1, Terminal.charsets.US);
+        this.setgCharset(2, Terminal.charsets.US);
+        this.setgCharset(3, Terminal.charsets.US);
+        // set VT100 mode here
+        break;
+      case 3: // 132 col mode
+        this.savedCols = this.cols;
+        this.resize(132, this.rows);
+        break;
+      case 6:
+        this.originMode = true;
+        break;
+      case 7:
+        this.wraparoundMode = true;
+        break;
+      case 12:
+        // this.cursorBlink = true;
+        break;
+      case 66:
+        this.log('Serial port requested application keypad.');
+        this.applicationKeypad = true;
+        this.viewport.syncScrollArea();
+        break;
+      case 9: // X10 Mouse
+        // no release, no motion, no wheel, no modifiers.
+      case 1000: // vt200 mouse
+        // no motion.
+        // no modifiers, except control on the wheel.
+      case 1002: // button event mouse
+      case 1003: // any event mouse
+        // any event - sends motion events,
+        // even if there is no button held down.
+        this.x10Mouse = params === 9;
+        this.vt200Mouse = params === 1000;
+        this.normalMouse = params > 1000;
+        this.mouseEvents = true;
+        this.element.style.cursor = 'default';
+        this.log('Binding to mouse events.');
+        break;
+      case 1004: // send focusin/focusout events
+        // focusin: ^[[I
+        // focusout: ^[[O
+        this.sendFocus = true;
+        break;
+      case 1005: // utf8 ext mode mouse
+        this.utfMouse = true;
+        // for wide terminals
+        // simply encodes large values as utf8 characters
+        break;
+      case 1006: // sgr ext mode mouse
+        this.sgrMouse = true;
+        // for wide terminals
+        // does not add 32 to fields
+        // press: ^[[<b;x;yM
+        // release: ^[[<b;x;ym
+        break;
+      case 1015: // urxvt ext mode mouse
+        this.urxvtMouse = true;
+        // for wide terminals
+        // numbers for fields
+        // press: ^[[b;x;yM
+        // motion: ^[[b;x;yT
+        break;
+      case 25: // show cursor
+        this.cursorHidden = false;
+        break;
+      case 1049: // alt screen buffer cursor
+        //this.saveCursor();
+        ; // FALL-THROUGH
+      case 47: // alt screen buffer
+      case 1047: // alt screen buffer
+        if (!this.normal) {
+          var normal = {
+            lines: this.lines,
+            ybase: this.ybase,
+            ydisp: this.ydisp,
+            x: this.x,
+            y: this.y,
+            scrollTop: this.scrollTop,
+            scrollBottom: this.scrollBottom,
+            tabs: this.tabs
+            // XXX save charset(s) here?
+            // charset: this.charset,
+            // glevel: this.glevel,
+            // charsets: this.charsets
+          };
+          this.reset();
+          this.normal = normal;
+          this.showCursor();
+        }
+        break;
+    }
+  }
+};
+
+/**
+ * CSI Pm l  Reset Mode (RM).
+ *     Ps = 2  -> Keyboard Action Mode (AM).
+ *     Ps = 4  -> Replace Mode (IRM).
+ *     Ps = 1 2  -> Send/receive (SRM).
+ *     Ps = 2 0  -> Normal Linefeed (LNM).
+ * CSI ? Pm l
+ *   DEC Private Mode Reset (DECRST).
+ *     Ps = 1  -> Normal Cursor Keys (DECCKM).
+ *     Ps = 2  -> Designate VT52 mode (DECANM).
+ *     Ps = 3  -> 80 Column Mode (DECCOLM).
+ *     Ps = 4  -> Jump (Fast) Scroll (DECSCLM).
+ *     Ps = 5  -> Normal Video (DECSCNM).
+ *     Ps = 6  -> Normal Cursor Mode (DECOM).
+ *     Ps = 7  -> No Wraparound Mode (DECAWM).
+ *     Ps = 8  -> No Auto-repeat Keys (DECARM).
+ *     Ps = 9  -> Don't send Mouse X & Y on button press.
+ *     Ps = 1 0  -> Hide toolbar (rxvt).
+ *     Ps = 1 2  -> Stop Blinking Cursor (att610).
+ *     Ps = 1 8  -> Don't print form feed (DECPFF).
+ *     Ps = 1 9  -> Limit print to scrolling region (DECPEX).
+ *     Ps = 2 5  -> Hide Cursor (DECTCEM).
+ *     Ps = 3 0  -> Don't show scrollbar (rxvt).
+ *     Ps = 3 5  -> Disable font-shifting functions (rxvt).
+ *     Ps = 4 0  -> Disallow 80 -> 132 Mode.
+ *     Ps = 4 1  -> No more(1) fix (see curses resource).
+ *     Ps = 4 2  -> Disable Nation Replacement Character sets (DEC-
+ *     NRCM).
+ *     Ps = 4 4  -> Turn Off Margin Bell.
+ *     Ps = 4 5  -> No Reverse-wraparound Mode.
+ *     Ps = 4 6  -> Stop Logging.  (This is normally disabled by a
+ *     compile-time option).
+ *     Ps = 4 7  -> Use Normal Screen Buffer.
+ *     Ps = 6 6  -> Numeric keypad (DECNKM).
+ *     Ps = 6 7  -> Backarrow key sends delete (DECBKM).
+ *     Ps = 1 0 0 0  -> Don't send Mouse X & Y on button press and
+ *     release.  See the section Mouse Tracking.
+ *     Ps = 1 0 0 1  -> Don't use Hilite Mouse Tracking.
+ *     Ps = 1 0 0 2  -> Don't use Cell Motion Mouse Tracking.
+ *     Ps = 1 0 0 3  -> Don't use All Motion Mouse Tracking.
+ *     Ps = 1 0 0 4  -> Don't send FocusIn/FocusOut events.
+ *     Ps = 1 0 0 5  -> Disable Extended Mouse Mode.
+ *     Ps = 1 0 1 0  -> Don't scroll to bottom on tty output
+ *     (rxvt).
+ *     Ps = 1 0 1 1  -> Don't scroll to bottom on key press (rxvt).
+ *     Ps = 1 0 3 4  -> Don't interpret "meta" key.  (This disables
+ *     the eightBitInput resource).
+ *     Ps = 1 0 3 5  -> Disable special modifiers for Alt and Num-
+ *     Lock keys.  (This disables the numLock resource).
+ *     Ps = 1 0 3 6  -> Don't send ESC  when Meta modifies a key.
+ *     (This disables the metaSendsEscape resource).
+ *     Ps = 1 0 3 7  -> Send VT220 Remove from the editing-keypad
+ *     Delete key.
+ *     Ps = 1 0 3 9  -> Don't send ESC  when Alt modifies a key.
+ *     (This disables the altSendsEscape resource).
+ *     Ps = 1 0 4 0  -> Do not keep selection when not highlighted.
+ *     (This disables the keepSelection resource).
+ *     Ps = 1 0 4 1  -> Use the PRIMARY selection.  (This disables
+ *     the selectToClipboard resource).
+ *     Ps = 1 0 4 2  -> Disable Urgency window manager hint when
+ *     Control-G is received.  (This disables the bellIsUrgent
+ *     resource).
+ *     Ps = 1 0 4 3  -> Disable raising of the window when Control-
+ *     G is received.  (This disables the popOnBell resource).
+ *     Ps = 1 0 4 7  -> Use Normal Screen Buffer, clearing screen
+ *     first if in the Alternate Screen.  (This may be disabled by
+ *     the titeInhibit resource).
+ *     Ps = 1 0 4 8  -> Restore cursor as in DECRC.  (This may be
+ *     disabled by the titeInhibit resource).
+ *     Ps = 1 0 4 9  -> Use Normal Screen Buffer and restore cursor
+ *     as in DECRC.  (This may be disabled by the titeInhibit
+ *     resource).  This combines the effects of the 1 0 4 7  and 1 0
+ *     4 8  modes.  Use this with terminfo-based applications rather
+ *     than the 4 7  mode.
+ *     Ps = 1 0 5 0  -> Reset terminfo/termcap function-key mode.
+ *     Ps = 1 0 5 1  -> Reset Sun function-key mode.
+ *     Ps = 1 0 5 2  -> Reset HP function-key mode.
+ *     Ps = 1 0 5 3  -> Reset SCO function-key mode.
+ *     Ps = 1 0 6 0  -> Reset legacy keyboard emulation (X11R6).
+ *     Ps = 1 0 6 1  -> Reset keyboard emulation to Sun/PC style.
+ *     Ps = 2 0 0 4  -> Reset bracketed paste mode.
+ */
+Terminal.prototype.resetMode = function(params) {
+  if (typeof params === 'object') {
+    var l = params.length
+    , i = 0;
+
+    for (; i < l; i++) {
+      this.resetMode(params[i]);
+    }
+
+    return;
+  }
+
+  if (!this.prefix) {
+    switch (params) {
+      case 4:
+        this.insertMode = false;
+        break;
+      case 20:
+        //this.convertEol = false;
+        break;
+    }
+  } else if (this.prefix === '?') {
+    switch (params) {
+      case 1:
+        this.applicationCursor = false;
+        break;
+      case 3:
+        if (this.cols === 132 && this.savedCols) {
+          this.resize(this.savedCols, this.rows);
+        }
+        delete this.savedCols;
+        break;
+      case 6:
+        this.originMode = false;
+        break;
+      case 7:
+        this.wraparoundMode = false;
+        break;
+      case 12:
+        // this.cursorBlink = false;
+        break;
+      case 66:
+        this.log('Switching back to normal keypad.');
+        this.applicationKeypad = false;
+        this.viewport.syncScrollArea();
+        break;
+      case 9: // X10 Mouse
+      case 1000: // vt200 mouse
+      case 1002: // button event mouse
+      case 1003: // any event mouse
+        this.x10Mouse = false;
+        this.vt200Mouse = false;
+        this.normalMouse = false;
+        this.mouseEvents = false;
+        this.element.style.cursor = '';
+        break;
+      case 1004: // send focusin/focusout events
+        this.sendFocus = false;
+        break;
+      case 1005: // utf8 ext mode mouse
+        this.utfMouse = false;
+        break;
+      case 1006: // sgr ext mode mouse
+        this.sgrMouse = false;
+        break;
+      case 1015: // urxvt ext mode mouse
+        this.urxvtMouse = false;
+        break;
+      case 25: // hide cursor
+        this.cursorHidden = true;
+        break;
+      case 1049: // alt screen buffer cursor
+        ; // FALL-THROUGH
+      case 47: // normal screen buffer
+      case 1047: // normal screen buffer - clearing it first
+        if (this.normal) {
+          this.lines = this.normal.lines;
+          this.ybase = this.normal.ybase;
+          this.ydisp = this.normal.ydisp;
+          this.x = this.normal.x;
+          this.y = this.normal.y;
+          this.scrollTop = this.normal.scrollTop;
+          this.scrollBottom = this.normal.scrollBottom;
+          this.tabs = this.normal.tabs;
+          this.normal = null;
+          // if (params === 1049) {
+          //   this.x = this.savedX;
+          //   this.y = this.savedY;
+          // }
+          this.refresh(0, this.rows - 1);
+          this.showCursor();
+        }
+        break;
+    }
+  }
+};
+
+
+/**
+ * CSI Ps ; Ps r
+ *   Set Scrolling Region [top;bottom] (default = full size of win-
+ *   dow) (DECSTBM).
+ * CSI ? Pm r
+ */
+Terminal.prototype.setScrollRegion = function(params) {
+  if (this.prefix) return;
+  this.scrollTop = (params[0] || 1) - 1;
+  this.scrollBottom = (params[1] || this.rows) - 1;
+  this.x = 0;
+  this.y = 0;
+};
+
+
+/**
+ * CSI s
+ *   Save cursor (ANSI.SYS).
+ */
+Terminal.prototype.saveCursor = function(params) {
+  this.savedX = this.x;
+  this.savedY = this.y;
+};
+
+
+/**
+ * CSI u
+ *   Restore cursor (ANSI.SYS).
+ */
+Terminal.prototype.restoreCursor = function(params) {
+  this.x = this.savedX || 0;
+  this.y = this.savedY || 0;
+};
+
+
+/**
+ * Lesser Used
+ */
+
+/**
+ * CSI Ps I
+ *   Cursor Forward Tabulation Ps tab stops (default = 1) (CHT).
+ */
+Terminal.prototype.cursorForwardTab = function(params) {
+  var param = params[0] || 1;
+  while (param--) {
+    this.x = this.nextStop();
+  }
+};
+
+
+/**
+ * CSI Ps S  Scroll up Ps lines (default = 1) (SU).
+ */
+Terminal.prototype.scrollUp = function(params) {
+  var param = params[0] || 1;
+  while (param--) {
+    this.lines.splice(this.ybase + this.scrollTop, 1);
+    this.lines.splice(this.ybase + this.scrollBottom, 0, this.blankLine());
+  }
+  // this.maxRange();
+  this.updateRange(this.scrollTop);
+  this.updateRange(this.scrollBottom);
+};
+
+
+/**
+     * CSI Ps T  Scroll down Ps lines (default = 1) (SD).
+     */
+Terminal.prototype.scrollDown = function(params) {
+  var param = params[0] || 1;
+  while (param--) {
+    this.lines.splice(this.ybase + this.scrollBottom, 1);
+    this.lines.splice(this.ybase + this.scrollTop, 0, this.blankLine());
+  }
+  // this.maxRange();
+  this.updateRange(this.scrollTop);
+  this.updateRange(this.scrollBottom);
+};
+
+
+/**
+ * CSI Ps ; Ps ; Ps ; Ps ; Ps T
+ *   Initiate highlight mouse tracking.  Parameters are
+ *   [func;startx;starty;firstrow;lastrow].  See the section Mouse
+ *   Tracking.
+ */
+Terminal.prototype.initMouseTracking = function(params) {
+  // Relevant: DECSET 1001
+};
+
+
+/**
+ * CSI > Ps; Ps T
+ *   Reset one or more features of the title modes to the default
+ *   value.  Normally, "reset" disables the feature.  It is possi-
+ *   ble to disable the ability to reset features by compiling a
+ *   different default for the title modes into xterm.
+ *     Ps = 0  -> Do not set window/icon labels using hexadecimal.
+ *     Ps = 1  -> Do not query window/icon labels using hexadeci-
+ *     mal.
+ *     Ps = 2  -> Do not set window/icon labels using UTF-8.
+ *     Ps = 3  -> Do not query window/icon labels using UTF-8.
+ *   (See discussion of "Title Modes").
+ */
+Terminal.prototype.resetTitleModes = function(params) {
+  ;
+};
+
+
+/**
+ * CSI Ps Z  Cursor Backward Tabulation Ps tab stops (default = 1) (CBT).
+ */
+Terminal.prototype.cursorBackwardTab = function(params) {
+  var param = params[0] || 1;
+  while (param--) {
+    this.x = this.prevStop();
+  }
+};
+
+
+/**
+ * CSI Ps b  Repeat the preceding graphic character Ps times (REP).
+ */
+Terminal.prototype.repeatPrecedingCharacter = function(params) {
+  var param = params[0] || 1
+  , line = this.lines[this.ybase + this.y]
+  , ch = line[this.x - 1] || [this.defAttr, ' ', 1];
+
+  while (param--) line[this.x++] = ch;
+};
+
+
+/**
+ * CSI Ps g  Tab Clear (TBC).
+ *     Ps = 0  -> Clear Current Column (default).
+ *     Ps = 3  -> Clear All.
+ * Potentially:
+ *   Ps = 2  -> Clear Stops on Line.
+ *   http://vt100.net/annarbor/aaa-ug/section6.html
+ */
+Terminal.prototype.tabClear = function(params) {
+  var param = params[0];
+  if (param <= 0) {
+    delete this.tabs[this.x];
+  } else if (param === 3) {
+    this.tabs = {};
+  }
+};
+
+
+/**
+ * CSI Pm i  Media Copy (MC).
+ *     Ps = 0  -> Print screen (default).
+ *     Ps = 4  -> Turn off printer controller mode.
+ *     Ps = 5  -> Turn on printer controller mode.
+ * CSI ? Pm i
+ *   Media Copy (MC, DEC-specific).
+ *     Ps = 1  -> Print line containing cursor.
+ *     Ps = 4  -> Turn off autoprint mode.
+ *     Ps = 5  -> Turn on autoprint mode.
+ *     Ps = 1  0  -> Print composed display, ignores DECPEX.
+ *     Ps = 1  1  -> Print all pages.
+ */
+Terminal.prototype.mediaCopy = function(params) {
+  ;
+};
+
+
+/**
+ * CSI > Ps; Ps m
+ *   Set or reset resource-values used by xterm to decide whether
+ *   to construct escape sequences holding information about the
+ *   modifiers pressed with a given key.  The first parameter iden-
+ *   tifies the resource to set/reset.  The second parameter is the
+ *   value to assign to the resource.  If the second parameter is
+ *   omitted, the resource is reset to its initial value.
+ *     Ps = 1  -> modifyCursorKeys.
+ *     Ps = 2  -> modifyFunctionKeys.
+ *     Ps = 4  -> modifyOtherKeys.
+ *   If no parameters are given, all resources are reset to their
+ *   initial values.
+ */
+Terminal.prototype.setResources = function(params) {
+  ;
+};
+
+
+/**
+ * CSI > Ps n
+ *   Disable modifiers which may be enabled via the CSI > Ps; Ps m
+ *   sequence.  This corresponds to a resource value of "-1", which
+ *   cannot be set with the other sequence.  The parameter identi-
+ *   fies the resource to be disabled:
+ *     Ps = 1  -> modifyCursorKeys.
+ *     Ps = 2  -> modifyFunctionKeys.
+ *     Ps = 4  -> modifyOtherKeys.
+ *   If the parameter is omitted, modifyFunctionKeys is disabled.
+ *   When modifyFunctionKeys is disabled, xterm uses the modifier
+ *   keys to make an extended sequence of functions rather than
+ *   adding a parameter to each function key to denote the modi-
+ *   fiers.
+ */
+Terminal.prototype.disableModifiers = function(params) {
+  ;
+};
+
+
+/**
+ * CSI > Ps p
+ *   Set resource value pointerMode.  This is used by xterm to
+ *   decide whether to hide the pointer cursor as the user types.
+ *   Valid values for the parameter:
+ *     Ps = 0  -> never hide the pointer.
+ *     Ps = 1  -> hide if the mouse tracking mode is not enabled.
+ *     Ps = 2  -> always hide the pointer.  If no parameter is
+ *     given, xterm uses the default, which is 1 .
+ */
+Terminal.prototype.setPointerMode = function(params) {
+  ;
+};
+
+
+/**
+ * CSI ! p   Soft terminal reset (DECSTR).
+ * http://vt100.net/docs/vt220-rm/table4-10.html
+ */
+Terminal.prototype.softReset = function(params) {
+  this.cursorHidden = false;
+  this.insertMode = false;
+  this.originMode = false;
+  this.wraparoundMode = false; // autowrap
+  this.applicationKeypad = false; // ?
+  this.viewport.syncScrollArea();
+  this.applicationCursor = false;
+  this.scrollTop = 0;
+  this.scrollBottom = this.rows - 1;
+  this.curAttr = this.defAttr;
+  this.x = this.y = 0; // ?
+  this.charset = null;
+  this.glevel = 0; // ??
+  this.charsets = [null]; // ??
+};
+
+
+/**
+ * CSI Ps$ p
+ *   Request ANSI mode (DECRQM).  For VT300 and up, reply is
+ *     CSI Ps; Pm$ y
+ *   where Ps is the mode number as in RM, and Pm is the mode
+ *   value:
+ *     0 - not recognized
+ *     1 - set
+ *     2 - reset
+ *     3 - permanently set
+ *     4 - permanently reset
+ */
+Terminal.prototype.requestAnsiMode = function(params) {
+  ;
+};
+
+
+/**
+ * CSI ? Ps$ p
+ *   Request DEC private mode (DECRQM).  For VT300 and up, reply is
+ *     CSI ? Ps; Pm$ p
+ *   where Ps is the mode number as in DECSET, Pm is the mode value
+ *   as in the ANSI DECRQM.
+ */
+Terminal.prototype.requestPrivateMode = function(params) {
+  ;
+};
+
+
+/**
+ * CSI Ps ; Ps " p
+ *   Set conformance level (DECSCL).  Valid values for the first
+ *   parameter:
+ *     Ps = 6 1  -> VT100.
+ *     Ps = 6 2  -> VT200.
+ *     Ps = 6 3  -> VT300.
+ *   Valid values for the second parameter:
+ *     Ps = 0  -> 8-bit controls.
+ *     Ps = 1  -> 7-bit controls (always set for VT100).
+ *     Ps = 2  -> 8-bit controls.
+ */
+Terminal.prototype.setConformanceLevel = function(params) {
+  ;
+};
+
+
+/**
+ * CSI Ps q  Load LEDs (DECLL).
+ *     Ps = 0  -> Clear all LEDS (default).
+ *     Ps = 1  -> Light Num Lock.
+ *     Ps = 2  -> Light Caps Lock.
+ *     Ps = 3  -> Light Scroll Lock.
+ *     Ps = 2  1  -> Extinguish Num Lock.
+ *     Ps = 2  2  -> Extinguish Caps Lock.
+ *     Ps = 2  3  -> Extinguish Scroll Lock.
+ */
+Terminal.prototype.loadLEDs = function(params) {
+  ;
+};
+
+
+/**
+ * CSI Ps SP q
+ *   Set cursor style (DECSCUSR, VT520).
+ *     Ps = 0  -> blinking block.
+ *     Ps = 1  -> blinking block (default).
+ *     Ps = 2  -> steady block.
+ *     Ps = 3  -> blinking underline.
+ *     Ps = 4  -> steady underline.
+ */
+Terminal.prototype.setCursorStyle = function(params) {
+  ;
+};
+
+
+/**
+ * CSI Ps " q
+ *   Select character protection attribute (DECSCA).  Valid values
+ *   for the parameter:
+ *     Ps = 0  -> DECSED and DECSEL can erase (default).
+ *     Ps = 1  -> DECSED and DECSEL cannot erase.
+ *     Ps = 2  -> DECSED and DECSEL can erase.
+ */
+Terminal.prototype.setCharProtectionAttr = function(params) {
+  ;
+};
+
+
+/**
+ * CSI ? Pm r
+ *   Restore DEC Private Mode Values.  The value of Ps previously
+ *   saved is restored.  Ps values are the same as for DECSET.
+ */
+Terminal.prototype.restorePrivateValues = function(params) {
+  ;
+};
+
+
+/**
+ * CSI Pt; Pl; Pb; Pr; Ps$ r
+ *   Change Attributes in Rectangular Area (DECCARA), VT400 and up.
+ *     Pt; Pl; Pb; Pr denotes the rectangle.
+ *     Ps denotes the SGR attributes to change: 0, 1, 4, 5, 7.
+ * NOTE: xterm doesn't enable this code by default.
+ */
+Terminal.prototype.setAttrInRectangle = function(params) {
+  var t = params[0]
+  , l = params[1]
+  , b = params[2]
+  , r = params[3]
+  , attr = params[4];
+
+  var line
+  , i;
+
+  for (; t < b + 1; t++) {
+    line = this.lines[this.ybase + t];
+    for (i = l; i < r; i++) {
+      line[i] = [attr, line[i][1]];
+    }
+  }
+
+  // this.maxRange();
+  this.updateRange(params[0]);
+  this.updateRange(params[2]);
+};
+
+
+/**
+ * CSI Pc; Pt; Pl; Pb; Pr$ x
+ *   Fill Rectangular Area (DECFRA), VT420 and up.
+ *     Pc is the character to use.
+ *     Pt; Pl; Pb; Pr denotes the rectangle.
+ * NOTE: xterm doesn't enable this code by default.
+ */
+Terminal.prototype.fillRectangle = function(params) {
+  var ch = params[0]
+  , t = params[1]
+  , l = params[2]
+  , b = params[3]
+  , r = params[4];
+
+  var line
+  , i;
+
+  for (; t < b + 1; t++) {
+    line = this.lines[this.ybase + t];
+    for (i = l; i < r; i++) {
+      line[i] = [line[i][0], String.fromCharCode(ch)];
+    }
+  }
+
+  // this.maxRange();
+  this.updateRange(params[1]);
+  this.updateRange(params[3]);
+};
+
+
+/**
+ * CSI Ps ; Pu ' z
+ *   Enable Locator Reporting (DECELR).
+ *   Valid values for the first parameter:
+ *     Ps = 0  -> Locator disabled (default).
+ *     Ps = 1  -> Locator enabled.
+ *     Ps = 2  -> Locator enabled for one report, then disabled.
+ *   The second parameter specifies the coordinate unit for locator
+ *   reports.
+ *   Valid values for the second parameter:
+ *     Pu = 0  <- or omitted -> default to character cells.
+ *     Pu = 1  <- device physical pixels.
+ *     Pu = 2  <- character cells.
+ */
+Terminal.prototype.enableLocatorReporting = function(params) {
+  var val = params[0] > 0;
+  //this.mouseEvents = val;
+  //this.decLocator = val;
+};
+
+
+/**
+ * CSI Pt; Pl; Pb; Pr$ z
+ *   Erase Rectangular Area (DECERA), VT400 and up.
+ *     Pt; Pl; Pb; Pr denotes the rectangle.
+ * NOTE: xterm doesn't enable this code by default.
+ */
+Terminal.prototype.eraseRectangle = function(params) {
+  var t = params[0]
+  , l = params[1]
+  , b = params[2]
+  , r = params[3];
+
+  var line
+  , i
+  , ch;
+
+  ch = [this.eraseAttr(), ' ', 1]; // xterm?
+
+  for (; t < b + 1; t++) {
+    line = this.lines[this.ybase + t];
+    for (i = l; i < r; i++) {
+      line[i] = ch;
+    }
+  }
+
+  // this.maxRange();
+  this.updateRange(params[0]);
+  this.updateRange(params[2]);
+};
+
+
+/**
+ * CSI P m SP }
+ * Insert P s Column(s) (default = 1) (DECIC), VT420 and up.
+ * NOTE: xterm doesn't enable this code by default.
+ */
+Terminal.prototype.insertColumns = function() {
+  var param = params[0]
+  , l = this.ybase + this.rows
+  , ch = [this.eraseAttr(), ' ', 1] // xterm?
+  , i;
+
+  while (param--) {
+    for (i = this.ybase; i < l; i++) {
+      this.lines[i].splice(this.x + 1, 0, ch);
+      this.lines[i].pop();
+    }
+  }
+
+  this.maxRange();
+};
+
+
+/**
+ * CSI P m SP ~
+ * Delete P s Column(s) (default = 1) (DECDC), VT420 and up
+ * NOTE: xterm doesn't enable this code by default.
+ */
+Terminal.prototype.deleteColumns = function() {
+  var param = params[0]
+  , l = this.ybase + this.rows
+  , ch = [this.eraseAttr(), ' ', 1] // xterm?
+  , i;
+
+  while (param--) {
+    for (i = this.ybase; i < l; i++) {
+      this.lines[i].splice(this.x, 1);
+      this.lines[i].push(ch);
+    }
+  }
+
+  this.maxRange();
+};
+
+/**
+ * Character Sets
+ */
+
+Terminal.charsets = {};
+
+// DEC Special Character and Line Drawing Set.
+// http://vt100.net/docs/vt102-ug/table5-13.html
+// A lot of curses apps use this if they see TERM=xterm.
+// testing: echo -e '\e(0a\e(B'
+// The xterm output sometimes seems to conflict with the
+// reference above. xterm seems in line with the reference
+// when running vttest however.
+// The table below now uses xterm's output from vttest.
+Terminal.charsets.SCLD = { // (0
+  '`': '\u25c6', // '◆'
+  'a': '\u2592', // '▒'
+  'b': '\u0009', // '\t'
+  'c': '\u000c', // '\f'
+  'd': '\u000d', // '\r'
+  'e': '\u000a', // '\n'
+  'f': '\u00b0', // '°'
+  'g': '\u00b1', // '±'
+  'h': '\u2424', // '\u2424' (NL)
+  'i': '\u000b', // '\v'
+  'j': '\u2518', // '┘'
+  'k': '\u2510', // '┐'
+  'l': '\u250c', // '┌'
+  'm': '\u2514', // '└'
+  'n': '\u253c', // '┼'
+  'o': '\u23ba', // '⎺'
+  'p': '\u23bb', // '⎻'
+  'q': '\u2500', // '─'
+  'r': '\u23bc', // '⎼'
+  's': '\u23bd', // '⎽'
+  't': '\u251c', // '├'
+  'u': '\u2524', // '┤'
+  'v': '\u2534', // '┴'
+  'w': '\u252c', // '┬'
+  'x': '\u2502', // '│'
+  'y': '\u2264', // '≤'
+  'z': '\u2265', // '≥'
+  '{': '\u03c0', // 'π'
+  '|': '\u2260', // '≠'
+  '}': '\u00a3', // '£'
+  '~': '\u00b7'  // '·'
+};
+
+Terminal.charsets.UK = null; // (A
+Terminal.charsets.US = null; // (B (USASCII)
+Terminal.charsets.Dutch = null; // (4
+Terminal.charsets.Finnish = null; // (C or (5
+Terminal.charsets.French = null; // (R
+Terminal.charsets.FrenchCanadian = null; // (Q
+Terminal.charsets.German = null; // (K
+Terminal.charsets.Italian = null; // (Y
+Terminal.charsets.NorwegianDanish = null; // (E or (6
+Terminal.charsets.Spanish = null; // (Z
+Terminal.charsets.Swedish = null; // (H or (7
+Terminal.charsets.Swiss = null; // (=
+Terminal.charsets.ISOLatin = null; // /A
+
+/**
+ * Helpers
+ */
+
+function contains(el, arr) {
+  for (var i = 0; i < arr.length; i += 1) {
+    if (el === arr[i]) {
+      return true;
+    }
+  }
+  return false;
+}
+
+function on(el, type, handler, capture) {
+  if (!Array.isArray(el)) {
+    el = [el];
+  }
+  el.forEach(function (element) {
+    element.addEventListener(type, handler, capture || false);
+  });
+}
+
+function off(el, type, handler, capture) {
+  el.removeEventListener(type, handler, capture || false);
+}
+
+function cancel(ev, force) {
+  if (!this.cancelEvents && !force) {
+    return;
+  }
+  ev.preventDefault();
+  ev.stopPropagation();
+  return false;
+}
+
+function inherits(child, parent) {
+  function f() {
+    this.constructor = child;
+  }
+  f.prototype = parent.prototype;
+  child.prototype = new f;
+}
+
+// if bold is broken, we can't
+// use it in the terminal.
+function isBoldBroken(document) {
+  var body = document.getElementsByTagName('body')[0];
+  var el = document.createElement('span');
+  el.innerHTML = 'hello world';
+  body.appendChild(el);
+  var w1 = el.scrollWidth;
+  el.style.fontWeight = 'bold';
+  var w2 = el.scrollWidth;
+  body.removeChild(el);
+  return w1 !== w2;
+}
+
+function indexOf(obj, el) {
+  var i = obj.length;
+  while (i--) {
+    if (obj[i] === el) return i;
+  }
+  return -1;
+}
+
+function isThirdLevelShift(term, ev) {
+  var thirdLevelKey =
+      (term.isMac && ev.altKey && !ev.ctrlKey && !ev.metaKey) ||
+      (term.isMSWindows && ev.altKey && ev.ctrlKey && !ev.metaKey);
+
+  if (ev.type == 'keypress') {
+    return thirdLevelKey;
+  }
+
+  // Don't invoke for arrows, pageDown, home, backspace, etc. (on non-keypress events)
+  return thirdLevelKey && (!ev.keyCode || ev.keyCode > 47);
+}
+
+function matchColor(r1, g1, b1) {
+  var hash = (r1 << 16) | (g1 << 8) | b1;
+
+  if (matchColor._cache[hash] != null) {
+    return matchColor._cache[hash];
+  }
+
+  var ldiff = Infinity
+  , li = -1
+  , i = 0
+  , c
+  , r2
+  , g2
+  , b2
+  , diff;
+
+  for (; i < Terminal.vcolors.length; i++) {
+    c = Terminal.vcolors[i];
+    r2 = c[0];
+    g2 = c[1];
+    b2 = c[2];
+
+    diff = matchColor.distance(r1, g1, b1, r2, g2, b2);
+
+    if (diff === 0) {
+      li = i;
+      break;
+    }
+
+    if (diff < ldiff) {
+      ldiff = diff;
+      li = i;
+    }
+  }
+
+  return matchColor._cache[hash] = li;
+}
+
+matchColor._cache = {};
+
+// http://stackoverflow.com/questions/1633828
+matchColor.distance = function(r1, g1, b1, r2, g2, b2) {
+  return Math.pow(30 * (r1 - r2), 2)
+    + Math.pow(59 * (g1 - g2), 2)
+    + Math.pow(11 * (b1 - b2), 2);
+};
+
+function each(obj, iter, con) {
+  if (obj.forEach) return obj.forEach(iter, con);
+  for (var i = 0; i < obj.length; i++) {
+    iter.call(con, obj[i], i, obj);
+  }
+}
+
+function keys(obj) {
+  if (Object.keys) return Object.keys(obj);
+  var key, keys = [];
+  for (key in obj) {
+    if (Object.prototype.hasOwnProperty.call(obj, key)) {
+      keys.push(key);
+    }
+  }
+  return keys;
+}
+
+var wcwidth = (function(opts) {
+  // extracted from https://www.cl.cam.ac.uk/%7Emgk25/ucs/wcwidth.c
+  // combining characters
+  var COMBINING = [
+    [0x0300, 0x036F], [0x0483, 0x0486], [0x0488, 0x0489],
+    [0x0591, 0x05BD], [0x05BF, 0x05BF], [0x05C1, 0x05C2],
+    [0x05C4, 0x05C5], [0x05C7, 0x05C7], [0x0600, 0x0603],
+    [0x0610, 0x0615], [0x064B, 0x065E], [0x0670, 0x0670],
+    [0x06D6, 0x06E4], [0x06E7, 0x06E8], [0x06EA, 0x06ED],
+    [0x070F, 0x070F], [0x0711, 0x0711], [0x0730, 0x074A],
+    [0x07A6, 0x07B0], [0x07EB, 0x07F3], [0x0901, 0x0902],
+    [0x093C, 0x093C], [0x0941, 0x0948], [0x094D, 0x094D],
+    [0x0951, 0x0954], [0x0962, 0x0963], [0x0981, 0x0981],
+    [0x09BC, 0x09BC], [0x09C1, 0x09C4], [0x09CD, 0x09CD],
+    [0x09E2, 0x09E3], [0x0A01, 0x0A02], [0x0A3C, 0x0A3C],
+    [0x0A41, 0x0A42], [0x0A47, 0x0A48], [0x0A4B, 0x0A4D],
+    [0x0A70, 0x0A71], [0x0A81, 0x0A82], [0x0ABC, 0x0ABC],
+    [0x0AC1, 0x0AC5], [0x0AC7, 0x0AC8], [0x0ACD, 0x0ACD],
+    [0x0AE2, 0x0AE3], [0x0B01, 0x0B01], [0x0B3C, 0x0B3C],
+    [0x0B3F, 0x0B3F], [0x0B41, 0x0B43], [0x0B4D, 0x0B4D],
+    [0x0B56, 0x0B56], [0x0B82, 0x0B82], [0x0BC0, 0x0BC0],
+    [0x0BCD, 0x0BCD], [0x0C3E, 0x0C40], [0x0C46, 0x0C48],
+    [0x0C4A, 0x0C4D], [0x0C55, 0x0C56], [0x0CBC, 0x0CBC],
+    [0x0CBF, 0x0CBF], [0x0CC6, 0x0CC6], [0x0CCC, 0x0CCD],
+    [0x0CE2, 0x0CE3], [0x0D41, 0x0D43], [0x0D4D, 0x0D4D],
+    [0x0DCA, 0x0DCA], [0x0DD2, 0x0DD4], [0x0DD6, 0x0DD6],
+    [0x0E31, 0x0E31], [0x0E34, 0x0E3A], [0x0E47, 0x0E4E],
+    [0x0EB1, 0x0EB1], [0x0EB4, 0x0EB9], [0x0EBB, 0x0EBC],
+    [0x0EC8, 0x0ECD], [0x0F18, 0x0F19], [0x0F35, 0x0F35],
+    [0x0F37, 0x0F37], [0x0F39, 0x0F39], [0x0F71, 0x0F7E],
+    [0x0F80, 0x0F84], [0x0F86, 0x0F87], [0x0F90, 0x0F97],
+    [0x0F99, 0x0FBC], [0x0FC6, 0x0FC6], [0x102D, 0x1030],
+    [0x1032, 0x1032], [0x1036, 0x1037], [0x1039, 0x1039],
+    [0x1058, 0x1059], [0x1160, 0x11FF], [0x135F, 0x135F],
+    [0x1712, 0x1714], [0x1732, 0x1734], [0x1752, 0x1753],
+    [0x1772, 0x1773], [0x17B4, 0x17B5], [0x17B7, 0x17BD],
+    [0x17C6, 0x17C6], [0x17C9, 0x17D3], [0x17DD, 0x17DD],
+    [0x180B, 0x180D], [0x18A9, 0x18A9], [0x1920, 0x1922],
+    [0x1927, 0x1928], [0x1932, 0x1932], [0x1939, 0x193B],
+    [0x1A17, 0x1A18], [0x1B00, 0x1B03], [0x1B34, 0x1B34],
+    [0x1B36, 0x1B3A], [0x1B3C, 0x1B3C], [0x1B42, 0x1B42],
+    [0x1B6B, 0x1B73], [0x1DC0, 0x1DCA], [0x1DFE, 0x1DFF],
+    [0x200B, 0x200F], [0x202A, 0x202E], [0x2060, 0x2063],
+    [0x206A, 0x206F], [0x20D0, 0x20EF], [0x302A, 0x302F],
+    [0x3099, 0x309A], [0xA806, 0xA806], [0xA80B, 0xA80B],
+    [0xA825, 0xA826], [0xFB1E, 0xFB1E], [0xFE00, 0xFE0F],
+    [0xFE20, 0xFE23], [0xFEFF, 0xFEFF], [0xFFF9, 0xFFFB],
+    [0x10A01, 0x10A03], [0x10A05, 0x10A06], [0x10A0C, 0x10A0F],
+    [0x10A38, 0x10A3A], [0x10A3F, 0x10A3F], [0x1D167, 0x1D169],
+    [0x1D173, 0x1D182], [0x1D185, 0x1D18B], [0x1D1AA, 0x1D1AD],
+    [0x1D242, 0x1D244], [0xE0001, 0xE0001], [0xE0020, 0xE007F],
+    [0xE0100, 0xE01EF]
+  ];
+  // binary search
+  function bisearch(ucs) {
+    var min = 0;
+    var max = COMBINING.length - 1;
+    var mid;
+    if (ucs < COMBINING[0][0] || ucs > COMBINING[max][1])
+      return false;
+    while (max >= min) {
+      mid = Math.floor((min + max) / 2);
+      if (ucs > COMBINING[mid][1])
+        min = mid + 1;
+      else if (ucs < COMBINING[mid][0])
+        max = mid - 1;
+      else
+        return true;
+    }
+    return false;
+  }
+  function wcwidth(ucs) {
+    // test for 8-bit control characters
+    if (ucs === 0)
+      return opts.nul;
+    if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))
+      return opts.control;
+    // binary search in table of non-spacing characters
+    if (bisearch(ucs))
+      return 0;
+    // if we arrive here, ucs is not a combining or C0/C1 control character
+    return 1 +
+      (
+      ucs >= 0x1100 &&
+      (
+        ucs <= 0x115f ||                // Hangul Jamo init. consonants
+        ucs == 0x2329 ||
+        ucs == 0x232a ||
+        (ucs >= 0x2e80 && ucs <= 0xa4cf && ucs != 0x303f) ||  // CJK..Yi
+        (ucs >= 0xac00 && ucs <= 0xd7a3) ||    // Hangul Syllables
+        (ucs >= 0xf900 && ucs <= 0xfaff) ||    // CJK Compat Ideographs
+        (ucs >= 0xfe10 && ucs <= 0xfe19) ||    // Vertical forms
+        (ucs >= 0xfe30 && ucs <= 0xfe6f) ||    // CJK Compat Forms
+        (ucs >= 0xff00 && ucs <= 0xff60) ||    // Fullwidth Forms
+        (ucs >= 0xffe0 && ucs <= 0xffe6) ||
+        (ucs >= 0x20000 && ucs <= 0x2fffd) ||
+        (ucs >= 0x30000 && ucs <= 0x3fffd)
+      )
+    );
+  }
+  return wcwidth;
+})({nul: 0, control: 0});  // configurable options
+
+/**
+ * Expose
+ */
+
+Terminal.EventEmitter = EventEmitter;
+Terminal.CompositionHelper = CompositionHelper;
+Terminal.Viewport = Viewport;
+Terminal.inherits = inherits;
+
+/**
+ * Adds an event listener to the terminal.
+ *
+ * @param {string} event The name of the event. TODO: Document all event types
+ * @param {function} callback The function to call when the event is triggered.
+ */
+Terminal.on = on;
+Terminal.off = off;
+Terminal.cancel = cancel;
+
+module.exports = Terminal;
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineModel.js b/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineModel.js
index 4755da5..0973bec 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineModel.js
@@ -635,9 +635,10 @@
      */
     _processBrowserEvents: function(tracingModel)
     {
-        var browserMain = tracingModel.threadByName("Browser", "CrBrowserMain");
+        var browserMain = WebInspector.TracingModel.browserMainThread(tracingModel);
         if (!browserMain)
             return;
+
         // Disregard regular events, we don't need them yet, but still process to get proper metadata.
         browserMain.events().forEach(this._processBrowserEvent, this);
         /** @type {!Map<!WebInspector.TimelineModel.AsyncEventGroup, !Array<!WebInspector.TracingModel.AsyncEvent>>} */
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/Widget.js b/third_party/WebKit/Source/devtools/front_end/ui/Widget.js
index bc4af9ba..e01fd5b4 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/Widget.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/Widget.js
@@ -153,6 +153,14 @@
         this._callOnVisibleChildren(this._processWasShown);
     },
 
+    _processWasDetachedFromHierarchy: function()
+    {
+        this._notify(this.wasDetachedFromHierarchy);
+        var copy = this._children.slice();
+        for (var widget of copy)
+            widget._processWasDetachedFromHierarchy();
+    },
+
     _processWillHide: function()
     {
         if (this._inNotification())
@@ -200,6 +208,10 @@
     {
     },
 
+    wasDetachedFromHierarchy: function()
+    {
+    },
+
     onResize: function()
     {
     },
@@ -338,6 +350,7 @@
             this._parentWidget.childWasDetached(this);
             var parent = this._parentWidget;
             this._parentWidget = null;
+            this._processWasDetachedFromHierarchy();
         } else {
             WebInspector.Widget.__assert(this._isRoot, "Removing non-root widget from DOM");
         }
diff --git a/third_party/WebKit/Source/devtools/scripts/check_injected_script_source.py b/third_party/WebKit/Source/devtools/scripts/check_injected_script_source.py
deleted file mode 100755
index 9a220bc..0000000
--- a/third_party/WebKit/Source/devtools/scripts/check_injected_script_source.py
+++ /dev/null
@@ -1,84 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2014 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import re
-import sys
-import os
-
-
-def validate_injected_script(fileName):
-    f = open(fileName, "r")
-    lines = f.readlines()
-    f.close()
-
-    proto_functions = "|".join([
-        # Array.prototype.*
-        "concat", "every", "filter", "forEach", "indexOf", "join", "lastIndexOf", "map", "pop",
-        "push", "reduce", "reduceRight", "reverse", "shift", "slice", "some", "sort", "splice", "toLocaleString", "toString", "unshift",
-        # Function.prototype.*
-        "apply", "bind", "call", "isGenerator", "toSource",
-        # Object.prototype.*
-        "toString",
-    ])
-
-    global_functions = "|".join([
-        "eval", "uneval", "isFinite", "isNaN", "parseFloat", "parseInt", "decodeURI", "decodeURIComponent",
-        "encodeURI", "encodeURIComponent", "escape", "unescape", "Map", "Set"
-    ])
-
-    # Black list:
-    # - instanceof, since e.g. "obj instanceof Error" may throw if Error is overridden and is not a function
-    # - Object.prototype.toString()
-    # - Array.prototype.*
-    # - Function.prototype.*
-    # - Math.*
-    # - Global functions
-    black_list_call_regex = re.compile(r"\sinstanceof\s+\w*|\bMath\.\w+\(|(?<!InjectedScriptHost)\.(" + proto_functions + r")\(|[^\.]\b(" + global_functions + r")\(")
-
-    errors_found = False
-    for i, line in enumerate(lines):
-        if line.find("suppressBlacklist") != -1:
-            continue
-        for match in re.finditer(black_list_call_regex, line):
-            errors_found = True
-            print "ERROR: Black listed expression in %s at line %02d column %02d: %s" % (os.path.basename(fileName), i + 1, match.start(), match.group(0))
-
-    if not errors_found:
-        print "OK"
-
-
-def main(argv):
-    if len(argv) < 2:
-        print('ERROR: Usage: %s path/to/InjectedScriptSource.js' % argv[0])
-        return 1
-
-    validate_injected_script(argv[1])
-
-if __name__ == '__main__':
-    sys.exit(main(sys.argv))
diff --git a/third_party/WebKit/Source/devtools/scripts/compile_frontend.py b/third_party/WebKit/Source/devtools/scripts/compile_frontend.py
index 03e91fcb..c41921d 100755
--- a/third_party/WebKit/Source/devtools/scripts/compile_frontend.py
+++ b/third_party/WebKit/Source/devtools/scripts/compile_frontend.py
@@ -76,10 +76,6 @@
 devtools_frontend_path = path.join(devtools_path, 'front_end')
 global_externs_file = to_platform_path(path.join(devtools_frontend_path, 'externs.js'))
 protocol_externs_file = path.join(devtools_frontend_path, 'protocol_externs.js')
-injected_script_source_name = path.join(v8_inspector_path, 'injected-script-source.js')
-injected_script_externs_file = path.join(v8_inspector_path, 'injected_script_externs.js')
-debugger_script_source_name = path.join(v8_inspector_path, 'debugger-script.js')
-debugger_script_externs_file = path.join(v8_inspector_path, 'debugger_script_externs.js')
 
 jsmodule_name_prefix = 'jsmodule_'
 runtime_module_name = '_runtime'
@@ -136,8 +132,8 @@
     return re.search(error_warning_regex, output) != None
 
 
-def verify_jsdoc_extra(additional_files):
-    files = [to_platform_path(file) for file in descriptors.all_compiled_files() + additional_files]
+def verify_jsdoc_extra():
+    files = [to_platform_path(compiled_file) for compiled_file in descriptors.all_compiled_files()]
     file_list = tempfile.NamedTemporaryFile(mode='wt', delete=False)
     try:
         file_list.write('\n'.join(files))
@@ -146,9 +142,9 @@
     return popen(java_exec + ['-jar', jsdoc_validator_jar, '--files-list-name', to_platform_path_exact(file_list.name)]), file_list
 
 
-def verify_jsdoc(additional_files):
+def verify_jsdoc():
     def file_list():
-        return descriptors.all_compiled_files() + additional_files
+        return descriptors.all_compiled_files()
 
     errors_found = False
     for full_file_name in file_list():
@@ -367,54 +363,11 @@
 
 modular_compiler_proc = popen(java_exec + ['-jar', closure_runner_jar, '--compiler-args-file', to_platform_path_exact(compiler_args_file.name)])
 
-def unclosure_injected_script(sourceFileName, outFileName):
-
-    source = read_file(sourceFileName)
-
-    def replace_function(matchobj):
-        return re.sub(r'@param', 'param', matchobj.group(1) or '') + '\n//' + matchobj.group(2)
-
-    # Comment out the closure function and its jsdocs
-    source = re.sub(r'(/\*\*(?:[\s\n]*\*\s*@param[^\n]+\n)+\s*\*/\s*)?\n(\(function)', replace_function, source, count=1)
-
-    # Comment out its return statement
-    source = re.sub(r'\n(\s*return\s+[^;]+;\s*\n\}\)\s*)$', '\n/*\\1*/', source)
-
-    # Replace the "var Object" override with a "self.Object" one
-    source = re.sub(r'\nvar Object =', '\nself.Object =', source, count=1)
-
-    write_file(outFileName, source)
-
-injectedScriptSourceTmpFile = to_platform_path(path.join(inspector_path, 'InjectedScriptSourceTmp.js'))
-
-unclosure_injected_script(injected_script_source_name, injectedScriptSourceTmpFile)
-
-print 'Compiling InjectedScriptSource.js...'
-
 spawned_compiler_command = java_exec + [
     '-jar',
     closure_compiler_jar
 ] + common_closure_args
 
-command = spawned_compiler_command + [
-    '--externs', to_platform_path_exact(injected_script_externs_file),
-    '--externs', to_platform_path_exact(protocol_externs_file),
-    '--module', jsmodule_name_prefix + 'injected_script' + ':1',
-    '--js', to_platform_path(injectedScriptSourceTmpFile)
-]
-
-injectedScriptCompileProc = popen(command)
-
-print 'Compiling DebuggerScript.js...'
-
-command = spawned_compiler_command + [
-    '--externs', to_platform_path_exact(debugger_script_externs_file),
-    '--module', jsmodule_name_prefix + 'debugger_script' + ':1',
-    '--js', to_platform_path(debugger_script_source_name)
-]
-
-debuggerScriptCompileProc = popen(command)
-
 print 'Compiling devtools.js...'
 
 command = spawned_compiler_command + [
@@ -427,13 +380,8 @@
 devtoolsJSCompileProc = popen(command)
 
 print 'Verifying JSDoc comments...'
-additional_jsdoc_check_files = [injectedScriptSourceTmpFile]
-errors_found |= verify_jsdoc(additional_jsdoc_check_files)
-jsdocValidatorProc, jsdocValidatorFileList = verify_jsdoc_extra(additional_jsdoc_check_files)
-
-print 'Validating InjectedScriptSource.js...'
-injectedscript_check_script_path = path.join(scripts_path, "check_injected_script_source.py")
-validateInjectedScriptProc = popen([sys.executable, injectedscript_check_script_path, injected_script_source_name])
+errors_found |= verify_jsdoc()
+(jsdocValidatorProc, jsdocValidatorFileList) = verify_jsdoc_extra()
 
 print
 
@@ -501,26 +449,13 @@
     print 'Total Closure errors: %d%s' % (error_count, os.linesep)
     errors_found = True
 
-(injectedScriptCompileOut, _) = injectedScriptCompileProc.communicate()
-print 'InjectedScriptSource.js compilation output:%s' % os.linesep, injectedScriptCompileOut
-errors_found |= hasErrors(injectedScriptCompileOut)
-
-(debuggerScriptCompilerOut, _) = debuggerScriptCompileProc.communicate()
-print 'DebuggerScript.js compilation output:%s' % os.linesep, debuggerScriptCompilerOut
-errors_found |= hasErrors(debuggerScriptCompilerOut)
-
 (devtoolsJSCompileOut, _) = devtoolsJSCompileProc.communicate()
 print 'devtools.js compilation output:%s' % os.linesep, devtoolsJSCompileOut
 errors_found |= hasErrors(devtoolsJSCompileOut)
 
-(validateInjectedScriptOut, _) = validateInjectedScriptProc.communicate()
-print 'Validate InjectedScriptSource.js output:%s' % os.linesep, (validateInjectedScriptOut if validateInjectedScriptOut else '<empty>')
-errors_found |= hasErrors(validateInjectedScriptOut)
-
 if errors_found:
     print 'ERRORS DETECTED'
 
-os.remove(injectedScriptSourceTmpFile)
 os.remove(compiler_args_file.name)
 os.remove(protocol_externs_file)
 shutil.rmtree(modules_dir, True)
diff --git a/third_party/WebKit/Source/modules/accessibility/AXInlineTextBox.cpp b/third_party/WebKit/Source/modules/accessibility/AXInlineTextBox.cpp
index 9252393..a2cf0fc7 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXInlineTextBox.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXInlineTextBox.cpp
@@ -66,11 +66,17 @@
     outBoundsInContainer = FloatRect();
     outContainerTransform.setIdentity();
 
-    if (!m_inlineTextBox)
+    if (!m_inlineTextBox || !parentObject() || !parentObject()->getLayoutObject())
         return;
 
     *outContainer = parentObject();
     outBoundsInContainer = FloatRect(m_inlineTextBox->localBounds());
+
+    // Subtract the local bounding box of the parent because they're
+    // both in the same coordinate system.
+    LayoutObject* parentLayoutObject = parentObject()->getLayoutObject();
+    FloatRect parentBoundingBox = parentLayoutObject->localBoundingBoxRectForAccessibility();
+    outBoundsInContainer.moveBy(-parentBoundingBox.location());
 }
 
 bool AXInlineTextBox::computeAccessibilityIsIgnored(IgnoredReasons* ignoredReasons) const
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothUUID.cpp b/third_party/WebKit/Source/modules/bluetooth/BluetoothUUID.cpp
index 77b1ac5..7a8a3ac 100644
--- a/third_party/WebKit/Source/modules/bluetooth/BluetoothUUID.cpp
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothUUID.cpp
@@ -327,8 +327,8 @@
             " e.g. 'gatt.characteristic_presentation_format'.");
         break;
     }
-    // Otherwise, throw a SyntaxError.
-    exceptionState.throwDOMException(SyntaxError, errorMessage.toString());
+    // Otherwise, throw a TypeError.
+    exceptionState.throwDOMException(V8TypeError, errorMessage.toString());
     return String();
 }
 
diff --git a/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.cpp b/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.cpp
index e0db5591..e1869511 100644
--- a/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.cpp
+++ b/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.cpp
@@ -964,7 +964,6 @@
         trackDrawCall(DrawBitmapImage, nullptr, dstRect.width(), dstRect.height());
     }
 
-
     int initialSaveCount = c->getSaveCount();
     SkPaint imagePaint = *paint;
 
@@ -1076,6 +1075,26 @@
 
     validateStateStack();
 
+    // Heuristic for disabling acceleration based on anticipated texture upload overhead
+    // See comments in ExpensiveCanvasHeuristicParameters.h for explanation.
+    ImageBuffer* buffer = imageBuffer();
+    if (buffer && buffer->isAccelerated() && !imageSource->isAccelerated()) {
+        float srcArea = srcRect.width() * srcRect.height();
+        if (srcArea > ExpensiveCanvasHeuristicParameters::DrawImageTextureUploadHardSizeLimit) {
+            buffer->disableAcceleration();
+        } else if (srcArea > ExpensiveCanvasHeuristicParameters::DrawImageTextureUploadSoftSizeLimit) {
+            SkRect bounds = dstRect;
+            SkMatrix ctm = drawingCanvas()->getTotalMatrix();
+            ctm.mapRect(&bounds);
+            float dstArea = dstRect.width() * dstRect.height();
+            if (srcArea > dstArea * ExpensiveCanvasHeuristicParameters::DrawImageTextureUploadSoftSizeLimitScaleThreshold) {
+                buffer->disableAcceleration();
+            }
+        }
+    }
+
+    validateStateStack();
+
     // TODO(xidachen): After collecting some data, come back and prune off
     // the ones that is not needed.
     Optional<ScopedUsHistogramTimer> timer;
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DState.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DState.cpp
index e0c9c60..b5455be0 100644
--- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DState.cpp
+++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DState.cpp
@@ -11,6 +11,7 @@
 #include "core/html/HTMLCanvasElement.h"
 #include "core/paint/FilterEffectBuilder.h"
 #include "core/style/ComputedStyle.h"
+#include "core/style/FilterOperation.h"
 #include "core/svg/SVGFilterElement.h"
 #include "modules/canvas2d/CanvasGradient.h"
 #include "modules/canvas2d/CanvasPattern.h"
@@ -18,7 +19,6 @@
 #include "modules/canvas2d/CanvasStyle.h"
 #include "platform/graphics/DrawLooperBuilder.h"
 #include "platform/graphics/filters/FilterEffect.h"
-#include "platform/graphics/filters/FilterOperation.h"
 #include "platform/graphics/filters/SkiaImageFilterBuilder.h"
 #include "platform/graphics/skia/SkiaUtils.h"
 #include "third_party/skia/include/effects/SkDashPathEffect.h"
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp
index 3d3f073..245429d 100644
--- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp
+++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp
@@ -47,6 +47,7 @@
     bool wouldTaintOrigin(SecurityOrigin* destinationSecurityOrigin) const override { return false; }
     FloatSize elementSize(const FloatSize&) const override { return FloatSize(m_size); }
     bool isOpaque() const override { return m_isOpaque; }
+    bool isAccelerated() const { return false; }
     int sourceWidth() override { return m_size.width(); }
     int sourceHeight() override { return m_size.height(); }
 
@@ -799,6 +800,56 @@
     RuntimeEnabledFeatures::setCanvas2dFixedRenderingModeEnabled(savedFixedRenderingMode);
 }
 
+TEST_F(CanvasRenderingContext2DTest, TextureUploadHeuristics)
+{
+    bool savedFixedRenderingMode = RuntimeEnabledFeatures::canvas2dFixedRenderingModeEnabled();
+    RuntimeEnabledFeatures::setCanvas2dFixedRenderingModeEnabled(false);
+
+    enum TestVariants {
+        LargeTextureDisablesAcceleration = 0,
+        SmallTextureDoesNotDisableAcceleration = 1,
+
+        TestVariantCount = 2,
+    };
+
+    for (int testVariant = 0; testVariant < TestVariantCount; testVariant++) {
+        int delta = testVariant == LargeTextureDisablesAcceleration ? 1 : -1;
+        int srcSize = std::sqrt(static_cast<float>(ExpensiveCanvasHeuristicParameters::DrawImageTextureUploadSoftSizeLimit)) + delta;
+        int dstSize = srcSize / std::sqrt(static_cast<float>(ExpensiveCanvasHeuristicParameters::DrawImageTextureUploadSoftSizeLimitScaleThreshold)) - delta;
+
+        createContext(NonOpaque);
+        FakeGLES2Interface gl;
+        std::unique_ptr<FakeWebGraphicsContext3DProvider> contextProvider(new FakeWebGraphicsContext3DProvider(&gl));
+        IntSize size(dstSize, dstSize);
+        RefPtr<Canvas2DLayerBridge> bridge = makeBridge(std::move(contextProvider), size, Canvas2DLayerBridge::EnableAcceleration);
+        std::unique_ptr<Canvas2DImageBufferSurface> surface(new Canvas2DImageBufferSurface(bridge, size));
+        canvasElement().createImageBufferUsingSurfaceForTesting(std::move(surface));
+
+        EXPECT_TRUE(canvasElement().buffer()->isAccelerated());
+        EXPECT_EQ(1u, getGlobalAcceleratedImageBufferCount());
+        // 4 bytes per pixel * 2 buffers = 8
+        EXPECT_EQ(8*dstSize*dstSize, getGlobalGPUMemoryUsage());
+        sk_sp<SkSurface> skSurface = SkSurface::MakeRasterN32Premul(srcSize, srcSize);
+        RefPtr<StaticBitmapImage> bigBitmap = StaticBitmapImage::create(skSurface->makeImageSnapshot());
+        ImageBitmap* bigImage = ImageBitmap::create(std::move(bigBitmap));
+        NonThrowableExceptionState exceptionState;
+        context2d()->drawImage(nullptr, bigImage, 0, 0, srcSize, srcSize, 0, 0, dstSize, dstSize, exceptionState);
+        EXPECT_FALSE(exceptionState.hadException());
+
+        if (testVariant == LargeTextureDisablesAcceleration) {
+            EXPECT_FALSE(canvasElement().buffer()->isAccelerated());
+            EXPECT_EQ(0u, getGlobalAcceleratedImageBufferCount());
+            EXPECT_EQ(0, getGlobalGPUMemoryUsage());
+        } else {
+            EXPECT_TRUE(canvasElement().buffer()->isAccelerated());
+            EXPECT_EQ(1u, getGlobalAcceleratedImageBufferCount());
+            EXPECT_EQ(8*dstSize*dstSize, getGlobalGPUMemoryUsage());
+        }
+    }
+    // Restore global state to prevent side-effects on other tests
+    RuntimeEnabledFeatures::setCanvas2dFixedRenderingModeEnabled(savedFixedRenderingMode);
+}
+
 TEST_F(CanvasRenderingContext2DTest, IsAccelerationOptimalForCanvasContentHeuristic)
 {
     createContext(NonOpaque);
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DUsageTrackingTest.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DUsageTrackingTest.cpp
index a2db8c1..d463fc1 100644
--- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DUsageTrackingTest.cpp
+++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DUsageTrackingTest.cpp
@@ -43,6 +43,7 @@
     bool wouldTaintOrigin(SecurityOrigin* destinationSecurityOrigin) const override { return false; }
     FloatSize elementSize(const FloatSize&) const override { return FloatSize(m_size); }
     bool isOpaque() const override { return m_isOpaque; }
+    bool isAccelerated() const override { return false; }
     int sourceWidth() override { return m_size.width(); }
     int sourceHeight() override { return m_size.height(); }
 
diff --git a/third_party/WebKit/Source/modules/installedapp/NavigatorInstalledApp.cpp b/third_party/WebKit/Source/modules/installedapp/NavigatorInstalledApp.cpp
index 6a8d01d..09a2f942 100644
--- a/third_party/WebKit/Source/modules/installedapp/NavigatorInstalledApp.cpp
+++ b/third_party/WebKit/Source/modules/installedapp/NavigatorInstalledApp.cpp
@@ -71,7 +71,7 @@
     ScriptPromise promise = resolver->promise();
 
     // Don't crash when called and unattached to document.
-    Document* document = m_frame ? m_frame->document() : 0;
+    Document* document = frame() ? frame()->document() : 0;
 
     if (!document || !controller()) {
         DOMException* exception = DOMException::create(InvalidStateError, "The object is no longer associated to a document.");
diff --git a/third_party/WebKit/Source/modules/mediastream/ConstrainBooleanParameters.idl b/third_party/WebKit/Source/modules/mediastream/ConstrainBooleanParameters.idl
index c8e9677a..55aafb0 100644
--- a/third_party/WebKit/Source/modules/mediastream/ConstrainBooleanParameters.idl
+++ b/third_party/WebKit/Source/modules/mediastream/ConstrainBooleanParameters.idl
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://w3c.github.io/mediacapture-main/getusermedia.html#idl-def-ConstrainBooleanParameters
+// https://w3c.github.io/mediacapture-main/#idl-def-constrainbooleanparameters
 
 dictionary ConstrainBooleanParameters {
     boolean exact;
diff --git a/third_party/WebKit/Source/modules/mediastream/ConstrainDOMStringParameters.idl b/third_party/WebKit/Source/modules/mediastream/ConstrainDOMStringParameters.idl
index 35e4a8fe..a27c88bb 100644
--- a/third_party/WebKit/Source/modules/mediastream/ConstrainDOMStringParameters.idl
+++ b/third_party/WebKit/Source/modules/mediastream/ConstrainDOMStringParameters.idl
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://w3c.github.io/mediacapture-main/getusermedia.html#idl-def-ConstrainLongRange
+// https://w3c.github.io/mediacapture-main/#idl-def-constraindomstringparameters
 
 dictionary ConstrainDOMStringParameters {
     (DOMString or sequence<DOMString>) exact;
diff --git a/third_party/WebKit/Source/modules/mediastream/ConstrainDoubleRange.idl b/third_party/WebKit/Source/modules/mediastream/ConstrainDoubleRange.idl
index 15e92f2..aefc25a 100644
--- a/third_party/WebKit/Source/modules/mediastream/ConstrainDoubleRange.idl
+++ b/third_party/WebKit/Source/modules/mediastream/ConstrainDoubleRange.idl
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://w3c.github.io/mediacapture-main/getusermedia.html#idl-def-ConstrainDoubleRange
+// https://w3c.github.io/mediacapture-main/#idl-def-constraindoublerange
 
 dictionary ConstrainDoubleRange : DoubleRange {
     double exact;
diff --git a/third_party/WebKit/Source/modules/mediastream/ConstrainLongRange.idl b/third_party/WebKit/Source/modules/mediastream/ConstrainLongRange.idl
index a8947341..d3ece44 100644
--- a/third_party/WebKit/Source/modules/mediastream/ConstrainLongRange.idl
+++ b/third_party/WebKit/Source/modules/mediastream/ConstrainLongRange.idl
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://w3c.github.io/mediacapture-main/getusermedia.html#idl-def-ConstrainLongRange
+// https://w3c.github.io/mediacapture-main/#idl-def-constrainlongrange
 
 dictionary ConstrainLongRange : LongRange {
     long exact;
diff --git a/third_party/WebKit/Source/modules/mediastream/DoubleRange.idl b/third_party/WebKit/Source/modules/mediastream/DoubleRange.idl
index 424dfb09..774d3f53 100644
--- a/third_party/WebKit/Source/modules/mediastream/DoubleRange.idl
+++ b/third_party/WebKit/Source/modules/mediastream/DoubleRange.idl
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://w3c.github.io/mediacapture-main/getusermedia.html#idl-def-DoubleRange
+// https://w3c.github.io/mediacapture-main/#idl-def-doublerange
 
 dictionary DoubleRange {
     double max;
diff --git a/third_party/WebKit/Source/modules/mediastream/LongRange.idl b/third_party/WebKit/Source/modules/mediastream/LongRange.idl
index d6dc0a43..d251187 100644
--- a/third_party/WebKit/Source/modules/mediastream/LongRange.idl
+++ b/third_party/WebKit/Source/modules/mediastream/LongRange.idl
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://w3c.github.io/mediacapture-main/getusermedia.html#idl-def-LongRange
+// https://w3c.github.io/mediacapture-main/#idl-def-longrange
 
 dictionary LongRange {
     long max;
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaDevices.idl b/third_party/WebKit/Source/modules/mediastream/MediaDevices.idl
index 1020e06..ce7a925 100644
--- a/third_party/WebKit/Source/modules/mediastream/MediaDevices.idl
+++ b/third_party/WebKit/Source/modules/mediastream/MediaDevices.idl
@@ -3,21 +3,19 @@
 // found in the LICENSE file.
 
 // The spec for MediaDevices is in two parts:
-// http://w3c.github.io/mediacapture-main/#mediadevices
-// http://w3c.github.io/mediacapture-main/#mediadevices-interface-extensions
+// https://w3c.github.io/mediacapture-main/#mediadevices
+// https://w3c.github.io/mediacapture-main/#mediadevices-interface-extensions
 
 [
     ActiveScriptWrappable,
     DependentLifetime,
-    ConstructorCallWith=ExecutionContext
-]
-interface MediaDevices : EventTarget {
+] interface MediaDevices : EventTarget {
+    [RuntimeEnabled=OnDeviceChange] attribute EventHandler ondevicechange;
     [CallWith=ScriptState, MeasureAs=MediaDevicesEnumerateDevices] Promise<sequence<MediaDeviceInfo>> enumerateDevices();
     [RuntimeEnabled=MediaConstraints] MediaTrackSupportedConstraints getSupportedConstraints();
     [RuntimeEnabled=GetUserMedia,
      CallWith=ScriptState,
      RaisesException,
      MeasureAs=GetUserMediaPromise
-    ] Promise<MediaStream> getUserMedia(MediaStreamConstraints options);
-    [RuntimeEnabled=OnDeviceChange] attribute EventHandler ondevicechange;
+    ] Promise<MediaStream> getUserMedia(optional MediaStreamConstraints constraints);
 };
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaStreamConstraints.idl b/third_party/WebKit/Source/modules/mediastream/MediaStreamConstraints.idl
index 4ca74de6..a63c6e3 100644
--- a/third_party/WebKit/Source/modules/mediastream/MediaStreamConstraints.idl
+++ b/third_party/WebKit/Source/modules/mediastream/MediaStreamConstraints.idl
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://w3c.github.io/mediacapture-main/getusermedia.html#idl-def-MediaStreamConstraints
+// https://w3c.github.io/mediacapture-main/#idl-def-mediastreamconstraints
 
 dictionary MediaStreamConstraints {
-  (boolean or MediaTrackConstraints) video;
-  (boolean or MediaTrackConstraints) audio;
+    (boolean or MediaTrackConstraints) video = false;
+    (boolean or MediaTrackConstraints) audio = false;
 };
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaStreamEvent.idl b/third_party/WebKit/Source/modules/mediastream/MediaStreamEvent.idl
index f088583..bbf0122 100644
--- a/third_party/WebKit/Source/modules/mediastream/MediaStreamEvent.idl
+++ b/third_party/WebKit/Source/modules/mediastream/MediaStreamEvent.idl
@@ -22,7 +22,8 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-// http://www.w3.org/TR/webrtc/#mediastreamevent
+// An old version of WebRTC defines the MediaStreamEvent interface:
+// https://www.w3.org/TR/2015/WD-webrtc-20150210/#mediastreamevent
 
 [
     Constructor(DOMString type, optional MediaStreamEventInit eventInitDict),
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaStreamEventInit.idl b/third_party/WebKit/Source/modules/mediastream/MediaStreamEventInit.idl
index 51afd96..8c58e16 100644
--- a/third_party/WebKit/Source/modules/mediastream/MediaStreamEventInit.idl
+++ b/third_party/WebKit/Source/modules/mediastream/MediaStreamEventInit.idl
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// http://www.w3.org/TR/webrtc/#mediastreamevent
+// An old version of WebRTC defines the MediaStreamEvent interface:
+// https://www.w3.org/TR/2015/WD-webrtc-20150210/#mediastreamevent
 
 dictionary MediaStreamEventInit : EventInit {
     MediaStream? stream;
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.idl b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.idl
index 6243ec4..134a0a9 100644
--- a/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.idl
+++ b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.idl
@@ -22,6 +22,16 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+// https://w3c.github.io/mediacapture-main/#mediastreamtrack
+
+// TODO(foolip): Remove or standardize MediaStreamTrackState "muted".
+// https://crbug.com/651414
+enum MediaStreamTrackState {
+    "live",
+    "muted",
+    "ended"
+};
+
 [
     ActiveScriptWrappable,
     DependentLifetime,
@@ -31,15 +41,19 @@
     readonly attribute DOMString label;
     attribute boolean enabled;
     readonly attribute boolean muted;
-    [MeasureAs=MediaStreamTrackRemote] readonly attribute boolean remote;
-    readonly attribute DOMString readyState;
-
-    [CallWith=ExecutionContext, RaisesException, DeprecateAs=MediaStreamTrackGetSources] static void getSources(MediaStreamTrackSourcesCallback callback);
-    [ImplementedAs=stopTrack, RaisesException] void stop();
-    [CallWith=ExecutionContext] MediaStreamTrack clone();
-    [RuntimeEnabled=MediaConstraints] MediaTrackConstraints getConstraints();
-    [RuntimeEnabled=MediaGetSettings] MediaTrackSettings getSettings();
     attribute EventHandler onmute;
     attribute EventHandler onunmute;
+    readonly attribute MediaStreamTrackState readyState;
     attribute EventHandler onended;
+
+    [CallWith=ExecutionContext] MediaStreamTrack clone();
+    [ImplementedAs=stopTrack, RaisesException] void stop();
+    [RuntimeEnabled=MediaConstraints] MediaTrackConstraints getConstraints();
+    [RuntimeEnabled=MediaGetSettings] MediaTrackSettings getSettings();
+
+    // Non-standard APIs
+    [MeasureAs=MediaStreamTrackRemote] readonly attribute boolean remote;
+    // TODO(guidou): Remove MediaStreamTrack.getSources().
+    // https://crbug.com/649710
+    [CallWith=ExecutionContext, RaisesException, DeprecateAs=MediaStreamTrackGetSources] static void getSources(MediaStreamTrackSourcesCallback callback);
 };
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaStreamTrackSourcesCallback.idl b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrackSourcesCallback.idl
index f8990fe..9756e09 100644
--- a/third_party/WebKit/Source/modules/mediastream/MediaStreamTrackSourcesCallback.idl
+++ b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrackSourcesCallback.idl
@@ -23,6 +23,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+// TODO(guidou): Remove MediaStreamTrack.getSources(). https://crbug.com/649710
 callback interface MediaStreamTrackSourcesCallback {
     void handleEvent(sequence<SourceInfo> sources);
 };
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaTrackConstraintSet.idl b/third_party/WebKit/Source/modules/mediastream/MediaTrackConstraintSet.idl
index b90448b..e1de4986 100644
--- a/third_party/WebKit/Source/modules/mediastream/MediaTrackConstraintSet.idl
+++ b/third_party/WebKit/Source/modules/mediastream/MediaTrackConstraintSet.idl
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://w3c.github.io/mediacapture-main/getusermedia.html#idl-def-MediaTrackConstraintSet
+// https://w3c.github.io/mediacapture-main/#idl-def-mediatrackconstraintset
 
 typedef (long or ConstrainLongRange) ConstrainLong;
 typedef (double or ConstrainDoubleRange) ConstrainDouble;
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaTrackConstraints.idl b/third_party/WebKit/Source/modules/mediastream/MediaTrackConstraints.idl
index 3aa2601..78de5861 100644
--- a/third_party/WebKit/Source/modules/mediastream/MediaTrackConstraints.idl
+++ b/third_party/WebKit/Source/modules/mediastream/MediaTrackConstraints.idl
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://w3c.github.io/mediacapture-main/getusermedia.html#idl-def-MediaTrackConstraints
+// https://w3c.github.io/mediacapture-main/#idl-def-mediatrackconstraints
 
 dictionary MediaTrackConstraints : MediaTrackConstraintSet {
   sequence<MediaTrackConstraintSet> advanced;
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaTrackSettings.idl b/third_party/WebKit/Source/modules/mediastream/MediaTrackSettings.idl
index 62a6226..88204f7 100644
--- a/third_party/WebKit/Source/modules/mediastream/MediaTrackSettings.idl
+++ b/third_party/WebKit/Source/modules/mediastream/MediaTrackSettings.idl
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://w3c.github.io/mediacapture-main/getusermedia.html#idl-def-MediaTrackSettings
+// https://w3c.github.io/mediacapture-main/#idl-def-mediatracksettings
 
 [RuntimeEnabled=MediaGetSettings]
 dictionary MediaTrackSettings {
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaTrackSupportedConstraints.idl b/third_party/WebKit/Source/modules/mediastream/MediaTrackSupportedConstraints.idl
index 999137e..3d70d7c 100644
--- a/third_party/WebKit/Source/modules/mediastream/MediaTrackSupportedConstraints.idl
+++ b/third_party/WebKit/Source/modules/mediastream/MediaTrackSupportedConstraints.idl
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://w3c.github.io/mediacapture-main/getusermedia.html#idl-def-MediaTrackSupportedConstraints
+// https://w3c.github.io/mediacapture-main/#idl-def-mediatracksupportedconstraints
 
 // NOTE: The names of this dictionary MUST be kept aligned with those in
 // MediaTrackConstraintSet.idl.
diff --git a/third_party/WebKit/Source/modules/mediastream/NavigatorMediaStream.h b/third_party/WebKit/Source/modules/mediastream/NavigatorMediaStream.h
index a155170..d02733b 100644
--- a/third_party/WebKit/Source/modules/mediastream/NavigatorMediaStream.h
+++ b/third_party/WebKit/Source/modules/mediastream/NavigatorMediaStream.h
@@ -39,8 +39,6 @@
     STATIC_ONLY(NavigatorMediaStream);
 public:
     static void getUserMedia(Navigator&, const MediaStreamConstraints&, NavigatorUserMediaSuccessCallback*, NavigatorUserMediaErrorCallback*, ExceptionState&);
-
-    static void getMediaDevices(Navigator&, MediaDeviceInfoCallback*, ExceptionState&);
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/mediastream/NavigatorMediaStream.idl b/third_party/WebKit/Source/modules/mediastream/NavigatorMediaStream.idl
index ec080c374..04230ab 100644
--- a/third_party/WebKit/Source/modules/mediastream/NavigatorMediaStream.idl
+++ b/third_party/WebKit/Source/modules/mediastream/NavigatorMediaStream.idl
@@ -17,17 +17,21 @@
  * Boston, MA 02110-1301, USA.
  */
 
+// https://w3c.github.io/mediacapture-main/#navigatorusermedia-interface-extensions
+
 partial interface Navigator {
     [RaisesException,
-     ImplementedAs=getUserMedia,
-     MeasureAs=GetUserMediaPrefixed
-    ] void webkitGetUserMedia(MediaStreamConstraints options,
-                                              NavigatorUserMediaSuccessCallback successCallback,
-                                              NavigatorUserMediaErrorCallback errorCallback);
-    [RaisesException,
      RuntimeEnabled=GetUserMedia,
      MeasureAs=GetUserMediaLegacy,
-    ] void getUserMedia(MediaStreamConstraints options,
-                                              NavigatorUserMediaSuccessCallback successCallback,
-                                              NavigatorUserMediaErrorCallback errorCallback);
+    ] void getUserMedia(MediaStreamConstraints constraints,
+                        NavigatorUserMediaSuccessCallback successCallback,
+                        NavigatorUserMediaErrorCallback errorCallback);
+
+    // Non-standard
+    [RaisesException,
+     ImplementedAs=getUserMedia,
+     MeasureAs=GetUserMediaPrefixed
+    ] void webkitGetUserMedia(MediaStreamConstraints constraints,
+                              NavigatorUserMediaSuccessCallback successCallback,
+                              NavigatorUserMediaErrorCallback errorCallback);
 };
diff --git a/third_party/WebKit/Source/modules/mediastream/NavigatorUserMedia.idl b/third_party/WebKit/Source/modules/mediastream/NavigatorUserMedia.idl
index 0366e4c..a64fe4a 100644
--- a/third_party/WebKit/Source/modules/mediastream/NavigatorUserMedia.idl
+++ b/third_party/WebKit/Source/modules/mediastream/NavigatorUserMedia.idl
@@ -2,11 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// http://w3c.github.io/mediacapture-main/#navigatorusermedia
+// https://w3c.github.io/mediacapture-main/#navigatorusermedia
 
-[
-    ConstructorCallWith=ExecutionContext,
-]
 partial interface Navigator {
-    readonly attribute MediaDevices mediaDevices;
+    [SameObject] readonly attribute MediaDevices mediaDevices;
 };
diff --git a/third_party/WebKit/Source/modules/mediastream/NavigatorUserMediaError.idl b/third_party/WebKit/Source/modules/mediastream/NavigatorUserMediaError.idl
index 813a93f..3780d1756 100644
--- a/third_party/WebKit/Source/modules/mediastream/NavigatorUserMediaError.idl
+++ b/third_party/WebKit/Source/modules/mediastream/NavigatorUserMediaError.idl
@@ -22,10 +22,17 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+// https://w3c.github.io/mediacapture-main/archives/20150629/getusermedia.html#mediastreamerror
+
+// TODO(foolip): This become OverconstrainedError in
+// https://github.com/w3c/mediacapture-main/pull/194 but but that does not have
+// a |constraintName| member:
+// https://w3c.github.io/mediacapture-main/#overconstrainederror-object
+// See also https://github.com/w3c/mediacapture-main/issues/405
 [
     NoInterfaceObject
 ] interface NavigatorUserMediaError {
     readonly attribute DOMString name;
     readonly attribute DOMString message;
-    readonly attribute DOMString constraintName;
+    [Measure] readonly attribute DOMString constraintName;
 };
diff --git a/third_party/WebKit/Source/modules/mediastream/NavigatorUserMediaErrorCallback.idl b/third_party/WebKit/Source/modules/mediastream/NavigatorUserMediaErrorCallback.idl
index 9f5b27e..112486d 100644
--- a/third_party/WebKit/Source/modules/mediastream/NavigatorUserMediaErrorCallback.idl
+++ b/third_party/WebKit/Source/modules/mediastream/NavigatorUserMediaErrorCallback.idl
@@ -22,6 +22,10 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+// https://w3c.github.io/mediacapture-main/#navigatorusermediaerrorcallback
+
+// TODO(foolip): This should be a callback function, not a callback interface.
+// https://crbug.com/569301
 callback interface NavigatorUserMediaErrorCallback {
     void handleEvent(NavigatorUserMediaError error);
 };
diff --git a/third_party/WebKit/Source/modules/mediastream/NavigatorUserMediaSuccessCallback.idl b/third_party/WebKit/Source/modules/mediastream/NavigatorUserMediaSuccessCallback.idl
index 57fdbeb..7344a75 100644
--- a/third_party/WebKit/Source/modules/mediastream/NavigatorUserMediaSuccessCallback.idl
+++ b/third_party/WebKit/Source/modules/mediastream/NavigatorUserMediaSuccessCallback.idl
@@ -22,6 +22,10 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+// https://w3c.github.io/mediacapture-main/#navigatorusermediasuccesscallback
+
+// TODO(foolip): This should be a callback function, not a callback interface.
+// https://crbug.com/569301
 callback interface NavigatorUserMediaSuccessCallback {
     void handleEvent(MediaStream stream);
 };
diff --git a/third_party/WebKit/Source/modules/mediastream/SourceInfo.idl b/third_party/WebKit/Source/modules/mediastream/SourceInfo.idl
index 814dd65c..15a0e2e 100644
--- a/third_party/WebKit/Source/modules/mediastream/SourceInfo.idl
+++ b/third_party/WebKit/Source/modules/mediastream/SourceInfo.idl
@@ -23,6 +23,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+// TODO(guidou): Remove MediaStreamTrack.getSources(). https://crbug.com/649710
 [
     NoInterfaceObject
 ] interface SourceInfo {
diff --git a/third_party/WebKit/Source/modules/mediastream/URLMediaStream.idl b/third_party/WebKit/Source/modules/mediastream/URLMediaStream.idl
index 7cdba87..3dab19c 100644
--- a/third_party/WebKit/Source/modules/mediastream/URLMediaStream.idl
+++ b/third_party/WebKit/Source/modules/mediastream/URLMediaStream.idl
@@ -28,10 +28,12 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+// An old version of Media Capture and Streams defines URL.createObjectURL:
+// https://w3c.github.io/mediacapture-main/archives/20131017/getusermedia.html
+
+// TODO(foolip): Update link if it's revived in the spec:
+// https://github.com/w3c/mediacapture-main/issues/404
+
 partial interface URL {
-    // This method was specified in the Media Capture and Streams specification
-    // until
-    // https://w3c.github.io/mediacapture-main/archives/20131017/getusermedia.html
-    // But it has been removed.
     [Exposed=(Window,DedicatedWorker,SharedWorker), CallWith=ExecutionContext] static DOMString? createObjectURL(MediaStream stream);
 };
diff --git a/third_party/WebKit/Source/modules/mediastream/UserMediaClient.h b/third_party/WebKit/Source/modules/mediastream/UserMediaClient.h
index be2905e..335d2f7 100644
--- a/third_party/WebKit/Source/modules/mediastream/UserMediaClient.h
+++ b/third_party/WebKit/Source/modules/mediastream/UserMediaClient.h
@@ -48,7 +48,6 @@
     virtual void requestUserMedia(UserMediaRequest*) = 0;
     virtual void cancelUserMediaRequest(UserMediaRequest*) = 0;
     virtual void requestMediaDevices(MediaDevicesRequest*) = 0;
-    virtual void cancelMediaDevicesRequest(MediaDevicesRequest*) = 0;
     virtual void requestSources(MediaStreamTrackSourcesRequest*) = 0;
     virtual void setMediaDeviceChangeObserver(MediaDevices*) = 0;
     virtual ~UserMediaClient() { }
diff --git a/third_party/WebKit/Source/modules/mediastream/UserMediaController.h b/third_party/WebKit/Source/modules/mediastream/UserMediaController.h
index 69b3e410..8eaaa9f 100644
--- a/third_party/WebKit/Source/modules/mediastream/UserMediaController.h
+++ b/third_party/WebKit/Source/modules/mediastream/UserMediaController.h
@@ -45,12 +45,8 @@
 
     void requestUserMedia(UserMediaRequest*);
     void cancelUserMediaRequest(UserMediaRequest*);
-
     void requestMediaDevices(MediaDevicesRequest*);
-    void cancelMediaDevicesRequest(MediaDevicesRequest*);
-
     void requestSources(MediaStreamTrackSourcesRequest*);
-
     void setMediaDeviceChangeObserver(MediaDevices*);
 
     static const char* supplementName();
@@ -77,11 +73,6 @@
     m_client->requestMediaDevices(request);
 }
 
-inline void UserMediaController::cancelMediaDevicesRequest(MediaDevicesRequest* request)
-{
-    m_client->cancelMediaDevicesRequest(request);
-}
-
 inline void UserMediaController::requestSources(MediaStreamTrackSourcesRequest* request)
 {
     m_client->requestSources(request);
diff --git a/third_party/WebKit/Source/modules/mediastream/UserMediaRequest.cpp b/third_party/WebKit/Source/modules/mediastream/UserMediaRequest.cpp
index f869e78..c6e5c1f 100644
--- a/third_party/WebKit/Source/modules/mediastream/UserMediaRequest.cpp
+++ b/third_party/WebKit/Source/modules/mediastream/UserMediaRequest.cpp
@@ -79,7 +79,7 @@
         return nullptr;
 
     if (audio.isNull() && video.isNull()) {
-        errorState.throwDOMException(SyntaxError, "At least one of audio and video must be requested");
+        errorState.throwTypeError("At least one of audio and video must be requested");
         return nullptr;
     }
 
diff --git a/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp b/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp
index 1d968f9..1f8d4d19 100644
--- a/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp
+++ b/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp
@@ -94,18 +94,13 @@
     return !!m_imageBuffer;
 }
 
-static bool shouldAccelerate(IntSize surfaceSize)
-{
-    return RuntimeEnabledFeatures::accelerated2dCanvasEnabled();
-}
-
 ImageBuffer* OffscreenCanvasRenderingContext2D::imageBuffer() const
 {
     if (!m_imageBuffer) {
         IntSize surfaceSize(width(), height());
         OpacityMode opacityMode = hasAlpha() ? NonOpaque : Opaque;
         std::unique_ptr<ImageBufferSurface> surface;
-        if (shouldAccelerate(surfaceSize)) {
+        if (RuntimeEnabledFeatures::accelerated2dCanvasEnabled()) {
             surface.reset(new AcceleratedImageBufferSurface(surfaceSize, opacityMode));
         }
 
diff --git a/third_party/WebKit/Source/modules/plugins/DOMMimeTypeArray.cpp b/third_party/WebKit/Source/modules/plugins/DOMMimeTypeArray.cpp
index 95b464d..4f9cace7 100644
--- a/third_party/WebKit/Source/modules/plugins/DOMMimeTypeArray.cpp
+++ b/third_party/WebKit/Source/modules/plugins/DOMMimeTypeArray.cpp
@@ -53,7 +53,7 @@
     const Vector<MimeClassInfo>& mimes = data->mimes();
     if (index >= mimes.size())
         return nullptr;
-    return DOMMimeType::create(data, m_frame, index);
+    return DOMMimeType::create(data, frame(), index);
 }
 
 DOMMimeType* DOMMimeTypeArray::namedItem(const AtomicString& propertyName)
@@ -64,16 +64,16 @@
     const Vector<MimeClassInfo>& mimes = data->mimes();
     for (unsigned i = 0; i < mimes.size(); ++i) {
         if (mimes[i].type == propertyName)
-            return DOMMimeType::create(data, m_frame, i);
+            return DOMMimeType::create(data, frame(), i);
     }
     return nullptr;
 }
 
 PluginData* DOMMimeTypeArray::getPluginData() const
 {
-    if (!m_frame)
+    if (!frame())
         return nullptr;
-    return m_frame->pluginData();
+    return frame()->pluginData();
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/plugins/DOMPluginArray.cpp b/third_party/WebKit/Source/modules/plugins/DOMPluginArray.cpp
index 32d1c968..f03df985b 100644
--- a/third_party/WebKit/Source/modules/plugins/DOMPluginArray.cpp
+++ b/third_party/WebKit/Source/modules/plugins/DOMPluginArray.cpp
@@ -53,7 +53,7 @@
     const Vector<PluginInfo>& plugins = data->plugins();
     if (index >= plugins.size())
         return nullptr;
-    return DOMPlugin::create(data, m_frame, index);
+    return DOMPlugin::create(data, frame(), index);
 }
 
 DOMPlugin* DOMPluginArray::namedItem(const AtomicString& propertyName)
@@ -64,25 +64,25 @@
     const Vector<PluginInfo>& plugins = data->plugins();
     for (unsigned i = 0; i < plugins.size(); ++i) {
         if (plugins[i].name == propertyName)
-            return DOMPlugin::create(data, m_frame, i);
+            return DOMPlugin::create(data, frame(), i);
     }
     return nullptr;
 }
 
 void DOMPluginArray::refresh(bool reload)
 {
-    if (!m_frame)
+    if (!frame())
         return;
     Page::refreshPlugins();
     if (reload)
-        m_frame->reload(FrameLoadTypeReload, ClientRedirectPolicy::ClientRedirect);
+        frame()->reload(FrameLoadTypeReload, ClientRedirectPolicy::ClientRedirect);
 }
 
 PluginData* DOMPluginArray::pluginData() const
 {
-    if (!m_frame)
+    if (!frame())
         return nullptr;
-    return m_frame->pluginData();
+    return frame()->pluginData();
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/screen_orientation/ScreenOrientation.cpp b/third_party/WebKit/Source/modules/screen_orientation/ScreenOrientation.cpp
index 16bee9eb..7d8d515 100644
--- a/third_party/WebKit/Source/modules/screen_orientation/ScreenOrientation.cpp
+++ b/third_party/WebKit/Source/modules/screen_orientation/ScreenOrientation.cpp
@@ -125,9 +125,9 @@
 
 ExecutionContext* ScreenOrientation::getExecutionContext() const
 {
-    if (!m_frame)
+    if (!frame())
         return 0;
-    return m_frame->document();
+    return frame()->document();
 }
 
 String ScreenOrientation::type() const
@@ -155,7 +155,7 @@
     ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(state);
     ScriptPromise promise = resolver->promise();
 
-    Document* document = m_frame ? m_frame->document() : 0;
+    Document* document = frame() ? frame()->document() : 0;
 
     if (!document || !controller()) {
         DOMException* exception = DOMException::create(InvalidStateError, "The object is no longer associated to a document.");
@@ -183,10 +183,10 @@
 
 ScreenOrientationController* ScreenOrientation::controller()
 {
-    if (!m_frame)
+    if (!frame())
         return 0;
 
-    return ScreenOrientationController::from(*m_frame);
+    return ScreenOrientationController::from(*frame());
 }
 
 DEFINE_TRACE(ScreenOrientation)
diff --git a/third_party/WebKit/Source/modules/storage/Storage.cpp b/third_party/WebKit/Source/modules/storage/Storage.cpp
index 372f916..e73646a 100644
--- a/third_party/WebKit/Source/modules/storage/Storage.cpp
+++ b/third_party/WebKit/Source/modules/storage/Storage.cpp
@@ -40,8 +40,8 @@
     : DOMWindowProperty(frame)
     , m_storageArea(storageArea)
 {
-    ASSERT(m_frame);
-    ASSERT(m_storageArea);
+    DCHECK(frame);
+    DCHECK(m_storageArea);
 }
 
 String Storage::anonymousNamedGetter(const AtomicString& name, ExceptionState& exceptionState)
diff --git a/third_party/WebKit/Source/modules/storage/Storage.h b/third_party/WebKit/Source/modules/storage/Storage.h
index 8e51d0ce..82920af 100644
--- a/third_party/WebKit/Source/modules/storage/Storage.h
+++ b/third_party/WebKit/Source/modules/storage/Storage.h
@@ -44,13 +44,13 @@
     USING_GARBAGE_COLLECTED_MIXIN(Storage);
 public:
     static Storage* create(LocalFrame*, StorageArea*);
-    unsigned length(ExceptionState& ec) const { return m_storageArea->length(ec, m_frame); }
-    String key(unsigned index, ExceptionState& ec) const { return m_storageArea->key(index, ec, m_frame); }
-    String getItem(const String& key, ExceptionState& ec) const { return m_storageArea->getItem(key, ec, m_frame); }
-    void setItem(const String& key, const String& value, ExceptionState& ec) { m_storageArea->setItem(key, value, ec, m_frame); }
-    void removeItem(const String& key, ExceptionState& ec) { m_storageArea->removeItem(key, ec, m_frame); }
-    void clear(ExceptionState& ec) { m_storageArea->clear(ec, m_frame); }
-    bool contains(const String& key, ExceptionState& ec) const { return m_storageArea->contains(key, ec, m_frame); }
+    unsigned length(ExceptionState& ec) const { return m_storageArea->length(ec, frame()); }
+    String key(unsigned index, ExceptionState& ec) const { return m_storageArea->key(index, ec, frame()); }
+    String getItem(const String& key, ExceptionState& ec) const { return m_storageArea->getItem(key, ec, frame()); }
+    void setItem(const String& key, const String& value, ExceptionState& ec) { m_storageArea->setItem(key, value, ec, frame()); }
+    void removeItem(const String& key, ExceptionState& ec) { m_storageArea->removeItem(key, ec, frame()); }
+    void clear(ExceptionState& ec) { m_storageArea->clear(ec, frame()); }
+    bool contains(const String& key, ExceptionState& ec) const { return m_storageArea->contains(key, ec, frame()); }
 
     StorageArea* area() const { return m_storageArea.get(); }
 
diff --git a/third_party/WebKit/Source/modules/vr/NavigatorVR.cpp b/third_party/WebKit/Source/modules/vr/NavigatorVR.cpp
index 356d998..377d668 100644
--- a/third_party/WebKit/Source/modules/vr/NavigatorVR.cpp
+++ b/third_party/WebKit/Source/modules/vr/NavigatorVR.cpp
@@ -49,7 +49,7 @@
     ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
     ScriptPromise promise = resolver->promise();
 
-    Document* document = m_frame ? m_frame->document() : 0;
+    Document* document = frame() ? frame()->document() : 0;
 
     if (!document || !controller()) {
         DOMException* exception = DOMException::create(InvalidStateError, "The object is no longer associated to a document.");
@@ -78,7 +78,7 @@
 
 Document* NavigatorVR::document()
 {
-    return m_frame ? m_frame->document() : 0;
+    return frame() ? frame()->document() : 0;
 }
 
 DEFINE_TRACE(NavigatorVR)
@@ -105,16 +105,16 @@
 
 void NavigatorVR::fireVRDisplayPresentChange(VRDisplay* display)
 {
-    if (m_frame && m_frame->localDOMWindow()) {
-        m_frame->localDOMWindow()->enqueueWindowEvent(
+    if (frame() && frame()->localDOMWindow()) {
+        frame()->localDOMWindow()->enqueueWindowEvent(
             VRDisplayEvent::create(EventTypeNames::vrdisplaypresentchange, true, false, display, ""));
     }
 }
 
 void NavigatorVR::fireVREvent(VRDisplayEvent* event)
 {
-    if (m_frame && m_frame->localDOMWindow()) {
-        m_frame->localDOMWindow()->enqueueWindowEvent(event);
+    if (frame() && frame()->localDOMWindow()) {
+        frame()->localDOMWindow()->enqueueWindowEvent(event);
     }
 }
 
diff --git a/third_party/WebKit/Source/modules/webdatabase/Database.cpp b/third_party/WebKit/Source/modules/webdatabase/Database.cpp
index 3f3b630..7176166 100644
--- a/third_party/WebKit/Source/modules/webdatabase/Database.cpp
+++ b/third_party/WebKit/Source/modules/webdatabase/Database.cpp
@@ -897,11 +897,13 @@
 
 SecurityOrigin* Database::getSecurityOrigin() const
 {
+    if (!getExecutionContext())
+        return nullptr;
     if (getExecutionContext()->isContextThread())
         return m_contextThreadSecurityOrigin.get();
     if (getDatabaseContext()->databaseThread()->isDatabaseThread())
         return m_databaseThreadSecurityOrigin.get();
-    return 0;
+    return nullptr;
 }
 
 bool Database::opened()
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
index fbbf02f..3ae8d5f 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
@@ -93,7 +93,6 @@
 #include "platform/graphics/UnacceleratedImageBufferSurface.h"
 #include "platform/graphics/gpu/AcceleratedImageBufferSurface.h"
 #include "public/platform/Platform.h"
-#include "public/platform/functional/WebFunction.h"
 #include "wtf/CheckedNumeric.h"
 #include "wtf/Functional.h"
 #include "wtf/PtrUtil.h"
@@ -1102,13 +1101,13 @@
     contextGL()->Scissor(0, 0, drawingBufferWidth(), drawingBufferHeight());
 
     drawingBuffer()->contextProvider()->setLostContextCallback(
-        WebClosure(WTF::bind(
+        convertToBaseCallback(WTF::bind(
             &WebGLRenderingContextBase::forceLostContext,
             wrapWeakPersistent(this),
             WebGLRenderingContextBase::RealLostContext,
             WebGLRenderingContextBase::Auto)));
     drawingBuffer()->contextProvider()->setErrorMessageCallback(
-        WebFunction<void(const char*, int32_t)>(WTF::bind(
+        convertToBaseCallback(WTF::bind(
             &WebGLRenderingContextBase::onErrorMessage,
             wrapWeakPersistent(this))));
 
@@ -1219,8 +1218,10 @@
 
     m_extensionsUtil.reset();
 
-    drawingBuffer()->contextProvider()->setLostContextCallback(WebClosure());
-    drawingBuffer()->contextProvider()->setErrorMessageCallback(WebFunction<void(const char*, int32_t)>());
+    std::unique_ptr<WTF::Closure> nullClosure;
+    std::unique_ptr<WTF::Function<void(const char*, int32_t)>> nullFunction;
+    drawingBuffer()->contextProvider()->setLostContextCallback(convertToBaseCallback(std::move(nullClosure)));
+    drawingBuffer()->contextProvider()->setErrorMessageCallback(convertToBaseCallback(std::move(nullFunction)));
     drawingBuffer()->addNewMailboxCallback(nullptr);
 
     ASSERT(drawingBuffer());
@@ -4508,7 +4509,7 @@
         return;
     ASSERT(bitmap->bitmapImage());
 
-    if (functionID != TexSubImage3D && bitmap->isTextureBacked() && canUseTexImageByGPU(functionID, internalformat, type)) {
+    if (functionID != TexSubImage3D && bitmap->isAccelerated() && canUseTexImageByGPU(functionID, internalformat, type)) {
         if (functionID == TexImage2D) {
             texImage2DBase(target, level, internalformat, bitmap->width(), bitmap->height(), 0, format, type, 0);
             texImageByGPU(TexImage2DByGPU, texture, target, level, internalformat, type, 0, 0, 0, bitmap);
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn
index f87b5b2..0dbcecc 100644
--- a/third_party/WebKit/Source/platform/BUILD.gn
+++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -907,10 +907,6 @@
     "graphics/filters/Filter.h",
     "graphics/filters/FilterEffect.cpp",
     "graphics/filters/FilterEffect.h",
-    "graphics/filters/FilterOperation.cpp",
-    "graphics/filters/FilterOperation.h",
-    "graphics/filters/FilterOperations.cpp",
-    "graphics/filters/FilterOperations.h",
     "graphics/filters/LightSource.cpp",
     "graphics/filters/LightSource.h",
     "graphics/filters/PaintFilterEffect.cpp",
@@ -1660,7 +1656,6 @@
     "graphics/GraphicsContextTest.cpp",
     "graphics/RecordingImageBufferSurfaceTest.cpp",
     "graphics/compositing/PaintArtifactCompositorTest.cpp",
-    "graphics/filters/FilterOperationsTest.cpp",
     "graphics/filters/ImageFilterBuilderTest.cpp",
     "graphics/gpu/DrawingBufferTest.cpp",
     "graphics/gpu/SharedGpuContextTest.cpp",
diff --git a/third_party/WebKit/Source/platform/PlatformMouseEvent.h b/third_party/WebKit/Source/platform/PlatformMouseEvent.h
index 28c9056..cb19318 100644
--- a/third_party/WebKit/Source/platform/PlatformMouseEvent.h
+++ b/third_party/WebKit/Source/platform/PlatformMouseEvent.h
@@ -46,7 +46,12 @@
     };
 
     PlatformMouseEvent()
-        : PlatformEvent(PlatformEvent::MouseMoved)
+        : PlatformMouseEvent(PlatformEvent::MouseMoved)
+    {
+    }
+
+    explicit PlatformMouseEvent(EventType type)
+        : PlatformEvent(type)
         , m_clickCount(0)
         , m_synthesized(RealOrIndistinguishable)
     {
diff --git a/third_party/WebKit/Source/platform/PlatformWheelEvent.h b/third_party/WebKit/Source/platform/PlatformWheelEvent.h
index 66d3eca..7552d22 100644
--- a/third_party/WebKit/Source/platform/PlatformWheelEvent.h
+++ b/third_party/WebKit/Source/platform/PlatformWheelEvent.h
@@ -27,6 +27,7 @@
 #define PlatformWheelEvent_h
 
 #include "platform/PlatformEvent.h"
+#include "platform/PlatformMouseEvent.h"
 #include "platform/geometry/IntPoint.h"
 
 namespace blink {
@@ -53,10 +54,10 @@
 };
 #endif
 
-class PlatformWheelEvent : public PlatformEvent {
+class PlatformWheelEvent : public PlatformMouseEvent {
 public:
     PlatformWheelEvent()
-        : PlatformEvent(PlatformEvent::Wheel)
+        : PlatformMouseEvent(PlatformEvent::Wheel)
         , m_deltaX(0)
         , m_deltaY(0)
         , m_wheelTicksX(0)
@@ -73,9 +74,6 @@
     {
     }
 
-    const IntPoint& position() const { return m_position; } // PlatformWindow coordinates.
-    const IntPoint& globalPosition() const { return m_globalPosition; } // Screen coordinates.
-
     float deltaX() const { return m_deltaX; }
     float deltaY() const { return m_deltaY; }
 
@@ -96,8 +94,6 @@
 #endif
 
 protected:
-    IntPoint m_position;
-    IntPoint m_globalPosition;
     float m_deltaX;
     float m_deltaY;
     float m_wheelTicksX;
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
index 7544c2da..52711200 100644
--- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
+++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
@@ -169,7 +169,7 @@
 PermissionDelegation status=test
 Permissions status=stable
 PermissionsRequestRevoke status=experimental
-PointerEvent status=experimental
+PointerEvent status=stable
 // For temporary compat testing of Edge-like model - crbug.com/640700
 PointerEventV1SpecCapturing
 PreciseMemoryInfo
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
index 2f76b3b0..ad28611 100644
--- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
+++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
@@ -380,6 +380,11 @@
     }
 }
 
+static void hibernateWrapperForTesting(WeakPtr<Canvas2DLayerBridge> bridge)
+{
+    hibernateWrapper(bridge, 0);
+}
+
 void Canvas2DLayerBridge::hibernate()
 {
     DCHECK(!isHibernating());
@@ -606,7 +611,11 @@
             m_layer->clearTexture();
         m_logger->reportHibernationEvent(HibernationScheduled);
         m_hibernationScheduled = true;
-        Platform::current()->currentThread()->scheduler()->postIdleTask(BLINK_FROM_HERE, WTF::bind(&hibernateWrapper, m_weakPtrFactory.createWeakPtr()));
+        if (m_dontUseIdleSchedulingForTesting) {
+            Platform::current()->currentThread()->getWebTaskRunner()->postTask(BLINK_FROM_HERE, WTF::bind(&hibernateWrapperForTesting, m_weakPtrFactory.createWeakPtr()));
+        } else {
+            Platform::current()->currentThread()->scheduler()->postIdleTask(BLINK_FROM_HERE, WTF::bind(&hibernateWrapper, m_weakPtrFactory.createWeakPtr()));
+        }
     }
     if (!isHidden() && m_softwareRenderingWhileHidden) {
         flushRecordingOnly();
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
index fc94bdc..6e095af3 100644
--- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
+++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
@@ -120,6 +120,7 @@
     void prepareSurfaceForPaintingIfNeeded();
     bool isHidden() { return m_isHidden; }
     OpacityMode opacityMode() { return m_opacityMode; }
+    void dontUseIdleSchedulingForTesting() { m_dontUseIdleSchedulingForTesting = true; }
 
     void beginDestruction();
     void hibernate();
@@ -259,6 +260,7 @@
     bool m_softwareRenderingWhileHidden;
     bool m_surfaceCreationFailedAtLeastOnce = false;
     bool m_hibernationScheduled = false;
+    bool m_dontUseIdleSchedulingForTesting = false;
 
     friend class Canvas2DLayerBridgeTest;
     friend class CanvasRenderingContext2DTest;
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp
index f4673ee4..c51738c 100644
--- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp
@@ -40,7 +40,6 @@
 #include "public/platform/WebTaskRunner.h"
 #include "public/platform/WebThread.h"
 #include "public/platform/WebTraceLocation.h"
-#include "public/platform/functional/WebFunction.h"
 #include "skia/ext/texture_handle.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -101,7 +100,9 @@
 public:
     PassRefPtr<Canvas2DLayerBridge> makeBridge(std::unique_ptr<FakeWebGraphicsContext3DProvider> provider, const IntSize& size, Canvas2DLayerBridge::AccelerationMode accelerationMode)
     {
-        return adoptRef(new Canvas2DLayerBridge(std::move(provider), size, 0, NonOpaque, accelerationMode, nullptr));
+        RefPtr<Canvas2DLayerBridge> bridge = adoptRef(new Canvas2DLayerBridge(std::move(provider), size, 0, NonOpaque, accelerationMode, nullptr));
+        bridge->dontUseIdleSchedulingForTesting();
+        return bridge.release();
     }
 
 protected:
@@ -462,7 +463,7 @@
     EXPECT_CALL(*mockLoggerPtr, didStartHibernating())
         .WillOnce(testing::Invoke(hibernationStartedEvent.get(), &WaitableEvent::signal));
     postSetIsHiddenTask(BLINK_FROM_HERE, testThread.get(), bridge.get(), true);
-    // Toggle visibility before the idle tasks that enters hibernation gets a
+    // Toggle visibility before the task that enters hibernation gets a
     // chance to run.
     postSetIsHiddenTask(BLINK_FROM_HERE, testThread.get(), bridge.get(), false);
     postSetIsHiddenTask(BLINK_FROM_HERE, testThread.get(), bridge.get(), true);
@@ -816,23 +817,6 @@
     postAndWaitDestroyBridgeTask(BLINK_FROM_HERE, testThread.get(), &bridge);
 }
 
-class IdleFenceTask : public WebThread::IdleTask {
-public:
-    IdleFenceTask(WaitableEvent* doneEvent)
-        : m_doneEvent(doneEvent)
-    { }
-
-    virtual ~IdleFenceTask() { }
-
-    void run(double /*deadline*/) override
-    {
-        m_doneEvent->signal();
-    }
-
-private:
-    WaitableEvent* m_doneEvent;
-};
-
 #if CANVAS2D_HIBERNATION_ENABLED
 TEST_F(Canvas2DLayerBridgeTest, TeardownWhileHibernationIsPending)
 #else
@@ -863,13 +847,13 @@
     // a bridge to hold the mockLogger.
     hibernationScheduledEvent->wait();
     // Once we know the hibernation task is scheduled, we can schedule a fence.
-    // Assuming Idle tasks are guaranteed to run in the order they were
+    // Assuming tasks are guaranteed to run in the order they were
     // submitted, this fence will guarantee the attempt to hibernate runs to
     // completion before the thread is destroyed.
     // This test passes by not crashing, which proves that the WeakPtr logic
     // is sound.
     std::unique_ptr<WaitableEvent> fenceEvent = wrapUnique(new WaitableEvent());
-    testThread->scheduler()->postIdleTask(BLINK_FROM_HERE, new IdleFenceTask(fenceEvent.get()));
+    testThread->getWebTaskRunner()->postTask(BLINK_FROM_HERE, WTF::bind(&WaitableEvent::signal, unretained(fenceEvent.get())));
     fenceEvent->wait();
 }
 
diff --git a/third_party/WebKit/Source/platform/graphics/ExpensiveCanvasHeuristicParameters.h b/third_party/WebKit/Source/platform/graphics/ExpensiveCanvasHeuristicParameters.h
index f32dda3d..1afe3b0 100644
--- a/third_party/WebKit/Source/platform/graphics/ExpensiveCanvasHeuristicParameters.h
+++ b/third_party/WebKit/Source/platform/graphics/ExpensiveCanvasHeuristicParameters.h
@@ -67,6 +67,16 @@
 
     GetImageDataForcesNoAcceleration = 1,
 
+    // When drawing very large images to canvases, there is a point where
+    // GPU acceleration becomes inefficient due to texture upload overhead,
+    // especially when the image is large enough that it is likely to
+    // monopolize the texture cache, and when it is being downsized to the
+    // point that few of the upload texels are actually sampled. When both
+    // of these conditions are met, we disable acceleration.
+    DrawImageTextureUploadSoftSizeLimit = 4096 * 4096,
+    DrawImageTextureUploadSoftSizeLimitScaleThreshold = 4,
+    DrawImageTextureUploadHardSizeLimit = 8192 * 8192,
+
 }; // enum
 
 
diff --git a/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp b/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp
index 12bf550b0b..031e0e5 100644
--- a/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp
+++ b/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp
@@ -438,16 +438,18 @@
     if (!isAccelerated())
         return;
 
-    // Get current frame.
-    SkImage* image = m_surface->newImageSnapshot(PreferNoAcceleration, SnapshotReasonPaint).get();
+    sk_sp<SkImage> image = m_surface->newImageSnapshot(PreferNoAcceleration, SnapshotReasonPaint);
+    // Using a GPU-backed image with RecordingImageBufferSurface
+    // will fail at playback time.
+    image = image->makeNonTextureImage();
 
     // Create and configure a recording (unaccelerated) surface.
     std::unique_ptr<RecordingImageBufferFallbackSurfaceFactory> surfaceFactory = wrapUnique(new UnacceleratedSurfaceFactory());
     std::unique_ptr<ImageBufferSurface> surface = wrapUnique(new RecordingImageBufferSurface(m_surface->size(), std::move(surfaceFactory), m_surface->getOpacityMode(), m_surface->colorSpace()));
-    surface->canvas()->drawImage(image, 0, 0);
+    surface->canvas()->drawImage(image.get(), 0, 0);
     surface->setImageBuffer(this);
-
-    // Replace the current surface with the new surface.
+    if (m_client)
+        m_client->restoreCanvasMatrixClipStack(surface->canvas());
     m_surface = std::move(surface);
 
     didDisableAcceleration();
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferSoftwareRenderingTest.cpp b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferSoftwareRenderingTest.cpp
index e90e920..4293d4200 100644
--- a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferSoftwareRenderingTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferSoftwareRenderingTest.cpp
@@ -34,8 +34,8 @@
     GrContext* grContext() override { return nullptr; }
     bool bindToCurrentThread() override { return false; }
     gpu::Capabilities getCapabilities() override { return gpu::Capabilities(); }
-    void setLostContextCallback(WebClosure) {}
-    void setErrorMessageCallback(WebFunction<void(const char*, int32_t id)>) {}
+    void setLostContextCallback(const base::Closure&) {}
+    void setErrorMessageCallback(const base::Callback<void(const char*, int32_t id)>&) {}
 
 private:
     std::unique_ptr<gpu::gles2::GLES2Interface> m_gl;
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTest.cpp b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTest.cpp
index 4b94349..99725f0 100644
--- a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTest.cpp
@@ -39,7 +39,6 @@
 #include "platform/graphics/UnacceleratedImageBufferSurface.h"
 #include "platform/graphics/gpu/DrawingBufferTestHelpers.h"
 #include "public/platform/Platform.h"
-#include "public/platform/functional/WebFunction.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "wtf/PtrUtil.h"
 #include "wtf/RefPtr.h"
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTestHelpers.h b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTestHelpers.h
index f2df77d93..2ed95414 100644
--- a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTestHelpers.h
+++ b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTestHelpers.h
@@ -64,8 +64,8 @@
     GrContext* grContext() override { return nullptr; }
     bool bindToCurrentThread() override { return false; }
     gpu::Capabilities getCapabilities() override { return gpu::Capabilities(); }
-    void setLostContextCallback(WebClosure) {}
-    void setErrorMessageCallback(WebFunction<void(const char*, int32_t id)>) {}
+    void setLostContextCallback(const base::Closure&) {}
+    void setErrorMessageCallback(const base::Callback<void(const char*, int32_t id)>&) {}
 
 private:
     std::unique_ptr<gpu::gles2::GLES2Interface> m_gl;
diff --git a/third_party/WebKit/Source/platform/graphics/test/FakeWebGraphicsContext3DProvider.h b/third_party/WebKit/Source/platform/graphics/test/FakeWebGraphicsContext3DProvider.h
index 63a8075a..56ae8b2 100644
--- a/third_party/WebKit/Source/platform/graphics/test/FakeWebGraphicsContext3DProvider.h
+++ b/third_party/WebKit/Source/platform/graphics/test/FakeWebGraphicsContext3DProvider.h
@@ -41,8 +41,8 @@
     }
 
     bool bindToCurrentThread() override { return false; }
-    void setLostContextCallback(WebClosure) override {}
-    void setErrorMessageCallback(WebFunction<void(const char*, int32_t id)>) {}
+    void setLostContextCallback(const base::Closure&) override {}
+    void setErrorMessageCallback(const base::Callback<void(const char*, int32_t id)>&) {}
 
 private:
     gpu::gles2::GLES2Interface* m_gl;
diff --git a/third_party/WebKit/Source/web/BUILD.gn b/third_party/WebKit/Source/web/BUILD.gn
index 10f22d5..2816303f 100644
--- a/third_party/WebKit/Source/web/BUILD.gn
+++ b/third_party/WebKit/Source/web/BUILD.gn
@@ -171,6 +171,7 @@
     "WebFormControlElement.cpp",
     "WebFormElement.cpp",
     "WebFrame.cpp",
+    "WebFrameClient.cpp",
     "WebFrameContentDumper.cpp",
     "WebFrameImplBase.cpp",
     "WebFrameImplBase.h",
diff --git a/third_party/WebKit/Source/web/ChromeClientImpl.cpp b/third_party/WebKit/Source/web/ChromeClientImpl.cpp
index 17c5196..f285211 100644
--- a/third_party/WebKit/Source/web/ChromeClientImpl.cpp
+++ b/third_party/WebKit/Source/web/ChromeClientImpl.cpp
@@ -1131,11 +1131,9 @@
 {
     WebLocalFrameImpl* webFrame = WebLocalFrameImpl::fromFrame(&frame);
     WebFrameClient* client = webFrame->client();
-    if (client) {
-        providePushControllerTo(frame, client->pushClient());
-        provideUserMediaTo(frame, UserMediaClientImpl::create(client->userMediaClient()));
-    }
-
+    DCHECK(client);
+    providePushControllerTo(frame, client->pushClient());
+    provideUserMediaTo(frame, UserMediaClientImpl::create(client->userMediaClient()));
     provideIndexedDBClientTo(frame, IndexedDBClientImpl::create());
     provideLocalFileSystemTo(frame, LocalFileSystemClient::create());
     provideNavigatorContentUtilsTo(frame, NavigatorContentUtilsClientImpl::create(webFrame));
@@ -1145,15 +1143,15 @@
     enableWebBluetooth = true;
 #endif
     if (enableWebBluetooth)
-        BluetoothSupplement::provideTo(frame, client ? client->bluetooth() : nullptr);
+        BluetoothSupplement::provideTo(frame, client->bluetooth());
 
-    ScreenOrientationController::provideTo(frame, client ? client->webScreenOrientationClient() : nullptr);
+    ScreenOrientationController::provideTo(frame, client->webScreenOrientationClient());
     if (RuntimeEnabledFeatures::presentationEnabled())
-        PresentationController::provideTo(frame, client ? client->presentationClient() : nullptr);
+        PresentationController::provideTo(frame, client->presentationClient());
     if (RuntimeEnabledFeatures::audioOutputDevicesEnabled())
         provideAudioOutputDeviceClientTo(frame, AudioOutputDeviceClientImpl::create());
     if (RuntimeEnabledFeatures::installedAppEnabled())
-        InstalledAppController::provideTo(frame, client ? client->installedAppClient() : nullptr);
+        InstalledAppController::provideTo(frame, client->installedAppClient());
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp b/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp
index a0684f8..3d4abe9 100644
--- a/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp
+++ b/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp
@@ -435,10 +435,10 @@
         m_webFrame->client()->didNavigateWithinPage(m_webFrame, WebHistoryItem(item), static_cast<WebHistoryCommitType>(commitType), contentInitiated);
 }
 
-void FrameLoaderClientImpl::dispatchWillClose()
+void FrameLoaderClientImpl::dispatchWillCommitProvisionalLoad()
 {
     if (m_webFrame->client())
-        m_webFrame->client()->willClose(m_webFrame);
+        m_webFrame->client()->willCommitProvisionalLoad(m_webFrame);
 }
 
 void FrameLoaderClientImpl::dispatchDidStartProvisionalLoad(double triggeringEventTime)
diff --git a/third_party/WebKit/Source/web/FrameLoaderClientImpl.h b/third_party/WebKit/Source/web/FrameLoaderClientImpl.h
index 2d6c7b4..9756e164 100644
--- a/third_party/WebKit/Source/web/FrameLoaderClientImpl.h
+++ b/third_party/WebKit/Source/web/FrameLoaderClientImpl.h
@@ -90,7 +90,7 @@
     void dispatchDidHandleOnloadEvents() override;
     void dispatchDidReceiveServerRedirectForProvisionalLoad() override;
     void dispatchDidNavigateWithinPage(HistoryItem*, HistoryCommitType, bool contentInitiated) override;
-    void dispatchWillClose() override;
+    void dispatchWillCommitProvisionalLoad() override;
     void dispatchDidStartProvisionalLoad(double triggeringEventTime) override;
     void dispatchDidReceiveTitle(const String&) override;
     void dispatchDidChangeIcons(IconType) override;
diff --git a/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp b/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp
index 156c1fc7..9104ebff 100644
--- a/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp
+++ b/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp
@@ -85,7 +85,6 @@
 DEFINE_TRACE(ServiceWorkerGlobalScopeProxy)
 {
     visitor->trace(m_document);
-    visitor->trace(m_workerGlobalScope);
 }
 
 void ServiceWorkerGlobalScopeProxy::setRegistration(std::unique_ptr<WebServiceWorkerRegistration::Handle> handle)
diff --git a/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.h b/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.h
index 3faf0079..c8886af 100644
--- a/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.h
+++ b/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.h
@@ -119,7 +119,7 @@
 
     WebServiceWorkerContextClient* m_client;
 
-    Member<ServiceWorkerGlobalScope> m_workerGlobalScope;
+    CrossThreadPersistent<ServiceWorkerGlobalScope> m_workerGlobalScope;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/web/UserMediaClientImpl.cpp b/third_party/WebKit/Source/web/UserMediaClientImpl.cpp
index dd55d65..3c7b089 100644
--- a/third_party/WebKit/Source/web/UserMediaClientImpl.cpp
+++ b/third_party/WebKit/Source/web/UserMediaClientImpl.cpp
@@ -64,12 +64,6 @@
         m_client->requestMediaDevices(request);
 }
 
-void UserMediaClientImpl::cancelMediaDevicesRequest(MediaDevicesRequest* request)
-{
-    if (m_client)
-        m_client->cancelMediaDevicesRequest(WebMediaDevicesRequest(request));
-}
-
 void UserMediaClientImpl::requestSources(MediaStreamTrackSourcesRequest* request)
 {
     if (m_client)
diff --git a/third_party/WebKit/Source/web/UserMediaClientImpl.h b/third_party/WebKit/Source/web/UserMediaClientImpl.h
index 375cc3e..22478fb7 100644
--- a/third_party/WebKit/Source/web/UserMediaClientImpl.h
+++ b/third_party/WebKit/Source/web/UserMediaClientImpl.h
@@ -53,7 +53,6 @@
     void requestUserMedia(UserMediaRequest*) override;
     void cancelUserMediaRequest(UserMediaRequest*) override;
     void requestMediaDevices(MediaDevicesRequest*) override;
-    void cancelMediaDevicesRequest(MediaDevicesRequest*) override;
     void requestSources(MediaStreamTrackSourcesRequest*) override;
     void setMediaDeviceChangeObserver(MediaDevices*) override;
 private:
diff --git a/third_party/WebKit/Source/web/WebFrameClient.cpp b/third_party/WebKit/Source/web/WebFrameClient.cpp
new file mode 100644
index 0000000..93ce5eb
--- /dev/null
+++ b/third_party/WebKit/Source/web/WebFrameClient.cpp
@@ -0,0 +1,23 @@
+// 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.
+
+#include "public/web/WebFrameClient.h"
+
+#include "public/web/WebFrameWidget.h"
+#include "public/web/WebLocalFrame.h"
+
+namespace blink {
+
+void WebFrameClient::frameDetached(WebLocalFrame* frame, DetachType type)
+{
+    if (type == DetachType::Remove && frame->parent())
+        frame->parent()->removeChild(frame);
+
+    if (frame->frameWidget())
+        frame->frameWidget()->close();
+
+    frame->close();
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
index 2fe90bb..9cca56f 100644
--- a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
+++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
@@ -1478,6 +1478,7 @@
     , m_webDevToolsFrontend(0)
     , m_selfKeepAlive(this)
 {
+    DCHECK(m_client);
     frameCount++;
 }
 
diff --git a/third_party/WebKit/Source/web/WebSettingsImpl.cpp b/third_party/WebKit/Source/web/WebSettingsImpl.cpp
index adac1a3..323fe5c 100644
--- a/third_party/WebKit/Source/web/WebSettingsImpl.cpp
+++ b/third_party/WebKit/Source/web/WebSettingsImpl.cpp
@@ -342,6 +342,11 @@
     m_settings->setSpatialNavigationEnabled(enabled);
 }
 
+void WebSettingsImpl::setSpellCheckEnabledByDefault(bool enabled)
+{
+    m_settings->setSpellCheckEnabledByDefault(enabled);
+}
+
 void WebSettingsImpl::setTextAreasAreResizable(bool areResizable)
 {
     m_settings->setTextAreasAreResizable(areResizable);
diff --git a/third_party/WebKit/Source/web/WebSettingsImpl.h b/third_party/WebKit/Source/web/WebSettingsImpl.h
index 00b3dc6..f1444885 100644
--- a/third_party/WebKit/Source/web/WebSettingsImpl.h
+++ b/third_party/WebKit/Source/web/WebSettingsImpl.h
@@ -155,6 +155,7 @@
     void setShrinksViewportContentToFit(bool) override;
     void setSmartInsertDeleteEnabled(bool) override;
     void setSpatialNavigationEnabled(bool) override;
+    void setSpellCheckEnabledByDefault(bool) override;
     void setStandardFontFamily(const WebString&, UScriptCode = USCRIPT_COMMON) override;
     void setStrictMixedContentChecking(bool) override;
     void setStrictMixedContentCheckingForPlugin(bool) override;
diff --git a/third_party/WebKit/Source/web/tests/ChromeClientImplTest.cpp b/third_party/WebKit/Source/web/tests/ChromeClientImplTest.cpp
index 9c35a86..c71def645 100644
--- a/third_party/WebKit/Source/web/tests/ChromeClientImplTest.cpp
+++ b/third_party/WebKit/Source/web/tests/ChromeClientImplTest.cpp
@@ -77,8 +77,7 @@
     void SetUp() override
     {
         m_webView = toWebViewImpl(WebView::create(&m_webViewClient, WebPageVisibilityStateVisible));
-        m_mainFrame = WebLocalFrame::create(WebTreeScopeType::Document, &m_webFrameClient);
-        m_webView->setMainFrame(m_mainFrame);
+        m_webView->setMainFrame(WebLocalFrame::create(WebTreeScopeType::Document, &m_webFrameClient));
         m_chromeClientImpl = toChromeClientImpl(&m_webView->page()->chromeClient());
         m_result = WebNavigationPolicyIgnore;
     }
@@ -86,7 +85,6 @@
     void TearDown() override
     {
         m_webView->close();
-        m_mainFrame->close();
     }
 
     WebNavigationPolicy getNavigationPolicyWithMouseEvent(int modifiers, WebMouseEvent::Button button, bool asPopup)
@@ -112,7 +110,6 @@
     WebNavigationPolicy m_result;
     TestWebViewClient m_webViewClient;
     WebViewImpl* m_webView;
-    WebFrame* m_mainFrame;
     FrameTestHelpers::TestWebFrameClient m_webFrameClient;
     Persistent<ChromeClientImpl> m_chromeClientImpl;
 };
@@ -281,12 +278,11 @@
     void TearDown() override
     {
         m_webView->close();
-        m_mainFrame->close();
     }
 
     ViewCreatingClient m_webViewClient;
     WebViewImpl* m_webView;
-    WebFrame* m_mainFrame;
+    WebLocalFrame* m_mainFrame;
     FrameTestHelpers::TestWebFrameClient m_webFrameClient;
     Persistent<ChromeClientImpl> m_chromeClientImpl;
 };
diff --git a/third_party/WebKit/Source/web/tests/FrameLoaderClientImplTest.cpp b/third_party/WebKit/Source/web/tests/FrameLoaderClientImplTest.cpp
index 3127ab78..9d4c750 100644
--- a/third_party/WebKit/Source/web/tests/FrameLoaderClientImplTest.cpp
+++ b/third_party/WebKit/Source/web/tests/FrameLoaderClientImplTest.cpp
@@ -74,7 +74,6 @@
     void TearDown() override
     {
         m_webView->close();
-        m_mainFrame->close();
     }
 
     WebString userAgent()
@@ -92,7 +91,7 @@
 private:
     MockWebFrameClient m_webFrameClient;
     WebView* m_webView;
-    WebFrame* m_mainFrame;
+    WebLocalFrame* m_mainFrame;
 };
 
 TEST_F(FrameLoaderClientImplTest, UserAgentOverride)
diff --git a/third_party/WebKit/Source/web/tests/FrameTestHelpers.cpp b/third_party/WebKit/Source/web/tests/FrameTestHelpers.cpp
index 0aa6861..693f9e4 100644
--- a/third_party/WebKit/Source/web/tests/FrameTestHelpers.cpp
+++ b/third_party/WebKit/Source/web/tests/FrameTestHelpers.cpp
@@ -275,24 +275,13 @@
 {
 }
 
-WebFrame* TestWebFrameClient::createChildFrame(WebLocalFrame* parent, WebTreeScopeType scope, const WebString& name, const WebString& uniqueName, WebSandboxFlags sandboxFlags, const WebFrameOwnerProperties& frameOwnerProperties)
+WebLocalFrame* TestWebFrameClient::createChildFrame(WebLocalFrame* parent, WebTreeScopeType scope, const WebString& name, const WebString& uniqueName, WebSandboxFlags sandboxFlags, const WebFrameOwnerProperties& frameOwnerProperties)
 {
-    WebFrame* frame = WebLocalFrame::create(scope, this);
+    WebLocalFrame* frame = WebLocalFrame::create(scope, this);
     parent->appendChild(frame);
     return frame;
 }
 
-void TestWebFrameClient::frameDetached(WebLocalFrame* frame, DetachType type)
-{
-    if (type == DetachType::Remove && frame->parent())
-        frame->parent()->removeChild(frame);
-
-    if (frame->frameWidget())
-        frame->frameWidget()->close();
-
-    frame->close();
-}
-
 void TestWebFrameClient::didStartLoading(bool)
 {
     ++m_loadsInProgress;
diff --git a/third_party/WebKit/Source/web/tests/FrameTestHelpers.h b/third_party/WebKit/Source/web/tests/FrameTestHelpers.h
index 523171da..4da105e8 100644
--- a/third_party/WebKit/Source/web/tests/FrameTestHelpers.h
+++ b/third_party/WebKit/Source/web/tests/FrameTestHelpers.h
@@ -210,8 +210,7 @@
 public:
     TestWebFrameClient();
 
-    WebFrame* createChildFrame(WebLocalFrame* parent, WebTreeScopeType, const WebString& name, const WebString& uniqueName, WebSandboxFlags, const WebFrameOwnerProperties&) override;
-    void frameDetached(WebLocalFrame*, DetachType) override;
+    WebLocalFrame* createChildFrame(WebLocalFrame* parent, WebTreeScopeType, const WebString& name, const WebString& uniqueName, WebSandboxFlags, const WebFrameOwnerProperties&) override;
     void didStartLoading(bool) override;
     void didStopLoading() override;
 
diff --git a/third_party/WebKit/Source/web/tests/VirtualTimeTest.cpp b/third_party/WebKit/Source/web/tests/VirtualTimeTest.cpp
index 76c8855..a1c4451f 100644
--- a/third_party/WebKit/Source/web/tests/VirtualTimeTest.cpp
+++ b/third_party/WebKit/Source/web/tests/VirtualTimeTest.cpp
@@ -41,6 +41,14 @@
             WebScriptSource(WebString(scriptSource)), false, &callbackHelper);
         return callbackHelper.result();
     }
+
+    void TearDown() override
+    {
+        // The SimTest destructor calls runPendingTasks. This is a problem because if there are
+        // any repeating tasks, advancing virtual time will cause the runloop to busy loop. Pausing
+        // virtual time here fixes that.
+        webView().scheduler()->setVirtualTimePolicy(WebViewScheduler::VirtualTimePolicy::PAUSE);
+    }
 };
 
 namespace {
diff --git a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
index b194b12..c7e3a87 100644
--- a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
@@ -5889,11 +5889,11 @@
     int willSendRequestCallCount() const { return m_willSendRequestCallCount; }
     int childFrameCreationCount() const { return m_childFrameCreationCount; }
 
-    virtual WebFrame* createChildFrame(WebLocalFrame* parent, WebTreeScopeType scope, const WebString&, const WebString&, WebSandboxFlags, const WebFrameOwnerProperties& frameOwnerProperties)
+    virtual WebLocalFrame* createChildFrame(WebLocalFrame* parent, WebTreeScopeType scope, const WebString&, const WebString&, WebSandboxFlags, const WebFrameOwnerProperties& frameOwnerProperties)
     {
         DCHECK(m_childClient);
         m_childFrameCreationCount++;
-        WebFrame* frame = WebLocalFrame::create(scope, m_childClient);
+        WebLocalFrame* frame = WebLocalFrame::create(scope, m_childClient);
         parent->appendChild(frame);
         return frame;
     }
@@ -6277,10 +6277,10 @@
 public:
     FailCreateChildFrame() : m_callCount(0) { }
 
-    WebFrame* createChildFrame(WebLocalFrame* parent, WebTreeScopeType scope, const WebString& frameName, const WebString& frameUniqueName, WebSandboxFlags sandboxFlags, const WebFrameOwnerProperties& frameOwnerProperties) override
+    WebLocalFrame* createChildFrame(WebLocalFrame* parent, WebTreeScopeType scope, const WebString& frameName, const WebString& frameUniqueName, WebSandboxFlags sandboxFlags, const WebFrameOwnerProperties& frameOwnerProperties) override
     {
         ++m_callCount;
-        return 0;
+        return nullptr;
     }
 
     int callCount() const { return m_callCount; }
@@ -7939,7 +7939,7 @@
     // Attempt a blocked navigation of an opener's subframe, and ensure that
     // the error shows up on the popup (calling) window's console, rather than
     // the target window.
-    popupView->mainFrame()->executeScript(WebScriptSource("opener.frames[1].location.href='data:text/html,foo'"));
+    popupView->mainFrame()->executeScript(WebScriptSource("try { opener.frames[1].location.href='data:text/html,foo'; } catch (e) {}"));
     EXPECT_TRUE(webFrameClient.messages.isEmpty());
     ASSERT_EQ(1u, popupWebFrameClient.messages.size());
     EXPECT_TRUE(std::string::npos != popupWebFrameClient.messages[0].text.utf8().find("Unsafe JavaScript attempt to initiate navigation"));
diff --git a/third_party/WebKit/Source/web/tests/WebViewTest.cpp b/third_party/WebKit/Source/web/tests/WebViewTest.cpp
index 424d1c5..85c3507 100644
--- a/third_party/WebKit/Source/web/tests/WebViewTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebViewTest.cpp
@@ -413,10 +413,10 @@
     // webView does not have a frame yet, but we should still be able to set the background color.
     webView->setBaseBackgroundColor(kBlue);
     EXPECT_EQ(kBlue, webView->backgroundColor());
-    WebLocalFrame* frame = WebLocalFrame::create(WebTreeScopeType::Document, nullptr);
+    FrameTestHelpers::TestWebFrameClient webFrameClient;
+    WebLocalFrame* frame = WebLocalFrame::create(WebTreeScopeType::Document, &webFrameClient);
     webView->setMainFrame(frame);
     webView->close();
-    frame->close();
 }
 
 TEST_F(WebViewTest, SetBaseBackgroundColorAndBlendWithExistingContent)
@@ -1827,7 +1827,8 @@
 TEST_F(WebViewTest, ClientTapHandlingNullWebViewClient)
 {
     WebViewImpl* webView = WebViewImpl::create(nullptr, WebPageVisibilityStateVisible);
-    WebLocalFrame* localFrame = WebLocalFrame::create(WebTreeScopeType::Document, nullptr);
+    FrameTestHelpers::TestWebFrameClient webFrameClient;
+    WebLocalFrame* localFrame = WebLocalFrame::create(WebTreeScopeType::Document, &webFrameClient);
     webView->setMainFrame(localFrame);
     WebGestureEvent event;
     event.type = WebInputEvent::GestureTap;
@@ -1836,8 +1837,6 @@
     event.y = 8;
     EXPECT_EQ(WebInputEventResult::NotHandled, webView->handleInputEvent(event));
     webView->close();
-    // Explicitly close as the frame as no frame client to do so on frameDetached().
-    localFrame->close();
 }
 
 TEST_F(WebViewTest, LongPressEmptyDiv)
@@ -2722,7 +2721,7 @@
 class CreateChildCounterFrameClient : public FrameTestHelpers::TestWebFrameClient {
 public:
     CreateChildCounterFrameClient() : m_count(0) { }
-    WebFrame* createChildFrame(WebLocalFrame* parent, WebTreeScopeType, const WebString& name, const WebString& uniqueName, WebSandboxFlags, const WebFrameOwnerProperties&) override;
+    WebLocalFrame* createChildFrame(WebLocalFrame* parent, WebTreeScopeType, const WebString& name, const WebString& uniqueName, WebSandboxFlags, const WebFrameOwnerProperties&) override;
 
     int count() const { return m_count; }
 
@@ -2730,7 +2729,7 @@
     int m_count;
 };
 
-WebFrame* CreateChildCounterFrameClient::createChildFrame(WebLocalFrame* parent, WebTreeScopeType scope, const WebString& name, const WebString& uniqueName, WebSandboxFlags sandboxFlags, const WebFrameOwnerProperties& frameOwnerProperties)
+WebLocalFrame* CreateChildCounterFrameClient::createChildFrame(WebLocalFrame* parent, WebTreeScopeType scope, const WebString& name, const WebString& uniqueName, WebSandboxFlags sandboxFlags, const WebFrameOwnerProperties& frameOwnerProperties)
 {
     ++m_count;
     return TestWebFrameClient::createChildFrame(parent, scope, name, uniqueName, sandboxFlags, frameOwnerProperties);
diff --git a/third_party/WebKit/Source/wtf/Functional.h b/third_party/WebKit/Source/wtf/Functional.h
index ef54a66..b2d535f9 100644
--- a/third_party/WebKit/Source/wtf/Functional.h
+++ b/third_party/WebKit/Source/wtf/Functional.h
@@ -210,7 +210,9 @@
 
     friend base::Callback<R(Args...)> convertToBaseCallback(std::unique_ptr<Function> function)
     {
-        return std::move(function->m_callback);
+        if (function)
+            return std::move(function->m_callback);
+        return base::Callback<R(Args...)>();
     }
 
 private:
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py
index d502f616..d89fb00 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py
@@ -156,7 +156,7 @@
         return self.device_directory() + 'fonts/'
 
     def device_forwarder_path(self):
-        return self.device_directory() + 'forwarder'
+        return self.device_directory() + 'device_forwarder'
 
     def device_fifo_directory(self):
         return '/data/data/' + self.package_name() + '/files/'
@@ -461,7 +461,10 @@
 
     # Local public methods.
     def path_to_forwarder(self):
-        return self._build_path('forwarder')
+        return self._build_path('device_forwarder')
+
+    def path_to_forwarder_host(self):
+        return self._build_path('host_forwarder')
 
     def path_to_md5sum(self):
         return self._build_path(MD5SUM_DEVICE_FILE_NAME)
@@ -506,6 +509,7 @@
         result = self._check_file_exists(self.path_to_md5sum(), 'md5sum utility')
         result = self._check_file_exists(self.path_to_md5sum_host(), 'md5sum host utility') and result
         result = self._check_file_exists(self.path_to_forwarder(), 'forwarder utility') and result
+        result = self._check_file_exists(self.path_to_forwarder_host(), 'forwarder host utility') and result
 
         if not result:
             # There is a race condition in adb at least <= 4.3 on Linux that causes it to go offline periodically
@@ -815,7 +819,6 @@
         self._err_fifo_path = driver_details.device_fifo_directory() + 'stderr.fifo'
         self._read_stdout_process = None
         self._read_stderr_process = None
-        self._forwarder_process = None
         self._original_governors = {}
         self._original_kptr_restrict = None
 
@@ -965,7 +968,10 @@
             self._android_commands.push(host_file, device_file)
 
     def _push_executable(self, log_callback):
-        self._push_file_if_needed(self._port.path_to_forwarder(), self._driver_details.device_forwarder_path(), log_callback)
+        self._push_file_if_needed(
+            self._port.path_to_forwarder(),
+            self._driver_details.device_forwarder_path(),
+            log_callback)
         for resource in self._driver_details.additional_resources():
             self._push_file_if_needed(self._port._build_path(
                 resource), self._driver_details.device_directory() + resource, log_callback)
@@ -1145,14 +1151,13 @@
         super(ChromiumAndroidDriver, self)._start(pixel_tests, per_test_args, wait_for_ready=False)
 
         self._log_debug('Starting forwarder')
-        self._forwarder_process = self._port._server_process_constructor(
-            self._port, 'Forwarder', self._android_commands.adb_command() +
-            ['shell', '%s -no-spawn-daemon %s' % (self._driver_details.device_forwarder_path(), FORWARD_PORTS)])
-        self._forwarder_process.start()
-
-        deadline = time.time() + DRIVER_START_STOP_TIMEOUT_SECS
-        if not self._wait_for_server_process_output(self._forwarder_process, deadline, 'Forwarding device port'):
-            return False
+        self._android_commands.run(['shell', self._driver_details.device_forwarder_path()])
+        for forward_port in FORWARD_PORTS.split():
+            self._port.host.executive.run_command([
+                self._port.path_to_forwarder_host(),
+                '--adb=%s' % AndroidCommands.adb_command_path(self._port.host.executive, self._debug_logging),
+                '--serial-id=%s' % self._android_commands.get_serial(),
+                '--map', forward_port, forward_port])
 
         self._android_commands.run(['logcat', '-c'])
 
@@ -1261,11 +1266,16 @@
             self._read_stderr_process.kill()
             self._read_stderr_process = None
 
-        super(ChromiumAndroidDriver, self).stop()
+        self._android_commands.run([
+            'shell',
+            self._driver_details.device_forwarder_path(),
+            '--kill-server'])
 
-        if self._forwarder_process:
-            self._forwarder_process.kill()
-            self._forwarder_process = None
+        self._port.host.executive.run_command([
+            self._port.path_to_forwarder_host(),
+            '--kill-server'])
+
+        super(ChromiumAndroidDriver, self).stop()
 
         if self._android_devices.is_device_prepared(self._android_commands.get_serial()):
             if not ChromiumAndroidDriver._loop_with_timeout(self._remove_all_pipes, DRIVER_START_STOP_TIMEOUT_SECS):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/cpp.py b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/cpp.py
index 2efad32..31dc24c 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/cpp.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/cpp.py
@@ -3502,6 +3502,7 @@
             # Various exceptions to the rule: JavaScript op codes functions, const_iterator.
             if (not (filename.find('JavaScriptCore') >= 0 and modified_identifier.find('op_') >= 0)
                     and not (filename.find('gtk') >= 0 and modified_identifier.startswith('webkit_') >= 0)
+                    and not (filename.find('StructTraits.h') >= 0)
                     and not modified_identifier.startswith('tst_')
                     and not modified_identifier.startswith('webkit_dom_object_')
                     and not modified_identifier.startswith('webkit_soup')
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/optimize_baselines_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/optimize_baselines_unittest.py
index f8a3538a..715e6a6 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/optimize_baselines_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/optimize_baselines_unittest.py
@@ -75,8 +75,8 @@
         self.assertEquals(
             out,
             '{"add": [], "remove-lines": [], '
-            '"delete": ["/test.checkout/LayoutTests/platform/test-mac-mac10.10/another/test-expected.png", '
-            '"/test.checkout/LayoutTests/platform/test-mac-mac10.10/another/test-expected.txt"]}\n')
+            '"delete": ["/test.checkout/LayoutTests/platform/test-mac-mac10.10/another/test-expected.txt", '
+            '"/test.checkout/LayoutTests/platform/test-mac-mac10.10/another/test-expected.png"]}\n')
         self.assertFalse(
             self.tool.filesystem.exists(self.tool.filesystem.join(
                 test_port.layout_tests_dir(), 'platform/mac/another/test-expected.txt')))
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline.py
index deebf32b..78d3011 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline.py
@@ -87,42 +87,29 @@
     TODO(qyearsley): Refactor this so that lines to remove are only tracked in one format.
     """
     def __init__(self, files_to_add=None, files_to_delete=None, lines_to_remove=None):
-        self._files_to_add = set(files_to_add or [])
-        self._files_to_delete = set(files_to_delete or [])
-        lines_to_remove = lines_to_remove or {}
-        self._lines_to_remove = {t: set(builders) for t, builders in lines_to_remove.iteritems()}
+        self.files_to_add = files_to_add or []
+        self.files_to_delete = files_to_delete or []
+        self.lines_to_remove = lines_to_remove or {}
 
     def add_file(self, path):
-        self._files_to_add.add(path)
+        self.files_to_add.append(path)
 
     def delete_file(self, path):
-        self._files_to_delete.add(path)
+        self.files_to_delete.append(path)
 
     def remove_line(self, test, builder):
-        if test not in self._lines_to_remove:
-            self._lines_to_remove[test] = set()
-        self._lines_to_remove[test].add(builder)
-
-    @property
-    def files_to_add(self):
-        return sorted(self._files_to_add - self._files_to_delete)
-
-    @property
-    def files_to_delete(self):
-        return sorted(self._files_to_delete - self._files_to_add)
-
-    @property
-    def lines_to_remove(self):
-        return {t: sorted(set(builders)) for t, builders in sorted(self._lines_to_remove.iteritems())}
+        if test not in self.lines_to_remove:
+            self.lines_to_remove[test] = []
+        self.lines_to_remove[test].append(builder)
 
     def to_dict(self):
         remove_lines = []
-        for test in sorted(self.lines_to_remove):
-            for builder in sorted(set(self.lines_to_remove[test])):
+        for test in self.lines_to_remove:
+            for builder in self.lines_to_remove[test]:
                 remove_lines.append({'test': test, 'builder': builder})
         return {
-            'add': self.files_to_add,
-            'delete': self.files_to_delete,
+            'add': list(self.files_to_add),
+            'delete': list(self.files_to_delete),
             'remove-lines': remove_lines,
         }
 
@@ -143,18 +130,19 @@
                     lines_to_remove[test] = []
                 lines_to_remove[test].append(builder)
         return ChangeSet(
-            files_to_add=files_to_add,
-            files_to_delete=files_to_delete,
+            files_to_add=list(files_to_add),
+            files_to_delete=list(files_to_delete),
             lines_to_remove=lines_to_remove)
 
     def update(self, other):
         assert isinstance(other, ChangeSet)
-        self._files_to_add.update(other.files_to_add)
-        self._files_to_delete.update(other.files_to_delete)
+        assert type(other.lines_to_remove) is dict
+        self.files_to_add.extend(other.files_to_add)
+        self.files_to_delete.extend(other.files_to_delete)
         for test in other.lines_to_remove:
-            if test not in self._lines_to_remove:
-                self._lines_to_remove[test] = set()
-            self._lines_to_remove[test].update(other.lines_to_remove[test])
+            if test not in self.lines_to_remove:
+                self.lines_to_remove[test] = []
+            self.lines_to_remove[test].extend(other.lines_to_remove[test])
 
 
 class BaseInternalRebaselineCommand(AbstractRebaseliningCommand):
@@ -499,18 +487,28 @@
         return (SKIP in full_expectations.get_expectations(test) and
                 SKIP not in generic_expectations.get_expectations(test))
 
-    def _run_in_parallel(self, commands):
+    def _run_in_parallel(self, commands, update_scm=True):
         if not commands:
-            return ChangeSet()
+            return {}
 
         command_results = self._tool.executive.run_in_parallel(commands)
         for _, _, stderr in command_results:
             if stderr:
                 _log.error(stderr)
 
-        return self._extract_scm_changes(command_results)
+        change_set = self._extract_scm_changes(command_results)
 
-    def _rebaseline(self, options, test_prefix_list):
+        # TODO(qyearsley): Instead of updating the SCM state here, aggregate changes
+        # and update once in _rebaseline. See http://crbug.com/639410.
+        if update_scm:
+            if change_set.files_to_delete:
+                self._tool.scm().delete_list(change_set.files_to_delete)
+            if change_set.files_to_add:
+                self._tool.scm().add_list(change_set.files_to_add)
+
+        return change_set.lines_to_remove
+
+    def _rebaseline(self, options, test_prefix_list, update_scm=True):
         """Downloads new baselines in parallel, then updates expectations files
         and optimizes baselines.
 
@@ -528,6 +526,7 @@
                 "some/other.html" but only from builder-1.
                 TODO(qyearsley): Replace test_prefix_list everywhere with some
                 sort of class that contains the same data.
+            update_scm: If True, commands like `git add` and `git rm` will be run.
         """
         for test, builds_to_check in sorted(test_prefix_list.items()):
             _log.info("Rebaselining %s", test)
@@ -536,25 +535,25 @@
 
         copy_baseline_commands, rebaseline_commands, extra_lines_to_remove = self._rebaseline_commands(
             test_prefix_list, options)
+        lines_to_remove = {}
 
-        change_set = ChangeSet(lines_to_remove=extra_lines_to_remove)
+        self._run_in_parallel(copy_baseline_commands, update_scm=update_scm)
+        lines_to_remove = self._run_in_parallel(rebaseline_commands, update_scm=update_scm)
 
-        change_set.update(self._run_in_parallel(copy_baseline_commands))
-        change_set.update(self._run_in_parallel(rebaseline_commands))
+        for test in extra_lines_to_remove:
+            if test in lines_to_remove:
+                lines_to_remove[test] = lines_to_remove[test] + extra_lines_to_remove[test]
+            else:
+                lines_to_remove[test] = extra_lines_to_remove[test]
 
-        if change_set.lines_to_remove:
-            self._update_expectations_files(change_set.lines_to_remove)
+        if lines_to_remove:
+            self._update_expectations_files(lines_to_remove)
 
         if options.optimize:
             # TODO(wkorman): Consider changing temporary branch to base off of HEAD rather than
             # origin/master to ensure we run baseline optimization processes with the same code as
             # auto-rebaseline itself.
-            change_set.update(self._run_in_parallel(self._optimize_baselines(test_prefix_list, options.verbose)))
-
-        if change_set.files_to_delete:
-            self._tool.scm().delete_list(change_set.files_to_delete)
-        if change_set.files_to_add:
-            self._tool.scm().add_list(change_set.files_to_add)
+            self._run_in_parallel(self._optimize_baselines(test_prefix_list, options.verbose), update_scm=update_scm)
 
     def _suffixes_for_actual_failures(self, test, build, existing_suffixes):
         """Gets the baseline suffixes for actual mismatch failures in some results.
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl.py
index 0914a0d..c62fd98 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl.py
@@ -83,7 +83,7 @@
 
         if options.dry_run:
             return
-        self._rebaseline(options, test_prefix_list)
+        self._rebaseline(options, test_prefix_list, update_scm=False)
 
     def _filter_existing(self, test_prefix_list):
         """Filters out entries in |test_prefix_list| for tests that don't exist."""
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py
index 20c1de4..abe3f60 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py
@@ -934,93 +934,3 @@
         self.calls = self.calls[:num_previous_calls]
         self.calls.append(new_calls)
         return command_outputs
-
-
-class ChangeSetTest(unittest.TestCase):
-
-    def test_constructor_and_getters(self):
-        change_set = ChangeSet(
-            files_to_add=['add/a.html', 'add/b.html'],
-            files_to_delete=['del/x.html'],
-            lines_to_remove={'my/test.html': ['my-builder']})
-        self.assertEqual(change_set.files_to_add, ['add/a.html', 'add/b.html'])
-        self.assertEqual(change_set.files_to_delete, ['del/x.html'])
-        self.assertEqual(change_set.lines_to_remove, {'my/test.html': ['my-builder']})
-
-    def test_files_to_add_and_files_to_delete_are_sorted_no_dupes(self):
-        change_set = ChangeSet(files_to_add=['b', 'a', 'a'], files_to_delete=['x', 'y', 'x'])
-        self.assertEqual(change_set.files_to_add, ['a', 'b'])
-        self.assertEqual(change_set.files_to_delete, ['x', 'y'])
-
-    def test_files_both_added_and_deleted_are_ignored(self):
-        change_set = ChangeSet(files_to_add=['a', 'b', 'c'], files_to_delete=['c', 'd', 'e'])
-        self.assertEqual(change_set.files_to_add, ['a', 'b'])
-        self.assertEqual(change_set.files_to_delete, ['d', 'e'])
-        change_set.add_file('d')
-        self.assertEqual(change_set.files_to_add, ['a', 'b'])
-        self.assertEqual(change_set.files_to_delete, ['e'])
-        change_set.delete_file('b')
-        self.assertEqual(change_set.files_to_add, ['a'])
-        self.assertEqual(change_set.files_to_delete, ['e'])
-
-    def test_add_file(self):
-        change_set = ChangeSet()
-        change_set.add_file('a')
-        change_set.add_file('b')
-        change_set.add_file('b')
-        self.assertEqual(change_set.files_to_add, ['a', 'b'])
-
-    def test_delete_file(self):
-        change_set = ChangeSet()
-        change_set.delete_file('a')
-        change_set.delete_file('b')
-        change_set.delete_file('b')
-        self.assertEqual(change_set.files_to_delete, ['a', 'b'])
-
-    def test_remove_line(self):
-        change_set = ChangeSet()
-        change_set.remove_line('test', 'builder-b')
-        change_set.remove_line('test', 'builder-a')
-        change_set.remove_line('test', 'builder-a')
-        self.assertEqual(
-            change_set.lines_to_remove,
-            {'test': ['builder-a', 'builder-b']})
-
-    def test_from_dict(self):
-        change_set = ChangeSet.from_dict({
-            'add': ['to/add.html'],
-            'remove-lines': [{'test': 'some/test.html', 'builder': 'builder-name'}]
-        })
-        self.assertEqual(change_set.files_to_add, ['to/add.html'])
-        self.assertEqual(change_set.lines_to_remove, {'some/test.html': ['builder-name']})
-
-    def test_to_dict(self):
-        change_set = ChangeSet(
-            files_to_add=['add/b.html', 'add/a.html'],
-            files_to_delete=['del/x.html'],
-            lines_to_remove={
-                'x/test.html': ['builder-b', 'builder-b', 'builder-a'],
-                'y/test.html': [],
-                'z/test.html': ['builder-c']})
-        self.assertEqual(change_set.to_dict(), {
-            'add': ['add/a.html', 'add/b.html'],
-            'delete': ['del/x.html'],
-            'remove-lines': [
-                {'test': 'x/test.html', 'builder': 'builder-a'},
-                {'test': 'x/test.html', 'builder': 'builder-b'},
-                {'test': 'z/test.html', 'builder': 'builder-c'},
-            ],
-        })
-
-    def test_update(self):
-        change_set = ChangeSet(
-            files_to_add=['add/a.html', 'add/b.html'],
-            files_to_delete=['del/x.html'],
-            lines_to_remove={'my/test.html': ['my-builder']})
-        change_set.update(ChangeSet(
-            files_to_add=['add/a.html', 'add/c.html', 'del/x.html'],
-            files_to_delete=['add/b.html', 'del/y.html'],
-            lines_to_remove={'my/test.html': ['my-builder', 'other-builder']}))
-        self.assertEqual(change_set.files_to_add, ['add/a.html', 'add/c.html'])
-        self.assertEqual(change_set.files_to_delete, ['del/y.html'])
-        self.assertEqual(change_set.lines_to_remove, {'my/test.html': ['my-builder', 'other-builder']})
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater.py
index 7330576..0d755981 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater.py
@@ -51,10 +51,10 @@
         chromium_commitish = show_ref_output.split()[0]
 
         if options.target == 'wpt':
-            import_commitish = self.update(WPT_DEST_NAME, WPT_REPO_URL, options.keep_w3c_repos_around)
+            import_commitish = self.update(WPT_DEST_NAME, WPT_REPO_URL, options.keep_w3c_repos_around, options.revision)
             self._copy_resources()
         elif options.target == 'css':
-            import_commitish = self.update(CSS_DEST_NAME, CSS_REPO_URL, options.keep_w3c_repos_around)
+            import_commitish = self.update(CSS_DEST_NAME, CSS_REPO_URL, options.keep_w3c_repos_around, options.revision)
         else:
             raise AssertionError("Unsupported target %s" % options.target)
 
@@ -74,6 +74,8 @@
                             help='allow script to run even if we have local commits')
         parser.add_argument('--keep-w3c-repos-around', action='store_true',
                             help='leave the w3c repos around that were imported previously.')
+        parser.add_argument('-r', dest='revision', action='store',
+                            help='Target revision.')
         parser.add_argument('target', choices=['css', 'wpt'],
                             help='Target repository.  "css" for csswg-test, "wpt" for web-platform-tests.')
         parser.add_argument('--auto-update', action='store_true',
@@ -140,12 +142,13 @@
             self.copyfile(source, destination)
             self.run(['git', 'add', destination])
 
-    def update(self, dest_dir_name, url, keep_w3c_repos_around):
+    def update(self, dest_dir_name, url, keep_w3c_repos_around, revision):
         """Updates an imported repository.
 
         Args:
             dest_dir_name: The destination directory name.
             url: URL of the git repository.
+            revision: Commit hash or None.
 
         Returns:
             A string for the commit description "<destination>@<commitish>".
@@ -154,6 +157,9 @@
         self.print_('## Cloning %s into %s.' % (url, temp_repo_path))
         self.run(['git', 'clone', url, temp_repo_path])
 
+        if revision is not None:
+            self.print_('## Checking out %s' % revision)
+            self.run(['git', 'checkout', revision], cwd=temp_repo_path)
         self.run(['git', 'submodule', 'update', '--init', '--recursive'], cwd=temp_repo_path)
 
         self.print_('## Noting the revision we are importing.')
@@ -297,6 +303,7 @@
             True if successfully committed, False otherwise.
         """
         self._upload_cl()
+        self.print_('## ' + self.git_cl.run(['issue']).strip())
 
         # First try: if there are failures, update expectations.
         self.print_('## Triggering try jobs.')
diff --git a/third_party/WebKit/public/BUILD.gn b/third_party/WebKit/public/BUILD.gn
index 40523f7c..aa8d4b48 100644
--- a/third_party/WebKit/public/BUILD.gn
+++ b/third_party/WebKit/public/BUILD.gn
@@ -671,6 +671,8 @@
     "platform/modules/permissions/permission_status.mojom",
     "platform/modules/presentation/presentation.mojom",
     "platform/modules/websockets/websocket.mojom",
+    "platform/referrer.mojom",
+    "web/window_features.mojom",
   ]
   public_deps = [
     "//url/mojo:url_mojom_gurl",
@@ -732,3 +734,16 @@
     ":offscreen_canvas_mojo_bindings_blink__generator",
   ]
 }
+
+# Some mojom typemaps are shared between Chromium and Blink variants and
+# therefore require some shared traits implementation. These definitions are
+# relegated to a separate target to avoid duplication between the variants.
+source_set("shared_typemap_traits") {
+  visibility = [ ":*" ]
+  sources = [
+    "web/WindowFeaturesStructTraits.cpp",
+  ]
+  deps = [
+    ":new_wrapper_types_mojo_bindings__generator",
+  ]
+}
diff --git a/third_party/WebKit/public/platform/DEPS b/third_party/WebKit/public/platform/DEPS
index d349569..f4bae6f 100644
--- a/third_party/WebKit/public/platform/DEPS
+++ b/third_party/WebKit/public/platform/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+    "+base/callback_forward.h",
     "+base/location.h",
     "+base/logging.h",
     "+base/metrics",
diff --git a/third_party/WebKit/public/platform/OWNERS b/third_party/WebKit/public/platform/OWNERS
new file mode 100644
index 0000000..ced8ab2
--- /dev/null
+++ b/third_party/WebKit/public/platform/OWNERS
@@ -0,0 +1,4 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+per-file *StructTraits*.*=set noparent
+per-file *StructTraits*.*=file://ipc/SECURITY_OWNERS
diff --git a/third_party/WebKit/public/platform/ReferrerPolicyEnumTraits.h b/third_party/WebKit/public/platform/ReferrerPolicyEnumTraits.h
new file mode 100644
index 0000000..5b032707
--- /dev/null
+++ b/third_party/WebKit/public/platform/ReferrerPolicyEnumTraits.h
@@ -0,0 +1,73 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ReferrerPolicyEnumTraits_h
+#define ReferrerPolicyEnumTraits_h
+
+#include "base/logging.h"
+#include "mojo/public/cpp/bindings/enum_traits.h"
+#include "third_party/WebKit/public/platform/WebReferrerPolicy.h"
+#include "third_party/WebKit/public/platform/referrer.mojom-shared.h"
+
+namespace mojo {
+
+template <>
+struct EnumTraits<::blink::mojom::ReferrerPolicy, ::blink::WebReferrerPolicy> {
+    static ::blink::mojom::ReferrerPolicy ToMojom(::blink::WebReferrerPolicy policy)
+    {
+        switch (policy) {
+        case ::blink::WebReferrerPolicyAlways:
+            return ::blink::mojom::ReferrerPolicy::ALWAYS;
+        case ::blink::WebReferrerPolicyDefault:
+            return ::blink::mojom::ReferrerPolicy::DEFAULT;
+        case ::blink::WebReferrerPolicyNoReferrerWhenDowngrade:
+            return ::blink::mojom::ReferrerPolicy::NO_REFERRER_WHEN_DOWNGRADE;
+        case ::blink::WebReferrerPolicyNever:
+            return ::blink::mojom::ReferrerPolicy::NEVER;
+        case ::blink::WebReferrerPolicyOrigin:
+            return ::blink::mojom::ReferrerPolicy::ORIGIN;
+        case ::blink::WebReferrerPolicyOriginWhenCrossOrigin:
+            return ::blink::mojom::ReferrerPolicy::ORIGIN_WHEN_CROSS_ORIGIN;
+        case ::blink::WebReferrerPolicyNoReferrerWhenDowngradeOriginWhenCrossOrigin:
+            return ::blink::mojom::ReferrerPolicy::NO_REFERRER_WHEN_DOWNGRADE_ORIGIN_WHEN_CROSS_ORIGIN;
+        default:
+            NOTREACHED();
+            return ::blink::mojom::ReferrerPolicy::DEFAULT;
+        }
+    }
+
+    static bool FromMojom(::blink::mojom::ReferrerPolicy policy, ::blink::WebReferrerPolicy* out)
+    {
+        switch (policy) {
+        case ::blink::mojom::ReferrerPolicy::ALWAYS:
+            *out = ::blink::WebReferrerPolicyAlways;
+            return true;
+        case ::blink::mojom::ReferrerPolicy::DEFAULT:
+            *out = ::blink::WebReferrerPolicyDefault;
+            return true;
+        case ::blink::mojom::ReferrerPolicy::NO_REFERRER_WHEN_DOWNGRADE:
+            *out = ::blink::WebReferrerPolicyNoReferrerWhenDowngrade;
+            return true;
+        case ::blink::mojom::ReferrerPolicy::NEVER:
+            *out = ::blink::WebReferrerPolicyNever;
+            return true;
+        case ::blink::mojom::ReferrerPolicy::ORIGIN:
+            *out = ::blink::WebReferrerPolicyOrigin;
+            return true;
+        case ::blink::mojom::ReferrerPolicy::ORIGIN_WHEN_CROSS_ORIGIN:
+            *out = ::blink::WebReferrerPolicyOriginWhenCrossOrigin;
+            return true;
+        case ::blink::mojom::ReferrerPolicy::NO_REFERRER_WHEN_DOWNGRADE_ORIGIN_WHEN_CROSS_ORIGIN:
+            *out = ::blink::WebReferrerPolicyNoReferrerWhenDowngradeOriginWhenCrossOrigin;
+            return true;
+        default:
+            NOTREACHED();
+            return false;
+        }
+    }
+};
+
+} // namespace mojo
+
+#endif
diff --git a/third_party/WebKit/public/platform/WebGraphicsContext3DProvider.h b/third_party/WebKit/public/platform/WebGraphicsContext3DProvider.h
index 3a5bbe6..4aad7eb 100644
--- a/third_party/WebKit/public/platform/WebGraphicsContext3DProvider.h
+++ b/third_party/WebKit/public/platform/WebGraphicsContext3DProvider.h
@@ -31,7 +31,7 @@
 #ifndef WebGraphicsContext3DProvider_h
 #define WebGraphicsContext3DProvider_h
 
-#include "public/platform/functional/WebFunction.h"
+#include "base/callback_forward.h"
 
 class GrContext;
 
@@ -58,8 +58,8 @@
     // this scenario, the compositor would not be using GPU.
     virtual bool isSoftwareRendering() const = 0;
 
-    virtual void setLostContextCallback(WebClosure) = 0;
-    virtual void setErrorMessageCallback(WebFunction<void(const char* msg, int32_t id)>) = 0;
+    virtual void setLostContextCallback(const base::Closure&) = 0;
+    virtual void setErrorMessageCallback(const base::Callback<void(const char* msg, int32_t id)>&) = 0;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/public/platform/WebTaskRunner.h b/third_party/WebKit/public/platform/WebTaskRunner.h
index fa2705b..2516f6cc 100644
--- a/third_party/WebKit/public/platform/WebTaskRunner.h
+++ b/third_party/WebKit/public/platform/WebTaskRunner.h
@@ -6,6 +6,7 @@
 #define WebTaskRunner_h
 
 #include "WebCommon.h"
+#include "base/callback_forward.h"
 #include "public/platform/WebTraceLocation.h"
 #include <memory>
 
diff --git a/third_party/WebKit/public/platform/functional/DEPS b/third_party/WebKit/public/platform/functional/DEPS
deleted file mode 100644
index 4acb8d2..0000000
--- a/third_party/WebKit/public/platform/functional/DEPS
+++ /dev/null
@@ -1,9 +0,0 @@
-include_rules = [
-    # Bind/Callback is only allowed in rare cases, here it's allowed to convert
-    # from WTF::Function to base::Callback in order to pass callbacks out of
-    # blink.
-    "+base/bind.h",
-    "+base/callback.h",
-    "+base/logging.h",
-    "+base/macros.h",
-]
diff --git a/third_party/WebKit/public/platform/functional/WebFunction.h b/third_party/WebKit/public/platform/functional/WebFunction.h
deleted file mode 100644
index 0cfbd6a..0000000
--- a/third_party/WebKit/public/platform/functional/WebFunction.h
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef WebFunction_h
-#define WebFunction_h
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/macros.h"
-#include "public/platform/WebCommon.h"
-
-#include <memory>
-#include <utility>
-
-#if BLINK_IMPLEMENTATION
-#include "wtf/Functional.h"
-#else
-#include "base/logging.h"
-#endif
-
-namespace blink {
-
-template <typename...>
-class WebFunction;
-
-// Conversion from WTF closures to base closures to pass a callback out of
-// blink.
-template <typename R, typename... Args>
-class WebFunction<R(Args...)> {
-private:
-#if BLINK_IMPLEMENTATION
-    using WTFFunction = WTF::Function<R(Args...), WTF::SameThreadAffinity>;
-#endif
-
-public:
-#if BLINK_IMPLEMENTATION
-    WebFunction()
-    {
-    }
-
-    explicit WebFunction(std::unique_ptr<WTFFunction> c)
-    {
-        m_callback = convertToBaseCallback(std::move(c));
-    }
-#endif
-
-    WebFunction(WebFunction&& other)
-    {
-        *this = std::move(other);
-    }
-    WebFunction& operator=(WebFunction&& other)
-    {
-#if DCHECK_IS_ON()
-        m_haveClosure = other.m_haveClosure;
-        other.m_haveClosure = false;
-#endif
-        m_callback = std::move(other.m_callback);
-        return *this;
-    }
-
-#if !BLINK_IMPLEMENTATION
-    // TODO(danakj): This could be rvalue-ref-qualified.
-    base::Callback<R(Args...)> TakeBaseCallback()
-    {
-#if DCHECK_IS_ON()
-        // Don't call this more than once!
-        DCHECK(m_haveClosure);
-        m_haveClosure = false;
-#endif
-        return std::move(m_callback);
-    }
-#endif
-
-private:
-#if DCHECK_IS_ON()
-    bool m_haveClosure = true;
-#endif
-    base::Callback<R(Args...)> m_callback;
-
-    DISALLOW_COPY_AND_ASSIGN(WebFunction);
-};
-
-using WebClosure = WebFunction<void()>;
-
-} // namespace blink
-
-#endif // WebClosure_h
diff --git a/third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom b/third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom
index e3b8b63..bd5074b 100644
--- a/third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom
+++ b/third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom
@@ -67,7 +67,6 @@
   REQUEST_DEVICE_WITH_BLACKLISTED_UUID,
   REQUEST_DEVICE_FROM_CROSS_ORIGIN_IFRAME,
   REQUEST_DEVICE_WITHOUT_FRAME,
-  // SyntaxError:
   // TODO(ortuno): Remove once we no longer use IPC.
   ENUM_MAX_VALUE = REQUEST_DEVICE_WITHOUT_FRAME,
 };
diff --git a/third_party/WebKit/public/platform/referrer.mojom b/third_party/WebKit/public/platform/referrer.mojom
new file mode 100644
index 0000000..961640e
--- /dev/null
+++ b/third_party/WebKit/public/platform/referrer.mojom
@@ -0,0 +1,30 @@
+// 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.
+
+module blink.mojom;
+
+import "url/mojo/url.mojom";
+
+// Maps to blink::WebReferrerPolicy in
+// src/third_party/WebKit/public/platform/WebReferrerPolicy.h.
+//
+// TODO(rockot): Update all WebReferrerPolicy consumers to use this type
+// instead, and remove the typemap.
+enum ReferrerPolicy {
+    ALWAYS,
+    DEFAULT,
+    NO_REFERRER_WHEN_DOWNGRADE,
+    NEVER,
+    ORIGIN,
+    ORIGIN_WHEN_CROSS_ORIGIN,
+    NO_REFERRER_WHEN_DOWNGRADE_ORIGIN_WHEN_CROSS_ORIGIN,
+};
+
+// This struct holds a referrer URL, as well as the referrer policy to be
+// applied to this URL. When passing around referrers that will eventually end
+// up being used for URL requests, always use this struct.
+struct Referrer {
+  url.mojom.Url url;
+  ReferrerPolicy policy;
+};
diff --git a/third_party/WebKit/public/platform/referrer_policy.typemap b/third_party/WebKit/public/platform/referrer_policy.typemap
new file mode 100644
index 0000000..ba2ee7d
--- /dev/null
+++ b/third_party/WebKit/public/platform/referrer_policy.typemap
@@ -0,0 +1,9 @@
+# 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.
+
+mojom = "//third_party/WebKit/public/platform/referrer.mojom"
+public_headers = [ "//third_party/WebKit/public/platform/WebReferrerPolicy.h" ]
+traits_headers =
+    [ "//third_party/WebKit/public/platform/ReferrerPolicyEnumTraits.h" ]
+type_mappings = [ "blink.mojom.ReferrerPolicy=::blink::WebReferrerPolicy" ]
diff --git a/third_party/WebKit/public/public_typemaps.gni b/third_party/WebKit/public/public_typemaps.gni
new file mode 100644
index 0000000..01301e2
--- /dev/null
+++ b/third_party/WebKit/public/public_typemaps.gni
@@ -0,0 +1,9 @@
+# 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.
+
+# These are typemaps which are shared between Blink public and its embedder.
+typemaps = [
+  "//third_party/WebKit/public/platform/referrer_policy.typemap",
+  "//third_party/WebKit/public/web/window_features.typemap",
+]
diff --git a/third_party/WebKit/public/web/DEPS b/third_party/WebKit/public/web/DEPS
index 1167e07f..002f14a 100644
--- a/third_party/WebKit/public/web/DEPS
+++ b/third_party/WebKit/public/web/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
     "+../platform",
     "+core",
+    "+mojo/public",
     "+platform",
     "+public/platform",
     "+public/web",
diff --git a/third_party/WebKit/public/web/OWNERS b/third_party/WebKit/public/web/OWNERS
index 30c7b9c3..cee6c11 100644
--- a/third_party/WebKit/public/web/OWNERS
+++ b/third_party/WebKit/public/web/OWNERS
@@ -4,3 +4,8 @@
 # Page load metrics
 per-file WebPerformance.h=bmcquade@chromium.org
 per-file WebPerformance.h=csharrison@chromium.org
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+per-file *StructTraits*.*=set noparent
+per-file *StructTraits*.*=file://ipc/SECURITY_OWNERS
diff --git a/third_party/WebKit/public/web/WebFrameClient.h b/third_party/WebKit/public/web/WebFrameClient.h
index e2c7a20..c0707d3 100644
--- a/third_party/WebKit/public/web/WebFrameClient.h
+++ b/third_party/WebKit/public/web/WebFrameClient.h
@@ -83,6 +83,7 @@
 class WebFileChooserCompletion;
 class WebFormElement;
 class WebInstalledAppClient;
+class WebLocalFrame;
 class WebMediaPlayer;
 class WebMediaPlayerClient;
 class WebMediaPlayerEncryptedMediaClient;
@@ -108,8 +109,10 @@
 struct WebRect;
 struct WebURLError;
 
-class WebFrameClient {
+class BLINK_EXPORT WebFrameClient {
 public:
+    virtual ~WebFrameClient() {}
+
     // Factory methods -----------------------------------------------------
 
     // May return null.
@@ -156,13 +159,11 @@
     // pending navigation's URL, because a URL spoof is possible.
     virtual void didAccessInitialDocument() { }
 
-    // A child frame was created in this frame. This is called when the frame
-    // is created and initialized. Takes the name of the new frame, the parent
-    // frame and returns a new WebFrame. The WebFrame is considered in-use
-    // until frameDetached() is called on it.
-    // Note: If you override this, you should almost certainly be overriding
-    // frameDetached().
-    virtual WebFrame* createChildFrame(WebLocalFrame* parent, WebTreeScopeType, const WebString& name, const WebString& uniqueName, WebSandboxFlags sandboxFlags, const WebFrameOwnerProperties&) { return nullptr; }
+    // Request the creation of a new child frame. Embedders may return nullptr
+    // to prevent the new child frame from being attached. Otherwise, embedders
+    // should create a new WebLocalFrame, insert it into the frame tree, and
+    // return the created frame.
+    virtual WebLocalFrame* createChildFrame(WebLocalFrame* parent, WebTreeScopeType, const WebString& name, const WebString& uniqueName, WebSandboxFlags sandboxFlags, const WebFrameOwnerProperties&) { return nullptr; }
 
     // This frame has set its opener to another frame, or disowned the opener
     // if opener is null. See http://html.spec.whatwg.org/#dom-opener.
@@ -171,15 +172,17 @@
     // Specifies the reason for the detachment.
     enum class DetachType { Remove, Swap };
 
-    // This frame has been detached from the view, but has not been closed yet.
-    virtual void frameDetached(WebLocalFrame*, DetachType) {}
+    // This frame has been detached. Embedders should release any resources
+    // associated with this frame. If the DetachType is Remove, the frame should
+    // also be removed from the frame tree; otherwise, if the DetachType is
+    // Swap, the frame is being replaced in-place by WebFrame::swap().
+    virtual void frameDetached(WebLocalFrame*, DetachType);
 
-    // This frame has become focused..
+    // This frame has become focused.
     virtual void frameFocused() { }
 
-    // This frame is about to be closed. This is called after frameDetached,
-    // when the document is being unloaded, due to new one committing.
-    virtual void willClose(WebFrame*) { }
+    // A provisional load is about to commit.
+    virtual void willCommitProvisionalLoad(WebLocalFrame*) {}
 
     // This frame's name has changed.
     virtual void didChangeName(const WebString& name, const WebString& uniqueName) { }
@@ -693,9 +696,6 @@
     {
         return WebURL();
     }
-
-protected:
-    virtual ~WebFrameClient() { }
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/public/web/WebLocalFrame.h b/third_party/WebKit/public/web/WebLocalFrame.h
index dc4815d..39814cc 100644
--- a/third_party/WebKit/public/web/WebLocalFrame.h
+++ b/third_party/WebKit/public/web/WebLocalFrame.h
@@ -37,7 +37,7 @@
 class WebLocalFrame : public WebFrame {
 public:
     // Creates a WebFrame. Delete this WebFrame by calling WebFrame::close().
-    // It is valid to pass a null client pointer.
+    // WebFrameClient may not be null.
     BLINK_EXPORT static WebLocalFrame* create(WebTreeScopeType, WebFrameClient*, WebFrame* opener = nullptr);
 
     // Used to create a provisional local frame in prepration for replacing a
diff --git a/third_party/WebKit/public/web/WebSettings.h b/third_party/WebKit/public/web/WebSettings.h
index 3ba8df2..bdc6ee9d 100644
--- a/third_party/WebKit/public/web/WebSettings.h
+++ b/third_party/WebKit/public/web/WebSettings.h
@@ -238,6 +238,7 @@
     // event handlers specified. User can also trigger click handlers for such
     // elements using SPACE or ENTER keys.
     virtual void setSpatialNavigationEnabled(bool) = 0;
+    virtual void setSpellCheckEnabledByDefault(bool) = 0;
     virtual void setStandardFontFamily(const WebString&, UScriptCode = USCRIPT_COMMON) = 0;
     virtual void setStrictMixedContentChecking(bool) = 0;
     virtual void setStrictMixedContentCheckingForPlugin(bool) = 0;
diff --git a/third_party/WebKit/public/web/WebUserMediaClient.h b/third_party/WebKit/public/web/WebUserMediaClient.h
index 02f337e..76a5b5af 100644
--- a/third_party/WebKit/public/web/WebUserMediaClient.h
+++ b/third_party/WebKit/public/web/WebUserMediaClient.h
@@ -45,7 +45,6 @@
     virtual void requestUserMedia(const WebUserMediaRequest&) = 0;
     virtual void cancelUserMediaRequest(const WebUserMediaRequest&) = 0;
     virtual void requestMediaDevices(const WebMediaDevicesRequest&) = 0;
-    virtual void cancelMediaDevicesRequest(const WebMediaDevicesRequest&) = 0;
     virtual void requestSources(const WebMediaStreamTrackSourcesRequest&) = 0;
     virtual void setMediaDeviceChangeObserver(const WebMediaDeviceChangeObserver&) = 0;
 };
diff --git a/third_party/WebKit/public/web/WindowFeaturesStructTraits.cpp b/third_party/WebKit/public/web/WindowFeaturesStructTraits.cpp
new file mode 100644
index 0000000..64d9fab2
--- /dev/null
+++ b/third_party/WebKit/public/web/WindowFeaturesStructTraits.cpp
@@ -0,0 +1,34 @@
+// 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.
+
+#include "third_party/WebKit/public/web/WindowFeaturesStructTraits.h"
+
+namespace mojo {
+
+// static
+bool
+StructTraits<::blink::mojom::WindowFeaturesDataView, ::blink::WebWindowFeatures>::Read(
+    ::blink::mojom::WindowFeaturesDataView data,
+    ::blink::WebWindowFeatures* out)
+{
+    out->x = data.x();
+    out->xSet = data.has_x();
+    out->y = data.y();
+    out->ySet = data.has_y();
+    out->width = data.width();
+    out->widthSet = data.has_width();
+    out->height = data.height();
+    out->heightSet = data.has_height();
+    out->menuBarVisible = data.menu_bar_visible();
+    out->statusBarVisible = data.status_bar_visible();
+    out->toolBarVisible = data.tool_bar_visible();
+    out->locationBarVisible = data.location_bar_visible();
+    out->scrollbarsVisible = data.scrollbars_visible();
+    out->resizable = data.resizable();
+    out->fullscreen = data.fullscreen();
+    out->dialog = data.dialog();
+    return true;
+}
+
+} // namespace mojo
diff --git a/third_party/WebKit/public/web/WindowFeaturesStructTraits.h b/third_party/WebKit/public/web/WindowFeaturesStructTraits.h
new file mode 100644
index 0000000..e327adc8
--- /dev/null
+++ b/third_party/WebKit/public/web/WindowFeaturesStructTraits.h
@@ -0,0 +1,40 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WindowFeaturesStructTraits_h
+#define WindowFeaturesStructTraits_h
+
+#include "WebWindowFeatures.h"
+#include "mojo/public/cpp/bindings/struct_traits.h"
+#include "third_party/WebKit/public/web/window_features.mojom-shared.h"
+
+namespace mojo {
+
+template <>
+struct StructTraits<::blink::mojom::WindowFeaturesDataView, ::blink::WebWindowFeatures> {
+    static float x(const ::blink::WebWindowFeatures& features) { return features.x; }
+    static bool has_x(const ::blink::WebWindowFeatures& features) { return features.xSet; }
+    static float y(const ::blink::WebWindowFeatures& features) { return features.y; }
+    static bool has_y(const ::blink::WebWindowFeatures& features) { return features.ySet; }
+    static float width(const ::blink::WebWindowFeatures& features) { return features.width; }
+    static bool has_width(const ::blink::WebWindowFeatures& features) { return features.widthSet; }
+    static float height(const ::blink::WebWindowFeatures& features) { return features.height; }
+    static bool has_height(const ::blink::WebWindowFeatures& features) { return features.heightSet; }
+
+    static bool menu_bar_visible(const ::blink::WebWindowFeatures& features) { return features.menuBarVisible; }
+    static bool status_bar_visible(const ::blink::WebWindowFeatures& features) { return features.statusBarVisible; }
+    static bool tool_bar_visible(const ::blink::WebWindowFeatures& features) { return features.toolBarVisible; }
+    static bool location_bar_visible(const ::blink::WebWindowFeatures& features) { return features.locationBarVisible; }
+    static bool scrollbars_visible(const ::blink::WebWindowFeatures& features) { return features.scrollbarsVisible; }
+    static bool resizable(const ::blink::WebWindowFeatures& features) { return features.resizable; }
+
+    static bool fullscreen(const ::blink::WebWindowFeatures& features) { return features.fullscreen; }
+    static bool dialog(const ::blink::WebWindowFeatures& features) { return features.dialog; }
+
+    static bool Read(::blink::mojom::WindowFeaturesDataView, ::blink::WebWindowFeatures* out);
+};
+
+} // namespace mojo
+
+#endif
diff --git a/third_party/WebKit/public/web/window_features.mojom b/third_party/WebKit/public/web/window_features.mojom
new file mode 100644
index 0000000..a26b8a3b4
--- /dev/null
+++ b/third_party/WebKit/public/web/window_features.mojom
@@ -0,0 +1,33 @@
+// 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.
+
+module blink.mojom;
+
+struct WindowFeatures {
+    float x;
+    bool has_x = false;
+
+    float y;
+    bool has_y = false;
+
+    float width;
+    bool has_width = false;
+
+    float height;
+    bool has_height = false;
+
+    bool menu_bar_visible = true;
+    bool status_bar_visible = true;
+    bool tool_bar_visible = true;
+    bool location_bar_visible = true;
+    bool scrollbars_visible = true;
+    bool resizable = true;
+
+    bool fullscreen = false;
+    bool dialog = false;
+
+    // NOTE: WebWindowFeatures::additionalFeatures is not mirrored by this
+    // mojom struct as it's never used by the browser and therefore doesn't need
+    // to be sent.
+};
diff --git a/third_party/WebKit/public/web/window_features.typemap b/third_party/WebKit/public/web/window_features.typemap
new file mode 100644
index 0000000..6bc6941
--- /dev/null
+++ b/third_party/WebKit/public/web/window_features.typemap
@@ -0,0 +1,12 @@
+# 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.
+
+mojom = "//third_party/WebKit/public/web/window_features.mojom"
+public_headers = [ "//third_party/WebKit/public/web/WebWindowFeatures.h" ]
+traits_headers =
+    [ "//third_party/WebKit/public/web/WindowFeaturesStructTraits.h" ]
+deps = [
+  "//third_party/WebKit/public:shared_typemap_traits",
+]
+type_mappings = [ "blink.mojom.WindowFeatures=::blink::WebWindowFeatures" ]
diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium
index df412bb..4853b70 100644
--- a/third_party/crashpad/README.chromium
+++ b/third_party/crashpad/README.chromium
@@ -2,7 +2,7 @@
 Short Name: crashpad
 URL: https://crashpad.chromium.org/
 Version: unknown
-Revision: ac6c01b5752ecb1aa1da0ea613740cf6825bb72e
+Revision: 5a6c961658ffc4b0bcb3bbad666d45d3ad27f6c8
 License: Apache 2.0
 License File: crashpad/LICENSE
 Security Critical: yes
diff --git a/third_party/crashpad/crashpad/handler/handler_main.cc b/third_party/crashpad/crashpad/handler/handler_main.cc
index ad6d5ac..8749c58 100644
--- a/third_party/crashpad/crashpad/handler/handler_main.cc
+++ b/third_party/crashpad/crashpad/handler/handler_main.cc
@@ -120,9 +120,20 @@
 
 #endif  // OS_MACOSX
 
+#if defined(OS_WIN)
+LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) {
+  Metrics::HandlerCrashed(exception_pointers->ExceptionRecord->ExceptionCode);
+  return EXCEPTION_CONTINUE_SEARCH;
+}
+#endif
+
 }  // namespace
 
 int HandlerMain(int argc, char* argv[]) {
+#if defined(OS_WIN)
+  SetUnhandledExceptionFilter(&UnhandledExceptionHandler);
+#endif
+
   const base::FilePath argv0(
       ToolSupport::CommandLineArgumentToFilePathStringType(argv[0]));
   const base::FilePath me(argv0.BaseName());
diff --git a/third_party/crashpad/crashpad/util/misc/metrics.cc b/third_party/crashpad/crashpad/util/misc/metrics.cc
index db7718b..f5ab07b 100644
--- a/third_party/crashpad/crashpad/util/misc/metrics.cc
+++ b/third_party/crashpad/crashpad/util/misc/metrics.cc
@@ -93,4 +93,16 @@
   ExceptionProcessing(ExceptionProcessingState::kStarted);
 }
 
+void Metrics::HandlerCrashed(uint32_t exception_code) {
+#if defined(OS_WIN)
+  static const char kExceptionCodeString[] =
+      "Crashpad.HandlerCrash.ExceptionCode.Win";
+#elif defined(OS_MACOSX)
+  static const char kExceptionCodeString[] =
+      "Crashpad.HandlerCrash.ExceptionCode.Mac";
+#endif
+  UMA_HISTOGRAM_SPARSE_SLOWLY(kExceptionCodeString,
+                              static_cast<int32_t>(exception_code));
+}
+
 }  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/util/misc/metrics.h b/third_party/crashpad/crashpad/util/misc/metrics.h
index 18666bec..a6a7f986 100644
--- a/third_party/crashpad/crashpad/util/misc/metrics.h
+++ b/third_party/crashpad/crashpad/util/misc/metrics.h
@@ -130,6 +130,11 @@
   //! \brief The exception handler server started capturing an exception.
   static void ExceptionEncountered();
 
+  //! \brief The handler process crashed with the given exception code.
+  //!
+  //! This is currently only reported on Windows.
+  static void HandlerCrashed(uint32_t exception_code);
+
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(Metrics);
 };
diff --git a/third_party/sqlite/amalgamation/sqlite3.c b/third_party/sqlite/amalgamation/sqlite3.c
index 58981ca9..97d1ab99 100644
--- a/third_party/sqlite/amalgamation/sqlite3.c
+++ b/third_party/sqlite/amalgamation/sqlite3.c
@@ -26285,36 +26285,21 @@
     return sqlite3AddInt64(pA, -iB);
   }
 }
-#define TWOPOWER32 (((i64)1)<<32)
-#define TWOPOWER31 (((i64)1)<<31)
 SQLITE_PRIVATE int sqlite3MulInt64(i64 *pA, i64 iB){
   i64 iA = *pA;
-  i64 iA1, iA0, iB1, iB0, r;
-
-  iA1 = iA/TWOPOWER32;
-  iA0 = iA % TWOPOWER32;
-  iB1 = iB/TWOPOWER32;
-  iB0 = iB % TWOPOWER32;
-  if( iA1==0 ){
-    if( iB1==0 ){
-      *pA *= iB;
-      return 0;
+  if( iB>0 ){
+    if( iA>LARGEST_INT64/iB ) return 1;
+    if( iA<SMALLEST_INT64/iB ) return 1;
+  }else if( iB<0 ){
+    if( iA>0 ){
+      if( iB<SMALLEST_INT64/iA ) return 1;
+    }else if( iA<0 ){
+      if( iB==SMALLEST_INT64 ) return 1;
+      if( iA==SMALLEST_INT64 ) return 1;
+      if( -iA>LARGEST_INT64/-iB ) return 1;
     }
-    r = iA0*iB1;
-  }else if( iB1==0 ){
-    r = iA1*iB0;
-  }else{
-    /* If both iA1 and iB1 are non-zero, overflow will result */
-    return 1;
   }
-  testcase( r==(-TWOPOWER31)-1 );
-  testcase( r==(-TWOPOWER31) );
-  testcase( r==TWOPOWER31 );
-  testcase( r==TWOPOWER31-1 );
-  if( r<(-TWOPOWER31) || r>=TWOPOWER31 ) return 1;
-  r *= TWOPOWER32;
-  if( sqlite3AddInt64(&r, iA0*iB0) ) return 1;
-  *pA = r;
+  *pA = iA*iB;
   return 0;
 }
 
diff --git a/third_party/sqlite/patches/0014-backport-Address-integer-overflow-in-sqlite3MulInt64.patch b/third_party/sqlite/patches/0014-backport-Address-integer-overflow-in-sqlite3MulInt64.patch
new file mode 100644
index 0000000..19a5210
--- /dev/null
+++ b/third_party/sqlite/patches/0014-backport-Address-integer-overflow-in-sqlite3MulInt64.patch
@@ -0,0 +1,112 @@
+From 7bcd4f0f17fb5bb6ae11be6ef0b70197195f2d61 Mon Sep 17 00:00:00 2001
+From: Scott Hess <shess@chromium.org>
+Date: Fri, 23 Sep 2016 09:54:14 -0700
+Subject: [PATCH 14/14] [backport] Address integer overflow in sqlite3MulInt64.
+
+SQLite check-in http://www.sqlite.org/src/info/db3ebd7c52cfc5fc
+
+"Improved implementation of 64-bit signed integer multiply that
+correctly detects overflow (and promotes to floating-point) in some
+corner cases. Fix for ticket [1ec41379c9c1e400]"
+
+http://www.sqlite.org/src/info/1ec41379c9c1e400"
+
+BUG=601727
+---
+ third_party/sqlite/src/src/util.c     | 37 +++++++++++------------------------
+ third_party/sqlite/src/test/expr.test | 27 +++++++++++++++++++++++++
+ 2 files changed, 38 insertions(+), 26 deletions(-)
+
+diff --git a/third_party/sqlite/src/src/util.c b/third_party/sqlite/src/src/util.c
+index b4c5e62..7640f1d 100644
+--- a/third_party/sqlite/src/src/util.c
++++ b/third_party/sqlite/src/src/util.c
+@@ -1244,36 +1244,21 @@ int sqlite3SubInt64(i64 *pA, i64 iB){
+     return sqlite3AddInt64(pA, -iB);
+   }
+ }
+-#define TWOPOWER32 (((i64)1)<<32)
+-#define TWOPOWER31 (((i64)1)<<31)
+ int sqlite3MulInt64(i64 *pA, i64 iB){
+   i64 iA = *pA;
+-  i64 iA1, iA0, iB1, iB0, r;
+-
+-  iA1 = iA/TWOPOWER32;
+-  iA0 = iA % TWOPOWER32;
+-  iB1 = iB/TWOPOWER32;
+-  iB0 = iB % TWOPOWER32;
+-  if( iA1==0 ){
+-    if( iB1==0 ){
+-      *pA *= iB;
+-      return 0;
++  if( iB>0 ){
++    if( iA>LARGEST_INT64/iB ) return 1;
++    if( iA<SMALLEST_INT64/iB ) return 1;
++  }else if( iB<0 ){
++    if( iA>0 ){
++      if( iB<SMALLEST_INT64/iA ) return 1;
++    }else if( iA<0 ){
++      if( iB==SMALLEST_INT64 ) return 1;
++      if( iA==SMALLEST_INT64 ) return 1;
++      if( -iA>LARGEST_INT64/-iB ) return 1;
+     }
+-    r = iA0*iB1;
+-  }else if( iB1==0 ){
+-    r = iA1*iB0;
+-  }else{
+-    /* If both iA1 and iB1 are non-zero, overflow will result */
+-    return 1;
+   }
+-  testcase( r==(-TWOPOWER31)-1 );
+-  testcase( r==(-TWOPOWER31) );
+-  testcase( r==TWOPOWER31 );
+-  testcase( r==TWOPOWER31-1 );
+-  if( r<(-TWOPOWER31) || r>=TWOPOWER31 ) return 1;
+-  r *= TWOPOWER32;
+-  if( sqlite3AddInt64(&r, iA0*iB0) ) return 1;
+-  *pA = r;
++  *pA = iA*iB;
+   return 0;
+ }
+ 
+diff --git a/third_party/sqlite/src/test/expr.test b/third_party/sqlite/src/test/expr.test
+index 7d7b8ce..7a6d477 100644
+--- a/third_party/sqlite/src/test/expr.test
++++ b/third_party/sqlite/src/test/expr.test
+@@ -308,6 +308,33 @@ ifcapable floatingpoint {if {[working_64bit_int]} {
+   test_realnum_expr expr-1.257\
+       {i1=-4294967296, i2=-2147483647} {i1*i2}    9223372032559808512
+ 
++  test_realnum_expr expr-1.260\
++      {i1=3037000500, i2=3037000500} {i1*i2}      9.22337203700025e+18
++  test_realnum_expr expr-1.261\
++      {i1=3037000500, i2=-3037000500} {i1*i2}     -9.22337203700025e+18
++  test_realnum_expr expr-1.262\
++      {i1=-3037000500, i2=3037000500} {i1*i2}     -9.22337203700025e+18
++  test_realnum_expr expr-1.263\
++      {i1=-3037000500, i2=-3037000500} {i1*i2}    9.22337203700025e+18
++
++  test_realnum_expr expr-1.264\
++      {i1=3037000500, i2=3037000499} {i1*i2}      9223372033963249500
++  test_realnum_expr expr-1.265\
++      {i1=3037000500, i2=-3037000499} {i1*i2}     -9223372033963249500
++  test_realnum_expr expr-1.266\
++      {i1=-3037000500, i2=3037000499} {i1*i2}     -9223372033963249500
++  test_realnum_expr expr-1.267\
++      {i1=-3037000500, i2=-3037000499} {i1*i2}    9223372033963249500
++
++  test_realnum_expr expr-1.268\
++      {i1=3037000499, i2=3037000500} {i1*i2}      9223372033963249500
++  test_realnum_expr expr-1.269\
++      {i1=3037000499, i2=-3037000500} {i1*i2}     -9223372033963249500
++  test_realnum_expr expr-1.270\
++      {i1=-3037000499, i2=3037000500} {i1*i2}     -9223372033963249500
++  test_realnum_expr expr-1.271\
++      {i1=-3037000499, i2=-3037000500} {i1*i2}    9223372033963249500
++
+ }}
+ 
+ ifcapable floatingpoint {
+-- 
+2.5.0
+
diff --git a/third_party/sqlite/src/src/util.c b/third_party/sqlite/src/src/util.c
index b4c5e62..7640f1d 100644
--- a/third_party/sqlite/src/src/util.c
+++ b/third_party/sqlite/src/src/util.c
@@ -1244,36 +1244,21 @@
     return sqlite3AddInt64(pA, -iB);
   }
 }
-#define TWOPOWER32 (((i64)1)<<32)
-#define TWOPOWER31 (((i64)1)<<31)
 int sqlite3MulInt64(i64 *pA, i64 iB){
   i64 iA = *pA;
-  i64 iA1, iA0, iB1, iB0, r;
-
-  iA1 = iA/TWOPOWER32;
-  iA0 = iA % TWOPOWER32;
-  iB1 = iB/TWOPOWER32;
-  iB0 = iB % TWOPOWER32;
-  if( iA1==0 ){
-    if( iB1==0 ){
-      *pA *= iB;
-      return 0;
+  if( iB>0 ){
+    if( iA>LARGEST_INT64/iB ) return 1;
+    if( iA<SMALLEST_INT64/iB ) return 1;
+  }else if( iB<0 ){
+    if( iA>0 ){
+      if( iB<SMALLEST_INT64/iA ) return 1;
+    }else if( iA<0 ){
+      if( iB==SMALLEST_INT64 ) return 1;
+      if( iA==SMALLEST_INT64 ) return 1;
+      if( -iA>LARGEST_INT64/-iB ) return 1;
     }
-    r = iA0*iB1;
-  }else if( iB1==0 ){
-    r = iA1*iB0;
-  }else{
-    /* If both iA1 and iB1 are non-zero, overflow will result */
-    return 1;
   }
-  testcase( r==(-TWOPOWER31)-1 );
-  testcase( r==(-TWOPOWER31) );
-  testcase( r==TWOPOWER31 );
-  testcase( r==TWOPOWER31-1 );
-  if( r<(-TWOPOWER31) || r>=TWOPOWER31 ) return 1;
-  r *= TWOPOWER32;
-  if( sqlite3AddInt64(&r, iA0*iB0) ) return 1;
-  *pA = r;
+  *pA = iA*iB;
   return 0;
 }
 
diff --git a/third_party/sqlite/src/test/expr.test b/third_party/sqlite/src/test/expr.test
index 7d7b8ce..7a6d477 100644
--- a/third_party/sqlite/src/test/expr.test
+++ b/third_party/sqlite/src/test/expr.test
@@ -308,6 +308,33 @@
   test_realnum_expr expr-1.257\
       {i1=-4294967296, i2=-2147483647} {i1*i2}    9223372032559808512
 
+  test_realnum_expr expr-1.260\
+      {i1=3037000500, i2=3037000500} {i1*i2}      9.22337203700025e+18
+  test_realnum_expr expr-1.261\
+      {i1=3037000500, i2=-3037000500} {i1*i2}     -9.22337203700025e+18
+  test_realnum_expr expr-1.262\
+      {i1=-3037000500, i2=3037000500} {i1*i2}     -9.22337203700025e+18
+  test_realnum_expr expr-1.263\
+      {i1=-3037000500, i2=-3037000500} {i1*i2}    9.22337203700025e+18
+
+  test_realnum_expr expr-1.264\
+      {i1=3037000500, i2=3037000499} {i1*i2}      9223372033963249500
+  test_realnum_expr expr-1.265\
+      {i1=3037000500, i2=-3037000499} {i1*i2}     -9223372033963249500
+  test_realnum_expr expr-1.266\
+      {i1=-3037000500, i2=3037000499} {i1*i2}     -9223372033963249500
+  test_realnum_expr expr-1.267\
+      {i1=-3037000500, i2=-3037000499} {i1*i2}    9223372033963249500
+
+  test_realnum_expr expr-1.268\
+      {i1=3037000499, i2=3037000500} {i1*i2}      9223372033963249500
+  test_realnum_expr expr-1.269\
+      {i1=3037000499, i2=-3037000500} {i1*i2}     -9223372033963249500
+  test_realnum_expr expr-1.270\
+      {i1=-3037000499, i2=3037000500} {i1*i2}     -9223372033963249500
+  test_realnum_expr expr-1.271\
+      {i1=-3037000499, i2=-3037000500} {i1*i2}    9223372033963249500
+
 }}
 
 ifcapable floatingpoint {
diff --git a/tools/android/forwarder/BUILD.gn b/tools/android/forwarder/BUILD.gn
deleted file mode 100644
index 548af39..0000000
--- a/tools/android/forwarder/BUILD.gn
+++ /dev/null
@@ -1,16 +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.
-
-import("//build/symlink.gni")
-
-executable("forwarder") {
-  sources = [
-    "forwarder.cc",
-  ]
-  deps = [
-    "//base",
-    "//build/config/sanitizers:deps",
-    "//tools/android/common",
-  ]
-}
diff --git a/tools/android/forwarder/forwarder.cc b/tools/android/forwarder/forwarder.cc
deleted file mode 100644
index e72c3bd9..0000000
--- a/tools/android/forwarder/forwarder.cc
+++ /dev/null
@@ -1,428 +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 <errno.h>
-#include <fcntl.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <pthread.h>
-#include <signal.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/select.h>
-#include <sys/socket.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/posix/eintr_wrapper.h"
-#include "tools/android/common/adb_connection.h"
-#include "tools/android/common/daemon.h"
-#include "tools/android/common/net.h"
-
-namespace {
-
-const pthread_t kInvalidThread = static_cast<pthread_t>(-1);
-volatile bool g_killed = false;
-
-void CloseSocket(int fd) {
-  if (fd >= 0) {
-    int old_errno = errno;
-    close(fd);
-    errno = old_errno;
-  }
-}
-
-class Buffer {
- public:
-  Buffer()
-      : bytes_read_(0),
-        write_offset_(0) {
-  }
-
-  bool CanRead() {
-    return bytes_read_ == 0;
-  }
-
-  bool CanWrite() {
-    return write_offset_ < bytes_read_;
-  }
-
-  int Read(int fd) {
-    int ret = -1;
-    if (CanRead()) {
-      ret = HANDLE_EINTR(read(fd, buffer_, kBufferSize));
-      if (ret > 0)
-        bytes_read_ = ret;
-    }
-    return ret;
-  }
-
-  int Write(int fd) {
-    int ret = -1;
-    if (CanWrite()) {
-      ret = HANDLE_EINTR(write(fd, buffer_ + write_offset_,
-                               bytes_read_ - write_offset_));
-      if (ret > 0) {
-        write_offset_ += ret;
-        if (write_offset_ == bytes_read_) {
-          write_offset_ = 0;
-          bytes_read_ = 0;
-        }
-      }
-    }
-    return ret;
-  }
-
- private:
-  // A big buffer to let our file-over-http bridge work more like real file.
-  static const int kBufferSize = 1024 * 128;
-  int bytes_read_;
-  int write_offset_;
-  char buffer_[kBufferSize];
-
-  DISALLOW_COPY_AND_ASSIGN(Buffer);
-};
-
-class Server;
-
-struct ForwarderThreadInfo {
-  ForwarderThreadInfo(Server* a_server, int a_forwarder_index)
-      : server(a_server),
-        forwarder_index(a_forwarder_index) {
-  }
-  Server* server;
-  int forwarder_index;
-};
-
-struct ForwarderInfo {
-  time_t start_time;
-  int socket1;
-  time_t socket1_last_byte_time;
-  size_t socket1_bytes;
-  int socket2;
-  time_t socket2_last_byte_time;
-  size_t socket2_bytes;
-};
-
-class Server {
- public:
-  Server()
-      : thread_(kInvalidThread),
-        socket_(-1) {
-    memset(forward_to_, 0, sizeof(forward_to_));
-    memset(&forwarders_, 0, sizeof(forwarders_));
-  }
-
-  int GetFreeForwarderIndex() {
-    for (int i = 0; i < kMaxForwarders; i++) {
-      if (forwarders_[i].start_time == 0)
-        return i;
-    }
-    return -1;
-  }
-
-  void DisposeForwarderInfo(int index) {
-    forwarders_[index].start_time = 0;
-  }
-
-  ForwarderInfo* GetForwarderInfo(int index) {
-    return &forwarders_[index];
-  }
-
-  void DumpInformation() {
-    LOG(INFO) << "Server information: " << forward_to_;
-    LOG(INFO) << "No.: age up(bytes,idle) down(bytes,idle)";
-    int count = 0;
-    time_t now = time(NULL);
-    for (int i = 0; i < kMaxForwarders; i++) {
-      const ForwarderInfo& info = forwarders_[i];
-      if (info.start_time) {
-        count++;
-        LOG(INFO) << count << ": " << now - info.start_time << " up("
-                  << info.socket1_bytes << ","
-                  << now - info.socket1_last_byte_time << " down("
-                  << info.socket2_bytes << ","
-                  << now - info.socket2_last_byte_time << ")";
-      }
-    }
-  }
-
-  void Shutdown() {
-    if (socket_ >= 0)
-      shutdown(socket_, SHUT_RDWR);
-  }
-
-  bool InitSocket(const char* arg);
-
-  void StartThread() {
-    pthread_create(&thread_, NULL, ServerThread, this);
-  }
-
-  void JoinThread() {
-    if (thread_ != kInvalidThread)
-      pthread_join(thread_, NULL);
-  }
-
- private:
-  static void* ServerThread(void* arg);
-
-  // There are 3 kinds of threads that will access the array:
-  // 1. Server thread will get a free ForwarderInfo and initialize it;
-  // 2. Forwarder threads will dispose the ForwarderInfo when it finishes;
-  // 3. Main thread will iterate and print the forwarders.
-  // Using an array is not optimal, but can avoid locks or other complex
-  // inter-thread communication.
-  static const int kMaxForwarders = 512;
-  ForwarderInfo forwarders_[kMaxForwarders];
-
-  pthread_t thread_;
-  int socket_;
-  char forward_to_[40];
-
-  DISALLOW_COPY_AND_ASSIGN(Server);
-};
-
-// Forwards all outputs from one socket to another socket.
-void* ForwarderThread(void* arg) {
-  ForwarderThreadInfo* thread_info =
-      reinterpret_cast<ForwarderThreadInfo*>(arg);
-  Server* server = thread_info->server;
-  int index = thread_info->forwarder_index;
-  delete thread_info;
-  ForwarderInfo* info = server->GetForwarderInfo(index);
-  int socket1 = info->socket1;
-  int socket2 = info->socket2;
-  int nfds = socket1 > socket2 ? socket1 + 1 : socket2 + 1;
-  fd_set read_fds;
-  fd_set write_fds;
-  Buffer buffer1;
-  Buffer buffer2;
-
-  while (!g_killed) {
-    FD_ZERO(&read_fds);
-    if (buffer1.CanRead())
-      FD_SET(socket1, &read_fds);
-    if (buffer2.CanRead())
-      FD_SET(socket2, &read_fds);
-
-    FD_ZERO(&write_fds);
-    if (buffer1.CanWrite())
-      FD_SET(socket2, &write_fds);
-    if (buffer2.CanWrite())
-      FD_SET(socket1, &write_fds);
-
-    if (HANDLE_EINTR(select(nfds, &read_fds, &write_fds, NULL, NULL)) <= 0) {
-      LOG(ERROR) << "Select error: " << strerror(errno);
-      break;
-    }
-
-    int now = time(NULL);
-    if (FD_ISSET(socket1, &read_fds)) {
-      info->socket1_last_byte_time = now;
-      int bytes = buffer1.Read(socket1);
-      if (bytes <= 0)
-        break;
-      info->socket1_bytes += bytes;
-    }
-    if (FD_ISSET(socket2, &read_fds)) {
-      info->socket2_last_byte_time = now;
-      int bytes = buffer2.Read(socket2);
-      if (bytes <= 0)
-        break;
-      info->socket2_bytes += bytes;
-    }
-    if (FD_ISSET(socket1, &write_fds)) {
-      if (buffer2.Write(socket1) <= 0)
-        break;
-    }
-    if (FD_ISSET(socket2, &write_fds)) {
-      if (buffer1.Write(socket2) <= 0)
-        break;
-    }
-  }
-
-  CloseSocket(socket1);
-  CloseSocket(socket2);
-  server->DisposeForwarderInfo(index);
-  return NULL;
-}
-
-// Listens to a server socket. On incoming request, forward it to the host.
-// static
-void* Server::ServerThread(void* arg) {
-  Server* server = reinterpret_cast<Server*>(arg);
-  while (!g_killed) {
-    int forwarder_index = server->GetFreeForwarderIndex();
-    if (forwarder_index < 0) {
-      LOG(ERROR) << "Too many forwarders";
-      continue;
-    }
-
-    struct sockaddr_in addr;
-    socklen_t addr_len = sizeof(addr);
-    int socket = HANDLE_EINTR(accept(server->socket_,
-                                     reinterpret_cast<sockaddr*>(&addr),
-                                     &addr_len));
-    if (socket < 0) {
-      LOG(ERROR) << "Failed to accept: " << strerror(errno);
-      break;
-    }
-    tools::DisableNagle(socket);
-
-    int host_socket = tools::ConnectAdbHostSocket(server->forward_to_);
-    if (host_socket >= 0) {
-      // Set NONBLOCK flag because we use select().
-      fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) | O_NONBLOCK);
-      fcntl(host_socket, F_SETFL, fcntl(host_socket, F_GETFL) | O_NONBLOCK);
-
-      ForwarderInfo* forwarder_info = server->GetForwarderInfo(forwarder_index);
-      time_t now = time(NULL);
-      forwarder_info->start_time = now;
-      forwarder_info->socket1 = socket;
-      forwarder_info->socket1_last_byte_time = now;
-      forwarder_info->socket1_bytes = 0;
-      forwarder_info->socket2 = host_socket;
-      forwarder_info->socket2_last_byte_time = now;
-      forwarder_info->socket2_bytes = 0;
-
-      pthread_t thread;
-      pthread_create(&thread, NULL, ForwarderThread,
-                     new ForwarderThreadInfo(server, forwarder_index));
-    } else {
-      // Close the unused client socket which is failed to connect to host.
-      CloseSocket(socket);
-    }
-  }
-
-  CloseSocket(server->socket_);
-  server->socket_ = -1;
-  return NULL;
-}
-
-// Format of arg: <Device port>[:<Forward to port>:<Forward to address>]
-bool Server::InitSocket(const char* arg) {
-  char* endptr;
-  int local_port = static_cast<int>(strtol(arg, &endptr, 10));
-  if (local_port < 0)
-    return false;
-
-  if (*endptr != ':') {
-    snprintf(forward_to_, sizeof(forward_to_), "%d:127.0.0.1", local_port);
-  } else {
-    strncpy(forward_to_, endptr + 1, sizeof(forward_to_) - 1);
-  }
-
-  socket_ = socket(AF_INET, SOCK_STREAM, 0);
-  if (socket_ < 0) {
-    perror("server socket");
-    return false;
-  }
-  tools::DisableNagle(socket_);
-
-  sockaddr_in addr;
-  memset(&addr, 0, sizeof(addr));
-  addr.sin_family = AF_INET;
-  addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-  addr.sin_port = htons(local_port);
-  int reuse_addr = 1;
-  setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR,
-             &reuse_addr, sizeof(reuse_addr));
-  tools::DeferAccept(socket_);
-  if (HANDLE_EINTR(bind(socket_, reinterpret_cast<sockaddr*>(&addr),
-                        sizeof(addr))) < 0 ||
-      HANDLE_EINTR(listen(socket_, 5)) < 0) {
-    perror("server bind");
-    CloseSocket(socket_);
-    socket_ = -1;
-    return false;
-  }
-
-  if (local_port == 0) {
-    socklen_t addrlen = sizeof(addr);
-    if (getsockname(socket_, reinterpret_cast<sockaddr*>(&addr), &addrlen)
-        != 0) {
-      perror("get listen address");
-      CloseSocket(socket_);
-      socket_ = -1;
-      return false;
-    }
-    local_port = ntohs(addr.sin_port);
-  }
-
-  printf("Forwarding device port %d to host %s\n", local_port, forward_to_);
-  return true;
-}
-
-int g_server_count = 0;
-Server* g_servers = NULL;
-
-void KillHandler(int unused) {
-  g_killed = true;
-  for (int i = 0; i < g_server_count; i++)
-    g_servers[i].Shutdown();
-}
-
-void DumpInformation(int unused) {
-  for (int i = 0; i < g_server_count; i++)
-    g_servers[i].DumpInformation();
-}
-
-}  // namespace
-
-int main(int argc, char** argv) {
-  printf("Android device to host TCP forwarder\n");
-  printf("Like 'adb forward' but in the reverse direction\n");
-
-  base::CommandLine command_line(argc, argv);
-  base::CommandLine::StringVector server_args = command_line.GetArgs();
-  if (tools::HasHelpSwitch(command_line) || server_args.empty()) {
-    tools::ShowHelp(
-        argv[0],
-        "<Device port>[:<Forward to port>:<Forward to address>] ...",
-        "  <Forward to port> default is <Device port>\n"
-        "  <Forward to address> default is 127.0.0.1\n"
-        "If <Device port> is 0, a port will by dynamically allocated.\n");
-    return 0;
-  }
-
-  g_servers = new Server[server_args.size()];
-  g_server_count = 0;
-  int failed_count = 0;
-  for (size_t i = 0; i < server_args.size(); i++) {
-    if (!g_servers[g_server_count].InitSocket(server_args[i].c_str())) {
-      printf("Couldn't start forwarder server for port spec: %s\n",
-             server_args[i].c_str());
-      ++failed_count;
-    } else {
-      ++g_server_count;
-    }
-  }
-
-  if (g_server_count == 0) {
-    printf("No forwarder servers could be started. Exiting.\n");
-    delete [] g_servers;
-    return failed_count;
-  }
-
-  if (!tools::HasNoSpawnDaemonSwitch(command_line))
-    tools::SpawnDaemon(failed_count);
-
-  signal(SIGTERM, KillHandler);
-  signal(SIGUSR2, DumpInformation);
-
-  for (int i = 0; i < g_server_count; i++)
-    g_servers[i].StartThread();
-  for (int i = 0; i < g_server_count; i++)
-    g_servers[i].JoinThread();
-  g_server_count = 0;
-  delete [] g_servers;
-
-  return 0;
-}
-
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index a337f46..4d791078 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -229,6 +229,11 @@
       'Linux Builder (dbg)': 'debug_bot',
       'Linux Builder (dbg)(32)': 'debug_bot_x86',
       'Linux Builder': 'release_bot',
+      # Trusty bots.
+      'Cast Linux Trusty': 'cast_release_bot',
+      'Linux Builder Trusty (dbg)': 'debug_bot',
+      'Linux Builder Trusty (dbg)(32)': 'debug_bot_x86',
+      'Linux Builder Trusty': 'release_bot',
     },
 
     'chromium.lkgr': {
@@ -297,7 +302,7 @@
     },
 
     'chromium.perf.fyi': {
-      'Win Builder': 'official_goma',
+      'Win Builder FYI': 'official_goma',
       'Win Clang Builder': 'official_goma_minimal_symbols_clang',
     },
 
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index e6c13e1d..4eef2a1a 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -15070,6 +15070,7 @@
     tab closing buttons because those doesn't send the user back to the previous
     app.
   </description>
+  <obsolete>The button option was removed and code deleted.</obsolete>
 </action>
 
 <action name="TaskManager">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index cefb886..8ae01e24 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -6997,23 +6997,70 @@
 </histogram>
 
 <histogram name="ContentSettings.PermissionRequested" enum="PermissionType">
+  <owner>kcarattini@chromium.org</owner>
+  <owner>dominickn@chromium.org</owner>
   <owner>miguelg@chromium.org</owner>
-  <summary>Number of times a given permission was requested.</summary>
+  <summary>
+    Number of times a given permission was requested by a website and the user
+    has the permission set to prompt (i.e. not blocked or allowed).
+
+    Note this is probably not the metric you want - it does not correspond to
+    the total number of times websites request a permission. Also, because
+    specific permissions have code that can automatically block or grant
+    permissions based on things like incognito, installed extensions etc., this
+    does also not correspond to the number of times users are prompted to allow
+    permissions.
+
+    For a better metric to track how often users are prompted, either use
+    ContentSettings.PermissionsActions*, or Permissions.Prompt.*.
+
+    See https://crbug.com/638076 for more details.
+  </summary>
 </histogram>
 
 <histogram name="ContentSettings.PermissionRequested_InsecureOrigin"
     enum="PermissionType">
+  <owner>kcarattini@chromium.org</owner>
+  <owner>dominickn@chromium.org</owner>
   <owner>miguelg@chromium.org</owner>
   <summary>
-    Number of times a given permission was requested from an insecure origin.
+    Number of times a given permission was requested by an insecure origin and
+    the user has the permission set to prompt (i.e. not blocked or allowed).
+
+    Note this is probably not the metric you want - it does not correspond to
+    the total number of times websites request a permission. Also, because
+    specific permissions have code that can automatically block or grant
+    permissions based on things like incognito, installed extensions etc., this
+    does also not correspond to the number of times users are prompted to allow
+    permissions.
+
+    For a better metric to track how often users are prompted, use
+    ContentSettings.PermissionsActions*.
+
+    See https://crbug.com/638076 for more details.
   </summary>
 </histogram>
 
 <histogram name="ContentSettings.PermissionRequested_SecureOrigin"
     enum="PermissionType">
+  <owner>kcarattini@chromium.org</owner>
+  <owner>dominickn@chromium.org</owner>
   <owner>miguelg@chromium.org</owner>
   <summary>
-    Number of times a given permission was requested from a secure origin.
+    Number of times a given permission was requested by a secure origin and the
+    user has the permission set to prompt (i.e. not blocked or allowed).
+
+    Note this is probably not the metric you want - it does not correspond to
+    the total number of times websites request a permission. Also, because
+    specific permissions have code that can automatically block or grant
+    permissions based on things like incognito, installed extensions etc., this
+    does also not correspond to the number of times users are prompted to allow
+    permissions.
+
+    For a better metric to track how often users are prompted, use
+    ContentSettings.PermissionsActions*.
+
+    See https://crbug.com/638076 for more details.
   </summary>
 </histogram>
 
@@ -7550,6 +7597,23 @@
   </summary>
 </histogram>
 
+<histogram name="Crashpad.HandlerCrash.ExceptionCode.Mac"
+    enum="CrashpadMacExceptionCodes">
+  <owner>crashpad-dev@chromium.org</owner>
+  <summary>
+    The exception code encountered for a crash of the crash handler process on
+    Mac OS X.
+  </summary>
+</histogram>
+
+<histogram name="Crashpad.HandlerCrash.ExceptionCode.Win" enum="CrashExitCodes">
+  <owner>crashpad-dev@chromium.org</owner>
+  <summary>
+    The exception code encountered for a crash of the crash handler process on
+    Windows.
+  </summary>
+</histogram>
+
 <histogram name="CrashReport.BreakpadCrashDumpOutcome" enum="DumpOutcome">
   <obsolete>
     Deprecated as of 04/2016 as CrashPad does not implement this.
@@ -17761,6 +17825,16 @@
   </summary>
 </histogram>
 
+<histogram name="GCM.DataMessageReceivedHasRegisteredApp"
+    enum="BooleanRegistered">
+  <owner>peter@chromium.org</owner>
+  <summary>
+    Records whether a corresponding registration was found for each received
+    DATA_MESSAGE or DELETED_MESSAGES message from Google Cloud Messaging.
+    Recorded while processing the received message.
+  </summary>
+</histogram>
+
 <histogram name="GCM.FirstReceivedDataMessageLatencyAfterConnection" units="ms">
   <owner>juyik@chromium.org</owner>
   <summary>
@@ -25039,6 +25113,30 @@
   </summary>
 </histogram>
 
+<histogram name="Memory.RendererAll" units="MB">
+  <owner>bashi@chromium.org</owner>
+  <owner>hajimehoshi@chromium.org</owner>
+  <owner>tasak@chromium.org</owner>
+  <summary>
+    The private working set used by each renderer process, including all
+    renderer types, i.e. this includes Chrome renderer, extensions renderer, as
+    well as regular renderer processes.  Each renderer process provides one
+    sample.  Recorded once per UMA ping.
+  </summary>
+</histogram>
+
+<histogram name="Memory.RendererAll.Committed" units="MB">
+  <owner>bashi@chromium.org</owner>
+  <owner>hajimehoshi@chromium.org</owner>
+  <owner>tasak@chromium.org</owner>
+  <summary>
+    The total committed memory used by each renderer process, including all
+    renderer types, i.e. this includes Chrome renderer, extensions renderer, as
+    well as regular renderer processes.  Each renderer process provides one
+    sample.  Recorded once per UMA ping.
+  </summary>
+</histogram>
+
 <histogram name="Memory.RendererGrowthIn30Min" units="KB">
   <owner>hajimehoshi@chromium.org</owner>
   <owner>kenjibaheux@google.com</owner>
@@ -25478,6 +25576,9 @@
   <owner>hajimehoshi@chromium.org</owner>
   <owner>kenjibaheux@google.com</owner>
   <owner>kouhei@chromium.org</owner>
+  <obsolete>
+    Deprecated 09/2016. Replaced by Memory.Total2.
+  </obsolete>
   <summary>
     The sum of all processes. This is not aware of shared memory so it is just a
     rough estimate. Recorded once per UMA ping. See Memory.Total2 for the same
@@ -26841,6 +26942,25 @@
   </summary>
 </histogram>
 
+<histogram name="Navigation.Reload.ReloadMainResourceToReloadDuration"
+    units="ms">
+  <owner>toyoshim@chromium.org</owner>
+  <summary>
+    Reported when a user triggers reload without any other navigations after the
+    previous reload in the same page, and the previous reload variant was
+    RELOAD_MAIN_RESOURCE. Duration time between two reloads is reported.
+  </summary>
+</histogram>
+
+<histogram name="Navigation.Reload.ReloadToReloadDuration" units="ms">
+  <owner>toyoshim@chromium.org</owner>
+  <summary>
+    Reported when a user triggers reload without any other navigations after the
+    previous reload in the same page. Duration time between two reloads is
+    reported.
+  </summary>
+</histogram>
+
 <histogram name="Navigation.Scheduled.MaybeCausedAbort"
     enum="ScheduledNavigationType">
   <owner>csharrison@chromium.org</owner>
@@ -41391,6 +41511,8 @@
 </histogram>
 
 <histogram name="Permissions.Action" enum="PermissionAction">
+  <owner>dominickn@chromium.org</owner>
+  <owner>kcarattini@chromium.org</owner>
   <owner>miguelg@chromium.org</owner>
   <owner>mlamouri@chromium.org</owner>
   <summary>
@@ -41400,6 +41522,8 @@
 </histogram>
 
 <histogram name="Permissions.Action.InsecureOrigin" enum="PermissionAction">
+  <owner>dominickn@chromium.org</owner>
+  <owner>kcarattini@chromium.org</owner>
   <owner>miguelg@chromium.org</owner>
   <owner>mlamouri@chromium.org</owner>
   <summary>
@@ -41409,6 +41533,8 @@
 </histogram>
 
 <histogram name="Permissions.Action.SecureOrigin" enum="PermissionAction">
+  <owner>dominickn@chromium.org</owner>
+  <owner>kcarattini@chromium.org</owner>
   <owner>miguelg@chromium.org</owner>
   <owner>mlamouri@chromium.org</owner>
   <summary>
@@ -41418,8 +41544,8 @@
 </histogram>
 
 <histogram name="Permissions.Prompt.Accepted" enum="PermissionRequestType">
-  <owner>benwells@chromium.org</owner>
-  <owner>tsergeant@chromium.org</owner>
+  <owner>dominickn@chromium.org</owner>
+  <owner>kcarattini@chromium.org</owner>
   <summary>
     Tracks the permission bubbles (merged and non-merged) that are accepted.
     Merged bubbles are considered accepted if all permissions are allowed.
@@ -41428,6 +41554,7 @@
 
 <histogram name="Permissions.Prompt.Accepted.Persisted" enum="BooleanPersisted">
   <owner>dominickn@chromium.org</owner>
+  <owner>kcarattini@chromium.org</owner>
   <summary>
     For each granted permission prompt displayed with a persistence toggle
     (remember my decision), records whether the persistence toggle was enabled
@@ -41437,6 +41564,7 @@
 
 <histogram name="Permissions.Prompt.Accepted.PriorDismissCount">
   <owner>dominickn@chromium.org</owner>
+  <owner>kcarattini@chromium.org</owner>
   <summary>
     This metric, recorded at the time of a permission prompt accept, records the
     total number of prompt dismissal events for this origin since the last time
@@ -41447,6 +41575,7 @@
 
 <histogram name="Permissions.Prompt.Accepted.PriorIgnoreCount">
   <owner>dominickn@chromium.org</owner>
+  <owner>kcarattini@chromium.org</owner>
   <summary>
     This metric, recorded at the time of a permission prompt accept, records the
     total number of prompt ignore events for this origin since the last time the
@@ -41456,8 +41585,8 @@
 </histogram>
 
 <histogram name="Permissions.Prompt.Denied" enum="PermissionRequestType">
-  <owner>benwells@chromium.org</owner>
-  <owner>tsergeant@chromium.org</owner>
+  <owner>dominickn@chromium.org</owner>
+  <owner>kcarattini@chromium.org</owner>
   <summary>
     Tracks the permission bubbles (merged and non-merged) that are denied.
     Merged bubbles are considered denied if any permission is denied.
@@ -41466,6 +41595,7 @@
 
 <histogram name="Permissions.Prompt.Denied.Persisted" enum="BooleanPersisted">
   <owner>dominickn@chromium.org</owner>
+  <owner>kcarattini@chromium.org</owner>
   <summary>
     For each denied permission prompt displayed with a persistence toggle
     (remember my decision), records whether the persistence toggle was enabled
@@ -41475,6 +41605,7 @@
 
 <histogram name="Permissions.Prompt.Denied.PriorDismissCount">
   <owner>dominickn@chromium.org</owner>
+  <owner>kcarattini@chromium.org</owner>
   <summary>
     This metric, recorded at the time of a permission prompt deny, records the
     total number of prompt dismissal events for this origin since the last time
@@ -41485,6 +41616,7 @@
 
 <histogram name="Permissions.Prompt.Denied.PriorIgnoreCount">
   <owner>dominickn@chromium.org</owner>
+  <owner>kcarattini@chromium.org</owner>
   <summary>
     This metric, recorded at the time of a permission prompt deny, records the
     total number of prompt ignore events for this origin since the last time the
@@ -41495,6 +41627,7 @@
 
 <histogram name="Permissions.Prompt.DismissCount">
   <owner>dominickn@chromium.org</owner>
+  <owner>kcarattini@chromium.org</owner>
   <obsolete>
     Renamed to Permissions.Prompt.Dismissed.PriorDismissCount on 17 August 2016.
   </obsolete>
@@ -41510,6 +41643,7 @@
 
 <histogram name="Permissions.Prompt.Dismissed.PriorDismissCount">
   <owner>dominickn@chromium.org</owner>
+  <owner>kcarattini@chromium.org</owner>
   <summary>
     This metric, recorded at the time of a permission prompt dismiss, records
     the total number of prompt dismissal events for this origin since the last
@@ -41520,6 +41654,7 @@
 
 <histogram name="Permissions.Prompt.Dismissed.PriorIgnoreCount">
   <owner>dominickn@chromium.org</owner>
+  <owner>kcarattini@chromium.org</owner>
   <summary>
     This metric, recorded at the time of a permission prompt dismiss, records
     the total number of prompt ignore events for this origin since the last time
@@ -41530,6 +41665,7 @@
 
 <histogram name="Permissions.Prompt.IgnoreCount">
   <owner>dominickn@chromium.org</owner>
+  <owner>kcarattini@chromium.org</owner>
   <obsolete>
     Renamed to Permissions.Prompt.Dismissed.PriorDismissCount on 17 August 2016.
   </obsolete>
@@ -41545,6 +41681,7 @@
 
 <histogram name="Permissions.Prompt.Ignored.PriorDismissCount">
   <owner>dominickn@chromium.org</owner>
+  <owner>kcarattini@chromium.org</owner>
   <summary>
     This metric, recorded at the time of a permission prompt ignore, records the
     total number of prompt dismissal events for this origin since the last time
@@ -41555,6 +41692,7 @@
 
 <histogram name="Permissions.Prompt.Ignored.PriorIgnoreCount">
   <owner>dominickn@chromium.org</owner>
+  <owner>kcarattini@chromium.org</owner>
   <summary>
     This metric, recorded at the time of a permission prompt ignore, records the
     total number of prompt ignore events for this origin since the last time the
@@ -41565,8 +41703,8 @@
 
 <histogram name="Permissions.Prompt.MergedBubbleAccepted"
     enum="PermissionRequestType">
-  <owner>benwells@chromium.org</owner>
-  <owner>tsergeant@chromium.org</owner>
+  <owner>dominickn@chromium.org</owner>
+  <owner>kcarattini@chromium.org</owner>
   <summary>
     Tracks acceptance of permission bubble request types that have been merged
     into coalesced bubbles.
@@ -41575,8 +41713,8 @@
 
 <histogram name="Permissions.Prompt.MergedBubbleDenied"
     enum="PermissionRequestType">
-  <owner>benwells@chromium.org</owner>
-  <owner>tsergeant@chromium.org</owner>
+  <owner>dominickn@chromium.org</owner>
+  <owner>kcarattini@chromium.org</owner>
   <summary>
     Tracks denial of permission bubble request types that have been merged into
     coalesced bubbles.
@@ -41585,8 +41723,8 @@
 
 <histogram name="Permissions.Prompt.MergedBubbleTypes"
     enum="PermissionRequestType">
-  <owner>benwells@chromium.org</owner>
-  <owner>tsergeant@chromium.org</owner>
+  <owner>dominickn@chromium.org</owner>
+  <owner>kcarattini@chromium.org</owner>
   <summary>
     Tracks the permission bubble request types that are being merged into
     coalesced bubbles.
@@ -41594,8 +41732,8 @@
 </histogram>
 
 <histogram name="Permissions.Prompt.RequestsPerPrompt">
-  <owner>benwells@chromium.org</owner>
-  <owner>tsergeant@chromium.org</owner>
+  <owner>dominickn@chromium.org</owner>
+  <owner>kcarattini@chromium.org</owner>
   <summary>
     How many permission requests each permissions prompt shown to the user
     contains.
@@ -41603,29 +41741,57 @@
 </histogram>
 
 <histogram name="Permissions.Prompt.Shown" enum="PermissionRequestType">
-  <owner>benwells@chromium.org</owner>
-  <owner>tsergeant@chromium.org</owner>
+  <owner>dominickn@chromium.org</owner>
+  <owner>kcarattini@chromium.org</owner>
   <summary>
     Tracks how many times permission prompts are shown to users.
   </summary>
 </histogram>
 
 <histogram name="Permissions.Requested.CrossOrigin" enum="PermissionStatus">
+  <owner>dominickn@chromium.org</owner>
+  <owner>kcarattini@chromium.org</owner>
   <owner>keenanb@google.com</owner>
   <owner>jww@chromium.org</owner>
   <summary>
     The embedder's permission setting at the time of a cross-origin iframe
     permission request for a given permission type. See the corresponding
     histogram suffixes.
+
+    A request is when a website makes a permission request and the user has the
+    permission set to prompt (i.e. not blocked or allowed).
+
+    Note this is probably not the metric you want - it does not correspond to
+    the total number of times websites request a permission. Also, because
+    specific permissions have code that can automatically block or grant
+    permissions based on things like incognito, installed extensions etc., this
+    does also not correspond to the number of times users are prompted to allow
+    permissions.
+
+    See https://crbug.com/638076 for more details.
   </summary>
 </histogram>
 
 <histogram name="Permissions.Requested.SameOrigin" enum="PermissionType">
+  <owner>dominickn@chromium.org</owner>
+  <owner>kcarattini@chromium.org</owner>
   <owner>keenanb@google.com</owner>
   <owner>jww@chromium.org</owner>
   <summary>
     The permission type (geolocation, and such) of a same-origin permission
     request.
+
+    A request is when a website makes a permission request and the user has the
+    permission set to prompt (i.e. not blocked or allowed).
+
+    Note this is probably not the metric you want - it does not correspond to
+    the total number of times websites request a permission. Also, because
+    specific permissions have code that can automatically block or grant
+    permissions based on things like incognito, installed extensions etc., this
+    does also not correspond to the number of times users are prompted to allow
+    permissions.
+
+    See https://crbug.com/638076 for more details.
   </summary>
 </histogram>
 
@@ -53648,6 +53814,17 @@
   </summary>
 </histogram>
 
+<histogram name="Search.ContextualSearchAllCapsResultsSeen"
+    enum="ContextualSearchResultsSeen">
+  <owner>donnd@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
+  <summary>
+    Whether search results were seen during a contextual search where the
+    selected text consisted of all capital letters. Only logged when contextual
+    search is triggered due to a tap. Implemented for Android.
+  </summary>
+</histogram>
+
 <histogram name="Search.ContextualSearchBarOverlap"
     enum="ContextualSearchTapSuppression">
   <owner>donnd@chromium.org</owner>
@@ -53710,6 +53887,26 @@
   </summary>
 </histogram>
 
+<histogram name="Search.ContextualSearchDurationBetweenTriggerAndScrollNotSeen"
+    units="ms">
+  <owner>donnd@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
+  <summary>
+    The duration between the panel being triggered and the panel being dismisesd
+    due to a scroll when search results were not seen. Implemented for Android.
+  </summary>
+</histogram>
+
+<histogram name="Search.ContextualSearchDurationBetweenTriggerAndScrollSeen"
+    units="ms">
+  <owner>donnd@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
+  <summary>
+    The duration between the panel being triggered and the panel being dismisesd
+    due to a scroll when search results were seen. Implemented for Android.
+  </summary>
+</histogram>
+
 <histogram name="Search.ContextualSearchDurationNonPrefetched" units="ms">
   <owner>donnd@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
@@ -54208,6 +54405,18 @@
   </summary>
 </histogram>
 
+<histogram name="Search.ContextualSearchStartedWithCapitalResultsSeen"
+    enum="ContextualSearchResultsSeen">
+  <owner>donnd@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
+  <summary>
+    Whether search results were seen during a contextual search where the
+    selected text started with a capital letter but was not all capital letters.
+    Only logged when contextual search is triggered due to a tap. Implemented
+    for Android.
+  </summary>
+</histogram>
+
 <histogram name="Search.ContextualSearchTapsSinceOpenDecided" units="taps">
   <owner>donnd@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
@@ -59803,6 +60012,18 @@
   </summary>
 </histogram>
 
+<histogram name="Style.AuthorStyleSheet.ParseTime" units="us">
+  <owner>csharrison@chromium.org</owner>
+  <summary>
+    Microseconds spent in StyleSheetContents::parseAuthorStyleSheet.
+  </summary>
+</histogram>
+
+<histogram name="Style.UpdateTime" units="us">
+  <owner>csharrison@chromium.org</owner>
+  <summary>Microseconds spent in Document::updateStyle.</summary>
+</histogram>
+
 <histogram name="SubresourceFilter.DocumentLoad.ActivationState"
     enum="SubresourceFilterActivationState">
   <owner>engedy@chromium.org</owner>
@@ -61054,6 +61275,17 @@
   </summary>
 </histogram>
 
+<histogram name="Sync.LostNavigationCount" units="navigations">
+  <owner>pnoland@chromium.org</owner>
+  <summary>
+    Counts instances of navigations that are recorded locally but not synced.
+    Recorded once per active tab for every inferred sync cycle. Sync cycles are
+    inferred by examining the is_synced and is_syncing flags of sync directories
+    when recording local changes to tabs or windows. Sync cycles that occur
+    without changes to tabs or windows won't cause this metric to be logged.
+  </summary>
+</histogram>
+
 <histogram name="Sync.MemoryPressureWarningBeforeCleanShutdown" units="count">
   <owner>gangwu@chromium.org</owner>
   <summary>
@@ -68924,6 +69156,14 @@
   </summary>
 </histogram>
 
+<histogram name="WebRTC.Video.EndToEndDelayInMs" units="ms">
+  <owner>asapersson@chromium.org</owner>
+  <summary>
+    The average end-to-end delay per frame for a received video stream. Recorded
+    when a stream is removed.
+  </summary>
+</histogram>
+
 <histogram name="WebRTC.Video.FecBitrateReceivedInKbps" units="kbps">
   <owner>asapersson@chromium.org</owner>
   <summary>
@@ -76557,6 +76797,8 @@
 <enum name="DownloadDatabaseRecordDroppedType" type="int">
   <int value="0" label="Bad State"/>
   <int value="1" label="Bad Danger Type"/>
+  <int value="2" label="Bad ID"/>
+  <int value="3" label="Duplicate ID"/>
 </enum>
 
 <enum name="DownloadDOMEvent" type="int">
@@ -81098,18 +81340,19 @@
   <int value="440" label="DocumentFonts"/>
   <int value="441" label="MixedContentFormsSubmitted"/>
   <int value="442" label="FormsSubmitted"/>
-  <int value="443" label="TextInputEventOnInput"/>
-  <int value="444" label="TextInputEventOnTextArea"/>
-  <int value="445" label="TextInputEventOnContentEditable"/>
-  <int value="446" label="TextInputEventOnNotNode"/>
-  <int value="447" label="WebkitBeforeTextInsertedOnInput"/>
-  <int value="448" label="WebkitBeforeTextInsertedOnTextArea"/>
-  <int value="449" label="WebkitBeforeTextInsertedOnContentEditable"/>
-  <int value="450" label="WebkitBeforeTextInsertedOnNotNode"/>
-  <int value="451" label="WebkitEditableContentChangedOnInput"/>
-  <int value="452" label="WebkitEditableContentChangedOnTextArea"/>
-  <int value="453" label="WebkitEditableContentChangedOnContentEditable"/>
-  <int value="454" label="WebkitEditableContentChangedOnNotNode"/>
+  <int value="443" label="TextInputEventOnInputObsolete"/>
+  <int value="444" label="TextInputEventOnTextAreaObsolete"/>
+  <int value="445" label="TextInputEventOnContentEditableObsolete"/>
+  <int value="446" label="TextInputEventOnNotNodeObsolete"/>
+  <int value="447" label="WebkitBeforeTextInsertedOnInputObsolete"/>
+  <int value="448" label="WebkitBeforeTextInsertedOnTextAreaObsolete"/>
+  <int value="449" label="WebkitBeforeTextInsertedOnContentEditableObsolete"/>
+  <int value="450" label="WebkitBeforeTextInsertedOnNotNodeObsolete"/>
+  <int value="451" label="WebkitEditableContentChangedOnInputObsolete"/>
+  <int value="452" label="WebkitEditableContentChangedOnTextAreaObsolete"/>
+  <int value="453"
+      label="WebkitEditableContentChangedOnContentEditableObsolete"/>
+  <int value="454" label="WebkitEditableContentChangedOnNotNodeObsolete"/>
   <int value="455" label="HTMLImports"/>
   <int value="456" label="ElementCreateShadowRoot"/>
   <int value="457" label="DocumentRegisterElement"/>
@@ -82269,6 +82512,22 @@
   <int value="1584" label="XSSAuditorEnabledFilter"/>
   <int value="1585" label="XSSAuditorEnabledBlock"/>
   <int value="1586" label="XSSAuditorInvalid"/>
+  <int value="1587" label="SVGCursorElement"/>
+  <int value="1588" label="SVGCursorElementHasClient"/>
+  <int value="1589" label="TextInputEventOnInput"/>
+  <int value="1590" label="TextInputEventOnTextArea"/>
+  <int value="1591" label="TextInputEventOnContentEditable"/>
+  <int value="1592" label="TextInputEventOnNotNode"/>
+  <int value="1593" label="WebkitBeforeTextInsertedOnInput"/>
+  <int value="1594" label="WebkitBeforeTextInsertedOnTextArea"/>
+  <int value="1595" label="WebkitBeforeTextInsertedOnContentEditable"/>
+  <int value="1596" label="WebkitBeforeTextInsertedOnNotNode"/>
+  <int value="1597" label="WebkitEditableContentChangedOnInput"/>
+  <int value="1598" label="WebkitEditableContentChangedOnTextArea"/>
+  <int value="1599" label="WebkitEditableContentChangedOnContentEditable"/>
+  <int value="1600" label="WebkitEditableContentChangedOnNotNode"/>
+  <int value="1601"
+      label="V8NavigatorUserMediaError_ConstraintName_AttributeGetter"/>
 </enum>
 
 <enum name="FetchRequestMode" type="int">
@@ -83325,6 +83584,8 @@
   <int value="4531384" label="date_of_birth"/>
   <int value="22829753" label="barometric_pressure_trend"/>
   <int value="33030714" label="scan_refresh"/>
+  <int value="36624371"
+      label="Anki OVERDRIVE cars; be15bee0-6186-407e-8381-0bd89c4d8df4"/>
   <int value="40437408" label="gender"/>
   <int value="64893984" label="local_east_coordinate.xml"/>
   <int value="67768539" label="alert_category_id_bit_mask"/>
@@ -83332,12 +83593,23 @@
   <int value="84948752"
       label="Eddystone Config ADV Slot Data;
              a3c8750a-8ed3-4bdf-8a39-a01bebede295"/>
+  <int value="87432554"
+      label="Parrot Drone; 9a66fd54-0800-9191-11e4-012d1540cb8e"/>
   <int value="89070880" label="blood_pressure_measurement"/>
   <int value="102699400" label="cycling_power_feature"/>
+  <int value="111826224"
+      label="micro:bit client requirements;
+             e95d23c4-251d-470a-a062-fa1922dfa9a8"/>
+  <int value="121100653"
+      label="Parrot Drone; 9a66fd22-0800-9191-11e4-012d1540cb8e"/>
   <int value="145478270" label="glucose_feature"/>
   <int value="162705488" label="manufacturer_name_string"/>
   <int value="164418508" label="weight_measurement"/>
   <int value="177223896" label="report_map"/>
+  <int value="193202136"
+      label="Anki OVERDRIVE cars; be15bee1-6186-407e-8381-0bd89c4d8df4"/>
+  <int value="203698195"
+      label="micro:bit event; e95d9775-251d-470a-a062-fa1922dfa9a8"/>
   <int value="203846063" label="ff0c"/>
   <int value="205016416" label="body_composition_measurement"/>
   <int value="235785246" label="irradiance"/>
@@ -83353,14 +83625,26 @@
   <int value="307449363" label="plx_features"/>
   <int value="310983691" label="cycling_power_measurement"/>
   <int value="312578485" label="navigation"/>
+  <int value="314022771"
+      label="Remote Lego; 8d8ba32b-96be-4590-910b-c756c5222c9f"/>
+  <int value="318124766"
+      label="Remote Lego; fa10e4de-259e-4d23-9f59-45a9c66802ca"/>
   <int value="333947401" label="temperature_measurement"/>
   <int value="338768495" label="ringer_setting"/>
   <int value="339742946" label="hid_information"/>
   <int value="358854697" label="bond_management_feature"/>
+  <int value="359765018"
+      label="micro:bit client event; e95d5404-251d-470a-a062-fa1922dfa9a8"/>
   <int value="361317539" label="language"/>
   <int value="363167947" label="blood_pressure_feature"/>
   <int value="364021976"
       label="nRF candy machine; b6c31338-6c07-453e-961a-d8a8a41bf368"/>
+  <int value="368068304"
+      label="MiP Robot; Magic Blue Bulb; 0000ffe9-0000-1000-8000-00805f9b34fb"/>
+  <int value="371778276"
+      label="micro:bit requirements; e95db84c-251d-470a-a062-fa1922dfa9a8"/>
+  <int value="372306057"
+      label="Bleno Pizza Example; 13333333-3333-3333-3333-333333330001"/>
   <int value="405569435" label="boot_keyboard_output_report"/>
   <int value="409618715" label="cycling_power_vector"/>
   <int value="419477741" label="body_composition_feature"/>
@@ -83369,7 +83653,11 @@
       label="Eddystone Config Advertising Interval;
              a3c87503-8ed3-4bdf-8a39-a01bebede295"/>
   <int value="486368335" label="location_name"/>
+  <int value="508191605"
+      label="Parrot Drone; 9a66fb1b-0800-9191-11e4-012d1540cb8e"/>
   <int value="512543326" label="date_of_threshold_assessment"/>
+  <int value="517791580"
+      label="Sphero Robot; 22bb746f-2bbf-7554-2d6f-726568705327"/>
   <int value="531135021" label="cgm_specific_ops_control_point"/>
   <int value="540054581" label="magnetic_declination"/>
   <int value="546162499"
@@ -83380,12 +83668,22 @@
   <int value="557034058" label="cycling_power_control_point"/>
   <int value="557040382" label="hardware_revision_string"/>
   <int value="561260257" label="analog"/>
+  <int value="580555542"
+      label="Remote Lego; 2ac1fdb2-d971-4595-8e32-e8c5d80edf5f"/>
+  <int value="589575132"
+      label="Sphero Robot; 22bb746f-2bbd-7554-2d6f-726568705327"/>
   <int value="589741087" label="model_number_string"/>
+  <int value="625191771"
+      label="Parrot Drone; 9a66fa0a-0800-9191-11e4-012d1540cb8e"/>
   <int value="638602429" label="new_alert"/>
   <int value="642925692" label="anaerobic_heart_rate_lower_limit"/>
   <int value="650507215" label="aerobic_heart_rate_lower_limit"/>
   <int value="653904148" label="cgm_session_run_time"/>
   <int value="675543714" label="aerobic_threshold"/>
+  <int value="682327952"
+      label="Parrot Drone; 9a66fa0b-0800-9191-11e4-012d1540cb8e"/>
+  <int value="685669143"
+      label="Parrot Drone; 9a66fa0c-0800-9191-11e4-012d1540cb8e"/>
   <int value="689682673" label="unread_alert_status"/>
   <int value="710863194" label="dew_point"/>
   <int value="713208266" label="apparent_wind_direction"/>
@@ -83394,20 +83692,29 @@
   <int value="752820597" label="boot_mouse_input_report"/>
   <int value="762835818" label="tx_power_level"/>
   <int value="765862810" label="cgm_session_start_time"/>
+  <int value="777276843"
+      label="Bleno Pizza Example; 13333333-3333-3333-3333-333333330003"/>
+  <int value="786588903"
+      label="Parrot Drone; 9a66fd53-0800-9191-11e4-012d1540cb8e"/>
   <int value="788890283"
       label="Eddystone Config Factory reset;
              a3c8750b-8ed3-4bdf-8a39-a01bebede295"/>
   <int value="797118889" label="time_source"/>
   <int value="839366223" label="user_index"/>
   <int value="842908520" label="rsc_measurement"/>
+  <int value="845003775"
+      label="Remote Lego; aad03b81-f2ea-47db-ae1e-7c2f9e86e93e"/>
   <int value="859809200" label="resting_heart_rate"/>
   <int value="867296114" label="gust_factor"/>
   <int value="868427891" label="local_north_coordinate"/>
   <int value="868892960" label="heat_index"/>
   <int value="873660243" label="body_sensor_location"/>
   <int value="893588698" label="scan_interval_window"/>
+  <int value="893850387"
+      label="Parrot Drone; 9a66fd23-0800-9191-11e4-012d1540cb8e"/>
   <int value="910416910"
-      label="nRF UART RX; 6e400003-b5a3-f393-e0a9-e50e24dcca9e"/>
+      label="nRF UART RX; nrf52-Quadcopter;
+             6e400003-b5a3-f393-e0a9-e50e24dcca9e"/>
   <int value="917477908" label="software_revision_string"/>
   <int value="918961501" label="plx_spot_check_measurement"/>
   <int value="922434244" label="ln_feature"/>
@@ -83425,10 +83732,15 @@
   <int value="1002619180" label="exact_time_256"/>
   <int value="1025676359" label="dst_offset"/>
   <int value="1050948662"
-      label="nRF UART TX; 6e400002-b5a3-f393-e0a9-e50e24dcca9e"/>
+      label="nRF UART TX; nrf52-Quadcopter;
+             6e400002-b5a3-f393-e0a9-e50e24dcca9e"/>
   <int value="1061486494" label="anaerobic_heart_rate_upper_limit"/>
   <int value="1072163984" label="gap.reconnection_address"/>
+  <int value="1077684177"
+      label="Parrot Drone; 9a66fd52-0800-9191-11e4-012d1540cb8e"/>
   <int value="1100640868" label="day_of_week"/>
+  <int value="1117053056"
+      label="Remote Lego; 7baf8dca-2bfc-47fb-af29-042fccc180eb"/>
   <int value="1125104414" label="gap.central_address_resolution_support"/>
   <int value="1134538374" label="hip_circumference"/>
   <int value="1136624215" label="maximum_recommended_heart_rate"/>
@@ -83442,8 +83754,12 @@
   <int value="1193066711" label="uv_index"/>
   <int value="1214133688" label="vo2_max"/>
   <int value="1217613737" label="three_zone_heart_rate_limits"/>
+  <int value="1225369773"
+      label="DOTTI; Makeblock mBot; 0000fff3-0000-1000-8000-00805f9b34fb"/>
   <int value="1227844535" label="floor_number"/>
   <int value="1237083013" label="first_name"/>
+  <int value="1243630465"
+      label="Sphero Robot; 22bb746f-2ba1-7554-2d6f-726568705327"/>
   <int value="1245615057" label="pnp_id"/>
   <int value="1254532025" label="user_control_point"/>
   <int value="1288236137" label="hid_control_point"/>
@@ -83456,6 +83772,8 @@
   <int value="1333242790" label="longitude"/>
   <int value="1358488787"
       label="sport_type_for_aerobic_and_anaerobic_thresholds"/>
+  <int value="1359562687"
+      label="PowerUp RC plane; 75b64e51-f184-4ed1-921a-476090d80ba7"/>
   <int value="1370497910" label="position_quality"/>
   <int value="1370779343" label="apparent_wind_speed"/>
   <int value="1399905251" label="elevation"/>
@@ -83467,6 +83785,8 @@
       label="gap.peripheral_preferred_connection_parameters"/>
   <int value="1419696114" label="record_access_control_point"/>
   <int value="1426243900" label="time_update_state"/>
+  <int value="1443769073"
+      label="Parrot Drone; 9a66fb0e-0800-9191-11e4-012d1540cb8e"/>
   <int value="1445812935" label="current_time"/>
   <int value="1448457670" label="cgm_feature"/>
   <int value="1479031407" label="five_zone_heart_rate_limits"/>
@@ -83479,6 +83799,10 @@
       label="Eddystone Config Capabilities;
              a3c87501-8ed3-4bdf-8a39-a01bebede295"/>
   <int value="1521362289" label="indoor_positioning_configuration"/>
+  <int value="1536163565"
+      label="Remote Lego; e0af3340-022e-47e1-a263-d68887dc41d4"/>
+  <int value="1537284424"
+      label="Bleno Pizza Example; 13333333-3333-3333-3333-333333330002"/>
   <int value="1541435682" label="fat_burn_heart_rate_upper_limit"/>
   <int value="1542101224" label="plx_continuous_measurent"/>
   <int value="1547112406"
@@ -83486,12 +83810,16 @@
              a3c87502-8ed3-4bdf-8a39-a01bebede295"/>
   <int value="1556918420" label="supported_new_alert_category"/>
   <int value="1562359952" label="bond_management_control_point"/>
+  <int value="1581120657"
+      label="Parrot Drone; 9a66fb1c-0800-9191-11e4-012d1540cb8e"/>
   <int value="1594190447" label="anaerobic_threshold"/>
   <int value="1594284383" label="time_accuracy"/>
   <int value="1599786113" label="sensor_location"/>
   <int value="1650767660" label="protocol_mode"/>
   <int value="1655824245" label="pressure"/>
   <int value="1658559118" label="digital"/>
+  <int value="1669829174"
+      label="Purple Eye; 00005200-0000-1000-8000-00805f9b34fb"/>
   <int value="1704141710" label="true_wind_direction"/>
   <int value="1732815395" label="alert_level"/>
   <int value="1735563923" label="rsc_feature"/>
@@ -83499,12 +83827,18 @@
   <int value="1774994865" label="day_date_time"/>
   <int value="1777827929" label="heart_rate_measurement"/>
   <int value="1778752264" label="magnetic_flux_density_2D"/>
+  <int value="1794935269"
+      label="Sphero Robot; 22bb746f-2bb2-7554-2d6f-726568705327"/>
   <int value="1807818076" label="rainfall"/>
   <int value="1811011331" label="report"/>
   <int value="1813165113" label="fat_burn_heart_rate_lower_limit"/>
   <int value="1822663159" label="altitude"/>
   <int value="1826219951" label="measurement_interval"/>
   <int value="1855704654" label="latitude"/>
+  <int value="1863022784"
+      label="Parrot Drone; 9a66fd24-0800-9191-11e4-012d1540cb8e"/>
+  <int value="1875571028"
+      label="PowerUp RC plane; 75b64e51-f185-4ed1-921a-476090d80ba7"/>
   <int value="1881531610" label="descriptor_value_changed"/>
   <int value="1899652799" label="pollen_concentration"/>
   <int value="1904364134" label="aerobic_heart_rate_upper_limit"/>
@@ -83523,11 +83857,17 @@
   <int value="2041423305" label="email_address"/>
   <int value="2042267197" label="age"/>
   <int value="2047173546" label="boot_keyboard_input_report"/>
+  <int value="2049531548"
+      label="nrf52-Quadcopter; 6e400004-b5a3-f393-e0a9-e50e24dcca9e"/>
+  <int value="2055293976"
+      label="Remote Lego; b394673e-dea0-4044-a189-86f1c85ce22e"/>
   <int value="2083994430" label="two_zone_heart_rate_limit"/>
   <int value="2084445069" label="ringer_control_point"/>
   <int value="2091531878" label="weight_scale_feature"/>
   <int value="2101185135" label="time_zone"/>
   <int value="2105952193" label="heart_rate_max"/>
+  <int value="2110830087"
+      label="Printer; 00002af1-0000-1000-8000-00805f9b34fb"/>
   <int value="2118566262" label="database_change_increment"/>
   <int value="2125906618" label="gap.appearance"/>
   <int value="2140490935" label="gatt.service_changed"/>
@@ -83545,6 +83885,8 @@
   <int value="46512116" label="fe03"/>
   <int value="47251880" label="fe8c"/>
   <int value="48328546" label="febf"/>
+  <int value="48912332"
+      label="micro:bit event; e95d93af-251d-470a-a062-fa1922dfa9a8"/>
   <int value="56938056" label="feb9"/>
   <int value="62669585" label="feff"/>
   <int value="70653353" label="fe37"/>
@@ -83554,6 +83896,8 @@
   <int value="109066436" label="Printer; 18f0"/>
   <int value="117033282" label="fe1e"/>
   <int value="119232939" label="fe16"/>
+  <int value="124193922"
+      label="nrf52-Quadcopter; 6e400020-b5a3-f393-e0a9-e50e24dcca9e"/>
   <int value="126220948" label="fec4"/>
   <int value="130754956" label="fe0d"/>
   <int value="134110769" label="fecf"/>
@@ -83583,7 +83927,8 @@
   <int value="314884784" label="fe65"/>
   <int value="315044617" label="fea9"/>
   <int value="321399472" label="fe86"/>
-  <int value="335078161" label="DOTTI; fff0"/>
+  <int value="335078161"
+      label="Dotti; MiP Robot; 0000fff0-0000-1000-8000-00805f9b34fb"/>
   <int value="336095190" label="fe1c"/>
   <int value="337129282" label="fe73"/>
   <int value="347254994" label="feb6"/>
@@ -83609,7 +83954,11 @@
   <int value="517314925" label="fe0e"/>
   <int value="534472233" label="feea"/>
   <int value="535574137" label="feb1"/>
+  <int value="540487861"
+      label="Parrot Drone; 9a66fd21-0800-9191-11e4-012d1540cb8e"/>
   <int value="547028880" label="fed0"/>
+  <int value="547268186"
+      label="Parrot Drone; 9a66fb00-0800-9191-11e4-012d1540cb8e"/>
   <int value="547391938" label="feee"/>
   <int value="563178896" label="fec8"/>
   <int value="572734315"
@@ -83627,8 +83976,12 @@
   <int value="617434027" label="fe59"/>
   <int value="621358948" label="fec7"/>
   <int value="633977000" label="fedf"/>
+  <int value="634740644"
+      label="Purple Eye; 00005100-0000-1000-8000-00805f9b34fb"/>
   <int value="642914459" label="fe3d"/>
   <int value="643543662" label="fefe"/>
+  <int value="661885353"
+      label="Remote Lego; 40480f29-7bad-4ea5-8bf8-499405c9b324"/>
   <int value="675211143" label="fe4a"/>
   <int value="677930586" label="fe11"/>
   <int value="683753134" label="fe82"/>
@@ -83679,6 +84032,8 @@
   <int value="960854785" label="fe53"/>
   <int value="961193127" label="feb8"/>
   <int value="963656436" label="fe77"/>
+  <int value="978815669"
+      label="CoolBeans Serial; a495ff10-c5b1-4b44-b512-1370f02d74de"/>
   <int value="1001310815" label="fe75"/>
   <int value="1024550252" label="feda"/>
   <int value="1029767622" label="internet_protocol_support"/>
@@ -83738,6 +84093,8 @@
   <int value="1352591424" label="fe2d"/>
   <int value="1357782294" label="fe90"/>
   <int value="1357850359" label="fefc"/>
+  <int value="1359442507"
+      label="Physical Web Light Switch; ba42561b-b1d2-440a-8d04-0cefb43faece"/>
   <int value="1362860533" label="fe9a"/>
   <int value="1366014117" label="fe2c"/>
   <int value="1369789354" label="current_time"/>
@@ -83756,9 +84113,13 @@
   <int value="1432421356" label="fe14"/>
   <int value="1433847022" label="fefa"/>
   <int value="1465794357" label="feb0"/>
+  <int value="1482395712"
+      label="Bleno Pizza Example; 13333333-3333-3333-3333-333333333337"/>
   <int value="1484296385" label="fe30"/>
   <int value="1513113754" label="fe39"/>
   <int value="1515793787" label="fef1"/>
+  <int value="1545945606"
+      label="Parrot Drone; 9a66fa00-0800-9191-11e4-012d1540cb8e"/>
   <int value="1548928839" label="fec5"/>
   <int value="1549672811"
       label="nRF candy machine; b6c31337-6c07-453e-961a-d8a8a41bf368"/>
@@ -83766,6 +84127,8 @@
   <int value="1563543855" label="fe72"/>
   <int value="1569655226" label="generic_access"/>
   <int value="1573199922" label="fe71"/>
+  <int value="1578535968"
+      label="Makeblock mBot; 0000ffe1-0000-1000-8000-00805f9b34fb"/>
   <int value="1594426590" label="fe4e"/>
   <int value="1600490722" label="fe46"/>
   <int value="1604724337" label="fe88"/>
@@ -83790,6 +84153,8 @@
   <int value="1696287138" label="weight_scale"/>
   <int value="1701893879" label="feac"/>
   <int value="1706666451" label="fea7"/>
+  <int value="1712085581"
+      label="MiP Robot; Magic Blue Bulb; 0000ffe5-0000-1000-8000-00805f9b34fb"/>
   <int value="1714031075" label="fe10"/>
   <int value="1724509641" label="fe8b"/>
   <int value="1729966097"
@@ -83852,6 +84217,8 @@
   <int value="2110412550" label="fe43"/>
   <int value="2113887919" label="fe5b"/>
   <int value="2115271248" label="fe94"/>
+  <int value="2124678180"
+      label="Parrot Drone; 9a66fd51-0800-9191-11e4-012d1540cb8e"/>
   <int value="2132514937" label="feec"/>
   <int value="2136716957" label="fe69"/>
 </enum>
@@ -85185,6 +85552,7 @@
   <int value="67" label="INSTANT_APPS_INFOBAR_DELEGATE_ANDROID"/>
   <int value="68" label="DATA_REDUCTION_PROXY_PREVIEW_INFOBAR_DELEGATE"/>
   <int value="69" label="SCREEN_CAPTURE_INFOBAR_DELEGATE_ANDROID"/>
+  <int value="70" label="GROUPED_PERMISSION_INFOBAR_DELEGATE_ANDROID"/>
 </enum>
 
 <enum name="InfoBarResponse" type="int">
@@ -87053,6 +87421,7 @@
   <int value="-1578295753" label="UserMediaScreenCapturing:disabled"/>
   <int value="-1572010356" label="enable-privet-v3"/>
   <int value="-1571841513" label="enable-devtools-experiments"/>
+  <int value="-1559789642" label="RunAllFlashInAllowMode:enabled"/>
   <int value="-1553477903" label="ash-disable-text-filtering-in-overview-mode"/>
   <int value="-1546903171" label="enable-touch-drag-drop"/>
   <int value="-1514943439" label="ash-enable-swipe-to-close-in-overview-mode"/>
@@ -87430,6 +87799,7 @@
   <int value="470011024" label="NonValidatingReloadOnNormalReload:enabled"/>
   <int value="474743272" label="material-design-ink-drop"/>
   <int value="477967119" label="enable-unified-media-pipeline"/>
+  <int value="479906041" label="RunAllFlashInAllowMode:disabled"/>
   <int value="480544447" label="NonValidatingReloadOnRefreshContentV2:enabled"/>
   <int value="493903641" label="disable-appcontainer"/>
   <int value="494733611" label="disable-drop-sync-credential"/>
@@ -99802,6 +100172,11 @@
   <int value="19" label="YUV422P10"/>
   <int value="20" label="YUV444P9"/>
   <int value="21" label="YUV444P10"/>
+  <int value="22" label="YUV420P12"/>
+  <int value="23" label="YUV422P12"/>
+  <int value="24" label="YUV444P12"/>
+  <int value="25" label="Y8"/>
+  <int value="26" label="Y16"/>
 </enum>
 
 <enum name="VideoPlayerCastAPIExtensionStatus" type="int">
diff --git a/tools/perf/benchmarks/battor.py b/tools/perf/benchmarks/battor.py
index 08f8a5e..a995ded 100644
--- a/tools/perf/benchmarks/battor.py
+++ b/tools/perf/benchmarks/battor.py
@@ -108,6 +108,7 @@
     return 'battor.power_cases'
 
 
+@benchmark.Disabled('all')  # crbug.com/651384.
 class BattOrPowerCasesNoChromeTrace(_BattOrBenchmark):
   page_set = page_sets.power_cases.PowerCasesPageSet
 
diff --git a/tools/perf/benchmarks/page_cycler_v2.py b/tools/perf/benchmarks/page_cycler_v2.py
index 68b8e27..2c3fa69 100644
--- a/tools/perf/benchmarks/page_cycler_v2.py
+++ b/tools/perf/benchmarks/page_cycler_v2.py
@@ -55,6 +55,12 @@
         possible_browser.platform.GetDeviceTypeName() == 'Nexus 5X' or
         possible_browser.platform.GetDeviceTypeName() == 'AOSP on BullHead'):
       return True
+
+    # crbug.com/651188
+    if (possible_browser.platform.GetDeviceTypeName() == 'Nexus 6' and
+        possible_browser.browser_type == 'android-webview'):
+      return True
+
     return False
 
 
diff --git a/tools/perf/bootstrap_deps b/tools/perf/bootstrap_deps
index 96149cb..121ca0dd 100644
--- a/tools/perf/bootstrap_deps
+++ b/tools/perf/bootstrap_deps
@@ -12,6 +12,10 @@
         "https://chromium.googlesource.com/chromium/canvas_bench.git",
     "src/chrome/test/data/third_party/spaceport":
         "https://src.chromium.org/chrome/trunk/src/chrome/test/data/third_party/spaceport",
+    "src/tools/json_comment_eater":
+        "https://src.chromium.org/chrome/trunk/src/tools/json_comment_eater",
+    "src/tools/json_to_struct":
+        "https://src.chromium.org/chrome/trunk/src/tools/json_to_struct",
     "src/tools/perf/benchmarks":
         "https://src.chromium.org/chrome/trunk/src/tools/perf/benchmarks",
     "src/tools/perf/core":
diff --git a/tools/perf/core/perf_benchmark.py b/tools/perf/core/perf_benchmark.py
index 2adffbf..2f8d07e 100644
--- a/tools/perf/core/perf_benchmark.py
+++ b/tools/perf/core/perf_benchmark.py
@@ -59,7 +59,7 @@
       return []
 
     return fieldtrial_util.GenerateArgs(
-        os.path.join(variations_dir, 'fieldtrial_testing_config_.json'),
+        os.path.join(variations_dir, 'fieldtrial_testing_config.json'),
         self._FixupTargetOS(possible_browser.target_os))
 
   @staticmethod
diff --git a/tools/perf/measurements/rasterize_and_record_micro.py b/tools/perf/measurements/rasterize_and_record_micro.py
index 429f4adb..bd208ef 100644
--- a/tools/perf/measurements/rasterize_and_record_micro.py
+++ b/tools/perf/measurements/rasterize_and_record_micro.py
@@ -82,8 +82,10 @@
     record_time_caching_disabled = data['record_time_caching_disabled_ms']
     record_time_construction_disabled = \
         data['record_time_construction_disabled_ms']
+    # TODO(wangxianzhu): Remove this workaround when reference builds get past
+    # r367465.
     record_time_subsequence_caching_disabled = \
-        data['record_time_subsequence_caching_disabled_ms']
+        data.get('record_time_subsequence_caching_disabled_ms', 0)
     results.AddValue(scalar.ScalarValue(
         results.current_page, 'record_time_painting_disabled', 'ms',
         record_time_painting_disabled))
diff --git a/tools/perf/page_sets/data/credentials.json.sha1 b/tools/perf/page_sets/data/credentials.json.sha1
index a16eb30..a668bc6 100644
--- a/tools/perf/page_sets/data/credentials.json.sha1
+++ b/tools/perf/page_sets/data/credentials.json.sha1
@@ -1 +1 @@
-9f4127d6d52237c810858bc68ac0942f67e20ebc
\ No newline at end of file
+83273b592dddd8b29205d718950cdf7284b76d2d
\ No newline at end of file
diff --git a/tools/perf/page_sets/login_helpers/facebook_login.py b/tools/perf/page_sets/login_helpers/facebook_login.py
index a07ddff..aeca2d4 100644
--- a/tools/perf/page_sets/login_helpers/facebook_login.py
+++ b/tools/perf/page_sets/login_helpers/facebook_login.py
@@ -5,7 +5,8 @@
 
 
 def LoginWithMobileSite(
-    action_runner, credential,
+    action_runner,
+    credential='facebooktest', # Recommended testing account.
     credentials_path=login_utils.DEFAULT_CREDENTIAL_PATH):
   """Logs in into mobile Facebook account.
 
@@ -15,7 +16,11 @@
   Args:
     action_runner: Action runner responsible for running actions on the page.
     credential: The credential to retrieve from the credentials file
-        (type string).
+        (type string). It's recommended to use 'facebooktest' account since
+        it's a test account and will not trigger credential verification.
+        However, the limitation is the test account cannot access actual
+        facebook's pages & people (more restrictions in
+        https://developers.facebook.com/docs/apps/test-users#rules)
     credentials_path: The string that specifies the path to credential file.
 
   Raises:
diff --git a/tools/perf/page_sets/system_health/long_running_stories.py b/tools/perf/page_sets/system_health/long_running_stories.py
index 2a70985..417faae 100644
--- a/tools/perf/page_sets/system_health/long_running_stories.py
+++ b/tools/perf/page_sets/system_health/long_running_stories.py
@@ -58,6 +58,11 @@
 class _LongRunningGmailMobileBase(_LongRunningGmailBase):
   SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY
 
+  @classmethod
+  def ShouldDisable(cls, possible_browser):
+    # crbug.com/651198
+    return possible_browser.platform.IsSvelte()
+
   def _DidLoadDocument(self, action_runner):
     # Close the "Get Inbox by Gmail" interstitial.
     action_runner.WaitForJavaScriptCondition(
diff --git a/tools/valgrind/gtest_exclude/chrome_elf_unittests.gtest-drmemory_win32.txt b/tools/valgrind/gtest_exclude/chrome_elf_unittests.gtest-drmemory_win32.txt
new file mode 100644
index 0000000..8f8d9f9
--- /dev/null
+++ b/tools/valgrind/gtest_exclude/chrome_elf_unittests.gtest-drmemory_win32.txt
@@ -0,0 +1,2 @@
+# https://crbug.com/628462
+BlacklistTest.LoadBlacklistedLibrary
diff --git a/ui/accessibility/ax_tree.cc b/ui/accessibility/ax_tree.cc
index ddf04d0..0ba6220 100644
--- a/ui/accessibility/ax_tree.cc
+++ b/ui/accessibility/ax_tree.cc
@@ -243,12 +243,19 @@
   // First, delete nodes that used to be children of this node but aren't
   // anymore.
   if (!DeleteOldChildren(node, src.child_ids, update_state)) {
+    // If DeleteOldChildren failed, we need to carefully clean up before
+    // returning false as well. In particular, if this node was a new root,
+    // we need to safely destroy the whole tree.
     if (update_state->new_root) {
       AXNode* old_root = root_;
       root_ = nullptr;
 
       DestroySubtree(old_root, update_state);
-      if (node != old_root &&
+
+      // Delete |node|'s subtree too as long as it wasn't already removed
+      // or added elsewhere in the tree.
+      if (update_state->removed_node_ids.find(src.id) ==
+              update_state->removed_node_ids.end() &&
           update_state->new_nodes.find(node) != update_state->new_nodes.end()) {
         DestroySubtree(node, update_state);
       }
diff --git a/ui/accessibility/ax_tree_unittest.cc b/ui/accessibility/ax_tree_unittest.cc
index 5e8bdcd..dda88e6 100644
--- a/ui/accessibility/ax_tree_unittest.cc
+++ b/ui/accessibility/ax_tree_unittest.cc
@@ -508,4 +508,24 @@
   tree.Unserialize(initial_state);
 }
 
+// UAF caught by ax_tree_fuzzer
+TEST(AXTreeTest, BogusAXTree3) {
+  AXTreeUpdate initial_state;
+  AXNodeData node;
+  node.id = 0;
+  node.state = 0;
+  node.child_ids.push_back(1);
+  initial_state.nodes.push_back(node);
+
+  AXNodeData node2;
+  node2.id = 1;
+  node2.state = 0;
+  node2.child_ids.push_back(1);
+  node2.child_ids.push_back(1);
+  initial_state.nodes.push_back(node2);
+
+  ui::AXTree tree;
+  tree.Unserialize(initial_state);
+}
+
 }  // namespace ui
diff --git a/ui/arc/BUILD.gn b/ui/arc/BUILD.gn
index cacbb33..b3b3b61a 100644
--- a/ui/arc/BUILD.gn
+++ b/ui/arc/BUILD.gn
@@ -24,7 +24,6 @@
     "//base",
     "//components/arc:arc_base",
     "//components/arc:arc_bindings",
-    "//components/arc:arc_bitmap",
     "//components/exo",
     "//components/signin/core/account_id",
     "//mojo/common:common_base",
diff --git a/ui/arc/notification/arc_custom_notification_item.cc b/ui/arc/notification/arc_custom_notification_item.cc
index e4c582c..24fcbb4 100644
--- a/ui/arc/notification/arc_custom_notification_item.cc
+++ b/ui/arc/notification/arc_custom_notification_item.cc
@@ -7,7 +7,6 @@
 #include "base/memory/ptr_util.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
-#include "components/arc/bitmap/bitmap_type_converters.h"
 #include "ui/arc/notification/arc_custom_notification_view.h"
 #include "ui/message_center/notification.h"
 #include "ui/message_center/notification_types.h"
@@ -54,41 +53,44 @@
 }
 
 void ArcCustomNotificationItem::UpdateWithArcNotificationData(
-    const mojom::ArcNotificationData& data) {
+    mojom::ArcNotificationDataPtr data) {
   DCHECK(CalledOnValidThread());
-  DCHECK_EQ(notification_key(), data.key);
+  DCHECK_EQ(notification_key(), data->key);
 
-  if (CacheArcNotificationData(data))
+  if (HasPendingNotification()) {
+    CacheArcNotificationData(std::move(data));
     return;
+  }
 
   message_center::RichNotificationData rich_data;
-  rich_data.pinned = (data.no_clear || data.ongoing_event);
-  rich_data.priority = ConvertAndroidPriority(data.priority);
-  rich_data.small_image = ConvertAndroidSmallIcon(data.small_icon);
-  if (!data.accessible_name.is_null())
-    rich_data.accessible_name = base::UTF8ToUTF16(data.accessible_name.get());
+  rich_data.pinned = (data->no_clear || data->ongoing_event);
+  rich_data.priority = ConvertAndroidPriority(data->priority);
+  if (data->small_icon)
+    rich_data.small_image = gfx::Image::CreateFrom1xBitmap(*data->small_icon);
+  if (!data->accessible_name.is_null())
+    rich_data.accessible_name = base::UTF8ToUTF16(data->accessible_name.get());
 
   message_center::NotifierId notifier_id(
       message_center::NotifierId::SYSTEM_COMPONENT, kNotifierId);
   notifier_id.profile_id = profile_id().GetUserEmail();
 
-  DCHECK(!data.title.is_null());
-  DCHECK(!data.message.is_null());
+  DCHECK(!data->title.is_null());
+  DCHECK(!data->message.is_null());
   SetNotification(base::MakeUnique<message_center::Notification>(
       message_center::NOTIFICATION_TYPE_CUSTOM, notification_id(),
-      base::UTF8ToUTF16(data.title.get()),
-      base::UTF8ToUTF16(data.message.get()), gfx::Image(),
+      base::UTF8ToUTF16(data->title.get()),
+      base::UTF8ToUTF16(data->message.get()), gfx::Image(),
       base::UTF8ToUTF16("arc"),  // display source
       GURL(),                    // empty origin url, for system component
       notifier_id, rich_data, new ArcNotificationDelegate(this)));
 
   pinned_ = rich_data.pinned;
 
-  if (data.snapshot_image.is_null()) {
+  if (!data->snapshot_image || data->snapshot_image->isNull()) {
     snapshot_ = gfx::ImageSkia();
   } else {
     snapshot_ = gfx::ImageSkia(gfx::ImageSkiaRep(
-        data.snapshot_image.To<SkBitmap>(), data.snapshot_image_scale));
+        *data->snapshot_image, data->snapshot_image_scale));
   }
 
   FOR_EACH_OBSERVER(Observer, observers_, OnItemUpdated());
diff --git a/ui/arc/notification/arc_custom_notification_item.h b/ui/arc/notification/arc_custom_notification_item.h
index c2069aa..404a0cd 100644
--- a/ui/arc/notification/arc_custom_notification_item.h
+++ b/ui/arc/notification/arc_custom_notification_item.h
@@ -33,7 +33,7 @@
   ~ArcCustomNotificationItem() override;
 
   void UpdateWithArcNotificationData(
-      const mojom::ArcNotificationData& data) override;
+      mojom::ArcNotificationDataPtr data) override;
 
   void CloseFromCloseButton();
 
diff --git a/ui/arc/notification/arc_notification_item.cc b/ui/arc/notification/arc_notification_item.cc
index 70496697..52d3a5b 100644
--- a/ui/arc/notification/arc_notification_item.cc
+++ b/ui/arc/notification/arc_notification_item.cc
@@ -13,7 +13,6 @@
 #include "base/task_runner.h"
 #include "base/task_runner_util.h"
 #include "base/threading/worker_pool.h"
-#include "components/arc/bitmap/bitmap_type_converters.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkPaint.h"
 #include "ui/gfx/codec/png_codec.h"
@@ -136,81 +135,85 @@
       weak_ptr_factory_(this) {}
 
 void ArcNotificationItem::UpdateWithArcNotificationData(
-    const mojom::ArcNotificationData& data) {
+    mojom::ArcNotificationDataPtr data) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(notification_key_ == data.key);
+  DCHECK(notification_key_ == data->key);
 
   // Check if a decode task is on-going or not. If |notification_| is non-null,
-  // a decode task is on-going asynchronously. Otherwise, there is no task.
+  // a decode task is on-going asynchronously. Otherwise, there is no task and
+  // cache the latest data to the |newer_data_| property.
   // TODO(yoshiki): Refactor and remove this check by omitting image decoding
   // from here.
-  if (CacheArcNotificationData(data))
+  if (HasPendingNotification()) {
+    CacheArcNotificationData(std::move(data));
     return;
+  }
 
   message_center::RichNotificationData rich_data;
   message_center::NotificationType type;
 
-  switch (data.type) {
+  switch (data->type) {
     case mojom::ArcNotificationType::BASIC:
       type = message_center::NOTIFICATION_TYPE_BASE_FORMAT;
       break;
     case mojom::ArcNotificationType::LIST:
       type = message_center::NOTIFICATION_TYPE_MULTIPLE;
 
-      if (data.texts.is_null())
+      if (data->texts.is_null())
         break;
 
       for (size_t i = 0;
-           i < std::min(data.texts.size(),
+           i < std::min(data->texts.size(),
                         message_center::kNotificationMaximumItems - 1);
            i++) {
         rich_data.items.emplace_back(
-            base::string16(), base::UTF8ToUTF16(data.texts.at(i).get()));
+            base::string16(), base::UTF8ToUTF16(data->texts.at(i).get()));
       }
 
-      if (data.texts.size() > message_center::kNotificationMaximumItems) {
+      if (data->texts.size() > message_center::kNotificationMaximumItems) {
         // Show an elipsis as the 5th item if there are more than 5 items.
         rich_data.items.emplace_back(base::string16(), gfx::kEllipsisUTF16);
-      } else if (data.texts.size() ==
+      } else if (data->texts.size() ==
                  message_center::kNotificationMaximumItems) {
         // Show the 5th item if there are exact 5 items.
         rich_data.items.emplace_back(
             base::string16(),
-            base::UTF8ToUTF16(data.texts.at(data.texts.size() - 1).get()));
+            base::UTF8ToUTF16(data->texts.at(data->texts.size() - 1).get()));
       }
       break;
     case mojom::ArcNotificationType::IMAGE:
       type = message_center::NOTIFICATION_TYPE_IMAGE;
 
-      if (!data.big_picture.is_null()) {
+      if (data->big_picture && !data->big_picture->isNull()) {
         rich_data.image = gfx::Image::CreateFrom1xBitmap(
-            CropImage(data.big_picture.To<SkBitmap>()));
+            CropImage(*data->big_picture));
       }
       break;
     case mojom::ArcNotificationType::PROGRESS:
       type = message_center::NOTIFICATION_TYPE_PROGRESS;
       rich_data.timestamp = base::Time::UnixEpoch() +
-                            base::TimeDelta::FromMilliseconds(data.time);
+                            base::TimeDelta::FromMilliseconds(data->time);
       rich_data.progress = std::max(
           0, std::min(100, static_cast<int>(std::round(
-                               static_cast<float>(data.progress_current) /
-                               data.progress_max * 100))));
+                               static_cast<float>(data->progress_current) /
+                               data->progress_max * 100))));
       break;
   }
-  DCHECK(IsKnownEnumValue(data.type)) << "Unsupported notification type: "
-                                      << data.type;
+  DCHECK(IsKnownEnumValue(data->type)) << "Unsupported notification type: "
+                                      << data->type;
 
-  for (size_t i = 0; i < data.buttons.size(); i++) {
+  for (size_t i = 0; i < data->buttons.size(); i++) {
     rich_data.buttons.emplace_back(
-        base::UTF8ToUTF16(data.buttons.at(i)->label.get()));
+        base::UTF8ToUTF16(data->buttons.at(i)->label.get()));
   }
 
   // If the client is old (version < 1), both |no_clear| and |ongoing_event|
   // are false.
-  rich_data.pinned = (data.no_clear || data.ongoing_event);
+  rich_data.pinned = (data->no_clear || data->ongoing_event);
 
-  rich_data.priority = ConvertAndroidPriority(data.priority);
-  rich_data.small_image = ConvertAndroidSmallIcon(data.small_icon);
+  rich_data.priority = ConvertAndroidPriority(data->priority);
+  if (data->small_icon)
+    rich_data.small_image = gfx::Image::CreateFrom1xBitmap(*data->small_icon);
 
   // The identifier of the notifier, which is used to distinguish the notifiers
   // in the message center.
@@ -218,19 +221,19 @@
       message_center::NotifierId::SYSTEM_COMPONENT, kNotifierId);
   notifier_id.profile_id = profile_id_.GetUserEmail();
 
-  DCHECK(!data.title.is_null());
-  DCHECK(!data.message.is_null());
+  DCHECK(!data->title.is_null());
+  DCHECK(!data->message.is_null());
   SetNotification(base::MakeUnique<message_center::Notification>(
-      type, notification_id_, base::UTF8ToUTF16(data.title.get()),
-      base::UTF8ToUTF16(data.message.get()),
+      type, notification_id_, base::UTF8ToUTF16(data->title.get()),
+      base::UTF8ToUTF16(data->message.get()),
       gfx::Image(),              // icon image: Will be overriden later.
       base::UTF8ToUTF16("arc"),  // display source
       GURL(),                    // empty origin url, for system component
       notifier_id, rich_data,
       new ArcNotificationDelegate(weak_ptr_factory_.GetWeakPtr())));
 
-  DCHECK(!data.icon_data.is_null());
-  if (data.icon_data.size() == 0) {
+  DCHECK(!data->icon_data.is_null());
+  if (data->icon_data.size() == 0) {
     OnImageDecoded(SkBitmap());  // Pass an empty bitmap.
     return;
   }
@@ -238,7 +241,7 @@
   // TODO(yoshiki): Remove decoding by passing a bitmap directly from Android.
   base::PostTaskAndReplyWithResult(
       base::WorkerPool::GetTaskRunner(true).get(), FROM_HERE,
-      base::Bind(&DecodeImage, data.icon_data.storage()),
+      base::Bind(&DecodeImage, data->icon_data.storage()),
       base::Bind(&ArcNotificationItem::OnImageDecoded,
                  weak_ptr_factory_.GetWeakPtr()));
 }
@@ -294,25 +297,14 @@
   }
 }
 
-// static
-gfx::Image ArcNotificationItem::ConvertAndroidSmallIcon(
-    const mojom::ArcBitmapPtr& arc_bitmap) {
-  if (arc_bitmap.is_null())
-    return gfx::Image();
-
-  return gfx::Image::CreateFrom1xBitmap(arc_bitmap.To<SkBitmap>());
+bool ArcNotificationItem::HasPendingNotification() {
+  return (notification_ != nullptr);
 }
 
-bool ArcNotificationItem::CacheArcNotificationData(
-    const mojom::ArcNotificationData& data) {
-  if (!notification_)
-    return false;
-
-  // Store the latest data to the |newer_data_| property if there is a pending
-  // |notification_|.
+void ArcNotificationItem::CacheArcNotificationData(
+    mojom::ArcNotificationDataPtr data) {
   // If old |newer_data_| has been stored, discard the old one.
-  newer_data_ = data.Clone();
-  return true;
+  newer_data_ = std::move(data);
 }
 
 void ArcNotificationItem::SetNotification(
@@ -326,8 +318,7 @@
 
   if (newer_data_) {
     // There is the newer data, so updates again.
-    mojom::ArcNotificationDataPtr data(std::move(newer_data_));
-    UpdateWithArcNotificationData(*data);
+    UpdateWithArcNotificationData(std::move(newer_data_));
   }
 }
 
diff --git a/ui/arc/notification/arc_notification_item.h b/ui/arc/notification/arc_notification_item.h
index 3c5131b..a285484 100644
--- a/ui/arc/notification/arc_notification_item.h
+++ b/ui/arc/notification/arc_notification_item.h
@@ -29,7 +29,7 @@
   virtual ~ArcNotificationItem();
 
   virtual void UpdateWithArcNotificationData(
-      const mojom::ArcNotificationData& data);
+      mojom::ArcNotificationDataPtr data);
 
   // Methods called from ArcNotificationManager:
   void OnClosedFromAndroid(bool by_user);
@@ -43,12 +43,11 @@
 
  protected:
   static int ConvertAndroidPriority(int android_priority);
-  static gfx::Image ConvertAndroidSmallIcon(
-      const mojom::ArcBitmapPtr& arc_bitmap);
 
-  // Checks whether there is on-going |notification_|. If so, cache the |data|
-  // in |newer_data_| and returns true. Otherwise, returns false.
-  bool CacheArcNotificationData(const mojom::ArcNotificationData& data);
+  // Checks whether there is on-going |notification_|.
+  bool HasPendingNotification();
+  // Cache the |data| in |newer_data_|.
+  void CacheArcNotificationData(mojom::ArcNotificationDataPtr data);
 
   // Sets the pending |notification_|.
   void SetNotification(
diff --git a/ui/arc/notification/arc_notification_manager.cc b/ui/arc/notification/arc_notification_manager.cc
index ddedc4e6..40f8ea42 100644
--- a/ui/arc/notification/arc_notification_manager.cc
+++ b/ui/arc/notification/arc_notification_manager.cc
@@ -88,7 +88,7 @@
     DCHECK(result.second);
     it = result.first;
   }
-  it->second->UpdateWithArcNotificationData(*data);
+  it->second->UpdateWithArcNotificationData(std::move(data));
 }
 
 void ArcNotificationManager::OnNotificationRemoved(const mojo::String& key) {
diff --git a/ui/gfx/image/canvas_image_source.cc b/ui/gfx/image/canvas_image_source.cc
index b336b31..e53257f 100644
--- a/ui/gfx/image/canvas_image_source.cc
+++ b/ui/gfx/image/canvas_image_source.cc
@@ -6,6 +6,7 @@
 
 #include "base/logging.h"
 #include "ui/gfx/canvas.h"
+#include "ui/gfx/image/image_skia.h"
 
 namespace gfx {
 
diff --git a/ui/gfx/image/canvas_image_source.h b/ui/gfx/image/canvas_image_source.h
index f41c281..1108f0d 100644
--- a/ui/gfx/image/canvas_image_source.h
+++ b/ui/gfx/image/canvas_image_source.h
@@ -7,8 +7,10 @@
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/gfx_export.h"
+#include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/image/image_skia_source.h"
 
 namespace gfx {
@@ -21,7 +23,18 @@
 // completed.
 class GFX_EXPORT CanvasImageSource : public gfx::ImageSkiaSource {
  public:
+  // Factory function to create an ImageSkia from a CanvasImageSource. Example:
+  //   gfx::ImageSkia my_image =
+  //       CanvasImageSource::MakeImageSkia<MySource>(param1, param2);
+  template <typename T, typename... Args>
+  static ImageSkia MakeImageSkia(Args&&... args) {
+    auto source = base::MakeUnique<T>(std::forward<Args>(args)...);
+    gfx::Size size = source->size();
+    return gfx::ImageSkia(source.release(), size);
+  }
+
   CanvasImageSource(const gfx::Size& size, bool is_opaque);
+  ~CanvasImageSource() override {}
 
   // Called when a new image needs to be drawn for a scale factor.
   virtual void Draw(gfx::Canvas* canvas) = 0;
@@ -33,8 +46,6 @@
   gfx::ImageSkiaRep GetImageForScale(float scale) override;
 
  protected:
-  ~CanvasImageSource() override {}
-
   const gfx::Size size_;
   const bool is_opaque_;
   DISALLOW_COPY_AND_ASSIGN(CanvasImageSource);
diff --git a/ui/gfx/ipc/gfx_param_traits_macros.h b/ui/gfx/ipc/gfx_param_traits_macros.h
index 2a8c6e5..cdee2f6 100644
--- a/ui/gfx/ipc/gfx_param_traits_macros.h
+++ b/ui/gfx/ipc/gfx_param_traits_macros.h
@@ -54,6 +54,7 @@
 IPC_STRUCT_TRAITS_BEGIN(gfx::NativePixmapPlane)
   IPC_STRUCT_TRAITS_MEMBER(stride)
   IPC_STRUCT_TRAITS_MEMBER(offset)
+  IPC_STRUCT_TRAITS_MEMBER(size)
   IPC_STRUCT_TRAITS_MEMBER(modifier)
 IPC_STRUCT_TRAITS_END()
 
diff --git a/ui/gfx/mojo/OWNERS b/ui/gfx/mojo/OWNERS
index 1841ff6..7a549ab 100644
--- a/ui/gfx/mojo/OWNERS
+++ b/ui/gfx/mojo/OWNERS
@@ -1,5 +1,2 @@
-per-file *_struct_traits*.*=set noparent
-per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
-
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
+set noparent
+file://ipc/SECURITY_OWNERS
diff --git a/ui/gfx/mojo/buffer_types.mojom b/ui/gfx/mojo/buffer_types.mojom
index 0f0be7e9..49c1ee1 100644
--- a/ui/gfx/mojo/buffer_types.mojom
+++ b/ui/gfx/mojo/buffer_types.mojom
@@ -53,6 +53,7 @@
 struct NativePixmapPlane {
   uint32 stride;
   int32 offset;
+  uint64 size;
   uint64 modifier;
 };
 
diff --git a/ui/gfx/mojo/buffer_types_traits.h b/ui/gfx/mojo/buffer_types_traits.h
index 175a493..311f98e 100644
--- a/ui/gfx/mojo/buffer_types_traits.h
+++ b/ui/gfx/mojo/buffer_types_traits.h
@@ -199,6 +199,9 @@
   static int32_t offset(const gfx::NativePixmapPlane& plane) {
     return plane.offset;
   }
+  static uint64_t size(const gfx::NativePixmapPlane& plane) {
+    return plane.size;
+  }
   static uint64_t modifier(const gfx::NativePixmapPlane& plane) {
     return plane.modifier;
   }
@@ -206,6 +209,7 @@
                    gfx::NativePixmapPlane* out) {
     out->stride = data.stride();
     out->offset = data.offset();
+    out->size = data.size();
     out->modifier = data.modifier();
     return true;
   }
diff --git a/ui/gfx/mojo/struct_traits_unittest.cc b/ui/gfx/mojo/struct_traits_unittest.cc
index 556954b0..d837cd8 100644
--- a/ui/gfx/mojo/struct_traits_unittest.cc
+++ b/ui/gfx/mojo/struct_traits_unittest.cc
@@ -144,6 +144,10 @@
   const gfx::GpuMemoryBufferId kId(99);
   const uint32_t kOffset = 126;
   const int32_t kStride = 256;
+#if defined(USE_OZONE)
+  const uint64_t kSize = kOffset + kStride;
+  const uint64_t kModifier = 2;
+#endif
   base::SharedMemory shared_memory;
   ASSERT_TRUE(shared_memory.CreateAnonymous(1024));
   ASSERT_TRUE(shared_memory.Map(1024));
@@ -155,6 +159,11 @@
   handle.offset = kOffset;
   handle.stride = kStride;
 
+#if defined(USE_OZONE)
+  handle.native_pixmap_handle.planes.emplace_back(kOffset, kStride, kSize,
+                                                  kModifier);
+#endif
+
   mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy();
   gfx::GpuMemoryBufferHandle output;
   proxy->EchoGpuMemoryBufferHandle(handle, &output);
@@ -162,6 +171,13 @@
   EXPECT_EQ(kId, output.id);
   EXPECT_EQ(kOffset, output.offset);
   EXPECT_EQ(kStride, output.stride);
+
+#if defined(USE_OZONE)
+  ASSERT_EQ(1u, output.native_pixmap_handle.planes.size());
+  EXPECT_EQ(kSize, output.native_pixmap_handle.planes.back().size);
+  EXPECT_EQ(kModifier, output.native_pixmap_handle.planes.back().modifier);
+#endif
+
 #if !defined(OS_MACOSX) && !defined(OS_IOS)
   // TODO: Add support for mach_port on mac.
   base::SharedMemory output_memory(output.handle, true);
diff --git a/ui/gfx/native_pixmap_handle.cc b/ui/gfx/native_pixmap_handle.cc
index a3092b265..f0144a8 100644
--- a/ui/gfx/native_pixmap_handle.cc
+++ b/ui/gfx/native_pixmap_handle.cc
@@ -2,14 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <stdint.h>
+
 #include "ui/gfx/native_pixmap_handle.h"
 
 namespace gfx {
 
-NativePixmapPlane::NativePixmapPlane() : stride(0), offset(0), modifier(0) {}
+NativePixmapPlane::NativePixmapPlane()
+    : stride(0), offset(0), size(0), modifier(0) {}
 
-NativePixmapPlane::NativePixmapPlane(int stride, int offset, uint64_t modifier)
-    : stride(stride), offset(offset), modifier(modifier) {}
+NativePixmapPlane::NativePixmapPlane(int stride,
+                                     int offset,
+                                     uint64_t size,
+                                     uint64_t modifier)
+    : stride(stride), offset(offset), size(size), modifier(modifier) {}
 
 NativePixmapPlane::NativePixmapPlane(const NativePixmapPlane& other) = default;
 
diff --git a/ui/gfx/native_pixmap_handle.h b/ui/gfx/native_pixmap_handle.h
index 767951b..eca2bd1d 100644
--- a/ui/gfx/native_pixmap_handle.h
+++ b/ui/gfx/native_pixmap_handle.h
@@ -5,7 +5,7 @@
 #ifndef UI_GFX_NATIVE_PIXMAP_HANDLE_H_
 #define UI_GFX_NATIVE_PIXMAP_HANDLE_H_
 
-#include <stdint.h>
+#include <stddef.h>
 #include <vector>
 
 #include "ui/gfx/gfx_export.h"
@@ -20,7 +20,7 @@
 // buffer. More fields can be added if they are plane specific.
 struct GFX_EXPORT NativePixmapPlane {
   NativePixmapPlane();
-  NativePixmapPlane(int stride, int offset, uint64_t modifier);
+  NativePixmapPlane(int stride, int offset, uint64_t size, uint64_t modifier);
   NativePixmapPlane(const NativePixmapPlane& other);
   ~NativePixmapPlane();
 
@@ -28,6 +28,9 @@
   // a memory mapping. One per plane per entry.
   int stride;
   int offset;
+  // Size in bytes of the plane.
+  // This is necessary to map the buffers.
+  uint64_t size;
   // The modifier is retrieved from GBM library and passed to EGL driver.
   // Generally it's platform specific, and we don't need to modify it in
   // Chromium code. Also one per plane per entry.
diff --git a/ui/gfx/paint_vector_icon.cc b/ui/gfx/paint_vector_icon.cc
index 70daac2..1ac78e27 100644
--- a/ui/gfx/paint_vector_icon.cc
+++ b/ui/gfx/paint_vector_icon.cc
@@ -10,6 +10,7 @@
 #include "base/i18n/rtl.h"
 #include "base/lazy_instance.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "third_party/skia/include/core/SkPaint.h"
@@ -596,8 +597,8 @@
 ImageSkia CreateVectorIconFromSource(const std::string& source,
                                      int dip_size,
                                      SkColor color) {
-  return ImageSkia(new VectorIconSourceLegacy(source, dip_size, color),
-                   gfx::Size(dip_size, dip_size));
+  return CanvasImageSource::MakeImageSkia<VectorIconSourceLegacy>(
+      source, dip_size, color);
 }
 
 }  // namespace gfx
diff --git a/ui/ozone/gl/gl_image_ozone_native_pixmap_drm_unittest.cc b/ui/ozone/gl/gl_image_ozone_native_pixmap_drm_unittest.cc
index cc2f152..8ab537f 100644
--- a/ui/ozone/gl/gl_image_ozone_native_pixmap_drm_unittest.cc
+++ b/ui/ozone/gl/gl_image_ozone_native_pixmap_drm_unittest.cc
@@ -50,6 +50,10 @@
       0, pitches[0] * size.height() + pitches[1] * size.height() / 2,
       pitches[0] * size.height(),
   };
+  std::vector<size_t> sizes{pitches[0] * size.height(),
+                            pitches[1] * size.height() / 2,
+                            pitches[2] * size.height() / 2};
+
   size_t byte_number = pitches[0] * size.height() +
                        pitches[1] * size.height() / 2 +
                        pitches[2] * size.height() / 2;
@@ -89,7 +93,7 @@
   gfx::NativePixmapHandle pixmap_handle;
   pixmap_handle.fds.emplace_back(fd, false);
   for (int i = 0; i < 3; i++) {
-    pixmap_handle.planes.emplace_back(pitches[i], offsets[i], 0);
+    pixmap_handle.planes.emplace_back(pitches[i], offsets[i], sizes[i], 0);
   }
   ui::SurfaceFactoryOzone* surface_factory =
       ui::OzonePlatform::GetInstance()->GetSurfaceFactoryOzone();
diff --git a/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc b/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc
index 98bf556..78514ef 100644
--- a/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc
+++ b/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc
@@ -38,11 +38,16 @@
     if (usage == gfx::BufferUsage::GPU_READ_CPU_READ_WRITE) {
       auto client_pixmap = client_pixmap_factory_->ImportFromHandle(
           pixmap->ExportHandle(), size, usage);
-      void* data = client_pixmap->Map();
-      EXPECT_TRUE(data);
-      GLImageTestSupport::SetBufferDataToColor(
-          size.width(), size.height(), pixmap->GetDmaBufPitch(0), 0,
-          pixmap->GetBufferFormat(), color, static_cast<uint8_t*>(data));
+      bool mapped = client_pixmap->Map();
+      EXPECT_TRUE(mapped);
+
+      for (size_t plane = 0; plane < NumberOfPlanesForBufferFormat(format);
+           ++plane) {
+        void* data = client_pixmap->GetMemoryAddress(plane);
+        GLImageTestSupport::SetBufferDataToColor(
+            size.width(), size.height(), pixmap->GetDmaBufPitch(plane), plane,
+            pixmap->GetBufferFormat(), color, static_cast<uint8_t*>(data));
+      }
       client_pixmap->Unmap();
     }
 
diff --git a/ui/ozone/platform/cast/client_native_pixmap_factory_cast.cc b/ui/ozone/platform/cast/client_native_pixmap_factory_cast.cc
index 9c1cf29..01f0b0f 100644
--- a/ui/ozone/platform/cast/client_native_pixmap_factory_cast.cc
+++ b/ui/ozone/platform/cast/client_native_pixmap_factory_cast.cc
@@ -19,12 +19,19 @@
 class ClientNativePixmapCast : public ClientNativePixmap {
  public:
   // ClientNativePixmap implementation:
-  void* Map() override {
+  bool Map() override {
+    NOTREACHED();
+    return false;
+  }
+  void* GetMemoryAddress(size_t plane) const override {
     NOTREACHED();
     return nullptr;
-  }
+  };
   void Unmap() override { NOTREACHED(); }
-  void GetStride(int* stride) const override { NOTREACHED(); }
+  int GetStride(size_t plane) const override {
+    NOTREACHED();
+    return 0;
+  }
 };
 
 class ClientNativePixmapFactoryCast : public ClientNativePixmapFactory {
diff --git a/ui/ozone/platform/drm/client_native_pixmap_factory_gbm.cc b/ui/ozone/platform/drm/client_native_pixmap_factory_gbm.cc
index 19b3e104..06aada4 100644
--- a/ui/ozone/platform/drm/client_native_pixmap_factory_gbm.cc
+++ b/ui/ozone/platform/drm/client_native_pixmap_factory_gbm.cc
@@ -21,12 +21,19 @@
   ClientNativePixmapGbm() {}
   ~ClientNativePixmapGbm() override {}
 
-  void* Map() override {
+  bool Map() override {
+    NOTREACHED();
+    return false;
+  }
+  void Unmap() override { NOTREACHED(); }
+  void* GetMemoryAddress(size_t plane) const override {
     NOTREACHED();
     return nullptr;
   }
-  void Unmap() override { NOTREACHED(); }
-  void GetStride(int* stride) const override { NOTREACHED(); }
+  int GetStride(size_t plane) const override {
+    NOTREACHED();
+    return 0;
+  }
 };
 
 }  // namespace
@@ -73,21 +80,20 @@
       const gfx::Size& size,
       gfx::BufferUsage usage) override {
     DCHECK(!handle.fds.empty());
-    base::ScopedFD scoped_fd(handle.fds[0].fd);
     switch (usage) {
       case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE:
       case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE_PERSISTENT:
 #if defined(OS_CHROMEOS)
-        // TODO(dcastagna): Add support for pixmaps with multiple FDs for non
-        // scanout buffers.
-        return ClientNativePixmapDmaBuf::ImportFromDmabuf(
-            scoped_fd.release(), size, handle.planes[0].stride);
+        return ClientNativePixmapDmaBuf::ImportFromDmabuf(handle, size);
 #else
         NOTREACHED();
         return nullptr;
 #endif
       case gfx::BufferUsage::GPU_READ:
       case gfx::BufferUsage::SCANOUT:
+        // Close all the fds.
+        for (const auto& fd : handle.fds)
+          base::ScopedFD scoped_fd(fd.fd);
         return base::WrapUnique(new ClientNativePixmapGbm);
     }
     NOTREACHED();
diff --git a/ui/ozone/platform/drm/common/client_native_pixmap_dmabuf.cc b/ui/ozone/platform/drm/common/client_native_pixmap_dmabuf.cc
index a04bc5c4..8c547f8 100644
--- a/ui/ozone/platform/drm/common/client_native_pixmap_dmabuf.cc
+++ b/ui/ozone/platform/drm/common/client_native_pixmap_dmabuf.cc
@@ -58,42 +58,46 @@
 
 // static
 std::unique_ptr<ClientNativePixmap> ClientNativePixmapDmaBuf::ImportFromDmabuf(
-    int dmabuf_fd,
-    const gfx::Size& size,
-    int stride) {
-  DCHECK_GE(dmabuf_fd, 0);
-  base::CheckedNumeric<size_t> map_size = stride;
-  map_size *= size.height();
-  if (!map_size.IsValid())
-    return nullptr;
-  return base::WrapUnique(new ClientNativePixmapDmaBuf(dmabuf_fd, size, stride,
-                                                       map_size.ValueOrDie()));
+    const gfx::NativePixmapHandle& handle,
+    const gfx::Size& size) {
+  return base::WrapUnique(new ClientNativePixmapDmaBuf(handle, size));
 }
 
-ClientNativePixmapDmaBuf::ClientNativePixmapDmaBuf(int dmabuf_fd,
-                                                   const gfx::Size& size,
-                                                   int stride,
-                                                   size_t map_size)
-    : dmabuf_fd_(dmabuf_fd), map_size_(map_size), size_(size), stride_(stride) {
+ClientNativePixmapDmaBuf::ClientNativePixmapDmaBuf(
+    const gfx::NativePixmapHandle& handle,
+    const gfx::Size& size)
+    : pixmap_handle_(handle), size_(size), data_{0} {
   TRACE_EVENT0("drm", "ClientNativePixmapDmaBuf");
-  data_ = mmap(nullptr, map_size_, (PROT_READ | PROT_WRITE), MAP_SHARED,
-               dmabuf_fd, 0);
+  // TODO(dcastagna): support multiple fds.
+  DCHECK_EQ(1u, handle.fds.size());
+  DCHECK_GE(handle.fds.front().fd, 0);
+  dmabuf_fd_.reset(handle.fds.front().fd);
+
+  DCHECK_GE(handle.planes.back().size, 0u);
+  size_t map_size = handle.planes.back().offset + handle.planes.back().size;
+  data_ = mmap(nullptr, map_size, (PROT_READ | PROT_WRITE), MAP_SHARED,
+               dmabuf_fd_.get(), 0);
   if (data_ == MAP_FAILED) {
     PLOG(ERROR) << "Failed mmap().";
-    base::TerminateBecauseOutOfMemory(map_size_);
+    base::TerminateBecauseOutOfMemory(map_size);
   }
 }
 
 ClientNativePixmapDmaBuf::~ClientNativePixmapDmaBuf() {
   TRACE_EVENT0("drm", "~ClientNativePixmapDmaBuf");
-  int ret = munmap(data_, map_size_);
+  size_t map_size =
+      pixmap_handle_.planes.back().offset + pixmap_handle_.planes.back().size;
+  int ret = munmap(data_, map_size);
   DCHECK(!ret);
 }
 
-void* ClientNativePixmapDmaBuf::Map() {
+bool ClientNativePixmapDmaBuf::Map() {
   TRACE_EVENT0("drm", "DmaBuf:Map");
-  PrimeSyncStart(dmabuf_fd_.get());
-  return data_;
+  if (data_ != nullptr) {
+    PrimeSyncStart(dmabuf_fd_.get());
+    return true;
+  }
+  return false;
 }
 
 void ClientNativePixmapDmaBuf::Unmap() {
@@ -101,8 +105,15 @@
   PrimeSyncEnd(dmabuf_fd_.get());
 }
 
-void ClientNativePixmapDmaBuf::GetStride(int* stride) const {
-  *stride = stride_;
+void* ClientNativePixmapDmaBuf::GetMemoryAddress(size_t plane) const {
+  DCHECK_LT(plane, pixmap_handle_.planes.size());
+  uint8_t* address = reinterpret_cast<uint8_t*>(data_);
+  return address + pixmap_handle_.planes[plane].offset;
+}
+
+int ClientNativePixmapDmaBuf::GetStride(size_t plane) const {
+  DCHECK_LT(plane, pixmap_handle_.planes.size());
+  return pixmap_handle_.planes[plane].stride;
 }
 
 }  // namespace ui
diff --git a/ui/ozone/platform/drm/common/client_native_pixmap_dmabuf.h b/ui/ozone/platform/drm/common/client_native_pixmap_dmabuf.h
index 4fef392..9817235 100644
--- a/ui/ozone/platform/drm/common/client_native_pixmap_dmabuf.h
+++ b/ui/ozone/platform/drm/common/client_native_pixmap_dmabuf.h
@@ -12,32 +12,33 @@
 #include "base/files/scoped_file.h"
 #include "base/macros.h"
 #include "ui/gfx/geometry/size.h"
+#include "ui/gfx/native_pixmap_handle.h"
 #include "ui/ozone/public/client_native_pixmap.h"
 
 namespace ui {
 
 class ClientNativePixmapDmaBuf : public ClientNativePixmap {
  public:
-  static std::unique_ptr<ClientNativePixmap>
-  ImportFromDmabuf(int dmabuf_fd, const gfx::Size& size, int stride);
+  static std::unique_ptr<ClientNativePixmap> ImportFromDmabuf(
+      const gfx::NativePixmapHandle& handle,
+      const gfx::Size& size);
 
   ~ClientNativePixmapDmaBuf() override;
 
   // Overridden from ClientNativePixmap.
-  void* Map() override;
+  bool Map() override;
   void Unmap() override;
-  void GetStride(int* stride) const override;
+
+  void* GetMemoryAddress(size_t plane) const override;
+  int GetStride(size_t plane) const override;
 
  private:
-  ClientNativePixmapDmaBuf(int dmabuf_fd,
-                           const gfx::Size& size,
-                           int stride,
-                           size_t map_size);
+  ClientNativePixmapDmaBuf(const gfx::NativePixmapHandle& handle,
+                           const gfx::Size& size);
 
-  base::ScopedFD dmabuf_fd_;
-  const size_t map_size_;
+  const gfx::NativePixmapHandle pixmap_handle_;
   const gfx::Size size_;
-  const int stride_;
+  base::ScopedFD dmabuf_fd_;
   void* data_;
 
   DISALLOW_COPY_AND_ASSIGN(ClientNativePixmapDmaBuf);
diff --git a/ui/ozone/platform/drm/gpu/gbm_buffer.cc b/ui/ozone/platform/drm/gpu/gbm_buffer.cc
index 8b9a893..0f38ed8 100644
--- a/ui/ozone/platform/drm/gpu/gbm_buffer.cc
+++ b/ui/ozone/platform/drm/gpu/gbm_buffer.cc
@@ -75,6 +75,11 @@
   return planes_[index].offset;
 }
 
+size_t GbmBuffer::GetSize(size_t index) const {
+  DCHECK_LT(index, planes_.size());
+  return planes_[index].size;
+}
+
 uint64_t GbmBuffer::GetFormatModifier(size_t index) const {
   DCHECK_LT(index, planes_.size());
   return planes_[index].modifier;
@@ -123,16 +128,20 @@
     // kept open for the lifetime of the buffer.
     base::ScopedFD fd(gbm_bo_get_plane_fd(bo, i));
 
-    if (!fd.is_valid()) {
-      PLOG(ERROR) << "Failed to export buffer to dma_buf";
-      gbm_bo_destroy(bo);
-      return nullptr;
+    // TODO(dcastagna): support multiple fds.
+    // crbug.com/642410
+    if (!i) {
+      if (!fd.is_valid()) {
+        PLOG(ERROR) << "Failed to export buffer to dma_buf";
+        gbm_bo_destroy(bo);
+        return nullptr;
+      }
+      fds.emplace_back(std::move(fd));
     }
-    fds.emplace_back(std::move(fd));
 
-    planes.emplace_back(gbm_bo_get_plane_stride(bo, i),
-                        gbm_bo_get_plane_offset(bo, i),
-                        gbm_bo_get_plane_format_modifier(bo, i));
+    planes.emplace_back(
+        gbm_bo_get_plane_stride(bo, i), gbm_bo_get_plane_offset(bo, i),
+        gbm_bo_get_plane_size(bo, i), gbm_bo_get_plane_format_modifier(bo, i));
   }
   scoped_refptr<GbmBuffer> buffer(new GbmBuffer(
       gbm, bo, format, usage, std::move(fds), size, std::move(planes)));
@@ -216,6 +225,7 @@
           base::FileDescriptor(scoped_fd.release(), true /* auto_close */));
     }
     handle.planes.emplace_back(buffer_->GetStride(i), buffer_->GetOffset(i),
+                               buffer_->GetSize(i),
                                buffer_->GetFormatModifier(i));
   }
   return handle;
diff --git a/ui/ozone/platform/drm/gpu/gbm_buffer.h b/ui/ozone/platform/drm/gpu/gbm_buffer.h
index b8397448..f4ff68a2 100644
--- a/ui/ozone/platform/drm/gpu/gbm_buffer.h
+++ b/ui/ozone/platform/drm/gpu/gbm_buffer.h
@@ -41,6 +41,7 @@
   int GetFd(size_t plane) const;
   int GetStride(size_t plane) const;
   int GetOffset(size_t plane) const;
+  size_t GetSize(size_t plane) const;
   uint64_t GetFormatModifier(size_t plane) const;
   gfx::Size GetSize() const override;
 
diff --git a/ui/ozone/platform/x11/x11_surface_factory.cc b/ui/ozone/platform/x11/x11_surface_factory.cc
index bb92d7e..484dc650 100644
--- a/ui/ozone/platform/x11/x11_surface_factory.cc
+++ b/ui/ozone/platform/x11/x11_surface_factory.cc
@@ -158,6 +158,7 @@
 
 std::vector<gl::GLImplementation>
 X11SurfaceFactory::GetAllowedGLImplementations() {
+  DCHECK(thread_checker_.CalledOnValidThread());
   std::vector<gl::GLImplementation> impls;
   impls.push_back(gl::kGLImplementationEGLGLES2);
   // DesktopGL (GLX) should be the first option when crbug.com/646982 is fixed.
@@ -167,6 +168,7 @@
 }
 
 GLOzone* X11SurfaceFactory::GetGLOzone(gl::GLImplementation implementation) {
+  DCHECK(thread_checker_.CalledOnValidThread());
   switch (implementation) {
     case gl::kGLImplementationDesktopGL:
       return glx_implementation_.get();
diff --git a/ui/ozone/platform/x11/x11_surface_factory.h b/ui/ozone/platform/x11/x11_surface_factory.h
index 77bee714..dfccd55 100644
--- a/ui/ozone/platform/x11/x11_surface_factory.h
+++ b/ui/ozone/platform/x11/x11_surface_factory.h
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "base/threading/thread_checker.h"
 #include "ui/gl/gl_surface.h"
 #include "ui/ozone/public/gl_ozone.h"
 #include "ui/ozone/public/surface_factory_ozone.h"
@@ -29,6 +30,11 @@
   std::unique_ptr<GLOzone> glx_implementation_;
   std::unique_ptr<GLOzone> egl_implementation_;
 
+  // X11 doesn't care if things being called from different threads if
+  // XInitThreads() was called. However, GBM does care. This will ensure X11
+  // and GBM behave roughly the same.
+  base::ThreadChecker thread_checker_;
+
   DISALLOW_COPY_AND_ASSIGN(X11SurfaceFactory);
 };
 
diff --git a/ui/ozone/public/client_native_pixmap.h b/ui/ozone/public/client_native_pixmap.h
index e7aa3615..a94e34f 100644
--- a/ui/ozone/public/client_native_pixmap.h
+++ b/ui/ozone/public/client_native_pixmap.h
@@ -16,9 +16,13 @@
  public:
   virtual ~ClientNativePixmap() {}
 
-  virtual void* Map() = 0;
+  // Map each plane in the client address space.
+  // Return false on error.
+  virtual bool Map() = 0;
   virtual void Unmap() = 0;
-  virtual void GetStride(int* stride) const = 0;
+
+  virtual void* GetMemoryAddress(size_t plane) const = 0;
+  virtual int GetStride(size_t plane) const = 0;
 };
 
 }  // namespace ui
diff --git a/ui/resources/default_100_percent/common/signal_0_bar_selected.png b/ui/resources/default_100_percent/common/signal_0_bar_selected.png
new file mode 100644
index 0000000..852adfc
--- /dev/null
+++ b/ui/resources/default_100_percent/common/signal_0_bar_selected.png
Binary files differ
diff --git a/ui/resources/default_100_percent/common/signal_1_bar.png b/ui/resources/default_100_percent/common/signal_1_bar.png
index 3c50615..a33489c7 100644
--- a/ui/resources/default_100_percent/common/signal_1_bar.png
+++ b/ui/resources/default_100_percent/common/signal_1_bar.png
Binary files differ
diff --git a/ui/resources/default_100_percent/common/signal_1_bar_selected.png b/ui/resources/default_100_percent/common/signal_1_bar_selected.png
new file mode 100644
index 0000000..3b7f7ade
--- /dev/null
+++ b/ui/resources/default_100_percent/common/signal_1_bar_selected.png
Binary files differ
diff --git a/ui/resources/default_100_percent/common/signal_2_bar.png b/ui/resources/default_100_percent/common/signal_2_bar.png
index 47fa640b..375738f0 100644
--- a/ui/resources/default_100_percent/common/signal_2_bar.png
+++ b/ui/resources/default_100_percent/common/signal_2_bar.png
Binary files differ
diff --git a/ui/resources/default_100_percent/common/signal_2_bar_selected.png b/ui/resources/default_100_percent/common/signal_2_bar_selected.png
new file mode 100644
index 0000000..b80307c3
--- /dev/null
+++ b/ui/resources/default_100_percent/common/signal_2_bar_selected.png
Binary files differ
diff --git a/ui/resources/default_100_percent/common/signal_3_bar.png b/ui/resources/default_100_percent/common/signal_3_bar.png
index 3423a2f..1cc3530 100644
--- a/ui/resources/default_100_percent/common/signal_3_bar.png
+++ b/ui/resources/default_100_percent/common/signal_3_bar.png
Binary files differ
diff --git a/ui/resources/default_100_percent/common/signal_3_bar_selected.png b/ui/resources/default_100_percent/common/signal_3_bar_selected.png
new file mode 100644
index 0000000..1ccc977
--- /dev/null
+++ b/ui/resources/default_100_percent/common/signal_3_bar_selected.png
Binary files differ
diff --git a/ui/resources/default_100_percent/common/signal_4_bar_selected.png b/ui/resources/default_100_percent/common/signal_4_bar_selected.png
new file mode 100644
index 0000000..6e8a4f9
--- /dev/null
+++ b/ui/resources/default_100_percent/common/signal_4_bar_selected.png
Binary files differ
diff --git a/ui/resources/default_200_percent/common/signal_0_bar_selected.png b/ui/resources/default_200_percent/common/signal_0_bar_selected.png
new file mode 100644
index 0000000..42b7a8d
--- /dev/null
+++ b/ui/resources/default_200_percent/common/signal_0_bar_selected.png
Binary files differ
diff --git a/ui/resources/default_200_percent/common/signal_1_bar_selected.png b/ui/resources/default_200_percent/common/signal_1_bar_selected.png
new file mode 100644
index 0000000..68cc98f4
--- /dev/null
+++ b/ui/resources/default_200_percent/common/signal_1_bar_selected.png
Binary files differ
diff --git a/ui/resources/default_200_percent/common/signal_2_bar.png b/ui/resources/default_200_percent/common/signal_2_bar.png
index f6a64e16..a29c55c 100644
--- a/ui/resources/default_200_percent/common/signal_2_bar.png
+++ b/ui/resources/default_200_percent/common/signal_2_bar.png
Binary files differ
diff --git a/ui/resources/default_200_percent/common/signal_2_bar_selected.png b/ui/resources/default_200_percent/common/signal_2_bar_selected.png
new file mode 100644
index 0000000..1b6faf4
--- /dev/null
+++ b/ui/resources/default_200_percent/common/signal_2_bar_selected.png
Binary files differ
diff --git a/ui/resources/default_200_percent/common/signal_3_bar_selected.png b/ui/resources/default_200_percent/common/signal_3_bar_selected.png
new file mode 100644
index 0000000..dbd7679
--- /dev/null
+++ b/ui/resources/default_200_percent/common/signal_3_bar_selected.png
Binary files differ
diff --git a/ui/resources/default_200_percent/common/signal_4_bar_selected.png b/ui/resources/default_200_percent/common/signal_4_bar_selected.png
new file mode 100644
index 0000000..967b476
--- /dev/null
+++ b/ui/resources/default_200_percent/common/signal_4_bar_selected.png
Binary files differ
diff --git a/ui/resources/ui_resources.grd b/ui/resources/ui_resources.grd
index 57360e74..9c4cd67 100644
--- a/ui/resources/ui_resources.grd
+++ b/ui/resources/ui_resources.grd
@@ -189,6 +189,11 @@
         <structure type="chrome_scaled_image" name="IDR_SIGNAL_2_BAR" file="common/signal_2_bar.png" />
         <structure type="chrome_scaled_image" name="IDR_SIGNAL_3_BAR" file="common/signal_3_bar.png" />
         <structure type="chrome_scaled_image" name="IDR_SIGNAL_4_BAR" file="common/signal_4_bar.png" />
+        <structure type="chrome_scaled_image" name="IDR_SIGNAL_0_BAR_SELECTED" file="common/signal_0_bar_selected.png" />
+        <structure type="chrome_scaled_image" name="IDR_SIGNAL_1_BAR_SELECTED" file="common/signal_1_bar_selected.png" />
+        <structure type="chrome_scaled_image" name="IDR_SIGNAL_2_BAR_SELECTED" file="common/signal_2_bar_selected.png" />
+        <structure type="chrome_scaled_image" name="IDR_SIGNAL_3_BAR_SELECTED" file="common/signal_3_bar_selected.png" />
+        <structure type="chrome_scaled_image" name="IDR_SIGNAL_4_BAR_SELECTED" file="common/signal_4_bar_selected.png" />
       </if>
       <if expr="use_aura">
         <structure type="chrome_scaled_image" name="IDR_TEXT_SELECTION_HANDLE_CENTER" file="common/text_selection_handle_center.png" />
diff --git a/ui/views/mus/clipboard_mus.cc b/ui/views/mus/clipboard_mus.cc
index 8e43571d..3fb01b9 100644
--- a/ui/views/mus/clipboard_mus.cc
+++ b/ui/views/mus/clipboard_mus.cc
@@ -4,6 +4,10 @@
 
 #include "ui/views/mus/clipboard_mus.h"
 
+#include <string>
+#include <utility>
+#include <vector>
+
 #include "base/logging.h"
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -256,7 +260,8 @@
 
 void ClipboardMus::WriteObjects(ui::ClipboardType type,
                                 const ObjectMap& objects) {
-  current_clipboard_.reset(new mojo::Map<mojo::String, mojo::Array<uint8_t>>);
+  current_clipboard_ =
+      base::MakeUnique<mojo::Map<mojo::String, mojo::Array<uint8_t>>>();
   for (const auto& p : objects)
     DispatchObject(static_cast<ObjectType>(p.first), p.second);
 
diff --git a/ui/views/mus/input_method_mus.cc b/ui/views/mus/input_method_mus.cc
index fb28dbd..9540e984 100644
--- a/ui/views/mus/input_method_mus.cc
+++ b/ui/views/mus/input_method_mus.cc
@@ -114,7 +114,7 @@
   InputMethodBase::OnDidChangeFocusedClient(focused_before, focused);
   UpdateTextInputType();
 
-  text_input_client_.reset(new TextInputClientImpl(focused, this));
+  text_input_client_ = base::MakeUnique<TextInputClientImpl>(focused, this);
   ime_server_->StartSession(text_input_client_->CreateInterfacePtrAndBind(),
                             GetProxy(&input_method_));
 }
diff --git a/ui/views/mus/input_method_mus_unittest.cc b/ui/views/mus/input_method_mus_unittest.cc
index 0c0e3c6..618a46b3 100644
--- a/ui/views/mus/input_method_mus_unittest.cc
+++ b/ui/views/mus/input_method_mus_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "ui/views/mus/input_method_mus.h"
 
+#include <memory>
+
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -37,7 +39,7 @@
   ~TestTextInputClient() override {}
 
   ui::KeyEvent* WaitUntilInputReceieved() {
-    run_loop_.reset(new base::RunLoop);
+    run_loop_ = base::MakeUnique<base::RunLoop>();
     run_loop_->Run();
     run_loop_.reset();
 
diff --git a/ui/views/mus/pointer_watcher_event_router_unittest.cc b/ui/views/mus/pointer_watcher_event_router_unittest.cc
index ba6cec9..511cc33 100644
--- a/ui/views/mus/pointer_watcher_event_router_unittest.cc
+++ b/ui/views/mus/pointer_watcher_event_router_unittest.cc
@@ -30,7 +30,7 @@
   void OnPointerEventObserved(const ui::PointerEvent& event,
                               const gfx::Point& location_in_screen,
                               Widget* target) override {
-    last_event_observed_.reset(new ui::PointerEvent(event));
+    last_event_observed_ = base::MakeUnique<ui::PointerEvent>(event);
   }
 
  private:
diff --git a/ui/views/mus/views_mus_test_suite.cc b/ui/views/mus/views_mus_test_suite.cc
index 701ea56..bf63030 100644
--- a/ui/views/mus/views_mus_test_suite.cc
+++ b/ui/views/mus/views_mus_test_suite.cc
@@ -5,6 +5,7 @@
 #include "ui/views/mus/views_mus_test_suite.h"
 
 #include <memory>
+#include <string>
 
 #include "base/command_line.h"
 #include "base/files/file_path.h"
@@ -33,7 +34,7 @@
 
 class DefaultService : public shell::Service {
  public:
-   DefaultService() {}
+  DefaultService() {}
   ~DefaultService() override {}
 
  private:
@@ -114,12 +115,11 @@
   }
 
   void SetUpConnections(base::WaitableEvent* wait) {
-    background_shell_.reset(new shell::BackgroundShell);
+    background_shell_ = base::MakeUnique<shell::BackgroundShell>();
     background_shell_->Init(nullptr);
-    service_.reset(new DefaultService);
-    shell_connection_.reset(new shell::ServiceContext(
-        service_.get(),
-        background_shell_->CreateServiceRequest(GetTestName())));
+    service_ = base::MakeUnique<DefaultService>();
+    shell_connection_ = base::MakeUnique<shell::ServiceContext>(
+        service_.get(), background_shell_->CreateServiceRequest(GetTestName()));
 
     // ui/views/mus requires a WindowManager running, so launch test_wm.
     shell::Connector* connector = shell_connection_->connector();
@@ -166,7 +166,7 @@
   EnsureCommandLineSwitch(ui::switches::kUseTestConfig);
 
   ViewsTestSuite::Initialize();
-  shell_connections_.reset(new ShellConnection);
+  shell_connections_ = base::MakeUnique<ShellConnection>();
 }
 
 void ViewsMusTestSuite::Shutdown() {
diff --git a/ui/views/mus/window_manager_connection.cc b/ui/views/mus/window_manager_connection.cc
index 7b30672..8c4cf85 100644
--- a/ui/views/mus/window_manager_connection.cc
+++ b/ui/views/mus/window_manager_connection.cc
@@ -4,6 +4,7 @@
 
 #include "ui/views/mus/window_manager_connection.h"
 
+#include <set>
 #include <utility>
 
 #include "base/lazy_instance.h"
@@ -113,20 +114,20 @@
   lazy_tls_ptr.Pointer()->Set(this);
 
   gpu_service_ = ui::GpuService::Create(connector, std::move(task_runner));
-  compositor_context_factory_.reset(
-      new views::SurfaceContextFactory(gpu_service_.get()));
+  compositor_context_factory_ =
+      base::MakeUnique<views::SurfaceContextFactory>(gpu_service_.get());
   aura::Env::GetInstance()->set_context_factory(
       compositor_context_factory_.get());
-  client_.reset(new ui::WindowTreeClient(this, nullptr, nullptr));
+  client_ = base::MakeUnique<ui::WindowTreeClient>(this, nullptr, nullptr);
   client_->ConnectViaWindowTreeFactory(connector_);
 
-  pointer_watcher_event_router_.reset(
-      new PointerWatcherEventRouter(client_.get()));
+  pointer_watcher_event_router_ =
+      base::MakeUnique<PointerWatcherEventRouter>(client_.get());
 
-  screen_.reset(new ScreenMus(this));
+  screen_ = base::MakeUnique<ScreenMus>(this);
   screen_->Init(connector);
 
-  std::unique_ptr<ClipboardMus> clipboard(new ClipboardMus);
+  std::unique_ptr<ClipboardMus> clipboard = base::MakeUnique<ClipboardMus>();
   clipboard->Init(connector);
   ui::Clipboard::SetClipboardForCurrentThread(std::move(clipboard));
 
diff --git a/ui/views/mus/window_tree_host_mus.cc b/ui/views/mus/window_tree_host_mus.cc
index 745c1a6c..caed8943 100644
--- a/ui/views/mus/window_tree_host_mus.cc
+++ b/ui/views/mus/window_tree_host_mus.cc
@@ -54,7 +54,7 @@
   dispatcher()->set_transform_events(false);
   compositor()->SetHostHasTransparentBackground(true);
 
-  input_method_.reset(new InputMethodMus(this, window));
+  input_method_ = base::MakeUnique<InputMethodMus>(this, window);
   SetSharedInputMethod(input_method_.get());
 }
 
diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc
index 4b3db3f..93eafed5 100644
--- a/ui/views/widget/widget.cc
+++ b/ui/views/widget/widget.cc
@@ -1210,7 +1210,14 @@
       }
       if (root_view)
         root_view->OnMouseReleased(*event);
-      if ((event->flags() & ui::EF_IS_NON_CLIENT) == 0)
+      if ((event->flags() & ui::EF_IS_NON_CLIENT) == 0 &&
+          // If none of the "normal" buttons are pressed, this event may be from
+          // one of the newer mice that have buttons bound to browser forward
+          // back actions. Don't squelch the event and let the default handler
+          // process it.
+          (event->flags() &
+           (ui::EF_LEFT_MOUSE_BUTTON | ui::EF_MIDDLE_MOUSE_BUTTON |
+            ui::EF_RIGHT_MOUSE_BUTTON)) != 0)
         event->SetHandled();
       return;
 
diff --git a/ui/webui/resources/cr_elements/cr_shared_menu/cr_shared_menu.html b/ui/webui/resources/cr_elements/cr_shared_menu/cr_shared_menu.html
index 6522f729..c9b0070a 100644
--- a/ui/webui/resources/cr_elements/cr_shared_menu/cr_shared_menu.html
+++ b/ui/webui/resources/cr_elements/cr_shared_menu/cr_shared_menu.html
@@ -6,27 +6,27 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-dropdown/iron-dropdown.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/paper-listbox/paper-listbox.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/shadow.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-menu-button/paper-menu-button-animations.html">
 
 <dom-module id="cr-shared-menu">
   <template>
     <style>
-      #menu {
+      paper-listbox {
         @apply(--shadow-elevation-2dp);
-        background-color: white;
         overflow: hidden;
-        padding: 8px 0;
         position: relative;
+        width: var(--cr-shared-menu-width);
       }
     </style>
     <iron-dropdown id="dropdown" allow-outside-scroll restore-focus-on-close
         vertical-align="auto" horizontal-align="right" opened="{{menuOpen}}"
         open-animation-config="[[openAnimationConfig]]"
         close-animation-config="[[closeAnimationConfig]]">
-      <div id="menu" class="dropdown-content" role="menu">
+      <paper-listbox id="menu" class="dropdown-content">
         <content></content>
-      </div>
+      </paper-listbox>
     </iron-dropdown>
   </template>
   <script src="cr_shared_menu.js"></script>
diff --git a/ui/webui/resources/cr_elements/cr_shared_menu/cr_shared_menu.js b/ui/webui/resources/cr_elements/cr_shared_menu/cr_shared_menu.js
index 6fc5d451..872b4b8 100644
--- a/ui/webui/resources/cr_elements/cr_shared_menu/cr_shared_menu.js
+++ b/ui/webui/resources/cr_elements/cr_shared_menu/cr_shared_menu.js
@@ -8,8 +8,6 @@
 Polymer({
   is: 'cr-shared-menu',
 
-  behaviors: [Polymer.IronA11yKeysBehavior],
-
   properties: {
     menuOpen: {
       type: Boolean,
@@ -28,14 +26,6 @@
       value: null,
     },
 
-    /** @override */
-    keyEventTarget: {
-      type: Object,
-      value: function() {
-        return this.$.menu;
-      }
-    },
-
     openAnimationConfig: {
       type: Object,
       value: function() {
@@ -76,10 +66,6 @@
     }
   },
 
-  keyBindings: {
-    'tab': 'onTabPressed_',
-  },
-
   listeners: {
     'dropdown.iron-overlay-canceled': 'onOverlayCanceled_',
   },
@@ -90,21 +76,19 @@
    */
   lastAnchor_: null,
 
-  /**
-   * The first focusable child in the menu's light DOM.
-   * @private {?Element}
-   */
-  firstFocus_: null,
-
-  /**
-   * The last focusable child in the menu's light DOM.
-   * @private {?Element}
-   */
-  lastFocus_: null,
+  /** @private {?function(!Event)} */
+  keyHandler_: null,
 
   /** @override */
   attached: function() {
     window.addEventListener('resize', this.closeMenu.bind(this));
+    this.keyHandler_ = this.onCaptureKeyDown_.bind(this);
+    this.$.menu.addEventListener('keydown', this.keyHandler_, true);
+  },
+
+  /** @override */
+  detached: function() {
+    this.$.menu.removeEventListener('keydown', this.keyHandler_, true);
   },
 
   /** Closes the menu. */
@@ -132,15 +116,7 @@
     this.itemData = opt_itemData || null;
     this.lastAnchor_ = anchor;
     this.$.dropdown.restoreFocusOnClose = true;
-
-    var focusableChildren = Polymer.dom(this).querySelectorAll(
-        '[tabindex]:not([disabled]):not([hidden]),' +
-        'button:not([disabled]):not([hidden])');
-    if (focusableChildren.length > 0) {
-      this.$.dropdown.focusTarget = focusableChildren[0];
-      this.firstFocus_ = focusableChildren[0];
-      this.lastFocus_ = focusableChildren[focusableChildren.length - 1];
-    }
+    this.$.menu.selected = -1;
 
     // Move the menu to the anchor.
     this.$.dropdown.positionTarget = anchor;
@@ -160,28 +136,22 @@
   },
 
   /**
-   * Trap focus inside the menu. As a very basic heuristic, will wrap focus from
-   * the first element with a nonzero tabindex to the last such element.
-   * TODO(tsergeant): Use iron-focus-wrap-behavior once it is available
-   * (https://github.com/PolymerElements/iron-overlay-behavior/issues/179).
-   * @param {CustomEvent} e
+   * Close the menu when tab is pressed. Note that we must
+   * explicitly add a capture event listener to do this as iron-menu-behavior
+   * eats all key events during bubbling. See
+   * https://github.com/PolymerElements/iron-menu-behavior/issues/56.
+   * This will move focus to the next focusable element before/after the
+   * anchor.
+   * @private
    */
-  onTabPressed_: function(e) {
-    if (!this.firstFocus_ || !this.lastFocus_)
-      return;
-
-    var toFocus;
-    var keyEvent = e.detail.keyboardEvent;
-    if (keyEvent.shiftKey && keyEvent.target == this.firstFocus_)
-      toFocus = this.lastFocus_;
-    else if (!keyEvent.shiftKey && keyEvent.target == this.lastFocus_)
-      toFocus = this.firstFocus_;
-
-    if (!toFocus)
-      return;
-
-    e.preventDefault();
-    toFocus.focus();
+  onCaptureKeyDown_: function(e) {
+    if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(e, 'tab')) {
+      // Need to refocus the anchor synchronously so that the tab event takes
+      // effect on it.
+      this.$.dropdown.restoreFocusOnClose = false;
+      this.lastAnchor_.focus();
+      this.closeMenu();
+    }
   },
 
   /**