diff --git a/BUILD.gn b/BUILD.gn
index 579eb72..26e7857f 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -282,6 +282,7 @@
       "//third_party/smhasher:murmurhash3",
       "//tools/android:android_tools",
       "//tools/android:memconsumer",
+      "//tools/android:push_apps_to_background",
       "//tools/android/heap_profiler:heap_profiler_unittests",
       "//tools/android/kerberos/SpnegoAuthenticator:spnego_authenticator_apk",
       "//tools/cygprofile:cygprofile_unittests",
diff --git a/DEPS b/DEPS
index 5a46e34..e958979 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': 'e683c56115a210b5993df9294260bb147b408bfa',
+  'skia_revision': '7fb4f8bd031eda87e1da9bc0f749968c0e872e6f',
   # 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': 'a7ac1c416b81b5b55cd451aa5f840eda2085613c',
+  'v8_revision': 'a09b4096907ecd4379058b5dd86119fc345044f7',
   # 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.
@@ -267,7 +267,7 @@
 
   'src/third_party/catapult':
     Var('chromium_git') + '/external/github.com/catapult-project/catapult.git' + '@' +
-    'ed08f0f1f07a6d16e3626c3a197499763f9b76c4',
+    'c56019de05c674d27b24ff4a6d5f1448fd923f09',
 
   'src/third_party/openh264/src':
     Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + 'b37cda248234162033e3e11b0335f3131cdfe488',
diff --git a/android_webview/android_webview_tests.gypi b/android_webview/android_webview_tests.gypi
index ab92ffc..c87b792 100644
--- a/android_webview/android_webview_tests.gypi
+++ b/android_webview/android_webview_tests.gypi
@@ -34,7 +34,7 @@
           '<(asset_location)/full_screen_video_test.html',
           '<(asset_location)/full_screen_video_inside_div_test.html',
           '<(asset_location)/multiple_videos_test.html',
-          '<(asset_location)/video.mp4',
+          '<(asset_location)/video.webm',
           '<(asset_location)/visual_state_during_fullscreen_test.html',
           '<(asset_location)/visual_state_waits_for_js_test.html',
           '<(asset_location)/visual_state_waits_for_js_detached_test.html',
@@ -62,7 +62,7 @@
             '<(java_in_dir)/assets/full_screen_video_test.html',
             '<(java_in_dir)/assets/full_screen_video_inside_div_test.html',
             '<(java_in_dir)/assets/multiple_videos_test.html',
-            '<(java_in_dir)/assets/video.mp4',
+            '<(java_in_dir)/assets/video.webm',
             '<(java_in_dir)/assets/visual_state_during_fullscreen_test.html',
             '<(java_in_dir)/assets/visual_state_waits_for_js_test.html',
             '<(java_in_dir)/assets/visual_state_waits_for_js_detached_test.html',
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/KeySystemTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/KeySystemTest.java
index 32ee9aa9..ff9e489f 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/KeySystemTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/KeySystemTest.java
@@ -4,6 +4,7 @@
 
 package org.chromium.android_webview.test;
 
+import android.os.Build;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import org.chromium.android_webview.AwContents;
@@ -66,12 +67,16 @@
                 + "  navigator.requestMediaKeySystemAccess(keySystem, [{}]).then("
                 + "      success, failure);"
                 + "}"
+                + "function areProprietaryCodecsSupported() {"
+                + "  var video = document.createElement('video');"
+                + "  return video.canPlayType('video/mp4; codecs=\"avc1\"');"
+                + "}"
                 + "</script> </html>";
     }
 
     private String isKeySystemSupported(String keySystem) throws Exception {
-        executeJavaScriptAndWaitForResult(mAwContents, mContentsClient,
-                  "isKeySystemSupported('" + keySystem + "')");
+        executeJavaScriptAndWaitForResult(
+                mAwContents, mContentsClient, "isKeySystemSupported('" + keySystem + "')");
 
         poll(new Callable<Boolean>() {
             @Override
@@ -83,6 +88,12 @@
         return getResultFromJS();
     }
 
+    private boolean areProprietaryCodecsSupported() throws Exception {
+        String result = executeJavaScriptAndWaitForResult(
+                mAwContents, mContentsClient, "areProprietaryCodecsSupported()");
+        return !result.isEmpty();
+    }
+
     private String getResultFromJS() {
         String result = "null";
         try {
@@ -94,6 +105,18 @@
         return result;
     }
 
+    private String getPlatformKeySystemExpectations() throws Exception {
+        // Android key systems only support non-proprietary codecs on Lollipop+.
+        // When neither is true isKeySystemSupported() will return an error for
+        // all key systems except ClearKey (which is handled by Chrome itself).
+        if (!areProprietaryCodecsSupported()
+                && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+            return "\"NotSupportedError\"";
+        }
+
+        return "\"supported\"";
+    }
+
     @Feature({"AndroidWebView"})
     @SmallTest
     public void testSupportClearKeySystem() throws Throwable {
@@ -103,7 +126,8 @@
     @Feature({"AndroidWebView"})
     @SmallTest
     public void testSupportWidevineKeySystem() throws Throwable {
-        assertEquals("\"supported\"", isKeySystemSupported("com.widevine.alpha"));
+        assertEquals(
+                getPlatformKeySystemExpectations(), isKeySystemSupported("com.widevine.alpha"));
     }
 
     @Feature({"AndroidWebView"})
@@ -115,7 +139,8 @@
     @Feature({"AndroidWebView"})
     @SmallTest
     public void testSupportPlatformKeySystem() throws Throwable {
-        assertEquals("\"supported\"", isKeySystemSupported("x-com.oem.test-keysystem"));
+        assertEquals(getPlatformKeySystemExpectations(),
+                isKeySystemSupported("x-com.oem.test-keysystem"));
     }
 
     @Feature({"AndroidWebView"})
diff --git a/android_webview/test/BUILD.gn b/android_webview/test/BUILD.gn
index 92b46fa..68b71d4 100644
--- a/android_webview/test/BUILD.gn
+++ b/android_webview/test/BUILD.gn
@@ -65,7 +65,7 @@
     "shell/assets/full_screen_video_inside_div_test.html",
     "shell/assets/full_screen_video_test.html",
     "shell/assets/multiple_videos_test.html",
-    "shell/assets/video.mp4",
+    "shell/assets/video.webm",
     "shell/assets/visual_state_during_fullscreen_test.html",
     "shell/assets/visual_state_on_page_commit_visible_test.html",
     "shell/assets/visual_state_waits_for_js_detached_test.html",
diff --git a/android_webview/test/shell/assets/full_screen_video_inside_div_test.html b/android_webview/test/shell/assets/full_screen_video_inside_div_test.html
index 7a8f4f2..f76d98110 100644
--- a/android_webview/test/shell/assets/full_screen_video_inside_div_test.html
+++ b/android_webview/test/shell/assets/full_screen_video_inside_div_test.html
@@ -9,7 +9,7 @@
 <div id='div'>
     <button id="playControl" style='padding:10px 10px;' onclick="playVideo(); return false">Play</button>
     <video style = 'width: 300px; height: 300px;'  id='video'>
-        <source src="video.mp4" type="video/mp4">
+        <source src="video.webm" type="video/webm">
     </video>
 </div>
 </body>
diff --git a/android_webview/test/shell/assets/full_screen_video_test.html b/android_webview/test/shell/assets/full_screen_video_test.html
index c046e70..6d1979d 100644
--- a/android_webview/test/shell/assets/full_screen_video_test.html
+++ b/android_webview/test/shell/assets/full_screen_video_test.html
@@ -9,7 +9,7 @@
 <button id="fullscreenControl" autofocus style ='padding:10px 10px;' onclick="goFullscreen('video'); return false">Go fullscreen</button>
 <button id="playControl" style='padding:10px 10px;' onclick="playVideo(); return false">Play</button>
 <video style = 'width: 10px; height: 10px;' id='video' controls>
-    <source src="video.mp4" type="video/mp4">
+    <source src="video.webm" type="video/webm">
 </video>
 </body>
 </html>
diff --git a/android_webview/test/shell/assets/multiple_videos_test.html b/android_webview/test/shell/assets/multiple_videos_test.html
index 12ded883..70c3945 100644
--- a/android_webview/test/shell/assets/multiple_videos_test.html
+++ b/android_webview/test/shell/assets/multiple_videos_test.html
@@ -18,11 +18,11 @@
 <button id="playSecondButton" style='padding:10px 10px;' onclick="playSecondVideo(); return false">Play second</button>
 
 <video style='width: 10px; height: 10px;' id='firstVideo' controls>
-  <source src="video.mp4" type="video/mp4">
+  <source src="video.webm" type="video/webm">
 </video>
 
 <video style='width: 10px; height: 10px;' id='secondVideo' controls>
-  <source src="video.mp4" type="video/mp4">
+  <source src="video.webm" type="video/webm">
 </video>
 
 </body>
diff --git a/android_webview/test/shell/assets/video.mp4 b/android_webview/test/shell/assets/video.mp4
deleted file mode 100644
index 3763b59..0000000
--- a/android_webview/test/shell/assets/video.mp4
+++ /dev/null
Binary files differ
diff --git a/android_webview/test/shell/assets/video.webm b/android_webview/test/shell/assets/video.webm
new file mode 100644
index 0000000..7bfc552
--- /dev/null
+++ b/android_webview/test/shell/assets/video.webm
Binary files differ
diff --git a/ash/shell.cc b/ash/shell.cc
index d8987ee..6949d6c0 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -866,6 +866,12 @@
       display_manager_.get(), window_tree_host_manager_.get()));
 
 #if defined(OS_CHROMEOS)
+  // When running as part of mash, OzonePlatform is not initialized in the
+  // ash_sysui process. DisplayConfigurator will try to use OzonePlatform and
+  // crash. Instead, mash can manually set default display size using
+  // --ash-host-window-bounds flag.
+  if (in_mus_)
+    display_configurator_->set_configure_display(false);
   display_configurator_->Init(!gpu_support_->IsPanelFittingDisabled());
 
   // The DBusThreadManager must outlive this Shell. See the DCHECK in ~Shell.
diff --git a/ash/touch/touch_hud_projection.cc b/ash/touch/touch_hud_projection.cc
index af38df2..277cdd82 100644
--- a/ash/touch/touch_hud_projection.cc
+++ b/ash/touch/touch_hud_projection.cc
@@ -85,14 +85,10 @@
       alpha = static_cast<int>(fadeout_->CurrentValueBetween(alpha, 0));
     fill_paint_.setAlpha(alpha);
     stroke_paint_.setAlpha(alpha);
-    skia::RefPtr<SkShader> shader = skia::AdoptRef(
-        SkGradientShader::CreateRadial(gradient_center_,
-                                       SkIntToScalar(kPointRadius),
-                                       gradient_colors_,
-                                       gradient_pos_,
-                                       arraysize(gradient_colors_),
-                                       SkShader::kMirror_TileMode));
-    fill_paint_.setShader(shader.get());
+    fill_paint_.setShader(SkGradientShader::MakeRadial(
+        gradient_center_, SkIntToScalar(kPointRadius), gradient_colors_,
+        gradient_pos_, arraysize(gradient_colors_),
+        SkShader::kMirror_TileMode));
     canvas->DrawCircle(circle_center_, SkIntToScalar(kPointRadius),
                        fill_paint_);
     canvas->DrawCircle(circle_center_, SkIntToScalar(kPointRadius),
diff --git a/ash/wm/gestures/long_press_affordance_handler.cc b/ash/wm/gestures/long_press_affordance_handler.cc
index eafa30d..a6c3f07 100644
--- a/ash/wm/gestures/long_press_affordance_handler.cc
+++ b/ash/wm/gestures/long_press_affordance_handler.cc
@@ -103,16 +103,13 @@
   int radius = (end_radius + start_radius) / 2;
   int glow_width = end_radius - start_radius;
   SkPoint sk_center(PointToSkPoint(center));
-  skia::RefPtr<SkShader> shader =
-      skia::AdoptRef(SkGradientShader::CreateTwoPointConical(
-          sk_center, SkIntToScalar(start_radius), sk_center,
-          SkIntToScalar(end_radius), colors, pos, num_colors,
-          SkShader::kClamp_TileMode));
-  DCHECK(shader);
   SkPaint paint;
   paint.setStyle(SkPaint::kStroke_Style);
   paint.setStrokeWidth(glow_width);
-  paint.setShader(shader.get());
+  paint.setShader(SkGradientShader::MakeTwoPointConical(
+      sk_center, SkIntToScalar(start_radius), sk_center,
+      SkIntToScalar(end_radius), colors, pos, num_colors,
+      SkShader::kClamp_TileMode));
   paint.setAntiAlias(true);
   SkPath arc_path;
   arc_path.addArc(SkRect::MakeXYWH(center.x() - radius,
diff --git a/base/allocator/allocator_shim.cc b/base/allocator/allocator_shim.cc
index cc5097ec..f6890350 100644
--- a/base/allocator/allocator_shim.cc
+++ b/base/allocator/allocator_shim.cc
@@ -72,8 +72,16 @@
 }
 
 inline const allocator::AllocatorDispatch* GetChainHead() {
+  // TODO(primiano): Just use NoBarrier_Load once crbug.com/593344 is fixed.
+  // Unfortunately due to that bug NoBarrier_Load() is mistakenly fully
+  // barriered on Linux+Clang, and that causes visible perf regressons.
   return reinterpret_cast<const allocator::AllocatorDispatch*>(
-      subtle::NoBarrier_Load(&g_chain_head));
+#if defined(OS_LINUX) && defined(__clang__)
+      *static_cast<const volatile subtle::AtomicWord*>(&g_chain_head)
+#else
+      subtle::NoBarrier_Load(&g_chain_head)
+#endif
+  );
 }
 
 }  // namespace
diff --git a/base/mac/sdk_forward_declarations.h b/base/mac/sdk_forward_declarations.h
index 85c98e9..c9b7d64 100644
--- a/base/mac/sdk_forward_declarations.h
+++ b/base/mac/sdk_forward_declarations.h
@@ -552,34 +552,6 @@
 #endif  // MAC_OS_X_VERSION_10_10
 
 // ----------------------------------------------------------------------------
-// Chrome uses -[CWNetwork securityMode] and -[CWNetwork rssi] on OSX 10.6. The
-// former method relies on the enum CWSecurityMode which was removed in the OSX
-// 10.9 SDK. In order for Chrome to compile against an OSX 10.9+ SDK, Chrome
-// must define this enum. Chrome must also declare these methods.
-//
-// These declarations and definitions will not be necessary once Chrome no
-// longer runs on OSX 10.6.
-// ----------------------------------------------------------------------------
-#if defined(MAC_OS_X_VERSION_10_9) && \
-    MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_6
-typedef enum {
-  kCWSecurityModeOpen = 0,
-  kCWSecurityModeWEP,
-  kCWSecurityModeWPA_PSK,
-  kCWSecurityModeWPA2_PSK,
-  kCWSecurityModeWPA_Enterprise,
-  kCWSecurityModeWPA2_Enterprise,
-  kCWSecurityModeWPS,
-  kCWSecurityModeDynamicWEP
-} CWSecurityMode;
-
-@interface CWNetwork (SnowLeopardSDK)
-@property(readonly) NSNumber* rssi;
-@property(readonly) NSNumber* securityMode;
-@end
-#endif
-
-// ----------------------------------------------------------------------------
 // The symbol for kCWSSIDDidChangeNotification is available in the
 // CoreWLAN.framework for OSX versions 10.6 through 10.10. The symbol is not
 // declared in the OSX 10.9+ SDK, so when compiling against an OSX 10.9+ SDK,
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
index 7feacdb..ea4f816 100644
--- a/base/metrics/histogram.cc
+++ b/base/metrics/histogram.cc
@@ -154,22 +154,10 @@
   ImportPersistentHistograms();
 
   HistogramBase* histogram = StatisticsRecorder::FindHistogram(name_);
-
-  // crbug.com/588946 debugging. See comment at end of function.
-  const BucketRanges* created_ranges =
-      reinterpret_cast<const BucketRanges*>(0xDEADBEEF);
-  const BucketRanges* registered_ranges =
-      reinterpret_cast<const BucketRanges*>(0xDEADBEEF);
-  HistogramBase* tentative_histogram =
-      reinterpret_cast<HistogramBase*>(0xDEADBEEF);
-  PersistentMemoryAllocator* allocator =
-      reinterpret_cast<PersistentMemoryAllocator*>(0xDEADBEEF);
-  PersistentMemoryAllocator::Reference histogram_ref = 0xDEADBEEF;
-
   if (!histogram) {
     // To avoid racy destruction at shutdown, the following will be leaked.
-    created_ranges = CreateRanges();
-    registered_ranges =
+    const BucketRanges* created_ranges = CreateRanges();
+    const BucketRanges* registered_ranges =
         StatisticsRecorder::RegisterOrDeleteDuplicateRanges(created_ranges);
 
     // In most cases, the bucket-count, minimum, and maximum values are known
@@ -182,17 +170,15 @@
       minimum_ = registered_ranges->range(1);
       maximum_ = registered_ranges->range(bucket_count_ - 1);
     }
-    CHECK_LT(0, minimum_);
-    CHECK_LT(0, maximum_);
 
     // Try to create the histogram using a "persistent" allocator. As of
     // 2015-01-14, the availability of such is controlled by a base::Feature
     // that is off by default. If the allocator doesn't exist or if
     // allocating from it fails, code below will allocate the histogram from
     // the process heap.
-    histogram_ref = 0;
-    tentative_histogram = nullptr;
-    allocator =
+    PersistentMemoryAllocator::Reference histogram_ref = 0;
+    HistogramBase* tentative_histogram = nullptr;
+    PersistentMemoryAllocator* allocator =
         GetPersistentHistogramMemoryAllocator();
     if (allocator) {
       flags_ |= HistogramBase::kIsPersistent;
@@ -205,12 +191,6 @@
           registered_ranges,
           flags_,
           &histogram_ref);
-      CHECK_LT(0, minimum_);
-      CHECK_LT(0, maximum_);
-      CHECK_EQ(minimum_,
-               static_cast<Histogram*>(tentative_histogram)->declared_min_);
-      CHECK_EQ(maximum_,
-               static_cast<Histogram*>(tentative_histogram)->declared_max_);
     }
 
     // Handle the case where no persistent allocator is present or the
@@ -220,12 +200,6 @@
       DCHECK(!allocator);  // Shouldn't have failed.
       flags_ &= ~HistogramBase::kIsPersistent;
       tentative_histogram = HeapAlloc(registered_ranges);
-      CHECK_LT(0, minimum_);
-      CHECK_LT(0, maximum_);
-      CHECK_EQ(minimum_,
-               static_cast<Histogram*>(tentative_histogram)->declared_min_);
-      CHECK_EQ(maximum_,
-               static_cast<Histogram*>(tentative_histogram)->declared_max_);
     }
 
     FillHistogram(tentative_histogram);
@@ -240,15 +214,6 @@
   }
 
   DCHECK_EQ(histogram_type_, histogram->GetHistogramType());
-  bool bad_args = false;
-  HistogramBase* existing_histogram = histogram;
-  HistogramType existing_type = histogram->GetHistogramType();
-  const char* existing_name = histogram->histogram_name().c_str();
-  Sample existing_minimum = static_cast<Histogram*>(histogram)->declared_min_;
-  Sample existing_maximum = static_cast<Histogram*>(histogram)->declared_max_;
-  uint32_t existing_bucket_count =
-    static_cast<Histogram*>(histogram)->bucket_count();
-
   if (bucket_count_ != 0 &&
       !histogram->HasConstructionArguments(minimum_, maximum_, bucket_count_)) {
     // The construction arguments do not match the existing histogram.  This can
@@ -258,45 +223,8 @@
     // on dereference, but extension/Pepper APIs will guard against NULL and not
     // crash.
     DLOG(ERROR) << "Histogram " << name_ << " has bad construction arguments";
-    bad_args = true;
-    histogram = nullptr;
+    return nullptr;
   }
-
-#if !DCHECK_IS_ON()  // Don't affect tests, only release builds.
-  // For the moment, crash here so that collected crash reports have access
-  // to the construction values in order to figure out why this is failing.
-  // TODO(bcwhite): Remove this once crbug.com/588946 is resolved. Also remove
-  // from beta-branch because we don't want crashes due to misbehaving
-  // extensions (see comment above).
-  if (!histogram) {
-    HistogramType histogram_type = histogram_type_;
-    HistogramBase::Sample minimum = minimum_;
-    HistogramBase::Sample maximum = maximum_;
-    uint32_t bucket_count = bucket_count_;
-    int32_t flags = flags_;
-    CHECK(histogram) << name_ << ": bad-args=" << bad_args;
-    base::debug::Alias(&histogram_type);
-    base::debug::Alias(&minimum);
-    base::debug::Alias(&maximum);
-    base::debug::Alias(&bucket_count);
-    base::debug::Alias(&flags);
-    base::debug::Alias(&created_ranges);
-    base::debug::Alias(&registered_ranges);
-    base::debug::Alias(&histogram_ref);
-    base::debug::Alias(&tentative_histogram);
-    base::debug::Alias(&allocator);
-    base::debug::Alias(&tentative_histogram);
-  }
-#endif
-
-  // Down here so vars are always "used".
-  base::debug::Alias(&bad_args);
-  base::debug::Alias(&existing_histogram);
-  base::debug::Alias(&existing_type);
-  base::debug::Alias(&existing_name);
-  base::debug::Alias(&existing_minimum);
-  base::debug::Alias(&existing_maximum);
-  base::debug::Alias(&existing_bucket_count);
   return histogram;
 }
 
@@ -558,12 +486,8 @@
     bucket_ranges_(ranges),
     declared_min_(minimum),
     declared_max_(maximum) {
-  CHECK_LT(0, minimum);
-  CHECK_LT(0, maximum);
   if (ranges)
     samples_.reset(new SampleVector(HashMetricName(name), ranges));
-  CHECK_EQ(minimum, declared_min_);
-  CHECK_EQ(maximum, declared_max_);
 }
 
 Histogram::Histogram(const std::string& name,
@@ -579,16 +503,12 @@
     bucket_ranges_(ranges),
     declared_min_(minimum),
     declared_max_(maximum) {
-  CHECK_LT(0, minimum);
-  CHECK_LT(0, maximum);
   if (ranges) {
     samples_.reset(new SampleVector(HashMetricName(name),
                                     counts, counts_size, meta, ranges));
     logged_samples_.reset(new SampleVector(samples_->id(), logged_counts,
                                            counts_size, logged_meta, ranges));
   }
-  CHECK_EQ(minimum, declared_min_);
-  CHECK_EQ(maximum, declared_max_);
 }
 
 Histogram::~Histogram() {
diff --git a/base/metrics/histogram_persistence.cc b/base/metrics/histogram_persistence.cc
index 34b3100b..f18d175 100644
--- a/base/metrics/histogram_persistence.cc
+++ b/base/metrics/histogram_persistence.cc
@@ -244,12 +244,6 @@
   // validated below; the local copy is to ensure that the contents cannot
   // be externally changed between validation and use.
   PersistentHistogramData histogram_data = *histogram_data_ptr;
-  CHECK_EQ(histogram_data.histogram_type, histogram_data_ptr->histogram_type);
-  CHECK_EQ(histogram_data.flags, histogram_data_ptr->flags);
-  CHECK_EQ(histogram_data.minimum, histogram_data_ptr->minimum);
-  CHECK_EQ(histogram_data.maximum, histogram_data_ptr->maximum);
-  CHECK_EQ(histogram_data.bucket_count, histogram_data_ptr->bucket_count);
-  CHECK_EQ(histogram_data.ranges_checksum, histogram_data_ptr->ranges_checksum);
 
   HistogramBase::Sample* ranges_data =
       allocator->GetAsObject<HistogramBase::Sample>(histogram_data.ranges_ref,
@@ -294,8 +288,6 @@
   HistogramBase::AtomicCount* logged_data =
       counts_data + histogram_data.bucket_count;
 
-  CHECK_LT(0, histogram_data.minimum);
-  CHECK_LT(0, histogram_data.maximum);
   std::string name(histogram_data_ptr->name);
   HistogramBase* histogram = nullptr;
   switch (histogram_data.histogram_type) {
diff --git a/base/metrics/histogram_unittest.cc b/base/metrics/histogram_unittest.cc
index e6aefd3..beb6a71 100644
--- a/base/metrics/histogram_unittest.cc
+++ b/base/metrics/histogram_unittest.cc
@@ -668,7 +668,7 @@
   EXPECT_FALSE(iter.SkipBytes(1));
 }
 
-TEST_P(HistogramTest, DISABLED_BadConstruction) {
+TEST_P(HistogramTest, BadConstruction) {
   HistogramBase* histogram = Histogram::FactoryGet(
       "BadConstruction", 0, 100, 8, HistogramBase::kNoFlags);
   EXPECT_TRUE(histogram->HasConstructionArguments(1, 100, 8));
diff --git a/base/metrics/metrics_hashes.cc b/base/metrics/metrics_hashes.cc
index 54c117b..5672b06d 100644
--- a/base/metrics/metrics_hashes.cc
+++ b/base/metrics/metrics_hashes.cc
@@ -4,7 +4,6 @@
 
 #include "base/metrics/metrics_hashes.h"
 
-#include "base/debug/alias.h"
 #include "base/logging.h"
 #include "base/md5.h"
 #include "base/sys_byteorder.h"
@@ -16,14 +15,9 @@
 // Converts the 8-byte prefix of an MD5 hash into a uint64_t value.
 inline uint64_t DigestToUInt64(const base::MD5Digest& digest) {
   uint64_t value;
-  CHECK_GE(sizeof(digest.a), sizeof(value));
+  DCHECK_GE(sizeof(digest.a), sizeof(value));
   memcpy(&value, digest.a, sizeof(value));
-  uint64_t hash = base::NetToHost64(value);
-  CHECK_NE(0U, hash);
-  base::debug::Alias(&hash);
-  base::debug::Alias(&value);
-  base::debug::Alias(&digest);
-  return hash;
+  return base::NetToHost64(value);
 }
 
 }  // namespace
diff --git a/base/metrics/statistics_recorder.cc b/base/metrics/statistics_recorder.cc
index 90d64bb..d0fa2ad 100644
--- a/base/metrics/statistics_recorder.cc
+++ b/base/metrics/statistics_recorder.cc
@@ -5,7 +5,6 @@
 #include "base/metrics/statistics_recorder.h"
 
 #include "base/at_exit.h"
-#include "base/debug/alias.h"
 #include "base/debug/leak_annotations.h"
 #include "base/json/string_escape.h"
 #include "base/logging.h"
@@ -124,17 +123,13 @@
         histogram_to_return = histogram;
       } else {
         // We already have one histogram with this name.
-        CHECK_EQ(histogram->histogram_name(),
-                 it->second->histogram_name()) << "hash collision";
+        DCHECK_EQ(histogram->histogram_name(),
+                  it->second->histogram_name()) << "hash collision";
         histogram_to_return = it->second;
         histogram_to_delete = histogram;
       }
-      base::debug::Alias(&it);
-      base::debug::Alias(&name);
-      base::debug::Alias(&name_hash);
     }
   }
-  base::debug::Alias(&histogram);
   delete histogram_to_delete;
   return histogram_to_return;
 }
@@ -284,22 +279,10 @@
   if (histograms_ == NULL)
     return NULL;
 
-  const uint64_t lookup_hash = HashMetricName(name);
-  HistogramMap::iterator it = histograms_->find(lookup_hash);
+  HistogramMap::iterator it = histograms_->find(HashMetricName(name));
   if (histograms_->end() == it)
     return NULL;
-
-  const uint64_t existing_hash = it->first;
-  const char* existing_name = it->second->histogram_name().c_str();
-  HistogramMap* histograms = histograms_;
-  CHECK_EQ(name, it->second->histogram_name()) << "hash collision";
-  base::debug::Alias(&lookup_hash);
-  base::debug::Alias(&existing_hash);
-  base::debug::Alias(&name);
-  base::debug::Alias(&existing_name);
-  base::debug::Alias(&it);
-  base::debug::Alias(&histograms);
-
+  DCHECK_EQ(name, it->second->histogram_name()) << "hash collision";
   return it->second;
 }
 
diff --git a/build/all.gyp b/build/all.gyp
index 8f5e701..4d2fe4f 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -834,6 +834,7 @@
             '../third_party/WebKit/public/all.gyp:*',
             '../tools/android/android_tools.gyp:android_tools',
             '../tools/android/android_tools.gyp:memconsumer',
+            '../tools/android/android_tools.gyp:push_apps_to_background',
             '../tools/android/findbugs_plugin/findbugs_plugin.gyp:findbugs_plugin_test',
             '../tools/cygprofile/cygprofile.gyp:cygprofile_unittests',
             '../ui/android/ui_android.gyp:ui_android_unittests',
diff --git a/build/android/BUILD.gn b/build/android/BUILD.gn
index 9766c87..77ee5fb 100644
--- a/build/android/BUILD.gn
+++ b/build/android/BUILD.gn
@@ -80,9 +80,9 @@
   data = [
     "devil_chromium.json",
     "devil_chromium.py",
-    "//third_party/android_tools/sdk/build-tools/23.0.0/aapt",
-    "//third_party/android_tools/sdk/build-tools/23.0.0/dexdump",
-    "//third_party/android_tools/sdk/build-tools/23.0.0/split-select",
+    "//third_party/android_tools/sdk/build-tools/23.0.1/aapt",
+    "//third_party/android_tools/sdk/build-tools/23.0.1/dexdump",
+    "//third_party/android_tools/sdk/build-tools/23.0.1/split-select",
     "//third_party/android_tools/sdk/platform-tools/adb",
     "//third_party/catapult/catapult_base/catapult_base/",
     "//third_party/catapult/dependency_manager/dependency_manager/",
diff --git a/build/android/devil_chromium.json b/build/android/devil_chromium.json
index 489add8..c1157fa 100644
--- a/build/android/devil_chromium.json
+++ b/build/android/devil_chromium.json
@@ -5,7 +5,7 @@
       "file_info": {
         "linux2_x86_64": {
           "local_paths": [
-            "../../third_party/android_tools/sdk/build-tools/23.0.0/aapt"
+            "../../third_party/android_tools/sdk/build-tools/23.0.1/aapt"
           ]
         }
       }
@@ -32,7 +32,7 @@
       "file_info": {
         "linux2_x86_64": {
           "local_paths": [
-            "../../third_party/android_tools/sdk/build-tools/23.0.0/dexdump"
+            "../../third_party/android_tools/sdk/build-tools/23.0.1/dexdump"
           ]
         }
       }
@@ -41,7 +41,7 @@
       "file_info": {
         "linux2_x86_64": {
           "local_paths": [
-            "../../third_party/android_tools/sdk/build-tools/23.0.0/split-select"
+            "../../third_party/android_tools/sdk/build-tools/23.0.1/split-select"
           ]
         }
       }
diff --git a/build/common.gypi b/build/common.gypi
index b1b14d1..885e3251 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -833,10 +833,9 @@
           'use_browser_spellchecker%': 1,
         }],
 
-        # Android OS includes support for proprietary codecs regardless of
-        # building Chromium or Google Chrome. We also ship Google Chrome and
-        # Chromecast with proprietary codecs.
-        ['OS=="android" or branding=="Chrome" or chromecast==1', {
+        # Enables proprietary codecs and demuxers; e.g. H264, AAC, MP3, and MP4.
+        # We always build Google Chrome and Chromecast with proprietary codecs.
+        ['branding=="Chrome" or chromecast==1', {
           'proprietary_codecs%': 1,
         }, {
           'proprietary_codecs%': 0,
diff --git a/build/config/features.gni b/build/config/features.gni
index 8efa7cf3..c965844 100644
--- a/build/config/features.gni
+++ b/build/config/features.gni
@@ -46,11 +46,9 @@
   # Enables the Media Router.
   enable_media_router = !is_ios
 
-  # Enables proprietary codecs and demuxers; e.g. H264, MOV, AAC, and MP3.
-  # Android OS includes support for proprietary codecs regardless of building
-  # Chromium or Google Chrome. We also ship Google Chrome and Chromecast with
-  # proprietary codecs.
-  proprietary_codecs = is_android || is_chrome_branded || is_chromecast
+  # Enables proprietary codecs and demuxers; e.g. H264, AAC, MP3, and MP4.
+  # We always build Google Chrome and Chromecast with proprietary codecs.
+  proprietary_codecs = is_chrome_branded || is_chromecast
 
   enable_configuration_policy = !is_ios
 
diff --git a/build/gn_migration.gypi b/build/gn_migration.gypi
index 3a4e4b5..ef543ea 100644
--- a/build/gn_migration.gypi
+++ b/build/gn_migration.gypi
@@ -233,6 +233,7 @@
             '../third_party/WebKit/Source/wtf/wtf_tests.gyp:wtf_unittests_apk',
             '../tools/android/heap_profiler/heap_profiler.gyp:heap_profiler_unittests_apk',
             '../tools/android/android_tools.gyp:memconsumer',
+            '../tools/android/android_tools.gyp:push_apps_to_background',
             '../tools/imagediff/image_diff.gyp:image_diff#host',
             '../third_party/catapult/telemetry/telemetry.gyp:bitmaptools#host',
             '../ui/android/ui_android.gyp:ui_android_unittests_apk',
diff --git a/cc/input/input_handler.h b/cc/input/input_handler.h
index 9a395626..b81ee99 100644
--- a/cc/input/input_handler.h
+++ b/cc/input/input_handler.h
@@ -99,7 +99,15 @@
     uint32_t main_thread_scrolling_reasons;
   };
 
-  enum ScrollInputType { GESTURE, WHEEL, ANIMATED_WHEEL, NON_BUBBLING_GESTURE };
+  enum ScrollInputType {
+    // TODO(dtapuska): crbug.com/593017; Remove GESTURE and just use
+    // TOUCHSCREEN.
+    GESTURE,
+    TOUCHSCREEN = GESTURE,
+    WHEEL,
+    ANIMATED_WHEEL,
+    NON_BUBBLING_GESTURE
+  };
 
   // Binds a client to this handler to receive notifications. Only one client
   // can be bound to an InputHandler. The client must live at least until the
@@ -118,6 +126,12 @@
   // targets at the root layer.
   virtual ScrollStatus RootScrollBegin(ScrollState* scroll_state,
                                        ScrollInputType type) = 0;
+
+  // Returns SCROLL_ON_IMPL_THREAD if a layer is actively being scrolled or
+  // a subsequent call to ScrollAnimated can begin on the impl thread.
+  virtual ScrollStatus ScrollAnimatedBegin(
+      const gfx::Point& viewport_point) = 0;
+
   virtual ScrollStatus ScrollAnimated(const gfx::Point& viewport_point,
                                       const gfx::Vector2dF& scroll_delta) = 0;
 
@@ -137,7 +151,7 @@
   virtual bool ScrollVerticallyByPage(const gfx::Point& viewport_point,
                                       ScrollDirection direction) = 0;
 
-  // Returns SCROLL_STARTED if a layer was being actively being scrolled,
+  // Returns SCROLL_STARTED if a layer was actively being scrolled,
   // SCROLL_IGNORED if not.
   virtual ScrollStatus FlingScrollBegin() = 0;
 
diff --git a/cc/layers/heads_up_display_layer_impl.cc b/cc/layers/heads_up_display_layer_impl.cc
index 6606c0fb..c5dc2eac 100644
--- a/cc/layers/heads_up_display_layer_impl.cc
+++ b/cc/layers/heads_up_display_layer_impl.cc
@@ -573,9 +573,7 @@
   const SkScalar pos[] = {SkFloatToScalar(0.2f), SkFloatToScalar(0.4f),
                           SkFloatToScalar(0.6f), SkFloatToScalar(0.8f),
                           SkFloatToScalar(1.0f)};
-  skia::RefPtr<SkShader> gradient_shader =
-      skia::AdoptRef(SkGradientShader::CreateSweep(cx, cy, colors, pos, 5));
-  paint.setShader(gradient_shader.get());
+  paint.setShader(SkGradientShader::MakeSweep(cx, cy, colors, pos, 5));
   paint.setFlags(SkPaint::kAntiAlias_Flag);
 
   // Draw current status.
diff --git a/cc/output/software_renderer.cc b/cc/output/software_renderer.cc
index 8e23961..a2a7c49 100644
--- a/cc/output/software_renderer.cc
+++ b/cc/output/software_renderer.cc
@@ -529,12 +529,10 @@
     SkMatrix mask_mat;
     mask_mat.setRectToRect(mask_rect, dest_rect, SkMatrix::kFill_ScaleToFit);
 
-    skia::RefPtr<SkShader> mask_shader = skia::AdoptRef(
-        SkShader::CreateBitmapShader(*mask, SkShader::kClamp_TileMode,
-                                     SkShader::kClamp_TileMode, &mask_mat));
-
     SkPaint mask_paint;
-    mask_paint.setShader(mask_shader.get());
+    mask_paint.setShader(
+        SkShader::MakeBitmapShader(*mask, SkShader::kClamp_TileMode,
+                                   SkShader::kClamp_TileMode, &mask_mat));
 
     SkLayerRasterizer::Builder builder;
     builder.addLayer(mask_paint);
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 7bda114..6e2dd2d 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -139,12 +139,16 @@
   TRACE_EVENT_ASYNC_END0("cc", "LayerTreeHostImpl::SetVisible", id);
 }
 
+bool IsWheelBasedScroll(InputHandler::ScrollInputType type) {
+  return type == InputHandler::WHEEL || type == InputHandler::ANIMATED_WHEEL;
+}
+
 enum ScrollThread { MAIN_THREAD, CC_THREAD };
 
 void RecordCompositorSlowScrollMetric(InputHandler::ScrollInputType type,
                                       ScrollThread scroll_thread) {
   bool scroll_on_main_thread = (scroll_thread == MAIN_THREAD);
-  if (type == InputHandler::WHEEL || type == InputHandler::ANIMATED_WHEEL) {
+  if (IsWheelBasedScroll(type)) {
     UMA_HISTOGRAM_BOOLEAN("Renderer4.CompositorWheelScrollUpdateThread",
                           scroll_on_main_thread);
   } else {
@@ -2475,14 +2479,12 @@
     }
   }
 
-  if (type == InputHandler::WHEEL || type == InputHandler::ANIMATED_WHEEL) {
+  if (IsWheelBasedScroll(type) &&
+      !active_tree()->settings().use_mouse_wheel_gestures) {
     EventListenerProperties event_properties =
         active_tree()->event_listener_properties(
             EventListenerClass::kMouseWheel);
-    if (event_properties == EventListenerProperties::kBlocking ||
-        event_properties == EventListenerProperties::kBlockingAndPassive ||
-        (!active_tree()->settings().use_mouse_wheel_gestures &&
-         event_properties == EventListenerProperties::kPassive)) {
+    if (event_properties != EventListenerProperties::kNone) {
       TRACE_EVENT0("cc", "LayerImpl::tryScroll: Failed WheelEventHandlers");
       scroll_status.thread = InputHandler::SCROLL_ON_MAIN_THREAD;
       scroll_status.main_thread_scrolling_reasons =
@@ -2620,7 +2622,7 @@
   active_tree_->SetCurrentlyScrollingLayer(scrolling_layer_impl);
   // TODO(majidvp): get rid of wheel_scrolling_ and set is_direct_manipulation
   // in input_handler_proxy instead.
-  wheel_scrolling_ = (type == WHEEL || type == ANIMATED_WHEEL);
+  wheel_scrolling_ = IsWheelBasedScroll(type);
   scroll_state->set_is_direct_manipulation(!wheel_scrolling_);
   // Invoke |DistributeScrollDelta| even with zero delta and velocity to ensure
   // scroll customization callbacks are invoked.
@@ -2692,6 +2694,46 @@
   return ScrollBeginImpl(scroll_state, scrolling_layer_impl, type);
 }
 
+InputHandler::ScrollStatus LayerTreeHostImpl::ScrollAnimatedBegin(
+    const gfx::Point& viewport_point) {
+  InputHandler::ScrollStatus scroll_status;
+  scroll_status.main_thread_scrolling_reasons =
+      MainThreadScrollingReason::kNotScrollingOnMain;
+  ScrollTree& scroll_tree = active_tree_->property_trees()->scroll_tree;
+  ScrollNode* scroll_node = scroll_tree.CurrentlyScrollingNode();
+  if (scroll_node) {
+    gfx::Vector2dF delta;
+
+    if (ScrollAnimationUpdateTarget(scroll_node, delta)) {
+      scroll_status.thread = SCROLL_ON_IMPL_THREAD;
+    } else {
+      scroll_status.thread = SCROLL_IGNORED;
+      scroll_status.main_thread_scrolling_reasons =
+          MainThreadScrollingReason::kNotScrollable;
+    }
+    return scroll_status;
+  }
+  ScrollStateData scroll_state_data;
+  scroll_state_data.start_position_x = viewport_point.x();
+  scroll_state_data.start_position_y = viewport_point.y();
+  scroll_state_data.is_in_inertial_phase = true;
+  ScrollState scroll_state(scroll_state_data);
+
+  // ScrollAnimated is used for animated wheel scrolls. We find the first layer
+  // that can scroll and set up an animation of its scroll offset. Note that
+  // this does not currently go through the scroll customization and viewport
+  // machinery that ScrollBy uses for non-animated wheel scrolls.
+  scroll_status = ScrollBegin(&scroll_state, ANIMATED_WHEEL);
+  scroll_node = scroll_tree.CurrentlyScrollingNode();
+  if (scroll_status.thread == SCROLL_ON_IMPL_THREAD) {
+    ScrollStateData scroll_state_end_data;
+    scroll_state_end_data.is_ending = true;
+    ScrollState scroll_state_end(scroll_state_end_data);
+    ScrollEnd(&scroll_state_end);
+  }
+  return scroll_status;
+}
+
 InputHandler::ScrollStatus LayerTreeHostImpl::ScrollAnimated(
     const gfx::Point& viewport_point,
     const gfx::Vector2dF& scroll_delta) {
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 359a436..7a8aca72 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -166,6 +166,7 @@
   InputHandler::ScrollStatus RootScrollBegin(
       ScrollState* scroll_state,
       InputHandler::ScrollInputType type) override;
+  ScrollStatus ScrollAnimatedBegin(const gfx::Point& viewport_point) override;
   InputHandler::ScrollStatus ScrollAnimated(
       const gfx::Point& viewport_point,
       const gfx::Vector2dF& scroll_delta) override;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkEditActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkEditActivity.java
index 1d098b5..e8ae88b82 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkEditActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkEditActivity.java
@@ -274,6 +274,7 @@
                 saveRemoveVisitButton.setVisibility(View.GONE);
             }
         }
+        saveRemoveVisitButton.setEnabled(true);
     }
 
     private void updateButtonToDeleteOfflinePage(final Button button) {
@@ -283,6 +284,7 @@
             @Override
             public void onClick(View v) {
                 recordOfflineButtonAction(true);
+                button.setEnabled(false);
                 ClientId clientId = ClientId.createClientIdForBookmarkId(mBookmarkId);
                 mModel.getOfflinePageBridge().deletePage(clientId, new DeletePageCallback() {
                     @Override
@@ -292,7 +294,6 @@
                         updateOfflineSection();
                     }
                 });
-                button.setClickable(false);
             }
         });
     }
@@ -305,6 +306,7 @@
             public void onClick(View v) {
                 recordOfflineButtonAction(true);
                 ClientId clientId = ClientId.createClientIdForBookmarkId(mBookmarkId);
+                button.setEnabled(false);
                 mModel.getOfflinePageBridge().savePage(
                         mWebContents, clientId, new SavePageCallback() {
                             @Override
@@ -315,7 +317,6 @@
                                 updateOfflineSection();
                             }
                         });
-                button.setClickable(false);
             }
         });
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
index e52423b..c581e2b1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
@@ -10,6 +10,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Process;
+import android.os.StrictMode;
 import android.preference.PreferenceManager;
 import android.text.TextUtils;
 
@@ -337,7 +338,9 @@
             ThreadUtils.assertOnUiThread();
             mApplication.initCommandLine();
             LibraryLoader libraryLoader = LibraryLoader.get(LibraryProcessType.PROCESS_BROWSER);
+            StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
             libraryLoader.ensureInitialized(mApplication);
+            StrictMode.setThreadPolicy(oldPolicy);
             libraryLoader.asyncPrefetchLibrariesToMemory();
             // The policies are used by browser startup, so we need to register the policy providers
             // before starting the browser process.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUIManager.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUIManager.java
index fa3a8315..f4338ea 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUIManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUIManager.java
@@ -226,7 +226,7 @@
             return;
         }
 
-        // Use the application context because it lives longer. When using he given context, it
+        // Use the application context because it lives longer. When using the given context, it
         // may be stopped before the preferences intent is handled.
         Context applicationContext = context.getApplicationContext();
 
@@ -328,8 +328,9 @@
      * @param tag A string identifier for this notification.
      * @return The generated platform tag.
      */
-    private static String makePlatformTag(long persistentNotificationId, String origin,
-                                          @Nullable String tag) {
+    @VisibleForTesting
+    static String makePlatformTag(
+            long persistentNotificationId, String origin, @Nullable String tag) {
         // The given tag may contain the separator character, so add it last to make reading the
         // preceding origin token reliable. If no tag was specified (it is the default empty
         // string), make the platform tag unique by appending the notification id.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
index ebda57ff..0f4b44c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
@@ -132,35 +132,23 @@
      * Records histograms related to the cost of storage. It is meant to be used after user
      * takes an action: save, delete or delete in bulk.
      *
-     * @param totalPageSizeBefore Total size of the pages before the action was taken.
-     * @param totalPageSizeAfter Total size of the pages after the action was taken.
+     * @param reportingAfterDelete Indicates that reporting has been requested after deleting an
+     *   offline copy.
      */
-    private static void recordStorageHistograms(
-            final long totalPageSizeBefore, final long totalPageSizeAfter) {
-        new AsyncTask<Void, Void, Void>() {
+    private void recordStorageHistograms(final boolean reportingAfterDelete) {
+        new AsyncTask<Void, Void, long[]>() {
             @Override
-            protected Void doInBackground(Void... params) {
-                // Total space taken by offline pages.
-                int totalPageSizeInMB = (int) (totalPageSizeAfter / (1024 * 1024));
-                RecordHistogram.recordCustomCountHistogram(
-                        "OfflinePages.TotalPageSize", totalPageSizeInMB, 1, 10000, 50);
+            protected long[] doInBackground(Void... params) {
+                // Getting the storage numbers violates strict mode when done on UI thread.
+                return new long[] { OfflinePageUtils.getTotalSpaceInBytes(),
+                        OfflinePageUtils.getFreeSpaceInBytes() };
+            }
 
-                // How much of the total space the offline pages take.
-                int totalPageSizePercentage = (int) (1.0 * totalPageSizeAfter
-                        / OfflinePageUtils.getTotalSpaceInBytes() * 100);
-                RecordHistogram.recordPercentageHistogram(
-                        "OfflinePages.TotalPageSizePercentage", totalPageSizePercentage);
-                if (totalPageSizeBefore > 0) {
-                    // If the user is deleting the pages, perhaps they are running out of free
-                    // space. Report the size before the operation, where a base for calculation
-                    // of total free space includes space taken by offline pages.
-                    int percentageOfFree = (int) (1.0 * totalPageSizeBefore
-                            / (totalPageSizeBefore + OfflinePageUtils.getFreeSpaceInBytes()) * 100);
-                    RecordHistogram.recordPercentageHistogram(
-                            "OfflinePages.DeletePage.TotalPageSizeAsPercentageOfFreeSpace",
-                            percentageOfFree);
-                }
-                return null;
+            @Override
+            protected void onPostExecute(long[] result) {
+                if (result == null || result.length != 2) return;
+                nativeRecordStorageHistograms(
+                        mNativeOfflinePageBridge, result[0], result[1], reportingAfterDelete);
             }
         }.execute();
     }
@@ -291,7 +279,8 @@
      *
      * @param webContents Contents of the page to save.
      * @param ClientId of the bookmark related to the offline page.
-     * @param callback Interface that contains a callback.
+     * @param callback Interface that contains a callback. This may be called synchronously, e.g.
+     * if the web contents is already destroyed.
      * @see SavePageCallback
      */
     public void savePage(final WebContents webContents, final ClientId clientId,
@@ -309,11 +298,8 @@
         SavePageCallback callbackWrapper = new SavePageCallback() {
             @Override
             public void onSavePageDone(int savePageResult, String url, long offlineId) {
-                // TODO(fgorski): Eliminate call to getAllPages() here.
-                // See http://crbug.com/566939
                 if (savePageResult == SavePageResult.SUCCESS && isOfflinePageModelLoaded()) {
-                    long totalPageSizeAfter = getTotalSize(getAllPages());
-                    recordStorageHistograms(0, totalPageSizeAfter);
+                    recordStorageHistograms(false /* reporting after delete */);
                 }
                 callback.onSavePageDone(savePageResult, url, offlineId);
             }
@@ -462,15 +448,11 @@
 
     private DeletePageCallback wrapCallbackWithHistogramReporting(
             final DeletePageCallback callback) {
-        final long totalPageSizeBefore = getTotalSize(getAllPages());
         return new DeletePageCallback() {
             @Override
             public void onDeletePageDone(int deletePageResult) {
-                // TODO(fgorski): Eliminate call to getAllPages() here.
-                // See http://crbug.com/566939
                 if (deletePageResult == DeletePageResult.SUCCESS && isOfflinePageModelLoaded()) {
-                    long totalPageSizeAfter = getTotalSize(getAllPages());
-                    recordStorageHistograms(totalPageSizeBefore, totalPageSizeAfter);
+                    recordStorageHistograms(true /* reporting after delete */);
                 }
                 callback.onDeletePageDone(deletePageResult);
             }
@@ -558,4 +540,6 @@
     private native void nativeCheckMetadataConsistency(long nativeOfflinePageBridge);
     private native String nativeGetOfflineUrlForOnlineUrl(
             long nativeOfflinePageBridge, String onlineUrl);
+    private native void nativeRecordStorageHistograms(long nativeOfflinePageBridge,
+            long totalSpaceInBytes, long freeSpaceInBytes, boolean reportingAfterDelete);
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java
index 8d69889..73aa40e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java
@@ -236,7 +236,7 @@
             throws InterruptedException, TimeoutException, SecurityException, IOException {
         // Click the video to enable playback
         DOMUtils.clickNode(this, getActivity().getCurrentContentViewCore(), "videoDOMElement");
-        saveMediaFromContextMenu("videoDOMElement", R.id.contextmenu_save_video, "test.mp4");
+        saveMediaFromContextMenu("videoDOMElement", R.id.contextmenu_save_video, "test.webm");
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java
index ce53ed6..57b8438 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java
@@ -12,6 +12,8 @@
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.tabmodel.TabList;
 import org.chromium.chrome.test.ChromeTabbedActivityTestBase;
+import org.chromium.content.browser.test.util.Criteria;
+import org.chromium.content.browser.test.util.CriteriaHelper;
 
 /**
  * Integration test suite for the first run experience.
@@ -25,21 +27,28 @@
      */
     @SmallTest
     @Feature({"FirstRunExperience"})
-    public void testExitFirstRunExperience() {
+    public void testExitFirstRunExperience() throws InterruptedException {
         if (FirstRunStatus.getFirstRunFlowComplete(getActivity())) {
             return;
         }
 
         sendKeys(KeyEvent.KEYCODE_BACK);
-        getInstrumentation().waitForIdleSync();
 
-        assertEquals("Expected no tabs to be present",
-                0, getActivity().getCurrentTabModel().getCount());
+        CriteriaHelper.pollForCriteria(new Criteria("Expected no tabs to be present") {
+            @Override
+            public boolean isSatisfied() {
+                return 0 == getActivity().getCurrentTabModel().getCount();
+            }
+        });
         TabList fullModel = getActivity().getCurrentTabModel().getComprehensiveModel();
         assertEquals("Expected no tabs to be present in the comprehensive model",
                 0, fullModel.getCount());
-        assertTrue("Activity was not closed.",
-                getActivity().isFinishing() || getActivity().isDestroyed());
+        CriteriaHelper.pollForCriteria(new Criteria("Activity was not closed.") {
+            @Override
+            public boolean isSatisfied() {
+                return getActivity().isFinishing() || getActivity().isDestroyed();
+            }
+        });
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationUIManagerIntentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationUIManagerIntentTest.java
new file mode 100644
index 0000000..71be46d
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationUIManagerIntentTest.java
@@ -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.
+
+package org.chromium.chrome.browser.notifications;
+
+import android.app.Notification;
+import android.content.Context;
+import android.content.Intent;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import org.chromium.base.library_loader.LibraryLoader;
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.document.ChromeLauncherActivity;
+import org.chromium.chrome.browser.preferences.Preferences;
+import org.chromium.chrome.browser.preferences.website.SingleCategoryPreferences;
+import org.chromium.chrome.browser.preferences.website.SingleWebsitePreferences;
+import org.chromium.chrome.test.ChromeActivityTestCaseBase;
+import org.chromium.chrome.test.util.ActivityUtils;
+
+/**
+ * Instrumentation tests for the Notification UI Manager implementation on Android.
+ *
+ * Exercises the handling of intents and explicitly does not do anything in startMainActivity so
+ * that the responsibility for correct initialization, e.g. loading the native library, lies with
+ * the code exercised by this test.
+ */
+public class NotificationUIManagerIntentTest extends ChromeActivityTestCaseBase<ChromeActivity> {
+    /**
+     * Name of the Intent extra holding the notification id. This is set by the framework when a
+     * notification preferences intent has been triggered from there, which could be one of the
+     * setting gears in system UI.
+     */
+    public static final String EXTRA_NOTIFICATION_ID = "notification_id";
+
+    public NotificationUIManagerIntentTest() {
+        super(ChromeActivity.class);
+    }
+
+    @Override
+    public void startMainActivity() throws InterruptedException {
+        // Don't do anything here. The responsibility for correct initialization, e.g. loading the
+        // native library, lies with the code exercised by this test.
+    }
+
+    /**
+     * Tests the scenario where the user clicks "App settings" in the Android App notifications
+     * screen. In this scenario the intent does not have the tag extra which holds the origin. This
+     * means that the preferences cannot be shown for a specific site, and Chrome falls back to
+     * showing the notification preferences for all sites.
+     */
+    @MediumTest
+    @Feature({"Browser", "Notifications"})
+    public void testLaunchNotificationPreferencesForCategory() throws Exception {
+        assertFalse("The native library should not be loaded yet", LibraryLoader.isInitialized());
+
+        final Context context = getInstrumentation().getTargetContext().getApplicationContext();
+
+        final Intent intent =
+                new Intent(Intent.ACTION_MAIN)
+                        .addCategory(Notification.INTENT_CATEGORY_NOTIFICATION_PREFERENCES)
+                        .setClassName(context, ChromeLauncherActivity.class.getName())
+                        .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        Preferences activity = ActivityUtils.waitForActivity(
+                getInstrumentation(), Preferences.class, new Runnable() {
+                    @Override
+                    public void run() {
+                        context.startActivity(intent);
+                    }
+                });
+        assertNotNull("Could not find the Preferences activity", activity);
+
+        SingleCategoryPreferences fragment =
+                ActivityUtils.waitForFragmentToAttach(activity, SingleCategoryPreferences.class);
+        assertNotNull("Could not find the SingleCategoryPreferences fragment", fragment);
+    }
+
+    /**
+     * Tests the scenario where the user clicks the settings gear on a notification that was flipped
+     * through a long press. In this scenario the intent has the tag extra which holds the origin
+     * that created the notification. Chrome will show the preferences for this specific site.
+     */
+    @MediumTest
+    @Feature({"Browser", "Notifications"})
+    public void testLaunchNotificationPreferencesForWebsite() throws Exception {
+        assertFalse("The native library should not be loaded yet", LibraryLoader.isInitialized());
+
+        final Context context = getInstrumentation().getTargetContext().getApplicationContext();
+
+        final Intent intent =
+                new Intent(Intent.ACTION_MAIN)
+                        .addCategory(Notification.INTENT_CATEGORY_NOTIFICATION_PREFERENCES)
+                        .setClassName(context, ChromeLauncherActivity.class.getName())
+                        .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+                        .putExtra(EXTRA_NOTIFICATION_ID, NotificationUIManager.PLATFORM_ID)
+                        .putExtra(NotificationConstants.EXTRA_NOTIFICATION_TAG,
+                                NotificationUIManager.makePlatformTag(
+                                        42L /* persistentNotificationId */, "https://example.com",
+                                        null /* tag */));
+
+        Preferences activity = ActivityUtils.waitForActivity(
+                getInstrumentation(), Preferences.class, new Runnable() {
+                    @Override
+                    public void run() {
+                        context.startActivity(intent);
+                    }
+                });
+        assertNotNull("Could not find the Preferences activity", activity);
+
+        SingleWebsitePreferences fragment =
+                ActivityUtils.waitForFragmentToAttach(activity, SingleWebsitePreferences.class);
+        assertNotNull("Could not find the SingleWebsitePreferences fragment", fragment);
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/PreferencesTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/PreferencesTest.java
index 59f7844..bc20d283 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/PreferencesTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/PreferencesTest.java
@@ -212,9 +212,6 @@
         return locationPermission;
     }
 
-    // TODO(mvanouwerkerk): Write new preference intent tests for notification settings.
-    // https://crbug.com/461885
-
     /**
      * Tests setting FontScaleFactor and ForceEnableZoom in AccessibilityPreferences and ensures
      * that ForceEnableZoom changes corresponding to FontScaleFactor.
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 3f4a837..6e80a1c8 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -5925,12 +5925,18 @@
       <message name="IDS_FLAGS_AFFILIATION_BASED_MATCHING_DESCRIPTION" desc="Description of the flag to enable affiliation based matching, so that credentials stored for an Android application will also be considered matches for, and be filled into corresponding websites (so-called 'affiliated' websites).">
         Allow credentials stored for Android applications to be filled into corresponding websites.
       </message>
-      <message name="IDS_FLAGS_AUTOFILL_SYNC_CREDENTIAL_NAME" desc="Name of the flag specifying how the browser will handle autofilling the users sync credential.">
+      <message name="IDS_FLAGS_PROTECT_SYNC_CREDENTIAL_NAME" desc="Name of the flag specifying how the browser will handle autofilling the users sync credential.">
         Autofill sync credential
       </message>
-      <message name="IDS_FLAGS_AUTOFILL_SYNC_CREDENTIAL_DESCRIPTION" desc="Description of the flag specifying how the browser will handle autofilling the users sync credential.">
+      <message name="IDS_FLAGS_PROTECT_SYNC_CREDENTIAL_DESCRIPTION" desc="Description of the flag specifying how the browser will handle autofilling the users sync credential.">
         How the password manager handles autofill for the sync credential.
       </message>
+      <message name="IDS_FLAGS_PROTECT_SYNC_CREDENTIAL_ON_REAUTH_NAME" desc="Name of the flag specifying how the browser will handle autofilling the users sync credential.">
+        Autofill sync credential only for transactional reauth pages
+      </message>
+      <message name="IDS_FLAGS_PROTECT_SYNC_CREDENTIAL_ON_REAUTH_DESCRIPTION" desc="Description of the flag specifying how the browser will handle autofilling of the sync credential only for transactional reauth pages.">
+        How the password manager handles autofill for the sync credential only for transactional reauth pages.
+      </message>
       <message name="IDS_FLAGS_ICON_NTP_NAME" desc="Name of the flag to enable large icons on the NTP.">
         Large icons on the New Tab page
       </message>
@@ -7231,7 +7237,7 @@
         Auto Sign-in
       </message>
       <message name="IDS_PASSWORDS_AUTO_SIGNIN_DESCRIPTION" desc="Text under 'Auto sign-in' checkbox">
-        Automatically sign in to websites using stored credential. When the feature is off, you'll be asked for verification every time before signing in to a website.
+        Automatically sign in to websites using stored credentials. When the feature is disabled, you will be asked for confirmation every time before signing to a website.
       </message>
       <message name="IDS_PASSWORDS_VIA_FEDERATION" desc="Text for federated credential's value.">
         with <ph name="PROVIDER">$1<ex>facebook.com</ex></ph>
@@ -14332,9 +14338,12 @@
       <message name="IDS_SECURE_PROTOCOL_AND_CIPHERSUITE_DESCRIPTION" desc="Description of a site that uses a modern, secure TLS protocol version and ciphersuite.">
         The connection to this site is using a strong protocol version and cipher suite.
       </message>
-      <message name="IDS_SAVE_PASSWORD_TITLE" desc="The title of the save password bubble when a password can be saved.">
+      <message name="IDS_SAVE_PASSWORD_DIFFERENT_DOMAINS_TITLE" desc="The title of the save password bubble when the submitted form origin isn't equal to the page origin.">
         Do you want <ph name="PASSWORD_MANAGER_BRAND">$1<ex>Google Chrome</ex></ph> to save your password for <ph name="ORIGIN">$2<ex>example.com</ex></ph>?
       </message>
+      <message name="IDS_UPDATE_PASSWORD_DIFFERENT_DOMAINS_TITLE" desc="The title of the update password bubble when the submitted form origin isn't equal to saved credentials origin.">
+        Do you want <ph name="PASSWORD_MANAGER_BRAND">$1<ex>Google Chrome</ex></ph> to update your password for <ph name="ORIGIN">$2<ex>example.com</ex></ph>?
+      </message>
       <message name="IDS_MANAGE_PASSWORDS_TITLE_DIFFERENT_DOMAIN" desc="The title text that is used in the manage passwords bubble when a password is autofilled or after a user has stored a password.">
         Saved passwords for <ph name="ORIGIN">$1<ex>example.com</ex></ph>:
       </message>
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index c5a0116..878d618 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -47,7 +47,6 @@
 #include "components/offline_pages/offline_page_switches.h"
 #include "components/omnibox/browser/omnibox_switches.h"
 #include "components/password_manager/core/common/password_manager_features.h"
-#include "components/password_manager/core/common/password_manager_switches.h"
 #include "components/proximity_auth/switches.h"
 #include "components/search/search_switches.h"
 #include "components/security_state/switches.h"
@@ -359,16 +358,6 @@
     switches::kExtensionContentVerificationEnforceStrict },
 };
 
-const FeatureEntry::Choice kAutofillSyncCredentialChoices[] = {
-  { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", ""},
-  { IDS_ALLOW_AUTOFILL_SYNC_CREDENTIAL,
-    password_manager::switches::kAllowAutofillSyncCredential, ""},
-  { IDS_DISALLOW_AUTOFILL_SYNC_CREDENTIAL_FOR_REAUTH,
-    password_manager::switches::kDisallowAutofillSyncCredentialForReauth, ""},
-  { IDS_DISALLOW_AUTOFILL_SYNC_CREDENTIAL,
-    password_manager::switches::kDisallowAutofillSyncCredential, ""},
-};
-
 const FeatureEntry::Choice kFillOnAccountSelectChoices[] = {
   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
@@ -770,8 +759,7 @@
 #if defined(OS_ANDROID)
     {"enable-system-download-manager",
      IDS_FLAGS_ENABLE_SYSTEM_DOWNLOAD_MANAGER_NAME,
-     IDS_FLAGS_ENABLE_SYSTEM_DOWNLOAD_MANAGER_DESCRIPTION,
-     kOsAndroid,
+     IDS_FLAGS_ENABLE_SYSTEM_DOWNLOAD_MANAGER_DESCRIPTION, kOsAndroid,
      FEATURE_VALUE_TYPE(chrome::android::kSystemDownloadManager)},
 #endif
 #if defined(OS_CHROMEOS)
@@ -933,13 +921,10 @@
      IDS_FLAGS_MANUAL_PASSWORD_GENERATION_DESCRIPTION, kOsAll,
      FEATURE_VALUE_TYPE(
          password_manager::features::kEnableManualPasswordGeneration)},
-    {"enable-affiliation-based-matching",
-     IDS_FLAGS_AFFILIATION_BASED_MATCHING_NAME,
+    {"affiliation-based-matching", IDS_FLAGS_AFFILIATION_BASED_MATCHING_NAME,
      IDS_FLAGS_AFFILIATION_BASED_MATCHING_DESCRIPTION,
      kOsWin | kOsLinux | kOsCrOS | kOsMac | kOsAndroid,
-     ENABLE_DISABLE_VALUE_TYPE(
-         password_manager::switches::kEnableAffiliationBasedMatching,
-         password_manager::switches::kDisableAffiliationBasedMatching)},
+     FEATURE_VALUE_TYPE(password_manager::features::kAffiliationBasedMatching)},
     {"wallet-service-use-sandbox", IDS_FLAGS_WALLET_SERVICE_USE_SANDBOX_NAME,
      IDS_FLAGS_WALLET_SERVICE_USE_SANDBOX_DESCRIPTION, kOsAndroid | kOsDesktop,
      ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(
@@ -1302,10 +1287,8 @@
      IDS_FLAGS_SETTINGS_WINDOW_DESCRIPTION, kOsDesktop,
      ENABLE_DISABLE_VALUE_TYPE(switches::kEnableSettingsWindow,
                                switches::kDisableSettingsWindow)},
-    {"inert-visual-viewport",
-     IDS_FLAGS_INERT_VISUAL_VIEWPORT_NAME,
-     IDS_FLAGS_INERT_VISUAL_VIEWPORT_DESCRIPTION,
-     kOsAll,
+    {"inert-visual-viewport", IDS_FLAGS_INERT_VISUAL_VIEWPORT_NAME,
+     IDS_FLAGS_INERT_VISUAL_VIEWPORT_DESCRIPTION, kOsAll,
      SINGLE_VALUE_TYPE(switches::kInertVisualViewport)},
 #if defined(OS_MACOSX)
     {"enable-save-password-bubble", IDS_FLAGS_SAVE_PASSWORD_BUBBLE_NAME,
@@ -1361,20 +1344,15 @@
      IDS_FLAGS_WEB_APP_FRAME_DESCRIPTION, kOsWin | kOsCrOS,
      SINGLE_VALUE_TYPE(switches::kEnableWebAppFrame)},
 #endif
-    {"enable-drop-sync-credential", IDS_FLAGS_DROP_SYNC_CREDENTIAL_NAME,
+    {"drop-sync-credential", IDS_FLAGS_DROP_SYNC_CREDENTIAL_NAME,
      IDS_FLAGS_DROP_SYNC_CREDENTIAL_DESCRIPTION, kOsAll,
-     ENABLE_DISABLE_VALUE_TYPE(
-         password_manager::switches::kEnableDropSyncCredential,
-         password_manager::switches::kDisableDropSyncCredential)},
+     FEATURE_VALUE_TYPE(password_manager::features::kDropSyncCredential)},
 #if defined(ENABLE_EXTENSIONS)
     {"enable-extension-action-redesign",
      IDS_FLAGS_EXTENSION_ACTION_REDESIGN_NAME,
      IDS_FLAGS_EXTENSION_ACTION_REDESIGN_DESCRIPTION, kOsDesktop,
      SINGLE_VALUE_TYPE(extensions::switches::kEnableExtensionActionRedesign)},
 #endif
-    {"autofill-sync-credential", IDS_FLAGS_AUTOFILL_SYNC_CREDENTIAL_NAME,
-     IDS_FLAGS_AUTOFILL_SYNC_CREDENTIAL_DESCRIPTION, kOsAll,
-     MULTI_VALUE_TYPE(kAutofillSyncCredentialChoices)},
 #if !defined(OS_ANDROID)
     {"enable-message-center-always-scroll-up-upon-notification-removal",
      IDS_FLAGS_MESSAGE_CENTER_ALWAYS_SCROLL_UP_UPON_REMOVAL_NAME,
@@ -1704,8 +1682,7 @@
      SINGLE_VALUE_TYPE(switches::kEnableTabSwitcherInDocumentMode)},
 #endif  // OS_ANDROID
     {"enable-md-history", IDS_FLAGS_ENABLE_MATERIAL_DESIGN_HISTORY_NAME,
-     IDS_FLAGS_ENABLE_MATERIAL_DESIGN_HISTORY_DESCRIPTION,
-     kOsDesktop,
+     IDS_FLAGS_ENABLE_MATERIAL_DESIGN_HISTORY_DESCRIPTION, kOsDesktop,
      SINGLE_VALUE_TYPE(switches::kEnableMaterialDesignHistory)},
 #if defined(OS_WIN)
     {"enable-windows-desktop-search-redirection",
@@ -1782,8 +1759,7 @@
      FEATURE_VALUE_TYPE(features::kScrollAnchoring)},
     {"enable-audio-support-for-desktop-share",
      IDS_FLAG_ENABLE_AUDIO_FOR_DESKTOP_SHARE,
-     IDS_FLAG_ENABLE_AUDIO_FOR_DESKTOP_SHARE_DESCRIPTION,
-     kOsAll,
+     IDS_FLAG_ENABLE_AUDIO_FOR_DESKTOP_SHARE_DESCRIPTION, kOsAll,
      SINGLE_VALUE_TYPE(switches::kEnableAudioSupportForDesktopShare)},
 #if defined(ENABLE_EXTENSIONS)
     {"enable-tab-for-desktop-share", IDS_FLAG_ENABLE_TAB_FOR_DESKTOP_SHARE,
@@ -1798,14 +1774,12 @@
 #if defined(ENABLE_WEBRTC) && BUILDFLAG(RTC_USE_H264)
     {"enable-webrtc-h264-with-openh264-ffmpeg",
      IDS_FLAGS_WEBRTC_H264_WITH_OPENH264_FFMPEG_NAME,
-     IDS_FLAGS_WEBRTC_H264_WITH_OPENH264_FFMPEG_DESCRIPTION,
-     kOsDesktop,
+     IDS_FLAGS_WEBRTC_H264_WITH_OPENH264_FFMPEG_DESCRIPTION, kOsDesktop,
      FEATURE_VALUE_TYPE(content::kWebRtcH264WithOpenH264FFmpeg)},
 #endif  // defined(ENABLE_WEBRTC) && BUILDFLAG(RTC_USE_H264)
 #if defined(OS_ANDROID)
-    {"ime-thread", IDS_FLAGS_IME_THREAD_NAME,
-     IDS_FLAGS_IME_THREAD_DESCRIPTION, kOsAndroid,
-     FEATURE_VALUE_TYPE(features::kImeThread)},
+    {"ime-thread", IDS_FLAGS_IME_THREAD_NAME, IDS_FLAGS_IME_THREAD_DESCRIPTION,
+     kOsAndroid, FEATURE_VALUE_TYPE(features::kImeThread)},
 #endif  // defined(OS_ANDROID)
 #if defined(OS_ANDROID)
     {"offline-pages-ntp", IDS_FLAGS_NTP_OFFLINE_PAGES_NAME,
@@ -1815,6 +1789,14 @@
      IDS_FLAGS_OFFLINING_RECENT_PAGES_DESCRIPTION, kOsAndroid,
      FEATURE_VALUE_TYPE(offline_pages::kOffliningRecentPagesFeature)},
 #endif  // defined(OS_ANDROID)
+    {"protect-sync-credential", IDS_FLAGS_PROTECT_SYNC_CREDENTIAL_NAME,
+     IDS_FLAGS_PROTECT_SYNC_CREDENTIAL_DESCRIPTION, kOsAll,
+     FEATURE_VALUE_TYPE(password_manager::features::kProtectSyncCredential)},
+    {"protect-sync-credential-on-reauth",
+     IDS_FLAGS_PROTECT_SYNC_CREDENTIAL_ON_REAUTH_NAME,
+     IDS_FLAGS_PROTECT_SYNC_CREDENTIAL_ON_REAUTH_DESCRIPTION, kOsAll,
+     FEATURE_VALUE_TYPE(
+         password_manager::features::kProtectSyncCredentialOnReauth)},
     // NOTE: Adding new command-line switches requires adding corresponding
     // entries to enum "LoginCustomFlags" in histograms.xml. See note in
     // histograms.xml and don't forget to run AboutFlagsHistogramTest unit test.
diff --git a/chrome/browser/android/most_visited_sites.cc b/chrome/browser/android/most_visited_sites.cc
index a41f6c8..edec098 100644
--- a/chrome/browser/android/most_visited_sites.cc
+++ b/chrome/browser/android/most_visited_sites.cc
@@ -26,19 +26,15 @@
 #include "chrome/browser/profiles/profile_android.h"
 #include "chrome/browser/search/suggestions/suggestions_service_factory.h"
 #include "chrome/browser/search/suggestions/suggestions_source.h"
-#include "chrome/browser/search/suggestions/suggestions_utils.h"
 #include "chrome/browser/supervised_user/supervised_user_service.h"
 #include "chrome/browser/supervised_user/supervised_user_service_factory.h"
 #include "chrome/browser/supervised_user/supervised_user_url_filter.h"
-#include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/thumbnails/thumbnail_list_source.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
-#include "components/browser_sync/browser/profile_sync_service.h"
 #include "components/history/core/browser/top_sites.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
-#include "components/suggestions/suggestions_service.h"
 #include "components/variations/variations_associated_data.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/url_data_source.h"
@@ -211,12 +207,11 @@
                               new suggestions::SuggestionsSource(profile_));
   content::URLDataSource::Add(profile_, new ThumbnailListSource(profile_));
 
-  // Register this class as an observer to the sync service. It is important to
-  // be notified of changes in the sync state such as initialization, sync
-  // being enabled or disabled, etc.
-  ProfileSyncService* profile_sync_service =
-      ProfileSyncServiceFactory::GetForProfile(profile_);
-  profile_sync_service->AddObserver(this);
+  SuggestionsService* suggestions_service =
+      SuggestionsServiceFactory::GetForProfile(profile_);
+  suggestions_subscription_ = suggestions_service->AddCallback(
+      base::Bind(&MostVisitedSites::OnSuggestionsProfileAvailable,
+                 base::Unretained(this)));
 
   SupervisedUserService* supervised_user_service =
       SupervisedUserServiceFactory::GetForProfile(profile_);
@@ -224,10 +219,6 @@
 }
 
 MostVisitedSites::~MostVisitedSites() {
-  ProfileSyncService* profile_sync_service =
-      ProfileSyncServiceFactory::GetForProfile(profile_);
-  profile_sync_service->RemoveObserver(this);
-
   SupervisedUserService* supervised_user_service =
       SupervisedUserServiceFactory::GetForProfile(profile_);
   supervised_user_service->RemoveObserver(this);
@@ -258,10 +249,13 @@
     received_popular_sites_ = true;
   }
 
+  OnSuggestionsProfileAvailable(
+      SuggestionsServiceFactory::GetForProfile(profile_)
+          ->GetSuggestionsDataFromCache());
+
   QueryMostVisitedURLs();
 
-  scoped_refptr<history::TopSites> top_sites =
-      TopSitesFactory::GetForProfile(profile_);
+  scoped_refptr<TopSites> top_sites = TopSitesFactory::GetForProfile(profile_);
   if (top_sites) {
     // TopSites updates itself after a delay. To ensure up-to-date results,
     // force an update now.
@@ -309,27 +303,24 @@
     // SuggestionsService can supply a thumbnail download URL.
     SuggestionsService* suggestions_service =
         SuggestionsServiceFactory::GetForProfile(profile_);
-    if (suggestions_service) {
-      if (popular_sites_) {
-        const std::vector<PopularSites::Site>& sites = popular_sites_->sites();
-        auto it = std::find_if(sites.begin(), sites.end(),
-                               [&url](const PopularSites::Site& site) {
-                                 return site.url == url;
-                               });
-        if (it != sites.end() && it->thumbnail_url.is_valid()) {
-          return suggestions_service->GetPageThumbnailWithURL(
-              url, it->thumbnail_url,
-              base::Bind(&MostVisitedSites::OnObtainedThumbnail,
-                         weak_ptr_factory_.GetWeakPtr(), false,
-                         base::Passed(&j_callback)));
-        }
+    if (popular_sites_) {
+      const std::vector<PopularSites::Site>& sites = popular_sites_->sites();
+      auto it = std::find_if(
+          sites.begin(), sites.end(),
+          [&url](const PopularSites::Site& site) { return site.url == url; });
+      if (it != sites.end() && it->thumbnail_url.is_valid()) {
+        return suggestions_service->GetPageThumbnailWithURL(
+            url, it->thumbnail_url,
+            base::Bind(&MostVisitedSites::OnObtainedThumbnail,
+                       weak_ptr_factory_.GetWeakPtr(), false,
+                       base::Passed(&j_callback)));
       }
-      if (mv_source_ == SUGGESTIONS_SERVICE) {
-        return suggestions_service->GetPageThumbnail(
-            url, base::Bind(&MostVisitedSites::OnObtainedThumbnail,
-                            weak_ptr_factory_.GetWeakPtr(), false,
-                            base::Passed(&j_callback)));
-      }
+    }
+    if (mv_source_ == SUGGESTIONS_SERVICE) {
+      return suggestions_service->GetPageThumbnail(
+          url, base::Bind(&MostVisitedSites::OnObtainedThumbnail,
+                          weak_ptr_factory_.GetWeakPtr(), false,
+                          base::Passed(&j_callback)));
     }
   }
   OnObtainedThumbnail(true, std::move(j_callback), url, bitmap.get());
@@ -359,26 +350,20 @@
   // Always blacklist in the local TopSites.
   scoped_refptr<TopSites> top_sites = TopSitesFactory::GetForProfile(profile_);
   if (top_sites) {
-    if (add_url) {
+    if (add_url)
       top_sites->AddBlacklistedURL(url);
-    } else {
+    else
       top_sites->RemoveBlacklistedURL(url);
-    }
   }
 
   // Only blacklist in the server-side suggestions service if it's active.
   if (mv_source_ == SUGGESTIONS_SERVICE) {
     SuggestionsService* suggestions_service =
         SuggestionsServiceFactory::GetForProfile(profile_);
-    DCHECK(suggestions_service);
-    suggestions::SuggestionsService::ResponseCallback callback(
-        base::Bind(&MostVisitedSites::OnSuggestionsProfileAvailable,
-                   weak_ptr_factory_.GetWeakPtr()));
-    if (add_url) {
-      suggestions_service->BlacklistURL(url, callback, base::Closure());
-    } else {
-      suggestions_service->UndoBlacklistURL(url, callback, base::Closure());
-    }
+    if (add_url)
+      suggestions_service->BlacklistURL(url);
+    else
+      suggestions_service->UndoBlacklistURL(url);
   }
 }
 
@@ -426,13 +411,6 @@
   LogHistogramEvent(histogram, tile_type, NUM_TILE_TYPES);
 }
 
-void MostVisitedSites::OnStateChanged() {
-  // There have been changes to the sync state. This class cares about a few
-  // (just initialized, enabled/disabled or history sync state changed). Re-run
-  // the query code which will use the proper state.
-  QueryMostVisitedURLs();
-}
-
 void MostVisitedSites::OnURLFilterChanged() {
   QueryMostVisitedURLs();
 }
@@ -452,15 +430,8 @@
 void MostVisitedSites::QueryMostVisitedURLs() {
   SuggestionsService* suggestions_service =
       SuggestionsServiceFactory::GetForProfile(profile_);
-  if (suggestions_service) {
-    // Suggestions service is enabled, initiate a query.
-    suggestions_service->FetchSuggestionsData(
-        suggestions::GetSyncState(profile_),
-        base::Bind(&MostVisitedSites::OnSuggestionsProfileAvailable,
-                   weak_ptr_factory_.GetWeakPtr()));
-  } else {
+  if (!suggestions_service->FetchSuggestionsData())
     InitiateTopSitesQuery();
-  }
 }
 
 void MostVisitedSites::InitiateTopSitesQuery() {
@@ -800,6 +771,10 @@
     UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.NumberOfTiles", num_suggestions);
     recorded_uma_ = true;
   }
+
+  if (observer_.is_null())
+    return;
+
   std::vector<base::string16> titles;
   std::vector<std::string> urls;
   titles.reserve(num_suggestions);
@@ -851,10 +826,9 @@
   }
 }
 
-void MostVisitedSites::TopSitesLoaded(history::TopSites* top_sites) {
-}
+void MostVisitedSites::TopSitesLoaded(TopSites* top_sites) {}
 
-void MostVisitedSites::TopSitesChanged(history::TopSites* top_sites,
+void MostVisitedSites::TopSitesChanged(TopSites* top_sites,
                                        ChangeReason change_reason) {
   if (mv_source_ == TOP_SITES) {
     // The displayed suggestions are invalidated.
diff --git a/chrome/browser/android/most_visited_sites.h b/chrome/browser/android/most_visited_sites.h
index 33fdca5..6324efd9 100644
--- a/chrome/browser/android/most_visited_sites.h
+++ b/chrome/browser/android/most_visited_sites.h
@@ -22,7 +22,7 @@
 #include "components/history/core/browser/history_types.h"
 #include "components/history/core/browser/top_sites_observer.h"
 #include "components/suggestions/proto/suggestions.pb.h"
-#include "components/sync_driver/sync_service_observer.h"
+#include "components/suggestions/suggestions_service.h"
 #include "url/gurl.h"
 
 namespace suggestions {
@@ -37,8 +37,7 @@
 class Profile;
 
 // Provides the list of most visited sites and their thumbnails to Java.
-class MostVisitedSites : public sync_driver::SyncServiceObserver,
-                         public history::TopSitesObserver,
+class MostVisitedSites : public history::TopSitesObserver,
                          public SupervisedUserServiceObserver {
  public:
   explicit MostVisitedSites(Profile* profile);
@@ -68,9 +67,6 @@
       jint index,
       jint tile_type);
 
-  // sync_driver::SyncServiceObserver implementation.
-  void OnStateChanged() override;
-
   // SupervisedUserServiceObserver implementation.
   void OnURLFilterChanged() override;
 
@@ -178,7 +174,8 @@
       SuggestionsVector* src_suggestions,
       SuggestionsVector* dst_suggestions);
 
-  // Notify the Java side observer about the availability of Most Visited Urls.
+  // Notifies the Java side observer about the availability of suggestions.
+  // Also records impressions UMA if not done already.
   void NotifyMostVisitedURLsObserver();
 
   void OnPopularSitesAvailable(bool success);
@@ -229,6 +226,10 @@
   // recorded once both the previous flags are true.
   bool recorded_uma_;
 
+  scoped_ptr<
+      suggestions::SuggestionsService::ResponseCallbackList::Subscription>
+      suggestions_subscription_;
+
   ScopedObserver<history::TopSites, history::TopSitesObserver> scoped_observer_;
 
   MostVisitedSource mv_source_;
diff --git a/chrome/browser/android/offline_pages/offline_page_bridge.cc b/chrome/browser/android/offline_pages/offline_page_bridge.cc
index 27a2856..7f98028 100644
--- a/chrome/browser/android/offline_pages/offline_page_bridge.cc
+++ b/chrome/browser/android/offline_pages/offline_page_bridge.cc
@@ -291,6 +291,16 @@
   return ConvertUTF8ToJavaString(env, offline_url.spec());
 }
 
+void OfflinePageBridge::RecordStorageHistograms(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj,
+    jlong total_space_bytes,
+    jlong free_space_bytes,
+    jboolean reporting_after_delete) {
+  offline_page_model_->RecordStorageHistograms(
+      total_space_bytes, free_space_bytes, reporting_after_delete);
+}
+
 void OfflinePageBridge::NotifyIfDoneLoading() const {
   if (!offline_page_model_->is_loaded())
     return;
diff --git a/chrome/browser/android/offline_pages/offline_page_bridge.h b/chrome/browser/android/offline_pages/offline_page_bridge.h
index 01da3b4..ceee3068 100644
--- a/chrome/browser/android/offline_pages/offline_page_bridge.h
+++ b/chrome/browser/android/offline_pages/offline_page_bridge.h
@@ -98,6 +98,12 @@
       const base::android::JavaParamRef<jobject>& obj,
       const base::android::JavaParamRef<jstring>& j_online_url);
 
+  void RecordStorageHistograms(JNIEnv* env,
+                               const base::android::JavaParamRef<jobject>& obj,
+                               jlong total_space_bytes,
+                               jlong free_space_bytes,
+                               jboolean reporting_after_delete);
+
   base::android::ScopedJavaGlobalRef<jobject> java_ref() { return java_ref_; }
 
  private:
diff --git a/chrome/browser/android/password_ui_view_android.cc b/chrome/browser/android/password_ui_view_android.cc
index 48d8f186..84dec75 100644
--- a/chrome/browser/android/password_ui_view_android.cc
+++ b/chrome/browser/android/password_ui_view_android.cc
@@ -6,7 +6,6 @@
 
 #include "base/android/jni_string.h"
 #include "base/android/jni_weak_ref.h"
-#include "base/command_line.h"
 #include "base/metrics/field_trial.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
@@ -17,7 +16,6 @@
 #include "components/password_manager/core/browser/password_bubble_experiment.h"
 #include "components/password_manager/core/browser/password_manager_constants.h"
 #include "components/password_manager/core/common/experiments.h"
-#include "components/password_manager/core/common/password_manager_switches.h"
 #include "components/prefs/pref_service.h"
 #include "jni/PasswordUIView_jni.h"
 
diff --git a/chrome/browser/autofill/autofill_cc_infobar_delegate_unittest.cc b/chrome/browser/autofill/autofill_save_card_infobar_delegate_mobile_unittest.cc
similarity index 75%
rename from chrome/browser/autofill/autofill_cc_infobar_delegate_unittest.cc
rename to chrome/browser/autofill/autofill_save_card_infobar_delegate_mobile_unittest.cc
index 73f33b62..dc8d076 100644
--- a/chrome/browser/autofill/autofill_cc_infobar_delegate_unittest.cc
+++ b/chrome/browser/autofill/autofill_save_card_infobar_delegate_mobile_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/autofill/core/browser/autofill_cc_infobar_delegate.h"
+#include "components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h"
 
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
@@ -13,6 +13,7 @@
 #include "chrome/test/base/testing_profile.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/infobars/core/confirm_infobar_delegate.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -42,10 +43,11 @@
 
 }  // namespace
 
-class AutofillCCInfobarDelegateTest : public ChromeRenderViewHostTestHarness {
+class AutofillSaveCardInfoBarDelegateMobileTest
+    : public ChromeRenderViewHostTestHarness {
  public:
-  AutofillCCInfobarDelegateTest();
-  ~AutofillCCInfobarDelegateTest() override;
+  AutofillSaveCardInfoBarDelegateMobileTest();
+  ~AutofillSaveCardInfoBarDelegateMobileTest() override;
 
   void SetUp() override;
   void TearDown() override;
@@ -56,20 +58,18 @@
   scoped_ptr<TestPersonalDataManager> personal_data_;
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(AutofillCCInfobarDelegateTest);
+  DISALLOW_COPY_AND_ASSIGN(AutofillSaveCardInfoBarDelegateMobileTest);
 };
 
-AutofillCCInfobarDelegateTest::AutofillCCInfobarDelegateTest() {
-}
+AutofillSaveCardInfoBarDelegateMobileTest::
+    AutofillSaveCardInfoBarDelegateMobileTest() {}
 
-AutofillCCInfobarDelegateTest::~AutofillCCInfobarDelegateTest() {}
+AutofillSaveCardInfoBarDelegateMobileTest::
+    ~AutofillSaveCardInfoBarDelegateMobileTest() {}
 
-void AutofillCCInfobarDelegateTest::SetUp() {
+void AutofillSaveCardInfoBarDelegateMobileTest::SetUp() {
   ChromeRenderViewHostTestHarness::SetUp();
 
-  // Ensure Mac OS X does not pop up a modal dialog for the Address Book.
-  test::DisableSystemServices(profile()->GetPrefs());
-
   PersonalDataManagerFactory::GetInstance()->SetTestingFactory(profile(), NULL);
 
   ChromeAutofillClient::CreateForWebContents(web_contents());
@@ -81,26 +81,29 @@
   personal_data_->SetPrefService(profile()->GetPrefs());
 }
 
-void AutofillCCInfobarDelegateTest::TearDown() {
+void AutofillSaveCardInfoBarDelegateMobileTest::TearDown() {
   personal_data_.reset();
   ChromeRenderViewHostTestHarness::TearDown();
 }
 
 scoped_ptr<ConfirmInfoBarDelegate>
-AutofillCCInfobarDelegateTest::CreateDelegate() {
+AutofillSaveCardInfoBarDelegateMobileTest::CreateDelegate() {
   base::HistogramTester histogram_tester;
   CreditCard credit_card;
-  scoped_ptr<ConfirmInfoBarDelegate> delegate(AutofillCCInfoBarDelegate::Create(
-      base::Bind(
-          base::IgnoreResult(&TestPersonalDataManager::SaveImportedCreditCard),
-          base::Unretained(personal_data_.get()), credit_card)));
+  scoped_ptr<base::DictionaryValue> legal_message;
+  scoped_ptr<ConfirmInfoBarDelegate> delegate(
+      new AutofillSaveCardInfoBarDelegateMobile(
+          false, credit_card, std::move(legal_message),
+          base::Bind(base::IgnoreResult(
+                         &TestPersonalDataManager::SaveImportedCreditCard),
+                     base::Unretained(personal_data_.get()), credit_card)));
   histogram_tester.ExpectUniqueSample("Autofill.CreditCardInfoBar",
                                       AutofillMetrics::INFOBAR_SHOWN, 1);
   return delegate;
 }
 
 // Test that credit card infobar metrics are logged correctly.
-TEST_F(AutofillCCInfobarDelegateTest, Metrics) {
+TEST_F(AutofillSaveCardInfoBarDelegateMobileTest, Metrics) {
   ::testing::InSequence dummy;
 
   // Accept the infobar.
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc
index ae0c2e0f..81bd54d 100644
--- a/chrome/browser/chromeos/login/chrome_restart_request.cc
+++ b/chrome/browser/chromeos/login/chrome_restart_request.cc
@@ -73,6 +73,7 @@
 
   static const char* const kForwardSwitches[] = {
     ::switches::kBlinkSettings,
+    ::switches::kDisable2dCanvasImageChromium,
     ::switches::kDisableAccelerated2dCanvas,
     ::switches::kDisableAcceleratedJpegDecoding,
     ::switches::kDisableAcceleratedMjpegDecode,
diff --git a/chrome/browser/chromeos/profiles/avatar_menu_actions_chromeos.cc b/chrome/browser/chromeos/profiles/avatar_menu_actions_chromeos.cc
index 1fc56f4..885cd3f 100644
--- a/chrome/browser/chromeos/profiles/avatar_menu_actions_chromeos.cc
+++ b/chrome/browser/chromeos/profiles/avatar_menu_actions_chromeos.cc
@@ -32,7 +32,7 @@
   ash::Shell::GetInstance()->system_tray_delegate()->ShowUserLogin();
 }
 
-void AvatarMenuActionsChromeOS::EditProfile(Profile* profile, size_t index) {
+void AvatarMenuActionsChromeOS::EditProfile(Profile* profile) {
   NOTIMPLEMENTED();
 }
 
diff --git a/chrome/browser/chromeos/profiles/avatar_menu_actions_chromeos.h b/chrome/browser/chromeos/profiles/avatar_menu_actions_chromeos.h
index 9311c47..7a2ce94 100644
--- a/chrome/browser/chromeos/profiles/avatar_menu_actions_chromeos.h
+++ b/chrome/browser/chromeos/profiles/avatar_menu_actions_chromeos.h
@@ -25,7 +25,7 @@
 
   // AvatarMenuActions overrides:
   void AddNewProfile(ProfileMetrics::ProfileAdd type) override;
-  void EditProfile(Profile* profile, size_t index) override;
+  void EditProfile(Profile* profile) override;
   bool ShouldShowAddNewProfileLink() const override;
   bool ShouldShowEditProfileLink() const override;
   void ActiveBrowserChanged(Browser* browser) override;
diff --git a/chrome/browser/chromeos/profiles/profile_list_chromeos.cc b/chrome/browser/chromeos/profiles/profile_list_chromeos.cc
index 840d29f..69e2186f 100644
--- a/chrome/browser/chromeos/profiles/profile_list_chromeos.cc
+++ b/chrome/browser/chromeos/profiles/profile_list_chromeos.cc
@@ -4,11 +4,14 @@
 
 #include "chrome/browser/chromeos/profiles/profile_list_chromeos.h"
 
-#include <algorithm>
+#include <unordered_map>
+#include <utility>
 
 #include "ash/shell.h"
 #include "base/command_line.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/profiles/profile_attributes_entry.h"
+#include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_avatar_icon_util.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/chrome_switches.h"
@@ -16,18 +19,17 @@
 #include "components/user_manager/user_manager.h"
 
 // static
-ProfileList* ProfileList::Create(ProfileInfoInterface* profile_cache) {
-  return new chromeos::ProfileListChromeOS(profile_cache);
+ProfileList* ProfileList::Create(ProfileAttributesStorage* profile_storage) {
+  return new chromeos::ProfileListChromeOS(profile_storage);
 }
 
 namespace chromeos {
 
-ProfileListChromeOS::ProfileListChromeOS(ProfileInfoInterface* profile_cache)
-    : profile_info_(profile_cache) {
-}
+ProfileListChromeOS::ProfileListChromeOS(
+    ProfileAttributesStorage* profile_storage)
+    : profile_storage_(profile_storage) {}
 
 ProfileListChromeOS::~ProfileListChromeOS() {
-  ClearMenu();
 }
 
 size_t ProfileListChromeOS::GetNumberOfItems() const {
@@ -40,72 +42,70 @@
 }
 
 void ProfileListChromeOS::RebuildMenu() {
-  ClearMenu();
+  items_.clear();
 
-  // Filter for profiles associated with logged-in users.
+  // Only the profiles associated with logged-in users are added to the menu.
   user_manager::UserList users =
       user_manager::UserManager::Get()->GetLoggedInUsers();
 
-  // Add corresponding profiles.
-  for (user_manager::UserList::const_iterator it = users.begin();
-       it != users.end();
-       ++it) {
-    size_t i = profile_info_->GetIndexOfProfileWithPath(
-        ProfileHelper::GetProfilePathByUserIdHash((*it)->username_hash()));
+  // Create a mapping from profile path to the corresponding entries in |users|.
+  std::unordered_map<base::FilePath::StringType, size_t> user_indices_by_path;
+  for (size_t i = 0; i < users.size(); ++i) {
+    user_indices_by_path.insert(std::make_pair(
+        ProfileHelper::GetProfilePathByUserIdHash(users[i]->username_hash())
+            .value(),
+        i));
+  }
+  DCHECK_EQ(user_indices_by_path.size(), users.size());
 
-    gfx::Image icon = gfx::Image((*it)->GetImage());
+  std::vector<ProfileAttributesEntry*> entries =
+      profile_storage_->GetAllProfilesAttributesSortedByName();
+
+  // Add the profiles.
+  for (ProfileAttributesEntry* entry : entries) {
+    auto user_index_it = user_indices_by_path.find(entry->GetPath().value());
+    if (user_index_it == user_indices_by_path.end())
+      continue;
+    user_manager::User* user = users[user_index_it->second];
+
+    gfx::Image icon = gfx::Image(user->GetImage());
     if (!switches::IsNewProfileManagement() && !icon.IsEmpty()) {
       // old avatar menu uses resized-small images
       icon = profiles::GetAvatarIconForMenu(icon, true);
     }
 
-    AvatarMenu::Item* item = new AvatarMenu::Item(i, i, icon);
-    item->name = (*it)->GetDisplayName();
-    item->username = profile_info_->GetUserNameOfProfileAtIndex(i);
-    item->profile_path = profile_info_->GetPathOfProfileAtIndex(i);
-    DCHECK(!profile_info_->ProfileIsLegacySupervisedAtIndex(i));
+    scoped_ptr<AvatarMenu::Item> item(
+        new AvatarMenu::Item(items_.size(), entry->GetPath(), icon));
+    item->name = user->GetDisplayName();
+    item->username = entry->GetUserName();
+    DCHECK(!entry->IsLegacySupervised());
     item->legacy_supervised = false;
-    item->child_account = profile_info_->ProfileIsChildAtIndex(i);
+    item->child_account = entry->IsChild();
     item->signed_in = true;
-    item->active = profile_info_->GetPathOfProfileAtIndex(i) ==
-        active_profile_path_;
-    item->signin_required = profile_info_->ProfileIsSigninRequiredAtIndex(i);
-    items_.push_back(item);
+    item->active = item->profile_path == active_profile_path_;
+    item->signin_required = entry->IsSigninRequired();
+    items_.push_back(std::move(item));
   }
-
-  SortMenu();
-
-  // After sorting, assign items their actual indices.
-  for (size_t i = 0; i < items_.size(); ++i)
-    items_[i]->menu_index = i;
 }
 
-size_t ProfileListChromeOS::MenuIndexFromProfileIndex(size_t index) {
+size_t ProfileListChromeOS::MenuIndexFromProfilePath(
+    const base::FilePath& path) const {
+  const size_t menu_count = GetNumberOfItems();
+
+  for (size_t i = 0; i < menu_count; ++i) {
+    const AvatarMenu::Item item = GetItemAt(i);
+    if (item.profile_path == path)
+      return i;
+  }
+
   // On ChromeOS, the active profile might be Default, which does not show
   // up in the model as a logged-in user. In that case, we return 0.
-  size_t menu_index = 0;
-
-  for (size_t i = 0; i < GetNumberOfItems(); ++i) {
-    if (items_[i]->profile_index == index) {
-      menu_index = i;
-      break;
-    }
-  }
-
-  return menu_index;
+  return 0;
 }
 
-void ProfileListChromeOS::ActiveProfilePathChanged(base::FilePath& path) {
-  active_profile_path_ = path;
-}
-
-void ProfileListChromeOS::ClearMenu() {
-  STLDeleteElements(&items_);
-}
-
-void ProfileListChromeOS::SortMenu() {
-  // Sort list of items by name.
-  std::sort(items_.begin(), items_.end(), &AvatarMenu::CompareItems);
+void ProfileListChromeOS::ActiveProfilePathChanged(
+    const base::FilePath& active_profile_path) {
+  active_profile_path_ = active_profile_path;
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/profiles/profile_list_chromeos.h b/chrome/browser/chromeos/profiles/profile_list_chromeos.h
index e7854eb..b17ef52c 100644
--- a/chrome/browser/chromeos/profiles/profile_list_chromeos.h
+++ b/chrome/browser/chromeos/profiles/profile_list_chromeos.h
@@ -12,36 +12,35 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
 
-class ProfileInfoInterface;
+class ProfileAttributesStorage;
 
 namespace chromeos {
 
 // This model represents profiles corresponding to logged-in ChromeOS users.
 class ProfileListChromeOS : public ProfileList {
  public:
-  explicit ProfileListChromeOS(ProfileInfoInterface* profile_cache);
+  explicit ProfileListChromeOS(ProfileAttributesStorage* profile_storage);
   ~ProfileListChromeOS() override;
 
+ private:
   // ProfileList overrides:
   size_t GetNumberOfItems() const override;
   const AvatarMenu::Item& GetItemAt(size_t index) const override;
   void RebuildMenu() override;
-  size_t MenuIndexFromProfileIndex(size_t index) override;
-  void ActiveProfilePathChanged(base::FilePath& path) override;
+  size_t MenuIndexFromProfilePath(const base::FilePath& path) const override;
+  void ActiveProfilePathChanged(
+      const base::FilePath& active_profile_path) override;
 
- private:
-  void ClearMenu();
-  void SortMenu();
-
-  // The cache that provides the profile information. Weak.
-  ProfileInfoInterface* profile_info_;
+  // The storage that provides the profile attributes. Not owned.
+  ProfileAttributesStorage* profile_storage_;
 
   // The path of the currently active profile.
   base::FilePath active_profile_path_;
 
   // List of built "menu items."
-  std::vector<AvatarMenu::Item*> items_;
+  std::vector<scoped_ptr<AvatarMenu::Item>> items_;
 
   DISALLOW_COPY_AND_ASSIGN(ProfileListChromeOS);
 };
diff --git a/chrome/browser/chromeos/profiles/profile_list_chromeos_unittest.cc b/chrome/browser/chromeos/profiles/profile_list_chromeos_unittest.cc
index d222bd6..d173430 100644
--- a/chrome/browser/chromeos/profiles/profile_list_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/profiles/profile_list_chromeos_unittest.cc
@@ -15,11 +15,13 @@
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/avatar_menu.h"
 #include "chrome/browser/profiles/avatar_menu_observer.h"
-#include "chrome/browser/profiles/profile_info_cache.h"
+#include "chrome/browser/profiles/profile_attributes_entry.h"
+#include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/ui/ash/chrome_shell_delegate.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/testing_browser_process.h"
+#include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/testing_profile_manager.h"
 #include "components/syncable_prefs/pref_service_syncable.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -71,7 +73,7 @@
         user_manager::UserManager::Get());
   }
 
-  void AddProfile(base::string16 name, bool log_in) {
+  TestingProfile* AddProfile(base::string16 name, bool log_in) {
     std::string email_string = base::UTF16ToASCII(name) + "@example.com";
     const AccountId account_id(AccountId::FromUserEmail(email_string));
 
@@ -81,7 +83,7 @@
       GetFakeChromeUserManager()->LoginUser(account_id);
 
     // Create a profile for the user.
-    manager()->CreateTestingProfile(account_id.GetUserEmail());
+    return manager()->CreateTestingProfile(account_id.GetUserEmail());
   }
 
   AvatarMenu* GetAvatarMenu() {
@@ -163,10 +165,10 @@
   AddProfile(name1, true);
 
   // Add a managed user profile.
-  ProfileInfoCache* cache = manager()->profile_info_cache();
-  manager()->profile_info_cache()->AddProfileToCache(
-      cache->GetUserDataDir().AppendASCII("p2"), supervised_name, std::string(),
-      base::string16(), 0, "TEST_ID");
+  ProfileAttributesStorage* storage = manager()->profile_attributes_storage();
+  storage->AddProfile(manager()->profiles_dir().AppendASCII("p2"),
+                      supervised_name, std::string(), base::string16(), 0U,
+                      "TEST_ID");
 
   GetFakeChromeUserManager()->AddUser(
       AccountId::FromUserEmail(base::UTF16ToASCII(supervised_name)));
@@ -174,7 +176,7 @@
   AvatarMenu* menu = GetAvatarMenu();
   ASSERT_EQ(1U, menu->GetNumberOfItems());
 
-  const AvatarMenu::Item& item1 = menu->GetItemAt(0);
+  const AvatarMenu::Item& item1 = menu->GetItemAt(0U);
   EXPECT_EQ(0U, item1.menu_index);
   EXPECT_EQ(name1, item1.name);
 }
@@ -227,7 +229,7 @@
   base::string16 name2(ASCIIToUTF16("Beta"));
   base::string16 newname1(ASCIIToUTF16("Gamma"));
 
-  AddProfile(name1, true);
+  TestingProfile* profile1 = AddProfile(name1, true);
   AddProfile(name2, true);
 
   AvatarMenu* menu = GetAvatarMenu();
@@ -242,14 +244,19 @@
   EXPECT_EQ(1U, item2.menu_index);
   EXPECT_EQ(name2, item2.name);
 
-  // Change name of the first profile, to trigger resorting of the profiles:
-  // now the first menu item should be named "beta", and the second be "gamma".
+  // Change the name of the first profile, and this triggers the resorting of
+  // the avatar menu.
   GetFakeChromeUserManager()->SaveUserDisplayName(
       AccountId::FromUserEmail(base::UTF16ToASCII(name1) + "@example.com"),
       newname1);
-  manager()->profile_info_cache()->SetNameOfProfileAtIndex(0, newname1);
+  ProfileAttributesEntry* entry;
+  ASSERT_TRUE(
+      manager()->profile_attributes_storage()->GetProfileAttributesWithPath(
+          profile1->GetPath(), &entry));
+  entry->SetName(newname1);
   EXPECT_EQ(1, change_count());
 
+  // Now the first menu item should be named "beta", and the second be "gamma".
   const AvatarMenu::Item& item1next = menu->GetItemAt(0);
   EXPECT_EQ(0U, item1next.menu_index);
   EXPECT_EQ(name2, item1next.name);
diff --git a/chrome/browser/extensions/api/metrics_private/metrics_apitest.cc b/chrome/browser/extensions/api/metrics_private/metrics_apitest.cc
index d4c5e3c..3160400 100644
--- a/chrome/browser/extensions/api/metrics_private/metrics_apitest.cc
+++ b/chrome/browser/extensions/api/metrics_private/metrics_apitest.cc
@@ -128,7 +128,7 @@
 
 }  // anonymous namespace
 
-IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_Metrics) {
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Metrics) {
   base::UserActionTester user_action_tester;
 
   base::FieldTrialList::CreateFieldTrial("apitestfieldtrial2", "group1");
diff --git a/chrome/browser/extensions/api/preferences_private/preferences_private_apitest.cc b/chrome/browser/extensions/api/preferences_private/preferences_private_apitest.cc
index 29969c11..75101a4 100644
--- a/chrome/browser/extensions/api/preferences_private/preferences_private_apitest.cc
+++ b/chrome/browser/extensions/api/preferences_private/preferences_private_apitest.cc
@@ -50,6 +50,7 @@
  public:
   explicit FakeProfileSyncService(Profile* profile)
       : ProfileSyncService(CreateProfileSyncServiceParamsForTest(profile)),
+        test_started_(false),
         sync_initialized_(true),
         initialized_state_violation_(false) {}
 
@@ -61,6 +62,10 @@
         new FakeProfileSyncService(static_cast<Profile*>(context)));
   }
 
+  void set_test_started(bool test_started) {
+    test_started_ = test_started;
+  }
+
   void set_sync_initialized(bool sync_initialized) {
     sync_initialized_ = sync_initialized;
   }
@@ -71,6 +76,10 @@
   bool IsSyncActive() const override { return sync_initialized_; }
 
   void AddObserver(sync_driver::SyncServiceObserver* observer) override {
+    // Ignore other SyncServiceObsevers which we don't care about.
+    if (!test_started_)
+      return;
+
     if (sync_initialized_)
       initialized_state_violation_ = true;
     // Set sync initialized state to true so the function will run after
@@ -99,6 +108,7 @@
   }
 
  private:
+  bool test_started_;
   bool sync_initialized_;
   // Set to true if a function is called when sync_initialized is in an
   // unexpected state.
@@ -141,6 +151,8 @@
         profile, &FakeProfileSyncService::BuildFakeProfileSyncService));
 
     browser_ = new Browser(Browser::CreateParams(profile));
+
+    service_->set_test_started(true);
   }
 
   // Calls GetSyncCategoriesWithoutPassphraseFunction and verifies that the
diff --git a/chrome/browser/media/android/remote/remote_media_player_bridge.cc b/chrome/browser/media/android/remote/remote_media_player_bridge.cc
index bcb4dab..af4069cd 100644
--- a/chrome/browser/media/android/remote/remote_media_player_bridge.cc
+++ b/chrome/browser/media/android/remote/remote_media_player_bridge.cc
@@ -43,10 +43,15 @@
     const std::string& user_agent,
     bool hide_url_log,
     RemoteMediaPlayerManager* manager)
-    : MediaPlayerAndroid(player_id,
-                         manager,
-                         base::Bind(&DoNothing),
-                         manager->GetLocalPlayer(player_id)->frame_url()),
+    : MediaPlayerAndroid(
+          player_id,
+          manager,
+          base::Bind(&DoNothing),
+          manager->GetLocalPlayer(player_id)->frame_url(),
+          // TODO(davve): Media session interaction with remote
+          // playback not defined. Use invalid session id for now.
+          // https://github.com/whatwg/mediasession/issues/123
+          media::kInvalidMediaSessionId),
       width_(0),
       height_(0),
       hide_url_log_(hide_url_log),
diff --git a/chrome/browser/media/chrome_media_stream_infobar_browsertest.cc b/chrome/browser/media/media_stream_infobar_browsertest.cc
similarity index 100%
rename from chrome/browser/media/chrome_media_stream_infobar_browsertest.cc
rename to chrome/browser/media/media_stream_infobar_browsertest.cc
diff --git a/chrome/browser/media/chrome_webrtc_apprtc_browsertest.cc b/chrome/browser/media/webrtc_apprtc_browsertest.cc
similarity index 100%
rename from chrome/browser/media/chrome_webrtc_apprtc_browsertest.cc
rename to chrome/browser/media/webrtc_apprtc_browsertest.cc
diff --git a/chrome/browser/media/chrome_webrtc_audio_quality_browsertest.cc b/chrome/browser/media/webrtc_audio_quality_browsertest.cc
similarity index 100%
rename from chrome/browser/media/chrome_webrtc_audio_quality_browsertest.cc
rename to chrome/browser/media/webrtc_audio_quality_browsertest.cc
diff --git a/chrome/browser/media/chrome_webrtc_browsertest.cc b/chrome/browser/media/webrtc_browsertest.cc
similarity index 100%
rename from chrome/browser/media/chrome_webrtc_browsertest.cc
rename to chrome/browser/media/webrtc_browsertest.cc
diff --git a/chrome/browser/media/chrome_webrtc_disable_encryption_flag_browsertest.cc b/chrome/browser/media/webrtc_disable_encryption_flag_browsertest.cc
similarity index 100%
rename from chrome/browser/media/chrome_webrtc_disable_encryption_flag_browsertest.cc
rename to chrome/browser/media/webrtc_disable_encryption_flag_browsertest.cc
diff --git a/chrome/browser/media/chrome_webrtc_getmediadevices_browsertest.cc b/chrome/browser/media/webrtc_getmediadevices_browsertest.cc
similarity index 100%
rename from chrome/browser/media/chrome_webrtc_getmediadevices_browsertest.cc
rename to chrome/browser/media/webrtc_getmediadevices_browsertest.cc
diff --git a/chrome/browser/media/chrome_webrtc_perf_browsertest.cc b/chrome/browser/media/webrtc_perf_browsertest.cc
similarity index 100%
rename from chrome/browser/media/chrome_webrtc_perf_browsertest.cc
rename to chrome/browser/media/webrtc_perf_browsertest.cc
diff --git a/chrome/browser/media/chrome_webrtc_simulcast_browsertest.cc b/chrome/browser/media/webrtc_simulcast_browsertest.cc
similarity index 100%
rename from chrome/browser/media/chrome_webrtc_simulcast_browsertest.cc
rename to chrome/browser/media/webrtc_simulcast_browsertest.cc
diff --git a/chrome/browser/media/chrome_webrtc_video_quality_browsertest.cc b/chrome/browser/media/webrtc_video_quality_browsertest.cc
similarity index 100%
rename from chrome/browser/media/chrome_webrtc_video_quality_browsertest.cc
rename to chrome/browser/media/webrtc_video_quality_browsertest.cc
diff --git a/chrome/browser/media/chrome_webrtc_webcam_browsertest.cc b/chrome/browser/media/webrtc_webcam_browsertest.cc
similarity index 100%
rename from chrome/browser/media/chrome_webrtc_webcam_browsertest.cc
rename to chrome/browser/media/webrtc_webcam_browsertest.cc
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc
index f84fa54..4185544f 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -46,7 +46,6 @@
 #include "components/password_manager/core/common/credential_manager_types.h"
 #include "components/password_manager/core/common/password_manager_features.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
-#include "components/password_manager/core/common/password_manager_switches.h"
 #include "components/password_manager/sync/browser/password_sync_util.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/core/browser/signin_manager.h"
diff --git a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
index d1f0ff6fe..d948385 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
@@ -9,7 +9,6 @@
 #include <string>
 #include <tuple>
 
-#include "base/command_line.h"
 #include "base/macros.h"
 #include "base/metrics/field_trial.h"
 #include "base/strings/string16.h"
@@ -27,10 +26,10 @@
 #include "components/password_manager/core/browser/log_receiver.h"
 #include "components/password_manager/core/browser/log_router.h"
 #include "components/password_manager/core/browser/password_manager_internals_service.h"
+#include "components/password_manager/core/browser/password_manager_test_utils.h"
 #include "components/password_manager/core/common/credential_manager_types.h"
 #include "components/password_manager/core/common/password_manager_features.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
-#include "components/password_manager/core/common/password_manager_switches.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/testing_pref_service.h"
@@ -169,11 +168,13 @@
 TEST_F(ChromePasswordManagerClientTest,
        IsAutomaticPasswordSavingEnabledWhenFlagIsSetTest) {
   // Add the enable-automatic-password-saving feature.
-  base::FeatureList::ClearInstanceForTesting();
   scoped_ptr<base::FeatureList> feature_list(new base::FeatureList);
-  feature_list->InitializeFromCommandLine(
-      password_manager::features::kEnableAutomaticPasswordSaving.name, "");
-  base::FeatureList::SetInstance(std::move(feature_list));
+  std::vector<const base::Feature*> enabled_features;
+  std::vector<const base::Feature*> disabled_features;
+  enabled_features.push_back(
+      &password_manager::features::kEnableAutomaticPasswordSaving);
+  password_manager::SetFeatures(enabled_features, disabled_features,
+                                std::move(feature_list));
 
   if (chrome::GetChannel() == version_info::Channel::UNKNOWN)
     EXPECT_TRUE(GetClient()->IsAutomaticPasswordSavingEnabled());
diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc
index d159169f..bff8b0c 100644
--- a/chrome/browser/password_manager/password_manager_browsertest.cc
+++ b/chrome/browser/password_manager/password_manager_browsertest.cc
@@ -40,7 +40,6 @@
 #include "components/password_manager/core/browser/login_model.h"
 #include "components/password_manager/core/browser/test_password_store.h"
 #include "components/password_manager/core/common/password_manager_features.h"
-#include "components/password_manager/core/common/password_manager_switches.h"
 #include "components/version_info/version_info.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/notification_service.h"
diff --git a/chrome/browser/password_manager/password_manager_test_base.cc b/chrome/browser/password_manager/password_manager_test_base.cc
index 7661d4f..7fdb0e2 100644
--- a/chrome/browser/password_manager/password_manager_test_base.cc
+++ b/chrome/browser/password_manager/password_manager_test_base.cc
@@ -6,7 +6,6 @@
 
 #include <string>
 
-#include "base/command_line.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
@@ -25,7 +24,6 @@
 #include "components/password_manager/core/browser/password_manager_test_utils.h"
 #include "components/password_manager/core/browser/test_password_store.h"
 #include "components/password_manager/core/common/password_manager_features.h"
-#include "components/password_manager/core/common/password_manager_switches.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
diff --git a/chrome/browser/password_manager/save_password_infobar_delegate.cc b/chrome/browser/password_manager/save_password_infobar_delegate.cc
index 2b65cfc..fe309bb 100644
--- a/chrome/browser/password_manager/save_password_infobar_delegate.cc
+++ b/chrome/browser/password_manager/save_password_infobar_delegate.cc
@@ -69,7 +69,7 @@
   PasswordTittleType type =
       form_to_save_->pending_credentials().federation_origin.unique()
           ? PasswordTittleType::SAVE_PASSWORD
-          : PasswordTittleType::UPDATE_PASSWORD;
+          : PasswordTittleType::SAVE_ACCOUNT;
   GetSavePasswordDialogTitleTextAndLinkRange(
       web_contents->GetVisibleURL(), form_to_save_->observed_form().origin,
       is_smartlock_branding_enabled, type,
diff --git a/chrome/browser/profiles/avatar_menu.cc b/chrome/browser/profiles/avatar_menu.cc
index a507dc8f..e2994cc 100644
--- a/chrome/browser/profiles/avatar_menu.cc
+++ b/chrome/browser/profiles/avatar_menu.cc
@@ -43,23 +43,21 @@
 AvatarMenu::AvatarMenu(ProfileAttributesStorage* profile_storage,
                        AvatarMenuObserver* observer,
                        Browser* browser)
-    : profile_list_(ProfileList::Create(
-          &g_browser_process->profile_manager()->GetProfileInfoCache())),
+    : profile_list_(ProfileList::Create(profile_storage)),
       menu_actions_(AvatarMenuActions::Create()),
 #if defined(ENABLE_SUPERVISED_USERS)
       supervised_user_observer_(this),
 #endif
-      profile_info_(
-          &g_browser_process->profile_manager()->GetProfileInfoCache()),
+      profile_storage_(profile_storage),
       observer_(observer),
       browser_(browser) {
-  DCHECK(profile_info_);
+  DCHECK(profile_storage_);
   // Don't DCHECK(browser_) so that unit tests can reuse this ctor.
 
   ActiveBrowserChanged(browser_);
 
   // Register this as an observer of the info cache.
-  g_browser_process->profile_manager()->GetProfileInfoCache().AddObserver(this);
+  profile_storage_->AddObserver(this);
 
 #if defined(ENABLE_SUPERVISED_USERS)
   // Register this as an observer of the SupervisedUserService to be notified
@@ -72,19 +70,17 @@
 }
 
 AvatarMenu::~AvatarMenu() {
-  g_browser_process->profile_manager()->
-      GetProfileInfoCache().RemoveObserver(this);
+  profile_storage_->RemoveObserver(this);
 }
 
-AvatarMenu::Item::Item(size_t menu_index,
-                       size_t profile_index,
+AvatarMenu::Item::Item(size_t menu_index, const base::FilePath& profile_path,
                        const gfx::Image& icon)
     : icon(icon),
       active(false),
       signed_in(false),
       signin_required(false),
       menu_index(menu_index),
-      profile_index(profile_index) {
+      profile_path(profile_path) {
 }
 
 AvatarMenu::Item::Item(const Item& other) = default;
@@ -105,11 +101,6 @@
 #endif
 }
 
-bool AvatarMenu::CompareItems(const Item* item1, const Item* item2) {
-  return base::i18n::ToLower(item1->name).compare(
-      base::i18n::ToLower(item2->name)) < 0;
-}
-
 void AvatarMenu::SwitchToProfile(size_t index,
                                  bool always_create,
                                  ProfileMetrics::ProfileOpen metric) {
@@ -128,10 +119,7 @@
   }
 #endif
 
-  base::FilePath path =
-      profile_info_->GetPathOfProfileAtIndex(item.profile_index);
-
-  profiles::SwitchToProfile(path, always_create,
+  profiles::SwitchToProfile(item.profile_path, always_create,
                             ProfileManager::CreateCallback(), metric);
 }
 
@@ -140,13 +128,10 @@
 }
 
 void AvatarMenu::EditProfile(size_t index) {
-  // Get the index in the profile cache from the menu index.
-  size_t profile_index = profile_list_->GetItemAt(index).profile_index;
-
   Profile* profile = g_browser_process->profile_manager()->GetProfileByPath(
-        profile_info_->GetPathOfProfileAtIndex(profile_index));
+      profile_list_->GetItemAt(index).profile_path);
 
-  menu_actions_->EditProfile(profile, profile_index);
+  menu_actions_->EditProfile(profile);
 }
 
 void AvatarMenu::RebuildMenu() {
@@ -161,22 +146,21 @@
   return profile_list_->GetItemAt(index);
 }
 
+size_t AvatarMenu::GetIndexOfItemWithProfilePath(const base::FilePath& path) {
+  return profile_list_->MenuIndexFromProfilePath(path);
+}
+
 size_t AvatarMenu::GetActiveProfileIndex() {
   // During singleton profile deletion, this function can be called with no
   // profiles in the model - crbug.com/102278 .
   if (profile_list_->GetNumberOfItems() == 0)
     return 0;
 
-  Profile* active_profile = NULL;
-  if (!browser_)
-    active_profile = ProfileManager::GetLastUsedProfile();
-  else
-    active_profile = browser_->profile();
+  Profile* active_profile = browser_ ? browser_->profile()
+                                     : ProfileManager::GetLastUsedProfile();
 
   size_t index =
-      profile_info_->GetIndexOfProfileWithPath(active_profile->GetPath());
-
-  index = profile_list_->MenuIndexFromProfileIndex(index);
+      profile_list_->MenuIndexFromProfilePath(active_profile->GetPath());
   DCHECK_LT(index, profile_list_->GetNumberOfItems());
   return index;
 }
@@ -210,7 +194,8 @@
   browser_ = browser;
   menu_actions_->ActiveBrowserChanged(browser);
 
-  // If browser is not NULL, get the path of its active profile.
+  // Get the path of its active profile if |browser| is not NULL. Note that
+  // |browser| is NULL in unit tests.
   base::FilePath path;
   if (browser)
     path = browser->profile()->GetPath();
@@ -268,9 +253,7 @@
 
 #if defined(ENABLE_SUPERVISED_USERS)
 void AvatarMenu::OnCustodianInfoChanged() {
-  RebuildMenu();
-  if (observer_)
-    observer_->OnAvatarMenuChanged(this);
+  Update();
 }
 #endif
 
diff --git a/chrome/browser/profiles/avatar_menu.h b/chrome/browser/profiles/avatar_menu.h
index 47aea9c..15c88ec5 100644
--- a/chrome/browser/profiles/avatar_menu.h
+++ b/chrome/browser/profiles/avatar_menu.h
@@ -11,10 +11,11 @@
 #include <vector>
 
 #include "base/compiler_specific.h"
+#include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/scoped_observer.h"
 #include "base/strings/string16.h"
-#include "chrome/browser/profiles/profile_info_cache_observer.h"
+#include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_metrics.h"
 #include "chrome/browser/ui/host_desktop.h"
 #include "content/public/browser/web_contents.h"
@@ -30,7 +31,6 @@
 class Browser;
 class Profile;
 class ProfileAttributesStorage;
-class ProfileInfoInterface;
 class ProfileList;
 class SupervisedUserService;
 
@@ -43,11 +43,12 @@
 #if defined(ENABLE_SUPERVISED_USERS)
     public SupervisedUserServiceObserver,
 #endif
-    public ProfileInfoCacheObserver {
+    public ProfileAttributesStorage::Observer {
  public:
   // Represents an item in the menu.
   struct Item {
-    Item(size_t menu_index, size_t profile_index, const gfx::Image& icon);
+    Item(size_t menu_index, const base::FilePath& profile_path,
+         const gfx::Image& icon);
     Item(const Item& other);
     ~Item();
 
@@ -83,9 +84,6 @@
     // profiles.
     size_t menu_index;
 
-    // The index in the |profile_cache| for this profile.
-    size_t profile_index;
-
     // The path of this profile.
     base::FilePath profile_path;
   };
@@ -107,9 +105,6 @@
                                     gfx::Image* image,
                                     bool* is_rectangle);
 
-  // Compare items by name.
-  static bool CompareItems(const Item* item1, const Item* item2);
-
   // Opens a Browser with the specified profile in response to the user
   // selecting an item. If |always_create| is true then a new window is created
   // even if a window for that profile already exists.
@@ -133,6 +128,9 @@
   // Gets the Item at the specified index.
   const Item& GetItemAt(size_t index) const;
 
+  // Gets the index in this menu for which profile_path is equal to |path|.
+  size_t GetIndexOfItemWithProfilePath(const base::FilePath& path);
+
   // Returns the index of the active profile.
   size_t GetActiveProfileIndex();
 
@@ -152,7 +150,7 @@
   bool ShouldShowEditProfileLink() const;
 
  private:
-  // ProfileInfoCacheObserver:
+  // ProfileAttributesStorage::Observer:
   void OnProfileAdded(const base::FilePath& profile_path) override;
   void OnProfileWasRemoved(const base::FilePath& profile_path,
       const base::string16& profile_name) override;
@@ -186,8 +184,8 @@
       supervised_user_observer_;
 #endif
 
-  // The cache that provides the profile information. Weak.
-  ProfileInfoInterface* profile_info_;
+  // The storage that provides the profile attributes. Weak.
+  ProfileAttributesStorage* profile_storage_;
 
   // The observer of this model, which is notified of changes. Weak.
   AvatarMenuObserver* observer_;
diff --git a/chrome/browser/profiles/avatar_menu_actions.h b/chrome/browser/profiles/avatar_menu_actions.h
index 3ae7515..312a17e 100644
--- a/chrome/browser/profiles/avatar_menu_actions.h
+++ b/chrome/browser/profiles/avatar_menu_actions.h
@@ -25,7 +25,7 @@
   virtual void AddNewProfile(ProfileMetrics::ProfileAdd type) = 0;
 
   // Allows the user to edit the profile at the given index in the cache.
-  virtual void EditProfile(Profile* profile, size_t index) = 0;
+  virtual void EditProfile(Profile* profile) = 0;
 
   // Returns true if the add profile link should be shown.
   virtual bool ShouldShowAddNewProfileLink() const = 0;
diff --git a/chrome/browser/profiles/avatar_menu_actions_desktop.cc b/chrome/browser/profiles/avatar_menu_actions_desktop.cc
index 3a3a872..233c8fe 100644
--- a/chrome/browser/profiles/avatar_menu_actions_desktop.cc
+++ b/chrome/browser/profiles/avatar_menu_actions_desktop.cc
@@ -48,7 +48,7 @@
   ProfileMetrics::LogProfileAddNewUser(type);
 }
 
-void AvatarMenuActionsDesktop::EditProfile(Profile* profile, size_t index) {
+void AvatarMenuActionsDesktop::EditProfile(Profile* profile) {
   Browser* settings_browser = browser_;
   if (!settings_browser) {
     settings_browser = new Browser(Browser::CreateParams(profile));
diff --git a/chrome/browser/profiles/avatar_menu_actions_desktop.h b/chrome/browser/profiles/avatar_menu_actions_desktop.h
index cc95ff15..ee24eeb 100644
--- a/chrome/browser/profiles/avatar_menu_actions_desktop.h
+++ b/chrome/browser/profiles/avatar_menu_actions_desktop.h
@@ -23,7 +23,7 @@
 
   // AvatarMenuActions overrides:
   void AddNewProfile(ProfileMetrics::ProfileAdd type) override;
-  void EditProfile(Profile* profile, size_t index) override;
+  void EditProfile(Profile* profile) override;
   bool ShouldShowAddNewProfileLink() const override;
   bool ShouldShowEditProfileLink() const override;
   void ActiveBrowserChanged(Browser* browser) override;
diff --git a/chrome/browser/profiles/avatar_menu_desktop.cc b/chrome/browser/profiles/avatar_menu_desktop.cc
index 7e7e133..8a7bca6 100644
--- a/chrome/browser/profiles/avatar_menu_desktop.cc
+++ b/chrome/browser/profiles/avatar_menu_desktop.cc
@@ -8,8 +8,9 @@
 
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_attributes_entry.h"
+#include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_avatar_icon_util.h"
-#include "chrome/browser/profiles/profile_info_cache.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "ui/base/resource/resource_bundle.h"
 
@@ -17,17 +18,16 @@
 void AvatarMenu::GetImageForMenuButton(const base::FilePath& profile_path,
                                        gfx::Image* image,
                                        bool* is_rectangle) {
-  ProfileInfoCache& cache =
-      g_browser_process->profile_manager()->GetProfileInfoCache();
-  size_t index = cache.GetIndexOfProfileWithPath(profile_path);
-  if (index == std::string::npos) {
+  ProfileAttributesEntry* entry;
+  if (!g_browser_process->profile_manager()->GetProfileAttributesStorage().
+          GetProfileAttributesWithPath(profile_path, &entry)) {
     NOTREACHED();
     return;
   }
 
   // If there is a Gaia image available, try to use that.
-  if (cache.IsUsingGAIAPictureOfProfileAtIndex(index)) {
-    const gfx::Image* gaia_image = cache.GetGAIAPictureOfProfileAtIndex(index);
+  if (entry->IsUsingGAIAPicture()) {
+    const gfx::Image* gaia_image = entry->GetGAIAPicture();
     if (gaia_image) {
       *image = *gaia_image;
       *is_rectangle = true;
@@ -36,7 +36,7 @@
   }
 
   // Otherwise, use the default resource, not the downloaded high-res one.
-  const size_t icon_index = cache.GetAvatarIconIndexOfProfileAtIndex(index);
+  const size_t icon_index = entry->GetAvatarIconIndex();
   const int resource_id =
       profiles::GetDefaultAvatarIconResourceIDAtIndex(icon_index);
   *image = ResourceBundle::GetSharedInstance().GetNativeImageNamed(resource_id);
diff --git a/chrome/browser/profiles/profile_list.h b/chrome/browser/profiles/profile_list.h
index d76ca23..6bceb0e 100644
--- a/chrome/browser/profiles/profile_list.h
+++ b/chrome/browser/profiles/profile_list.h
@@ -7,16 +7,17 @@
 
 #include <stddef.h>
 
+#include "base/files/file_path.h"
 #include "chrome/browser/profiles/avatar_menu.h"
 
-class ProfileInfoInterface;
+class ProfileAttributesStorage;
 
 // This model represents the profiles added to Chrome.
 class ProfileList {
  public:
   virtual ~ProfileList() {}
 
-  static ProfileList* Create(ProfileInfoInterface* profile_cache);
+  static ProfileList* Create(ProfileAttributesStorage* profile_storage);
 
   // Returns the number of profiles in the model.
   virtual size_t GetNumberOfItems() const = 0;
@@ -28,10 +29,11 @@
   virtual void RebuildMenu() = 0;
 
   // Returns the index in the menu of the specified profile.
-  virtual size_t MenuIndexFromProfileIndex(size_t index) = 0;
+  virtual size_t MenuIndexFromProfilePath(const base::FilePath& path) const = 0;
 
   // Updates the path of the active browser's profile.
-  virtual void ActiveProfilePathChanged(base::FilePath& path) = 0;
+  virtual void ActiveProfilePathChanged(
+      const base::FilePath& active_profile_path) = 0;
 };
 
 #endif  // CHROME_BROWSER_PROFILES_PROFILE_LIST_H_
diff --git a/chrome/browser/profiles/profile_list_desktop.cc b/chrome/browser/profiles/profile_list_desktop.cc
index 2e84242..2b23924 100644
--- a/chrome/browser/profiles/profile_list_desktop.cc
+++ b/chrome/browser/profiles/profile_list_desktop.cc
@@ -4,25 +4,27 @@
 
 #include "chrome/browser/profiles/profile_list_desktop.h"
 
+#include <string>
+
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_attributes_entry.h"
+#include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_avatar_icon_util.h"
-#include "chrome/browser/profiles/profile_info_cache.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/signin/core/common/profile_management_switches.h"
 #include "ui/base/l10n/l10n_util.h"
 
-ProfileListDesktop::ProfileListDesktop(ProfileInfoInterface* profile_cache)
-    : profile_info_(profile_cache),
-      omitted_item_count_(0) {
+ProfileListDesktop::ProfileListDesktop(
+    ProfileAttributesStorage* profile_storage)
+    : profile_storage_(profile_storage) {
 }
 
 ProfileListDesktop::~ProfileListDesktop() {
-  ClearMenu();
 }
 
 // static
-ProfileList* ProfileList::Create(ProfileInfoInterface* profile_cache) {
-  return new ProfileListDesktop(profile_cache);
+ProfileList* ProfileList::Create(ProfileAttributesStorage* profile_storage) {
+  return new ProfileListDesktop(profile_storage);
 }
 
 size_t ProfileListDesktop::GetNumberOfItems() const {
@@ -35,54 +37,40 @@
 }
 
 void ProfileListDesktop::RebuildMenu() {
-  ClearMenu();
+  std::vector<ProfileAttributesEntry*> entries =
+      profile_storage_->GetAllProfilesAttributesSortedByName();
 
-  const size_t count = profile_info_->GetNumberOfProfiles();
-  for (size_t i = 0; i < count; ++i) {
-    if (profile_info_->IsOmittedProfileAtIndex(i)) {
-      omitted_item_count_++;
+  items_.clear();
+  for (ProfileAttributesEntry* entry : entries) {
+    if (entry->IsOmitted())
       continue;
-    }
 
-    gfx::Image icon = profile_info_->GetAvatarIconOfProfileAtIndex(i);
-    AvatarMenu::Item* item = new AvatarMenu::Item(i - omitted_item_count_,
-                                                  i,
-                                                  icon);
-    item->name = profile_info_->GetNameOfProfileAtIndex(i);
-    item->username = profile_info_->GetUserNameOfProfileAtIndex(i);
-    item->profile_path = profile_info_->GetPathOfProfileAtIndex(i);
-    item->legacy_supervised =
-        profile_info_->ProfileIsLegacySupervisedAtIndex(i);
-    item->child_account = profile_info_->ProfileIsChildAtIndex(i);
-    item->signed_in = profile_info_->ProfileIsAuthenticatedAtIndex(i);
+    gfx::Image icon = entry->GetAvatarIcon();
+    scoped_ptr<AvatarMenu::Item> item(
+        new AvatarMenu::Item(items_.size(), entry->GetPath(), icon));
+    item->name = entry->GetName();
+    item->username = entry->GetUserName();
+    item->legacy_supervised = entry->IsLegacySupervised();
+    item->child_account = entry->IsChild();
+    item->signed_in = entry->IsAuthenticated();
     if (!item->signed_in) {
       item->username = l10n_util::GetStringUTF16(
           item->legacy_supervised ? IDS_LEGACY_SUPERVISED_USER_AVATAR_LABEL :
                                     IDS_PROFILES_LOCAL_PROFILE_STATE);
     }
-    item->active = profile_info_->GetPathOfProfileAtIndex(i) ==
-        active_profile_path_;
-    item->signin_required = profile_info_->ProfileIsSigninRequiredAtIndex(i);
-    items_.push_back(item);
+    item->active = item->profile_path == active_profile_path_;
+    item->signin_required = entry->IsSigninRequired();
+    items_.push_back(std::move(item));
   }
-  // One omitted item is expected when a supervised-user profile is in the
-  // process of being registered, but there shouldn't be more than one.
-  VLOG_IF(2, (omitted_item_count_ > 1)) << omitted_item_count_
-                                        << " profiles omitted fom list.";
 }
 
-size_t ProfileListDesktop::MenuIndexFromProfileIndex(size_t index) {
+size_t ProfileListDesktop::MenuIndexFromProfilePath(const base::FilePath& path)
+    const {
   const size_t menu_count = GetNumberOfItems();
-  DCHECK_LT(index, menu_count + omitted_item_count_);
-
-  // In the common case, valid profile-cache indices correspond to indices in
-  // the menu.
-  if (!omitted_item_count_)
-    return index;
 
   for (size_t i = 0; i < menu_count; ++i) {
     const AvatarMenu::Item item = GetItemAt(i);
-    if (item.profile_index == index)
+    if (item.profile_path == path)
       return i;
   }
 
@@ -91,11 +79,7 @@
   return 0;
 }
 
-void ProfileListDesktop::ActiveProfilePathChanged(base::FilePath& path) {
-  active_profile_path_ = path;
-}
-
-void ProfileListDesktop::ClearMenu() {
-  STLDeleteElements(&items_);
-  omitted_item_count_ = 0;
+void ProfileListDesktop::ActiveProfilePathChanged(
+    const base::FilePath& active_profile_path) {
+  active_profile_path_ = active_profile_path;
 }
diff --git a/chrome/browser/profiles/profile_list_desktop.h b/chrome/browser/profiles/profile_list_desktop.h
index 9657461..ea7150ab 100644
--- a/chrome/browser/profiles/profile_list_desktop.h
+++ b/chrome/browser/profiles/profile_list_desktop.h
@@ -10,43 +10,40 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/profiles/profile_list.h"
 
 class Browser;
-class ProfileInfoInterface;
+class ProfileAttributesStorage;
 
 // This model represents the profiles added to desktop Chrome (as opposed to
 // Chrome OS). Profiles marked not to appear in the list will be omitted
 // throughout.
 class ProfileListDesktop : public ProfileList {
  public:
-  explicit ProfileListDesktop(ProfileInfoInterface* profile_cache);
+  explicit ProfileListDesktop(ProfileAttributesStorage* profile_storage);
   ~ProfileListDesktop() override;
 
+ private:
   // ProfileList overrides:
   size_t GetNumberOfItems() const override;
   const AvatarMenu::Item& GetItemAt(size_t index) const override;
   void RebuildMenu() override;
-  // Returns the menu index of the profile at |index| in the ProfileInfoCache.
-  // The profile index must exist, and it may not be marked as omitted from the
-  // menu.
-  size_t MenuIndexFromProfileIndex(size_t index) override;
-  void ActiveProfilePathChanged(base::FilePath& path) override;
+  // Returns the menu index of the profile with |path| in the
+  // ProfileAttributesStorage. The profile with the |path| must exist, and it
+  // may not be marked as omitted from the menu.
+  size_t MenuIndexFromProfilePath(const base::FilePath& path) const override;
+  void ActiveProfilePathChanged(
+      const base::FilePath& active_profile_path) override;
 
- private:
-  void ClearMenu();
-
-  // The cache that provides the profile information. Weak.
-  ProfileInfoInterface* profile_info_;
+  // The storage that provides the profile attributes. Not owned.
+  ProfileAttributesStorage* profile_storage_;
 
   // The path of the currently active profile.
   base::FilePath active_profile_path_;
 
   // List of built "menu items."
-  std::vector<AvatarMenu::Item*> items_;
-
-  // The number of profiles that were omitted from the list when it was built.
-  size_t omitted_item_count_;
+  std::vector<scoped_ptr<AvatarMenu::Item>> items_;
 
   DISALLOW_COPY_AND_ASSIGN(ProfileListDesktop);
 };
diff --git a/chrome/browser/profiles/profile_list_desktop_browsertest.cc b/chrome/browser/profiles/profile_list_desktop_browsertest.cc
index 89458355..3303bc2 100644
--- a/chrome/browser/profiles/profile_list_desktop_browsertest.cc
+++ b/chrome/browser/profiles/profile_list_desktop_browsertest.cc
@@ -63,26 +63,27 @@
 
   ProfileManager* profile_manager = g_browser_process->profile_manager();
   Profile* current_profile = browser()->profile();
-  ProfileInfoCache& cache = profile_manager->GetProfileInfoCache();
   ProfileAttributesStorage& storage =
       profile_manager->GetProfileAttributesStorage();
-  size_t index = cache.GetIndexOfProfileWithPath(current_profile->GetPath());
+  ProfileAttributesEntry* entry;
+  ASSERT_TRUE(storage.GetProfileAttributesWithPath(current_profile->GetPath(),
+                                                   &entry));
 
   scoped_ptr<AvatarMenu> menu = CreateAvatarMenu(&storage);
   menu->RebuildMenu();
 
   BrowserList* browser_list = BrowserList::GetInstance();
-  EXPECT_EQ(1U, browser_list->size());
+  EXPECT_EQ(1u, browser_list->size());
   content::WindowedNotificationObserver window_close_observer(
       chrome::NOTIFICATION_BROWSER_CLOSED,
       content::Source<Browser>(browser()));
 
-  EXPECT_FALSE(cache.ProfileIsSigninRequiredAtIndex(index));
+  EXPECT_FALSE(entry->IsSigninRequired());
   profiles::LockProfile(current_profile);
   window_close_observer.Wait();  // rely on test time-out for failure indication
 
-  EXPECT_TRUE(cache.ProfileIsSigninRequiredAtIndex(index));
-  EXPECT_EQ(0U, browser_list->size());
+  EXPECT_TRUE(entry->IsSigninRequired());
+  EXPECT_EQ(0u, browser_list->size());
 
   // Signing out brings up the User Manager which we should close before exit.
   UserManager::Hide();
@@ -99,23 +100,21 @@
 #if defined(OS_WIN) && defined(USE_ASH)
   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kAshBrowserTests))
+          switches::kAshBrowserTests)) {
     return;
+  }
 #endif
 
   if (!profiles::IsMultipleProfilesEnabled())
     return;
 
   ProfileManager* profile_manager = g_browser_process->profile_manager();
-  Profile* current_profile = browser()->profile();
-  ProfileInfoCache& cache = profile_manager->GetProfileInfoCache();
   ProfileAttributesStorage& storage =
       profile_manager->GetProfileAttributesStorage();
-  base::FilePath path_profile1 = current_profile->GetPath();
-  base::FilePath user_dir = cache.GetUserDataDir();
+  base::FilePath path_profile1 = browser()->profile()->GetPath();
 
   // Create an additional profile.
-  base::FilePath path_profile2 = user_dir.Append(
+  base::FilePath path_profile2 = profile_manager->user_data_dir().Append(
       FILE_PATH_LITERAL("New Profile 2"));
   profile_manager->CreateProfileAsync(path_profile2,
                                       base::Bind(&OnUnblockOnProfileCreation),
@@ -125,29 +124,29 @@
   // Spin to allow profile creation to take place, loop is terminated
   // by OnUnblockOnProfileCreation when the profile is created.
   content::RunMessageLoop();
-  ASSERT_EQ(cache.GetNumberOfProfiles(), 2U);
+  ASSERT_EQ(2u, storage.GetNumberOfProfiles());
 
   scoped_ptr<AvatarMenu> menu = CreateAvatarMenu(&storage);
   menu->RebuildMenu();
   BrowserList* browser_list = BrowserList::GetInstance();
-  EXPECT_EQ(1U, browser_list->size());
+  EXPECT_EQ(1u, browser_list->size());
   EXPECT_EQ(path_profile1, browser_list->get(0)->profile()->GetPath());
 
   // Open a browser window for the first profile.
-  menu->SwitchToProfile(cache.GetIndexOfProfileWithPath(path_profile1),
+  menu->SwitchToProfile(menu->GetIndexOfItemWithProfilePath(path_profile1),
                         false, ProfileMetrics::SWITCH_PROFILE_ICON);
-  EXPECT_EQ(1U, browser_list->size());
+  EXPECT_EQ(1u, browser_list->size());
   EXPECT_EQ(path_profile1, browser_list->get(0)->profile()->GetPath());
 
   // Open a browser window for the second profile.
-  menu->SwitchToProfile(cache.GetIndexOfProfileWithPath(path_profile2),
+  menu->SwitchToProfile(menu->GetIndexOfItemWithProfilePath(path_profile2),
                         false, ProfileMetrics::SWITCH_PROFILE_ICON);
-  EXPECT_EQ(2U, browser_list->size());
+  EXPECT_EQ(2u, browser_list->size());
 
   // Switch to the first profile without opening a new window.
-  menu->SwitchToProfile(cache.GetIndexOfProfileWithPath(path_profile1),
+  menu->SwitchToProfile(menu->GetIndexOfItemWithProfilePath(path_profile1),
                         false, ProfileMetrics::SWITCH_PROFILE_ICON);
-  EXPECT_EQ(2U, browser_list->size());
+  EXPECT_EQ(2u, browser_list->size());
   EXPECT_EQ(path_profile1, browser_list->get(0)->profile()->GetPath());
   EXPECT_EQ(path_profile2, browser_list->get(1)->profile()->GetPath());
 }
diff --git a/chrome/browser/profiles/profile_list_desktop_unittest.cc b/chrome/browser/profiles/profile_list_desktop_unittest.cc
index 640f891a..a873d01 100644
--- a/chrome/browser/profiles/profile_list_desktop_unittest.cc
+++ b/chrome/browser/profiles/profile_list_desktop_unittest.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/profiles/profile_list_desktop.h"
 
 #include <string>
+#include <vector>
 
 #include "base/command_line.h"
 #include "base/macros.h"
@@ -14,10 +15,13 @@
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "chrome/browser/profiles/avatar_menu_observer.h"
-#include "chrome/browser/profiles/profile_info_cache.h"
+#include "chrome/browser/profiles/profile_attributes_entry.h"
+#include "chrome/browser/profiles/profile_attributes_storage.h"
+#include "chrome/browser/profiles/profile_list.h"
 #include "chrome/browser/profiles/profiles_state.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/testing_browser_process.h"
+#include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/testing_profile_manager.h"
 #include "components/signin/core/common/profile_management_switches.h"
 #include "components/syncable_prefs/pref_service_syncable.h"
@@ -76,10 +80,9 @@
   TestingProfileManager* manager() { return &manager_; }
 
   void AddOmittedProfile(const std::string& name) {
-    ProfileInfoCache* cache = manager()->profile_info_cache();
-    cache->AddProfileToCache(
-        cache->GetUserDataDir().AppendASCII(name), ASCIIToUTF16(name),
-        std::string(), base::string16(), 0, "TEST_ID");
+    ProfileAttributesStorage* storage = manager()->profile_attributes_storage();
+    storage->AddProfile(manager()->profiles_dir().AppendASCII(name),
+      ASCIIToUTF16(name), std::string(), base::string16(), 0, "TEST_ID");
   }
 
   int change_count() const { return mock_observer_->change_count(); }
@@ -97,109 +100,99 @@
   manager()->CreateTestingProfile("Test 1");
   manager()->CreateTestingProfile("Test 2");
 
-  AvatarMenu* model = GetAvatarMenu();
+  AvatarMenu* menu = GetAvatarMenu();
   EXPECT_EQ(0, change_count());
 
-  ASSERT_EQ(2U, model->GetNumberOfItems());
+  ASSERT_EQ(2U, menu->GetNumberOfItems());
 
-  const AvatarMenu::Item& item1 = model->GetItemAt(0);
+  const AvatarMenu::Item& item1 = menu->GetItemAt(0);
   EXPECT_EQ(0U, item1.menu_index);
   EXPECT_EQ(ASCIIToUTF16("Test 1"), item1.name);
 
-  const AvatarMenu::Item& item2 = model->GetItemAt(1);
+  const AvatarMenu::Item& item2 = menu->GetItemAt(1);
   EXPECT_EQ(1U, item2.menu_index);
   EXPECT_EQ(ASCIIToUTF16("Test 2"), item2.name);
 }
 
 TEST_F(ProfileListDesktopTest, NoOmittedProfiles) {
-  ProfileListDesktop profile_list(manager()->profile_info_cache());
+  ProfileListDesktop
+      profile_list_desktop(manager()->profile_attributes_storage());
+  ProfileList* profile_list = &profile_list_desktop;
 
   // Profiles are stored and listed alphabetically.
-  manager()->CreateTestingProfile("1 included");
-  manager()->CreateTestingProfile("2 included");
-  manager()->CreateTestingProfile("3 included");
-  manager()->CreateTestingProfile("4 included");
+  std::vector<std::string> profile_names = {"0 included",
+                                            "1 included",
+                                            "2 included",
+                                            "3 included"};
+  size_t profile_count = profile_names.size();
 
-  profile_list.RebuildMenu();
-  ASSERT_EQ(4u, profile_list.GetNumberOfItems());
+  // Add the profiles.
+  for (const std::string profile_name : profile_names)
+    manager()->CreateTestingProfile(profile_name);
 
-  const AvatarMenu::Item& item1 = profile_list.GetItemAt(0);
-  EXPECT_EQ(0u, item1.menu_index);
-  EXPECT_EQ(0u, item1.profile_index);
-  EXPECT_EQ(ASCIIToUTF16("1 included"), item1.name);
+  // Rebuild avatar menu.
+  profile_list->RebuildMenu();
+  ASSERT_EQ(profile_count, profile_list->GetNumberOfItems());
 
-  const AvatarMenu::Item& item2 = profile_list.GetItemAt(1);
-  EXPECT_EQ(1u, item2.menu_index);
-  EXPECT_EQ(1u, item2.profile_index);
-  EXPECT_EQ(ASCIIToUTF16("2 included"), item2.name);
-
-  const AvatarMenu::Item& item3 = profile_list.GetItemAt(2);
-  EXPECT_EQ(2u, item3.menu_index);
-  EXPECT_EQ(2u, item3.profile_index);
-  EXPECT_EQ(ASCIIToUTF16("3 included"), item3.name);
-
-  const AvatarMenu::Item& item4 = profile_list.GetItemAt(3);
-  EXPECT_EQ(3u, item4.menu_index);
-  EXPECT_EQ(3u, item4.profile_index);
-  EXPECT_EQ(ASCIIToUTF16("4 included"), item4.name);
-
-  EXPECT_EQ(0u, profile_list.MenuIndexFromProfileIndex(0));
-  EXPECT_EQ(1u, profile_list.MenuIndexFromProfileIndex(1));
-  EXPECT_EQ(2u, profile_list.MenuIndexFromProfileIndex(2));
-  EXPECT_EQ(3u, profile_list.MenuIndexFromProfileIndex(3));
+  // Verify contents in avatar menu.
+  for (size_t i = 0u; i < profile_count; ++i) {
+    const AvatarMenu::Item& item = profile_list->GetItemAt(i);
+    EXPECT_EQ(i, item.menu_index);
+    EXPECT_EQ(ASCIIToUTF16(profile_names[i]), item.name);
+    EXPECT_EQ(i, profile_list->MenuIndexFromProfilePath(item.profile_path));
+  }
 }
 
 TEST_F(ProfileListDesktopTest, WithOmittedProfiles) {
-  ProfileListDesktop profile_list(manager()->profile_info_cache());
+  ProfileListDesktop
+      profile_list_desktop(manager()->profile_attributes_storage());
+  ProfileList* profile_list = &profile_list_desktop;
 
   // Profiles are stored and listed alphabetically.
-  AddOmittedProfile("0 omitted");
-  manager()->CreateTestingProfile("1 included");
-  AddOmittedProfile("2 omitted");
-  manager()->CreateTestingProfile("3 included");
-  manager()->CreateTestingProfile("4 included");
-  AddOmittedProfile("5 omitted");
-  manager()->CreateTestingProfile("6 included");
-  AddOmittedProfile("7 omitted");
+  std::vector<std::string> profile_names = {"0 omitted",
+                                            "1 included",
+                                            "2 omitted",
+                                            "3 included",
+                                            "4 included",
+                                            "5 omitted",
+                                            "6 included",
+                                            "7 omitted"};
 
-  profile_list.RebuildMenu();
-  ASSERT_EQ(4u, profile_list.GetNumberOfItems());
+  // Add the profiles.
+  std::vector<size_t> included_profile_indices;
+  for (size_t i = 0u; i < profile_names.size(); ++i) {
+    if (profile_names[i].find("included") != std::string::npos) {
+      manager()->CreateTestingProfile(profile_names[i]);
+      included_profile_indices.push_back(i);
+    } else {
+      AddOmittedProfile(profile_names[i]);
+    }
+  }
 
-  const AvatarMenu::Item& item1 = profile_list.GetItemAt(0);
-  EXPECT_EQ(0u, item1.menu_index);
-  EXPECT_EQ(1u, item1.profile_index);
-  EXPECT_EQ(ASCIIToUTF16("1 included"), item1.name);
+  // Rebuild avatar menu.
+  size_t included_profile_count = included_profile_indices.size();
+  profile_list->RebuildMenu();
+  ASSERT_EQ(included_profile_count, profile_list->GetNumberOfItems());
 
-  const AvatarMenu::Item& item2 = profile_list.GetItemAt(1);
-  EXPECT_EQ(1u, item2.menu_index);
-  EXPECT_EQ(3u, item2.profile_index);
-  EXPECT_EQ(ASCIIToUTF16("3 included"), item2.name);
-
-  const AvatarMenu::Item& item3 = profile_list.GetItemAt(2);
-  EXPECT_EQ(2u, item3.menu_index);
-  EXPECT_EQ(4u, item3.profile_index);
-  EXPECT_EQ(ASCIIToUTF16("4 included"), item3.name);
-
-  const AvatarMenu::Item& item4 = profile_list.GetItemAt(3);
-  EXPECT_EQ(3u, item4.menu_index);
-  EXPECT_EQ(6u, item4.profile_index);
-  EXPECT_EQ(ASCIIToUTF16("6 included"), item4.name);
-
-  EXPECT_EQ(0u, profile_list.MenuIndexFromProfileIndex(1));
-  EXPECT_EQ(1u, profile_list.MenuIndexFromProfileIndex(3));
-  EXPECT_EQ(2u, profile_list.MenuIndexFromProfileIndex(4));
-  EXPECT_EQ(3u, profile_list.MenuIndexFromProfileIndex(6));
+  // Verify contents in avatar menu.
+  for (size_t i = 0u; i < included_profile_count; ++i) {
+    const AvatarMenu::Item& item = profile_list->GetItemAt(i);
+    EXPECT_EQ(i, item.menu_index);
+    EXPECT_EQ(ASCIIToUTF16(profile_names[included_profile_indices[i]]),
+              item.name);
+    EXPECT_EQ(i, profile_list->MenuIndexFromProfilePath(item.profile_path));
+  }
 }
 
 TEST_F(ProfileListDesktopTest, ActiveItem) {
   manager()->CreateTestingProfile("Test 1");
   manager()->CreateTestingProfile("Test 2");
 
-  AvatarMenu* model = GetAvatarMenu();
-  ASSERT_EQ(2U, model->GetNumberOfItems());
+  AvatarMenu* menu = GetAvatarMenu();
+  ASSERT_EQ(2u, menu->GetNumberOfItems());
   // TODO(jeremy): Expand test to verify active profile index other than 0
   // crbug.com/100871
-  ASSERT_EQ(0U, model->GetActiveProfileIndex());
+  ASSERT_EQ(0u, menu->GetActiveProfileIndex());
 }
 
 TEST_F(ProfileListDesktopTest, ModifyingNameResortsCorrectly) {
@@ -207,33 +200,37 @@
   std::string name2("Beta");
   std::string newname1("Gamma");
 
-  manager()->CreateTestingProfile(name1);
+  TestingProfile* profile1 = manager()->CreateTestingProfile(name1);
   manager()->CreateTestingProfile(name2);
 
-  AvatarMenu* model = GetAvatarMenu();
+  AvatarMenu* menu = GetAvatarMenu();
   EXPECT_EQ(0, change_count());
 
-  ASSERT_EQ(2U, model->GetNumberOfItems());
+  ASSERT_EQ(2u, menu->GetNumberOfItems());
 
-  const AvatarMenu::Item& item1 = model->GetItemAt(0);
-  EXPECT_EQ(0U, item1.menu_index);
+  const AvatarMenu::Item& item1 = menu->GetItemAt(0u);
+  EXPECT_EQ(0u, item1.menu_index);
   EXPECT_EQ(ASCIIToUTF16(name1), item1.name);
 
-  const AvatarMenu::Item& item2 = model->GetItemAt(1);
-  EXPECT_EQ(1U, item2.menu_index);
+  const AvatarMenu::Item& item2 = menu->GetItemAt(1u);
+  EXPECT_EQ(1u, item2.menu_index);
   EXPECT_EQ(ASCIIToUTF16(name2), item2.name);
 
-  // Change name of the first profile, to trigger resorting of the profiles:
-  // now the first model should be named "beta", and the second be "gamma".
-  manager()->profile_info_cache()->SetNameOfProfileAtIndex(0,
-        ASCIIToUTF16(newname1));
-  const AvatarMenu::Item& item1next = model->GetItemAt(0);
+  // Change the name of the first profile, and this triggers the resorting of
+  // the avatar menu.
+  ProfileAttributesEntry* entry;
+  ASSERT_TRUE(manager()->profile_attributes_storage()->
+                  GetProfileAttributesWithPath(profile1->GetPath(), &entry));
+  entry->SetName(ASCIIToUTF16(newname1));
   EXPECT_EQ(1, change_count());
-  EXPECT_EQ(0U, item1next.menu_index);
+
+  // Now the first menu item should be named "beta", and the second be "gamma".
+  const AvatarMenu::Item& item1next = menu->GetItemAt(0u);
+  EXPECT_EQ(0u, item1next.menu_index);
   EXPECT_EQ(ASCIIToUTF16(name2), item1next.name);
 
-  const AvatarMenu::Item& item2next = model->GetItemAt(1);
-  EXPECT_EQ(1U, item2next.menu_index);
+  const AvatarMenu::Item& item2next = menu->GetItemAt(1u);
+  EXPECT_EQ(1u, item2next.menu_index);
   EXPECT_EQ(ASCIIToUTF16(newname1), item2next.name);
 }
 
@@ -241,30 +238,30 @@
   manager()->CreateTestingProfile("Test 1");
   manager()->CreateTestingProfile("Test 2");
 
-  AvatarMenu* model = GetAvatarMenu();
+  AvatarMenu* menu = GetAvatarMenu();
   EXPECT_EQ(0, change_count());
-  EXPECT_EQ(2U, model->GetNumberOfItems());
+  EXPECT_EQ(2u, menu->GetNumberOfItems());
 
   manager()->CreateTestingProfile("Test 3");
 
   // Three changes happened via the call to CreateTestingProfile: adding the
-  // profile to the cache, setting the user name (which rebuilds the list of
-  // profiles after the name change) and changing the avatar.
+  // profile to the attributes storage, setting the user name (which rebuilds
+  // the list of profiles after the name change) and changing the avatar.
   // On Windows, an extra change happens to set the shortcut name for the
   // profile.
   EXPECT_GE(3, change_count());
-  ASSERT_EQ(3U, model->GetNumberOfItems());
+  ASSERT_EQ(3u, menu->GetNumberOfItems());
 
-  const AvatarMenu::Item& item1 = model->GetItemAt(0);
-  EXPECT_EQ(0U, item1.menu_index);
+  const AvatarMenu::Item& item1 = menu->GetItemAt(0u);
+  EXPECT_EQ(0u, item1.menu_index);
   EXPECT_EQ(ASCIIToUTF16("Test 1"), item1.name);
 
-  const AvatarMenu::Item& item2 = model->GetItemAt(1);
-  EXPECT_EQ(1U, item2.menu_index);
+  const AvatarMenu::Item& item2 = menu->GetItemAt(1u);
+  EXPECT_EQ(1u, item2.menu_index);
   EXPECT_EQ(ASCIIToUTF16("Test 2"), item2.name);
 
-  const AvatarMenu::Item& item3 = model->GetItemAt(2);
-  EXPECT_EQ(2U, item3.menu_index);
+  const AvatarMenu::Item& item3 = menu->GetItemAt(2u);
+  EXPECT_EQ(2u, item3.menu_index);
   EXPECT_EQ(ASCIIToUTF16("Test 3"), item3.name);
 }
 
@@ -307,25 +304,27 @@
   manager()->CreateTestingProfile("Test 1");
 
   // Add a managed user profile.
-  ProfileInfoCache* cache = manager()->profile_info_cache();
-  base::FilePath path = cache->GetUserDataDir().AppendASCII("p2");
-  cache->AddProfileToCache(path, ASCIIToUTF16("Test 2"), std::string(),
-                           base::string16(), 0, "TEST_ID");
-  cache->SetIsOmittedProfileAtIndex(cache->GetIndexOfProfileWithPath(path),
-                                    false);
+  ProfileAttributesStorage* storage = manager()->profile_attributes_storage();
+  base::FilePath path = manager()->profiles_dir().AppendASCII("p2");
+  storage->AddProfile(path, ASCIIToUTF16("Test 2"), std::string(),
+                      base::string16(), 0u, "TEST_ID");
 
-  AvatarMenu* model = GetAvatarMenu();
-  model->RebuildMenu();
-  EXPECT_EQ(2U, model->GetNumberOfItems());
+  ProfileAttributesEntry* entry;
+  ASSERT_TRUE(storage->GetProfileAttributesWithPath(path, &entry));
+  entry->SetIsOmitted(false);
+
+  AvatarMenu* menu = GetAvatarMenu();
+  menu->RebuildMenu();
+  EXPECT_EQ(2u, menu->GetNumberOfItems());
 
   // Now check that the username of a supervised user shows the supervised
   // user avatar label instead.
   base::string16 supervised_user_label =
       l10n_util::GetStringUTF16(IDS_LEGACY_SUPERVISED_USER_AVATAR_LABEL);
-  const AvatarMenu::Item& item1 = model->GetItemAt(0);
+  const AvatarMenu::Item& item1 = menu->GetItemAt(0u);
   EXPECT_NE(item1.username, supervised_user_label);
 
-  const AvatarMenu::Item& item2 = model->GetItemAt(1);
+  const AvatarMenu::Item& item2 = menu->GetItemAt(1u);
   EXPECT_EQ(item2.username, supervised_user_label);
 }
 
diff --git a/chrome/browser/resources/local_ntp/most_visited_single.js b/chrome/browser/resources/local_ntp/most_visited_single.js
index d6a1d5c..5a7350ac7 100644
--- a/chrome/browser/resources/local_ntp/most_visited_single.js
+++ b/chrome/browser/resources/local_ntp/most_visited_single.js
@@ -271,15 +271,7 @@
   tiles = document.createElement('div');
 
   if (impressionUrl) {
-    if (navigator.sendBeacon) {
-      navigator.sendBeacon(impressionUrl);
-    } else {
-      // if sendBeacon is not enabled, we fallback to "a ping".
-      var a = document.createElement('a');
-      a.href = '#';
-      a.ping = impressionUrl;
-      a.click();
-    }
+    navigator.sendBeacon(impressionUrl);
     impressionUrl = null;
   }
 };
@@ -327,6 +319,17 @@
 
 
 /**
+ * Returns whether the given URL has a known, safe scheme.
+ * @param {string} url URL to check.
+ */
+var isSchemeAllowed = function(url) {
+  return url.startsWith('http://') || url.startsWith('https://') ||
+         url.startsWith('ftp://') || url.startsWith('file://') ||
+         url.startsWith('chrome-extension://');
+};
+
+
+/**
  * Renders a MostVisited tile to the DOM.
  * @param {object} data Object containing rid, url, title, favicon, thumbnail.
  *     data is null if you want to construct an empty tile.
@@ -343,31 +346,25 @@
 
   tile.className = 'mv-tile';
   tile.setAttribute('data-tid', data.tid);
-  var tooltip = queryArgs['removeTooltip'] || '';
   var html = [];
   if (!USE_ICONS) {
     html.push('<div class="mv-favicon"></div>');
   }
   html.push('<div class="mv-title"></div><div class="mv-thumb"></div>');
-  html.push('<div title="' + tooltip + '" class="mv-x"></div>');
+  html.push('<div class="mv-x"></div>');
   tile.innerHTML = html.join('');
+  tile.lastElementChild.title = queryArgs['removeTooltip'] || '';
 
-  tile.href = data.url;
+  if (isSchemeAllowed(data.url)) {
+    tile.href = data.url;
+  }
   tile.title = data.title;
   if (data.impressionUrl) {
     impressionUrl = data.impressionUrl;
   }
   if (data.pingUrl) {
     tile.addEventListener('click', function(ev) {
-      if (navigator.sendBeacon) {
-        navigator.sendBeacon(data.pingUrl);
-      } else {
-        // if sendBeacon is not enabled, we fallback to "a ping".
-        var a = document.createElement('a');
-        a.href = '#';
-        a.ping = data.pingUrl;
-        a.click();
-      }
+      navigator.sendBeacon(data.pingUrl);
     });
   }
   // For local suggestions, we use navigateContentWindow instead of the default
diff --git a/chrome/browser/search/instant_service.cc b/chrome/browser/search/instant_service.cc
index fd75e1d..1089c78 100644
--- a/chrome/browser/search/instant_service.cc
+++ b/chrome/browser/search/instant_service.cc
@@ -22,7 +22,6 @@
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/search/suggestions/suggestions_service_factory.h"
 #include "chrome/browser/search/suggestions/suggestions_source.h"
-#include "chrome/browser/search/suggestions/suggestions_utils.h"
 #include "chrome/browser/search/thumbnail_source.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/search_engines/ui_thread_search_terms_data.h"
@@ -184,10 +183,11 @@
   }
 
   if (suggestions_service_) {
-    suggestions_service_->FetchSuggestionsData(
-        suggestions::GetSyncState(profile_),
+    suggestions_subscription_ = suggestions_service_->AddCallback(
         base::Bind(&InstantService::OnSuggestionsAvailable,
-                   weak_ptr_factory_.GetWeakPtr()));
+                   base::Unretained(this)));
+    suggestions_service_->FetchSuggestionsData();
+    // TODO(treib): Also re-fetch suggestions on local NTP loads.
   }
 }
 
@@ -225,12 +225,8 @@
   if (top_sites)
     top_sites->AddBlacklistedURL(url);
 
-  if (suggestions_service_) {
-    suggestions_service_->BlacklistURL(
-        url, base::Bind(&InstantService::OnSuggestionsAvailable,
-                        weak_ptr_factory_.GetWeakPtr()),
-        base::Closure());
-  }
+  if (suggestions_service_)
+    suggestions_service_->BlacklistURL(url);
 }
 
 void InstantService::UndoMostVisitedDeletion(const GURL& url) {
@@ -239,12 +235,8 @@
   if (top_sites)
     top_sites->RemoveBlacklistedURL(url);
 
-  if (suggestions_service_) {
-    suggestions_service_->UndoBlacklistURL(
-        url, base::Bind(&InstantService::OnSuggestionsAvailable,
-                        weak_ptr_factory_.GetWeakPtr()),
-        base::Closure());
-  }
+  if (suggestions_service_)
+    suggestions_service_->UndoBlacklistURL(url);
 }
 
 void InstantService::UndoAllMostVisitedDeletions() {
@@ -253,11 +245,8 @@
   if (top_sites)
     top_sites->ClearBlacklistedURLs();
 
-  if (suggestions_service_) {
-    suggestions_service_->ClearBlacklist(
-        base::Bind(&InstantService::OnSuggestionsAvailable,
-                   weak_ptr_factory_.GetWeakPtr()));
-  }
+  if (suggestions_service_)
+    suggestions_service_->ClearBlacklist();
 }
 
 void InstantService::UpdateThemeInfo() {
diff --git a/chrome/browser/search/instant_service.h b/chrome/browser/search/instant_service.h
index 49f37d3..dccf4e7c 100644
--- a/chrome/browser/search/instant_service.h
+++ b/chrome/browser/search/instant_service.h
@@ -10,6 +10,7 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "components/history/core/browser/history_types.h"
@@ -184,6 +185,11 @@
   // Suggestions Service to fetch server suggestions.
   suggestions::SuggestionsService* suggestions_service_;
 
+  // Subscription to the SuggestionsService.
+  scoped_ptr<
+      suggestions::SuggestionsService::ResponseCallbackList::Subscription>
+      suggestions_subscription_;
+
   // Used for Top Sites async retrieval.
   base::WeakPtrFactory<InstantService> weak_ptr_factory_;
 
diff --git a/chrome/browser/search/instant_service_factory.cc b/chrome/browser/search/instant_service_factory.cc
index efd98a9..6cc76f3 100644
--- a/chrome/browser/search/instant_service_factory.cc
+++ b/chrome/browser/search/instant_service_factory.cc
@@ -8,6 +8,7 @@
 #include "chrome/browser/profiles/incognito_helpers.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search/instant_service.h"
+#include "chrome/browser/search/suggestions/suggestions_service_factory.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
@@ -31,6 +32,7 @@
     : BrowserContextKeyedServiceFactory(
         "InstantService",
         BrowserContextDependencyManager::GetInstance()) {
+  DependsOn(suggestions::SuggestionsServiceFactory::GetInstance());
   DependsOn(TemplateURLServiceFactory::GetInstance());
 #if defined(ENABLE_THEMES)
   DependsOn(ThemeServiceFactory::GetInstance());
diff --git a/chrome/browser/search/suggestions/suggestions_service_factory.cc b/chrome/browser/search/suggestions/suggestions_service_factory.cc
index 5ca5f909..4edfcfa4 100644
--- a/chrome/browser/search/suggestions/suggestions_service_factory.cc
+++ b/chrome/browser/search/suggestions/suggestions_service_factory.cc
@@ -12,6 +12,8 @@
 #include "chrome/browser/search/suggestions/image_fetcher_impl.h"
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/browser/sync/profile_sync_service_factory.h"
+#include "components/browser_sync/browser/profile_sync_service.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/leveldb_proto/proto_database.h"
 #include "components/leveldb_proto/proto_database_impl.h"
@@ -49,42 +51,45 @@
           BrowserContextDependencyManager::GetInstance()) {
   DependsOn(SigninManagerFactory::GetInstance());
   DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance());
+  DependsOn(ProfileSyncServiceFactory::GetInstance());
 }
 
 SuggestionsServiceFactory::~SuggestionsServiceFactory() {}
 
 KeyedService* SuggestionsServiceFactory::BuildServiceInstanceFor(
-    content::BrowserContext* profile) const {
+    content::BrowserContext* context) const {
   scoped_refptr<base::SequencedTaskRunner> background_task_runner =
       BrowserThread::GetBlockingPool()->GetSequencedTaskRunner(
           base::SequencedWorkerPool::GetSequenceToken());
 
-  Profile* the_profile = static_cast<Profile*>(profile);
+  Profile* profile = static_cast<Profile*>(context);
 
   SigninManagerBase* signin_manager =
-      SigninManagerFactory::GetForProfile(the_profile);
+      SigninManagerFactory::GetForProfile(profile);
   ProfileOAuth2TokenService* token_service =
-      ProfileOAuth2TokenServiceFactory::GetForProfile(the_profile);
+      ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
+  ProfileSyncService* sync_service =
+      ProfileSyncServiceFactory::GetForProfile(profile);
 
   scoped_ptr<SuggestionsStore> suggestions_store(
-      new SuggestionsStore(the_profile->GetPrefs()));
+      new SuggestionsStore(profile->GetPrefs()));
   scoped_ptr<BlacklistStore> blacklist_store(
-      new BlacklistStore(the_profile->GetPrefs()));
+      new BlacklistStore(profile->GetPrefs()));
 
   scoped_ptr<leveldb_proto::ProtoDatabaseImpl<ImageData> > db(
       new leveldb_proto::ProtoDatabaseImpl<ImageData>(background_task_runner));
 
   base::FilePath database_dir(
-      the_profile->GetPath().Append(FILE_PATH_LITERAL("Thumbnails")));
+      profile->GetPath().Append(FILE_PATH_LITERAL("Thumbnails")));
 
   scoped_ptr<ImageFetcherImpl> image_fetcher(
-      new ImageFetcherImpl(the_profile->GetRequestContext()));
+      new ImageFetcherImpl(profile->GetRequestContext()));
   scoped_ptr<ImageManager> thumbnail_manager(
       new ImageManager(
           std::move(image_fetcher), std::move(db), database_dir,
           BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB)));
   return new SuggestionsService(
-      signin_manager, token_service, the_profile->GetRequestContext(),
+      signin_manager, token_service, sync_service, profile->GetRequestContext(),
       std::move(suggestions_store), std::move(thumbnail_manager),
       std::move(blacklist_store));
 }
diff --git a/chrome/browser/search/suggestions/suggestions_source.cc b/chrome/browser/search/suggestions/suggestions_source.cc
index 1442a5a..292c745 100644
--- a/chrome/browser/search/suggestions/suggestions_source.cc
+++ b/chrome/browser/search/suggestions/suggestions_source.cc
@@ -24,7 +24,6 @@
 #include "chrome/browser/search/suggestions/suggestions_service_factory.h"
 #include "chrome/common/url_constants.h"
 #include "components/suggestions/suggestions_service.h"
-#include "components/suggestions/suggestions_utils.h"
 #include "net/base/escape.h"
 #include "ui/base/l10n/time_format.h"
 #include "ui/gfx/codec/png_codec.h"
@@ -121,18 +120,9 @@
     const content::URLDataSource::GotDataCallback& callback) {
   SuggestionsService* suggestions_service =
       SuggestionsServiceFactory::GetForProfile(profile_);
-
-  if (!suggestions_service) {
-    callback.Run(NULL);
-    return;
-  }
-
-  // Since it's a debugging page, it's fine to specify that sync state is
-  // initialized.
-  suggestions_service->FetchSuggestionsData(
-      INITIALIZED_ENABLED_HISTORY,
-      base::Bind(&SuggestionsSource::OnSuggestionsAvailable,
-                 weak_ptr_factory_.GetWeakPtr(), callback));
+  OnSuggestionsAvailable(callback,
+                         suggestions_service->GetSuggestionsDataFromCache());
+  suggestions_service->FetchSuggestionsData();
 }
 
 std::string SuggestionsSource::GetMimeType(const std::string& path) const {
diff --git a/chrome/browser/search/suggestions/suggestions_utils.cc b/chrome/browser/search/suggestions/suggestions_utils.cc
deleted file mode 100644
index b012e39..0000000
--- a/chrome/browser/search/suggestions/suggestions_utils.cc
+++ /dev/null
@@ -1,23 +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/search/suggestions/suggestions_utils.h"
-
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/sync/profile_sync_service_factory.h"
-#include "components/browser_sync/browser/profile_sync_service.h"
-
-namespace suggestions {
-
-SyncState GetSyncState(Profile* profile) {
-  ProfileSyncService* sync =
-      ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile);
-  if (!sync)
-    return SyncState::SYNC_OR_HISTORY_SYNC_DISABLED;
-  return GetSyncState(
-      sync->CanSyncStart(), sync->IsSyncActive() && sync->ConfigurationDone(),
-      sync->GetActiveDataTypes().Has(syncer::HISTORY_DELETE_DIRECTIVES));
-}
-
-}  // namespace suggestions
diff --git a/chrome/browser/search/suggestions/suggestions_utils.h b/chrome/browser/search/suggestions/suggestions_utils.h
deleted file mode 100644
index f5a58f5..0000000
--- a/chrome/browser/search/suggestions/suggestions_utils.h
+++ /dev/null
@@ -1,19 +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_SEARCH_SUGGESTIONS_SUGGESTIONS_UTILS_H_
-#define CHROME_BROWSER_SEARCH_SUGGESTIONS_SUGGESTIONS_UTILS_H_
-
-#include "components/suggestions/suggestions_utils.h"
-
-class Profile;
-
-namespace suggestions {
-
-// Returns the current SyncState for use with the SuggestionsService.
-SyncState GetSyncState(Profile* profile);
-
-}  // namespace suggestions
-
-#endif  // CHROME_BROWSER_SEARCH_SUGGESTIONS_SUGGESTIONS_UTILS_H_
diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc
index 2aaedad..259efd6 100644
--- a/chrome/browser/sync/test/integration/sync_test.cc
+++ b/chrome/browser/sync/test/integration/sync_test.cc
@@ -590,14 +590,18 @@
 bool SyncTest::SetupSync() {
   // Create sync profiles and clients if they haven't already been created.
   if (profiles_.empty()) {
-    if (!SetupClients())
+    if (!SetupClients()) {
       LOG(FATAL) << "SetupClients() failed.";
+      return false;
+    }
   }
 
   // Sync each of the profiles.
   for (int i = 0; i < num_clients_; ++i) {
-    if (!GetClient(i)->SetupSync())
+    if (!GetClient(i)->SetupSync()) {
       LOG(FATAL) << "SetupSync() failed.";
+      return false;
+    }
   }
 
   // Because clients may modify sync data as part of startup (for example local
@@ -608,7 +612,10 @@
   // have to find their own way of waiting for an initial state if they really
   // need such guarantees.
   if (TestUsesSelfNotifications()) {
-    AwaitQuiescence();
+    if (!AwaitQuiescence()) {
+      LOG(FATAL) << "AwaitQuiescence() failed.";
+      return false;
+    }
   }
 
   // SyncRefresher is used instead of invalidations to notify other profiles to
diff --git a/chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider.cc b/chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider.cc
index beb1fc8a..6329248 100644
--- a/chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider.cc
+++ b/chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider.cc
@@ -11,14 +11,12 @@
 #include "chrome/browser/favicon/favicon_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search/suggestions/suggestions_service_factory.h"
-#include "chrome/browser/search/suggestions/suggestions_utils.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/ui/app_list/search/suggestions/url_suggestion_result.h"
 #include "components/browser_sync/browser/profile_sync_service.h"
 #include "components/favicon/core/favicon_service.h"
 #include "components/suggestions/proto/suggestions.pb.h"
 #include "components/suggestions/suggestions_service.h"
-#include "components/suggestions/suggestions_utils.h"
 
 namespace app_list {
 
@@ -41,26 +39,13 @@
 void SuggestionsSearchProvider::Start(bool /*is_voice_query*/,
                                       const base::string16& query) {
   ClearResults();
-  // If the service is not enabled, do not return any results.
-  if (!suggestions_service_)
-    return;
 
   // Only return suggestions on an empty query.
   if (!query.empty())
     return;
 
-  // Suggestions service is enabled; initiate a query.
-  suggestions_service_->FetchSuggestionsData(
-      suggestions::GetSyncState(profile_),
-      base::Bind(&SuggestionsSearchProvider::OnSuggestionsProfileAvailable,
-                 weak_ptr_factory_.GetWeakPtr()));
-}
-
-void SuggestionsSearchProvider::Stop() {
-}
-
-void SuggestionsSearchProvider::OnSuggestionsProfileAvailable(
-    const suggestions::SuggestionsProfile& suggestions_profile) {
+  const suggestions::SuggestionsProfile& suggestions_profile =
+      suggestions_service_->GetSuggestionsDataFromCache();
   for (int i = 0; i < suggestions_profile.suggestions_size(); ++i) {
     const suggestions::ChromeSuggestion& suggestion =
         suggestions_profile.suggestions(i);
@@ -74,4 +59,7 @@
   }
 }
 
+void SuggestionsSearchProvider::Stop() {
+}
+
 }  // namespace app_list
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index cd0b0961..365ce5d 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -34,7 +34,6 @@
 #include "chrome/common/url_constants.h"
 #include "components/autofill/content/browser/content_autofill_driver.h"
 #include "components/autofill/content/common/autofill_messages.h"
-#include "components/autofill/core/browser/autofill_cc_infobar_delegate.h"
 #include "components/autofill/core/browser/ui/card_unmask_prompt_view.h"
 #include "components/autofill/core/common/autofill_pref_names.h"
 #include "components/autofill/core/common/autofill_switches.h"
diff --git a/chrome/browser/ui/cocoa/extensions/browser_action_button.h b/chrome/browser/ui/cocoa/extensions/browser_action_button.h
index cc6d0d8..bcd543e0 100644
--- a/chrome/browser/ui/cocoa/extensions/browser_action_button.h
+++ b/chrome/browser/ui/cocoa/extensions/browser_action_button.h
@@ -87,6 +87,9 @@
 // cell image drawn into it.
 - (NSImage*)compositedImage;
 
+// Shows the context menu for the action.
+- (void)showContextMenu;
+
 @property(readonly, nonatomic) BOOL isBeingDragged;
 
 @end
diff --git a/chrome/browser/ui/cocoa/extensions/browser_action_button.mm b/chrome/browser/ui/cocoa/extensions/browser_action_button.mm
index 57854f6..57ba2345 100644
--- a/chrome/browser/ui/cocoa/extensions/browser_action_button.mm
+++ b/chrome/browser/ui/cocoa/extensions/browser_action_button.mm
@@ -111,10 +111,15 @@
 }
 
 void ToolbarActionViewDelegateBridge::ShowContextMenu() {
-  // We should only be showing the context menu in this way if we're doing so
-  // for an overflowed action.
-  DCHECK(![owner_ superview]);
+  DCHECK(![controller_ toolbarActionsBar]->in_overflow_mode());
+  if ([owner_ superview]) {
+    // If the button is already visible on the toolbar, we can skip ahead to
+    // just showing the menu.
+    DoShowContextMenu();
+    return;
+  }
 
+  // Otherwise, we have to slide the button out.
   contextMenuRunning_ = true;
   AppMenuController* appMenuController =
       [[[BrowserWindowController browserWindowControllerForWindow:
@@ -127,6 +132,7 @@
 
   [controller_ toolbarActionsBar]->PopOutAction(
       viewController_,
+      false,
       base::Bind(&ToolbarActionViewDelegateBridge::DoShowContextMenu,
                  weakFactory_.GetWeakPtr()));
 }
@@ -331,21 +337,7 @@
                                fromView:nil];
   // Only perform the click if we didn't drag the button.
   if (NSPointInRect(location, [self bounds]) && !isBeingDragged_) {
-    // There's also a chance that the action is disabled, and the left click
-    // should show the context menu.
-    if (!viewController_->IsEnabled(
-            [browserActionsController_ currentWebContents]) &&
-        viewController_->DisabledClickOpensMenu()) {
-      // No menus-in-menus; see comment in -rightMouseDown:.
-      if ([browserActionsController_ isOverflow]) {
-        [browserActionsController_ mainButtonForId:viewController_->GetId()]->
-            viewControllerDelegate_->ShowContextMenu();
-      } else {
-        [NSMenu popUpContextMenu:[self menu] withEvent:theEvent forView:self];
-      }
-    } else {
-      [self performClick:self];
-    }
+    [self performClick:self];
   } else {
     // Make sure an ESC to end a drag doesn't trigger 2 endDrags.
     if (isBeingDragged_) {
@@ -489,6 +481,10 @@
   return image;
 }
 
+- (void)showContextMenu {
+  viewControllerDelegate_->ShowContextMenu();
+}
+
 - (NSMenu*)menu {
   // Hack: Since Cocoa doesn't support menus-running-in-menus (see also comment
   // in -rightMouseDown:), it doesn't launch the menu for an overflowed action
diff --git a/chrome/browser/ui/cocoa/extensions/browser_action_button_interactive_uitest.mm b/chrome/browser/ui/cocoa/extensions/browser_action_button_interactive_uitest.mm
index 03717c0..6d714d3 100644
--- a/chrome/browser/ui/cocoa/extensions/browser_action_button_interactive_uitest.mm
+++ b/chrome/browser/ui/cocoa/extensions/browser_action_button_interactive_uitest.mm
@@ -531,3 +531,60 @@
                                ui_controls::DOWN | ui_controls::UP);
   runLoop.Run();
 }
+
+// Test that activating an action that doesn't want to run on the page via the
+// mouse and the keyboard works.
+IN_PROC_BROWSER_TEST_F(BrowserActionButtonUiTest,
+                       OpenMenuOnDisabledActionWithMouseOrKeyboard) {
+  // Add an extension with a page action.
+  scoped_refptr<const extensions::Extension> extension =
+      extensions::extension_action_test_util::CreateActionExtension(
+          "page action", extensions::extension_action_test_util::PAGE_ACTION);
+  extension_service()->AddExtension(extension.get());
+  ASSERT_EQ(1u, model()->toolbar_items().size());
+
+  BrowserActionsController* actionsController =
+      [toolbarController() browserActionsController];
+  BrowserActionButton* actionButton = [actionsController buttonWithIndex:0];
+  ASSERT_TRUE(actionButton);
+
+  // Stub out the action button's normal context menu with a fake one so we
+  // can track when it opens.
+  base::scoped_nsobject<NSMenu> testContextMenu(
+      [[NSMenu alloc] initWithTitle:@""]);
+  base::scoped_nsobject<MenuHelper> menuHelper([[MenuHelper alloc] init]);
+  [testContextMenu setDelegate:menuHelper.get()];
+  [actionButton setTestContextMenu:testContextMenu.get()];
+
+  // The button should be attached.
+  EXPECT_TRUE([actionButton superview]);
+
+  // Move the mouse and click on the button. The menu should open.
+  MoveMouseToCenter(actionButton);
+  {
+    EXPECT_FALSE([menuHelper menuOpened]);
+    base::RunLoop runLoop;
+    ui_controls::SendMouseEventsNotifyWhenDone(
+        ui_controls::LEFT, ui_controls::DOWN | ui_controls::UP,
+        runLoop.QuitClosure());
+    runLoop.Run();
+    EXPECT_TRUE([menuHelper menuOpened]);
+  }
+
+  // Reset the menu helper so we can use it again.
+  [menuHelper setMenuOpened:NO];
+
+  // Send the 'space' key to the button with it as the first responder. The menu
+  // should open.
+  [[actionButton window] makeFirstResponder:actionButton];
+  EXPECT_TRUE([[actionButton window] firstResponder] == actionButton);
+  {
+    EXPECT_FALSE([menuHelper menuOpened]);
+    base::RunLoop runLoop;
+    ui_controls::SendKeyPressNotifyWhenDone([actionButton window],
+                                            ui::VKEY_SPACE, false, false, false,
+                                            false, runLoop.QuitClosure());
+    runLoop.Run();
+    EXPECT_TRUE([menuHelper menuOpened]);
+  }
+}
diff --git a/chrome/browser/ui/cocoa/extensions/extension_action_platform_delegate_cocoa.h b/chrome/browser/ui/cocoa/extensions/extension_action_platform_delegate_cocoa.h
index c82beba..a6b2ee8 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_action_platform_delegate_cocoa.h
+++ b/chrome/browser/ui/cocoa/extensions/extension_action_platform_delegate_cocoa.h
@@ -32,6 +32,7 @@
       bool grant_tab_permissions,
       ExtensionActionViewController::PopupShowAction show_action) override;
   void CloseOverflowMenu() override;
+  void ShowContextMenu() override;
 
   // content::NotificationObserver:
   void Observe(int type,
diff --git a/chrome/browser/ui/cocoa/extensions/extension_action_platform_delegate_cocoa.mm b/chrome/browser/ui/cocoa/extensions/extension_action_platform_delegate_cocoa.mm
index db8a936d..11178a5 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_action_platform_delegate_cocoa.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_action_platform_delegate_cocoa.mm
@@ -14,6 +14,7 @@
 #include "chrome/browser/ui/browser_window.h"
 #import "chrome/browser/ui/cocoa/app_menu/app_menu_controller.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#import "chrome/browser/ui/cocoa/extensions/browser_action_button.h"
 #import "chrome/browser/ui/cocoa/extensions/browser_actions_controller.h"
 #import "chrome/browser/ui/cocoa/extensions/extension_popup_controller.h"
 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
@@ -92,6 +93,20 @@
     [appMenuController cancel];
 }
 
+void ExtensionActionPlatformDelegateCocoa::ShowContextMenu() {
+  // We should only use this code path for extensions shown in the toolbar.
+  DCHECK(controller_->extension_action()->action_type() ==
+             extensions::ActionInfo::TYPE_BROWSER ||
+         extensions::FeatureSwitch::extension_action_redesign()->IsEnabled());
+  BrowserWindowController* windowController = [BrowserWindowController
+      browserWindowControllerForWindow:controller_->browser()
+                                           ->window()
+                                           ->GetNativeWindow()];
+  BrowserActionsController* actionsController =
+      [[windowController toolbarController] browserActionsController];
+  [[actionsController mainButtonForId:controller_->GetId()] showContextMenu];
+}
+
 NSPoint ExtensionActionPlatformDelegateCocoa::GetPopupPoint() const {
   BrowserWindowController* windowController =
       [BrowserWindowController browserWindowControllerForWindow:
diff --git a/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm b/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm
index 2aed5dc..9475910 100644
--- a/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm
+++ b/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm
@@ -1898,7 +1898,7 @@
       ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(
           profiles::GetPlaceholderAvatarIconResourceID());
   AvatarMenu::Item guestItem(std::string::npos, /* menu_index, not used */
-                             std::string::npos, /* profile_index, not used */
+                             base::FilePath(), /* profile_path, not used */
                              guestIcon);
   guestItem.active = true;
   guestItem.name = base::SysNSStringToUTF16(
diff --git a/chrome/browser/ui/extensions/extension_action_platform_delegate.h b/chrome/browser/ui/extensions/extension_action_platform_delegate.h
index d15405c..9fb4b261 100644
--- a/chrome/browser/ui/extensions/extension_action_platform_delegate.h
+++ b/chrome/browser/ui/extensions/extension_action_platform_delegate.h
@@ -39,6 +39,9 @@
 
   // Closes the overflow menu, if it was open.
   virtual void CloseOverflowMenu() = 0;
+
+  // Shows the context menu for the extension.
+  virtual void ShowContextMenu() = 0;
 };
 
 #endif  // CHROME_BROWSER_UI_EXTENSIONS_EXTENSION_ACTION_PLATFORM_DELEGATE_H_
diff --git a/chrome/browser/ui/extensions/extension_action_view_controller.cc b/chrome/browser/ui/extensions/extension_action_view_controller.cc
index ee58e3b0..cca14768 100644
--- a/chrome/browser/ui/extensions/extension_action_view_controller.cc
+++ b/chrome/browser/ui/extensions/extension_action_view_controller.cc
@@ -184,6 +184,15 @@
 }
 
 bool ExtensionActionViewController::ExecuteAction(bool by_user) {
+  if (!ExtensionIsValid())
+    return false;
+
+  if (!IsEnabled(view_delegate_->GetCurrentWebContents())) {
+    if (DisabledClickOpensMenu())
+      GetPreferredPopupViewController()->platform_delegate_->ShowContextMenu();
+    return false;
+  }
+
   return ExecuteAction(SHOW_POPUP, by_user);
 }
 
@@ -323,6 +332,7 @@
     platform_delegate_->CloseOverflowMenu();
     toolbar_actions_bar_->PopOutAction(
         this,
+        show_action == SHOW_POPUP_AND_INSPECT,
         base::Bind(&ExtensionActionViewController::ShowPopup,
                    weak_factory_.GetWeakPtr(), base::Passed(std::move(host)),
                    grant_tab_permissions, show_action));
diff --git a/chrome/browser/ui/extensions/extension_action_view_controller_unittest.cc b/chrome/browser/ui/extensions/extension_action_view_controller_unittest.cc
index dc33417..020dd96 100644
--- a/chrome/browser/ui/extensions/extension_action_view_controller_unittest.cc
+++ b/chrome/browser/ui/extensions/extension_action_view_controller_unittest.cc
@@ -226,6 +226,7 @@
                           IDS_EXTENSIONS_SHOW_BUTTON_IN_TOOLBAR);
   base::RunLoop run_loop;
   toolbar_actions_bar()->PopOutAction(toolbar_actions_bar()->GetActions()[0],
+                                      false,
                                       run_loop.QuitClosure());
   run_loop.Run();
   check_visibility_string(toolbar_actions_bar()->GetActions()[0],
diff --git a/chrome/browser/ui/passwords/manage_passwords_view_utils.cc b/chrome/browser/ui/passwords/manage_passwords_view_utils.cc
index f70cc62c..f584e39d 100644
--- a/chrome/browser/ui/passwords/manage_passwords_view_utils.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_view_utils.cc
@@ -98,7 +98,9 @@
   // the one seen in the omnibox) and the password form post-submit navigation
   // URL differs or not.
   if (!SameDomainOrHost(user_visible_url, form_origin_url)) {
-    title_id = IDS_SAVE_PASSWORD_TITLE;
+    title_id = dialog_type == PasswordTittleType::UPDATE_PASSWORD
+                   ? IDS_UPDATE_PASSWORD_DIFFERENT_DOMAINS_TITLE
+                   : IDS_SAVE_PASSWORD_DIFFERENT_DOMAINS_TITLE;
     // TODO(palmer): Look into passing real language prefs here, not "".
     // crbug.com/498069.
     replacements.push_back(url_formatter::FormatUrlForSecurityDisplay(
diff --git a/chrome/browser/ui/passwords/manage_passwords_view_utils_unittest.cc b/chrome/browser/ui/passwords/manage_passwords_view_utils_unittest.cc
index 15f0828..4b0d891 100644
--- a/chrome/browser/ui/passwords/manage_passwords_view_utils_unittest.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_view_utils_unittest.cc
@@ -62,12 +62,18 @@
     {"https://another.org", "https://example.com:8001/login#form?value=3", true,
      PasswordTittleType::SAVE_PASSWORD, "https://example.com:8001", 12, 29},
 
-    // Update bubble.
+    // Update bubble, same domains.
     {"http://example.com/landing", "http://example.com/login#form?value=3",
      false, PasswordTittleType::UPDATE_PASSWORD, "this site", 0, 0},
     {"http://example.com/landing", "http://example.com/login#form?value=3",
      true, PasswordTittleType::UPDATE_PASSWORD, "this site", 12, 29},
 
+    // Update bubble, different domains.
+    {"https://another.org", "http://example.com/login#form?value=3", false,
+     PasswordTittleType::UPDATE_PASSWORD, "http://example.com", 0, 0},
+    {"https://another.org", "http://example.com/login#form?value=3", true,
+     PasswordTittleType::UPDATE_PASSWORD, "http://example.com", 12, 29},
+
     // Same domains, federated credential.
     {"http://example.com/landing", "http://example.com/login#form?value=3",
      false, PasswordTittleType::SAVE_ACCOUNT, "this site", 0, 0},
diff --git a/chrome/browser/ui/toolbar/app_menu_model.cc b/chrome/browser/ui/toolbar/app_menu_model.cc
index 070381126..42a7e06 100644
--- a/chrome/browser/ui/toolbar/app_menu_model.cc
+++ b/chrome/browser/ui/toolbar/app_menu_model.cc
@@ -480,6 +480,12 @@
       LogMenuAction(MENU_ACTION_PRINT);
       break;
 
+    case IDC_ROUTE_MEDIA:
+      if (!uma_action_recorded_)
+        UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.Cast", delta);
+      LogMenuAction(MENU_ACTION_CAST);
+      break;
+
     // Edit menu.
     case IDC_CUT:
       if (!uma_action_recorded_)
diff --git a/chrome/browser/ui/toolbar/app_menu_model.h b/chrome/browser/ui/toolbar/app_menu_model.h
index ebb4c73..327b262 100644
--- a/chrome/browser/ui/toolbar/app_menu_model.h
+++ b/chrome/browser/ui/toolbar/app_menu_model.h
@@ -70,6 +70,7 @@
   MENU_ACTION_RECENT_TAB = 41,
   MENU_ACTION_BOOKMARK_OPEN = 42,
   MENU_ACTION_UPGRADE_DIALOG = 44,
+  MENU_ACTION_CAST = 45,
   LIMIT_MENU_ACTION
 };
 
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar.cc b/chrome/browser/ui/toolbar/toolbar_actions_bar.cc
index 94775754..546acd4 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_bar.cc
+++ b/chrome/browser/ui/toolbar/toolbar_actions_bar.cc
@@ -124,6 +124,7 @@
       checked_extension_bubble_(false),
       is_drag_in_progress_(false),
       popped_out_action_(nullptr),
+      is_popped_out_sticky_(false),
       weak_ptr_factory_(this) {
   if (model_)  // |model_| can be null in unittests.
     model_observer_.Add(model_);
@@ -283,10 +284,13 @@
 bool ToolbarActionsBar::NeedsOverflow() const {
   DCHECK(!in_overflow_mode());
   // We need an overflow view if either the end index is less than the number of
-  // icons, or if a drag is in progress with the redesign turned on (since the
-  // user can drag an icon into the app menu).
+  // icons, if a drag is in progress with the redesign turned on (since the
+  // user can drag an icon into the app menu), or if there is a non-sticky
+  // popped out action (because the action will pop back into overflow when the
+  // menu opens).
   return GetEndIndexInBounds() != toolbar_actions_.size() ||
-         (is_drag_in_progress_ && !platform_settings_.chevron_enabled);
+         (is_drag_in_progress_ && !platform_settings_.chevron_enabled) ||
+         (popped_out_action_ && !is_popped_out_sticky_);
 }
 
 gfx::Rect ToolbarActionsBar::GetFrameForIndex(
@@ -507,11 +511,13 @@
 }
 
 void ToolbarActionsBar::PopOutAction(ToolbarActionViewController* controller,
+                                     bool is_sticky,
                                      const base::Closure& closure) {
   DCHECK(!in_overflow_mode()) << "Only the main bar can pop out actions.";
   DCHECK(!popped_out_action_) << "Only one action can be popped out at a time!";
   bool needs_redraw = !IsActionVisibleOnMainBar(controller);
   popped_out_action_ = controller;
+  is_popped_out_sticky_ = is_sticky;
   if (needs_redraw) {
     // We suppress animation for this draw, because we need the action to get
     // into position immediately, since it's about to show its popup.
@@ -533,6 +539,7 @@
   DCHECK(popped_out_action_);
   ToolbarActionViewController* controller = popped_out_action_;
   popped_out_action_ = nullptr;
+  is_popped_out_sticky_ = false;
   popped_out_closure_.Reset();
   if (!IsActionVisibleOnMainBar(controller))
     delegate_->Redraw(true);
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar.h b/chrome/browser/ui/toolbar/toolbar_actions_bar.h
index ddba825..1c04daed 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_bar.h
+++ b/chrome/browser/ui/toolbar/toolbar_actions_bar.h
@@ -186,8 +186,11 @@
       const;
 
   // Pops out a given |action|, ensuring it is visible.
+  // |is_sticky| refers to whether or not the action will stay popped out if
+  // the overflow menu is opened.
   // |closure| will be called once any animation is complete.
   void PopOutAction(ToolbarActionViewController* action,
+                    bool is_sticky,
                     const base::Closure& closure);
 
   // Undoes the current "pop out"; i.e., moves the popped out action back into
@@ -325,6 +328,10 @@
   // order to show a popup.
   ToolbarActionViewController* popped_out_action_;
 
+  // True if the popped out action is "sticky", meaning it will stay popped
+  // out even if another menu is opened.
+  bool is_popped_out_sticky_;
+
   // The task to alert the |popped_out_action_| that animation has finished, and
   // it is fully popped out.
   base::Closure popped_out_closure_;
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc b/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc
index a84530b..ac79127 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc
+++ b/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc
@@ -595,3 +595,64 @@
   EXPECT_EQ(3u, overflow_bar()->GetEndIndexInBounds());
   EXPECT_FALSE(toolbar_actions_bar()->NeedsOverflow());
 }
+
+// Tests the logic for determining if the container needs an overflow menu item.
+TEST_P(ToolbarActionsBarRedesignUnitTest, TestNeedsOverflow) {
+  CreateAndAddExtension(
+      "extension 1",
+      extensions::extension_action_test_util::BROWSER_ACTION);
+  // One extension on the main bar, none overflowed. Overflow not needed.
+  EXPECT_EQ(1u, toolbar_actions_bar()->GetIconCount());
+  EXPECT_EQ(0u, overflow_bar()->GetIconCount());
+  EXPECT_FALSE(toolbar_actions_bar()->NeedsOverflow());
+
+  // Set one extension in the overflow menu, none on the main bar. Overflow
+  // needed.
+  toolbar_model()->SetVisibleIconCount(0u);
+  EXPECT_EQ(0u, toolbar_actions_bar()->GetIconCount());
+  EXPECT_EQ(1u, overflow_bar()->GetIconCount());
+  EXPECT_TRUE(toolbar_actions_bar()->NeedsOverflow());
+
+  // Pop out an extension for a non-sticky popup. Even though the extension is
+  // on the main bar, overflow is still needed because it will pop back in
+  // when the menu is opened.
+  ToolbarActionViewController* action = toolbar_actions_bar()->GetActions()[0];
+  {
+    base::RunLoop run_loop;
+    toolbar_actions_bar()->PopOutAction(action, false, run_loop.QuitClosure());
+    run_loop.Run();
+  }
+  EXPECT_EQ(1u, toolbar_actions_bar()->GetIconCount());
+  EXPECT_TRUE(toolbar_actions_bar()->NeedsOverflow());
+
+  // Back to one in overflow, none on the main bar.
+  toolbar_actions_bar()->UndoPopOut();
+  EXPECT_EQ(0u, toolbar_actions_bar()->GetIconCount());
+  EXPECT_EQ(1u, overflow_bar()->GetIconCount());
+  EXPECT_TRUE(toolbar_actions_bar()->NeedsOverflow());
+
+  // Pop out an extension for a sticky popup. Overflow shouldn't be needed now
+  // because the extension will remain popped out even when the menu opens.
+  {
+    base::RunLoop run_loop;
+    toolbar_actions_bar()->PopOutAction(action, true, run_loop.QuitClosure());
+    run_loop.Run();
+  }
+  EXPECT_EQ(1u, toolbar_actions_bar()->GetIconCount());
+  EXPECT_FALSE(toolbar_actions_bar()->NeedsOverflow());
+
+  // Add another extension and verify that if one is still in overflow when
+  // another is popped out, we still need overflow.
+  toolbar_actions_bar()->UndoPopOut();
+  CreateAndAddExtension(
+      "extension 2",
+      extensions::extension_action_test_util::BROWSER_ACTION);
+  toolbar_model()->SetVisibleIconCount(0u);
+  {
+    base::RunLoop run_loop;
+    toolbar_actions_bar()->PopOutAction(action, true, run_loop.QuitClosure());
+    run_loop.Run();
+  }
+  EXPECT_EQ(1u, toolbar_actions_bar()->GetIconCount());
+  EXPECT_TRUE(toolbar_actions_bar()->NeedsOverflow());
+}
diff --git a/chrome/browser/ui/views/extensions/extension_action_platform_delegate_views.cc b/chrome/browser/ui/views/extensions/extension_action_platform_delegate_views.cc
index a3d97c00..1a21af9d 100644
--- a/chrome/browser/ui/views/extensions/extension_action_platform_delegate_views.cc
+++ b/chrome/browser/ui/views/extensions/extension_action_platform_delegate_views.cc
@@ -97,6 +97,12 @@
     app_menu_button->CloseMenu();
 }
 
+void ExtensionActionPlatformDelegateViews::ShowContextMenu() {
+  views::View* view = GetDelegateViews()->GetAsView();
+  view->context_menu_controller()->ShowContextMenuForView(
+      view, view->GetKeyboardContextMenuLocation(), ui::MENU_SOURCE_NONE);
+}
+
 void ExtensionActionPlatformDelegateViews::Observe(
     int type,
     const content::NotificationSource& source,
diff --git a/chrome/browser/ui/views/extensions/extension_action_platform_delegate_views.h b/chrome/browser/ui/views/extensions/extension_action_platform_delegate_views.h
index 3da2ef9..c16fa8f 100644
--- a/chrome/browser/ui/views/extensions/extension_action_platform_delegate_views.h
+++ b/chrome/browser/ui/views/extensions/extension_action_platform_delegate_views.h
@@ -38,6 +38,7 @@
       bool grant_tab_permissions,
       ExtensionActionViewController::PopupShowAction show_action) override;
   void CloseOverflowMenu() override;
+  void ShowContextMenu() override;
 
   // content::NotificationObserver:
   void Observe(int type,
diff --git a/chrome/browser/ui/views/infobars/infobar_background.cc b/chrome/browser/ui/views/infobars/infobar_background.cc
index 9a93fef..7e9fe10 100644
--- a/chrome/browser/ui/views/infobars/infobar_background.cc
+++ b/chrome/browser/ui/views/infobars/infobar_background.cc
@@ -29,15 +29,13 @@
   gradient_points[0].iset(0, 0);
   gradient_points[1].iset(0, view->height());
   SkColor gradient_colors[2] = { top_color_, bottom_color_ };
-  skia::RefPtr<SkShader> gradient_shader = skia::AdoptRef(
-      SkGradientShader::CreateLinear(gradient_points, gradient_colors, NULL, 2,
-                                     SkShader::kClamp_TileMode));
   SkPaint paint;
   paint.setStrokeWidth(
       SkIntToScalar(InfoBarContainerDelegate::kSeparatorLineHeight));
   paint.setStyle(SkPaint::kFill_Style);
   paint.setStrokeCap(SkPaint::kRound_Cap);
-  paint.setShader(gradient_shader.get());
+  paint.setShader(SkGradientShader::MakeLinear(
+      gradient_points, gradient_colors, NULL, 2, SkShader::kClamp_TileMode));
 
   InfoBarView* infobar = static_cast<InfoBarView*>(view);
   SkCanvas* canvas_skia = canvas->sk_canvas();
diff --git a/chrome/browser/ui/views/profiles/profile_chooser_view.cc b/chrome/browser/ui/views/profiles/profile_chooser_view.cc
index 95234c0..f800d2d 100644
--- a/chrome/browser/ui/views/profiles/profile_chooser_view.cc
+++ b/chrome/browser/ui/views/profiles/profile_chooser_view.cc
@@ -1433,7 +1433,7 @@
   gfx::Image guest_icon =
       ui::ResourceBundle::GetSharedInstance().GetImageNamed(
           profiles::GetPlaceholderAvatarIconResourceID());
-  AvatarMenu::Item guest_avatar_item(0, 0, guest_icon);
+  AvatarMenu::Item guest_avatar_item(0, base::FilePath(), guest_icon);
   guest_avatar_item.active = true;
   guest_avatar_item.name = l10n_util::GetStringUTF16(
       IDS_PROFILES_GUEST_PROFILE_NAME);
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index 3b5e36f5..9f2d643 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -134,12 +134,11 @@
                    SkScalar radius,
                    SkColor color) {
   const SkColor colors[2] = { color, SkColorSetA(color, 0) };
-  skia::RefPtr<SkShader> shader = skia::AdoptRef(SkGradientShader::CreateRadial(
-      p, radius, colors, nullptr, 2, SkShader::kClamp_TileMode));
   SkPaint paint;
   paint.setStyle(SkPaint::kFill_Style);
   paint.setAntiAlias(true);
-  paint.setShader(shader.get());
+  paint.setShader(SkGradientShader::MakeRadial(p, radius, colors, nullptr, 2,
+                                               SkShader::kClamp_TileMode));
   canvas->sk_canvas()->drawRect(
       SkRect::MakeXYWH(p.x() - radius, p.y() - radius, radius * 2, radius * 2),
       paint);
diff --git a/chrome/browser/ui/views/toolbar/app_menu.cc b/chrome/browser/ui/views/toolbar/app_menu.cc
index 52143661..6200059d 100644
--- a/chrome/browser/ui/views/toolbar/app_menu.cc
+++ b/chrome/browser/ui/views/toolbar/app_menu.cc
@@ -1153,11 +1153,6 @@
       case IDC_EXTENSIONS_OVERFLOW_MENU: {
         scoped_ptr<ExtensionToolbarMenuView> extension_toolbar(
             new ExtensionToolbarMenuView(browser_, this, item));
-        if (!extension_toolbar->ShouldShow()) {
-          item->SetVisible(false);
-          extension_toolbar_ = nullptr;
-          break;
-        }
         if (ui::MaterialDesignController::IsModeMaterial()) {
           for (int i = 0; i < extension_toolbar->contents()->child_count();
                ++i) {
diff --git a/chrome/browser/ui/views/toolbar/app_menu_button.cc b/chrome/browser/ui/views/toolbar/app_menu_button.cc
index 473d423..ffcf9b78d 100644
--- a/chrome/browser/ui/views/toolbar/app_menu_button.cc
+++ b/chrome/browser/ui/views/toolbar/app_menu_button.cc
@@ -40,7 +40,6 @@
       toolbar_view_(toolbar_view),
       allow_extension_dragging_(
           extensions::FeatureSwitch::extension_action_redesign()->IsEnabled()),
-      destroyed_(nullptr),
       margin_trailing_(0),
       ink_drop_delegate_(new views::ButtonInkDropDelegate(this, this)),
       weak_factory_(this) {
@@ -49,10 +48,7 @@
     icon_painter_.reset(new AppMenuIconPainter(this));
 }
 
-AppMenuButton::~AppMenuButton() {
-  if (destroyed_)
-    *destroyed_ = true;
-}
+AppMenuButton::~AppMenuButton() {}
 
 void AppMenuButton::SetSeverity(AppMenuIconPainter::Severity severity,
                                 bool animate) {
@@ -87,16 +83,6 @@
 
   FOR_EACH_OBSERVER(views::MenuListener, menu_listeners_, OnMenuOpened());
 
-  // Because running the menu below spins a nested message loop, |this| can be
-  // deleted by the time RunMenu() returns. To detect this, we set |destroyed_|
-  // (which is normally null) to point to a local. If our destructor runs during
-  // RunMenu(), then this local will be set to true on return, and we'll know
-  // it's not safe to access any member variables.
-  bool destroyed = false;
-  destroyed_ = &destroyed;
-
-  ink_drop_delegate()->OnAction(views::InkDropState::ACTIVATED);
-
   base::TimeTicks menu_open_time = base::TimeTicks::Now();
   menu_->RunMenu(this);
 
@@ -107,11 +93,6 @@
     UMA_HISTOGRAM_TIMES("Toolbar.AppMenuTimeToAction",
                         base::TimeTicks::Now() - menu_open_time);
   }
-
-  if (!destroyed) {
-    ink_drop_delegate()->OnAction(views::InkDropState::DEACTIVATED);
-    destroyed_ = nullptr;
-  }
 }
 
 void AppMenuButton::CloseMenu() {
diff --git a/chrome/browser/ui/views/toolbar/app_menu_button.h b/chrome/browser/ui/views/toolbar/app_menu_button.h
index c0c4cc7..21bffcb 100644
--- a/chrome/browser/ui/views/toolbar/app_menu_button.h
+++ b/chrome/browser/ui/views/toolbar/app_menu_button.h
@@ -106,9 +106,6 @@
   scoped_ptr<AppMenuModel> menu_model_;
   scoped_ptr<AppMenu> menu_;
 
-  // Used by ShowMenu() to detect when |this| has been deleted; see comments
-  // there.
-  bool* destroyed_;
 
   // Any trailing margin to be applied. Used when the browser is in
   // a maximized state to extend to the full window width.
diff --git a/chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.cc b/chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.cc
index 659c61e6..c430a7d 100644
--- a/chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.cc
+++ b/chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.cc
@@ -41,9 +41,6 @@
   container_ = new BrowserActionsContainer(browser_, main);
   container_->Init();
   SetContents(container_);
-  // We Layout() the container here so that we know the number of actions
-  // that will be visible in ShouldShow().
-  container_->Layout();
 
   // Listen for the drop to finish so we can close the app menu, if necessary.
   toolbar_actions_bar_observer_.Add(main->toolbar_actions_bar());
@@ -60,11 +57,6 @@
 ExtensionToolbarMenuView::~ExtensionToolbarMenuView() {
 }
 
-bool ExtensionToolbarMenuView::ShouldShow() {
-  return app_menu_->for_drop() ||
-         container_->VisibleBrowserActionsAfterAnimation();
-}
-
 gfx::Size ExtensionToolbarMenuView::GetPreferredSize() const {
   gfx::Size s = views::ScrollView::GetPreferredSize();
   // views::ScrollView::GetPreferredSize() includes the contents' size, but
diff --git a/chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.h b/chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.h
index bba9cba..f3c0b10 100644
--- a/chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.h
+++ b/chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.h
@@ -33,11 +33,6 @@
                            views::MenuItemView* menu_item);
   ~ExtensionToolbarMenuView() override;
 
-  // Returns whether the app menu should show this view. This is true when
-  // either |container_| has icons to display or the menu was opened for a drag-
-  // and-drop operation.
-  bool ShouldShow();
-
   // views::View:
   gfx::Size GetPreferredSize() const override;
   int GetHeightForWidth(int width) const override;
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view.cc b/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
index 38ee8f7..73f9efba 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
@@ -84,6 +84,9 @@
 }
 
 ToolbarActionView::~ToolbarActionView() {
+  // Avoid access to a destroyed InkDropDelegate when the |pressed_lock_| is
+  // destroyed.
+  set_ink_drop_delegate(nullptr);
   view_controller_->SetDelegate(nullptr);
 }
 
@@ -116,8 +119,10 @@
         ui::NativeTheme::kColorId_HoverMenuItemBackgroundColor);
   }
 
-  return GetThemeProvider()->GetColor(
-      ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON);
+  return GetThemeProvider()
+             ? GetThemeProvider()->GetColor(
+                   ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON)
+             : CustomButton::GetInkDropBaseColor();
 }
 
 bool ToolbarActionView::ShouldShowInkDropHover() const {
@@ -176,7 +181,6 @@
   menu_ = nullptr;
   view_controller_->OnContextMenuClosed();
   menu_adapter_.reset();
-  ink_drop_delegate()->OnAction(views::InkDropState::DEACTIVATED);
 }
 
 gfx::ImageSkia ToolbarActionView::GetIconForTest() {
@@ -195,7 +199,7 @@
 
 bool ToolbarActionView::OnMousePressed(const ui::MouseEvent& event) {
   // views::MenuButton actions are only triggered by left mouse clicks.
-  if (event.IsOnlyLeftMouseButton()) {
+  if (event.IsOnlyLeftMouseButton() && !pressed_lock_) {
     // TODO(bruthig): The ACTION_PENDING triggering logic should be in
     // MenuButton::OnPressed() however there is a bug with the pressed state
     // logic in MenuButton. See http://crbug.com/567252.
@@ -298,7 +302,6 @@
       delegate_->GetOverflowReferenceView()->GetWidget() :
       GetWidget();
 
-  ink_drop_delegate()->OnAction(views::InkDropState::ACTIVATED);
   // Unretained() is safe here as ToolbarActionView will always outlive the
   // menu. Any action that would lead to the deletion of |this| first triggers
   // the closing of the menu through lost capture.
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view_unittest.cc b/chrome/browser/ui/views/toolbar/toolbar_action_view_unittest.cc
index a7afc419..4375812ba 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_action_view_unittest.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_action_view_unittest.cc
@@ -15,6 +15,7 @@
 #include "content/public/test/test_web_contents_factory.h"
 #include "ui/accessibility/ax_view_state.h"
 #include "ui/events/test/event_generator.h"
+#include "ui/views/animation/test/test_ink_drop_delegate.h"
 #include "ui/views/test/views_test_base.h"
 
 namespace {
@@ -129,12 +130,70 @@
   DISALLOW_COPY_AND_ASSIGN(ToolbarActionViewUnitTest);
 };
 
+// A MenuButton subclass that provides access to some MenuButton internals.
+class TestToolbarActionView : public ToolbarActionView {
+ public:
+  TestToolbarActionView(ToolbarActionViewController* view_controller,
+                        Delegate* delegate)
+      : ToolbarActionView(view_controller, delegate) {}
+
+  ~TestToolbarActionView() override {}
+
+  // Accessors to protected ToolbarActionView methods.
+  void set_ink_drop_delegate(views::InkDropDelegate* ink_drop_delegate) {
+    ToolbarActionView::set_ink_drop_delegate(ink_drop_delegate);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestToolbarActionView);
+};
+
+// Verifies there is no crash when a ToolbarActionView with an InkDropDelegate
+// is destroyed while holding a |pressed_lock_|.
+TEST_F(ToolbarActionViewUnitTest,
+       NoCrashWhenDestroyingToolbarActionViewThatHasAPressedLock) {
+  TestToolbarActionViewController controller("fake controller");
+  TestToolbarActionViewDelegate action_view_delegate;
+
+  // Create a new toolbar action view.
+  scoped_ptr<ToolbarActionView> view(
+      new ToolbarActionView(&controller, &action_view_delegate));
+  view->set_owned_by_client();
+  view->SetBoundsRect(gfx::Rect(0, 0, 200, 20));
+  widget()->SetContentsView(view.get());
+  widget()->Show();
+
+  controller.ShowPopup(true);
+
+  view.reset();
+}
+
+// Verifies the InkDropAnimation used by the ToolbarActionView doesn't fail a
+// DCHECK for an unsupported transition from ACTIVATED to ACTION_PENDING.
+TEST_F(ToolbarActionViewUnitTest,
+       NoCrashWhenPressingMouseOnToolbarActionViewThatHasAPressedLock) {
+  TestToolbarActionViewController controller("fake controller");
+  TestToolbarActionViewDelegate action_view_delegate;
+
+  // Create a new toolbar action view.
+  ToolbarActionView view(&controller, &action_view_delegate);
+  view.set_owned_by_client();
+  view.SetBoundsRect(gfx::Rect(0, 0, 200, 20));
+  widget()->SetContentsView(&view);
+  widget()->Show();
+
+  ui::test::EventGenerator generator(GetContext(), widget()->GetNativeWindow());
+
+  controller.ShowPopup(true);
+  generator.PressLeftButton();
+}
+
 // Test the basic ui of a ToolbarActionView and that it responds correctly to
 // a controller's state.
 TEST_F(ToolbarActionViewUnitTest, BasicToolbarActionViewTest) {
   TestingProfile profile;
 
-  // ViewsTestBase initializees the aura environment, so the factory shouldn't.
+  // ViewsTestBase initializes the aura environment, so the factory shouldn't.
   content::TestWebContentsFactory web_contents_factory;
 
   TestToolbarActionViewController controller("fake controller");
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index bb85a65..8a6a175 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -9,7 +9,6 @@
 #include <vector>
 
 #include "base/bind.h"
-#include "base/command_line.h"
 #include "base/location.h"
 #include "base/thread_task_runner_handle.h"
 #include "build/build_config.h"
@@ -65,7 +64,6 @@
 #include "components/favicon_base/favicon_util.h"
 #include "components/favicon_base/select_favicon_frames.h"
 #include "components/history/core/browser/history_types.h"
-#include "components/password_manager/core/common/password_manager_switches.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/core/common/profile_management_switches.h"
 #include "content/public/browser/web_contents.h"
diff --git a/chrome/browser/ui/webui/password_manager_internals/password_manager_internals_ui_browsertest.cc b/chrome/browser/ui/webui/password_manager_internals/password_manager_internals_ui_browsertest.cc
index eddcc0d1..a5b3c0b 100644
--- a/chrome/browser/ui/webui/password_manager_internals/password_manager_internals_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/password_manager_internals/password_manager_internals_ui_browsertest.cc
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/command_line.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -12,7 +11,6 @@
 #include "chrome/test/base/web_ui_browser_test.h"
 #include "components/password_manager/content/browser/password_manager_internals_service_factory.h"
 #include "components/password_manager/core/browser/password_manager_internals_service.h"
-#include "components/password_manager/core/common/password_manager_switches.h"
 #include "content/public/browser/web_contents.h"
 
 class PasswordManagerInternalsWebUIBrowserTest : public WebUIBrowserTest {
diff --git a/chrome/browser/ui/webui/settings/appearance_handler.h b/chrome/browser/ui/webui/settings/appearance_handler.h
index 56161bd..86befb6 100644
--- a/chrome/browser/ui/webui/settings/appearance_handler.h
+++ b/chrome/browser/ui/webui/settings/appearance_handler.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_UI_WEBUI_SETTINGS_APPEARANCE_HANDLER_H_
 
 #include "base/macros.h"
-#include "chrome/browser/ui/webui/settings/md_settings_ui.h"
+#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 
diff --git a/chrome/browser/ui/webui/settings/certificates_handler.h b/chrome/browser/ui/webui/settings/certificates_handler.h
index 99607f2..7e4b6e2 100644
--- a/chrome/browser/ui/webui/settings/certificates_handler.h
+++ b/chrome/browser/ui/webui/settings/certificates_handler.h
@@ -13,7 +13,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "chrome/browser/certificate_manager_model.h"
-#include "chrome/browser/ui/webui/settings/md_settings_ui.h"
+#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 #include "net/cert/nss_cert_database.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/shell_dialogs/select_file_dialog.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.h b/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.h
index a31c669c..36824293 100644
--- a/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.h
+++ b/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.h
@@ -9,7 +9,7 @@
 #include "base/scoped_observer.h"
 #include "chrome/browser/chromeos/camera_presence_notifier.h"
 #include "chrome/browser/image_decoder.h"
-#include "chrome/browser/ui/webui/settings/md_settings_ui.h"
+#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "ui/gfx/image/image_skia.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler.h b/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler.h
index 2ea6cbf..e8ce39e 100644
--- a/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler.h
+++ b/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_DEVICE_KEYBOARD_HANDLER_H_
 
 #include "base/macros.h"
-#include "chrome/browser/ui/webui/settings/md_settings_ui.h"
+#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 #include "ui/events/devices/input_device_event_observer.h"
 
 namespace base {
diff --git a/chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler.h b/chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler.h
index 4741f97c..93a9904 100644
--- a/chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler.h
+++ b/chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler.h
@@ -7,7 +7,7 @@
 
 #include "base/macros.h"
 #include "chrome/browser/signin/easy_unlock_service_observer.h"
-#include "chrome/browser/ui/webui/settings/md_settings_ui.h"
+#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 
 namespace content {
 class WebUIDataSource;
diff --git a/chrome/browser/ui/webui/settings/downloads_handler.h b/chrome/browser/ui/webui/settings/downloads_handler.h
index 7da67fed..cdb9d60a 100644
--- a/chrome/browser/ui/webui/settings/downloads_handler.h
+++ b/chrome/browser/ui/webui/settings/downloads_handler.h
@@ -9,7 +9,7 @@
 
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
-#include "chrome/browser/ui/webui/settings/md_settings_ui.h"
+#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 #include "ui/shell_dialogs/select_file_dialog.h"
 
 namespace base {
diff --git a/chrome/browser/ui/webui/settings/font_handler.h b/chrome/browser/ui/webui/settings/font_handler.h
index 6da85cb..28748a2d 100644
--- a/chrome/browser/ui/webui/settings/font_handler.h
+++ b/chrome/browser/ui/webui/settings/font_handler.h
@@ -8,7 +8,7 @@
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "chrome/browser/ui/webui/settings/md_settings_ui.h"
+#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 
 namespace base {
 class ListValue;
diff --git a/chrome/browser/ui/webui/settings/languages_handler.h b/chrome/browser/ui/webui/settings/languages_handler.h
index b8e1a93..1afd40f 100644
--- a/chrome/browser/ui/webui/settings/languages_handler.h
+++ b/chrome/browser/ui/webui/settings/languages_handler.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_UI_WEBUI_SETTINGS_LANGUAGES_HANDLER_H_
 
 #include "base/macros.h"
-#include "chrome/browser/ui/webui/settings/md_settings_ui.h"
+#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 
 namespace base {
 class ListValue;
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui.cc b/chrome/browser/ui/webui/settings/md_settings_ui.cc
index 6ee2da9b..c748fbd 100644
--- a/chrome/browser/ui/webui/settings/md_settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_ui.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/ui/webui/settings/reset_settings_handler.h"
 #include "chrome/browser/ui/webui/settings/search_engines_handler.h"
 #include "chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.h"
+#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 #include "chrome/browser/ui/webui/settings/settings_startup_pages_handler.h"
 #include "chrome/browser/ui/webui/settings/site_settings_handler.h"
 #include "chrome/browser/ui/webui/settings/system_handler.h"
@@ -44,30 +45,6 @@
 
 namespace settings {
 
-SettingsPageUIHandler::SettingsPageUIHandler() {
-}
-
-SettingsPageUIHandler::~SettingsPageUIHandler() {
-}
-
-void SettingsPageUIHandler::ResolveJavascriptCallback(
-    const base::Value& callback_id,
-    const base::Value& response) {
-  // cr.webUIResponse is a global JS function exposed from cr.js.
-  web_ui()->CallJavascriptFunction(
-      "cr.webUIResponse", callback_id,
-      base::FundamentalValue(true), response);
-}
-
-void SettingsPageUIHandler::RejectJavascriptCallback(
-    const base::Value& callback_id,
-    const base::Value& response) {
-  // cr.webUIResponse is a global JS function exposed from cr.js.
-  web_ui()->CallJavascriptFunction(
-      "cr.webUIResponse", callback_id,
-      base::FundamentalValue(false), response);
-}
-
 MdSettingsUI::MdSettingsUI(content::WebUI* web_ui)
     : content::WebUIController(web_ui),
       WebContentsObserver(web_ui->GetWebContents()) {
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui.h b/chrome/browser/ui/webui/settings/md_settings_ui.h
index 0ebdcb9cf..f826a1e 100644
--- a/chrome/browser/ui/webui/settings/md_settings_ui.h
+++ b/chrome/browser/ui/webui/settings/md_settings_ui.h
@@ -5,48 +5,16 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_MD_SETTINGS_UI_H_
 #define CHROME_BROWSER_UI_WEBUI_SETTINGS_MD_SETTINGS_UI_H_
 
-#include <string>
 #include <unordered_set>
 
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/time/time.h"
-#include "base/values.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_ui_controller.h"
-#include "content/public/browser/web_ui_message_handler.h"
 
 namespace settings {
 
-// The base class handler of Javascript messages of settings pages.
-class SettingsPageUIHandler : public content::WebUIMessageHandler {
- public:
-  SettingsPageUIHandler();
-  ~SettingsPageUIHandler() override;
-
-  // WebUIMessageHandler:
-  void RegisterMessages() override {}
-
-  // Called when a navigation re-uses a renderer process (i.e. reload).
-  // TODO(dbeam): move to WebUIMessageHandler?
-  virtual void RenderViewReused() {}
-
- protected:
-  // Helper method for responding to JS requests initiated with
-  // cr.sendWithPromise(), for the case where the returned promise should be
-  // resolved (request succeeded).
-  void ResolveJavascriptCallback(const base::Value& callback_id,
-                                 const base::Value& response);
-
-  // Helper method for responding to JS requests initiated with
-  // cr.sendWithPromise(), for the case where the returned promise should be
-  // rejected (request failed).
-  void RejectJavascriptCallback(const base::Value& callback_id,
-                                const base::Value& response);
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SettingsPageUIHandler);
-};
+class SettingsPageUIHandler;
 
 // The WebUI handler for chrome://md-settings.
 class MdSettingsUI : public content::WebUIController,
diff --git a/chrome/browser/ui/webui/settings/people_handler.h b/chrome/browser/ui/webui/settings/people_handler.h
index 4556b74..2c0f523 100644
--- a/chrome/browser/ui/webui/settings/people_handler.h
+++ b/chrome/browser/ui/webui/settings/people_handler.h
@@ -14,7 +14,7 @@
 #include "build/build_config.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/sync/sync_startup_tracker.h"
-#include "chrome/browser/ui/webui/settings/md_settings_ui.h"
+#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "components/signin/core/browser/signin_manager_base.h"
diff --git a/chrome/browser/ui/webui/settings/reset_settings_handler.h b/chrome/browser/ui/webui/settings/reset_settings_handler.h
index aa27c8f..4ee30cc 100644
--- a/chrome/browser/ui/webui/settings/reset_settings_handler.h
+++ b/chrome/browser/ui/webui/settings/reset_settings_handler.h
@@ -12,7 +12,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "build/build_config.h"
-#include "chrome/browser/ui/webui/settings/md_settings_ui.h"
+#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 
 namespace base {
 class DictionaryValue;
diff --git a/chrome/browser/ui/webui/settings/search_engines_handler.h b/chrome/browser/ui/webui/settings/search_engines_handler.h
index c321a38d..f211bc6e 100644
--- a/chrome/browser/ui/webui/settings/search_engines_handler.h
+++ b/chrome/browser/ui/webui/settings/search_engines_handler.h
@@ -7,7 +7,7 @@
 
 #include "base/macros.h"
 #include "chrome/browser/ui/search_engines/edit_search_engine_controller.h"
-#include "chrome/browser/ui/webui/settings/md_settings_ui.h"
+#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 #include "ui/base/models/table_model_observer.h"
 
 class KeywordEditorController;
diff --git a/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.h b/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.h
index ce9a47b..39248a3 100644
--- a/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.h
+++ b/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.h
@@ -9,7 +9,7 @@
 #include "base/memory/scoped_vector.h"
 #include "chrome/browser/browsing_data/browsing_data_remover.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/webui/settings/md_settings_ui.h"
+#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 #include "components/prefs/pref_member.h"
 
 namespace base {
diff --git a/chrome/browser/ui/webui/settings/settings_default_browser_handler.h b/chrome/browser/ui/webui/settings/settings_default_browser_handler.h
index beb9d6b..e018e93a0 100644
--- a/chrome/browser/ui/webui/settings/settings_default_browser_handler.h
+++ b/chrome/browser/ui/webui/settings/settings_default_browser_handler.h
@@ -9,7 +9,7 @@
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/shell_integration.h"
-#include "chrome/browser/ui/webui/settings/md_settings_ui.h"
+#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 #include "components/prefs/pref_member.h"
 
 namespace base {
diff --git a/chrome/browser/ui/webui/settings/settings_manage_profile_handler.h b/chrome/browser/ui/webui/settings/settings_manage_profile_handler.h
index eb2bcc4..8c31f14 100644
--- a/chrome/browser/ui/webui/settings/settings_manage_profile_handler.h
+++ b/chrome/browser/ui/webui/settings/settings_manage_profile_handler.h
@@ -9,7 +9,7 @@
 
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
-#include "chrome/browser/ui/webui/settings/md_settings_ui.h"
+#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 
 namespace base {
 class StringValue;
diff --git a/chrome/browser/ui/webui/settings/settings_page_ui_handler.cc b/chrome/browser/ui/webui/settings/settings_page_ui_handler.cc
new file mode 100644
index 0000000..93326fa
--- /dev/null
+++ b/chrome/browser/ui/webui/settings/settings_page_ui_handler.cc
@@ -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.
+
+#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
+
+#include "content/public/browser/web_ui.h"
+
+namespace settings {
+
+SettingsPageUIHandler::SettingsPageUIHandler() {}
+
+SettingsPageUIHandler::~SettingsPageUIHandler() {}
+
+void SettingsPageUIHandler::ResolveJavascriptCallback(
+    const base::Value& callback_id,
+    const base::Value& response) {
+  // cr.webUIResponse is a global JS function exposed from cr.js.
+  web_ui()->CallJavascriptFunction(
+      "cr.webUIResponse", callback_id,
+      base::FundamentalValue(true), response);
+}
+
+void SettingsPageUIHandler::RejectJavascriptCallback(
+    const base::Value& callback_id,
+    const base::Value& response) {
+  // cr.webUIResponse is a global JS function exposed from cr.js.
+  web_ui()->CallJavascriptFunction(
+      "cr.webUIResponse", callback_id,
+      base::FundamentalValue(false), response);
+}
+
+}  // namespace settings
diff --git a/chrome/browser/ui/webui/settings/settings_page_ui_handler.h b/chrome/browser/ui/webui/settings/settings_page_ui_handler.h
new file mode 100644
index 0000000..f71d75a
--- /dev/null
+++ b/chrome/browser/ui/webui/settings/settings_page_ui_handler.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 CHROME_BROWSER_UI_WEBUI_SETTINGS_SETTINGS_PAGE_UI_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_SETTINGS_SETTINGS_PAGE_UI_HANDLER_H_
+
+#include "base/macros.h"
+#include "base/values.h"
+#include "content/public/browser/web_ui_message_handler.h"
+
+namespace settings {
+
+// The base class handler of Javascript messages of settings pages.
+class SettingsPageUIHandler : public content::WebUIMessageHandler {
+ public:
+  SettingsPageUIHandler();
+  ~SettingsPageUIHandler() override;
+
+  // WebUIMessageHandler implementation.
+  void RegisterMessages() override {}
+
+  // TODO(dbeam): move to WebUIMessageHandler?
+  // Called when a navigation re-uses a renderer process (i.e. reload).
+  virtual void RenderViewReused() {}
+
+ protected:
+  // Helper method for responding to JS requests initiated with
+  // cr.sendWithPromise(), for the case where the returned promise should be
+  // resolved (request succeeded).
+  void ResolveJavascriptCallback(const base::Value& callback_id,
+                                 const base::Value& response);
+
+  // Helper method for responding to JS requests initiated with
+  // cr.sendWithPromise(), for the case where the returned promise should be
+  // rejected (request failed).
+  void RejectJavascriptCallback(const base::Value& callback_id,
+                                const base::Value& response);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SettingsPageUIHandler);
+};
+
+}  // namespace settings
+
+#endif  // CHROME_BROWSER_UI_WEBUI_SETTINGS_SETTINGS_PAGE_UI_HANDLER_H_
diff --git a/chrome/browser/ui/webui/settings/settings_startup_pages_handler.h b/chrome/browser/ui/webui/settings/settings_startup_pages_handler.h
index 64a4a76..68a3987 100644
--- a/chrome/browser/ui/webui/settings/settings_startup_pages_handler.h
+++ b/chrome/browser/ui/webui/settings/settings_startup_pages_handler.h
@@ -7,7 +7,7 @@
 
 #include "base/macros.h"
 #include "chrome/browser/custom_home_pages_table_model.h"
-#include "chrome/browser/ui/webui/settings/md_settings_ui.h"
+#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "ui/base/models/table_model_observer.h"
 
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler.h b/chrome/browser/ui/webui/settings/site_settings_handler.h
index 92f3fd2..9825cf98 100644
--- a/chrome/browser/ui/webui/settings/site_settings_handler.h
+++ b/chrome/browser/ui/webui/settings/site_settings_handler.h
@@ -8,7 +8,7 @@
 #include <vector>
 
 #include "chrome/browser/storage/storage_info_fetcher.h"
-#include "chrome/browser/ui/webui/settings/md_settings_ui.h"
+#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 
 class Profile;
 
diff --git a/chrome/browser/ui/webui/settings/system_handler.h b/chrome/browser/ui/webui/settings/system_handler.h
index d325e4f..ea7ca04 100644
--- a/chrome/browser/ui/webui/settings/system_handler.h
+++ b/chrome/browser/ui/webui/settings/system_handler.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_UI_WEBUI_SETTINGS_SYSTEM_HANDLER_H_
 
 #include "base/macros.h"
-#include "chrome/browser/ui/webui/settings/md_settings_ui.h"
+#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 
 namespace base {
 class ListValue;
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 9b7080ba..c809cc6ff 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -536,8 +536,6 @@
       'browser/search/suggestions/suggestions_service_factory.h',
       'browser/search/suggestions/suggestions_source.cc',
       'browser/search/suggestions/suggestions_source.h',
-      'browser/search/suggestions/suggestions_utils.cc',
-      'browser/search/suggestions/suggestions_utils.h',
       'browser/search/thumbnail_source.cc',
       'browser/search/thumbnail_source.h',
       'browser/shell_integration.cc',
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index 32c70a9..d6107d3 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -2031,6 +2031,8 @@
       'browser/ui/webui/settings/settings_clear_browsing_data_handler.h',
       'browser/ui/webui/settings/settings_manage_profile_handler.cc',
       'browser/ui/webui/settings/settings_manage_profile_handler.h',
+      'browser/ui/webui/settings/settings_page_ui_handler.cc',
+      'browser/ui/webui/settings/settings_page_ui_handler.h',
       'browser/ui/webui/settings/settings_startup_pages_handler.cc',
       'browser/ui/webui/settings/settings_startup_pages_handler.h',
       'browser/ui/webui/settings/site_settings_handler.cc',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 049c723..aeb1f60 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -258,8 +258,8 @@
       'browser/extensions/extension_startup_browsertest.cc',
       'browser/extensions/extension_storage_apitest.cc',
       'browser/extensions/extension_storage_monitor_browsertest.cc',
-      'browser/extensions/extension_tabs_apitest.cc',
       'browser/extensions/extension_tab_util_browsertest.cc',
+      'browser/extensions/extension_tabs_apitest.cc',
       'browser/extensions/extension_url_rewrite_browsertest.cc',
       'browser/extensions/extension_view_host_factory_browsertest.cc',
       'browser/extensions/extension_websocket_apitest.cc',
@@ -317,25 +317,19 @@
       'browser/lifetime/browser_close_manager_browsertest.cc',
       'browser/loadtimes_extension_bindings_browsertest.cc',
       'browser/locale_tests_browsertest.cc',
-      'browser/media/chrome_media_stream_infobar_browsertest.cc',
-      'browser/media/chrome_webrtc_apprtc_browsertest.cc',
-      'browser/media/chrome_webrtc_audio_quality_browsertest.cc',
-      'browser/media/chrome_webrtc_browsertest.cc',
-      'browser/media/chrome_webrtc_disable_encryption_flag_browsertest.cc',
-      'browser/media/chrome_webrtc_getmediadevices_browsertest.cc',
-      'browser/media/chrome_webrtc_perf_browsertest.cc',
-      'browser/media/chrome_webrtc_simulcast_browsertest.cc',
-      'browser/media/chrome_webrtc_video_quality_browsertest.cc',
-      'browser/media/chrome_webrtc_webcam_browsertest.cc',
       'browser/media/defer_background_media_browsertest.cc',
       'browser/media/encrypted_media_browsertest.cc',
       'browser/media/encrypted_media_supported_types_browsertest.cc',
       'browser/media/media_browsertest.cc',
       'browser/media/media_browsertest.h',
       'browser/media/media_stream_devices_controller_browsertest.cc',
+      'browser/media/media_stream_infobar_browsertest.cc',
       'browser/media/test_license_server.cc',
       'browser/media/test_license_server.h',
       'browser/media/test_license_server_config.h',
+      'browser/media/webrtc_apprtc_browsertest.cc',
+      'browser/media/webrtc_audio_quality_browsertest.cc',
+      'browser/media/webrtc_browsertest.cc',
       'browser/media/webrtc_browsertest_audio.cc',
       'browser/media/webrtc_browsertest_audio.h',
       'browser/media/webrtc_browsertest_base.cc',
@@ -344,6 +338,12 @@
       'browser/media/webrtc_browsertest_common.h',
       'browser/media/webrtc_browsertest_perf.cc',
       'browser/media/webrtc_browsertest_perf.h',
+      'browser/media/webrtc_disable_encryption_flag_browsertest.cc',
+      'browser/media/webrtc_getmediadevices_browsertest.cc',
+      'browser/media/webrtc_perf_browsertest.cc',
+      'browser/media/webrtc_simulcast_browsertest.cc',
+      'browser/media/webrtc_video_quality_browsertest.cc',
+      'browser/media/webrtc_webcam_browsertest.cc',
       'browser/media/wv_test_license_server_config.cc',
       'browser/media/wv_test_license_server_config.h',
       'browser/media_galleries/fileapi/iapps_finder_impl_win_browsertest.cc',
@@ -387,14 +387,14 @@
       'browser/profiles/profile_window_browsertest.cc',
       'browser/push_messaging/push_messaging_browsertest.cc',
       'browser/referrer_policy_browsertest.cc',
+      'browser/renderer_context_menu/mock_render_view_context_menu.cc',
+      'browser/renderer_context_menu/mock_render_view_context_menu.h',
       'browser/renderer_context_menu/render_view_context_menu_browsertest.cc',
       'browser/renderer_context_menu/render_view_context_menu_browsertest_util.cc',
       'browser/renderer_context_menu/render_view_context_menu_browsertest_util.h',
       'browser/renderer_context_menu/render_view_context_menu_test_util.cc',
       'browser/renderer_context_menu/render_view_context_menu_test_util.h',
       'browser/renderer_context_menu/spelling_menu_observer_browsertest.cc',
-      'browser/renderer_context_menu/mock_render_view_context_menu.cc',
-      'browser/renderer_context_menu/mock_render_view_context_menu.h',
       'browser/renderer_host/chrome_resource_dispatcher_host_delegate_browsertest.cc',
       'browser/renderer_host/render_process_host_chrome_browsertest.cc',
       'browser/repost_form_warning_browsertest.cc',
@@ -675,6 +675,8 @@
       'browser/ui/views/web_dialog_view_browsertest.cc',
     ],
     'chrome_browser_tests_chromeos_sources': [
+      '../ui/base/ime/chromeos/input_method_whitelist.cc',
+      '../ui/base/ime/chromeos/input_method_whitelist.h',
       'browser/apps/custom_launcher_page_browsertest_views.cc',
       'browser/chromeos/accessibility/accessibility_manager_browsertest.cc',
       'browser/chromeos/accessibility/magnification_manager_browsertest.cc',
@@ -837,8 +839,6 @@
       'browser/ui/webui/options/chromeos/guest_mode_options_browsertest.cc',
       'browser/ui/webui/options/chromeos/guest_mode_options_ui_browsertest.cc',
       'browser/ui/webui/options/chromeos/shared_options_browsertest.cc',
-      '../ui/base/ime/chromeos/input_method_whitelist.h',
-      '../ui/base/ime/chromeos/input_method_whitelist.cc',
     ],
     'chrome_browser_tests_views_non_cros_or_mac_sources': [
       # This should be brought up on OSX Views but not CrOS.
@@ -1087,8 +1087,8 @@
       'test/base/interactive_test_utils.h',
       'test/base/interactive_test_utils_aura.cc',
       'test/base/interactive_test_utils_aura.h',
-      'test/base/interactive_test_utils_mac.mm',
       'test/base/interactive_test_utils_common_views.cc',
+      'test/base/interactive_test_utils_mac.mm',
       'test/base/interactive_test_utils_win.cc',
       'test/base/interactive_ui_tests_main.cc',
       'test/base/view_event_test_platform_part.h',
@@ -2447,15 +2447,15 @@
           'sources!': [
             'browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc',
             'browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc',
-            'browser/media/chrome_webrtc_apprtc_browsertest.cc',
-            'browser/media/chrome_webrtc_audio_quality_browsertest.cc',
-            'browser/media/chrome_webrtc_browsertest.cc',
-            'browser/media/chrome_webrtc_disable_encryption_flag_browsertest.cc',
-            'browser/media/chrome_webrtc_getmediadevices_browsertest.cc',
-            'browser/media/chrome_webrtc_perf_browsertest.cc',
-            'browser/media/chrome_webrtc_simulcast_browsertest.cc',
-            'browser/media/chrome_webrtc_video_quality_browsertest.cc',
-            'browser/media/chrome_webrtc_webcam_browsertest.cc',
+            'browser/media/webrtc_apprtc_browsertest.cc',
+            'browser/media/webrtc_audio_quality_browsertest.cc',
+            'browser/media/webrtc_browsertest.cc',
+            'browser/media/webrtc_disable_encryption_flag_browsertest.cc',
+            'browser/media/webrtc_getmediadevices_browsertest.cc',
+            'browser/media/webrtc_perf_browsertest.cc',
+            'browser/media/webrtc_simulcast_browsertest.cc',
+            'browser/media/webrtc_video_quality_browsertest.cc',
+            'browser/media/webrtc_webcam_browsertest.cc',
          ],
         }],
         ['OS=="win"', {
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index e19e3c0..cc4e592 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -324,10 +324,10 @@
       '../tools/json_schema_compiler/test/simple_api_unittest.cc',
     ],
     'chrome_unit_tests_mac_android_sources': [
-      'browser/autofill/autofill_cc_infobar_delegate_unittest.cc',
       'browser/password_manager/save_password_infobar_delegate_unittest.cc',
     ],
     'chrome_unit_tests_android_sources': [
+      'browser/autofill/autofill_save_card_infobar_delegate_mobile_unittest.cc',
       'browser/password_manager/auto_signin_first_run_dialog_android_unittest.cc',
       'browser/permissions/permission_queue_controller_unittest.cc',
     ],
diff --git a/chrome/test/data/android/contextmenu/context_menu_test.html b/chrome/test/data/android/contextmenu/context_menu_test.html
index 3c88f46..ab9418da 100644
--- a/chrome/test/data/android/contextmenu/context_menu_test.html
+++ b/chrome/test/data/android/contextmenu/context_menu_test.html
@@ -31,7 +31,7 @@
 width="16" height="14" alt="embedded folder icon" id="dataUrlIcon"><br />
 
   <video id="videoDOMElement" controls>
-    <source src="../media/test.mp4" type="video/mp4">
+    <source src="../media/test.webm" type="video/webm">
   </video><br />
 
 </body>
diff --git a/chrome/test/data/android/media/test.webm b/chrome/test/data/android/media/test.webm
new file mode 100644
index 0000000..f1a92fc
--- /dev/null
+++ b/chrome/test/data/android/media/test.webm
Binary files differ
diff --git a/chrome/test/data/webui/media_router/media_router_container_cast_mode_list_tests.js b/chrome/test/data/webui/media_router/media_router_container_cast_mode_list_tests.js
new file mode 100644
index 0000000..eeda8be60
--- /dev/null
+++ b/chrome/test/data/webui/media_router/media_router_container_cast_mode_list_tests.js
@@ -0,0 +1,399 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/** @fileoverview Suite of tests for media-router-container that focus on the
+ * cast mode list.
+ */
+cr.define('media_router_container_cast_mode_list', function() {
+  function registerTests() {
+    suite('MediaRouterContainerCastModeList', function() {
+      /**
+       * Checks whether |view| matches the current view of |container|.
+       *
+       * @param {!media_router.MediaRouterView} view Expected view type.
+       */
+      var checkCurrentView;
+
+      /**
+       * Checks whether the elements specified in |elementIdList| are visible.
+       * Checks whether all other elements are not visible. Throws an assertion
+       * error if this is not true.
+       *
+       * @param {!Array<!string>} elementIdList List of id's of elements that
+       *     should be visible.
+       */
+      var checkElementsVisibleWithId;
+
+      /**
+       * Checks whether |expected| and the text in the |element| are equal.
+       *
+       * @param {!string} expected Expected text.
+       * @param {!Element} element Element whose text will be checked.
+       */
+      var checkElementText;
+
+      /**
+       * Media Router Container created before each test.
+       * @type {?MediaRouterContainer}
+       */
+      var container;
+
+      /**
+       * The blocking issue to show.
+       * @type {?media_router.Issue}
+       */
+      var fakeBlockingIssue;
+
+      /**
+       * The list of CastModes to show.
+       * @type {!Array<!media_router.CastMode>}
+       */
+      var fakeCastModeList = [];
+
+      /**
+       * The list of CastModes to show with non-default modes only.
+       * @type {!Array<!media_router.CastMode>}
+       */
+      var fakeCastModeListWithNonDefaultModesOnly = [];
+
+      /**
+       * The blocking issue to show.
+       * @type {?media_router.Issue}
+       */
+      var fakeNonBlockingIssue;
+
+      /**
+       * The list of available sinks.
+       * @type {!Array<!media_router.Sink>}
+       */
+      var fakeSinkList = [];
+
+      // Import media_router_container.html before running suite.
+      suiteSetup(function() {
+        return PolymerTest.importHtml(
+            'chrome://media-router/elements/media_router_container/' +
+            'media_router_container.html');
+      });
+
+      setup(function(done) {
+        PolymerTest.clearBody();
+        // Initialize a media-router-container before each test.
+        container = document.createElement('media-router-container');
+        document.body.appendChild(container);
+
+        // Get common functions and variables.
+        var test_base = media_router_container_test_base.init(container);
+
+        checkCurrentView = test_base.checkCurrentView;
+        checkElementsVisibleWithId = test_base.checkElementsVisibleWithId;
+        checkElementText = test_base.checkElementText;
+        fakeBlockingIssue = test_base.fakeBlockingIssue;
+        fakeCastModeList = test_base.fakeCastModeList;
+        fakeCastModeListWithNonDefaultModesOnly =
+            test_base.fakeCastModeListWithNonDefaultModesOnly;
+        fakeNonBlockingIssue = test_base.fakeNonBlockingIssue;
+        fakeSinkList = test_base.fakeSinkList;
+
+        container.castModeList = test_base.fakeCastModeList;
+
+        // Allow for the media router container to be created and attached.
+        setTimeout(done);
+      });
+
+      // Container remains in auto mode even if the cast mode list changed.
+      test('cast mode list updated in auto mode', function(done) {
+        assertEquals(media_router.AUTO_CAST_MODE.description,
+            container.headerText);
+        assertEquals(media_router.CastModeType.AUTO,
+            container.shownCastModeValue_);
+        assertFalse(container.userHasSelectedCastMode_);
+
+        container.castModeList = fakeCastModeList.slice(1);
+        setTimeout(function() {
+          assertEquals(media_router.AUTO_CAST_MODE.description,
+              container.headerText);
+          assertEquals(media_router.CastModeType.AUTO,
+              container.shownCastModeValue_);
+          assertFalse(container.userHasSelectedCastMode_);
+          done();
+        });
+      });
+
+      // Tests that |container| returns to SINK_LIST view and arrow drop icon
+      // toggles after a cast mode is selected.
+      test('select cast mode', function(done) {
+        container.castModeList = fakeCastModeListWithNonDefaultModesOnly;
+
+        MockInteractions.tap(container.$['container-header'].
+            $['arrow-drop-icon']);
+        checkCurrentView(media_router.MediaRouterView.CAST_MODE_LIST);
+
+        setTimeout(function() {
+          var castModeList =
+              container.$$('#cast-mode-list').querySelectorAll('paper-item');
+
+          MockInteractions.tap(castModeList[2]);
+          checkCurrentView(media_router.MediaRouterView.SINK_LIST);
+          done();
+        });
+      });
+
+      // Tests that clicking on the drop down icon will toggle |container|
+      // between SINK_LIST and CAST_MODE_LIST views.
+      test('click drop down icon', function() {
+        checkCurrentView(media_router.MediaRouterView.SINK_LIST);
+
+        MockInteractions.tap(container.$['container-header'].
+            $['arrow-drop-icon']);
+        checkCurrentView(media_router.MediaRouterView.CAST_MODE_LIST);
+
+        MockInteractions.tap(container.$['container-header'].
+            $['arrow-drop-icon']);
+        checkCurrentView(media_router.MediaRouterView.SINK_LIST);
+      });
+
+      // Tests the header text. Choosing a cast mode updates the header text.
+      test('header text with no default cast modes', function(done) {
+        assertEquals(loadTimeData.getString('selectCastModeHeader'),
+            container.selectCastModeHeaderText_);
+
+        // The container is currently in auto cast mode, since we have not
+        // picked a cast mode explicitly, and the sinks is not compatible
+        // with exactly one cast mode.
+        assertEquals(media_router.AUTO_CAST_MODE.description,
+            container.headerText);
+        assertFalse(container.userHasSelectedCastMode_);
+
+        container.castModeList = fakeCastModeListWithNonDefaultModesOnly;
+
+        // Switch to cast mode list view.
+        MockInteractions.tap(container.$['container-header'].
+            $['arrow-drop-icon']);
+        setTimeout(function() {
+          var castModeList =
+              container.$$('#cast-mode-list').querySelectorAll('paper-item');
+          assertEquals(fakeCastModeListWithNonDefaultModesOnly.length,
+              castModeList.length);
+          for (var i = 0; i < castModeList.length; i++) {
+            MockInteractions.tap(castModeList[i]);
+            assertEquals(
+                fakeCastModeListWithNonDefaultModesOnly[i].description,
+                container.headerText);
+            checkElementText(
+                fakeCastModeListWithNonDefaultModesOnly[i].description,
+                castModeList[i]);
+          }
+
+          done();
+        });
+      });
+
+      // Tests the header text when updated with a cast mode list with a mix of
+      // default and non-default cast modes.
+      test('cast modes with one default mode', function(done) {
+        container.castModeList = fakeCastModeList;
+
+        // Switch to cast mode list view.
+        MockInteractions.tap(container.$['container-header'].
+            $['arrow-drop-icon']);
+        setTimeout(function() {
+          var castModeList =
+              container.$$('#cast-mode-list').querySelectorAll('paper-item');
+
+          for (var i = 0; i < fakeCastModeList.length; i++) {
+            MockInteractions.tap(castModeList[i]);
+            if (fakeCastModeList[i].type ==
+                media_router.CastModeType.DEFAULT) {
+              assertEquals(fakeCastModeList[i].description,
+                  container.headerText);
+
+              checkElementText(fakeCastModeList[i].host, castModeList[i]);
+            } else {
+              assertEquals(fakeCastModeList[i].description,
+                  container.headerText);
+              checkElementText(fakeCastModeList[i].description,
+                  castModeList[i]);
+            }
+          }
+
+          done();
+        });
+      });
+
+      // Tests for expected visible UI when the view is CAST_MODE_LIST.
+      test('cast mode list state visibility', function(done) {
+        container.showCastModeList_();
+        setTimeout(function() {
+          checkElementsVisibleWithId(['cast-mode-list',
+                                      'container-header',
+                                      'device-missing']);
+
+          // Set a non-blocking issue. The issue should stay hidden.
+          container.issue = fakeNonBlockingIssue;
+          setTimeout(function() {
+            checkElementsVisibleWithId(['cast-mode-list',
+                                        'container-header',
+                                        'device-missing']);
+
+            // Set a blocking issue. The issue should stay hidden.
+            container.issue = fakeBlockingIssue;
+            setTimeout(function() {
+              checkElementsVisibleWithId(['container-header',
+                                          'device-missing',
+                                          'issue-banner']);
+              done();
+            });
+          });
+        });
+      });
+
+      // If the container is not in auto mode, and the mode it is currently in
+      // no longer exists in the list of cast modes, then switch back to auto
+      // mode.
+      test('cast mode list updated in selected cast mode', function(done) {
+        assertEquals(media_router.AUTO_CAST_MODE.description,
+            container.headerText);
+        assertEquals(media_router.CastModeType.AUTO,
+            container.shownCastModeValue_);
+        assertFalse(container.userHasSelectedCastMode_);
+
+        MockInteractions.tap(container.$['container-header'].
+            $['arrow-drop-icon']);
+        setTimeout(function() {
+          var castModeList =
+                container.$$('#cast-mode-list').querySelectorAll('paper-item');
+          MockInteractions.tap(castModeList[0]);
+          setTimeout(function() {
+            assertEquals(fakeCastModeList[0].description, container.headerText);
+            assertEquals(fakeCastModeList[0].type,
+                container.shownCastModeValue_);
+            assertTrue(container.userHasSelectedCastMode_);
+            container.castModeList = fakeCastModeList.slice(1);
+            setTimeout(function() {
+              assertEquals(media_router.AUTO_CAST_MODE.description,
+                  container.headerText);
+              assertEquals(media_router.CastModeType.AUTO,
+                  container.shownCastModeValue_);
+              assertFalse(container.userHasSelectedCastMode_);
+              done();
+            });
+          });
+        });
+      });
+
+      // Tests that after a different cast mode is selected, the sink list will
+      // change based on the sinks compatibility with the new cast mode.
+      test('changing cast mode changes sink list', function(done) {
+        container.allSinks = fakeSinkList;
+
+        MockInteractions.tap(container.$['container-header'].
+            $['arrow-drop-icon']);
+        setTimeout(function() {
+          var castModeList =
+                container.$$('#cast-mode-list').querySelectorAll('paper-item');
+          MockInteractions.tap(castModeList[0]);
+          assertEquals(fakeCastModeList[0].description, container.headerText);
+
+          setTimeout(function() {
+            var sinkList =
+                container.$['sink-list'].querySelectorAll('paper-item');
+
+            // The sink list is empty because none of the sinks in fakeSinkList
+            // is compatible with cast mode 0.
+            assertEquals(0, sinkList.length);
+            MockInteractions.tap(castModeList[2]);
+            assertEquals(fakeCastModeList[2].description, container.headerText);
+
+            setTimeout(function() {
+              var sinkList =
+                  container.$['sink-list'].querySelectorAll('paper-item');
+              assertEquals(3, sinkList.length);
+              done();
+            });
+          });
+        });
+      });
+
+      // Tests that the sink list does not contain any sinks that are not
+      // compatible with the selected cast mode and are not associated with a
+      // route.
+      test('sink list in user selected cast mode', function(done) {
+        var newSinks = [
+          new media_router.Sink('sink id 10', 'Sink 10', null, null,
+              media_router.SinkIconType.CAST,
+              media_router.SinkStatus.ACTIVE, 0x4 | 0x8),
+          new media_router.Sink('sink id 20', 'Sink 20', null, null,
+              media_router.SinkIconType.CAST,
+              media_router.SinkStatus.ACTIVE, 0x2 | 0x4 | 0x8),
+          new media_router.Sink('sink id 30', 'Sink 30', null, null,
+              media_router.SinkIconType.CAST,
+              media_router.SinkStatus.PENDING, 0x4 | 0x8),
+        ];
+
+        container.allSinks = newSinks;
+        container.routeList = [
+          new media_router.Route('id 1', 'sink id 30',
+                                 'Title 1', 1, false, false),
+        ];
+
+        setTimeout(function() {
+          var sinkList =
+              container.$['sink-list'].querySelectorAll('paper-item');
+
+          // Since we haven't selected a cast mode, we don't filter sinks.
+          assertEquals(3, sinkList.length);
+
+          MockInteractions.tap(container.$['container-header'].
+              $['arrow-drop-icon']);
+          setTimeout(function() {
+            // Cast mode 1 is selected, and the sink list is filtered.
+            var castModeList =
+                container.$$('#cast-mode-list').querySelectorAll('paper-item');
+            MockInteractions.tap(castModeList[1]);
+            assertEquals(fakeCastModeList[1].description, container.headerText);
+            assertEquals(fakeCastModeList[1].type,
+                container.shownCastModeValue_);
+
+            setTimeout(function() {
+              var sinkList =
+                  container.$['sink-list'].querySelectorAll('paper-item');
+
+              // newSinks[0] got filtered out since it is not compatible with
+              // cast mode 1.
+              // 'Sink 20' should be on the list because it contains the
+              // selected cast mode. (sinkList[0] = newSinks[1])
+              // 'Sink 30' should be on the list because it has a route.
+              // (sinkList[1] = newSinks[2])
+              assertEquals(2, sinkList.length);
+              checkElementText(newSinks[1].name, sinkList[0]);
+
+              // |sinkList[1]| contains route title in addition to sink name.
+              assertTrue(sinkList[1].textContent.trim().startsWith(
+                  newSinks[2].name.trim()));
+
+              // Cast mode is not switched back even if there are no sinks
+              // compatible with selected cast mode, because we explicitly
+              // selected that cast mode.
+              container.allSinks = [];
+              setTimeout(function() {
+                assertEquals(fakeCastModeList[1].description,
+                    container.headerText);
+                assertEquals(fakeCastModeList[1].type,
+                    container.shownCastModeValue_);
+                var sinkList =
+                    container.$['sink-list'].querySelectorAll('paper-item');
+                assertEquals(0, sinkList.length);
+                done();
+              });
+            });
+          });
+        });
+      });
+    });
+  }
+
+  return {
+    registerTests: registerTests,
+  };
+});
diff --git a/chrome/test/data/webui/media_router/media_router_container_filter_tests.js b/chrome/test/data/webui/media_router/media_router_container_filter_tests.js
index 3128fb4d..70a9145 100644
--- a/chrome/test/data/webui/media_router/media_router_container_filter_tests.js
+++ b/chrome/test/data/webui/media_router/media_router_container_filter_tests.js
@@ -3,11 +3,43 @@
 // found in the LICENSE file.
 
 /** @fileoverview Suite of tests for media-router-container specifically related
- * to the filter view. */
+ * to the filter view.
+ */
 cr.define('media_router_container_filter', function() {
   function registerTests() {
     suite('MediaRouterContainerFilter', function() {
       /**
+       * Checks whether |view| matches the current view of |container|.
+       *
+       * @param {!media_router.MediaRouterView} view Expected view type.
+       */
+      var checkCurrentView;
+
+      /**
+       * Checks whether the elements specified in |elementIdList| are visible.
+       * Checks whether all other elements are not visible. Throws an assertion
+       * error if this is not true.
+       *
+       * @param {!Array<!string>} elementIdList List of id's of elements that
+       *     should be visible.
+       */
+      var checkElementsVisibleWithId;
+
+      /**
+       * Checks whether |expected| and the text in the |element| are equal.
+       *
+       * @param {!string} expected Expected text.
+       * @param {!Element} element Element whose text will be checked.
+       */
+      var checkElementText;
+
+      /**
+       * Media Router Container created before each test.
+       * @type {?MediaRouterContainer}
+       */
+      var container;
+
+      /**
        * The list of current routes.
        * @type {!Array<!media_router.Route>}
        */
@@ -20,73 +52,23 @@
       var fakeSinkList = [];
 
       /**
-       * The list of elements to check for visibility.
-       * @const {!Array<string>}
-       */
-      var hiddenCheckElementIdList = [
-        'cast-mode-list',
-        'container-header',
-        'device-missing',
-        'first-run-flow',
-        'first-run-flow-cloud-pref',
-        'issue-banner',
-        'no-search-matches',
-        'route-details',
-        'search-results',
-        'sink-list',
-        'sink-list-view',
-      ];
-
-      /**
        * Search text that will match all sinks.
-       * @type {string}
+       * @type {?string}
        */
       var searchTextAll;
 
       /**
        * Search text that won't match any sink in fakeSinkList.
-       * @type {string}
+       * @type {?string}
        */
       var searchTextNone;
 
       /**
        * Search text that will match exactly one sink.
-       * @type {string}
+       * @type {?string}
        */
       var searchTextOne;
 
-      // Checks whether |view| matches the current view of |container|.
-      var checkCurrentView = function(view) {
-        assertEquals(view, container.currentView_);
-      };
-
-      // Checks whether the elements specified in |elementIdList| are visible.
-      // Checks whether all other elements are not visible.
-      var checkElementsVisibleWithId = function(elementIdList) {
-        for (var i = 0; i < elementIdList.length; i++)
-          checkElementVisibleWithId(true, elementIdList[i]);
-
-        for (var j = 0; j < hiddenCheckElementIdList.length; j++) {
-          if (elementIdList.indexOf(hiddenCheckElementIdList[j]) == -1)
-            checkElementVisibleWithId(false, hiddenCheckElementIdList[j]);
-        }
-      };
-
-      // Checks the visibility of an element with |elementId| in |container|.
-      // An element is considered visible if it exists and its |hidden| property
-      // is |false|.
-      var checkElementVisibleWithId = function(visible, elementId) {
-        var element = container.$$('#' + elementId);
-        var elementVisible = !!element && !element.hidden &&
-            element.style.display != 'none';
-        assertEquals(visible, elementVisible, elementId);
-      };
-
-      // Checks whether |expected| and the text in the |element| are equal.
-      var checkElementText = function(expected, element) {
-        assertEquals(expected.trim(), element.textContent.trim());
-      };
-
       // Import media_router_container.html before running suite.
       suiteSetup(function() {
         return PolymerTest.importHtml(
@@ -94,49 +76,25 @@
             'media_router_container.html');
       });
 
-      // Initialize a media-router-container before each test.
       setup(function(done) {
         PolymerTest.clearBody();
+        // Initialize a media-router-container before each test.
         container = document.createElement('media-router-container');
         document.body.appendChild(container);
 
-        // Initialize local variables.
-        container.castModeList = [
-          new media_router.CastMode(0x1, 'Description 0', 'google.com'),
-          new media_router.CastMode(0x2, 'Description 1', null),
-          new media_router.CastMode(0x4, 'Description 2', null),
-        ];
+        // Get common functions and variables.
+        var test_base = media_router_container_test_base.init(container);
 
-        fakeRouteList = [
-          new media_router.Route('id 1', 'sink id 1',
-                                 'Title 1', 0, true, false),
-          new media_router.Route('id 2', 'sink id 2',
-                                 'Title 2', 1, false, true),
-        ];
+        checkCurrentView = test_base.checkCurrentView;
+        checkElementsVisibleWithId = test_base.checkElementsVisibleWithId;
+        checkElementText = test_base.checkElementText;
+        fakeRouteList = test_base.fakeRouteList;
+        fakeSinkList = test_base.fakeSinkList;
+        searchTextAll = test_base.searchTextAll;
+        searchTextNone = test_base.searchTextNone;
+        searchTextOne = test_base.searchTextOne;
 
-        fakeRouteListWithLocalRoutesOnly = [
-          new media_router.Route('id 1', 'sink id 1',
-                                 'Title 1', 0, true, false),
-          new media_router.Route('id 2', 'sink id 2',
-                                 'Title 2', 1, true, false),
-        ];
-
-        var castModeBitset = 0x2 | 0x4 | 0x8;
-        fakeSinkList = [
-          new media_router.Sink('sink id 1', 'Sink 1', null, null,
-              media_router.SinkIconType.CAST,
-              media_router.SinkStatus.ACTIVE, castModeBitset),
-          new media_router.Sink('sink id 2', 'Sink 2', null, null,
-              media_router.SinkIconType.CAST,
-              media_router.SinkStatus.ACTIVE, castModeBitset),
-          new media_router.Sink('sink id 3', 'Sink 3', null, null,
-              media_router.SinkIconType.CAST,
-              media_router.SinkStatus.PENDING, castModeBitset),
-        ];
-
-        searchTextAll = 'sink';
-        searchTextNone = 'abc';
-        searchTextOne = 'sink 1';
+        container.castModeList = test_base.fakeCastModeList;
 
         // Allow for the media router container to be created and attached.
         setTimeout(done);
diff --git a/chrome/test/data/webui/media_router/media_router_container_first_run_flow_tests.js b/chrome/test/data/webui/media_router/media_router_container_first_run_flow_tests.js
new file mode 100644
index 0000000..aa758df
--- /dev/null
+++ b/chrome/test/data/webui/media_router/media_router_container_first_run_flow_tests.js
@@ -0,0 +1,179 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/** @fileoverview Suite of tests for media-router-container that focus on the
+ * first run flow.
+ */
+cr.define('media_router_container_first_run_flow', function() {
+  function registerTests() {
+    suite('MediaRouterContainerFirstRunFlow', function() {
+      /**
+       * Checks whether the elements specified in |elementIdList| are visible.
+       * Checks whether all other elements are not visible. Throws an assertion
+       * error if this is not true.
+       *
+       * @param {!Array<!string>} elementIdList List of id's of elements that
+       *     should be visible.
+       */
+      var checkElementsVisibleWithId;
+
+      /**
+       * Checks the visibility of an element with |elementId| in |container|.
+       * An element is considered visible if it exists and its |hidden| property
+       * is |false|.
+       *
+       * @param {boolean} visible Whether the element should be visible.
+       * @param {!string} elementId The id of the element to test.
+       */
+      var checkElementVisibleWithId;
+
+      /**
+       * Media Router Container created before each test.
+       * @type {?MediaRouterContainer}
+       */
+      var container;
+
+      /**
+       * The list of CastModes to show.
+       * @type {!Array<!media_router.CastMode>}
+       */
+      var fakeCastModeList = [];
+
+      /**
+       * The list of CastModes to show with non-default modes only.
+       * @type {!Array<!media_router.CastMode>}
+       */
+      var fakeCastModeListWithNonDefaultModesOnly = [];
+
+      // Import media_router_container.html before running suite.
+      suiteSetup(function() {
+        return PolymerTest.importHtml(
+            'chrome://media-router/elements/media_router_container/' +
+            'media_router_container.html');
+      });
+
+      setup(function(done) {
+        PolymerTest.clearBody();
+        // Initialize a media-router-container before each test.
+        container = document.createElement('media-router-container');
+        document.body.appendChild(container);
+
+        // Get common functions and variables.
+        var test_base = media_router_container_test_base.init(container);
+
+        checkElementsVisibleWithId = test_base.checkElementsVisibleWithId;
+        checkElementVisibleWithId = test_base.checkElementVisibleWithId;
+        fakeCastModeList = test_base.fakeCastModeList;
+        fakeCastModeListWithNonDefaultModesOnly =
+            test_base.fakeCastModeListWithNonDefaultModesOnly;
+
+        container.castModeList = test_base.fakeCastModeList;
+
+        // Allow for the media router container to be created and attached.
+        setTimeout(done);
+      });
+
+      // Tests for 'acknowledge-first-run-flow' event firing when the
+      // 'first-run-button' button is clicked and the cloud preference checkbox
+      // is not shown.
+      test('first run button click', function(done) {
+        container.showFirstRunFlow = true;
+
+        setTimeout(function() {
+          container.addEventListener('acknowledge-first-run-flow',
+              function(data) {
+            assertEquals(undefined, data.detail.optedIntoCloudServices);
+            done();
+          });
+          MockInteractions.tap(container.shadowRoot.getElementById(
+              'first-run-button'));
+        });
+      });
+
+      // Tests for 'acknowledge-first-run-flow' event firing when the
+      // 'first-run-button' button is clicked and the cloud preference checkbox
+      // is also shown.
+      test('first run button with cloud pref click', function(done) {
+        container.showFirstRunFlow = true;
+        container.showFirstRunFlowCloudPref = true;
+
+        setTimeout(function() {
+          container.addEventListener('acknowledge-first-run-flow',
+              function(data) {
+            assertTrue(data.detail.optedIntoCloudServices);
+            done();
+          });
+          MockInteractions.tap(container.shadowRoot.getElementById(
+              'first-run-button'));
+        });
+      });
+
+      // Tests for 'acknowledge-first-run-flow' event firing when the
+      // 'first-run-button' button is clicked after the cloud preference
+      // checkbox is deselected.
+      test('first run button with cloud pref deselected click',
+          function(done) {
+        container.showFirstRunFlow = true;
+        container.showFirstRunFlowCloudPref = true;
+
+        setTimeout(function() {
+          container.addEventListener('acknowledge-first-run-flow',
+              function(data) {
+            assertFalse(data.detail.optedIntoCloudServices);
+            done();
+          });
+          MockInteractions.tap(container.shadowRoot.getElementById(
+              'first-run-cloud-checkbox'));
+          MockInteractions.tap(container.shadowRoot.getElementById(
+              'first-run-button'));
+        });
+      });
+
+      // Tests for the expected visible UI when interacting with the first run
+      // flow.
+      test('first run button visibility', function(done) {
+        container.showFirstRunFlow = true;
+
+        setTimeout(function() {
+          checkElementVisibleWithId(true, 'first-run-flow');
+          MockInteractions.tap(container.shadowRoot.getElementById(
+              'first-run-button'));
+
+          setTimeout(function() {
+            checkElementVisibleWithId(false, 'first-run-flow');
+            done();
+          });
+        });
+      });
+
+      // Tests for the expected visible UI when interacting with the first run
+      // flow with cloud services preference.
+      test('first run button visibility', function(done) {
+        container.showFirstRunFlow = true;
+        container.showFirstRunFlowCloudPref = true;
+
+        setTimeout(function() {
+          checkElementsVisibleWithId(['container-header',
+                                      'device-missing',
+                                      'first-run-flow',
+                                      'first-run-flow-cloud-pref',
+                                      'sink-list-view']);
+          MockInteractions.tap(container.shadowRoot.getElementById(
+              'first-run-button'));
+
+          setTimeout(function() {
+            checkElementsVisibleWithId(['container-header',
+                                        'device-missing',
+                                        'sink-list-view']);
+            done();
+          });
+        });
+      });
+    });
+  }
+
+  return {
+    registerTests: registerTests,
+  };
+});
diff --git a/chrome/test/data/webui/media_router/media_router_container_route_tests.js b/chrome/test/data/webui/media_router/media_router_container_route_tests.js
new file mode 100644
index 0000000..95ed483
--- /dev/null
+++ b/chrome/test/data/webui/media_router/media_router_container_route_tests.js
@@ -0,0 +1,344 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/** @fileoverview Suite of tests for media-router-container that focus on
+ * routes.
+ */
+cr.define('media_router_container_route', function() {
+  function registerTests() {
+    suite('MediaRouterContainerRoute', function() {
+      /**
+       * Checks whether |view| matches the current view of |container|.
+       *
+       * @param {!media_router.MediaRouterView} view Expected view type.
+       */
+      var checkCurrentView;
+
+      /**
+       * Checks whether the elements specified in |elementIdList| are visible.
+       * Checks whether all other elements are not visible. Throws an assertion
+       * error if this is not true.
+       *
+       * @param {!Array<!string>} elementIdList List of id's of elements that
+       *     should be visible.
+       */
+      var checkElementsVisibleWithId;
+
+      /**
+       * Checks whether |expected| and the text in the |element| are equal.
+       *
+       * @param {!string} expected Expected text.
+       * @param {!Element} element Element whose text will be checked.
+       */
+      var checkElementText;
+
+      /**
+       * Media Router Container created before each test.
+       * @type {?MediaRouterContainer}
+       */
+      var container;
+
+      /**
+       * The blocking issue to show.
+       * @type {?media_router.Issue}
+       */
+      var fakeBlockingIssue;
+
+      /**
+       * The list of CastModes to show.
+       * @type {!Array<!media_router.CastMode>}
+       */
+      var fakeCastModeList = [];
+
+      /**
+       * The blocking issue to show.
+       * @type {?media_router.Issue}
+       */
+      var fakeNonBlockingIssue;
+
+      /**
+       * The list of current routes.
+       * @type {!Array<!media_router.Route>}
+       */
+      var fakeRouteList = [];
+
+      /**
+       * The list of available sinks.
+       * @type {!Array<!media_router.Sink>}
+       */
+      var fakeSinkList = [];
+
+      // Import media_router_container.html before running suite.
+      suiteSetup(function() {
+        return PolymerTest.importHtml(
+            'chrome://media-router/elements/media_router_container/' +
+            'media_router_container.html');
+      });
+
+      setup(function(done) {
+        PolymerTest.clearBody();
+        // Initialize a media-router-container before each test.
+        container = document.createElement('media-router-container');
+        document.body.appendChild(container);
+
+        // Get common functions and variables.
+        var test_base = media_router_container_test_base.init(container);
+
+        checkCurrentView = test_base.checkCurrentView;
+        checkElementsVisibleWithId = test_base.checkElementsVisibleWithId;
+        checkElementText = test_base.checkElementText;
+        fakeBlockingIssue = test_base.fakeBlockingIssue;
+        fakeCastModeList = test_base.fakeCastModeList;
+        fakeNonBlockingIssue = test_base.fakeNonBlockingIssue;
+        fakeRouteList = test_base.fakeRouteList;
+        fakeRouteListWithLocalRoutesOnly =
+            test_base.fakeRouteListWithLocalRoutesOnly;
+        fakeSinkList = test_base.fakeSinkList;
+
+        container.castModeList = test_base.fakeCastModeList;
+
+        // Allow for the media router container to be created and attached.
+        setTimeout(done);
+      });
+
+      // Tests for 'create-route' event firing when a sink with no associated
+      // route is clicked.
+      test('select sink without a route', function(done) {
+        container.allSinks = fakeSinkList;
+
+        setTimeout(function() {
+          var sinkList =
+              container.$['sink-list'].querySelectorAll('paper-item');
+          container.addEventListener('create-route', function(data) {
+            // Container is initially in auto mode since a cast mode has not
+            // been selected.
+            assertEquals(media_router.CastModeType.AUTO,
+                container.shownCastModeValue_);
+            assertEquals(fakeSinkList[2].id, data.detail.sinkId);
+
+            // The preferred compatible cast mode on the sink is used, since
+            // the we did not choose a cast mode on the container.
+            assertEquals(0x2, data.detail.selectedCastModeValue);
+            done();
+          });
+          // Tap on a sink without a route, which should fire a 'create-route'
+          // event.
+          assertEquals(fakeSinkList.length, sinkList.length);
+          MockInteractions.tap(sinkList[2]);
+        });
+      });
+
+      // Tests that selecting a sink with an associated route will make the
+      // |container| switch to ROUTE_DETAILS view.
+      test('select sink with a route', function(done) {
+        container.allSinks = fakeSinkList;
+        container.routeList = fakeRouteList;
+
+        setTimeout(function() {
+          var sinkList =
+              container.$['sink-list'].querySelectorAll('paper-item');
+
+          // Start from the SINK_LIST view.
+          container.showSinkList_();
+          checkCurrentView(media_router.MediaRouterView.SINK_LIST);
+          MockInteractions.tap(sinkList[0]);
+          checkCurrentView(media_router.MediaRouterView.ROUTE_DETAILS);
+          done();
+        });
+      });
+
+      // Tests the text shown for the sink list.
+      test('initial sink list route text', function(done) {
+        // Sink 1 - no sink description, no route -> no subtext
+        // Sink 2 - sink description, no route -> subtext = sink description
+        // Sink 3 - no sink description, route -> subtext = route description
+        // Sink 4 - sink description, route -> subtext = route description
+        container.allSinks = [
+            new media_router.Sink('sink id 1', 'Sink 1', null, null,
+                media_router.SinkIconType.CAST,
+                media_router.SinkStatus.ACTIVE, [1, 2, 3]),
+            new media_router.Sink('sink id 2', 'Sink 2',
+                'Sink 2 description', null,
+                media_router.SinkIconType.CAST,
+                media_router.SinkStatus.ACTIVE, [1, 2, 3]),
+            new media_router.Sink('sink id 3', 'Sink 3', null, null,
+                media_router.SinkIconType.CAST,
+                media_router.SinkStatus.PENDING, [1, 2, 3]),
+            new media_router.Sink('sink id 4', 'Sink 4',
+                'Sink 4 description', null,
+                media_router.SinkIconType.CAST,
+                media_router.SinkStatus.PENDING, [1, 2, 3])
+        ];
+
+        container.routeList = [
+            new media_router.Route('id 3', 'sink id 3', 'Title 3', 0, true),
+            new media_router.Route('id 4', 'sink id 4', 'Title 4', 1, false),
+        ];
+
+        setTimeout(function() {
+          var sinkSubtextList =
+              container.$['sink-list'].querySelectorAll('.sink-subtext');
+
+          // There will only be 3 sink subtext entries, because Sink 1 does not
+          // have any subtext.
+          assertEquals(3, sinkSubtextList.length);
+
+          checkElementText(container.allSinks[1].description,
+              sinkSubtextList[0]);
+
+          // Route description overrides sink description for subtext.
+          checkElementText(container.routeList[0].description,
+              sinkSubtextList[1]);
+
+          checkElementText(container.routeList[1].description,
+              sinkSubtextList[2]);
+          done();
+        });
+      });
+
+      // Tests the expected view when there is only one local active route and
+      // media_router_container is created for the first time.
+      test('initial view with one local route', function() {
+        container.allSinks = fakeSinkList;
+        container.routeList = fakeRouteList;
+        container.maybeShowRouteDetailsOnOpen();
+
+        checkCurrentView(media_router.MediaRouterView.ROUTE_DETAILS);
+      });
+
+      // Tests the expected view when there are multiple local active routes
+      // and media_router_container is created for the first time.
+      test('initial view with multiple local routes', function() {
+        container.allSinks = fakeSinkList;
+        container.routeList = fakeRouteListWithLocalRoutesOnly;
+
+        checkCurrentView(media_router.MediaRouterView.SINK_LIST);
+      });
+
+      // Tests the expected view when there are no local active routes and
+      // media_router_container is created for the first time.
+      test('initial view with no local route', function() {
+        container.allSinks = fakeSinkList;
+        container.routeList = [];
+
+        checkCurrentView(media_router.MediaRouterView.SINK_LIST);
+      });
+
+      // Tests the expected view when there are no local active routes and
+      // media_router_container is created for the first time.
+      test('view after route is closed remotely', function() {
+        container.allSinks = fakeSinkList;
+        container.routeList = fakeRouteList;
+        container.maybeShowRouteDetailsOnOpen();
+        checkCurrentView(media_router.MediaRouterView.ROUTE_DETAILS);
+
+        container.routeList = [];
+        checkCurrentView(media_router.MediaRouterView.SINK_LIST);
+      });
+
+      // Tests for expected visible UI when the view is ROUTE_DETAILS.
+      test('route details visibility', function(done) {
+        container.showRouteDetails_();
+        setTimeout(function() {
+          checkElementsVisibleWithId(['container-header',
+                                      'device-missing',
+                                      'route-details']);
+          done();
+        });
+      });
+
+      test('updated route in route details', function(done) {
+        container.allSinks = fakeSinkList;
+        var description = 'Title';
+        var route = new media_router.Route(
+            'id 1', 'sink id 1', description, 0, true, false);
+        container.routeList = [route];
+        container.showRouteDetails_(route);
+        setTimeout(function() {
+          // Note that sink-list-view is hidden.
+          checkElementsVisibleWithId(
+              ['container-header', 'route-details', 'sink-list']);
+          assertTrue(!!container.currentRoute_);
+          assertEquals(description, container.currentRoute_.description);
+
+          var newDescription = 'Foo';
+          route.description = newDescription;
+          container.routeList = [route];
+          setTimeout(function() {
+            // Note that sink-list-view is hidden.
+            checkElementsVisibleWithId(
+                ['container-header', 'route-details', 'sink-list']);
+            assertTrue(!!container.currentRoute_);
+            assertEquals(newDescription, container.currentRoute_.description);
+            done();
+          });
+        });
+      });
+
+      // Tests for expected visible UI when the view is ROUTE_DETAILS, and there
+      // is a non-blocking issue.
+      test('route details visibility non blocking issue', function(done) {
+        container.showRouteDetails_();
+
+        // Set a non-blocking issue. The issue should be shown.
+        container.issue = fakeNonBlockingIssue;
+        setTimeout(function() {
+          checkElementsVisibleWithId(['container-header',
+                                      'device-missing',
+                                      'route-details']);
+          done();
+        });
+      });
+
+      // Tests for expected visible UI when the view is ROUTE_DETAILS, and there
+      // is a blocking issue.
+      test('route details visibility with blocking issue', function(done) {
+        container.showRouteDetails_();
+
+        // Set a blocking issue. The issue should be shown, and everything
+        // else, hidden.
+        container.issue = fakeBlockingIssue;
+        setTimeout(function() {
+          checkElementsVisibleWithId(['container-header',
+                                      'device-missing',
+                                      'issue-banner']);
+          done();
+         });
+      });
+
+      test('creating route with selected cast mode', function(done) {
+        container.allSinks = fakeSinkList;
+        MockInteractions.tap(container.$['container-header'].
+            $['arrow-drop-icon']);
+        setTimeout(function() {
+          // Select cast mode 2.
+          var castModeList =
+              container.$$('#cast-mode-list').querySelectorAll('paper-item');
+          MockInteractions.tap(castModeList[1]);
+          assertEquals(fakeCastModeList[1].description, container.headerText);
+          setTimeout(function() {
+            var sinkList =
+                container.$['sink-list'].querySelectorAll('paper-item');
+            container.addEventListener('create-route', function(data) {
+              assertEquals(fakeSinkList[2].id, data.detail.sinkId);
+              // Cast mode 2 is used, since we selected it explicitly.
+              assertEquals(fakeCastModeList[1].type,
+                           data.detail.selectedCastModeValue);
+              done();
+            });
+            // All sinks are compatible with cast mode 2.
+            assertEquals(fakeSinkList.length, sinkList.length);
+            // Tap on a sink without a route, which should fire a 'create-route'
+            // event.
+            MockInteractions.tap(sinkList[2]);
+          });
+        });
+      });
+    });
+  }
+
+  return {
+    registerTests: registerTests,
+  };
+});
diff --git a/chrome/test/data/webui/media_router/media_router_container_sink_list_tests.js b/chrome/test/data/webui/media_router/media_router_container_sink_list_tests.js
new file mode 100644
index 0000000..91ad26f
--- /dev/null
+++ b/chrome/test/data/webui/media_router/media_router_container_sink_list_tests.js
@@ -0,0 +1,286 @@
+// 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.
+
+/** @fileoverview Suite of tests for media-router-container that focus on the
+ * sink list.
+ */
+cr.define('media_router_container_sink_list', function() {
+  function registerTests() {
+    suite('MediaRouterContainerSinkList', function() {
+      /**
+       * Checks whether the elements specified in |elementIdList| are visible.
+       * Checks whether all other elements are not visible. Throws an assertion
+       * error if this is not true.
+       *
+       * @param {!Array<!string>} elementIdList List of id's of elements that
+       *     should be visible.
+       */
+      var checkElementsVisibleWithId;
+
+      /**
+       * Checks whether |expected| and the text in the |element| are equal.
+       *
+       * @param {!string} expected Expected text.
+       * @param {!Element} element Element whose text will be checked.
+       */
+      var checkElementText;
+
+      /**
+       * Media Router Container created before each test.
+       * @type {?MediaRouterContainer}
+       */
+      var container;
+
+      /**
+       * The blocking issue to show.
+       * @type {?media_router.Issue}
+       */
+      var fakeBlockingIssue;
+
+      /**
+       * The list of CastModes to show.
+       * @type {!Array<!media_router.CastMode>}
+       */
+      var fakeCastModeList = [];
+
+      /**
+       * The blocking issue to show.
+       * @type {?media_router.Issue}
+       */
+      var fakeNonBlockingIssue;
+
+      /**
+       * The list of available sinks.
+       * @type {!Array<!media_router.Sink>}
+       */
+      var fakeSinkList = [];
+
+      // Import media_router_container.html before running suite.
+      suiteSetup(function() {
+        return PolymerTest.importHtml(
+            'chrome://media-router/elements/media_router_container/' +
+            'media_router_container.html');
+      });
+
+      setup(function(done) {
+        PolymerTest.clearBody();
+        // Initialize a media-router-container before each test.
+        container = document.createElement('media-router-container');
+        document.body.appendChild(container);
+
+        // Get common functions and variables.
+        var test_base = media_router_container_test_base.init(container);
+
+        checkElementsVisibleWithId = test_base.checkElementsVisibleWithId;
+        checkElementText = test_base.checkElementText;
+        fakeBlockingIssue = test_base.fakeBlockingIssue;
+        fakeCastModeList = test_base.fakeCastModeList;
+        fakeNonBlockingIssue = test_base.fakeNonBlockingIssue;
+        fakeSinkList = test_base.fakeSinkList;
+
+        container.castModeList = test_base.fakeCastModeList;
+
+        // Allow for the media router container to be created and attached.
+        setTimeout(done);
+      });
+
+      // Tests that text shown for each sink matches their names.
+      test('sink list text', function(done) {
+        container.allSinks = fakeSinkList;
+
+        setTimeout(function() {
+          var sinkList =
+              container.$['sink-list'].querySelectorAll('paper-item');
+          assertEquals(fakeSinkList.length, sinkList.length);
+          for (var i = 0; i < fakeSinkList.length; i++) {
+            checkElementText(fakeSinkList[i].name, sinkList[i]);
+          }
+          done();
+        });
+      });
+
+      // Tests that text shown for sink with domain matches the name and domain.
+      test('sink with domain text', function(done) {
+        // Sink 1 - sink, no domain -> text = name
+        // Sink 2 - sink, domain -> text = sink + domain
+        container.allSinks = [
+            new media_router.Sink('sink id 1', 'Sink 1', null, null,
+                media_router.SinkIconType.HANGOUT,
+                media_router.SinkStatus.ACTIVE, [1, 2, 3]),
+            new media_router.Sink('sink id 2', 'Sink 2',
+                null, 'example.com',
+                media_router.SinkIconType.HANGOUT,
+                media_router.SinkStatus.ACTIVE, [1, 2, 3]),
+        ];
+
+        container.showDomain = true;
+
+        setTimeout(function() {
+          var sinkList =
+              container.$['sink-list'].querySelectorAll('paper-item');
+          assertEquals(2, sinkList.length);
+
+          // |sinkList[0]| has sink name only.
+          checkElementText(container.allSinks[0].name, sinkList[0]);
+          // |sinkList[1]| contains sink name and domain.
+          assertTrue(sinkList[1].textContent.trim().startsWith(
+              container.allSinks[1].name.trim()));
+          assertTrue(sinkList[1].textContent.trim().indexOf(
+              container.allSinks[1].domain.trim()) != -1);
+          done();
+        });
+      });
+
+      // Tests that domain text is not shown when |showDomain| is false.
+      test('sink with domain text', function(done) {
+        // Sink 1 - sink, no domain -> text = name
+        // Sink 2 - sink, domain -> text = sink + domain
+        container.allSinks = [
+            new media_router.Sink('sink id 1', 'Sink 1', null, null,
+                media_router.SinkIconType.HANGOUT,
+                media_router.SinkStatus.ACTIVE, [1, 2, 3]),
+            new media_router.Sink('sink id 2', 'Sink 2',
+                null, 'example.com',
+                media_router.SinkIconType.HANGOUT,
+                media_router.SinkStatus.ACTIVE, [1, 2, 3]),
+        ];
+
+        container.showDomain = false;
+
+        setTimeout(function() {
+          var sinkList =
+              container.$['sink-list'].querySelectorAll('paper-item');
+          assertEquals(2, sinkList.length);
+
+          // |sinkList[0]| has sink name only.
+          checkElementText(container.allSinks[0].name, sinkList[0]);
+          // |sinkList[1]| has sink name but domain should be hidden.
+          checkElementText(container.allSinks[1].name, sinkList[1]);
+          assertTrue(sinkList[1].textContent.trim().indexOf(
+              container.allSinks[1].domain.trim()) == -1);
+          done();
+        });
+      });
+
+      // Tests for expected visible UI when the view is SINK_LIST.
+      test('sink list state visibility', function() {
+        container.showSinkList_();
+        checkElementsVisibleWithId(['container-header',
+                                    'device-missing',
+                                    'sink-list-view']);
+
+        // Set an non-empty sink list.
+        container.allSinks = fakeSinkList;
+        checkElementsVisibleWithId(['container-header',
+                                    'sink-list',
+                                    'sink-list-view']);
+      });
+
+      // Tests for expected visible UI when the view is SINK_LIST, and there is
+      // a non blocking issue.
+      test('sink list visibility non blocking issue', function(done) {
+        container.showSinkList_();
+
+        // Set an non-empty sink list.
+        container.allSinks = fakeSinkList;
+
+        // Set a non-blocking issue. The issue should be shown.
+        container.issue = fakeNonBlockingIssue;
+        setTimeout(function() {
+          checkElementsVisibleWithId(['container-header',
+                                      'issue-banner',
+                                      'sink-list',
+                                      'sink-list-view']);
+          done();
+        });
+      });
+
+      // Tests for expected visible UI when the view is SINK_LIST, and there is
+      // a blocking issue.
+      test('sink list visibility blocking issue', function(done) {
+        container.showSinkList_();
+
+        // Set an non-empty sink list.
+        container.allSinks = fakeSinkList;
+
+        // Set a blocking issue. The issue should be shown, and everything
+        // else, hidden.
+        container.issue = fakeBlockingIssue;
+        setTimeout(function() {
+          checkElementsVisibleWithId(['container-header',
+                                      'issue-banner',
+                                      'sink-list']);
+          done();
+        });
+      });
+
+      // Tests all sinks are always shown in auto mode, and that the mode will
+      // switch if the sinks support only 1 cast mode.
+      test('sink list in auto mode', function(done) {
+        container.allSinks = fakeSinkList;
+        setTimeout(function() {
+          // Container is initially in auto mode since a cast mode has not been
+          // selected.
+          assertEquals(media_router.AUTO_CAST_MODE.description,
+              container.headerText);
+          assertEquals(media_router.CastModeType.AUTO,
+              container.shownCastModeValue_);
+          assertFalse(container.userHasSelectedCastMode_);
+          var sinkList =
+              container.$['sink-list'].querySelectorAll('paper-item');
+
+          // All sinks are shown in auto mode.
+          assertEquals(3, sinkList.length);
+
+          // When sink list changes to only 1 compatible cast mode, the mode is
+          // switched, and all sinks are shown.
+          container.allSinks = [
+            new media_router.Sink('sink id 10', 'Sink 10', null, null,
+                media_router.SinkIconType.CAST,
+                media_router.SinkStatus.ACTIVE, 0x4),
+            new media_router.Sink('sink id 20', 'Sink 20', null, null,
+                media_router.SinkIconType.CAST,
+                media_router.SinkStatus.ACTIVE, 0x4),
+            new media_router.Sink('sink id 30', 'Sink 30', null, null,
+                media_router.SinkIconType.CAST,
+                media_router.SinkStatus.PENDING, 0x4),
+          ];
+
+          setTimeout(function() {
+            assertEquals(fakeCastModeList[2].description, container.headerText);
+            assertEquals(fakeCastModeList[2].type,
+                container.shownCastModeValue_);
+            assertFalse(container.userHasSelectedCastMode_);
+
+            var sinkList =
+                container.$['sink-list'].querySelectorAll('paper-item');
+            assertEquals(3, sinkList.length);
+
+            // When compatible cast modes size is no longer exactly 1, switch
+            // back to auto mode, and all sinks are shown.
+            container.allSinks = fakeSinkList;
+            setTimeout(function() {
+              assertEquals(media_router.AUTO_CAST_MODE.description,
+                  container.headerText);
+              assertEquals(media_router.CastModeType.AUTO,
+                  container.shownCastModeValue_);
+              assertFalse(container.userHasSelectedCastMode_);
+              var sinkList =
+                  container.$['sink-list'].querySelectorAll('paper-item');
+
+              // All sinks are shown in auto mode.
+              assertEquals(3, sinkList.length);
+
+              done();
+            });
+          });
+        });
+      });
+    });
+  }
+
+  return {
+    registerTests: registerTests,
+  };
+});
diff --git a/chrome/test/data/webui/media_router/media_router_container_test_base.js b/chrome/test/data/webui/media_router/media_router_container_test_base.js
new file mode 100644
index 0000000..45d6d64
--- /dev/null
+++ b/chrome/test/data/webui/media_router/media_router_container_test_base.js
@@ -0,0 +1,190 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/** @fileoverview Provides basic utility functions and variables for
+ * media-router-container tests.
+ */
+
+cr.define('media_router_container_test_base', function() {
+  function init(container) {
+    /**
+     * Checks whether |view| matches the current view of |container|.
+     *
+     * @param {!media_router.MediaRouterView} view Expected view type.
+     */
+    var checkCurrentView = function(view) {
+      assertEquals(view, container.currentView_);
+    };
+
+    /**
+     * Checks whether the elements specified in |elementIdList| are visible.
+     * Checks whether all other elements are not visible. Throws an assertion
+     * error if this is not true.
+     *
+     * @param {!Array<!string>} elementIdList List of id's of elements that
+     *     should be visible.
+     */
+    var checkElementsVisibleWithId = function(elementIdList) {
+      for (var i = 0; i < elementIdList.length; i++)
+        checkElementVisibleWithId(true, elementIdList[i]);
+
+      for (var j = 0; j < hiddenCheckElementIdList.length; j++) {
+        if (elementIdList.indexOf(hiddenCheckElementIdList[j]) == -1)
+          checkElementVisibleWithId(false, hiddenCheckElementIdList[j]);
+      }
+    };
+
+    /**
+     * Checks the visibility of an element with |elementId| in |container|.
+     * An element is considered visible if it exists and its |hidden| property
+     * is |false|.
+     *
+     * @param {boolean} visible Whether the element should be visible.
+     * @param {!string} elementId The id of the element to test.
+     */
+    var checkElementVisibleWithId = function(visible, elementId) {
+      var element = container.$$('#' + elementId);
+      var elementVisible = !!element && !element.hidden &&
+          element.style.display != 'none';
+      assertEquals(visible, elementVisible, elementId);
+    };
+
+    /**
+     * Checks whether |expected| and the text in the |element| are equal.
+     *
+     * @param {!string} expected Expected text.
+     * @param {!Element} element Element whose text will be checked.
+     */
+    var checkElementText = function(expected, element) {
+      assertEquals(expected.trim(), element.textContent.trim());
+    };
+
+    /**
+     * The blocking issue to show.
+     * @type {!media_router.Issue}
+     */
+    var fakeBlockingIssue = new media_router.Issue(
+        'issue id 1', 'Issue Title 1', 'Issue Message 1', 0, 1,
+        'route id 1', true, 1234);
+
+    /**
+     * The list of CastModes to show.
+     * @type {!Array<!media_router.CastMode>}
+     */
+    var fakeCastModeList = [
+      new media_router.CastMode(0x1, 'Description 0', 'google.com'),
+      new media_router.CastMode(0x2, 'Description 1', null),
+      new media_router.CastMode(0x4, 'Description 2', null),
+    ];
+
+    /**
+     * The list of CastModes to show with non-default modes only.
+     * @type {!Array<!media_router.CastMode>}
+     */
+    var fakeCastModeListWithNonDefaultModesOnly = [
+      new media_router.CastMode(0x2, 'Description 1', null),
+      new media_router.CastMode(0x4, 'Description 2', null),
+      new media_router.CastMode(0x8, 'Description 3', null),
+    ];
+
+    /**
+     * The blocking issue to show.
+     * @type {!media_router.Issue}
+     */
+    var fakeNonBlockingIssue = new media_router.Issue(
+        'issue id 2', 'Issue Title 2', 'Issue Message 2', 0, 1,
+        'route id 2', false, 1234);
+
+    /**
+     * The list of current routes.
+     * @type {!Array<!media_router.Route>}
+     */
+    var fakeRouteList = [
+      new media_router.Route('id 1', 'sink id 1', 'Title 1', 0, true, false),
+      new media_router.Route('id 2', 'sink id 2', 'Title 2', 1, false, true),
+    ];
+
+    /**
+     * The list of current routes with local routes only.
+     * @type {!Array<!media_router.Route>}
+     */
+    var fakeRouteListWithLocalRoutesOnly = [
+      new media_router.Route('id 1', 'sink id 1', 'Title 1', 0, true, false),
+      new media_router.Route('id 2', 'sink id 2', 'Title 2', 1, true, false),
+    ];
+
+    // Common cast mode bitset for creating sinks in |fakeSinkList|.
+    var castModeBitset = 0x2 | 0x4 | 0x8;
+    /**
+     * The list of available sinks.
+     * @type {!Array<!media_router.Sink>}
+     */
+    var fakeSinkList = [
+      new media_router.Sink('sink id 1', 'Sink 1', null, null,
+          media_router.SinkIconType.CAST,
+          media_router.SinkStatus.ACTIVE, castModeBitset),
+      new media_router.Sink('sink id 2', 'Sink 2', null, null,
+          media_router.SinkIconType.CAST,
+          media_router.SinkStatus.ACTIVE, castModeBitset),
+      new media_router.Sink('sink id 3', 'Sink 3', null, null,
+          media_router.SinkIconType.CAST,
+          media_router.SinkStatus.PENDING, castModeBitset),
+    ];
+
+    /**
+     * The list of elements to check for visibility.
+     * @const {!Array<!string>}
+     */
+    var hiddenCheckElementIdList = [
+      'cast-mode-list',
+      'container-header',
+      'device-missing',
+      'first-run-flow',
+      'first-run-flow-cloud-pref',
+      'issue-banner',
+      'no-search-matches',
+      'route-details',
+      'search-results',
+      'sink-list',
+      'sink-list-view',
+    ];
+
+    /**
+     * Search text that will match all sinks.
+     * @type {!string}
+     */
+    var searchTextAll = 'sink';
+
+    /**
+     * Search text that won't match any sink in fakeSinkList.
+     * @type {!string}
+     */
+    var searchTextNone = 'abc';
+
+    /**
+     * Search text that will match exactly one sink.
+     * @type {!string}
+     */
+    var searchTextOne = 'sink 1';
+
+    return {
+      checkCurrentView: checkCurrentView,
+      checkElementsVisibleWithId: checkElementsVisibleWithId,
+      checkElementVisibleWithId: checkElementVisibleWithId,
+      checkElementText: checkElementText,
+      fakeBlockingIssue: fakeBlockingIssue,
+      fakeCastModeList: fakeCastModeList,
+      fakeCastModeListWithNonDefaultModesOnly:
+          fakeCastModeListWithNonDefaultModesOnly,
+      fakeNonBlockingIssue: fakeNonBlockingIssue,
+      fakeRouteList: fakeRouteList,
+      fakeRouteListWithLocalRoutesOnly: fakeRouteListWithLocalRoutesOnly,
+      fakeSinkList: fakeSinkList,
+      searchTextAll: searchTextAll,
+      searchTextNone: searchTextNone,
+      searchTextOne: searchTextOne,
+    };
+  }
+  return {init: init};
+});
diff --git a/chrome/test/data/webui/media_router/media_router_container_tests.js b/chrome/test/data/webui/media_router/media_router_container_tests.js
deleted file mode 100644
index 446b098..0000000
--- a/chrome/test/data/webui/media_router/media_router_container_tests.js
+++ /dev/null
@@ -1,996 +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.
-
-/** @fileoverview Suite of tests for media-router-container. */
-cr.define('media_router_container', function() {
-  function registerTests() {
-    suite('MediaRouterContainer', function() {
-      /**
-       * Media Router Container created before each test.
-       * @type {MediaRouterContainer}
-       */
-      var container;
-
-      /**
-       * The blocking issue to show.
-       * @type {?media_router.Issue}
-       */
-      var fakeBlockingIssue;
-
-      /**
-       * The list of CastModes to show.
-       * @type {!Array<!media_router.CastMode>}
-       */
-      var fakeCastModeList = [];
-
-      /**
-       * The list of CastModes to show with non-default modes only.
-       * @type {!Array<!media_router.CastMode>}
-       */
-      var fakeCastModeListWithNonDefaultModesOnly = [];
-
-      /**
-       * The blocking issue to show.
-       * @type {?media_router.Issue}
-       */
-      var fakeNonBlockingIssue;
-
-      /**
-       * The list of current routes.
-       * @type {!Array<!media_router.Route>}
-       */
-      var fakeRouteList = [];
-
-      /**
-       * The list of available sinks.
-       * @type {!Array<!media_router.Sink>}
-       */
-      var fakeSinkList = [];
-
-      /**
-       * The list of elements to check for visibility.
-       * @const {!Array<string>}
-       */
-      var hiddenCheckElementIdList = [
-        'cast-mode-list',
-        'container-header',
-        'device-missing',
-        'first-run-flow',
-        'first-run-flow-cloud-pref',
-        'issue-banner',
-        'no-search-matches',
-        'route-details',
-        'search-results',
-        'sink-list',
-        'sink-list-view',
-      ];
-
-      // Checks whether |view| matches the current view of |container|.
-      var checkCurrentView = function(view) {
-        assertEquals(view, container.currentView_);
-      };
-
-      // Checks whether the elements specified in |elementIdList| are visible.
-      // Checks whether all other elements are not visible.
-      var checkElementsVisibleWithId = function(elementIdList) {
-        for (var i = 0; i < elementIdList.length; i++)
-          checkElementVisibleWithId(true, elementIdList[i]);
-
-        for (var j = 0; j < hiddenCheckElementIdList.length; j++) {
-          if (elementIdList.indexOf(hiddenCheckElementIdList[j]) == -1)
-            checkElementVisibleWithId(false, hiddenCheckElementIdList[j]);
-        }
-      };
-
-      // Checks the visibility of an element with |elementId| in |container|.
-      // An element is considered visible if it exists and its |hidden| property
-      // is |false|.
-      var checkElementVisibleWithId = function(visible, elementId) {
-        var element = container.$$('#' + elementId);
-        var elementVisible = !!element && !element.hidden &&
-            element.style.display != 'none';
-        assertEquals(visible, elementVisible, elementId);
-      };
-
-      // Checks whether |expected| and the text in the |element| are equal.
-      var checkElementText = function(expected, element) {
-        assertEquals(expected.trim(), element.textContent.trim());
-      };
-
-      // Checks whether |expected| and the |property| in |container| are equal.
-      var checkPropertyValue = function(expected, property) {
-        assertEquals(expected.trim(), container.property);
-      }
-
-      // Import media_router_container.html before running suite.
-      suiteSetup(function() {
-        return PolymerTest.importHtml(
-            'chrome://media-router/elements/media_router_container/' +
-            'media_router_container.html');
-      });
-
-      // Initialize a media-router-container before each test.
-      setup(function(done) {
-        PolymerTest.clearBody();
-        container = document.createElement('media-router-container');
-        document.body.appendChild(container);
-
-        // Initialize local variables.
-        fakeCastModeList = [
-          new media_router.CastMode(0x1, 'Description 0', 'google.com'),
-          new media_router.CastMode(0x2, 'Description 1', null),
-          new media_router.CastMode(0x4, 'Description 2', null),
-        ];
-
-        fakeCastModeListWithNonDefaultModesOnly = [
-          new media_router.CastMode(0x2, 'Description 1', null),
-          new media_router.CastMode(0x4, 'Description 2', null),
-          new media_router.CastMode(0x8, 'Description 3', null),
-        ];
-
-        fakeRouteList = [
-          new media_router.Route('id 1', 'sink id 1',
-                                 'Title 1', 0, true, false),
-          new media_router.Route('id 2', 'sink id 2',
-                                 'Title 2', 1, false, true),
-        ];
-
-        fakeRouteListWithLocalRoutesOnly = [
-          new media_router.Route('id 1', 'sink id 1',
-                                 'Title 1', 0, true, false),
-          new media_router.Route('id 2', 'sink id 2',
-                                 'Title 2', 1, true, false),
-        ];
-
-        var castModeBitset = 0x2 | 0x4 | 0x8;
-        fakeSinkList = [
-          new media_router.Sink('sink id 1', 'Sink 1', null, null,
-              media_router.SinkIconType.CAST,
-              media_router.SinkStatus.ACTIVE, castModeBitset),
-          new media_router.Sink('sink id 2', 'Sink 2', null, null,
-              media_router.SinkIconType.CAST,
-              media_router.SinkStatus.ACTIVE, castModeBitset),
-          new media_router.Sink('sink id 3', 'Sink 3', null, null,
-              media_router.SinkIconType.CAST,
-              media_router.SinkStatus.PENDING, castModeBitset),
-        ];
-
-        searchTextAll = 'sink';
-        searchTextNone = 'abc';
-        searchTextOne = 'sink 1';
-
-        fakeBlockingIssue = new media_router.Issue(
-            'issue id 1', 'Issue Title 1', 'Issue Message 1', 0, 1,
-            'route id 1', true, 1234);
-
-        fakeNonBlockingIssue = new media_router.Issue(
-            'issue id 2', 'Issue Title 2', 'Issue Message 2', 0, 1,
-            'route id 2', false, 1234);
-
-        container.castModeList = fakeCastModeList;
-
-        // Allow for the media router container to be created and attached.
-        setTimeout(done);
-      });
-
-      // Tests for 'acknowledge-first-run-flow' event firing when the
-      // 'first-run-button' button is clicked and the cloud preference checkbox
-      // is not shown.
-      test('first run button click', function(done) {
-        container.showFirstRunFlow = true;
-
-        setTimeout(function() {
-          container.addEventListener('acknowledge-first-run-flow',
-              function(data) {
-            assertEquals(undefined, data.detail.optedIntoCloudServices);
-            done();
-          });
-          MockInteractions.tap(container.shadowRoot.getElementById(
-              'first-run-button'));
-        });
-      });
-
-      // Tests for 'acknowledge-first-run-flow' event firing when the
-      // 'first-run-button' button is clicked and the cloud preference checkbox
-      // is also shown.
-      test('first run button with cloud pref click', function(done) {
-        container.showFirstRunFlow = true;
-        container.showFirstRunFlowCloudPref = true;
-
-        setTimeout(function() {
-          container.addEventListener('acknowledge-first-run-flow',
-              function(data) {
-            assertTrue(data.detail.optedIntoCloudServices);
-            done();
-          });
-          MockInteractions.tap(container.shadowRoot.getElementById(
-              'first-run-button'));
-        });
-      });
-
-      // Tests for 'acknowledge-first-run-flow' event firing when the
-      // 'first-run-button' button is clicked after the cloud preference
-      // checkbox is deselected.
-      test('first run button with cloud pref deselected click',
-          function(done) {
-        container.showFirstRunFlow = true;
-        container.showFirstRunFlowCloudPref = true;
-
-        setTimeout(function() {
-          container.addEventListener('acknowledge-first-run-flow',
-              function(data) {
-            assertFalse(data.detail.optedIntoCloudServices);
-            done();
-          });
-          MockInteractions.tap(container.shadowRoot.getElementById(
-              'first-run-cloud-checkbox'));
-          MockInteractions.tap(container.shadowRoot.getElementById(
-              'first-run-button'));
-        });
-      });
-
-      // Tests for 'create-route' event firing when a sink with no associated
-      // route is clicked.
-      test('select sink without a route', function(done) {
-        container.allSinks = fakeSinkList;
-
-        setTimeout(function() {
-          var sinkList =
-              container.$['sink-list'].querySelectorAll('paper-item');
-          container.addEventListener('create-route', function(data) {
-            // Container is initially in auto mode since a cast mode has not
-            // been selected.
-            assertEquals(media_router.CastModeType.AUTO,
-                container.shownCastModeValue_);
-            assertEquals(fakeSinkList[2].id, data.detail.sinkId);
-
-            // The preferred compatible cast mode on the sink is used, since
-            // the we did not choose a cast mode on the container.
-            assertEquals(0x2, data.detail.selectedCastModeValue);
-            done();
-          });
-          // Tap on a sink without a route, which should fire a 'create-route'
-          // event.
-          assertEquals(fakeSinkList.length, sinkList.length);
-          MockInteractions.tap(sinkList[2]);
-        });
-      });
-
-      // Tests that selecting a sink with an associated route will make the
-      // |container| switch to ROUTE_DETAILS view.
-      test('select sink with a route', function(done) {
-        container.allSinks = fakeSinkList;
-        container.routeList = fakeRouteList;
-
-        setTimeout(function() {
-          var sinkList =
-              container.$['sink-list'].querySelectorAll('paper-item');
-
-          // Start from the SINK_LIST view.
-          container.showSinkList_();
-          checkCurrentView(media_router.MediaRouterView.SINK_LIST);
-          MockInteractions.tap(sinkList[0]);
-          checkCurrentView(media_router.MediaRouterView.ROUTE_DETAILS);
-          done();
-        });
-      });
-
-      // Tests that |container| returns to SINK_LIST view and arrow drop icon
-      // toggles after a cast mode is selected.
-      test('select cast mode', function(done) {
-        container.castModeList = fakeCastModeListWithNonDefaultModesOnly;
-
-        MockInteractions.tap(container.$['container-header'].
-            $['arrow-drop-icon']);
-        checkCurrentView(media_router.MediaRouterView.CAST_MODE_LIST);
-
-        setTimeout(function() {
-          var castModeList =
-              container.$$('#cast-mode-list').querySelectorAll('paper-item');
-
-          MockInteractions.tap(castModeList[2]);
-          checkCurrentView(media_router.MediaRouterView.SINK_LIST);
-          done();
-        });
-      });
-
-      // Tests that clicking on the drop down icon will toggle |container|
-      // between SINK_LIST and CAST_MODE_LIST views.
-      test('click drop down icon', function() {
-        checkCurrentView(media_router.MediaRouterView.SINK_LIST);
-
-        MockInteractions.tap(container.$['container-header'].
-            $['arrow-drop-icon']);
-        checkCurrentView(media_router.MediaRouterView.CAST_MODE_LIST);
-
-        MockInteractions.tap(container.$['container-header'].
-            $['arrow-drop-icon']);
-        checkCurrentView(media_router.MediaRouterView.SINK_LIST);
-      });
-
-      // Tests the header text. Choosing a cast mode updates the header text.
-      test('header text with no default cast modes', function(done) {
-        assertEquals(loadTimeData.getString('selectCastModeHeader'),
-            container.selectCastModeHeaderText_);
-
-        // The container is currently in auto cast mode, since we have not
-        // picked a cast mode explicitly, and the sinks is not compatible
-        // with exactly one cast mode.
-        assertEquals(media_router.AUTO_CAST_MODE.description,
-            container.headerText);
-        assertFalse(container.userHasSelectedCastMode_);
-
-        container.castModeList = fakeCastModeListWithNonDefaultModesOnly;
-
-        // Switch to cast mode list view.
-        MockInteractions.tap(container.$['container-header'].
-            $['arrow-drop-icon']);
-        setTimeout(function() {
-          var castModeList =
-              container.$$('#cast-mode-list').querySelectorAll('paper-item');
-          assertEquals(fakeCastModeListWithNonDefaultModesOnly.length,
-              castModeList.length);
-          for (var i = 0; i < castModeList.length; i++) {
-            MockInteractions.tap(castModeList[i]);
-            assertEquals(
-                fakeCastModeListWithNonDefaultModesOnly[i].description,
-                container.headerText);
-            checkElementText(
-                fakeCastModeListWithNonDefaultModesOnly[i].description,
-                castModeList[i]);
-          }
-
-          done();
-        });
-      });
-
-      // Tests the header text when updated with a cast mode list with a mix of
-      // default and non-default cast modes.
-      test('cast modes with one default mode', function(done) {
-        container.castModeList = fakeCastModeList;
-
-        // Switch to cast mode list view.
-        MockInteractions.tap(container.$['container-header'].
-            $['arrow-drop-icon']);
-        setTimeout(function() {
-          var castModeList =
-              container.$$('#cast-mode-list').querySelectorAll('paper-item');
-
-          for (var i = 0; i < fakeCastModeList.length; i++) {
-            MockInteractions.tap(castModeList[i]);
-            if (fakeCastModeList[i].type ==
-                media_router.CastModeType.DEFAULT) {
-              assertEquals(fakeCastModeList[i].description,
-                  container.headerText);
-
-              checkElementText(fakeCastModeList[i].host, castModeList[i]);
-            } else {
-              assertEquals(fakeCastModeList[i].description,
-                  container.headerText);
-              checkElementText(fakeCastModeList[i].description,
-                  castModeList[i]);
-            }
-          }
-
-          done();
-        });
-      });
-
-      // Tests that text shown for each sink matches their names.
-      test('sink list text', function(done) {
-        container.allSinks = fakeSinkList;
-
-        setTimeout(function() {
-          var sinkList =
-              container.$['sink-list'].querySelectorAll('paper-item');
-          assertEquals(fakeSinkList.length, sinkList.length);
-          for (var i = 0; i < fakeSinkList.length; i++) {
-            checkElementText(fakeSinkList[i].name, sinkList[i]);
-          }
-          done();
-        });
-      });
-
-      // Tests that text shown for sink with domain matches the name and domain.
-      test('sink with domain text', function(done) {
-        // Sink 1 - sink, no domain -> text = name
-        // Sink 2 - sink, domain -> text = sink + domain
-        container.allSinks = [
-            new media_router.Sink('sink id 1', 'Sink 1', null, null,
-                media_router.SinkIconType.HANGOUT,
-                media_router.SinkStatus.ACTIVE, [1, 2, 3]),
-            new media_router.Sink('sink id 2', 'Sink 2',
-                null, 'example.com',
-                media_router.SinkIconType.HANGOUT,
-                media_router.SinkStatus.ACTIVE, [1, 2, 3]),
-        ];
-
-        container.showDomain = true;
-
-        setTimeout(function() {
-          var sinkList =
-              container.$['sink-list'].querySelectorAll('paper-item');
-          assertEquals(2, sinkList.length);
-
-          // |sinkList[0]| has sink name only.
-          checkElementText(container.allSinks[0].name, sinkList[0]);
-          // |sinkList[1]| contains sink name and domain.
-          assertTrue(sinkList[1].textContent.trim().startsWith(
-              container.allSinks[1].name.trim()));
-          assertTrue(sinkList[1].textContent.trim().indexOf(
-              container.allSinks[1].domain.trim()) != -1);
-          done();
-        });
-      });
-
-      // Tests that domain text is not shown when |showDomain| is false.
-      test('sink with domain text', function(done) {
-        // Sink 1 - sink, no domain -> text = name
-        // Sink 2 - sink, domain -> text = sink + domain
-        container.allSinks = [
-            new media_router.Sink('sink id 1', 'Sink 1', null, null,
-                media_router.SinkIconType.HANGOUT,
-                media_router.SinkStatus.ACTIVE, [1, 2, 3]),
-            new media_router.Sink('sink id 2', 'Sink 2',
-                null, 'example.com',
-                media_router.SinkIconType.HANGOUT,
-                media_router.SinkStatus.ACTIVE, [1, 2, 3]),
-        ];
-
-        container.showDomain = false;
-
-        setTimeout(function() {
-          var sinkList =
-              container.$['sink-list'].querySelectorAll('paper-item');
-          assertEquals(2, sinkList.length);
-
-          // |sinkList[0]| has sink name only.
-          checkElementText(container.allSinks[0].name, sinkList[0]);
-          // |sinkList[1]| has sink name but domain should be hidden.
-          checkElementText(container.allSinks[1].name, sinkList[1]);
-          assertTrue(sinkList[1].textContent.trim().indexOf(
-              container.allSinks[1].domain.trim()) == -1);
-          done();
-        });
-      });
-
-      // Tests the text shown for the sink list.
-      test('initial sink list route text', function(done) {
-        // Sink 1 - no sink description, no route -> no subtext
-        // Sink 2 - sink description, no route -> subtext = sink description
-        // Sink 3 - no sink description, route -> subtext = route description
-        // Sink 4 - sink description, route -> subtext = route description
-        container.allSinks = [
-            new media_router.Sink('sink id 1', 'Sink 1', null, null,
-                media_router.SinkIconType.CAST,
-                media_router.SinkStatus.ACTIVE, [1, 2, 3]),
-            new media_router.Sink('sink id 2', 'Sink 2',
-                'Sink 2 description', null,
-                media_router.SinkIconType.CAST,
-                media_router.SinkStatus.ACTIVE, [1, 2, 3]),
-            new media_router.Sink('sink id 3', 'Sink 3', null, null,
-                media_router.SinkIconType.CAST,
-                media_router.SinkStatus.PENDING, [1, 2, 3]),
-            new media_router.Sink('sink id 4', 'Sink 4',
-                'Sink 4 description', null,
-                media_router.SinkIconType.CAST,
-                media_router.SinkStatus.PENDING, [1, 2, 3])
-        ];
-
-        container.routeList = [
-            new media_router.Route('id 3', 'sink id 3', 'Title 3', 0, true),
-            new media_router.Route('id 4', 'sink id 4', 'Title 4', 1, false),
-        ];
-
-        setTimeout(function() {
-          var sinkSubtextList =
-              container.$['sink-list'].querySelectorAll('.sink-subtext');
-
-          // There will only be 3 sink subtext entries, because Sink 1 does not
-          // have any subtext.
-          assertEquals(3, sinkSubtextList.length);
-
-          checkElementText(container.allSinks[1].description,
-              sinkSubtextList[0]);
-
-          // Route description overrides sink description for subtext.
-          checkElementText(container.routeList[0].description,
-              sinkSubtextList[1]);
-
-          checkElementText(container.routeList[1].description,
-              sinkSubtextList[2]);
-          done();
-        });
-      });
-
-      // Tests the expected view when there is only one local active route and
-      // media_router_container is created for the first time.
-      test('initial view with one local route', function() {
-        container.allSinks = fakeSinkList;
-        container.routeList = fakeRouteList;
-        container.maybeShowRouteDetailsOnOpen();
-
-        checkCurrentView(media_router.MediaRouterView.ROUTE_DETAILS);
-      });
-
-      // Tests the expected view when there are multiple local active routes
-      // and media_router_container is created for the first time.
-      test('initial view with multiple local routes', function() {
-        container.allSinks = fakeSinkList;
-        container.routeList = fakeRouteListWithLocalRoutesOnly;
-
-        checkCurrentView(media_router.MediaRouterView.SINK_LIST);
-      });
-
-      // Tests the expected view when there are no local active routes and
-      // media_router_container is created for the first time.
-      test('initial view with no local route', function() {
-        container.allSinks = fakeSinkList;
-        container.routeList = [];
-
-        checkCurrentView(media_router.MediaRouterView.SINK_LIST);
-      });
-
-      // Tests the expected view when there are no local active routes and
-      // media_router_container is created for the first time.
-      test('view after route is closed remotely', function() {
-        container.allSinks = fakeSinkList;
-        container.routeList = fakeRouteList;
-        container.maybeShowRouteDetailsOnOpen();
-        checkCurrentView(media_router.MediaRouterView.ROUTE_DETAILS);
-
-        container.routeList = [];
-        checkCurrentView(media_router.MediaRouterView.SINK_LIST);
-      });
-
-      // Tests for expected visible UI when the view is CAST_MODE_LIST.
-      test('cast mode list state visibility', function(done) {
-        container.showCastModeList_();
-        setTimeout(function() {
-          checkElementsVisibleWithId(['cast-mode-list',
-                                      'container-header',
-                                      'device-missing']);
-
-          // Set a non-blocking issue. The issue should stay hidden.
-          container.issue = fakeNonBlockingIssue;
-          setTimeout(function() {
-            checkElementsVisibleWithId(['cast-mode-list',
-                                        'container-header',
-                                        'device-missing']);
-
-            // Set a blocking issue. The issue should stay hidden.
-            container.issue = fakeBlockingIssue;
-            setTimeout(function() {
-              checkElementsVisibleWithId(['container-header',
-                                          'device-missing',
-                                          'issue-banner']);
-              done();
-            });
-          });
-        });
-      });
-
-      // Tests for the expected visible UI when interacting with the first run
-      // flow.
-      test('first run button visibility', function(done) {
-        container.showFirstRunFlow = true;
-
-        setTimeout(function() {
-          checkElementVisibleWithId(true, 'first-run-flow');
-          MockInteractions.tap(container.shadowRoot.getElementById(
-              'first-run-button'));
-
-          setTimeout(function() {
-            checkElementVisibleWithId(false, 'first-run-flow');
-            done();
-          });
-        });
-      });
-
-      // Tests for the expected visible UI when interacting with the first run
-      // flow with cloud services preference.
-      test('first run button visibility', function(done) {
-        container.showFirstRunFlow = true;
-        container.showFirstRunFlowCloudPref = true;
-
-        setTimeout(function() {
-          checkElementsVisibleWithId(['container-header',
-                                      'device-missing',
-                                      'first-run-flow',
-                                      'first-run-flow-cloud-pref',
-                                      'sink-list-view']);
-          MockInteractions.tap(container.shadowRoot.getElementById(
-              'first-run-button'));
-
-          setTimeout(function() {
-            checkElementsVisibleWithId(['container-header',
-                                        'device-missing',
-                                        'sink-list-view']);
-            done();
-          });
-        });
-      });
-
-      // Tests for expected visible UI when the view is ROUTE_DETAILS.
-      test('route details visibility', function(done) {
-        container.showRouteDetails_();
-        setTimeout(function() {
-          checkElementsVisibleWithId(['container-header',
-                                      'device-missing',
-                                      'route-details']);
-          done();
-        });
-      });
-
-      test('updated route in route details', function(done) {
-        container.allSinks = fakeSinkList;
-        var description = 'Title';
-        var route = new media_router.Route(
-            'id 1', 'sink id 1', description, 0, true, false);
-        container.routeList = [route];
-        container.showRouteDetails_(route);
-        setTimeout(function() {
-          // Note that sink-list-view is hidden.
-          checkElementsVisibleWithId(
-              ['container-header', 'route-details', 'sink-list']);
-          assertTrue(!!container.currentRoute_);
-          assertEquals(description, container.currentRoute_.description);
-
-          var newDescription = 'Foo';
-          route.description = newDescription;
-          container.routeList = [route];
-          setTimeout(function() {
-            // Note that sink-list-view is hidden.
-            checkElementsVisibleWithId(
-                ['container-header', 'route-details', 'sink-list']);
-            assertTrue(!!container.currentRoute_);
-            assertEquals(newDescription, container.currentRoute_.description);
-            done();
-          });
-        });
-      });
-
-      // Tests for expected visible UI when the view is ROUTE_DETAILS, and there
-      // is a non-blocking issue.
-      test('route details visibility non blocking issue', function(done) {
-        container.showRouteDetails_();
-
-        // Set a non-blocking issue. The issue should be shown.
-        container.issue = fakeNonBlockingIssue;
-        setTimeout(function() {
-          checkElementsVisibleWithId(['container-header',
-                                      'device-missing',
-                                      'route-details']);
-          done();
-        });
-      });
-
-      // Tests for expected visible UI when the view is ROUTE_DETAILS, and there
-      // is a blocking issue.
-      test('route details visibility with blocking issue', function(done) {
-        container.showRouteDetails_();
-
-        // Set a blocking issue. The issue should be shown, and everything
-        // else, hidden.
-        container.issue = fakeBlockingIssue;
-        setTimeout(function() {
-          checkElementsVisibleWithId(['container-header',
-                                      'device-missing',
-                                      'issue-banner']);
-          done();
-         });
-      });
-
-      // Tests for expected visible UI when the view is SINK_LIST.
-      test('sink list state visibility', function() {
-        container.showSinkList_();
-        checkElementsVisibleWithId(['container-header',
-                                    'device-missing',
-                                    'sink-list-view']);
-
-        // Set an non-empty sink list.
-        container.allSinks = fakeSinkList;
-        checkElementsVisibleWithId(['container-header',
-                                    'sink-list',
-                                    'sink-list-view']);
-      });
-
-      // Tests for expected visible UI when the view is SINK_LIST, and there is
-      // a non blocking issue.
-      test('sink list visibility non blocking issue', function(done) {
-        container.showSinkList_();
-
-        // Set an non-empty sink list.
-        container.allSinks = fakeSinkList;
-
-        // Set a non-blocking issue. The issue should be shown.
-        container.issue = fakeNonBlockingIssue;
-        setTimeout(function() {
-          checkElementsVisibleWithId(['container-header',
-                                      'issue-banner',
-                                      'sink-list',
-                                      'sink-list-view']);
-          done();
-        });
-      });
-
-      // Tests for expected visible UI when the view is SINK_LIST, and there is
-      // a blocking issue.
-      test('sink list visibility blocking issue', function(done) {
-        container.showSinkList_();
-
-        // Set an non-empty sink list.
-        container.allSinks = fakeSinkList;
-
-        // Set a blocking issue. The issue should be shown, and everything
-        // else, hidden.
-        container.issue = fakeBlockingIssue;
-        setTimeout(function() {
-          checkElementsVisibleWithId(['container-header',
-                                      'issue-banner',
-                                      'sink-list']);
-          done();
-        });
-      });
-
-      // Tests all sinks are always shown in auto mode, and that the mode will
-      // switch if the sinks support only 1 case mode.
-      test('sink list in auto mode', function(done) {
-        container.allSinks = fakeSinkList;
-        setTimeout(function() {
-          // Container is initially in auto mode since a cast mode has not been
-          // selected.
-          assertEquals(media_router.AUTO_CAST_MODE.description,
-              container.headerText);
-          assertEquals(media_router.CastModeType.AUTO,
-              container.shownCastModeValue_);
-          assertFalse(container.userHasSelectedCastMode_);
-          var sinkList =
-              container.$['sink-list'].querySelectorAll('paper-item');
-
-          // All sinks are shown in auto mode.
-          assertEquals(3, sinkList.length);
-
-          // When sink list changes to only 1 compatible cast mode, the mode is
-          // switched, and all sinks are shown.
-          container.allSinks = [
-            new media_router.Sink('sink id 10', 'Sink 10', null, null,
-                media_router.SinkIconType.CAST,
-                media_router.SinkStatus.ACTIVE, 0x4),
-            new media_router.Sink('sink id 20', 'Sink 20', null, null,
-                media_router.SinkIconType.CAST,
-                media_router.SinkStatus.ACTIVE, 0x4),
-            new media_router.Sink('sink id 30', 'Sink 30', null, null,
-                media_router.SinkIconType.CAST,
-                media_router.SinkStatus.PENDING, 0x4),
-          ];
-
-          setTimeout(function() {
-            assertEquals(fakeCastModeList[2].description, container.headerText);
-            assertEquals(fakeCastModeList[2].type,
-                container.shownCastModeValue_);
-            assertFalse(container.userHasSelectedCastMode_);
-
-            var sinkList =
-                container.$['sink-list'].querySelectorAll('paper-item');
-            assertEquals(3, sinkList.length);
-
-            // When compatible cast modes size is no longer exactly 1, switch
-            // back to auto mode, and all sinks are shown.
-            container.allSinks = fakeSinkList;
-            setTimeout(function() {
-              assertEquals(media_router.AUTO_CAST_MODE.description,
-                  container.headerText);
-              assertEquals(media_router.CastModeType.AUTO,
-                  container.shownCastModeValue_);
-              assertFalse(container.userHasSelectedCastMode_);
-              var sinkList =
-                  container.$['sink-list'].querySelectorAll('paper-item');
-
-              // All sinks are shown in auto mode.
-              assertEquals(3, sinkList.length);
-
-              done();
-            });
-          });
-        });
-      });
-
-      // Tests that the sink list does not contain any sinks that are not
-      // compatible with the selected cast mode and are not associated with a
-      // route.
-      test('sink list in user selected cast mode', function(done) {
-        var newSinks = [
-          new media_router.Sink('sink id 10', 'Sink 10', null, null,
-              media_router.SinkIconType.CAST,
-              media_router.SinkStatus.ACTIVE, 0x4 | 0x8),
-          new media_router.Sink('sink id 20', 'Sink 20', null, null,
-              media_router.SinkIconType.CAST,
-              media_router.SinkStatus.ACTIVE, 0x2 | 0x4 | 0x8),
-          new media_router.Sink('sink id 30', 'Sink 30', null, null,
-              media_router.SinkIconType.CAST,
-              media_router.SinkStatus.PENDING, 0x4 | 0x8),
-        ];
-
-        container.allSinks = newSinks;
-        container.routeList = [
-          new media_router.Route('id 1', 'sink id 30',
-                                 'Title 1', 1, false, false),
-        ];
-
-        setTimeout(function() {
-          var sinkList =
-              container.$['sink-list'].querySelectorAll('paper-item');
-
-          // Since we haven't selected a cast mode, we don't filter sinks.
-          assertEquals(3, sinkList.length);
-
-          MockInteractions.tap(container.$['container-header'].
-              $['arrow-drop-icon']);
-          setTimeout(function() {
-            // Cast mode 1 is selected, and the sink list is filtered.
-            var castModeList =
-                container.$$('#cast-mode-list').querySelectorAll('paper-item');
-            MockInteractions.tap(castModeList[1]);
-            assertEquals(fakeCastModeList[1].description, container.headerText);
-            assertEquals(fakeCastModeList[1].type,
-                container.shownCastModeValue_);
-
-            setTimeout(function() {
-              var sinkList =
-                  container.$['sink-list'].querySelectorAll('paper-item');
-
-              // newSinks[0] got filtered out since it is not compatible with
-              // cast mode 1.
-              // 'Sink 20' should be on the list because it contains the
-              // selected cast mode. (sinkList[0] = newSinks[1])
-              // 'Sink 30' should be on the list because it has a route.
-              // (sinkList[1] = newSinks[2])
-              assertEquals(2, sinkList.length);
-              checkElementText(newSinks[1].name, sinkList[0]);
-
-              // |sinkList[1]| contains route title in addition to sink name.
-              assertTrue(sinkList[1].textContent.trim().startsWith(
-                  newSinks[2].name.trim()));
-
-              // Cast mode is not switched back even if there are no sinks
-              // compatible with selected cast mode, because we explicitly
-              // selected that cast mode.
-              container.allSinks = [];
-              setTimeout(function() {
-                assertEquals(fakeCastModeList[1].description,
-                    container.headerText);
-                assertEquals(fakeCastModeList[1].type,
-                    container.shownCastModeValue_);
-                var sinkList =
-                    container.$['sink-list'].querySelectorAll('paper-item');
-                assertEquals(0, sinkList.length);
-                done();
-              });
-            });
-          });
-        });
-      });
-
-      // Container remains in auto mode even if the cast mode list changed.
-      test('cast mode list updated in auto mode', function(done) {
-        assertEquals(media_router.AUTO_CAST_MODE.description,
-            container.headerText);
-        assertEquals(media_router.CastModeType.AUTO,
-            container.shownCastModeValue_);
-        assertFalse(container.userHasSelectedCastMode_);
-
-        container.castModeList = fakeCastModeList.slice(1);
-        setTimeout(function() {
-          assertEquals(media_router.AUTO_CAST_MODE.description,
-              container.headerText);
-          assertEquals(media_router.CastModeType.AUTO,
-              container.shownCastModeValue_);
-          assertFalse(container.userHasSelectedCastMode_);
-          done();
-        });
-      });
-
-      // If the container is not in auto mode, and the mode it is currently in
-      // no longer exists in the list of cast modes, then switch back to auto
-      // mode.
-      test('cast mode list updated in selected cast mode', function(done) {
-        assertEquals(media_router.AUTO_CAST_MODE.description,
-            container.headerText);
-        assertEquals(media_router.CastModeType.AUTO,
-            container.shownCastModeValue_);
-        assertFalse(container.userHasSelectedCastMode_);
-
-        MockInteractions.tap(container.$['container-header'].
-            $['arrow-drop-icon']);
-        setTimeout(function() {
-          var castModeList =
-                container.$$('#cast-mode-list').querySelectorAll('paper-item');
-          MockInteractions.tap(castModeList[0]);
-          setTimeout(function() {
-            assertEquals(fakeCastModeList[0].description, container.headerText);
-            assertEquals(fakeCastModeList[0].type,
-                container.shownCastModeValue_);
-            assertTrue(container.userHasSelectedCastMode_);
-            container.castModeList = fakeCastModeList.slice(1);
-            setTimeout(function() {
-              assertEquals(media_router.AUTO_CAST_MODE.description,
-                  container.headerText);
-              assertEquals(media_router.CastModeType.AUTO,
-                  container.shownCastModeValue_);
-              assertFalse(container.userHasSelectedCastMode_);
-              done();
-            });
-          });
-        });
-      });
-
-      test('creating route with selected cast mode', function(done) {
-        container.allSinks = fakeSinkList;
-        MockInteractions.tap(container.$['container-header'].
-            $['arrow-drop-icon']);
-        setTimeout(function() {
-          // Select cast mode 2.
-          var castModeList =
-              container.$$('#cast-mode-list').querySelectorAll('paper-item');
-          MockInteractions.tap(castModeList[1]);
-          assertEquals(fakeCastModeList[1].description, container.headerText);
-          setTimeout(function() {
-            var sinkList =
-                container.$['sink-list'].querySelectorAll('paper-item');
-            container.addEventListener('create-route', function(data) {
-              assertEquals(fakeSinkList[2].id, data.detail.sinkId);
-              // Cast mode 2 is used, since we selected it explicitly.
-              assertEquals(fakeCastModeList[1].type,
-                           data.detail.selectedCastModeValue);
-              done();
-            });
-            // All sinks are compatible with cast mode 2.
-            assertEquals(fakeSinkList.length, sinkList.length);
-            // Tap on a sink without a route, which should fire a 'create-route'
-            // event.
-            MockInteractions.tap(sinkList[2]);
-          });
-        });
-      });
-
-      // Tests that after a different cast mode is selected, the sink list will
-      // change based on the sinks compatibility with the new cast mode.
-      test('changing cast mode changes sink list', function(done) {
-        container.allSinks = fakeSinkList;
-
-        MockInteractions.tap(container.$['container-header'].
-            $['arrow-drop-icon']);
-        setTimeout(function() {
-          var castModeList =
-                container.$$('#cast-mode-list').querySelectorAll('paper-item');
-          MockInteractions.tap(castModeList[0]);
-          assertEquals(fakeCastModeList[0].description, container.headerText);
-
-          setTimeout(function() {
-            var sinkList =
-                container.$['sink-list'].querySelectorAll('paper-item');
-
-            // The sink list is empty because none of the sinks in fakeSinkList
-            // is compatible with cast mode 0.
-            assertEquals(0, sinkList.length);
-            MockInteractions.tap(castModeList[2]);
-            assertEquals(fakeCastModeList[2].description, container.headerText);
-
-            setTimeout(function() {
-              var sinkList =
-                  container.$['sink-list'].querySelectorAll('paper-item');
-              assertEquals(3, sinkList.length);
-              done();
-            });
-          });
-        });
-      });
-    });
-  }
-
-  return {
-    registerTests: registerTests,
-  };
-});
diff --git a/chrome/test/data/webui/media_router/media_router_elements_browsertest.js b/chrome/test/data/webui/media_router/media_router_elements_browsertest.js
index eae673a..4ee903d 100644
--- a/chrome/test/data/webui/media_router/media_router_elements_browsertest.js
+++ b/chrome/test/data/webui/media_router/media_router_elements_browsertest.js
@@ -34,15 +34,19 @@
     switchName: 'media-router', switchValue: '1'
   }],
 
-  // List tests for individual elements. The media_router_container tests are
-  // split between media_router_container_tests.js and
-  // media_router_container_filter_tests.js.
+  // List tests for individual elements. The media-router-container tests are
+  // split between several files and use common functionality from
+  // media_router_container_test_base.js.
   extraLibraries: PolymerTest.getLibraries(ROOT_PATH).concat([
     'issue_banner_tests.js',
-    'media_router_container_tests.js',
+    'media_router_container_cast_mode_list_tests.js',
     'media_router_container_filter_tests.js',
+    'media_router_container_first_run_flow_tests.js',
+    'media_router_container_route_tests.js',
+    'media_router_container_sink_list_tests.js',
+    'media_router_container_test_base.js',
     'media_router_header_tests.js',
-    'media_router_search_highlighter.js',
+    'media_router_search_highlighter_tests.js',
     'route_details_tests.js',
   ]),
 
@@ -82,62 +86,61 @@
   },
 };
 
-TEST_F('MediaRouterElementsBrowserTest', 'MediaRouterElementsTestIssueBanner',
-    function() {
-  // Register mocha tests for the issue banner.
+TEST_F('MediaRouterElementsBrowserTest', 'IssueBanner', function() {
   issue_banner.registerTests();
-
-  // Run all registered tests.
   mocha.run();
 });
 
-// See bugs.chromium.org issue 591227
+// The media-router-container tests are being split into multiple parts due to
+// timeout issues on bots.
 TEST_F('MediaRouterElementsBrowserTest',
-    'DISABLED_MediaRouterElementsTestMediaRouterContainer',
+    'MediaRouterContainerCastModeList',
     function() {
-  // Register mocha tests for the container.
-  media_router_container.registerTests();
-
-  // Run all registered tests.
+  media_router_container_cast_mode_list.registerTests();
   mocha.run();
 });
 
 TEST_F('MediaRouterElementsBrowserTest',
-    'MediaRouterElementsTestMediaRouterContainerFilter',
+    'MediaRouterContainerFirstRunFlow',
     function() {
-  // Register mocha tests for the container filter.
+  media_router_container_first_run_flow.registerTests();
+  mocha.run();
+});
+
+TEST_F('MediaRouterElementsBrowserTest',
+    'MediaRouterContainerRoute',
+    function() {
+  media_router_container_route.registerTests();
+  mocha.run();
+});
+
+TEST_F('MediaRouterElementsBrowserTest',
+    'MediaRouterContainerSinkList',
+    function() {
+  media_router_container_sink_list.registerTests();
+  mocha.run();
+});
+
+TEST_F('MediaRouterElementsBrowserTest',
+    'MediaRouterContainerFilter',
+    function() {
   media_router_container_filter.registerTests();
-
-  // Run all registered tests.
   mocha.run();
 });
 
-TEST_F('MediaRouterElementsBrowserTest',
-    'MediaRouterElementsTestMediaRouterHeader',
-    function() {
-  // Register mocha tests for the header.
+TEST_F('MediaRouterElementsBrowserTest', 'MediaRouterHeader', function() {
   media_router_header.registerTests();
-
-  // Run all registered tests.
   mocha.run();
 });
 
 TEST_F('MediaRouterElementsBrowserTest',
-    'MediaRouterElementsTestMediaRouterSearchHighlighter',
+    'MediaRouterSearchHighlighter',
     function() {
-  // Register mocha tests for the search highlighter.
   media_router_search_highlighter.registerTests();
-
-  // Run all registered tests.
   mocha.run();
 });
 
-TEST_F('MediaRouterElementsBrowserTest',
-    'MediaRouterElementsTestMediaRouterRouteDetails',
-    function() {
-  // Register mocha tests for the route details.
+TEST_F('MediaRouterElementsBrowserTest', 'MediaRouterRouteDetails', function() {
   route_details.registerTests();
-
-  // Run all registered tests.
   mocha.run();
 });
diff --git a/chrome/test/data/webui/media_router/media_router_search_highlighter.js b/chrome/test/data/webui/media_router/media_router_search_highlighter_tests.js
similarity index 100%
rename from chrome/test/data/webui/media_router/media_router_search_highlighter.js
rename to chrome/test/data/webui/media_router/media_router_search_highlighter_tests.js
diff --git a/components/OWNERS b/components/OWNERS
index 4fb304f3a..a37dc71 100644
--- a/components/OWNERS
+++ b/components/OWNERS
@@ -3,399 +3,231 @@
 jochen@chromium.org
 sdefresne@chromium.org
 
-per-file app_modal*=avi@chromium.org
+# Note: Best not to use globs (like autofill*) due to crbug.com/397984
 
-per-file arc.gypi=elijahtaylor@chromium.org
-per-file arc.gypi=hidehiko@chromium.org
-per-file arc.gypi=lhchavez@chromium.org
+per-file app_modal.gypi=file://components/app_modal/OWNERS
+per-file app_modal_strings.grdp=file://components/app_modal/OWNERS
 
-per-file audio_modem.gypi=ckehoe@chromium.org
-per-file audio_modem.gypi=rkc@chromium.org
-per-file audio_modem.gypi=xiyuan@chromium.org
+per-file arc.gypi=file://components/arc/OWNERS
 
-# Can not match autofill* due to crbug.com/397984
-per-file autofill.gypi=estade@chromium.org
-per-file autofill.gypi=isherman@chromium.org
-per-file autofill.gypi=mathp@chromium.org
-per-file autofill.gypi=vabr@chromium.org
-per-file autofill_strings.grdp=estade@chromium.org
-per-file autofill_strings.grdp=isherman@chromium.org
-per-file autofill_strings.grdp=mathp@chromium.org
-per-file autofill_strings.grdp=vabr@chromium.org
+per-file audio_modem.gypi=file://components/audio_modem/OWNERS
 
-per-file bookmark_bar_strings.grdp=sky@chromium.org
-per-file bookmarks.gypi=sky@chromium.org
+per-file autofill.gypi=file://components/autofill/OWNERS
+per-file autofill_strings.grdp=file://components/autofill/OWNERS
 
-per-file browser_sync.gypi=pavely@chromium.org
-per-file browser_sync.gypi=stanisc@chromium.org
-per-file browser_sync.gypi=zea@chromium.org
+per-file bookmark_bar_strings.grdp=file://components/bookmarks/OWNERS
+per-file bookmarks.gypi=file://components/bookmarks/OWNERS
 
-per-file browsing_data.gypi=markusheintz@chromium.org
-per-file browsing_data.gypi=mkwst@chromium.org
-per-file browsing_data.gypi=bauerb@chromium.org
-per-file browsing_data.gypi=michaeln@chromium.org
+per-file browser_sync.gypi=file://components/browser_sync/OWNERS
 
-per-file bubble.gypi=groby@chromium.org
-per-file bubble.gypi=hcarmona@chromium.org
-per-file bubble.gypi=msw@chromium.org
-per-file bubble.gypi=rouslan@chromium.org
+per-file browsing_data.gypi=file://components/browsing_data/OWNERS
 
-per-file cdm.gypi=ddorwin@chromium.org
-per-file cdm.gypi=xhwang@chromium.org
+per-file bubble.gypi=file://components/bubble/OWNERS
 
-per-file cloud_devices*=gene@chromium.org
-per-file cloud_devices*=vitalybuka@chromium.org
+per-file cdm.gypi=file://components/cdm/OWNERS
 
-per-file chrome_apps.gypi=tbarzic@chromium.org
+per-file chrome_apps.gypi=file://components/chrome_apps/OWNERS
 
-per-file component_updater.gypi=sorin@chromium.org
-per-file component_updater.gypi=waffles@chromium.org
+per-file cloud_devices.gypi=file://components/cloud_devices/OWNERS
 
-per-file constrained_window*=gbillock@chromium.org
-per-file constrained_window*=msw@chromium.org
+per-file component_updater.gypi=file://components/component_updater/OWNERS
 
-per-file content_settings*=markusheintz@chromium.org
-per-file content_settings*=bauerb@chromium.org
-per-file content_settings*=jochen@chromium.org
+per-file constrained_window.gypi=file://components/constrained_window/OWNERS
 
-per-file copresence.gypi=rkc@chromium.org
-per-file copresence.gypi=ckehoe@chromium.org
-per-file copresence.gypi=xiyuan@chromium.org
-per-file copresence.gypi=derat@chromium.org
+per-file content_settings.gypi=file://components/content_settings/OWNERS
 
-per-file copresence_sockets.gypi=rkc@chromium.org
+per-file copresence.gypi=file://components/copresence/OWNERS
 
-per-file crash.gypi=jochen@chromium.org
-per-file crash.gypi=mark@chromium.org
-per-file crash.gypi=rsesek@chromium.org
-per-file crash.gypi=scottmg@chromium.org
-per-file crash.gypi=thestig@chromium.org
+per-file crash.gypi=file://components/crash/OWNERS
 
-per-file crash_keys.gypi=rsesek@chromium.org
+per-file cronet.gypi=file://components/cronet/OWNERS
 
-per-file cronet*=mef@chromium.org
-per-file cronet*=mmenke@chromium.org
-per-file cronet*=pauljensen@chromium.org
-per-file cronet*=xunjieli@chromium.org
+per-file data_reduction_proxy.gypi=file://components/data_reduction_proxy/OWNERS
 
-per-file data_reduction_proxy*=bengr@chromium.org
-per-file data_reduction_proxy*=bolian@chromium.org
-per-file data_reduction_proxy*=kundaji@chromium.org
-per-file data_reduction_proxy*=marq@chromium.org
-per-file data_reduction_proxy*=megjablon@chromium.org
-per-file data_reduction_proxy*=sclittle@chromium.org
-per-file data_reduction_proxy*=tbansal@chromium.org
+per-file data_usage.gypi=file://components/data_usage/OWNERS
 
-per-file data_usage*=bengr@chromium.org
-per-file data_usage*=sclittle@chromium.org
-per-file data_usage*=tbansal@chromium.org
+per-file data_use_measurement.gypi=file://components/data_use_measurement/OWNERS
 
-per-file data_use_measurement*=sclittle@chromium.org
-per-file data_use_measurement*=bengr@chromium.org
+per-file device_event_log.gypi=file://components/device_event_log/OWNERS
 
-per-file device_event_log*=stevenjb@chromium.org
-per-file device_event_log*=reillyg@chromium.org
+per-file devtools_discovery.gypi=file://components/devtools_discovery/OWNERS
 
-per-file devtools_discovery.gyp*=dgozman@chromium.org
-per-file devtools_discovery.gyp*=pfeldman@chromium.org
+per-file devtools_http_handler.gypi=file://components/devtools_http_handler/OWNERS
 
-per-file devtools_http_handler.gyp*=dgozman@chromium.org
-per-file devtools_http_handler.gyp*=pfeldman@chromium.org
+per-file dom_distiller.gypi=file://components/dom_distiller/OWNERS
+per-file dom_distiller_strings.grdp=file://components/dom_distiller/OWNERS
 
-per-file network_hints*=jar@chromium.org
-per-file network_hints*=ttuttle@chromium.org
+per-file domain_reliability.gypi=file://components/domain_reliability/OWNERS
 
-per-file dom_distiller*=bengr@chromium.org
-per-file dom_distiller*=mdjones@chromium.org
-per-file dom_distiller*=nyquist@chromium.org
-per-file dom_distiller*=wychen@chromium.org
+per-file drive.gypi=file://components/drive/OWNERS
 
-per-file domain_reliability.gypi=davidben@chromium.org
-per-file domain_reliability.gypi=rdsmith@chromium.org
-per-file domain_reliability.gypi=ttuttle@chromium.org
+per-file error_page.gypi=file://components/error_page/OWNERS
+per-file error_page_strings.grdp=file://components/error_page/OWNERS
 
-per-file drive.gypi=fukino@chromium.org
-per-file drive.gypi=hashimoto@chromium.org
-per-file drive.gypi=hidehiko@chromium.org
-per-file drive.gypi=hirono@chromium.org
-per-file drive.gypi=kinaba@chromium.org
-per-file drive.gypi=mtomasz@chromium.org
-per-file drive.gypi=yoshiki@chromium.org
+per-file exo.gypi=file://components/exo/OWNERS
 
-per-file error_page*=mmenke@chromium.org
-per-file error_page*=ttuttle@chromium.org
+per-file external_video_surface.gypi=file://components/external_video_surface/OWNERS
 
-per-file exo.gypi=reveman@chromium.org
+per-file favicon.gypi=file://components/favicon/OWNERS
+per-file favicon_base.gypi=file://components/favicon_base/OWNERS
 
-per-file external_video_surface.gypi=boliu@chromium.org
-per-file external_video_surface.gypi=qinmin@chromium.org
+per-file feedback.gypi=file://components/feedback/OWNERS
 
-per-file favicon*=pkotwicz@chromium.org
-per-file favicon*=sky@chromium.org
-per-file favicon*=stevenjb@chromium.org
+per-file gcm_driver.gypi=file://components/gcm_driver/OWNERS
 
-per-file feedback.gypi=bsimonnet@chromium.org
-per-file feedback.gypi=zork@chromium.org
+per-file google.gypi=file://components/google/OWNERS
 
-per-file gcm_driver.gypi=dimich@chromium.org
-per-file gcm_driver.gypi=fgorski@chromium.org
-per-file gcm_driver.gypi=jianli@chromium.org
-per-file gcm_driver.gypi=peter@chromium.org
-per-file gcm_driver.gypi=zea@chromium.org
+per-file guest_view.gypi=file://components/guest_view/OWNERS
 
-per-file google*=isherman@chromium.org
-per-file google*=pkasting@chromium.org
+per-file handoff.gypi=file://components/handoff/OWNERS
 
-per-file guest_view.gypi=fsamuel@chromium.org
-per-file guest_view.gypi=lazyboy@chromium.org
-per-file guest_view.gypi=hanxi@chromium.org
+per-file history.gypi=file://components/history/OWNERS
 
-per-file handoff.gypi=erikchen@chromium.org
+per-file infobars.gypi=file://components/infobars/OWNERS
 
-per-file history.gypi=sdefresne@chromium.org
-per-file history.gypi=sky@chromium.org
+per-file invalidation.gypi=file://components/invalidation/OWNERS
 
-per-file infobars.gypi=pkasting@chromium.org
+per-file json_schema.gypi=file://components/json_schema/OWNERS
 
-per-file invalidation.gypi=dcheng@chromium.org
-per-file invalidation.gypi=nyquist@chromium.org
-per-file invalidation.gypi=pavely@chromium.org
+per-file keyed_service.gypi=file://components/keyed_service/OWNERS
 
-per-file json_schema.gypi=asargent@chromium.org
-per-file json_schema.gypi=calamity@chromium.org
-per-file json_schema.gypi=mpcomplete@chromium.org
+per-file leveldb_proto.gypi=file://components/leveldb_proto/OWNERS
 
-per-file keyed_service.gypi=erg@chromium.org
-per-file keyed_service.gypi=phajdan.jr@chromium.org
+per-file login.gypi=file://components/login/OWNERS
 
-per-file leveldb_proto*=mathp@chromium.org
-per-file leveldb_proto*=nyquist@chromium.org
+per-file memory_pressure.gypi=file://components/memory_pressure/OWNERS
 
-per-file login*=alemate@chromium.org
-per-file login*=antrim@chromium.org
-per-file login*=dzhioev@chromium.org
-per-file login*=nkostylev@chromium.org
-per-file login*=achuith@chromium.org
+per-file metrics.gypi=file://components/metrics/OWNERS
+per-file metrics_services_manager.gypi=file://components/metrics_services_manager/OWNERS
 
-per-file memory_pressure*=chrisha@chromium.org
-per-file memory_pressure*=shrike@chromium.org
-per-file memory_pressure*=skuhne@chromium.org
+per-file nacl.gyp=file://components/nacl/OWNERS
+per-file nacl_helper_nonsfi_unittests.isolate=file://components/nacl/OWNERS
+per-file nacl_loader_unittests.isolate=file://components/nacl/OWNERS
+per-file nacl_nonsfi.gyp=file://components/nacl/OWNERS
 
-per-file metrics*=asvitkine@chromium.org
-per-file metrics*=mpearson@chromium.org
-per-file metrics*=jar@chromium.org
-per-file metrics*=isherman@chromium.org
-# OWNER-to-be: per-file metrics*=holte@chromium.org
+per-file navigation_interception.gypi=file://components/navigation_interception/OWNERS
 
-per-file nacl*=bradnelson@chromium.org
-per-file nacl*=dschuff@chromium.org
-per-file nacl*=mseaborn@chromium.org
-per-file nacl*=noelallen@chromium.org
+per-file network_hints.gypi=file://components/network_hints/OWNERS
 
-per-file navigation_interception.gypi=mnaganov@chromium.org
+per-file network_time.gypi=file://components/network_time/OWNERS
 
-per-file network_time.gypi=zea@chromium.org
+per-file ntp_snippets.gypi=file://components/ntp_snippets/OWNERS
 
-per-file ntp_snippets.gypi=noyau@chromium.org
-per-file ntp_snippets.gypi=bauerb@chromium.org
+per-file offline_pages.gypi=file://components/offline_pages/OWNERS
 
-per-file offline_pages*=dimich@chromium.org
-per-file offline_pages*=fgorski@chromium.org
+per-file omnibox.gypi=file://components/omnibox/OWNERS
 
-per-file omnibox.gypi=pkasting@chromium.org
-per-file omnibox.gypi=mpearson@chromium.org
+per-file onc.gypi=file://components/onc/OWNERS
 
-per-file onc.gypi=armansito@chromium.org
-per-file onc.gypi=cschuet@chromium.org
-per-file onc.gypi=gauravsh@chromium.org
-per-file onc.gypi=gspencer@chromium.org
-per-file onc.gypi=stevenjb@chromium.org
+per-file open_from_clipboard.gypi=file://components/open_from_clipboard/OWNERS
 
-per-file open_from_clipboard.gypi=jif@chromium.org
+per-file ownership.gypi=file://components/ownership/OWNERS
 
-per-file ownership.gypi=alemate@chromium.org
+per-file packed_ct_ev_whitelist.gypi=file://components/packed_ct_ev_whitelist/OWNERS
 
-per-file packed_ct_ev_whitelist.gypi=eranm@chromium.org
-per-file packed_ct_ev_whitelist.gypi=rsleevi@chromium.org
+per-file page_load_metrics.gypi=file://components/page_load_metrics/OWNERS
 
-per-file page_load_metrics.gypi=rdsmith@chromium.org
-per-file page_load_metrics.gypi=ttuttle@chromium.org
+per-file pairing.gypi=file://components/pairing/OWNERS
 
-per-file pairing.gypi=achuith@chromium.org
-per-file pairing.gypi=dzhioev@chromium.org
-per-file pairing.gypi=zork@chromium.org
+per-file password_manager.gypi=file://components/password_manager/OWNERS
+per-file password_manager_strings.grdp=file://components/password_manager/OWNERS
 
-per-file password_manager*=dvadym@chromium.org
-per-file password_manager*=engedy@chromium.org
-per-file password_manager*=gcasto@chromium.org
-per-file password_manager*=isherman@chromium.org
-per-file password_manager*=mkwst@chromium.org
-per-file password_manager*=vabr@chromium.org
-per-file password_manager*=vasilii@chromium.org
-
-per-file pdf.gypi=gene@chromium.org
-per-file pdf.gypi=jam@chromium.org
-per-file pdf.gypi=raymes@chromium.org
-per-file pdf.gypi=thestig@chromium.org
+per-file pdf.gypi=file://components/pdf/OWNERS
 per-file pdf_strings.grdp=raymes@chromium.org
 per-file pdf_strings.grdp=tsergeant@chromium.org
 
-per-file plugins.gypi=bauerb@chromium.org
-per-file plugins.gypi=tommycli@chromium.org
+per-file plugins.gypi=file://components/plugins/OWNERS
 
-per-file precache*=bengr@chromium.org
-per-file precache*=sclittle@chromium.org
+per-file policy.gypi=file://components/policy/OWNERS
+per-file policy_strings.grdp=file://components/policy/OWNERS
 
-per-file printing*=alekseys@chromium.org
-per-file printing*=gene@chromium.org
-per-file printing*=thestig@chromium.org
-per-file printing*=vitalybuka@chromium.org
+per-file precache.gypi=file://components/precache/OWNERS
 
-per-file policy*=bartfab@chromium.org
-per-file policy*=atwilson@chromium.org
-per-file policy*=cschuet@chromium.org
+per-file printing.gypi=file://components/printing/OWNERS
 
-per-file profile_metrics*=anthonyvd@chromium.org
-per-file profile_metrics*=erg@chromium.org
-per-file profile_metrics*=mlerman@chromium.org
+per-file profile_metrics.gypi=file://components/profile_metrics/OWNERS
 
-per-file proximity_auth*=isherman@chromium.org
-per-file proximity_auth*=tbarzic@chromium.org
-per-file proximity_auth*=tengs@chromium.org
-per-file proximity_auth*=xiyuan@chromium.org
+per-file proximity_auth.gypi=file://components/proximity_auth/OWNERS
 
-per-file proxy_config*=stevenjb@chromium.org
+per-file proxy_config.gypi=file://components/proxy_config/OWNERS
 
-per-file query_parser.gypi=sky@chromium.org
+per-file query_parser.gypi=file://components/query_parser/OWNERS
 
-per-file rappor*=asvitkine@chromium.org
-# OWNER-to-be: per-file rappor*=holte@chromium.org
+per-file rappor.gypi=file://components/rappor/OWNERS
 
-per-file renderer_context_menu*=avi@chromium.org
-per-file renderer_context_menu*=lazyboy@chromium.org
+per-file renderer_context_menu.gypi=file://components/renderer_context_menu/OWNERS
 
-per-file safe_browsing_db.gypi=nparker@chromium.org
+per-file safe_browsing_db.gypi=file://components/safe_browsing_db/OWNERS
 
-per-file safe_json.gypi=bauerb@chromium.org
-per-file safe_json.gypi=rsesek@chromium.org
+per-file safe_json.gypi=file://components/safe_json/OWNERS
 
 per-file search.gypi=file://components/search/OWNERS
 
-per-file search_engines.gypi=pkasting@chromium.org
-per-file search_engines.gypi=stevet@chromium.org
+per-file search_engines.gypi=file://components/search_engines/OWNERS
 
-per-file search_provider_logos*=newt@chromium.org
-per-file search_provider_logos*=justincohen@chromium.org
+per-file search_provider_logos.gypi=file://components/search_provider_logos/OWNERS
 
-per-file security_interstitials*=estark@chromium.org
-per-file security_interstitials*=felt@chromium.org
-per-file security_interstitials*=meacer@chromium.org
-per-file security_interstitials*=palmer@chromium.org
+per-file security_interstitials.gypi=file://components/security_interstitials/OWNERS
+per-file security_interstitials_strings.grdp=file://components/security_interstitials/OWNERS
 
-per-file session_manager.gypi=antrim@chromium.org
-per-file session_manager.gypi=dzhioev@chromium.org
-per-file session_manager.gypi=nkostylev@chromium.org
+per-file session_manager.gypi=file://components/session_manager/OWNERS
 
-per-file sessions.gypi=marja@chromium.org
-per-file sessions.gypi=sky@chromium.org
+per-file sessions.gypi=file://components/sessions/OWNERS
 
-per-file signin*=atwilson@chromium.org
-per-file signin*=rogerta@chromium.org
+per-file signin.gypi=file://components/signin/OWNERS
 
-per-file ssl_errors*=estark@chromium.org
-per-file ssl_errors*=felt@chromium.org
+per-file ssl_errors.gypi=file://components/ssl_errors/OWNERS
+per-file ssl_errors_strings.grdp=file://components/ssl_errors/OWNERS
 
-per-file startup_metric_utils.gypi=gab@chromium.org
-per-file startup_metric_utils.gypi=erikchen@chromium.org
+per-file startup_metric_utils.gypi=file://components/startup_metric_utils/OWNERS
 
-per-file storage_monitor.gypi=gbillock@chromium.org
-per-file storage_monitor.gypi=thestig@chromium.org
-per-file storage_monitor.gypi=vandebo@chromium.org
+per-file storage_monitor.gypi=file://components/storage_monitor/OWNERS
 
 per-file suggestions.gypi=file://components/suggestions/OWNERS
 
-per-file sync_driver*=pavely@chromium.org
-per-file sync_driver*=stanisc@chromium.org
-per-file sync_driver*=zea@chromium.org
+per-file sync_driver.gypi=file://components/sync_driver/OWNERS
 
-per-file sync_sessions.gypi=pavely@chromium.org
-per-file sync_sessions.gypi=stanisc@chromium.org
-per-file sync_sessions.gypi=zea@chromium.org
+per-file sync_sessions.gypi=file://components/sync_sessions/OWNERS
 
-per-file timers*=chirantan@chromium.org
-per-file timers*=derat@chromium.org
+per-file timers.gypi=file://components/timers/OWNERS
 
-per-file tracing*=jbauman@chromium.org
-per-file tracing*=nduca@chromium.org
-per-file tracing*=dsinclair@chromium.org
-per-file tracing*=simonhatch@chromium.org
+per-file tracing.gypi=file://components/tracing/OWNERS
+per-file tracing_nacl.gypi=file://components/tracing/OWNERS
 
-per-file translate.gypi=andrewhayden@chromium.org
-per-file translate.gypi=droger@chromium.org
-per-file translate.gypi=hajimehoshi@chromium.org
-per-file translate.gypi=toyoshim@chromium.org
-per-file translate_strings.grdp=andrewhayden@chromium.org
-per-file translate_strings.grdp=droger@chromium.org
-per-file translate_strings.grdp=hajimehoshi@chromium.org
-per-file translate_strings.grdp=toyoshim@chromium.org
+per-file translate.gypi=file://components/translate/OWNERS
+per-file translate_strings.grdp=file://components/translate/OWNERS
 
-per-file startup_metric_utils.gypi=jeremy@chromium.org
+per-file undo.gypi=file://components/undo/OWNERS
+per-file undo_strings.grdp=file://components/undo/OWNERS
 
-per-file undo.gypi=sky@chromium.org
-per-file undo.gypi=tom.cassiotis@gmail.com
-per-file undo_strings.grdp=sky@chromium.org
-per-file undo_strings.grdp=tom.cassiotis@gmail.com
+per-file update_client.gypi=file://components/update_client/OWNERS
 
-per-file update_client.gypi=sorin@chromium.org
-per-file update_client.gypi=waffles@chromium.org
+per-file url_formatter.gypi=file://components/url_formatter/OWNERS
 
-per-file user_manager.gypi=antrim@chromium.org
-per-file user_manager.gypi=dzhioev@chromium.org
-per-file user_manager.gypi=nkostylev@chromium.org
+per-file user_manager.gypi=file://components/user_manager/OWNERS
 
-per-file url_formatter.gypi=pkasting@chromium.org
+per-file user_prefs.gypi=file://components/user_prefs/OWNERS
 
-per-file user_prefs.gypi=battre@chromium.org
-per-file user_prefs.gypi=bauerb@chromium.org
-per-file user_prefs.gypi=gab@chromium.org
-per-file user_prefs.gypi=pam@chromium.org
+per-file variations.gypi=file://components/variations/OWNERS
 
-per-file variations.gypi=asvitkine@chromium.org
-per-file variations.gypi=jwd@chromium.org
-per-file variations.gypi=stevet@chromium.org
+per-file version_ui.gypi=file://components/version_ui/OWNERS
 
-per-file version_ui.gypi=bauerb@chromium.org
-per-file version_ui.gypi=dbeam@chromium.org
-per-file version_ui.gypi=estade@chromium.org
-per-file version_ui.gypi=nkostylev@chromium.org
-per-file version_ui.gypi=pam@chromium.org
-per-file version_ui.gypi=xiyuan@chromium.org
+per-file web_contents_delegate_android.gypi=file://components/web_contents_delegate_android/OWNERS
 
-per-file webdata.gypi=pkasting@chromium.org
-per-file webdata_services.gypi=pkasting@chromium.org
+per-file web_modal.gypi=file://components/web_modal/OWNERS
 
-per-file webp_transcode.gypi=droger@chromium.org
-per-file webp_transcode.gypi=sdefresne@chromium.org
+per-file web_resource.gypi=file://components/web_resource/OWNERS
 
-per-file web_contents_delegate_android.gypi=mnaganov@chromium.org
-per-file web_contents_delegate_android.gypi=tedchoc@chromium.org
+per-file web_restrictions.gypi=file://components/web_restrictions/OWNERS
 
-per-file web_modal.gypi=wittman@chromium.org
+per-file webdata.gypi=file://components/webdata/OWNERS
+per-file webdata_services.gypi=file://components/webdata_services/OWNERS
 
-per-file web_resource.gypi=achuith@chromium.org
-per-file web_resource.gypi=asvitkine@chromium.org
-per-file web_resource.gypi=dbeam@chromium.org
-per-file web_resource.gypi=rsesek@chromium.org
-per-file web_resource.gypi=stevet@chromium.org
+per-file webp_transcode.gypi=file://components/webp_transcode/OWNERS
 
-per-file web_restrictions.gypi=aberent@chromium.org
-per-file web_restrictions.gypi=bauerb@chromium.org
+per-file webusb.gypi=file://components/webusb/OWNERS
 
-per-file webusb.gypi=juncai@chromium.org
-per-file webusb.gypi=reillyg@chromium.org
-per-file webusb.gypi=rockot@chromium.org
-
-per-file wifi.gypi=mef@chromium.org
+per-file wifi.gypi=file://components/wifi/OWNERS
 
 per-file *.isolate=maruel@chromium.org
 per-file *.isolate=tandrii@chromium.org
diff --git a/components/autofill.gypi b/components/autofill.gypi
index ac1660d..1a6326f 100644
--- a/components/autofill.gypi
+++ b/components/autofill.gypi
@@ -108,8 +108,6 @@
         'autofill/core/browser/autocomplete_history_manager.cc',
         'autofill/core/browser/autocomplete_history_manager.h',
         'autofill/core/browser/autofill-inl.h',
-        'autofill/core/browser/autofill_cc_infobar_delegate.cc',
-        'autofill/core/browser/autofill_cc_infobar_delegate.h',
         'autofill/core/browser/autofill_client.h',
         'autofill/core/browser/autofill_country.cc',
         'autofill/core/browser/autofill_country.h',
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index eed6113..cd0d17e 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -25,8 +25,6 @@
     "autocomplete_history_manager.cc",
     "autocomplete_history_manager.h",
     "autofill-inl.h",
-    "autofill_cc_infobar_delegate.cc",
-    "autofill_cc_infobar_delegate.h",
     "autofill_client.h",
     "autofill_country.cc",
     "autofill_country.h",
diff --git a/components/autofill/core/browser/autofill_cc_infobar_delegate.cc b/components/autofill/core/browser/autofill_cc_infobar_delegate.cc
deleted file mode 100644
index d065307..0000000
--- a/components/autofill/core/browser/autofill_cc_infobar_delegate.cc
+++ /dev/null
@@ -1,130 +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 "components/autofill/core/browser/autofill_cc_infobar_delegate.h"
-
-#include "base/logging.h"
-#include "build/build_config.h"
-#include "components/autofill/core/browser/credit_card.h"
-#include "components/autofill/core/browser/personal_data_manager.h"
-#include "components/autofill/core/common/autofill_constants.h"
-#include "components/infobars/core/infobar.h"
-#include "components/infobars/core/infobar_manager.h"
-#include "grit/components_scaled_resources.h"
-#include "grit/components_strings.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/gfx/vector_icons_public.h"
-#include "url/gurl.h"
-
-namespace autofill {
-
-// static
-void AutofillCCInfoBarDelegate::CreateForLocalSave(
-    infobars::InfoBarManager* infobar_manager,
-    const base::Closure& save_card_callback) {
-  infobar_manager->AddInfoBar(
-      infobar_manager->CreateConfirmInfoBar(scoped_ptr<ConfirmInfoBarDelegate>(
-          new AutofillCCInfoBarDelegate(false, save_card_callback))));
-}
-
-// static
-void AutofillCCInfoBarDelegate::CreateForUpload(
-    infobars::InfoBarManager* infobar_manager,
-    const base::Closure& save_card_callback) {
-  infobar_manager->AddInfoBar(
-      infobar_manager->CreateConfirmInfoBar(scoped_ptr<ConfirmInfoBarDelegate>(
-          new AutofillCCInfoBarDelegate(true, save_card_callback))));
-}
-
-AutofillCCInfoBarDelegate::~AutofillCCInfoBarDelegate() {
-  if (!had_user_interaction_)
-    LogUserAction(AutofillMetrics::INFOBAR_IGNORED);
-}
-
-int AutofillCCInfoBarDelegate::GetIconId() const {
-  return IDR_INFOBAR_AUTOFILL_CC;
-}
-
-base::string16 AutofillCCInfoBarDelegate::GetMessageText() const {
-  return l10n_util::GetStringUTF16(
-      upload_ ? IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD
-              : IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_LOCAL);
-}
-
-base::string16 AutofillCCInfoBarDelegate::GetLinkText() const {
-  return l10n_util::GetStringUTF16(IDS_LEARN_MORE);
-}
-
-AutofillCCInfoBarDelegate::AutofillCCInfoBarDelegate(
-    bool upload,
-    const base::Closure& save_card_callback)
-    : ConfirmInfoBarDelegate(),
-      upload_(upload),
-      save_card_callback_(save_card_callback),
-      had_user_interaction_(false) {
-  AutofillMetrics::LogCreditCardInfoBarMetric(AutofillMetrics::INFOBAR_SHOWN);
-}
-
-void AutofillCCInfoBarDelegate::LogUserAction(
-    AutofillMetrics::InfoBarMetric user_action) {
-  DCHECK(!had_user_interaction_);
-
-  AutofillMetrics::LogCreditCardInfoBarMetric(user_action);
-  had_user_interaction_ = true;
-}
-
-infobars::InfoBarDelegate::InfoBarIdentifier
-AutofillCCInfoBarDelegate::GetIdentifier() const {
-  return AUTOFILL_CC_INFOBAR_DELEGATE;
-}
-
-infobars::InfoBarDelegate::Type
-AutofillCCInfoBarDelegate::GetInfoBarType() const {
-  return PAGE_ACTION_TYPE;
-}
-
-gfx::VectorIconId AutofillCCInfoBarDelegate::GetVectorIconId() const {
-#if !defined(OS_MACOSX) && !defined(OS_IOS) && !defined(OS_ANDROID)
-  return gfx::VectorIconId::AUTOFILL;
-#else
-  return gfx::VectorIconId::VECTOR_ICON_NONE;
-#endif
-}
-
-bool AutofillCCInfoBarDelegate::ShouldExpire(
-    const NavigationDetails& details) const {
-  // The user has submitted a form, causing the page to navigate elsewhere. We
-  // don't want the infobar to be expired at this point, because the user won't
-  // get a chance to answer the question.
-  return false;
-}
-
-void AutofillCCInfoBarDelegate::InfoBarDismissed() {
-  LogUserAction(AutofillMetrics::INFOBAR_DENIED);
-}
-
-base::string16 AutofillCCInfoBarDelegate::GetButtonLabel(
-    InfoBarButton button) const {
-  return l10n_util::GetStringUTF16(button == BUTTON_OK
-                                       ? IDS_AUTOFILL_SAVE_CARD_PROMPT_ACCEPT
-                                       : IDS_AUTOFILL_SAVE_CARD_PROMPT_DENY);
-}
-
-bool AutofillCCInfoBarDelegate::Accept() {
-  save_card_callback_.Run();
-  save_card_callback_.Reset();
-  LogUserAction(AutofillMetrics::INFOBAR_ACCEPTED);
-  return true;
-}
-
-bool AutofillCCInfoBarDelegate::Cancel() {
-  LogUserAction(AutofillMetrics::INFOBAR_DENIED);
-  return true;
-}
-
-GURL AutofillCCInfoBarDelegate::GetLinkURL() const {
-  return GURL(kHelpURL);
-}
-
-}  // namespace autofill
diff --git a/components/autofill/core/browser/autofill_cc_infobar_delegate.h b/components/autofill/core/browser/autofill_cc_infobar_delegate.h
deleted file mode 100644
index 7323dac..0000000
--- a/components/autofill/core/browser/autofill_cc_infobar_delegate.h
+++ /dev/null
@@ -1,82 +0,0 @@
-// 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.
-
-#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_CC_INFOBAR_DELEGATE_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_CC_INFOBAR_DELEGATE_H_
-
-#include "base/callback.h"
-#include "base/gtest_prod_util.h"
-#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/strings/string16.h"
-#include "components/autofill/core/browser/autofill_metrics.h"
-#include "components/infobars/core/confirm_infobar_delegate.h"
-#include "ui/base/window_open_disposition.h"
-
-namespace infobars {
-class InfoBarManager;
-}
-
-namespace autofill {
-
-// An InfoBar delegate that enables the user to allow or deny storing credit
-// card information gathered from a form submission.
-class AutofillCCInfoBarDelegate : public ConfirmInfoBarDelegate {
- public:
-  // Creates an autofill credit card infobar and delegate and adds the infobar
-  // to |infobar_manager|.
-  static void CreateForLocalSave(infobars::InfoBarManager* infobar_manager,
-                                 const base::Closure& save_card_callback);
-  static void CreateForUpload(infobars::InfoBarManager* infobar_manager,
-                              const base::Closure& save_card_callback);
-
-#if defined(UNIT_TEST)
-  static scoped_ptr<ConfirmInfoBarDelegate> Create(
-      const base::Closure& save_card_callback) {
-    return scoped_ptr<ConfirmInfoBarDelegate>(
-        new AutofillCCInfoBarDelegate(false, save_card_callback));
-  }
-#endif
-
-  ~AutofillCCInfoBarDelegate() override;
-
-  // ConfirmInfoBarDelegate:
-  int GetIconId() const override;
-  base::string16 GetMessageText() const override;
-  base::string16 GetLinkText() const override;
-
- protected:
-  AutofillCCInfoBarDelegate(bool upload,
-                            const base::Closure& save_card_callback);
-
- private:
-  void LogUserAction(AutofillMetrics::InfoBarMetric user_action);
-
-  // ConfirmInfoBarDelegate:
-  Type GetInfoBarType() const override;
-  infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
-  gfx::VectorIconId GetVectorIconId() const override;
-  bool ShouldExpire(const NavigationDetails& details) const override;
-  void InfoBarDismissed() override;
-  base::string16 GetButtonLabel(InfoBarButton button) const override;
-  bool Accept() override;
-  bool Cancel() override;
-  GURL GetLinkURL() const override;
-
-  bool upload_;
-
-  // The callback to save credit card if the user accepts the infobar.
-  base::Closure save_card_callback_;
-
-  // Did the user ever explicitly accept or dismiss this infobar?
-  bool had_user_interaction_;
-
-  FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, CreditCardInfoBar);
-
-  DISALLOW_COPY_AND_ASSIGN(AutofillCCInfoBarDelegate);
-};
-
-}  // namespace autofill
-
-#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_CC_INFOBAR_DELEGATE_H_
diff --git a/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc b/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc
index 66dc2d9..9c93cfe4 100644
--- a/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc
+++ b/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc
@@ -10,9 +10,14 @@
 #include "base/values.h"
 #include "components/autofill/core/browser/credit_card.h"
 #include "components/autofill/core/browser/legal_message_line.h"
+#include "components/autofill/core/common/autofill_constants.h"
 #include "components/infobars/core/infobar.h"
 #include "components/infobars/core/infobar_manager.h"
+#include "grit/components_scaled_resources.h"
+#include "grit/components_strings.h"
+#include "ui/base/l10n/l10n_util.h"
 #include "ui/base/window_open_disposition.h"
+#include "ui/gfx/vector_icons_public.h"
 #include "url/gurl.h"
 
 namespace autofill {
@@ -22,27 +27,101 @@
     const CreditCard& card,
     scoped_ptr<base::DictionaryValue> legal_message,
     const base::Closure& save_card_callback)
-    : AutofillCCInfoBarDelegate(upload, save_card_callback),
+    : ConfirmInfoBarDelegate(),
+      upload_(upload),
+      save_card_callback_(save_card_callback),
+      had_user_interaction_(false),
 #if defined(OS_IOS)
       // TODO(jdonnelly): Use credit card issuer images on iOS.
       // http://crbug.com/535784
       issuer_icon_id_(kNoIconID),
 #else
-      issuer_icon_id_(CreditCard::IconResourceId(
-          CreditCard::GetCreditCardType(card.GetRawInfo(CREDIT_CARD_NUMBER)))),
+      issuer_icon_id_(CreditCard::IconResourceId(card.type())),
 #endif
       card_label_(base::string16(kMidlineEllipsis) + card.LastFourDigits()),
       card_sub_label_(card.AbbreviatedExpirationDateForDisplay()) {
   if (legal_message)
     LegalMessageLine::Parse(*legal_message, &legal_messages_);
+
+  AutofillMetrics::LogCreditCardInfoBarMetric(AutofillMetrics::INFOBAR_SHOWN);
 }
 
 AutofillSaveCardInfoBarDelegateMobile::
-    ~AutofillSaveCardInfoBarDelegateMobile() {}
+    ~AutofillSaveCardInfoBarDelegateMobile() {
+  if (!had_user_interaction_)
+    LogUserAction(AutofillMetrics::INFOBAR_IGNORED);
+}
 
 void AutofillSaveCardInfoBarDelegateMobile::OnLegalMessageLinkClicked(
     GURL url) {
   infobar()->owner()->OpenURL(url, NEW_FOREGROUND_TAB);
 }
 
+int AutofillSaveCardInfoBarDelegateMobile::GetIconId() const {
+  return IDR_INFOBAR_AUTOFILL_CC;
+}
+
+base::string16 AutofillSaveCardInfoBarDelegateMobile::GetMessageText() const {
+  return l10n_util::GetStringUTF16(
+      upload_ ? IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD
+              : IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_LOCAL);
+}
+
+base::string16 AutofillSaveCardInfoBarDelegateMobile::GetLinkText() const {
+  return l10n_util::GetStringUTF16(IDS_LEARN_MORE);
+}
+
+infobars::InfoBarDelegate::Type
+AutofillSaveCardInfoBarDelegateMobile::GetInfoBarType() const {
+  return PAGE_ACTION_TYPE;
+}
+
+infobars::InfoBarDelegate::InfoBarIdentifier
+AutofillSaveCardInfoBarDelegateMobile::GetIdentifier() const {
+  return AUTOFILL_CC_INFOBAR_DELEGATE;
+}
+
+bool AutofillSaveCardInfoBarDelegateMobile::ShouldExpire(
+    const NavigationDetails& details) const {
+  // The user has submitted a form, causing the page to navigate elsewhere. We
+  // don't want the infobar to be expired at this point, because the user won't
+  // get a chance to answer the question.
+  return false;
+}
+
+void AutofillSaveCardInfoBarDelegateMobile::InfoBarDismissed() {
+  LogUserAction(AutofillMetrics::INFOBAR_DENIED);
+}
+
+base::string16 AutofillSaveCardInfoBarDelegateMobile::GetButtonLabel(
+    InfoBarButton button) const {
+  return l10n_util::GetStringUTF16(button == BUTTON_OK
+                                       ? IDS_AUTOFILL_SAVE_CARD_PROMPT_ACCEPT
+                                       : IDS_AUTOFILL_SAVE_CARD_PROMPT_DENY);
+}
+
+bool AutofillSaveCardInfoBarDelegateMobile::Accept() {
+  save_card_callback_.Run();
+  save_card_callback_.Reset();
+  LogUserAction(AutofillMetrics::INFOBAR_ACCEPTED);
+  return true;
+}
+
+bool AutofillSaveCardInfoBarDelegateMobile::Cancel() {
+  LogUserAction(AutofillMetrics::INFOBAR_DENIED);
+  return true;
+}
+
+GURL AutofillSaveCardInfoBarDelegateMobile::GetLinkURL() const {
+  return GURL(kHelpURL);
+}
+
+void AutofillSaveCardInfoBarDelegateMobile::LogUserAction(
+    AutofillMetrics::InfoBarMetric user_action) {
+  DCHECK(!had_user_interaction_);
+
+  AutofillMetrics::LogCreditCardInfoBarMetric(user_action);
+  had_user_interaction_ = true;
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h b/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h
index 7610d0c..3f1aeaaf 100644
--- a/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h
+++ b/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h
@@ -9,8 +9,9 @@
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
-#include "components/autofill/core/browser/autofill_cc_infobar_delegate.h"
+#include "components/autofill/core/browser/autofill_metrics.h"
 #include "components/autofill/core/browser/legal_message_line.h"
+#include "components/infobars/core/confirm_infobar_delegate.h"
 
 namespace base {
 class DictionaryValue;
@@ -20,8 +21,9 @@
 
 class CreditCard;
 
-// An InfoBarDelegate for saving credit cards on mobile devices.
-class AutofillSaveCardInfoBarDelegateMobile : public AutofillCCInfoBarDelegate {
+// An InfoBarDelegate that enables the user to allow or deny storing credit
+// card information gathered from a form submission. Only used on mobile.
+class AutofillSaveCardInfoBarDelegateMobile : public ConfirmInfoBarDelegate {
  public:
   AutofillSaveCardInfoBarDelegateMobile(
       bool upload,
@@ -39,7 +41,31 @@
   // Called when a link in the legal message text was clicked.
   void OnLegalMessageLinkClicked(GURL url);
 
+  // ConfirmInfoBarDelegate:
+  int GetIconId() const override;
+  base::string16 GetMessageText() const override;
+  base::string16 GetLinkText() const override;
+  Type GetInfoBarType() const override;
+  infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
+  bool ShouldExpire(const NavigationDetails& details) const override;
+  void InfoBarDismissed() override;
+  base::string16 GetButtonLabel(InfoBarButton button) const override;
+  bool Accept() override;
+  bool Cancel() override;
+  GURL GetLinkURL() const override;
+
  private:
+  void LogUserAction(AutofillMetrics::InfoBarMetric user_action);
+
+  // Whether the action is an upload or a local save.
+  bool upload_;
+
+  // The callback to save credit card if the user accepts the infobar.
+  base::Closure save_card_callback_;
+
+  // Did the user ever explicitly accept or dismiss this infobar?
+  bool had_user_interaction_;
+
   // The resource ID for the icon that identifies the issuer of the card.
   int issuer_icon_id_;
 
diff --git a/components/browser_sync/browser/profile_sync_service.cc b/components/browser_sync/browser/profile_sync_service.cc
index 67987b2..185438f 100644
--- a/components/browser_sync/browser/profile_sync_service.cc
+++ b/components/browser_sync/browser/profile_sync_service.cc
@@ -250,7 +250,7 @@
   sync_client_->Initialize();
 
   startup_controller_.reset(new browser_sync::StartupController(
-      start_behavior_, oauth2_token_service_, &sync_prefs_, signin_.get(),
+      oauth2_token_service_, &sync_prefs_, signin_.get(),
       base::Bind(&ProfileSyncService::StartUpSlowBackendComponents,
                  startup_controller_weak_factory_.GetWeakPtr())));
   scoped_ptr<browser_sync::LocalSessionEventRouter> router(
@@ -815,6 +815,9 @@
 
 void ProfileSyncService::SetFirstSetupComplete() {
   sync_prefs_.SetFirstSetupComplete();
+  if (IsBackendInitialized()) {
+    ReconfigureDatatypeManager();
+  }
 }
 
 void ProfileSyncService::UpdateLastSyncedTime() {
@@ -932,20 +935,12 @@
     UpdateLastSyncedTime();
   }
 
-  if (startup_controller_->auto_start_enabled() && !IsFirstSetupInProgress()) {
-    // Backend is initialized but we're not in sync setup, so this must be an
-    // autostart - mark our sync setup as completed and we'll start syncing
-    // below.
+  // Auto-start means IsFirstSetupComplete gets set automatically.
+  if (start_behavior_ == browser_sync::AUTO_START && !IsFirstSetupComplete()) {
+    // This will trigger a configure if it completes setup.
     SetFirstSetupComplete();
-  }
-
-  // Check IsFirstSetupComplete() before NotifyObservers() to avoid spurious
-  // data type configuration because observer may flag setup as complete and
-  // trigger data type configuration.
-  if (IsFirstSetupComplete()) {
+  } else if (CanConfigureDataTypes()) {
     ConfigureDataTypeManager();
-  } else {
-    DCHECK(IsFirstSetupInProgress());
   }
 
   NotifyObservers();
@@ -1237,15 +1232,11 @@
                                   syncer::STOP_SOURCE_LIMIT);
       }
       RequestStop(CLEAR_DATA);
-#if !defined(OS_CHROMEOS)
-      // On desktop Chrome, sign out the user after a dashboard clear.
-      // Skip sign out on ChromeOS/Android.
-      if (!startup_controller_->auto_start_enabled()) {
-        SigninManager* signin_manager =
-            static_cast<SigninManager*>(signin_->GetOriginal());
-        signin_manager->SignOut(signin_metrics::SERVER_FORCED_DISABLE,
-                                signin_metrics::SignoutDelete::IGNORE_METRIC);
-      }
+#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
+      // On desktop and iOS, sign out the user after a dashboard clear.
+      static_cast<SigninManager*>(signin_->GetOriginal())
+          ->SignOut(signin_metrics::SERVER_FORCED_DISABLE,
+                    signin_metrics::SignoutDelete::IGNORE_METRIC);
 #endif
       break;
     case syncer::STOP_SYNC_FOR_DISABLED_ACCOUNT:
@@ -1455,10 +1446,6 @@
   return startup_controller_->GetBackendInitializationStateString();
 }
 
-bool ProfileSyncService::auto_start_enabled() const {
-  return startup_controller_->auto_start_enabled();
-}
-
 bool ProfileSyncService::IsSetupInProgress() const {
   return startup_controller_->IsSetupInProgress();
 }
@@ -1480,6 +1467,10 @@
   return last_auth_error_;
 }
 
+bool ProfileSyncService::CanConfigureDataTypes() const {
+  return IsFirstSetupComplete() && !IsSetupInProgress();
+}
+
 bool ProfileSyncService::IsFirstSetupInProgress() const {
   return !IsFirstSetupComplete() && startup_controller_->IsSetupInProgress();
 }
@@ -1738,7 +1729,7 @@
   // start syncing data until the user is done configuring encryption options,
   // etc. ReconfigureDatatypeManager() will get called again once the UI calls
   // SetSetupInProgress(false).
-  if (startup_controller_->IsSetupInProgress())
+  if (!CanConfigureDataTypes())
     return;
 
   bool restart = false;
diff --git a/components/browser_sync/browser/profile_sync_service.h b/components/browser_sync/browser/profile_sync_service.h
index df981bc3..bd48e87 100644
--- a/components/browser_sync/browser/profile_sync_service.h
+++ b/components/browser_sync/browser/profile_sync_service.h
@@ -165,14 +165,8 @@
 //   up sync at least once on their account. SetSetupInProgress(true) should be
 //   called while the user is actively configuring their account, and then
 //   SetSetupInProgress(false) should be called when configuration is complete.
-//   When SetFirstSetupComplete() == false, but SetSetupInProgress(true) has
-//   been called, then the sync engine knows not to download any user data.
-//
-//   When initial sync is complete, the UI code should call
-//   SetFirstSetupComplete() followed by SetSetupInProgress(false) - this will
-//   tell the sync engine that setup is completed and it can begin downloading
-//   data from the sync server.
-//
+//   Once both these conditions have been met, CanConfigureDataTypes() will
+//   return true and datatype configuration can begin.
 class ProfileSyncService : public sync_driver::SyncService,
                            public sync_driver::SyncFrontend,
                            public sync_driver::SyncPrefObserver,
@@ -508,9 +502,6 @@
 
   SigninManagerBase* signin() const;
 
-  // Used by tests.
-  bool auto_start_enabled() const;
-
   SyncErrorController* sync_error_controller() {
     return sync_error_controller_.get();
   }
@@ -782,6 +773,9 @@
   // Restarts sync clearing directory in the process.
   void OnClearServerDataDone();
 
+  // True if setup has been completed at least once and is not in progress.
+  bool CanConfigureDataTypes() const;
+
   // This profile's SyncClient, which abstracts away non-Sync dependencies and
   // the Sync API component factory.
   scoped_ptr<sync_driver::SyncClient> sync_client_;
diff --git a/components/browser_sync/browser/profile_sync_service_startup_unittest.cc b/components/browser_sync/browser/profile_sync_service_startup_unittest.cc
index 206ce89..98f66d1b 100644
--- a/components/browser_sync/browser/profile_sync_service_startup_unittest.cc
+++ b/components/browser_sync/browser/profile_sync_service_startup_unittest.cc
@@ -208,6 +208,7 @@
 
   // Simulate the UI telling sync it has finished setting up.
   sync_service_->SetSetupInProgress(false);
+  sync_service_->SetFirstSetupComplete();
   EXPECT_TRUE(sync_service_->IsSyncActive());
 }
 
@@ -411,26 +412,32 @@
   SetUpSyncBackendHost();
   DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
   EXPECT_CALL(*data_type_manager, Configure(_, _));
+  EXPECT_CALL(*data_type_manager, state())
+      .WillRepeatedly(Return(DataTypeManager::CONFIGURED));
   EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
   IssueTestTokens(account_id);
   sync_service_->Initialize();
+  EXPECT_TRUE(sync_service_->IsBackendInitialized());
+  EXPECT_TRUE(sync_service_->IsSyncActive());
 
   // The service should stop when switching to managed mode.
   Mock::VerifyAndClearExpectations(data_type_manager);
   EXPECT_CALL(*data_type_manager, state()).
       WillOnce(Return(DataTypeManager::CONFIGURED));
   EXPECT_CALL(*data_type_manager, Stop()).Times(1);
-  EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
   pref_service()->SetBoolean(sync_driver::prefs::kSyncManaged, true);
+  EXPECT_FALSE(sync_service_->IsBackendInitialized());
+  // Note that PSS no longer references |data_type_manager| after stopping.
 
-  // When switching back to unmanaged, the state should change, but the service
-  // should not start up automatically (kSyncFirstSetupComplete will be
-  // false).
-  Mock::VerifyAndClearExpectations(data_type_manager);
+  // When switching back to unmanaged, the state should change and sync should
+  // start but not become active because IsFirstSetupComplete() will be false.
+  SetUpSyncBackendHost();
+  // A new DataTypeManager should not be created.
   EXPECT_CALL(*component_factory_, CreateDataTypeManager(_, _, _, _, _))
       .Times(0);
-  EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
   pref_service()->ClearPref(sync_driver::prefs::kSyncManaged);
+  EXPECT_TRUE(sync_service_->IsBackendInitialized());
+  EXPECT_FALSE(sync_service_->IsSyncActive());
 }
 
 TEST_F(ProfileSyncServiceStartupTest, StartFailure) {
diff --git a/components/browser_sync/browser/profile_sync_service_unittest.cc b/components/browser_sync/browser/profile_sync_service_unittest.cc
index b348ffa..be52cbe 100644
--- a/components/browser_sync/browser/profile_sync_service_unittest.cc
+++ b/components/browser_sync/browser/profile_sync_service_unittest.cc
@@ -92,14 +92,15 @@
 class TestSyncServiceObserver : public sync_driver::SyncServiceObserver {
  public:
   explicit TestSyncServiceObserver(ProfileSyncService* service)
-      : service_(service), first_setup_in_progress_(false) {}
+      : service_(service), setup_in_progress_(false) {}
   void OnStateChanged() override {
-    first_setup_in_progress_ = service_->IsFirstSetupInProgress();
+    setup_in_progress_ = service_->IsSetupInProgress();
   }
-  bool first_setup_in_progress() const { return first_setup_in_progress_; }
+  bool setup_in_progress() const { return setup_in_progress_; }
+
  private:
   ProfileSyncService* service_;
-  bool first_setup_in_progress_;
+  bool setup_in_progress_;
 };
 
 // A variant of the SyncBackendHostMock that won't automatically
@@ -265,8 +266,7 @@
 
   void InitializeForNthSync() {
     // Set first sync time before initialize to simulate a complete sync setup.
-    sync_driver::SyncPrefs sync_prefs(
-        service_->GetSyncClient()->GetPrefService());
+    sync_driver::SyncPrefs sync_prefs(prefs());
     sync_prefs.SetFirstSyncTime(base::Time::Now());
     sync_prefs.SetFirstSetupComplete();
     sync_prefs.SetKeepEverythingSynced(true);
@@ -423,9 +423,9 @@
   service()->AddObserver(&observer);
 
   service()->SetSetupInProgress(true);
-  EXPECT_TRUE(observer.first_setup_in_progress());
+  EXPECT_TRUE(observer.setup_in_progress());
   service()->SetSetupInProgress(false);
-  EXPECT_FALSE(observer.first_setup_in_progress());
+  EXPECT_FALSE(observer.setup_in_progress());
 
   service()->RemoveObserver(&observer);
 }
@@ -477,23 +477,21 @@
 TEST_F(ProfileSyncServiceTest, EarlyRequestStop) {
   CreateService(browser_sync::AUTO_START);
   IssueTestTokens();
-
-  service()->RequestStop(ProfileSyncService::KEEP_DATA);
-  EXPECT_TRUE(prefs()->GetBoolean(sync_driver::prefs::kSyncSuppressStart));
-
-  // Because of suppression, this should fail.
-  sync_driver::SyncPrefs sync_prefs(
-      service()->GetSyncClient()->GetPrefService());
-  sync_prefs.SetFirstSyncTime(base::Time::Now());
-  service()->Initialize();
-  EXPECT_FALSE(service()->IsSyncActive());
-
-  // Request start.  This should be enough to allow init to happen.
   ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
   ExpectSyncBackendHostCreation(1);
+
+  service()->RequestStop(ProfileSyncService::KEEP_DATA);
+  EXPECT_FALSE(service()->IsSyncRequested());
+
+  // Because sync is not requested, this should fail.
+  InitializeForNthSync();
+  EXPECT_FALSE(service()->IsSyncRequested());
+  EXPECT_FALSE(service()->IsSyncActive());
+
+  // Request start. This should be enough to allow init to happen.
   service()->RequestStart();
+  EXPECT_TRUE(service()->IsSyncRequested());
   EXPECT_TRUE(service()->IsSyncActive());
-  EXPECT_FALSE(prefs()->GetBoolean(sync_driver::prefs::kSyncSuppressStart));
 }
 
 // Test RequestStop() after we've initialized the backend.
diff --git a/components/cdm/browser/widevine_drm_delegate_android.cc b/components/cdm/browser/widevine_drm_delegate_android.cc
index ba09143..d4133ee 100644
--- a/components/cdm/browser/widevine_drm_delegate_android.cc
+++ b/components/cdm/browser/widevine_drm_delegate_android.cc
@@ -36,9 +36,13 @@
   if (init_data_type != media::EmeInitDataType::CENC)
     return true;
 
+#if defined(PROPRIETARY_CODECS)
   // Widevine MediaDrm plugin only accepts the "data" part of the PSSH box as
   // the init data when using MP4 container.
   return media::GetPsshData(init_data, GetUUID(), init_data_out);
+#else
+  return false;
+#endif
 }
 
 }  // namespace cdm
diff --git a/components/cronet/android/java/src/org/chromium/net/CronetUploadDataStream.java b/components/cronet/android/java/src/org/chromium/net/CronetUploadDataStream.java
index 6256d46..a1a6e4f 100644
--- a/components/cronet/android/java/src/org/chromium/net/CronetUploadDataStream.java
+++ b/components/cronet/android/java/src/org/chromium/net/CronetUploadDataStream.java
@@ -232,7 +232,7 @@
     /**
      * Posts task to application Executor.
      */
-    private void postTaskToExecutor(Runnable task) {
+    void postTaskToExecutor(Runnable task) {
         try {
             mExecutor.execute(task);
         } catch (Throwable e) {
@@ -293,34 +293,35 @@
     }
 
     /**
-     * Creates native objects and attaches them to the underlying request
-     * adapter object.
-     * TODO(mmenke):  If more types of native upload streams are needed, create
-     * an interface with just this method, to minimize CronetURLRequest's
-     * dependencies on each upload stream type.
+     * Initializes upload length by getting it from data provider. Always called
+     * on executor thread to allow getLength() to block and/or report errors.
+     * If data provider throws an exception, then it is reported to the request.
+     * No native calls to urlRequest are allowed as this is done before request
+     * start, so native object may not exist.
      */
-    void attachToRequest(final CronetUrlRequest request, final long requestAdapter,
-            final Runnable afterAttachCallback) {
-        mRequest = request;
-        postTaskToExecutor(new Runnable() {
-            @Override
-            public void run() {
-                synchronized (mLock) {
-                    mInWhichUserCallback = UserCallback.GET_LENGTH;
-                }
-                try {
-                    mLength = mDataProvider.getLength();
-                } catch (Throwable t) {
-                    onError(t);
-                }
-                synchronized (mLock) {
-                    mInWhichUserCallback = UserCallback.NOT_IN_CALLBACK;
-                    mUploadDataStreamAdapter =
-                            nativeAttachUploadDataToRequest(requestAdapter, mLength);
-                }
-                afterAttachCallback.run();
-            }
-        });
+    void initializeWithRequest(final CronetUrlRequest urlRequest) {
+        synchronized (mLock) {
+            mRequest = urlRequest;
+            mInWhichUserCallback = UserCallback.GET_LENGTH;
+        }
+        try {
+            mLength = mDataProvider.getLength();
+        } catch (Throwable t) {
+            onError(t);
+        }
+        synchronized (mLock) {
+            mInWhichUserCallback = UserCallback.NOT_IN_CALLBACK;
+        }
+    }
+
+    /**
+     * Creates native objects and attaches them to the underlying request
+     * adapter object. Always called on executor thread.
+     */
+    void attachNativeAdapterToRequest(final long requestAdapter) {
+        synchronized (mLock) {
+            mUploadDataStreamAdapter = nativeAttachUploadDataToRequest(requestAdapter, mLength);
+        }
     }
 
     /**
@@ -330,10 +331,11 @@
      */
     @VisibleForTesting
     long createUploadDataStreamForTesting() throws IOException {
-        mUploadDataStreamAdapter = nativeCreateAdapterForTesting();
-        mLength = mDataProvider.getLength();
-        return nativeCreateUploadDataStreamForTesting(mLength,
-                mUploadDataStreamAdapter);
+        synchronized (mLock) {
+            mUploadDataStreamAdapter = nativeCreateAdapterForTesting();
+            mLength = mDataProvider.getLength();
+            return nativeCreateUploadDataStreamForTesting(mLength, mUploadDataStreamAdapter);
+        }
     }
 
     @VisibleForTesting
diff --git a/components/cronet/android/java/src/org/chromium/net/CronetUrlRequest.java b/components/cronet/android/java/src/org/chromium/net/CronetUrlRequest.java
index e03e97dd..01d241e 100644
--- a/components/cronet/android/java/src/org/chromium/net/CronetUrlRequest.java
+++ b/components/cronet/android/java/src/org/chromium/net/CronetUrlRequest.java
@@ -211,10 +211,15 @@
                                 "Requests with upload data must have a Content-Type.");
                     }
                     mStarted = true;
-                    mUploadDataStream.attachToRequest(this, mUrlRequestAdapter, new Runnable() {
+                    mUploadDataStream.postTaskToExecutor(new Runnable() {
                         @Override
                         public void run() {
+                            mUploadDataStream.initializeWithRequest(CronetUrlRequest.this);
                             synchronized (mUrlRequestAdapterLock) {
+                                if (isDoneLocked()) {
+                                    return;
+                                }
+                                mUploadDataStream.attachNativeAdapterToRequest(mUrlRequestAdapter);
                                 startInternalLocked();
                             }
                         }
@@ -232,6 +237,10 @@
         }
     }
 
+    /*
+     * Starts fully configured request. Could execute on UploadDataProvider executor.
+     * Caller is expected to ensure that request isn't canceled and mUrlRequestAdapter is valid.
+     */
     @GuardedBy("mUrlRequestAdapterLock")
     private void startInternalLocked() {
         if (mDisableCache) {
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/UploadDataProvidersTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/UploadDataProvidersTest.java
index c03ba844..7a9eb69 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/UploadDataProvidersTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/UploadDataProvidersTest.java
@@ -4,6 +4,7 @@
 
 package org.chromium.net;
 
+import android.os.ConditionVariable;
 import android.os.ParcelFileDescriptor;
 import android.os.StrictMode;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -13,6 +14,8 @@
 
 import java.io.File;
 import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
 
 /** Test the default provided implementations of {@link UploadDataProvider} */
 public class UploadDataProvidersTest extends CronetTestBase {
@@ -137,4 +140,70 @@
         assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
         assertEquals(LOREM, callback.mResponseAsString);
     }
+
+    @SmallTest
+    @Feature({"Cronet"})
+    public void testNoErrorWhenCanceledDuringStart() throws Exception {
+        TestUrlRequestCallback callback = new TestUrlRequestCallback();
+        UrlRequest.Builder builder = new UrlRequest.Builder(NativeTestServer.getEchoBodyURL(),
+                callback, callback.getExecutor(), mTestFramework.mCronetEngine);
+        final ConditionVariable first = new ConditionVariable();
+        final ConditionVariable second = new ConditionVariable();
+        builder.addHeader("Content-Type", "useless/string");
+        builder.setUploadDataProvider(new UploadDataProvider() {
+            @Override
+            public long getLength() throws IOException {
+                first.open();
+                second.block();
+                return 0;
+            }
+
+            @Override
+            public void read(UploadDataSink uploadDataSink, ByteBuffer byteBuffer)
+                    throws IOException {}
+
+            @Override
+            public void rewind(UploadDataSink uploadDataSink) throws IOException {}
+        }, callback.getExecutor());
+        UrlRequest urlRequest = builder.build();
+        urlRequest.start();
+        first.block();
+        urlRequest.cancel();
+        second.open();
+        callback.blockForDone();
+        assertTrue(callback.mOnCanceledCalled);
+    }
+
+    @SmallTest
+    @Feature({"Cronet"})
+    public void testNoErrorWhenExceptionDuringStart() throws Exception {
+        TestUrlRequestCallback callback = new TestUrlRequestCallback();
+        UrlRequest.Builder builder = new UrlRequest.Builder(NativeTestServer.getEchoBodyURL(),
+                callback, callback.getExecutor(), mTestFramework.mCronetEngine);
+        final ConditionVariable first = new ConditionVariable();
+        final String exceptionMessage = "Bad Length";
+        builder.addHeader("Content-Type", "useless/string");
+        builder.setUploadDataProvider(new UploadDataProvider() {
+            @Override
+            public long getLength() throws IOException {
+                first.open();
+                throw new IOException(exceptionMessage);
+            }
+
+            @Override
+            public void read(UploadDataSink uploadDataSink, ByteBuffer byteBuffer)
+                    throws IOException {}
+
+            @Override
+            public void rewind(UploadDataSink uploadDataSink) throws IOException {}
+        }, callback.getExecutor());
+        UrlRequest urlRequest = builder.build();
+        urlRequest.start();
+        first.block();
+        callback.blockForDone();
+        assertFalse(callback.mOnCanceledCalled);
+        assertEquals(UrlRequestError.LISTENER_EXCEPTION_THROWN, callback.mError.getErrorCode());
+        assertEquals("Exception received from UploadDataProvider", callback.mError.getMessage());
+        assertEquals(exceptionMessage, callback.mError.getCause().getMessage());
+    }
 }
diff --git a/components/cronet/tools/cr_cronet.py b/components/cronet/tools/cr_cronet.py
index f6d3490..35633d705 100755
--- a/components/cronet/tools/cr_cronet.py
+++ b/components/cronet/tools/cr_cronet.py
@@ -70,10 +70,10 @@
   print extra_options_list
   gyp_defines = 'GYP_DEFINES="OS=android enable_websockets=0 '+ \
       'disable_file_support=1 disable_ftp_support=1 '+ \
-      'enable_bidirectional_stream=1"'
+      'enable_bidirectional_stream=1 enable_errorprone=1"'
   gn_args = 'target_os="android" enable_websockets=false '+ \
       'disable_file_support=true disable_ftp_support=true '+ \
-      'enable_bidirectional_stream=false'
+      'enable_bidirectional_stream=false use_errorprone_java_compiler=true'
   out_dir = 'out/Debug'
   release_arg = ''
   extra_options = ' '.join(extra_options_list)
diff --git a/components/dom_distiller/content/browser/distiller_page_web_contents_browsertest.cc b/components/dom_distiller/content/browser/distiller_page_web_contents_browsertest.cc
index 78ba075a9..bc52b01 100644
--- a/components/dom_distiller/content/browser/distiller_page_web_contents_browsertest.cc
+++ b/components/dom_distiller/content/browser/distiller_page_web_contents_browsertest.cc
@@ -250,7 +250,7 @@
 
   // A relative source/track should've been updated.
   EXPECT_THAT(distiller_result_->distilled_content().html(),
-              ContainsRegex("src=\"http://127.0.0.1:.*/relative_video.mp4\""));
+              ContainsRegex("src=\"http://127.0.0.1:.*/relative_video.webm\""));
   EXPECT_THAT(
       distiller_result_->distilled_content().html(),
       ContainsRegex("src=\"http://127.0.0.1:.*/relative_track_en.vtt\""));
diff --git a/components/mus/ws/window_manager_state.cc b/components/mus/ws/window_manager_state.cc
index 081ca5e0..a06e900d4 100644
--- a/components/mus/ws/window_manager_state.cc
+++ b/components/mus/ws/window_manager_state.cc
@@ -11,7 +11,6 @@
 #include "components/mus/ws/user_display_manager.h"
 #include "components/mus/ws/user_id_tracker.h"
 #include "components/mus/ws/window_tree.h"
-#include "mojo/converters/input_events/input_events_type_converters.h"
 #include "mojo/shell/public/interfaces/connector.mojom.h"
 #include "ui/events/event.h"
 
@@ -188,7 +187,6 @@
 }
 
 void WindowManagerState::ProcessEvent(const ui::Event& event) {
-  mojom::EventPtr mojo_event(mojom::Event::From(event));
   // If this is still waiting for an ack from a previously sent event, then
   // queue up the event to be dispatched once the ack is received.
   if (event_ack_timer_.IsRunning()) {
@@ -294,13 +292,13 @@
                          &WindowManagerState::OnEventAckTimeout);
 
   tree_awaiting_input_ack_ = tree;
-  tree->DispatchInputEvent(target, mojom::Event::From(event));
+  tree->DispatchInputEvent(target, event);
 }
 
 void WindowManagerState::OnAccelerator(uint32_t accelerator_id,
                                        const ui::Event& event) {
   DCHECK(IsActive());
-  tree_->OnAccelerator(accelerator_id, mojom::Event::From(event));
+  tree_->OnAccelerator(accelerator_id, event);
 }
 
 void WindowManagerState::SetFocusedWindowFromEventDispatcher(
diff --git a/components/mus/ws/window_tree.cc b/components/mus/ws/window_tree.cc
index 58c0f282..8016ad8 100644
--- a/components/mus/ws/window_tree.cc
+++ b/components/mus/ws/window_tree.cc
@@ -39,8 +39,8 @@
 
 class TargetedEvent : public ServerWindowObserver {
  public:
-  TargetedEvent(ServerWindow* target, mojom::EventPtr event)
-      : target_(target), event_(std::move(event)) {
+  TargetedEvent(ServerWindow* target, const ui::Event& event)
+      : target_(target), event_(ui::Event::Clone(event)) {
     target_->AddObserver(this);
   }
   ~TargetedEvent() override {
@@ -49,7 +49,7 @@
   }
 
   ServerWindow* target() { return target_; }
-  mojom::EventPtr event() { return std::move(event_); }
+  ui::Event* event() { return event_.get(); }
 
  private:
   // ServerWindowObserver:
@@ -60,7 +60,7 @@
   }
 
   ServerWindow* target_;
-  mojom::EventPtr event_;
+  scoped_ptr<ui::Event> event_;
 
   DISALLOW_COPY_AND_ASSIGN(TargetedEvent);
 };
@@ -285,11 +285,10 @@
 }
 
 void WindowTree::DispatchInputEvent(ServerWindow* target,
-                                    mojom::EventPtr event) {
+                                    const ui::Event& event) {
   if (event_ack_id_) {
     // This is currently waiting for an event ack. Add it to the queue.
-    event_queue_.push(
-        make_scoped_ptr(new TargetedEvent(target, std::move(event))));
+    event_queue_.push(make_scoped_ptr(new TargetedEvent(target, event)));
     // TODO(sad): If the |event_queue_| grows too large, then this should notify
     // Display, so that it can stop sending events.
     return;
@@ -299,12 +298,11 @@
   // and dispatch the latest event from the queue instead that still has a live
   // target.
   if (!event_queue_.empty()) {
-    event_queue_.push(
-        make_scoped_ptr(new TargetedEvent(target, std::move(event))));
+    event_queue_.push(make_scoped_ptr(new TargetedEvent(target, event)));
     return;
   }
 
-  DispatchInputEventImpl(target, std::move(event));
+  DispatchInputEventImpl(target, event);
 }
 
 bool WindowTree::IsWaitingForNewTopLevelWindow(uint32_t wm_change_id) {
@@ -335,9 +333,11 @@
   client()->OnChangeCompleted(change_id, success);
 }
 
-void WindowTree::OnAccelerator(uint32_t accelerator_id, mojom::EventPtr event) {
+void WindowTree::OnAccelerator(uint32_t accelerator_id,
+                               const ui::Event& event) {
   DCHECK(window_manager_internal_);
-  window_manager_internal_->OnAccelerator(accelerator_id, std::move(event));
+  window_manager_internal_->OnAccelerator(accelerator_id,
+                                          mojom::Event::From(event));
 }
 
 void WindowTree::ProcessWindowBoundsChanged(const ServerWindow* window,
@@ -887,18 +887,19 @@
 }
 
 void WindowTree::DispatchInputEventImpl(ServerWindow* target,
-                                        mojom::EventPtr event) {
+                                        const ui::Event& event) {
   DCHECK(!event_ack_id_);
   // We do not want to create a sequential id for each event, because that can
-  // leak some information to the client. So instead, manufacture the id from
-  // the event pointer.
-  event_ack_id_ =
-      0x1000000 | (reinterpret_cast<uintptr_t>(event.get()) & 0xffffff);
+  // leak some information to the client. So instead, manufacture the id
+  // randomly.
+  // TODO(moshayedi): Find a faster way to generate ids.
+  event_ack_id_ = 0x1000000 | (rand() & 0xffffff);
   event_source_wms_ = GetWindowManagerState(target);
   // Should only get events from windows attached to a host.
   DCHECK(event_source_wms_);
-  client()->OnWindowInputEvent(
-      event_ack_id_, ClientWindowIdForWindow(target).id, std::move(event));
+  client()->OnWindowInputEvent(event_ack_id_,
+                               ClientWindowIdForWindow(target).id,
+                               mojom::Event::From(event));
 }
 
 void WindowTree::NewWindow(
@@ -1173,7 +1174,7 @@
   if (!event_queue_.empty()) {
     DCHECK(!event_ack_id_);
     ServerWindow* target = nullptr;
-    mojom::EventPtr event;
+    ui::Event* event = nullptr;
     do {
       scoped_ptr<TargetedEvent> targeted_event =
           std::move(event_queue_.front());
@@ -1182,7 +1183,7 @@
       event = targeted_event->event();
     } while (!event_queue_.empty() && !GetDisplay(target));
     if (target)
-      DispatchInputEventImpl(target, std::move(event));
+      DispatchInputEventImpl(target, *event);
   }
 }
 
diff --git a/components/mus/ws/window_tree.h b/components/mus/ws/window_tree.h
index c4c5055..f84a38db 100644
--- a/components/mus/ws/window_tree.h
+++ b/components/mus/ws/window_tree.h
@@ -29,6 +29,10 @@
 class Rect;
 }
 
+namespace ui {
+class Event;
+}
+
 namespace mus {
 namespace ws {
 
@@ -135,7 +139,7 @@
   bool SetWindowVisibility(const ClientWindowId& window_id, bool visible);
   bool Embed(const ClientWindowId& window_id,
              mojom::WindowTreeClientPtr client);
-  void DispatchInputEvent(ServerWindow* target, mojom::EventPtr event);
+  void DispatchInputEvent(ServerWindow* target, const ui::Event& event);
 
   bool IsWaitingForNewTopLevelWindow(uint32_t wm_change_id);
   void OnWindowManagerCreatedTopLevelWindow(uint32_t wm_change_id,
@@ -144,7 +148,7 @@
 
   // Calls through to the client.
   void OnChangeCompleted(uint32_t change_id, bool success);
-  void OnAccelerator(uint32_t accelerator_id, mojom::EventPtr event);
+  void OnAccelerator(uint32_t accelerator_id, const ui::Event& event);
 
   // The following methods are invoked after the corresponding change has been
   // processed. They do the appropriate bookkeeping and update the client as
@@ -289,7 +293,7 @@
   void PrepareForEmbed(ServerWindow* window);
   void RemoveChildrenAsPartOfEmbed(ServerWindow* window);
 
-  void DispatchInputEventImpl(ServerWindow* target, mojom::EventPtr event);
+  void DispatchInputEventImpl(ServerWindow* target, const ui::Event& event);
 
   // Calls OnChangeCompleted() on the client.
   void NotifyChangeCompleted(uint32_t change_id,
diff --git a/components/offline_pages/offline_page_model.cc b/components/offline_pages/offline_page_model.cc
index 50698ff5..2ab8537 100644
--- a/components/offline_pages/offline_page_model.cc
+++ b/components/offline_pages/offline_page_model.cc
@@ -393,6 +393,38 @@
                  base::Owned(ids_of_pages_missing_archive_file)));
 }
 
+void OfflinePageModel::RecordStorageHistograms(int64_t total_space_bytes,
+                                               int64_t free_space_bytes,
+                                               bool reporting_after_delete) {
+  // Total space taken by offline pages.
+  int64_t total_page_size = 0;
+  for (const auto& id_page_pair : offline_pages_) {
+    if (!id_page_pair.second.IsMarkedForDeletion())
+      continue;
+    total_page_size += id_page_pair.second.file_size;
+  }
+
+  int total_page_size_mb = static_cast<int>(total_page_size / (1024 * 1024));
+  UMA_HISTOGRAM_COUNTS_10000("OfflinePages.TotalPageSize", total_page_size_mb);
+
+  // How much of the total space the offline pages take.
+  int total_page_size_percentage =
+      static_cast<int>(1.0 * total_page_size / total_space_bytes * 100);
+  UMA_HISTOGRAM_PERCENTAGE("OfflinePages.TotalPageSizePercentage",
+                           total_page_size_percentage);
+
+  // If the user is deleting the pages, perhaps they are running out of free
+  // space. Report the size before the operation, where a base for calculation
+  // of total free space includes space taken by offline pages.
+  if (reporting_after_delete && free_space_bytes > 0) {
+    int percentage_of_free = static_cast<int>(
+        1.0 * total_page_size / (total_page_size + free_space_bytes) * 100);
+    UMA_HISTOGRAM_PERCENTAGE(
+        "OfflinePages.DeletePage.TotalPageSizeAsPercentageOfFreeSpace",
+        percentage_of_free);
+  }
+}
+
 OfflinePageMetadataStore* OfflinePageModel::GetStoreForTesting() {
   return store_.get();
 }
diff --git a/components/offline_pages/offline_page_model.h b/components/offline_pages/offline_page_model.h
index 571f12bc..bae72ab5 100644
--- a/components/offline_pages/offline_page_model.h
+++ b/components/offline_pages/offline_page_model.h
@@ -220,6 +220,17 @@
   // observers.
   void CheckForExternalFileDeletion();
 
+  // Reports the storage histograms related to total size of all stored offline
+  // pages. Method is to be called after a page was saved or some pages are
+  // deleted. In the latter case |reporting_after_delete| is set to true.
+  // Caller is supposed to provide the current |total_space_bytes| on drive
+  // where the pages are stored, as well as |free_space_bytes| after the
+  // operation was taken. The method will report total size of all pages, and
+  // percentage of size of pages as compared to total space and free space.
+  void RecordStorageHistograms(int64_t total_space_bytes,
+                               int64_t free_space_bytes,
+                               bool reporting_after_delete);
+
   // Methods for testing only:
   OfflinePageMetadataStore* GetStoreForTesting();
 
diff --git a/components/password_manager.gypi b/components/password_manager.gypi
index 17ab476..d3b0631 100644
--- a/components/password_manager.gypi
+++ b/components/password_manager.gypi
@@ -212,8 +212,6 @@
         'password_manager/core/common/password_manager_features.h',
         'password_manager/core/common/password_manager_pref_names.cc',
         'password_manager/core/common/password_manager_pref_names.h',
-        'password_manager/core/common/password_manager_switches.cc',
-        'password_manager/core/common/password_manager_switches.h',
         'password_manager/core/common/password_manager_ui.h',
       ],
     },
diff --git a/components/password_manager/core/browser/affiliation_utils.cc b/components/password_manager/core/browser/affiliation_utils.cc
index 853edc5..b76d782 100644
--- a/components/password_manager/core/browser/affiliation_utils.cc
+++ b/components/password_manager/core/browser/affiliation_utils.cc
@@ -8,12 +8,9 @@
 #include <ostream>
 
 #include "base/base64.h"
-#include "base/command_line.h"
-#include "base/metrics/field_trial.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "components/autofill/core/common/password_form.h"
-#include "components/password_manager/core/common/password_manager_switches.h"
 #include "components/url_formatter/elide_url.h"
 #include "components/variations/variations_associated_data.h"
 #include "net/base/escape.h"
@@ -27,9 +24,6 @@
 // The scheme used for identifying Android applications.
 const char kAndroidAppScheme[] = "android";
 
-// The name of the field trial controlling affiliation-based matching.
-const char kFieldTrialName[] = "AffiliationBasedMatching";
-
 // Returns a StringPiece corresponding to |component| in |uri|, or the empty
 // string in case there is no such component.
 base::StringPiece ComponentString(const std::string& uri,
@@ -294,35 +288,6 @@
   return std::equal(a_sorted.begin(), a_sorted.end(), b_sorted.begin());
 }
 
-bool IsAffiliationBasedMatchingEnabled(const base::CommandLine& command_line) {
-  // Note: It is important to always query the field trial state, to ensure that
-  // UMA reports the correct group.
-  const std::string group_name =
-      base::FieldTrialList::FindFullName(kFieldTrialName);
-
-  if (command_line.HasSwitch(switches::kDisableAffiliationBasedMatching))
-    return false;
-  if (command_line.HasSwitch(switches::kEnableAffiliationBasedMatching))
-    return true;
-  return !base::StartsWith(group_name, "Disabled",
-                           base::CompareCase::INSENSITIVE_ASCII);
-}
-
-bool IsPropagatingPasswordChangesToWebCredentialsEnabled(
-    const base::CommandLine& command_line) {
-  // Note: It is important to always query the variation param first, which, in
-  // turn, queries the field trial state, which ensures that UMA reports the
-  // correct group if it is forced by a command line flag.
-  const std::string update_enabled = variations::GetVariationParamValue(
-      kFieldTrialName, "propagate_password_changes_to_web");
-
-  if (command_line.HasSwitch(switches::kDisableAffiliationBasedMatching))
-    return false;
-  if (command_line.HasSwitch(switches::kEnableAffiliationBasedMatching))
-    return true;
-  return !base::LowerCaseEqualsASCII(update_enabled, "disabled");
-}
-
 bool IsValidAndroidFacetURI(const std::string& url) {
   FacetURI facet = FacetURI::FromPotentiallyInvalidSpec(url);
   return facet.IsValidAndroidFacetURI();
diff --git a/components/password_manager/core/browser/affiliation_utils.h b/components/password_manager/core/browser/affiliation_utils.h
index ae2d986..1bc5767b 100644
--- a/components/password_manager/core/browser/affiliation_utils.h
+++ b/components/password_manager/core/browser/affiliation_utils.h
@@ -180,20 +180,6 @@
 // A shorter way to spell FacetURI::IsValidAndroidFacetURI().
 bool IsValidAndroidFacetURI(const std::string& uri);
 
-// Returns whether or not affiliation based matching is enabled. The feature is
-// enabled by default, but can be disabled either via command line flags or
-// field trials. The command line flag, if present, always takes precedence.
-bool IsAffiliationBasedMatchingEnabled(const base::CommandLine& command_line);
-
-// Returns whether or not propagating password changes to affiliated saved web
-// credentials is enabled. It is enabled by default, but can be disabled
-// separately via variation parameters while leaving the rest of the
-// affiliation-based matching enabled. If the main feature is forced
-// enabled/disabled via the command line, this sub-feature will be force
-// enabled/disabled correspondingly.
-bool IsPropagatingPasswordChangesToWebCredentialsEnabled(
-    const base::CommandLine& command_line);
-
 // Returns the origin URI in a format which can be presented to a user based of
 // |password_from| field values. For web URIs |languages| is using in order to
 // determine whether a URI is 'comprehensible' to a user who understands
diff --git a/components/password_manager/core/browser/affiliation_utils_unittest.cc b/components/password_manager/core/browser/affiliation_utils_unittest.cc
index f8f32ec4..332271e 100644
--- a/components/password_manager/core/browser/affiliation_utils_unittest.cc
+++ b/components/password_manager/core/browser/affiliation_utils_unittest.cc
@@ -8,7 +8,6 @@
 #include "base/metrics/field_trial.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/autofill/core/common/password_form.h"
-#include "components/password_manager/core/common/password_manager_switches.h"
 #include "components/variations/variations_associated_data.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/url_constants.h"
@@ -16,7 +15,6 @@
 namespace password_manager {
 
 namespace {
-const char kFieldTrialName[] = "AffiliationBasedMatching";
 const std::string kSchemeHostExample = "http://example.com";
 const char kTestFacetURI1[] = "https://alpha.example.com/";
 const char kTestFacetURI2[] = "https://beta.example.com/";
@@ -200,89 +198,6 @@
   EXPECT_FALSE(AreEquivalenceClassesEqual(c, b));
 }
 
-TEST(AffiliationUtilsTest, IsAffiliationBasedMatchingEnabled) {
-  struct {
-    const char* field_trial_group;
-    const char* command_line_switch;
-    bool expected_enabled;
-  } kTestCases[] = {
-      {"", "", true},
-      {"", switches::kEnableAffiliationBasedMatching, true},
-      {"", switches::kDisableAffiliationBasedMatching, false},
-      {"garbage value", "", true},
-      {"disabled", "", false},
-      {"disabled2", "", false},
-      {"Disabled", "", false},
-      {"Disabled", switches::kDisableAffiliationBasedMatching, false},
-      {"Disabled", switches::kEnableAffiliationBasedMatching, true},
-      {"enabled", "", true},
-      {"enabled2", "", true},
-      {"Enabled", "", true},
-      {"Enabled", switches::kDisableAffiliationBasedMatching, false},
-      {"Enabled", switches::kEnableAffiliationBasedMatching, true}};
-
-  for (const auto& test_case : kTestCases) {
-    SCOPED_TRACE(testing::Message("Command line = ")
-                 << test_case.command_line_switch);
-    SCOPED_TRACE(testing::Message("Group name = ")
-                 << test_case.field_trial_group);
-
-    base::FieldTrialList field_trials(nullptr);
-    base::FieldTrialList::CreateFieldTrial(kFieldTrialName,
-                                           test_case.field_trial_group);
-
-    base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
-    command_line.AppendSwitch(test_case.command_line_switch);
-    EXPECT_EQ(test_case.expected_enabled,
-              IsAffiliationBasedMatchingEnabled(command_line));
-  }
-}
-
-TEST(AffiliationUtilsTest,
-     IsPropagatingPasswordChangesToWebCredentialsEnabled) {
-  const char kExperimentName[] = "DoesNotMatter";
-
-  struct {
-    const char* variation_param;
-    const char* command_line_switch;
-    bool expected_enabled;
-  } kTestCases[] = {
-      {"", "", true},
-      {"", switches::kEnableAffiliationBasedMatching, true},
-      {"", switches::kDisableAffiliationBasedMatching, false},
-      {"garbage value", "", true},
-      {"disabled", "", false},
-      {"Disabled", "", false},
-      {"Disabled", switches::kDisableAffiliationBasedMatching, false},
-      {"Disabled", switches::kEnableAffiliationBasedMatching, true},
-      {"enabled", "", true},
-      {"Enabled", "", true},
-      {"Enabled", switches::kDisableAffiliationBasedMatching, false},
-      {"Enabled", switches::kEnableAffiliationBasedMatching, true}};
-
-  for (const auto& test_case : kTestCases) {
-    SCOPED_TRACE(testing::Message("Command line = ")
-                 << test_case.command_line_switch);
-    SCOPED_TRACE(testing::Message("Variation param = ")
-                 << test_case.variation_param);
-
-    variations::testing::ClearAllVariationParams();
-    base::FieldTrialList field_trials(nullptr);
-    base::FieldTrialList::CreateFieldTrial(kFieldTrialName, kExperimentName);
-    std::map<std::string, std::string> variation_params;
-    variation_params["propagate_password_changes_to_web"] =
-        test_case.variation_param;
-    ASSERT_TRUE(variations::AssociateVariationParams(
-        kFieldTrialName, kExperimentName, variation_params));
-
-    base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
-    command_line.AppendSwitch(test_case.command_line_switch);
-    EXPECT_EQ(
-        test_case.expected_enabled,
-        IsPropagatingPasswordChangesToWebCredentialsEnabled(command_line));
-  }
-}
-
 class GetHumanReadableOriginTest : public testing::Test {
  public:
   GetHumanReadableOriginTest() {
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc
index 65d8f00..6ed264a7 100644
--- a/components/password_manager/core/browser/password_manager.cc
+++ b/components/password_manager/core/browser/password_manager.cc
@@ -8,7 +8,6 @@
 #include <map>
 #include <utility>
 
-#include "base/command_line.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_util.h"
@@ -29,8 +28,8 @@
 #include "components/password_manager/core/browser/password_manager_driver.h"
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/password_manager/core/browser/password_manager_util.h"
+#include "components/password_manager/core/common/password_manager_features.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
-#include "components/password_manager/core/common/password_manager_switches.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
@@ -52,21 +51,6 @@
 // already.
 typedef autofill::SavePasswordProgressLogger Logger;
 
-bool ShouldDropSyncCredential() {
-  std::string group_name =
-      base::FieldTrialList::FindFullName("PasswordManagerDropSyncCredential");
-
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(switches::kEnableDropSyncCredential))
-    return true;
-
-  if (command_line->HasSwitch(switches::kDisableDropSyncCredential))
-    return false;
-
-  // Default to not saving.
-  return group_name != "Disabled";
-}
-
 bool URLsEqualUpToScheme(const GURL& a, const GURL& b) {
   return (a.GetContent() == b.GetContent());
 }
@@ -674,7 +658,7 @@
     logger->LogMessage(Logger::STRING_ON_ASK_USER_OR_SAVE_PASSWORD);
   }
 
-  if (ShouldDropSyncCredential() &&
+  if (base::FeatureList::IsEnabled(features::kDropSyncCredential) &&
       !client_->GetStoreResultFilter()->ShouldSave(
           provisional_save_manager_->pending_credentials())) {
     provisional_save_manager_->WipeStoreCopyIfOutdated();
diff --git a/components/password_manager/core/browser/password_manager_test_utils.cc b/components/password_manager/core/browser/password_manager_test_utils.cc
index edfe390..ccf2829 100644
--- a/components/password_manager/core/browser/password_manager_test_utils.cc
+++ b/components/password_manager/core/browser/password_manager_test_utils.cc
@@ -8,6 +8,7 @@
 #include <ostream>
 #include <string>
 
+#include "base/feature_list.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 
@@ -15,6 +16,18 @@
 
 namespace password_manager {
 
+namespace {
+
+void GetFeatureOverridesAsCSV(const std::vector<const base::Feature*>& features,
+                              std::string* overrides) {
+  for (const base::Feature* feature : features) {
+    overrides->append(feature->name);
+    overrides->push_back(',');
+  }
+}
+
+}  // namespace
+
 const char kTestingIconUrlSpec[] = "https://accounts.google.com/Icon";
 const char kTestingFederationUrlSpec[] = "https://accounts.google.com/login";
 const int kTestingDaysAfterPasswordsAreSynced = 1;
@@ -95,6 +108,20 @@
   return !had_mismatched_actual_form && remaining_expectations.empty();
 }
 
+void SetFeatures(const std::vector<const base::Feature*>& enable_features,
+                 const std::vector<const base::Feature*>& disable_features,
+                 scoped_ptr<base::FeatureList> feature_list) {
+  std::string enable_overrides;
+  std::string disable_overrides;
+
+  GetFeatureOverridesAsCSV(enable_features, &enable_overrides);
+  GetFeatureOverridesAsCSV(disable_features, &disable_overrides);
+
+  base::FeatureList::ClearInstanceForTesting();
+  feature_list->InitializeFromCommandLine(enable_overrides, disable_overrides);
+  base::FeatureList::SetInstance(std::move(feature_list));
+}
+
 MockPasswordStoreObserver::MockPasswordStoreObserver() {}
 
 MockPasswordStoreObserver::~MockPasswordStoreObserver() {}
diff --git a/components/password_manager/core/browser/password_manager_test_utils.h b/components/password_manager/core/browser/password_manager_test_utils.h
index 93f004f..fe16f8c 100644
--- a/components/password_manager/core/browser/password_manager_test_utils.h
+++ b/components/password_manager/core/browser/password_manager_test_utils.h
@@ -8,6 +8,7 @@
 #include <iosfwd>
 #include <vector>
 
+#include "base/feature_list.h"
 #include "base/memory/ref_counted.h"
 #include "components/autofill/core/common/password_form.h"
 #include "components/password_manager/core/browser/password_store.h"
@@ -73,6 +74,13 @@
                                              result_listener->stream());
 }
 
+// Helper function to initialize feature overrides via command-line flags
+// supplied as |enable_features| and |disable_features| using the
+// |feature_list|.
+void SetFeatures(const std::vector<const base::Feature*>& enable_features,
+                 const std::vector<const base::Feature*>& disable_features,
+                 scoped_ptr<base::FeatureList> feature_list);
+
 class MockPasswordStoreObserver : public PasswordStore::Observer {
  public:
   MockPasswordStoreObserver();
diff --git a/components/password_manager/core/browser/password_manager_unittest.cc b/components/password_manager/core/browser/password_manager_unittest.cc
index a0a6f7b..052a6eb 100644
--- a/components/password_manager/core/browser/password_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_manager_unittest.cc
@@ -8,7 +8,6 @@
 #include <utility>
 #include <vector>
 
-#include "base/command_line.h"
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
 #include "base/strings/string_util.h"
@@ -22,7 +21,6 @@
 #include "components/password_manager/core/browser/stub_password_manager_driver.h"
 #include "components/password_manager/core/common/password_manager_features.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
-#include "components/password_manager/core/common/password_manager_switches.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/components/password_manager/core/browser/password_store_factory_util.cc b/components/password_manager/core/browser/password_store_factory_util.cc
index 5f6eb80..d141fa9 100644
--- a/components/password_manager/core/browser/password_store_factory_util.cc
+++ b/components/password_manager/core/browser/password_store_factory_util.cc
@@ -6,11 +6,11 @@
 
 #include <utility>
 
-#include "base/command_line.h"
 #include "components/password_manager/core/browser/affiliated_match_helper.h"
 #include "components/password_manager/core/browser/affiliation_service.h"
 #include "components/password_manager/core/browser/affiliation_utils.h"
 #include "components/password_manager/core/browser/password_manager_constants.h"
+#include "components/password_manager/core/common/password_manager_features.h"
 
 namespace password_manager {
 
@@ -18,11 +18,8 @@
 
 bool ShouldAffiliationBasedMatchingBeActive(
     sync_driver::SyncService* sync_service) {
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  if (!IsAffiliationBasedMatchingEnabled(*command_line))
-    return false;
-
-  return sync_service && sync_service->CanSyncStart() &&
+  return base::FeatureList::IsEnabled(features::kAffiliationBasedMatching) &&
+         sync_service && sync_service->CanSyncStart() &&
          sync_service->IsSyncActive() &&
          sync_service->GetPreferredDataTypes().Has(syncer::PASSWORDS) &&
          !sync_service->IsUsingSecondaryPassphrase();
@@ -46,8 +43,7 @@
   password_store->SetAffiliatedMatchHelper(std::move(affiliated_match_helper));
 
   password_store->enable_propagating_password_changes_to_web_credentials(
-      IsPropagatingPasswordChangesToWebCredentialsEnabled(
-          *base::CommandLine::ForCurrentProcess()));
+      base::FeatureList::IsEnabled(features::kAffiliationBasedMatching));
 }
 
 base::FilePath GetAffiliationDatabasePath(const base::FilePath& profile_path) {
diff --git a/components/password_manager/core/browser/psl_matching_helper.cc b/components/password_manager/core/browser/psl_matching_helper.cc
index 5482feb..9167817f 100644
--- a/components/password_manager/core/browser/psl_matching_helper.cc
+++ b/components/password_manager/core/browser/psl_matching_helper.cc
@@ -4,12 +4,10 @@
 
 #include "components/password_manager/core/browser/psl_matching_helper.h"
 
-#include "base/command_line.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string_util.h"
 #include "components/autofill/core/common/password_form.h"
-#include "components/password_manager/core/common/password_manager_switches.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "url/gurl.h"
 
diff --git a/components/password_manager/core/common/BUILD.gn b/components/password_manager/core/common/BUILD.gn
index ad04554..80229d9 100644
--- a/components/password_manager/core/common/BUILD.gn
+++ b/components/password_manager/core/common/BUILD.gn
@@ -12,8 +12,6 @@
     "password_manager_features.h",
     "password_manager_pref_names.cc",
     "password_manager_pref_names.h",
-    "password_manager_switches.cc",
-    "password_manager_switches.h",
     "password_manager_ui.h",
   ]
 
diff --git a/components/password_manager/core/common/password_manager_features.cc b/components/password_manager/core/common/password_manager_features.cc
index c1f9f4d9..ca9f658 100644
--- a/components/password_manager/core/common/password_manager_features.cc
+++ b/components/password_manager/core/common/password_manager_features.cc
@@ -8,6 +8,16 @@
 
 namespace features {
 
+// Enable affiliation based matching, so that credentials stored for an Android
+// application will also be considered matches for, and be filled into
+// corresponding Web applications.
+const base::Feature kAffiliationBasedMatching = {
+    "affiliation-based-matching", base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Drop the sync credential if captured for saving, do not offer it for saving.
+const base::Feature kDropSyncCredential = {"drop-sync-credential",
+                                           base::FEATURE_ENABLED_BY_DEFAULT};
+
 // Disables the save-password prompt. Passwords are then saved automatically,
 // without asking the user.
 const base::Feature kEnableAutomaticPasswordSaving = {
@@ -27,6 +37,15 @@
 extern const base::Feature kEnableManualPasswordGeneration = {
     "enable-manual-password-generation", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Disallow autofilling of the sync credential.
+const base::Feature kProtectSyncCredential = {
+    "protect-sync-credential", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Disallow autofilling of the sync credential only for transactional reauth
+// pages.
+const base::Feature kProtectSyncCredentialOnReauth = {
+    "protect-sync-credential-on-reauth", base::FEATURE_DISABLED_BY_DEFAULT};
+
 }  // namespace features
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/common/password_manager_features.h b/components/password_manager/core/common/password_manager_features.h
index 32cfcb8..2e42281 100644
--- a/components/password_manager/core/common/password_manager_features.h
+++ b/components/password_manager/core/common/password_manager_features.h
@@ -17,10 +17,14 @@
 // All features in alphabetical order. The features should be documented
 // alongside the definition of their values in the .cc file.
 
+extern const base::Feature kAffiliationBasedMatching;
+extern const base::Feature kDropSyncCredential;
 extern const base::Feature kEnableAutomaticPasswordSaving;
 extern const base::Feature kEnableManualPasswordGeneration;
 extern const base::Feature kEnablePasswordChangeSupport;
 extern const base::Feature kEnablePasswordForceSaving;
+extern const base::Feature kProtectSyncCredential;
+extern const base::Feature kProtectSyncCredentialOnReauth;
 
 }  // namespace features
 
diff --git a/components/password_manager/core/common/password_manager_switches.cc b/components/password_manager/core/common/password_manager_switches.cc
deleted file mode 100644
index abae7eb..0000000
--- a/components/password_manager/core/common/password_manager_switches.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/password_manager/core/common/password_manager_switches.h"
-
-namespace password_manager {
-
-namespace switches {
-
-// Force the password manager to allow sync credentials to be autofilled.
-const char kAllowAutofillSyncCredential[] = "allow-autofill-sync-credential";
-
-// Disable affiliation based matching, so that credentials stored for an Android
-// application will not be considered matches for, and will not be filled into
-// corresponding Web applications.
-const char kDisableAffiliationBasedMatching[] =
-    "disable-affiliation-based-matching";
-
-// Disable dropping the credential used to sync passwords.
-const char kDisableDropSyncCredential[] = "disable-drop-sync-credential";
-
-// Disallow autofilling of the sync credential.
-const char kDisallowAutofillSyncCredential[] =
-    "disallow-autofill-sync-credential";
-
-// Disallow autofilling of the sync credential only for transactional reauth
-// pages.
-const char kDisallowAutofillSyncCredentialForReauth[] =
-    "disallow-autofill-sync-credential-for-reauth";
-
-// Enable affiliation based matching, so that credentials stored for an Android
-// application will also be considered matches for, and be filled into
-// corresponding Web applications.
-const char kEnableAffiliationBasedMatching[] =
-    "enable-affiliation-based-matching";
-
-// Enable dropping the credential used to sync passwords.
-const char kEnableDropSyncCredential[] = "enable-drop-sync-credential";
-
-}  // namespace switches
-
-}  // namespace password_manager
diff --git a/components/password_manager/core/common/password_manager_switches.h b/components/password_manager/core/common/password_manager_switches.h
deleted file mode 100644
index 67e0843..0000000
--- a/components/password_manager/core/common/password_manager_switches.h
+++ /dev/null
@@ -1,27 +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 COMPONENTS_PASSWORD_MANAGER_CORE_COMMON_PASSWORD_MANAGER_SWITCHES_H_
-#define COMPONENTS_PASSWORD_MANAGER_CORE_COMMON_PASSWORD_MANAGER_SWITCHES_H_
-
-namespace password_manager {
-
-namespace switches {
-
-// All switches in alphabetical order. The switches should be documented
-// alongside the definition of their values in the .cc file.
-
-extern const char kAllowAutofillSyncCredential[];
-extern const char kDisableAffiliationBasedMatching[];
-extern const char kDisableDropSyncCredential[];
-extern const char kDisallowAutofillSyncCredential[];
-extern const char kDisallowAutofillSyncCredentialForReauth[];
-extern const char kEnableAffiliationBasedMatching[];
-extern const char kEnableDropSyncCredential[];
-
-}  // namespace switches
-
-}  // namespace password_manager
-
-#endif  // COMPONENTS_PASSWORD_MANAGER_CORE_COMMON_PASSWORD_MANAGER_SWITCHES_H_
diff --git a/components/password_manager/sync/browser/sync_credentials_filter.cc b/components/password_manager/sync/browser/sync_credentials_filter.cc
index 7e9699d..5632331d 100644
--- a/components/password_manager/sync/browser/sync_credentials_filter.cc
+++ b/components/password_manager/sync/browser/sync_credentials_filter.cc
@@ -6,12 +6,12 @@
 
 #include <algorithm>
 
-#include "base/command_line.h"
 #include "base/macros.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
-#include "components/password_manager/core/common/password_manager_switches.h"
+#include "components/password_manager/core/browser/password_manager_util.h"
+#include "components/password_manager/core/common/password_manager_features.h"
 #include "components/password_manager/sync/browser/password_sync_util.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "net/base/url_util.h"
@@ -88,25 +88,33 @@
 // static
 SyncCredentialsFilter::AutofillForSyncCredentialsState
 SyncCredentialsFilter::GetAutofillForSyncCredentialsState() {
-  std::string group_name =
-      base::FieldTrialList::FindFullName("AutofillSyncCredential");
+  bool protect_sync_credential_enabled =
+      base::FeatureList::IsEnabled(features::kProtectSyncCredential);
+  bool protect_sync_credential_on_reauth_enabled =
+      base::FeatureList::IsEnabled(features::kProtectSyncCredentialOnReauth);
 
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(switches::kAllowAutofillSyncCredential))
-    return ALLOW_SYNC_CREDENTIALS;
-  if (command_line->HasSwitch(
-          switches::kDisallowAutofillSyncCredentialForReauth)) {
+  if (protect_sync_credential_enabled) {
+    if (protect_sync_credential_on_reauth_enabled) {
+      // Both the features are enabled, do not ever fill the sync credential.
+      return DISALLOW_SYNC_CREDENTIALS;
+    }
+
+    // Only 'protect-sync-credential-on-reauth' feature is kept disabled. This
+    // is "illegal", emit a warning and do not ever fill the sync credential.
+    LOG(WARNING) << "This is illegal! Feature "
+                    "'protect-sync-credential-on-reauth' cannot be kept "
+                    "disabled if 'protect-sync-credential' feature is enabled. "
+                    "We shall not ever fill the sync credential is such cases.";
+    return DISALLOW_SYNC_CREDENTIALS;
+  }
+
+  if (protect_sync_credential_on_reauth_enabled) {
+    // Only 'protect-sync-credential-on-reauth' feature is kept enabled, fill
+    // the sync credential everywhere but on reauth.
     return DISALLOW_SYNC_CREDENTIALS_FOR_REAUTH;
   }
-  if (command_line->HasSwitch(switches::kDisallowAutofillSyncCredential))
-    return DISALLOW_SYNC_CREDENTIALS;
 
-  if (group_name == "DisallowSyncCredentialsForReauth")
-    return DISALLOW_SYNC_CREDENTIALS_FOR_REAUTH;
-  if (group_name == "DisallowSyncCredentials")
-    return DISALLOW_SYNC_CREDENTIALS;
-
-  // Allow by default.
+  // Both the features are disabled, fill the sync credential everywhere.
   return ALLOW_SYNC_CREDENTIALS;
 }
 
diff --git a/components/password_manager/sync/browser/sync_credentials_filter_unittest.cc b/components/password_manager/sync/browser/sync_credentials_filter_unittest.cc
index cc43857..a6dbcba 100644
--- a/components/password_manager/sync/browser/sync_credentials_filter_unittest.cc
+++ b/components/password_manager/sync/browser/sync_credentials_filter_unittest.cc
@@ -6,16 +6,17 @@
 
 #include <stddef.h>
 #include <utility>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
-#include "base/command_line.h"
 #include "base/macros.h"
 #include "base/test/histogram_tester.h"
 #include "base/test/user_action_tester.h"
 #include "components/autofill/core/common/password_form.h"
+#include "components/password_manager/core/browser/password_manager_test_utils.h"
 #include "components/password_manager/core/browser/stub_password_manager_client.h"
-#include "components/password_manager/core/common/password_manager_switches.h"
+#include "components/password_manager/core/common/password_manager_features.h"
 #include "components/password_manager/sync/browser/sync_username_test_base.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -135,9 +136,14 @@
 }
 
 TEST_F(CredentialsFilterTest, FilterResults_DisallowSyncOnReauth) {
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  command_line->AppendSwitch(
-      switches::kDisallowAutofillSyncCredentialForReauth);
+  // Only 'protect-sync-credential-on-reauth' feature is kept enabled, fill the
+  // sync credential everywhere but on reauth.
+  scoped_ptr<base::FeatureList> feature_list(new base::FeatureList);
+  std::vector<const base::Feature*> enabled_features;
+  std::vector<const base::Feature*> disabled_features;
+  disabled_features.push_back(&features::kProtectSyncCredential);
+  enabled_features.push_back(&features::kProtectSyncCredentialOnReauth);
+  SetFeatures(enabled_features, disabled_features, std::move(feature_list));
 
   const TestCase kTestCases[] = {
       // Reauth URL, not sync username.
@@ -176,8 +182,14 @@
 }
 
 TEST_F(CredentialsFilterTest, FilterResults_DisallowSync) {
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  command_line->AppendSwitch(switches::kDisallowAutofillSyncCredential);
+  // Both features are kept enabled, should cause sync credential to be
+  // filtered.
+  scoped_ptr<base::FeatureList> feature_list(new base::FeatureList);
+  std::vector<const base::Feature*> enabled_features;
+  std::vector<const base::Feature*> disabled_features;
+  enabled_features.push_back(&features::kProtectSyncCredential);
+  enabled_features.push_back(&features::kProtectSyncCredentialOnReauth);
+  SetFeatures(enabled_features, disabled_features, std::move(feature_list));
 
   const TestCase kTestCases[] = {
       // Reauth URL, not sync username.
@@ -248,9 +260,14 @@
 }
 
 TEST_F(CredentialsFilterTest, ShouldFilterOneForm) {
-  // Adding disallow switch should cause sync credential to be filtered.
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  command_line->AppendSwitch(switches::kDisallowAutofillSyncCredential);
+  // Both features are kept enabled, should cause sync credential to be
+  // filtered.
+  scoped_ptr<base::FeatureList> feature_list(new base::FeatureList);
+  std::vector<const base::Feature*> enabled_features;
+  std::vector<const base::Feature*> disabled_features;
+  enabled_features.push_back(&features::kProtectSyncCredential);
+  enabled_features.push_back(&features::kProtectSyncCredentialOnReauth);
+  SetFeatures(enabled_features, disabled_features, std::move(feature_list));
 
   ScopedVector<autofill::PasswordForm> results;
   results.push_back(new PasswordForm(SimpleGaiaForm("test1@gmail.com")));
diff --git a/components/suggestions.gypi b/components/suggestions.gypi
index efffdef..dbbfe64d 100644
--- a/components/suggestions.gypi
+++ b/components/suggestions.gypi
@@ -19,6 +19,7 @@
         'components.gyp:data_use_measurement_core',
         'components.gyp:keyed_service_core',
         'components.gyp:pref_registry',
+        'components.gyp:sync_driver',
         'components.gyp:variations',
         'components.gyp:variations_net',
       ],
@@ -37,8 +38,6 @@
         'suggestions/suggestions_service.h',
         'suggestions/suggestions_store.cc',
         'suggestions/suggestions_store.h',
-        'suggestions/suggestions_utils.cc',
-        'suggestions/suggestions_utils.h',
       ],
       'variables': {
         'proto_in_dir': 'suggestions/proto',
diff --git a/components/suggestions/BUILD.gn b/components/suggestions/BUILD.gn
index 4ffad36..e33d5f1 100644
--- a/components/suggestions/BUILD.gn
+++ b/components/suggestions/BUILD.gn
@@ -17,8 +17,6 @@
     "suggestions_service.h",
     "suggestions_store.cc",
     "suggestions_store.h",
-    "suggestions_utils.cc",
-    "suggestions_utils.h",
   ]
 
   public_deps = [
@@ -36,6 +34,7 @@
     "//components/leveldb_proto",
     "//components/pref_registry",
     "//components/signin/core/browser",
+    "//components/sync_driver:sync_driver",
     "//components/variations",
     "//components/variations/net",
     "//google_apis",
@@ -62,6 +61,7 @@
     "//components/leveldb_proto:test_support",
     "//components/pref_registry:test_support",
     "//components/signin/core/browser:test_support",
+    "//components/sync_driver:test_support",
     "//net:test_support",
     "//testing/gmock",
     "//testing/gtest",
diff --git a/components/suggestions/DEPS b/components/suggestions/DEPS
index c9c05fa..db8a80f 100644
--- a/components/suggestions/DEPS
+++ b/components/suggestions/DEPS
@@ -6,6 +6,7 @@
   "+components/pref_registry",
   "+components/prefs",
   "+components/signin/core/browser",
+  "+components/sync_driver",
   "+components/variations",
   "+google_apis",
   "+net",
diff --git a/components/suggestions/suggestions_service.cc b/components/suggestions/suggestions_service.cc
index d76ec66..5293228 100644
--- a/components/suggestions/suggestions_service.cc
+++ b/components/suggestions/suggestions_service.cc
@@ -22,6 +22,7 @@
 #include "components/suggestions/blacklist_store.h"
 #include "components/suggestions/image_manager.h"
 #include "components/suggestions/suggestions_store.h"
+#include "components/sync_driver/sync_service.h"
 #include "components/variations/net/variations_http_headers.h"
 #include "google_apis/gaia/gaia_constants.h"
 #include "google_apis/gaia/oauth2_token_service.h"
@@ -42,6 +43,37 @@
 
 namespace {
 
+// Establishes the different sync states that matter to SuggestionsService.
+// There are three different concepts in the sync service: initialized, sync
+// enabled and history sync enabled.
+enum SyncState {
+  // State: Sync service is not initialized, yet not disabled. History sync
+  //     state is unknown (since not initialized).
+  // Behavior: Does not issue a server request, but serves from cache if
+  //     available.
+  NOT_INITIALIZED_ENABLED,
+
+  // State: Sync service is initialized, sync is enabled and history sync is
+  //     enabled.
+  // Behavior: Update suggestions from the server. Serve from cache on timeout.
+  INITIALIZED_ENABLED_HISTORY,
+
+  // State: Sync service is disabled or history sync is disabled.
+  // Behavior: Do not issue a server request. Clear the cache. Serve empty
+  //     suggestions.
+  SYNC_OR_HISTORY_SYNC_DISABLED,
+};
+
+SyncState GetSyncState(sync_driver::SyncService* sync) {
+  if (!sync || !sync->CanSyncStart())
+    return SYNC_OR_HISTORY_SYNC_DISABLED;
+  if (!sync->IsSyncActive() || !sync->ConfigurationDone())
+    return NOT_INITIALIZED_ENABLED;
+  return sync->GetActiveDataTypes().Has(syncer::HISTORY_DELETE_DIRECTIVES)
+             ? INITIALIZED_ENABLED_HISTORY
+             : SYNC_OR_HISTORY_SYNC_DISABLED;
+}
+
 // Used to UMA log the state of the last response from the server.
 enum SuggestionsResponseState {
   RESPONSE_EMPTY,
@@ -167,44 +199,51 @@
 SuggestionsService::SuggestionsService(
     const SigninManagerBase* signin_manager,
     OAuth2TokenService* token_service,
+    sync_driver::SyncService* sync_service,
     net::URLRequestContextGetter* url_request_context,
     scoped_ptr<SuggestionsStore> suggestions_store,
     scoped_ptr<ImageManager> thumbnail_manager,
     scoped_ptr<BlacklistStore> blacklist_store)
-    : url_request_context_(url_request_context),
+    : sync_service_(sync_service),
+      sync_service_observer_(this),
+      url_request_context_(url_request_context),
       suggestions_store_(std::move(suggestions_store)),
       thumbnail_manager_(std::move(thumbnail_manager)),
       blacklist_store_(std::move(blacklist_store)),
       scheduling_delay_(TimeDelta::FromSeconds(kDefaultSchedulingDelaySec)),
       token_fetcher_(new AccessTokenFetcher(signin_manager, token_service)),
-      weak_ptr_factory_(this) {}
+      weak_ptr_factory_(this) {
+  // |sync_service_| is null if switches::kDisableSync is set (tests use that).
+  if (sync_service_)
+    sync_service_observer_.Add(sync_service_);
+  // Immediately get the current sync state, so we'll flush the cache if
+  // necessary.
+  OnStateChanged();
+}
 
 SuggestionsService::~SuggestionsService() {}
 
-void SuggestionsService::FetchSuggestionsData(
-    SyncState sync_state,
-    const ResponseCallback& callback) {
+bool SuggestionsService::FetchSuggestionsData() {
   DCHECK(thread_checker_.CalledOnValidThread());
-  switch (sync_state) {
-    case SYNC_OR_HISTORY_SYNC_DISABLED:
-      // Cancel any ongoing request, to stop interacting with the server.
-      pending_request_.reset(nullptr);
-      suggestions_store_->ClearSuggestions();
-      if (!callback.is_null())
-        callback.Run(SuggestionsProfile());
-      break;
-    case INITIALIZED_ENABLED_HISTORY:
-    case NOT_INITIALIZED_ENABLED:
-      // TODO(treib): For NOT_INITIALIZED_ENABLED, we shouldn't issue a network
-      // request. Verify that that won't break anything.
-      // Sync is enabled. Serve previously cached suggestions if available, else
-      // an empty set of suggestions.
-      ServeFromCache(callback);
+  // If sync state allows, issue a network request to refresh the suggestions.
+  if (GetSyncState(sync_service_) != INITIALIZED_ENABLED_HISTORY)
+    return false;
+  IssueRequestIfNoneOngoing(BuildSuggestionsURL());
+  return true;
+}
 
-      // Issue a network request to refresh the suggestions in the cache.
-      IssueRequestIfNoneOngoing(BuildSuggestionsURL());
-      break;
-  }
+SuggestionsProfile SuggestionsService::GetSuggestionsDataFromCache() const {
+  SuggestionsProfile suggestions;
+  // In case of empty cache or error, |suggestions| stays empty.
+  suggestions_store_->LoadSuggestions(&suggestions);
+  thumbnail_manager_->Initialize(suggestions);
+  blacklist_store_->FilterSuggestions(&suggestions);
+  return suggestions;
+}
+
+scoped_ptr<SuggestionsService::ResponseCallbackList::Subscription>
+SuggestionsService::AddCallback(const ResponseCallback& callback) {
+  return callback_list_.Add(callback);
 }
 
 void SuggestionsService::GetPageThumbnail(const GURL& url,
@@ -220,27 +259,23 @@
   GetPageThumbnail(url, callback);
 }
 
-void SuggestionsService::BlacklistURL(const GURL& candidate_url,
-                                      const ResponseCallback& callback,
-                                      const base::Closure& fail_callback) {
+bool SuggestionsService::BlacklistURL(const GURL& candidate_url) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  if (!blacklist_store_->BlacklistUrl(candidate_url)) {
-    if (!fail_callback.is_null())
-      fail_callback.Run();
-    return;
-  }
+  if (!blacklist_store_->BlacklistUrl(candidate_url))
+    return false;
 
-  ServeFromCache(callback);
+  callback_list_.Notify(GetSuggestionsDataFromCache());
+
   // Blacklist uploads are scheduled on any request completion, so only schedule
   // an upload if there is no ongoing request.
   if (!pending_request_.get())
     ScheduleBlacklistUpload();
+
+  return true;
 }
 
-void SuggestionsService::UndoBlacklistURL(const GURL& url,
-                                          const ResponseCallback& callback,
-                                          const base::Closure& fail_callback) {
+bool SuggestionsService::UndoBlacklistURL(const GURL& url) {
   DCHECK(thread_checker_.CalledOnValidThread());
   TimeDelta time_delta;
   if (blacklist_store_->GetTimeUntilURLReadyForUpload(url, &time_delta) &&
@@ -248,18 +283,17 @@
       blacklist_store_->RemoveUrl(url)) {
     // The URL was not yet candidate for upload to the server and could be
     // removed from the blacklist.
-    ServeFromCache(callback);
-    return;
+    callback_list_.Notify(GetSuggestionsDataFromCache());
+    return true;
   }
-  if (!fail_callback.is_null())
-    fail_callback.Run();
+  return false;
 }
 
-void SuggestionsService::ClearBlacklist(const ResponseCallback& callback) {
+void SuggestionsService::ClearBlacklist() {
   DCHECK(thread_checker_.CalledOnValidThread());
   blacklist_store_->ClearBlacklist();
+  callback_list_.Notify(GetSuggestionsDataFromCache());
   IssueRequestIfNoneOngoing(BuildSuggestionsBlacklistClearURL());
-  ServeFromCache(callback);
 }
 
 // static
@@ -323,6 +357,26 @@
                                  kDeviceType));
 }
 
+void SuggestionsService::OnStateChanged() {
+  switch (GetSyncState(sync_service_)) {
+    case SYNC_OR_HISTORY_SYNC_DISABLED:
+      // Cancel any ongoing request, to stop interacting with the server.
+      pending_request_.reset(nullptr);
+      suggestions_store_->ClearSuggestions();
+      callback_list_.Notify(SuggestionsProfile());
+      break;
+    case NOT_INITIALIZED_ENABLED:
+      // Keep the cache (if any), but don't refresh.
+      break;
+    case INITIALIZED_ENABLED_HISTORY:
+      // If we have any observers, issue a network request to refresh the
+      // suggestions in the cache.
+      if (!callback_list_.empty())
+        IssueRequestIfNoneOngoing(BuildSuggestionsURL());
+      break;
+  }
+}
+
 void SuggestionsService::SetDefaultExpiryTimestamp(
     SuggestionsProfile* suggestions,
     int64_t default_timestamp_usec) {
@@ -455,6 +509,8 @@
     LogResponseState(RESPONSE_INVALID);
   }
 
+  callback_list_.Notify(GetSuggestionsDataFromCache());
+
   UpdateBlacklistDelay(true);
   ScheduleBlacklistUpload();
 }
@@ -483,16 +539,6 @@
   pending_request_.reset(nullptr);
 }
 
-void SuggestionsService::ServeFromCache(const ResponseCallback& callback) {
-  SuggestionsProfile suggestions;
-  // In case of empty cache or error, |suggestions| stays empty.
-  suggestions_store_->LoadSuggestions(&suggestions);
-  thumbnail_manager_->Initialize(suggestions);
-  blacklist_store_->FilterSuggestions(&suggestions);
-  if (!callback.is_null())
-    callback.Run(suggestions);
-}
-
 void SuggestionsService::ScheduleBlacklistUpload() {
   DCHECK(thread_checker_.CalledOnValidThread());
   TimeDelta time_delta;
diff --git a/components/suggestions/suggestions_service.h b/components/suggestions/suggestions_service.h
index 558633c..49d2052 100644
--- a/components/suggestions/suggestions_service.h
+++ b/components/suggestions/suggestions_service.h
@@ -10,15 +10,17 @@
 #include <string>
 
 #include "base/callback.h"
+#include "base/callback_list.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/scoped_observer.h"
 #include "base/threading/thread_checker.h"
 #include "base/time/time.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/suggestions/proto/suggestions.pb.h"
-#include "components/suggestions/suggestions_utils.h"
+#include "components/sync_driver/sync_service_observer.h"
 #include "net/url_request/url_fetcher_delegate.h"
 #include "url/gurl.h"
 
@@ -26,6 +28,10 @@
 class URLRequestContextGetter;
 }  // namespace net
 
+namespace sync_driver {
+class SyncService;
+}
+
 namespace user_prefs {
 class PrefRegistrySyncable;
 }  // namespace user_prefs
@@ -41,32 +47,36 @@
 class SuggestionsStore;
 
 // An interface to fetch server suggestions asynchronously.
-class SuggestionsService : public KeyedService, public net::URLFetcherDelegate {
+class SuggestionsService : public KeyedService,
+                           public net::URLFetcherDelegate,
+                           public sync_driver::SyncServiceObserver {
  public:
   using ResponseCallback = base::Callback<void(const SuggestionsProfile&)>;
   using BitmapCallback = base::Callback<void(const GURL&, const SkBitmap*)>;
 
-  SuggestionsService(
-      const SigninManagerBase* signin_manager,
-      OAuth2TokenService* token_service,
-      net::URLRequestContextGetter* url_request_context,
-      scoped_ptr<SuggestionsStore> suggestions_store,
-      scoped_ptr<ImageManager> thumbnail_manager,
-      scoped_ptr<BlacklistStore> blacklist_store);
+  using ResponseCallbackList =
+      base::CallbackList<void(const SuggestionsProfile&)>;
+
+  SuggestionsService(const SigninManagerBase* signin_manager,
+                     OAuth2TokenService* token_service,
+                     sync_driver::SyncService* sync_service,
+                     net::URLRequestContextGetter* url_request_context,
+                     scoped_ptr<SuggestionsStore> suggestions_store,
+                     scoped_ptr<ImageManager> thumbnail_manager,
+                     scoped_ptr<BlacklistStore> blacklist_store);
   ~SuggestionsService() override;
 
-  // Requests suggestions data. Passes the currently cached data to |callback|.
-  // |sync_state| influences the behavior of this function (see SyncState
-  // definition).
-  //
-  // |sync_state| must be specified based on the current state of the system
-  // (see suggestions::GetSyncState). Callers should call this function again if
-  // sync state changes.
-  //
-  // If state allows for a network request, it is initiated unless a pending one
-  // exists, to fill the cache for next time.
-  void FetchSuggestionsData(SyncState sync_state,
-                            const ResponseCallback& callback);
+  // Initiates a network request for suggestions if sync state allows and there
+  // is no pending request. Returns true iff sync state allowed for a request,
+  // whether a new request was actually sent or not.
+  bool FetchSuggestionsData();
+
+  // Returns the current set of suggestions from the cache.
+  SuggestionsProfile GetSuggestionsDataFromCache() const;
+
+  // Adds a callback that is called when the suggestions are updated.
+  scoped_ptr<ResponseCallbackList::Subscription> AddCallback(
+      const ResponseCallback& callback) WARN_UNUSED_RESULT;
 
   // Retrieves stored thumbnail for website |url| asynchronously. Calls
   // |callback| with Bitmap pointer if found, and NULL otherwise.
@@ -79,21 +89,16 @@
                                const GURL& thumbnail_url,
                                const BitmapCallback& callback);
 
-  // Adds a URL to the blacklist cache, invoking |callback| on success or
-  // |fail_callback| otherwise. The URL will eventually be uploaded to the
-  // server.
-  void BlacklistURL(const GURL& candidate_url,
-                    const ResponseCallback& callback,
-                    const base::Closure& fail_callback);
+  // Adds a URL to the blacklist cache, returning true on success or false on
+  // failure. The URL will eventually be uploaded to the server.
+  bool BlacklistURL(const GURL& candidate_url);
 
-  // Removes a URL from the local blacklist, then invokes |callback|. If the URL
-  // cannot be removed, the |fail_callback| is called.
-  void UndoBlacklistURL(const GURL& url,
-                        const ResponseCallback& callback,
-                        const base::Closure& fail_callback);
+  // Removes a URL from the local blacklist, returning true on success or false
+  // on failure.
+  bool UndoBlacklistURL(const GURL& url);
 
-  // Removes all URLs from the blacklist then invokes |callback|.
-  void ClearBlacklist(const ResponseCallback& callback);
+  // Removes all URLs from the blacklist.
+  void ClearBlacklist();
 
   // Determines which URL a blacklist request was for, irrespective of the
   // request's status. Returns false if |request| is not a blacklist request.
@@ -104,6 +109,9 @@
 
  private:
   friend class SuggestionsServiceTest;
+  FRIEND_TEST_ALL_PREFIXES(SuggestionsServiceTest, FetchSuggestionsData);
+  FRIEND_TEST_ALL_PREFIXES(SuggestionsServiceTest,
+                           FetchSuggestionsDataSyncDisabled);
   FRIEND_TEST_ALL_PREFIXES(SuggestionsServiceTest,
                            FetchSuggestionsDataNoAccessToken);
   FRIEND_TEST_ALL_PREFIXES(SuggestionsServiceTest,
@@ -131,6 +139,9 @@
   static GURL BuildSuggestionsBlacklistURL(const GURL& candidate_url);
   static GURL BuildSuggestionsBlacklistClearURL();
 
+  // sync_driver::SyncServiceObserver implementation.
+  void OnStateChanged() override;
+
   // Sets default timestamp for suggestions which do not have expiry timestamp.
   void SetDefaultExpiryTimestamp(SuggestionsProfile* suggestions,
                                  int64_t timestamp_usec);
@@ -159,10 +170,6 @@
   // KeyedService implementation.
   void Shutdown() override;
 
-  // Loads the cached suggestions (or empty suggestions if no cache), applies
-  // the local blacklist, then calls the |callback|.
-  void ServeFromCache(const ResponseCallback& callback);
-
   // Schedules a blacklisting request if the local blacklist isn't empty.
   void ScheduleBlacklistUpload();
 
@@ -183,6 +190,10 @@
 
   base::ThreadChecker thread_checker_;
 
+  sync_driver::SyncService* sync_service_;
+  ScopedObserver<sync_driver::SyncService, sync_driver::SyncServiceObserver>
+      sync_service_observer_;
+
   net::URLRequestContextGetter* url_request_context_;
 
   // The cache for the suggestions.
@@ -210,6 +221,8 @@
   // the latency of requests. Initially zero.
   base::TimeTicks last_request_started_time_;
 
+  ResponseCallbackList callback_list_;
+
   // For callbacks may be run after destruction.
   base::WeakPtrFactory<SuggestionsService> weak_ptr_factory_;
 
diff --git a/components/suggestions/suggestions_service_unittest.cc b/components/suggestions/suggestions_service_unittest.cc
index 4e7d950..7398bda8 100644
--- a/components/suggestions/suggestions_service_unittest.cc
+++ b/components/suggestions/suggestions_service_unittest.cc
@@ -6,8 +6,6 @@
 
 #include <stdint.h>
 
-#include <map>
-#include <sstream>
 #include <utility>
 
 #include "base/bind.h"
@@ -19,7 +17,8 @@
 #include "components/suggestions/image_manager.h"
 #include "components/suggestions/proto/suggestions.pb.h"
 #include "components/suggestions/suggestions_store.h"
-#include "components/suggestions/suggestions_utils.h"
+#include "components/sync_driver/fake_sync_service.h"
+#include "components/sync_driver/sync_service.h"
 #include "net/base/escape.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_status_code.h"
@@ -29,7 +28,6 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using std::string;
 using testing::DoAll;
 using ::testing::AnyNumber;
 using ::testing::Eq;
@@ -115,6 +113,16 @@
   return profile;
 }
 
+class MockSyncService : public sync_driver::FakeSyncService {
+ public:
+  MockSyncService() {}
+  virtual ~MockSyncService() {}
+  MOCK_CONST_METHOD0(CanSyncStart, bool());
+  MOCK_CONST_METHOD0(IsSyncActive, bool());
+  MOCK_CONST_METHOD0(ConfigurationDone, bool());
+  MOCK_CONST_METHOD0(GetActiveDataTypes, syncer::ModelTypeSet());
+};
+
 class TestSuggestionsStore : public suggestions::SuggestionsStore {
  public:
   TestSuggestionsStore() {
@@ -124,8 +132,7 @@
     suggestions->CopyFrom(cached_suggestions);
     return cached_suggestions.suggestions_size();
   }
-  bool StoreSuggestions(const SuggestionsProfile& suggestions)
-      override {
+  bool StoreSuggestions(const SuggestionsProfile& suggestions) override {
     cached_suggestions.CopyFrom(suggestions);
     return true;
   }
@@ -164,6 +171,8 @@
  public:
   void CheckCallback(const SuggestionsProfile& suggestions_profile) {
     ++suggestions_data_callback_count_;
+    if (suggestions_profile.suggestions_size() == 0)
+      ++suggestions_empty_data_count_;
   }
 
   void CheckSuggestionsData() {
@@ -179,19 +188,6 @@
     EXPECT_EQ(kTestClickUrl, suggestions_profile.suggestions(0).click_url());
   }
 
-  void SetBlacklistFailure() {
-    blacklisting_failed_ = true;
-  }
-
-  void SetUndoBlacklistFailure() {
-    undo_blacklisting_failed_ = true;
-  }
-
-  void ExpectEmptySuggestionsProfile(const SuggestionsProfile& profile) {
-    EXPECT_EQ(0, profile.suggestions_size());
-    ++suggestions_empty_data_count_;
-  }
-
   int suggestions_data_callback_count_;
   int suggestions_empty_data_count_;
   bool blacklisting_failed_;
@@ -203,10 +199,11 @@
         suggestions_empty_data_count_(0),
         blacklisting_failed_(false),
         undo_blacklisting_failed_(false),
-        factory_(NULL, base::Bind(&CreateURLFetcher)),
-        mock_thumbnail_manager_(NULL),
-        mock_blacklist_store_(NULL),
-        test_suggestions_store_(NULL) {
+        factory_(nullptr, base::Bind(&CreateURLFetcher)),
+        mock_sync_service_(nullptr),
+        mock_thumbnail_manager_(nullptr),
+        mock_blacklist_store_(nullptr),
+        test_suggestions_store_(nullptr) {
     token_service_.UpdateCredentials(kAccountId, "refresh_token");
     token_service_.set_auto_post_fetch_response_on_message_loop(true);
   }
@@ -228,40 +225,16 @@
         new net::TestURLRequestContextGetter(io_message_loop_.task_runner());
   }
 
-  void FetchSuggestionsDataHelper(SyncState sync_state) {
-    scoped_ptr<SuggestionsService> suggestions_service(
-        CreateSuggestionsServiceWithMocks());
-    EXPECT_TRUE(suggestions_service != NULL);
-
-    SuggestionsProfile suggestions_profile = CreateSuggestionsProfile();
-
-    // Set up net::FakeURLFetcherFactory.
-    factory_.SetFakeResponse(SuggestionsService::BuildSuggestionsURL(),
-                             suggestions_profile.SerializeAsString(),
-                             net::HTTP_OK, net::URLRequestStatus::SUCCESS);
-
-    // Expectations.
-    EXPECT_CALL(*mock_thumbnail_manager_,
-                Initialize(EqualsProto(suggestions_profile)));
-    EXPECT_CALL(*mock_blacklist_store_, FilterSuggestions(_));
-    EXPECT_CALL(*mock_blacklist_store_, GetTimeUntilReadyForUpload(_))
-        .WillOnce(Return(false));
-
-    // Send the request. The data will be returned to the callback.
-    suggestions_service->FetchSuggestionsData(
-        sync_state, base::Bind(&SuggestionsServiceTest::CheckCallback,
-                               base::Unretained(this)));
-
-    // Ensure that CheckCallback() ran once.
-    EXPECT_EQ(1, suggestions_data_callback_count_);
-
-    // Let the network request run.
-    io_message_loop_.RunUntilIdle();
-
-    CheckSuggestionsData();
-  }
-
   SuggestionsService* CreateSuggestionsServiceWithMocks() {
+    mock_sync_service_.reset(new MockSyncService);
+    ON_CALL(*mock_sync_service_, CanSyncStart()).WillByDefault(Return(true));
+    ON_CALL(*mock_sync_service_, IsSyncActive()).WillByDefault(Return(true));
+    ON_CALL(*mock_sync_service_, ConfigurationDone())
+        .WillByDefault(Return(true));
+    ON_CALL(*mock_sync_service_, GetActiveDataTypes())
+        .WillByDefault(
+            Return(syncer::ModelTypeSet(syncer::HISTORY_DELETE_DIRECTIVES)));
+
     // These objects are owned by the returned SuggestionsService, but we keep
     // the pointer around for testing.
     test_suggestions_store_ = new TestSuggestionsStore();
@@ -270,6 +243,7 @@
     return new SuggestionsService(
         nullptr /* signin_manager */,
         &token_service_,
+        mock_sync_service_.get(),
         request_context_.get(),
         scoped_ptr<SuggestionsStore>(test_suggestions_store_),
         scoped_ptr<ImageManager>(mock_thumbnail_manager_),
@@ -277,19 +251,11 @@
   }
 
   void Blacklist(SuggestionsService* suggestions_service, GURL url) {
-    suggestions_service->BlacklistURL(
-        url, base::Bind(&SuggestionsServiceTest::CheckCallback,
-                        base::Unretained(this)),
-        base::Bind(&SuggestionsServiceTest::SetBlacklistFailure,
-                   base::Unretained(this)));
+    blacklisting_failed_ = !suggestions_service->BlacklistURL(url);
   }
 
   void UndoBlacklist(SuggestionsService* suggestions_service, GURL url) {
-    suggestions_service->UndoBlacklistURL(
-        url, base::Bind(&SuggestionsServiceTest::CheckCallback,
-                        base::Unretained(this)),
-        base::Bind(&SuggestionsServiceTest::SetUndoBlacklistFailure,
-                   base::Unretained(this)));
+    undo_blacklisting_failed_ = !suggestions_service->UndoBlacklistURL(url);
   }
 
   // Helper for Undo failure tests. Depending on |is_uploaded|, tests either
@@ -298,10 +264,14 @@
   void UndoBlacklistURLFailsHelper(bool is_uploaded) {
     scoped_ptr<SuggestionsService> suggestions_service(
         CreateSuggestionsServiceWithMocks());
-    EXPECT_TRUE(suggestions_service != NULL);
+    EXPECT_TRUE(suggestions_service != nullptr);
     // Ensure scheduling the request doesn't happen before undo.
     base::TimeDelta delay = base::TimeDelta::FromHours(1);
     suggestions_service->set_blacklist_delay(delay);
+
+    auto subscription = suggestions_service->AddCallback(base::Bind(
+        &SuggestionsServiceTest::CheckCallback, base::Unretained(this)));
+
     SuggestionsProfile suggestions_profile = CreateSuggestionsProfile();
     GURL blacklisted_url(kBlacklistedUrl);
 
@@ -343,6 +313,7 @@
   base::MessageLoopForIO io_message_loop_;
   net::FakeURLFetcherFactory factory_;
   FakeProfileOAuth2TokenService token_service_;
+  scoped_ptr<MockSyncService> mock_sync_service_;
   // Only used if the SuggestionsService is built with mocks. Not owned.
   MockImageManager* mock_thumbnail_manager_;
   MockBlacklistStore* mock_blacklist_store_;
@@ -354,27 +325,91 @@
 };
 
 TEST_F(SuggestionsServiceTest, FetchSuggestionsData) {
-  FetchSuggestionsDataHelper(INITIALIZED_ENABLED_HISTORY);
+  scoped_ptr<SuggestionsService> suggestions_service(
+      CreateSuggestionsServiceWithMocks());
+  ASSERT_TRUE(suggestions_service != nullptr);
+  auto subscription = suggestions_service->AddCallback(base::Bind(
+      &SuggestionsServiceTest::CheckCallback, base::Unretained(this)));
+
+  SuggestionsProfile suggestions_profile = CreateSuggestionsProfile();
+
+  // Set up net::FakeURLFetcherFactory.
+  factory_.SetFakeResponse(SuggestionsService::BuildSuggestionsURL(),
+                           suggestions_profile.SerializeAsString(),
+                           net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+
+  // Expectations.
+  EXPECT_CALL(*mock_thumbnail_manager_, Initialize(_));
+  EXPECT_CALL(*mock_blacklist_store_, FilterSuggestions(_));
+  EXPECT_CALL(*mock_blacklist_store_, GetTimeUntilReadyForUpload(_))
+      .WillOnce(Return(false));
+
+  // Send the request. The data should be returned to the callback.
+  suggestions_service->FetchSuggestionsData();
+
+  // Let the network request run.
+  io_message_loop_.RunUntilIdle();
+
+  // Ensure that CheckCallback() ran once.
+  EXPECT_EQ(1, suggestions_data_callback_count_);
+
+  CheckSuggestionsData();
 }
 
 TEST_F(SuggestionsServiceTest, FetchSuggestionsDataSyncNotInitializedEnabled) {
-  FetchSuggestionsDataHelper(NOT_INITIALIZED_ENABLED);
+  scoped_ptr<SuggestionsService> suggestions_service(
+      CreateSuggestionsServiceWithMocks());
+  ASSERT_TRUE(suggestions_service != nullptr);
+  EXPECT_CALL(*mock_sync_service_, IsSyncActive())
+      .WillRepeatedly(Return(false));
+
+  auto subscription = suggestions_service->AddCallback(base::Bind(
+      &SuggestionsServiceTest::CheckCallback, base::Unretained(this)));
+
+  // Try to fetch suggestions. Since sync is not active, no network request
+  // should be sent.
+  suggestions_service->FetchSuggestionsData();
+
+  // Let any network request run.
+  io_message_loop_.RunUntilIdle();
+
+  // Ensure that CheckCallback() didn't run.
+  EXPECT_EQ(0, suggestions_data_callback_count_);
+
+  // |test_suggestions_store_| should still contain the default values.
+  SuggestionsProfile suggestions;
+  test_suggestions_store_->LoadSuggestions(&suggestions);
+  EXPECT_EQ(CreateSuggestionsProfile().SerializeAsString(),
+            suggestions.SerializeAsString());
 }
 
 TEST_F(SuggestionsServiceTest, FetchSuggestionsDataSyncDisabled) {
   scoped_ptr<SuggestionsService> suggestions_service(
       CreateSuggestionsServiceWithMocks());
-  EXPECT_TRUE(suggestions_service != NULL);
+  ASSERT_TRUE(suggestions_service != nullptr);
+  EXPECT_CALL(*mock_sync_service_, CanSyncStart())
+      .WillRepeatedly(Return(false));
 
-  // Send the request. Cache is cleared and empty data will be returned to the
-  // callback.
-  suggestions_service->FetchSuggestionsData(
-      SYNC_OR_HISTORY_SYNC_DISABLED,
-      base::Bind(&SuggestionsServiceTest::ExpectEmptySuggestionsProfile,
-                 base::Unretained(this)));
+  auto subscription = suggestions_service->AddCallback(base::Bind(
+      &SuggestionsServiceTest::CheckCallback, base::Unretained(this)));
 
-  // Ensure that ExpectEmptySuggestionsProfile ran once.
+  // Tell SuggestionsService that the sync state changed. The cache should be
+  // cleared and empty data returned to the callback.
+  suggestions_service->OnStateChanged();
+
+  // Ensure that CheckCallback ran once with empty data.
+  EXPECT_EQ(1, suggestions_data_callback_count_);
   EXPECT_EQ(1, suggestions_empty_data_count_);
+
+  // Try to fetch suggestions. Since sync is not active, no network request
+  // should be sent.
+  suggestions_service->FetchSuggestionsData();
+
+  // Let any network request run.
+  io_message_loop_.RunUntilIdle();
+
+  // Ensure that CheckCallback didn't run again.
+  EXPECT_EQ(1, suggestions_data_callback_count_);
 }
 
 TEST_F(SuggestionsServiceTest, FetchSuggestionsDataNoAccessToken) {
@@ -384,33 +419,26 @@
 
   scoped_ptr<SuggestionsService> suggestions_service(
       CreateSuggestionsServiceWithMocks());
-  ASSERT_TRUE(suggestions_service != NULL);
+  ASSERT_TRUE(suggestions_service != nullptr);
 
-  // We should get served from cache.
-  // TODO(treib,mathp): Is this the correct behavior when the credentials have
-  // expired? Currently, the SuggestionsService immediately serves from cache,
-  // before even attempting any online auth.
-  EXPECT_CALL(*mock_thumbnail_manager_, Initialize(_));
-  EXPECT_CALL(*mock_blacklist_store_, FilterSuggestions(_));
+  auto subscription = suggestions_service->AddCallback(base::Bind(
+      &SuggestionsServiceTest::CheckCallback, base::Unretained(this)));
+
   EXPECT_CALL(*mock_blacklist_store_, GetTimeUntilReadyForUpload(_))
       .WillOnce(Return(false));
 
-  suggestions_service->FetchSuggestionsData(
-      INITIALIZED_ENABLED_HISTORY,
-      base::Bind(&SuggestionsServiceTest::CheckCallback,
-                 base::Unretained(this)));
+  suggestions_service->FetchSuggestionsData();
 
-  EXPECT_EQ(1, suggestions_data_callback_count_);
-
-  // But no network request should be sent.
+  // No network request should be sent.
   io_message_loop_.RunUntilIdle();
   EXPECT_FALSE(HasPendingSuggestionsRequest(suggestions_service.get()));
+  EXPECT_EQ(0, suggestions_data_callback_count_);
 }
 
 TEST_F(SuggestionsServiceTest, IssueRequestIfNoneOngoingError) {
   scoped_ptr<SuggestionsService> suggestions_service(
       CreateSuggestionsServiceWithMocks());
-  EXPECT_TRUE(suggestions_service != NULL);
+  ASSERT_TRUE(suggestions_service != nullptr);
 
   // Fake a request error.
   factory_.SetFakeResponse(SuggestionsService::BuildSuggestionsURL(),
@@ -431,7 +459,7 @@
 TEST_F(SuggestionsServiceTest, IssueRequestIfNoneOngoingResponseNotOK) {
   scoped_ptr<SuggestionsService> suggestions_service(
       CreateSuggestionsServiceWithMocks());
-  EXPECT_TRUE(suggestions_service != NULL);
+  ASSERT_TRUE(suggestions_service != nullptr);
 
   // Fake a non-200 response code.
   factory_.SetFakeResponse(SuggestionsService::BuildSuggestionsURL(),
@@ -457,10 +485,13 @@
 TEST_F(SuggestionsServiceTest, BlacklistURL) {
   scoped_ptr<SuggestionsService> suggestions_service(
       CreateSuggestionsServiceWithMocks());
-  EXPECT_TRUE(suggestions_service != NULL);
+  EXPECT_TRUE(suggestions_service != nullptr);
   base::TimeDelta no_delay = base::TimeDelta::FromSeconds(0);
   suggestions_service->set_blacklist_delay(no_delay);
 
+  auto subscription = suggestions_service->AddCallback(base::Bind(
+      &SuggestionsServiceTest::CheckCallback, base::Unretained(this)));
+
   GURL blacklisted_url(kBlacklistedUrl);
   GURL request_url(
       SuggestionsService::BuildSuggestionsBlacklistURL(blacklisted_url));
@@ -468,13 +499,12 @@
   factory_.SetFakeResponse(request_url,
                            suggestions_profile.SerializeAsString(),
                            net::HTTP_OK, net::URLRequestStatus::SUCCESS);
-  EXPECT_CALL(*mock_thumbnail_manager_,
-              Initialize(EqualsProto(suggestions_profile)));
+  EXPECT_CALL(*mock_thumbnail_manager_, Initialize(_)).Times(2);
 
   // Expected calls to the blacklist store.
   EXPECT_CALL(*mock_blacklist_store_, BlacklistUrl(Eq(blacklisted_url)))
       .WillOnce(Return(true));
-  EXPECT_CALL(*mock_blacklist_store_, FilterSuggestions(_));
+  EXPECT_CALL(*mock_blacklist_store_, FilterSuggestions(_)).Times(2);
   EXPECT_CALL(*mock_blacklist_store_, GetTimeUntilReadyForUpload(_))
       .WillOnce(DoAll(SetArgPointee<0>(no_delay), Return(true)))
       .WillOnce(Return(false));
@@ -484,6 +514,7 @@
       .WillOnce(Return(true));
 
   Blacklist(suggestions_service.get(), blacklisted_url);
+  EXPECT_EQ(1, suggestions_data_callback_count_);
 
   // Wait on the upload task. This only works when the scheduling task is not
   // for future execution (note how both the SuggestionsService's scheduling
@@ -493,7 +524,7 @@
   io_message_loop_.RunUntilIdle();
   base::MessageLoop::current()->RunUntilIdle();
 
-  EXPECT_EQ(1, suggestions_data_callback_count_);
+  EXPECT_EQ(2, suggestions_data_callback_count_);
   EXPECT_FALSE(blacklisting_failed_);
   CheckSuggestionsData();
 }
@@ -501,7 +532,11 @@
 TEST_F(SuggestionsServiceTest, BlacklistURLFails) {
   scoped_ptr<SuggestionsService> suggestions_service(
       CreateSuggestionsServiceWithMocks());
-  EXPECT_TRUE(suggestions_service != NULL);
+  ASSERT_TRUE(suggestions_service != nullptr);
+
+  auto subscription = suggestions_service->AddCallback(base::Bind(
+      &SuggestionsServiceTest::CheckCallback, base::Unretained(this)));
+
   GURL blacklisted_url(kBlacklistedUrl);
   EXPECT_CALL(*mock_blacklist_store_, BlacklistUrl(Eq(blacklisted_url)))
       .WillOnce(Return(false));
@@ -516,10 +551,13 @@
 TEST_F(SuggestionsServiceTest, BlacklistURLRequestFails) {
   scoped_ptr<SuggestionsService> suggestions_service(
       CreateSuggestionsServiceWithMocks());
-  EXPECT_TRUE(suggestions_service != NULL);
+  ASSERT_TRUE(suggestions_service != nullptr);
   base::TimeDelta no_delay = base::TimeDelta::FromSeconds(0);
   suggestions_service->set_blacklist_delay(no_delay);
 
+  auto subscription = suggestions_service->AddCallback(base::Bind(
+      &SuggestionsServiceTest::CheckCallback, base::Unretained(this)));
+
   GURL blacklisted_url(kBlacklistedUrl);
   GURL request_url(
       SuggestionsService::BuildSuggestionsBlacklistURL(blacklisted_url));
@@ -539,11 +577,10 @@
                            net::HTTP_OK, net::URLRequestStatus::SUCCESS);
 
   // Expectations.
-  EXPECT_CALL(*mock_thumbnail_manager_,
-              Initialize(EqualsProto(suggestions_profile)));
+  EXPECT_CALL(*mock_thumbnail_manager_, Initialize(_)).Times(2);
   EXPECT_CALL(*mock_blacklist_store_, BlacklistUrl(Eq(blacklisted_url)))
       .WillOnce(Return(true));
-  EXPECT_CALL(*mock_blacklist_store_, FilterSuggestions(_));
+  EXPECT_CALL(*mock_blacklist_store_, FilterSuggestions(_)).Times(2);
   EXPECT_CALL(*mock_blacklist_store_, GetTimeUntilReadyForUpload(_))
       .WillOnce(DoAll(SetArgPointee<0>(no_delay), Return(true)))
       .WillOnce(DoAll(SetArgPointee<0>(no_delay), Return(true)))
@@ -574,10 +611,14 @@
 TEST_F(SuggestionsServiceTest, UndoBlacklistURL) {
   scoped_ptr<SuggestionsService> suggestions_service(
       CreateSuggestionsServiceWithMocks());
-  EXPECT_TRUE(suggestions_service != NULL);
+  ASSERT_TRUE(suggestions_service != nullptr);
   // Ensure scheduling the request doesn't happen before undo.
   base::TimeDelta delay = base::TimeDelta::FromHours(1);
   suggestions_service->set_blacklist_delay(delay);
+
+  auto subscription = suggestions_service->AddCallback(base::Bind(
+      &SuggestionsServiceTest::CheckCallback, base::Unretained(this)));
+
   SuggestionsProfile suggestions_profile = CreateSuggestionsProfile();
   GURL blacklisted_url(kBlacklistedUrl);
 
@@ -609,10 +650,14 @@
 TEST_F(SuggestionsServiceTest, ClearBlacklist) {
   scoped_ptr<SuggestionsService> suggestions_service(
       CreateSuggestionsServiceWithMocks());
-  EXPECT_TRUE(suggestions_service != NULL);
+  ASSERT_TRUE(suggestions_service != nullptr);
   // Ensure scheduling the request doesn't happen before undo.
   base::TimeDelta delay = base::TimeDelta::FromHours(1);
   suggestions_service->set_blacklist_delay(delay);
+
+  auto subscription = suggestions_service->AddCallback(base::Bind(
+      &SuggestionsServiceTest::CheckCallback, base::Unretained(this)));
+
   SuggestionsProfile suggestions_profile = CreateSuggestionsProfile();
   GURL blacklisted_url(kBlacklistedUrl);
 
@@ -633,8 +678,7 @@
   EXPECT_CALL(*mock_blacklist_store_, ClearBlacklist());
 
   Blacklist(suggestions_service.get(), blacklisted_url);
-  suggestions_service->ClearBlacklist(base::Bind(
-      &SuggestionsServiceTest::CheckCallback, base::Unretained(this)));
+  suggestions_service->ClearBlacklist();
 
   EXPECT_EQ(2, suggestions_data_callback_count_);
   EXPECT_FALSE(blacklisting_failed_);
@@ -655,7 +699,7 @@
 
   // Not a blacklist request.
   request_url.reset(new GURL("http://not-blacklisting.com/a?b=c"));
-  fetcher = CreateURLFetcher(*request_url, NULL, "", net::HTTP_OK,
+  fetcher = CreateURLFetcher(*request_url, nullptr, "", net::HTTP_OK,
                              net::URLRequestStatus::SUCCESS);
   EXPECT_FALSE(SuggestionsService::GetBlacklistedUrl(*fetcher, &retrieved_url));
 
@@ -668,7 +712,7 @@
   request_url.reset(
       new GURL(blacklist_request_prefix + encoded_blacklisted_url));
   fetcher.reset();
-  fetcher = CreateURLFetcher(*request_url, NULL, "", net::HTTP_OK,
+  fetcher = CreateURLFetcher(*request_url, nullptr, "", net::HTTP_OK,
                              net::URLRequestStatus::SUCCESS);
   EXPECT_TRUE(SuggestionsService::GetBlacklistedUrl(*fetcher, &retrieved_url));
   EXPECT_EQ(blacklisted_url, retrieved_url.spec());
@@ -706,7 +750,7 @@
 TEST_F(SuggestionsServiceTest, GetPageThumbnail) {
   scoped_ptr<SuggestionsService> suggestions_service(
       CreateSuggestionsServiceWithMocks());
-  ASSERT_TRUE(suggestions_service != NULL);
+  ASSERT_TRUE(suggestions_service != nullptr);
 
   GURL test_url(kTestUrl);
   GURL thumbnail_url("https://www.thumbnails.com/thumb.jpg");
diff --git a/components/suggestions/suggestions_utils.cc b/components/suggestions/suggestions_utils.cc
deleted file mode 100644
index 9c32791..0000000
--- a/components/suggestions/suggestions_utils.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/suggestions/suggestions_utils.h"
-
-namespace suggestions {
-
-SyncState GetSyncState(bool sync_enabled,
-                       bool sync_initialized,
-                       bool history_sync_enabled) {
-  if (!sync_enabled)
-    return SYNC_OR_HISTORY_SYNC_DISABLED;
-
-  if (!sync_initialized)
-    return NOT_INITIALIZED_ENABLED;
-
-  return history_sync_enabled ?
-      INITIALIZED_ENABLED_HISTORY : SYNC_OR_HISTORY_SYNC_DISABLED;
-}
-
-}  // namespace suggestions
diff --git a/components/suggestions/suggestions_utils.h b/components/suggestions/suggestions_utils.h
deleted file mode 100644
index f703f18..0000000
--- a/components/suggestions/suggestions_utils.h
+++ /dev/null
@@ -1,40 +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 COMPONENTS_SUGGESTIONS_SUGGESTIONS_UTILS_H_
-#define COMPONENTS_SUGGESTIONS_SUGGESTIONS_UTILS_H_
-
-namespace suggestions {
-
-// Establishes the different sync states that users of SuggestionsService can
-// specify. There are three different concepts in the sync service: initialized,
-// sync enabled and history sync enabled.
-enum SyncState {
-  // State: Sync service is not initialized, yet not disabled. History sync
-  //     state is unknown (since not initialized).
-  // Behavior: Does not issue a server request, but serves from cache if
-  //     available.
-  NOT_INITIALIZED_ENABLED,
-
-  // State: Sync service is initialized, sync is enabled and history sync is
-  //     enabled.
-  // Behavior: Update suggestions from the server. Serve from cache on timeout.
-  INITIALIZED_ENABLED_HISTORY,
-
-  // State: Sync service is disabled or history sync is disabled.
-  // Behavior: Do not issue a server request. Clear the cache. Serve empty
-  //     suggestions.
-  SYNC_OR_HISTORY_SYNC_DISABLED,
-};
-
-// Users of SuggestionsService should always use this function to get SyncState.
-// Note: In chrome/browser/search/suggestions/suggestions_utils.h, there is
-// another variant of this function that takes a Profile* instead.
-SyncState GetSyncState(bool sync_enabled,
-                       bool sync_initialized,
-                       bool history_sync_enabled);
-
-}  // namespace suggestions
-
-#endif  // COMPONENTS_SUGGESTIONS_SUGGESTIONS_UTILS_H_
diff --git a/components/sync_driver/startup_controller.cc b/components/sync_driver/startup_controller.cc
index 4db2bb2..a8ae941 100644
--- a/components/sync_driver/startup_controller.cc
+++ b/components/sync_driver/startup_controller.cc
@@ -39,21 +39,18 @@
 }  // namespace
 
 StartupController::StartupController(
-    ProfileSyncServiceStartBehavior start_behavior,
     const ProfileOAuth2TokenService* token_service,
     const sync_driver::SyncPrefs* sync_prefs,
     const SigninManagerWrapper* signin,
     base::Closure start_backend)
     : received_start_request_(false),
       setup_in_progress_(false),
-      auto_start_enabled_(start_behavior == AUTO_START),
       sync_prefs_(sync_prefs),
       token_service_(token_service),
       signin_(signin),
       start_backend_(start_backend),
       fallback_timeout_(
           base::TimeDelta::FromSeconds(kDeferredInitFallbackSeconds)),
-      first_start_(true),
       weak_factory_(this) {
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kSyncDeferredStartupTimeoutSeconds)) {
@@ -108,7 +105,6 @@
   if (start_backend_time_.is_null()) {
     start_backend_time_ = base::Time::Now();
     start_backend_.Run();
-    first_start_ = false;
   }
 
   return true;
@@ -143,34 +139,18 @@
   // PSS will show error to user asking to reauthenticate.
   UMA_HISTOGRAM_BOOLEAN("Sync.RefreshTokenAvailable", true);
 
-  // If sync setup has completed we always start the backend. If the user is in
-  // the process of setting up now, we should start the backend to download
-  // account control state / encryption information). If autostart is enabled,
-  // but we haven't completed sync setup, we try to start sync anyway, since
-  // it's possible we crashed/shutdown after logging in but before the backend
-  // finished initializing the last time.
+  // For performance reasons, defer the heavy lifting for sync init unless:
   //
-  // However, the only time we actually need to start sync _immediately_ is if
-  // we haven't completed sync setup and the user is in the process of setting
-  // up - either they just signed in (for the first time) on an auto-start
-  // platform or they explicitly kicked off sync setup, and e.g we need to
-  // fetch account details like encryption state to populate UI. Otherwise,
-  // for performance reasons and maximizing parallelism at chrome startup, we
-  // defer the heavy lifting for sync init until things have calmed down.
-  if (sync_prefs_->IsFirstSetupComplete()) {
-    // For first time, defer start if data type hasn't requested sync to avoid
-    // stressing browser start.
-    if (!received_start_request_ && first_start_)
-      return StartUp(STARTUP_BACKEND_DEFERRED);
-    else
-      return StartUp(STARTUP_IMMEDIATE);
-  } else if (setup_in_progress_ || auto_start_enabled_) {
-    // We haven't completed sync setup. Start immediately if the user explicitly
-    // kicked this off or we're supposed to automatically start syncing.
+  // - a datatype has requested an immediate start of sync, or
+  // - sync needs to start up the backend immediately to provide control state
+  //   and encryption information to the UI, or
+  // - this is the first time sync is ever starting up.
+  if (received_start_request_ || setup_in_progress_ ||
+      !sync_prefs_->IsFirstSetupComplete()) {
     return StartUp(STARTUP_IMMEDIATE);
+  } else {
+    return StartUp(STARTUP_BACKEND_DEFERRED);
   }
-
-  return false;
 }
 
 void StartupController::RecordTimeDeferred() {
diff --git a/components/sync_driver/startup_controller.h b/components/sync_driver/startup_controller.h
index c64275048..6d6993a 100644
--- a/components/sync_driver/startup_controller.h
+++ b/components/sync_driver/startup_controller.h
@@ -35,8 +35,7 @@
 // to as "the backend").
 class StartupController {
  public:
-  StartupController(ProfileSyncServiceStartBehavior start_behavior,
-                    const ProfileOAuth2TokenService* token_service,
+  StartupController(const ProfileOAuth2TokenService* token_service,
                     const sync_driver::SyncPrefs* sync_prefs,
                     const SigninManagerWrapper* signin,
                     base::Closure start_backend);
@@ -64,7 +63,6 @@
 
   void set_setup_in_progress(bool in_progress);
   bool IsSetupInProgress() const { return setup_in_progress_; }
-  bool auto_start_enabled() const { return auto_start_enabled_; }
   base::Time start_backend_time() const { return start_backend_time_; }
   std::string GetBackendInitializationStateString() const;
 
@@ -98,12 +96,6 @@
   // due to explicit requests to do so via set_setup_in_progress.
   bool setup_in_progress_;
 
-  // If true, we want to automatically start sync signin whenever we have
-  // credentials (user doesn't need to go through the startup flow). This is
-  // typically enabled on platforms (like ChromeOS) that have their own
-  // distinct signin flow.
-  const bool auto_start_enabled_;
-
   const sync_driver::SyncPrefs* sync_prefs_;
 
   const ProfileOAuth2TokenService* token_service_;
@@ -122,9 +114,6 @@
   // Used to compute preferred_types from SyncPrefs as-needed.
   syncer::ModelTypeSet registered_types_;
 
-  // True before calling |start_backend_| for the first time. False after that.
-  bool first_start_;
-
   base::WeakPtrFactory<StartupController> weak_factory_;
 };
 
diff --git a/components/sync_driver/startup_controller_unittest.cc b/components/sync_driver/startup_controller_unittest.cc
index e11678db..6fada80 100644
--- a/components/sync_driver/startup_controller_unittest.cc
+++ b/components/sync_driver/startup_controller_unittest.cc
@@ -55,7 +55,7 @@
     token_service_.reset(new FakeProfileOAuth2TokenService());
     signin_.reset(new FakeSigninManagerWrapper());
 
-    SetUpController(AUTO_START);
+    SetUpController();
   }
 
   void TearDown() override {
@@ -67,13 +67,12 @@
     started_ = false;
   }
 
-  void SetUpController(ProfileSyncServiceStartBehavior start_behavior) {
+  void SetUpController() {
     started_ = false;
     base::Closure fake_start_backend = base::Bind(
         &StartupControllerTest::FakeStartBackend, base::Unretained(this));
-    controller_.reset(new StartupController(start_behavior, token_service(),
-                                            sync_prefs_.get(), signin_.get(),
-                                            fake_start_backend));
+    controller_.reset(new StartupController(token_service(), sync_prefs_.get(),
+                                            signin_.get(), fake_start_backend));
     controller_->Reset(syncer::UserTypes());
     controller_->OverrideFallbackTimeoutForTest(
         base::TimeDelta::FromSeconds(0));
@@ -81,6 +80,28 @@
 
   void FakeStartBackend() {
     started_ = true;
+    sync_prefs()->SetFirstSetupComplete();
+  }
+
+  void ExpectStarted() {
+    EXPECT_TRUE(started());
+    EXPECT_EQ(kStateStringStarted,
+              controller()->GetBackendInitializationStateString());
+  }
+
+  void ExpectStartDeferred() {
+    const bool deferred_start =
+        !base::CommandLine::ForCurrentProcess()->HasSwitch(
+            switches::kSyncDisableDeferredStartup);
+    EXPECT_EQ(!deferred_start, started());
+    EXPECT_EQ(deferred_start ? kStateStringDeferred : kStateStringStarted,
+              controller()->GetBackendInitializationStateString());
+  }
+
+  void ExpectNotStarted() {
+    EXPECT_FALSE(started());
+    EXPECT_EQ(kStateStringNotStarted,
+              controller()->GetBackendInitializationStateString());
   }
 
   bool started() const { return started_; }
@@ -105,22 +126,19 @@
 // Test that sync doesn't start until all conditions are met.
 TEST_F(StartupControllerTest, Basic) {
   controller()->TryStart();
-  EXPECT_FALSE(started());
+  ExpectNotStarted();
+
   sync_prefs()->SetFirstSetupComplete();
   controller()->TryStart();
-  EXPECT_FALSE(started());
+  ExpectNotStarted();
+
   signin()->set_account_id(kTestUser);
   controller()->TryStart();
-  EXPECT_FALSE(started());
+  ExpectNotStarted();
+
   token_service()->UpdateCredentials(kTestUser, kTestToken);
-  const bool deferred_start =
-      !base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kSyncDisableDeferredStartup);
   controller()->TryStart();
-  EXPECT_EQ(!deferred_start, started());
-  std::string state(controller()->GetBackendInitializationStateString());
-  EXPECT_TRUE(deferred_start ? state == kStateStringDeferred :
-                               state == kStateStringStarted);
+  ExpectStartDeferred();
 }
 
 // Test that sync doesn't start when not requested even if all other
@@ -131,9 +149,7 @@
   signin()->set_account_id(kTestUser);
   token_service()->UpdateCredentials(kTestUser, kTestToken);
   controller()->TryStart();
-  EXPECT_FALSE(started());
-  EXPECT_EQ(kStateStringNotStarted,
-            controller()->GetBackendInitializationStateString());
+  ExpectNotStarted();
 }
 
 // Test that sync doesn't when managed even if all other conditons are met.
@@ -143,9 +159,7 @@
   signin()->set_account_id(kTestUser);
   token_service()->UpdateCredentials(kTestUser, kTestToken);
   controller()->TryStart();
-  EXPECT_FALSE(started());
-  EXPECT_EQ(kStateStringNotStarted,
-            controller()->GetBackendInitializationStateString());
+  ExpectNotStarted();
 }
 
 // Test that sync doesn't start until all conditions are met and a
@@ -155,13 +169,10 @@
   signin()->set_account_id(kTestUser);
   token_service()->UpdateCredentials(kTestUser, kTestToken);
   controller()->TryStart();
-  EXPECT_FALSE(started());
-  EXPECT_EQ(kStateStringDeferred,
-            controller()->GetBackendInitializationStateString());
+  ExpectStartDeferred();
+
   controller()->OnDataTypeRequestsSyncStartup(syncer::SESSIONS);
-  EXPECT_TRUE(started());
-  EXPECT_EQ(kStateStringStarted,
-            controller()->GetBackendInitializationStateString());
+  ExpectStarted();
 
   // The fallback timer shouldn't result in another invocation of the closure
   // we passed to the StartupController.
@@ -177,9 +188,10 @@
   signin()->set_account_id(kTestUser);
   token_service()->UpdateCredentials(kTestUser, kTestToken);
   controller()->TryStart();
-  EXPECT_FALSE(started());
+  ExpectStartDeferred();
+
   base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(started());
+  ExpectStarted();
 }
 
 // Test that we start immediately if sessions is disabled.
@@ -194,60 +206,44 @@
   sync_prefs()->SetPreferredDataTypes(syncer::UserTypes(), types);
   controller()->Reset(syncer::UserTypes());
   sync_prefs()->SetFirstSetupComplete();
+
   signin()->set_account_id(kTestUser);
   token_service()->UpdateCredentials(kTestUser, kTestToken);
   controller()->TryStart();
-  EXPECT_TRUE(started());
+  ExpectStarted();
 }
 
 // Sanity check that the fallback timer doesn't fire before startup
 // conditions are met.
 TEST_F(StartupControllerTest, FallbackTimerWaits) {
   controller()->TryStart();
-  EXPECT_FALSE(started());
+  ExpectNotStarted();
   base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(started());
+  ExpectNotStarted();
 }
 
-// Test that sync starts without the user having to explicitly ask for
-// setup when AUTO_START is the startup behavior requested.
-TEST_F(StartupControllerTest, FirstSetupWithAutoStart) {
-  signin()->set_account_id(kTestUser);
-  token_service()->UpdateCredentials(kTestUser, kTestToken);
-  controller()->TryStart();
-  EXPECT_TRUE(started());
-}
-
-// Test that sync starts only after user explicitly asks for setup when
-// MANUAL_START is the startup behavior requested.
-TEST_F(StartupControllerTest, FirstSetupWithManualStart) {
-  signin()->set_account_id(kTestUser);
-  token_service()->UpdateCredentials(kTestUser, kTestToken);
-  SetUpController(MANUAL_START);
-  controller()->TryStart();
-  EXPECT_FALSE(started());
-  controller()->set_setup_in_progress(true);
-  controller()->TryStart();
-  EXPECT_TRUE(started());
-}
-
-TEST_F(StartupControllerTest, Reset) {
+// Test that start isn't deferred when setup is in progress.
+TEST_F(StartupControllerTest, NoDeferralWithSetupInProgress) {
   sync_prefs()->SetFirstSetupComplete();
   signin()->set_account_id(kTestUser);
   token_service()->UpdateCredentials(kTestUser, kTestToken);
+  controller()->set_setup_in_progress(true);
   controller()->TryStart();
-  const bool deferred_start =
-      !base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kSyncDisableDeferredStartup);
-  EXPECT_EQ(!deferred_start, started());
-  controller()->OnDataTypeRequestsSyncStartup(syncer::SESSIONS);
-  EXPECT_TRUE(started());
+  ExpectStarted();
+}
+
+// Test that start isn't deferred on the first start but is on restarts.
+TEST_F(StartupControllerTest, DeferralOnRestart) {
+  signin()->set_account_id(kTestUser);
+  token_service()->UpdateCredentials(kTestUser, kTestToken);
+  controller()->TryStart();
+  ExpectStarted();
+
   clear_started();
   controller()->Reset(syncer::UserTypes());
-  EXPECT_FALSE(started());
+  ExpectNotStarted();
   controller()->TryStart();
-  // Restart is not deferred.
-  EXPECT_TRUE(started());
+  ExpectStartDeferred();
 }
 
 // Test that setup-in-progress tracking is persistent across a Reset.
diff --git a/components/test/data/dom_distiller/video_article.html b/components/test/data/dom_distiller/video_article.html
index 7fac7ae..1ca2ce9 100644
--- a/components/test/data/dom_distiller/video_article.html
+++ b/components/test/data/dom_distiller/video_article.html
@@ -7,7 +7,7 @@
 
 <p>Lorem ipsum dolor sit amet, at alia aliquip vel. Quas inani labore an vel. Sed an nemore minimum accusata. Sint inermis tacimates est ex, ad movet iracundia mei, delicata iracundia laboramus ei eos. Illud principes complectitur te nec, ius alienum insolens ea, cu quo oratio omnesque.
 <video width="500" height="400" controls>
-  <source src="relative_video.mp4" type="video/mp4">
+  <source src="relative_video.webm" type="video/webm">
   <source src="http://www.google.com/absolute_video.ogg" type="video/ogg">
   <track src="relative_track_en.vtt" kind="chapters" srclang="en" label="English">
   <track src="http://www.google.com/absolute_track_fr.vtt" kind="chapters" srclang="fr" label="French">
diff --git a/components/test_runner/mock_credential_manager_client.cc b/components/test_runner/mock_credential_manager_client.cc
index 6b408fcc..bda8acd 100644
--- a/components/test_runner/mock_credential_manager_client.cc
+++ b/components/test_runner/mock_credential_manager_client.cc
@@ -9,8 +9,8 @@
 
 namespace test_runner {
 
-MockCredentialManagerClient::MockCredentialManagerClient() {
-}
+MockCredentialManagerClient::MockCredentialManagerClient()
+    : error_(blink::WebCredentialManagerNoError) {}
 
 MockCredentialManagerClient::~MockCredentialManagerClient() {
 }
@@ -20,6 +20,17 @@
   credential_.reset(credential);
 }
 
+void MockCredentialManagerClient::SetError(const std::string& error) {
+  if (error == "pending")
+    error_ = blink::WebCredentialManagerPendingRequestError;
+  if (error == "disabled")
+    error_ = blink::WebCredentialManagerDisabledError;
+  if (error == "unknown")
+    error_ = blink::WebCredentialManagerUnknownError;
+  if (error.empty())
+    error_ = blink::WebCredentialManagerNoError;
+}
+
 void MockCredentialManagerClient::dispatchStore(
     const blink::WebCredential&,
     blink::WebCredentialManagerClient::NotificationCallbacks* callbacks) {
@@ -38,7 +49,10 @@
     bool include_passwords,
     const blink::WebVector<blink::WebURL>& federations,
     RequestCallbacks* callbacks) {
-  callbacks->onSuccess(adoptWebPtr(credential_.release()));
+  if (error_ != blink::WebCredentialManagerNoError)
+    callbacks->onError(error_);
+  else
+    callbacks->onSuccess(adoptWebPtr(credential_.release()));
   delete callbacks;
 }
 
diff --git a/components/test_runner/mock_credential_manager_client.h b/components/test_runner/mock_credential_manager_client.h
index f2556d29..34c2974 100644
--- a/components/test_runner/mock_credential_manager_client.h
+++ b/components/test_runner/mock_credential_manager_client.h
@@ -8,6 +8,7 @@
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "third_party/WebKit/public/platform/WebCredentialManagerClient.h"
+#include "third_party/WebKit/public/platform/WebCredentialManagerError.h"
 #include "third_party/WebKit/public/platform/WebVector.h"
 
 namespace blink {
@@ -25,6 +26,7 @@
 
   // We take ownership of the |credential|.
   void SetResponse(blink::WebCredential* credential);
+  void SetError(const std::string& error);
 
   // blink::WebCredentialManager:
   void dispatchStore(const blink::WebCredential& credential,
@@ -37,6 +39,7 @@
 
  private:
   scoped_ptr<blink::WebCredential> credential_;
+  blink::WebCredentialManagerError error_;
 
   DISALLOW_COPY_AND_ASSIGN(MockCredentialManagerClient);
 };
diff --git a/components/test_runner/test_common.cc b/components/test_runner/test_common.cc
index ab02077..c488b111 100644
--- a/components/test_runner/test_common.cc
+++ b/components/test_runner/test_common.cc
@@ -29,7 +29,7 @@
 class MockBlinkPlatform : NON_EXPORTED_BASE(public blink::Platform) {
  public:
   MockBlinkPlatform() {
-    blink::initializeWithoutV8(this);
+    blink::Platform::initialize(this);
   }
   ~MockBlinkPlatform() override {}
 
diff --git a/components/test_runner/test_runner.cc b/components/test_runner/test_runner.cc
index b85bc61..2ccdc631 100644
--- a/components/test_runner/test_runner.cc
+++ b/components/test_runner/test_runner.cc
@@ -302,6 +302,7 @@
                                         const std::string& name,
                                         const std::string& avatar,
                                         const std::string& password);
+  void AddMockCredentialManagerError(const std::string& error);
   void AddWebPageOverlay();
   void RemoveWebPageOverlay();
   void LayoutAndPaintAsync();
@@ -579,6 +580,8 @@
                  &TestRunnerBindings::WasMockSpeechRecognitionAborted)
       .SetMethod("addMockCredentialManagerResponse",
                  &TestRunnerBindings::AddMockCredentialManagerResponse)
+      .SetMethod("addMockCredentialManagerError",
+                 &TestRunnerBindings::AddMockCredentialManagerError)
       .SetMethod("addWebPageOverlay", &TestRunnerBindings::AddWebPageOverlay)
       .SetMethod("removeWebPageOverlay",
                  &TestRunnerBindings::RemoveWebPageOverlay)
@@ -1448,6 +1451,12 @@
     runner_->AddMockCredentialManagerResponse(id, name, avatar, password);
 }
 
+void TestRunnerBindings::AddMockCredentialManagerError(
+    const std::string& error) {
+  if (runner_)
+    runner_->AddMockCredentialManagerError(error);
+}
+
 void TestRunnerBindings::AddWebPageOverlay() {
   if (runner_)
     runner_->AddWebPageOverlay();
@@ -2980,6 +2989,10 @@
                                 WebURL(GURL(avatar))));
 }
 
+void TestRunner::AddMockCredentialManagerError(const std::string& error) {
+  proxy_->GetCredentialManagerClientMock()->SetError(error);
+}
+
 void TestRunner::AddWebPageOverlay() {
   if (web_view_)
     web_view_->setPageOverlayColor(SK_ColorCYAN);
diff --git a/components/test_runner/test_runner.h b/components/test_runner/test_runner.h
index 1c359e7..fe42c0a3 100644
--- a/components/test_runner/test_runner.h
+++ b/components/test_runner/test_runner.h
@@ -599,6 +599,7 @@
                                         const std::string& name,
                                         const std::string& avatar,
                                         const std::string& password);
+  void AddMockCredentialManagerError(const std::string& error);
 
   // WebPageOverlay related functions. Permits the adding and removing of only
   // one opaque overlay.
diff --git a/components/test_runner/web_frame_test_proxy.h b/components/test_runner/web_frame_test_proxy.h
index 74a9d2e..363f5e37 100644
--- a/components/test_runner/web_frame_test_proxy.h
+++ b/components/test_runner/web_frame_test_proxy.h
@@ -27,29 +27,30 @@
   void set_base_proxy(WebTestProxyBase* proxy) { base_proxy_ = proxy; }
 
   // WebFrameClient implementation.
-  virtual blink::WebPlugin* createPlugin(blink::WebLocalFrame* frame,
-                                         const blink::WebPluginParams& params) {
+  blink::WebPlugin* createPlugin(
+      blink::WebLocalFrame* frame,
+      const blink::WebPluginParams& params) override {
     blink::WebPlugin* plugin = base_proxy_->CreatePlugin(frame, params);
     if (plugin)
       return plugin;
     return Base::createPlugin(frame, params);
   }
 
-  virtual blink::WebScreenOrientationClient* webScreenOrientationClient() {
+  blink::WebScreenOrientationClient* webScreenOrientationClient() override {
     return base_proxy_->GetScreenOrientationClientMock();
   }
 
-  virtual void didAddMessageToConsole(const blink::WebConsoleMessage& message,
-                                      const blink::WebString& source_name,
-                                      unsigned source_line,
-                                      const blink::WebString& stack_trace) {
+  void didAddMessageToConsole(const blink::WebConsoleMessage& message,
+                              const blink::WebString& source_name,
+                              unsigned source_line,
+                              const blink::WebString& stack_trace) override {
     base_proxy_->DidAddMessageToConsole(message, source_name, source_line);
     Base::didAddMessageToConsole(
         message, source_name, source_line, stack_trace);
   }
 
-  virtual bool canCreatePluginWithoutRenderer(
-      const blink::WebString& mime_type) {
+  bool canCreatePluginWithoutRenderer(
+      const blink::WebString& mime_type) override {
     using blink::WebString;
 
     const CR_DEFINE_STATIC_LOCAL(
@@ -57,33 +58,33 @@
     return mime_type.utf8().find(suffix.utf8()) != std::string::npos;
   }
 
-  virtual void loadURLExternally(const blink::WebURLRequest& request,
-                                 blink::WebNavigationPolicy policy,
-                                 const blink::WebString& suggested_name,
-                                 bool replaces_current_history_item) {
+  void loadURLExternally(const blink::WebURLRequest& request,
+                         blink::WebNavigationPolicy policy,
+                         const blink::WebString& suggested_name,
+                         bool replaces_current_history_item) override {
     base_proxy_->LoadURLExternally(request, policy, suggested_name,
                                    replaces_current_history_item);
     Base::loadURLExternally(request, policy, suggested_name,
                             replaces_current_history_item);
   }
 
-  virtual void didStartProvisionalLoad(blink::WebLocalFrame* frame,
-                                       double triggeringEventTime) {
+  void didStartProvisionalLoad(blink::WebLocalFrame* frame,
+                               double triggeringEventTime) override {
     base_proxy_->DidStartProvisionalLoad(frame);
     Base::didStartProvisionalLoad(
         frame, triggeringEventTime);
   }
 
-  virtual void didReceiveServerRedirectForProvisionalLoad(
-      blink::WebLocalFrame* frame) {
+  void didReceiveServerRedirectForProvisionalLoad(
+      blink::WebLocalFrame* frame) override {
     base_proxy_->DidReceiveServerRedirectForProvisionalLoad(frame);
     Base::didReceiveServerRedirectForProvisionalLoad(frame);
   }
 
-  virtual void didFailProvisionalLoad(
+  void didFailProvisionalLoad(
       blink::WebLocalFrame* frame,
       const blink::WebURLError& error,
-      blink::WebHistoryCommitType commit_type) {
+      blink::WebHistoryCommitType commit_type) override {
     // If the test finished, don't notify the embedder of the failed load,
     // as we already destroyed the document loader.
     if (base_proxy_->DidFailProvisionalLoad(frame, error, commit_type))
@@ -91,83 +92,83 @@
     Base::didFailProvisionalLoad(frame, error, commit_type);
   }
 
-  virtual void didCommitProvisionalLoad(
+  void didCommitProvisionalLoad(
       blink::WebLocalFrame* frame,
       const blink::WebHistoryItem& item,
-      blink::WebHistoryCommitType commit_type) {
+      blink::WebHistoryCommitType commit_type) override {
     base_proxy_->DidCommitProvisionalLoad(frame, item, commit_type);
     Base::didCommitProvisionalLoad(frame, item, commit_type);
   }
 
-  virtual void didReceiveTitle(blink::WebLocalFrame* frame,
-                               const blink::WebString& title,
-                               blink::WebTextDirection direction) {
+  void didReceiveTitle(blink::WebLocalFrame* frame,
+                       const blink::WebString& title,
+                       blink::WebTextDirection direction) override {
     base_proxy_->DidReceiveTitle(frame, title, direction);
     Base::didReceiveTitle(frame, title, direction);
   }
 
-  virtual void didChangeIcon(blink::WebLocalFrame* frame,
-                             blink::WebIconURL::Type icon_type) {
+  void didChangeIcon(blink::WebLocalFrame* frame,
+                     blink::WebIconURL::Type icon_type) override {
     base_proxy_->DidChangeIcon(frame, icon_type);
     Base::didChangeIcon(frame, icon_type);
   }
 
-  virtual void didFinishDocumentLoad(blink::WebLocalFrame* frame, bool empty) {
+  void didFinishDocumentLoad(blink::WebLocalFrame* frame, bool empty) override {
     base_proxy_->DidFinishDocumentLoad(frame);
     Base::didFinishDocumentLoad(frame, empty);
   }
 
-  virtual void didHandleOnloadEvents(blink::WebLocalFrame* frame) {
+  void didHandleOnloadEvents(blink::WebLocalFrame* frame) override {
     base_proxy_->DidHandleOnloadEvents(frame);
     Base::didHandleOnloadEvents(frame);
   }
 
-  virtual void didFailLoad(blink::WebLocalFrame* frame,
-                           const blink::WebURLError& error,
-                           blink::WebHistoryCommitType commit_type) {
+  void didFailLoad(blink::WebLocalFrame* frame,
+                   const blink::WebURLError& error,
+                   blink::WebHistoryCommitType commit_type) override {
     base_proxy_->DidFailLoad(frame, error, commit_type);
     Base::didFailLoad(frame, error, commit_type);
   }
 
-  virtual void didFinishLoad(blink::WebLocalFrame* frame) {
+  void didFinishLoad(blink::WebLocalFrame* frame) override {
     Base::didFinishLoad(frame);
     base_proxy_->DidFinishLoad(frame);
   }
 
-  virtual void didChangeSelection(bool is_selection_empty) {
+  void didChangeSelection(bool is_selection_empty) override {
     base_proxy_->DidChangeSelection(is_selection_empty);
     Base::didChangeSelection(is_selection_empty);
   }
 
-  virtual blink::WebColorChooser* createColorChooser(
+  blink::WebColorChooser* createColorChooser(
       blink::WebColorChooserClient* client,
       const blink::WebColor& initial_color,
-      const blink::WebVector<blink::WebColorSuggestion>& suggestions) {
+      const blink::WebVector<blink::WebColorSuggestion>& suggestions) override {
     return base_proxy_->CreateColorChooser(client, initial_color, suggestions);
   }
 
-  virtual void runModalAlertDialog(const blink::WebString& message) {
+  void runModalAlertDialog(const blink::WebString& message) override {
     base_proxy_->GetDelegate()->PrintMessage(std::string("ALERT: ") +
                                              message.utf8().data() + "\n");
   }
 
-  virtual bool runModalConfirmDialog(const blink::WebString& message) {
+  bool runModalConfirmDialog(const blink::WebString& message) override {
     base_proxy_->GetDelegate()->PrintMessage(std::string("CONFIRM: ") +
                                              message.utf8().data() + "\n");
     return true;
   }
 
-  virtual bool runModalPromptDialog(const blink::WebString& message,
-                                    const blink::WebString& default_value,
-                                    blink::WebString*) {
+  bool runModalPromptDialog(const blink::WebString& message,
+                            const blink::WebString& default_value,
+                            blink::WebString*) override {
     base_proxy_->GetDelegate()->PrintMessage(
         std::string("PROMPT: ") + message.utf8().data() + ", default text: " +
         default_value.utf8().data() + "\n");
     return true;
   }
 
-  virtual bool runModalBeforeUnloadDialog(bool is_reload,
-                                          const blink::WebString& message) {
+  bool runModalBeforeUnloadDialog(bool is_reload,
+                                  const blink::WebString& message) override {
     base_proxy_->GetDelegate()->PrintMessage(
         std::string("CONFIRM NAVIGATION: ") + message.utf8().data() + "\n");
     return !base_proxy_->GetInterfaces()
@@ -175,50 +176,50 @@
                 ->ShouldStayOnPageAfterHandlingBeforeUnload();
   }
 
-  virtual void showContextMenu(
-      const blink::WebContextMenuData& context_menu_data) {
+  void showContextMenu(
+      const blink::WebContextMenuData& context_menu_data) override {
     base_proxy_->ShowContextMenu(context_menu_data);
     Base::showContextMenu(context_menu_data);
   }
 
-  virtual void didDetectXSS(const blink::WebURL& insecure_url,
-                            bool did_block_entire_page) {
+  void didDetectXSS(const blink::WebURL& insecure_url,
+                    bool did_block_entire_page) override {
     // This is not implemented in RenderFrameImpl, so need to explicitly call
     // into the base proxy.
     base_proxy_->DidDetectXSS(insecure_url, did_block_entire_page);
     Base::didDetectXSS(insecure_url, did_block_entire_page);
   }
 
-  virtual void didDispatchPingLoader(const blink::WebURL& url) {
+  void didDispatchPingLoader(const blink::WebURL& url) override {
     // This is not implemented in RenderFrameImpl, so need to explicitly call
     // into the base proxy.
     base_proxy_->DidDispatchPingLoader(url);
     Base::didDispatchPingLoader(url);
   }
 
-  virtual void didCreateDataSource(blink::WebLocalFrame* frame,
-                                   blink::WebDataSource* ds) {
+  void didCreateDataSource(blink::WebLocalFrame* frame,
+                           blink::WebDataSource* ds) override {
     Base::didCreateDataSource(frame, ds);
   }
 
-  virtual void willSendRequest(blink::WebLocalFrame* frame,
-                               unsigned identifier,
-                               blink::WebURLRequest& request,
-                               const blink::WebURLResponse& redirect_response) {
+  void willSendRequest(
+      blink::WebLocalFrame* frame,
+      unsigned identifier,
+      blink::WebURLRequest& request,
+      const blink::WebURLResponse& redirect_response) override {
     Base::willSendRequest(frame, identifier, request, redirect_response);
     base_proxy_->WillSendRequest(frame, identifier, request, redirect_response);
   }
 
-  virtual void didReceiveResponse(unsigned identifier,
-                                  const blink::WebURLResponse& response) {
+  void didReceiveResponse(unsigned identifier,
+                          const blink::WebURLResponse& response) override {
     base_proxy_->DidReceiveResponse(identifier, response);
     Base::didReceiveResponse(identifier, response);
   }
 
-  virtual void didChangeResourcePriority(
-      unsigned identifier,
-      const blink::WebURLRequest::Priority& priority,
-      int intra_priority_value) {
+  void didChangeResourcePriority(unsigned identifier,
+                                 const blink::WebURLRequest::Priority& priority,
+                                 int intra_priority_value) override {
     // This is not implemented in RenderFrameImpl, so need to explicitly call
     // into the base proxy.
     base_proxy_->DidChangeResourcePriority(
@@ -227,13 +228,13 @@
         identifier, priority, intra_priority_value);
   }
 
-  virtual void didFinishResourceLoad(blink::WebLocalFrame* frame,
-                                     unsigned identifier) {
+  void didFinishResourceLoad(blink::WebLocalFrame* frame,
+                             unsigned identifier) override {
     base_proxy_->DidFinishResourceLoad(frame, identifier);
   }
 
-  virtual blink::WebNavigationPolicy decidePolicyForNavigation(
-      const blink::WebFrameClient::NavigationPolicyInfo& info) {
+  blink::WebNavigationPolicy decidePolicyForNavigation(
+      const blink::WebFrameClient::NavigationPolicyInfo& info) override {
     blink::WebNavigationPolicy policy = base_proxy_->DecidePolicyForNavigation(
         info);
     if (policy == blink::WebNavigationPolicyIgnore)
@@ -242,21 +243,21 @@
     return Base::decidePolicyForNavigation(info);
   }
 
-  virtual void willStartUsingPeerConnectionHandler(
-      blink::WebRTCPeerConnectionHandler* handler) {
+  void willStartUsingPeerConnectionHandler(
+      blink::WebRTCPeerConnectionHandler* handler) override {
     // RenderFrameImpl::willStartUsingPeerConnectionHandler can not be mocked.
     // See http://crbug/363285.
   }
 
-  virtual blink::WebUserMediaClient* userMediaClient() {
+  blink::WebUserMediaClient* userMediaClient() override {
     return base_proxy_->GetUserMediaClient();
   }
 
-  virtual bool willCheckAndDispatchMessageEvent(
+  bool willCheckAndDispatchMessageEvent(
       blink::WebLocalFrame* source_frame,
       blink::WebFrame* target_frame,
       blink::WebSecurityOrigin target,
-      blink::WebDOMMessageEvent event) {
+      blink::WebDOMMessageEvent event) override {
     if (base_proxy_->WillCheckAndDispatchMessageEvent(
             source_frame, target_frame, target, event))
       return true;
@@ -264,16 +265,16 @@
         source_frame, target_frame, target, event);
   }
 
-  virtual void postAccessibilityEvent(const blink::WebAXObject& object,
-                                      blink::WebAXEvent event) {
+  void postAccessibilityEvent(const blink::WebAXObject& object,
+                              blink::WebAXEvent event) override {
     base_proxy_->PostAccessibilityEvent(object, event);
     Base::postAccessibilityEvent(object, event);
   }
 
-  virtual void checkIfAudioSinkExistsAndIsAuthorized(
+  void checkIfAudioSinkExistsAndIsAuthorized(
       const blink::WebString& sink_id,
       const blink::WebSecurityOrigin& security_origin,
-      blink::WebSetSinkIdCallbacks* web_callbacks) {
+      blink::WebSetSinkIdCallbacks* web_callbacks) override {
     base_proxy_->CheckIfAudioSinkExistsAndIsAuthorized(sink_id, security_origin,
                                                        web_callbacks);
   }
diff --git a/components/test_runner/web_test_proxy.h b/components/test_runner/web_test_proxy.h
index 566ba317..7020773 100644
--- a/components/test_runner/web_test_proxy.h
+++ b/components/test_runner/web_test_proxy.h
@@ -306,79 +306,82 @@
   explicit WebTestProxy(Args... args) : Base(args...) {}
 
   // WebWidgetClient implementation.
-  virtual blink::WebScreenInfo screenInfo() {
+  blink::WebScreenInfo screenInfo() override {
     blink::WebScreenInfo info = Base::screenInfo();
     WebTestProxyBase::GetScreenOrientationForTesting(info);
     return info;
   }
 
   // WebViewClient implementation.
-  virtual void scheduleAnimation() { WebTestProxyBase::ScheduleAnimation(); }
-  virtual void startDragging(blink::WebLocalFrame* frame,
-                             const blink::WebDragData& data,
-                             blink::WebDragOperationsMask mask,
-                             const blink::WebImage& image,
-                             const blink::WebPoint& point) {
+  void scheduleAnimation() override { WebTestProxyBase::ScheduleAnimation(); }
+  void startDragging(blink::WebLocalFrame* frame,
+                     const blink::WebDragData& data,
+                     blink::WebDragOperationsMask mask,
+                     const blink::WebImage& image,
+                     const blink::WebPoint& point) override {
     WebTestProxyBase::StartDragging(frame, data, mask, image, point);
     // Don't forward this call to Base because we don't want to do a real
     // drag-and-drop.
   }
-  virtual void didChangeContents() {
+  void didChangeContents() override {
     WebTestProxyBase::DidChangeContents();
     Base::didChangeContents();
   }
-  virtual blink::WebView* createView(blink::WebLocalFrame* creator,
-                                     const blink::WebURLRequest& request,
-                                     const blink::WebWindowFeatures& features,
-                                     const blink::WebString& frame_name,
-                                     blink::WebNavigationPolicy policy,
-                                     bool suppress_opener) {
+  blink::WebView* createView(blink::WebLocalFrame* creator,
+                             const blink::WebURLRequest& request,
+                             const blink::WebWindowFeatures& features,
+                             const blink::WebString& frame_name,
+                             blink::WebNavigationPolicy policy,
+                             bool suppress_opener) override {
     if (!WebTestProxyBase::CreateView(
             creator, request, features, frame_name, policy, suppress_opener))
       return 0;
     return Base::createView(
         creator, request, features, frame_name, policy, suppress_opener);
   }
-  virtual void setStatusText(const blink::WebString& text) {
+  void setStatusText(const blink::WebString& text) override {
     WebTestProxyBase::SetStatusText(text);
     Base::setStatusText(text);
   }
-  virtual void printPage(blink::WebLocalFrame* frame) {
+  void printPage(blink::WebLocalFrame* frame) override {
     WebTestProxyBase::PrintPage(frame);
   }
-  virtual blink::WebSpeechRecognizer* speechRecognizer() {
+  blink::WebSpeechRecognizer* speechRecognizer() override {
     return WebTestProxyBase::GetSpeechRecognizer();
   }
-  virtual bool requestPointerLock() {
+  bool requestPointerLock() override {
     return WebTestProxyBase::RequestPointerLock();
   }
-  virtual void requestPointerUnlock() {
+  void requestPointerUnlock() override {
     WebTestProxyBase::RequestPointerUnlock();
   }
-  virtual bool isPointerLocked() { return WebTestProxyBase::IsPointerLocked(); }
-  virtual void didFocus() {
+  bool isPointerLocked() override {
+    return WebTestProxyBase::IsPointerLocked();
+  }
+  void didFocus() override {
     WebTestProxyBase::DidFocus();
     Base::didFocus();
   }
-  virtual void setToolTipText(const blink::WebString& text,
-                              blink::WebTextDirection hint) {
+  void setToolTipText(const blink::WebString& text,
+                      blink::WebTextDirection hint) override {
     WebTestProxyBase::SetToolTipText(text, hint);
     Base::setToolTipText(text, hint);
   }
-  virtual void resetInputMethod() { WebTestProxyBase::ResetInputMethod(); }
-  virtual bool runFileChooser(const blink::WebFileChooserParams& params,
-                              blink::WebFileChooserCompletion* completion) {
+  void resetInputMethod() override { WebTestProxyBase::ResetInputMethod(); }
+  bool runFileChooser(const blink::WebFileChooserParams& params,
+                      blink::WebFileChooserCompletion* completion) override {
     return WebTestProxyBase::RunFileChooser(params, completion);
   }
-  virtual void showValidationMessage(const blink::WebRect& anchor_in_root_view,
-                                     const blink::WebString& main_message,
-                                     blink::WebTextDirection main_message_hint,
-                                     const blink::WebString& sub_message,
-                                     blink::WebTextDirection sub_message_hint) {
+  void showValidationMessage(
+      const blink::WebRect& anchor_in_root_view,
+      const blink::WebString& main_message,
+      blink::WebTextDirection main_message_hint,
+      const blink::WebString& sub_message,
+      blink::WebTextDirection sub_message_hint) override {
     WebTestProxyBase::ShowValidationMessage(main_message, main_message_hint,
                                             sub_message, sub_message_hint);
   }
-  virtual blink::WebString acceptLanguages() {
+  blink::WebString acceptLanguages() override {
     return WebTestProxyBase::acceptLanguages();
   }
 
diff --git a/components/web_cache.gypi b/components/web_cache.gypi
index 53b0714..a48ce61 100644
--- a/components/web_cache.gypi
+++ b/components/web_cache.gypi
@@ -5,16 +5,14 @@
 {
   'targets': [
     {
-      'target_name': 'web_cache_common',
+      # GN version: //components/web_cache/public/interfaces
+      'target_name': 'web_cache_mojo_bindings',
       'type': 'static_library',
-      'dependencies': [
-        '<(DEPTH)/ipc/ipc.gyp:ipc',
-      ],
       'sources': [
-        'web_cache/common/web_cache_message_generator.cc',
-        'web_cache/common/web_cache_message_generator.h',
-        'web_cache/common/web_cache_messages.h',
+        # NOTE: Sources duplicated in //components/web_cache/public/interfaces/BUILD.gn
+        'web_cache/public/interfaces/web_cache.mojom',
       ],
+      'includes': [ '../mojo/mojom_bindings_generator.gypi'],
     },
     {
       'target_name': 'web_cache_browser',
@@ -23,7 +21,7 @@
         '<(DEPTH)/base/base.gyp:base',
         '<(DEPTH)/content/content.gyp:content_browser',
         '<(DEPTH)/third_party/WebKit/public/blink.gyp:blink',
-        'web_cache_common',
+        'web_cache_mojo_bindings',
       ],
       'sources': [
         'web_cache/browser/web_cache_manager.cc',
@@ -39,7 +37,7 @@
         '<(DEPTH)/base/base.gyp:base',
         '<(DEPTH)/content/content.gyp:content_renderer',
         '<(DEPTH)/third_party/WebKit/public/blink.gyp:blink',
-        'web_cache_common',
+        'web_cache_mojo_bindings',
       ],
       'sources': [
         'web_cache/renderer/web_cache_render_process_observer.cc',
diff --git a/components/web_cache/browser/BUILD.gn b/components/web_cache/browser/BUILD.gn
index 0afff18..e304cdb 100644
--- a/components/web_cache/browser/BUILD.gn
+++ b/components/web_cache/browser/BUILD.gn
@@ -13,8 +13,9 @@
   deps = [
     "//base",
     "//components/prefs",
-    "//components/web_cache/common",
+    "//components/web_cache/public/interfaces",
     "//content/public/browser",
+    "//content/public/common",
     "//third_party/WebKit/public:blink_headers",
   ]
 }
diff --git a/components/web_cache/browser/web_cache_manager.cc b/components/web_cache/browser/web_cache_manager.cc
index 66076e9..95816ba 100644
--- a/components/web_cache/browser/web_cache_manager.cc
+++ b/components/web_cache/browser/web_cache_manager.cc
@@ -19,10 +19,10 @@
 #include "base/time/time.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
-#include "components/web_cache/common/web_cache_messages.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_process_host.h"
+#include "content/public/common/service_registry.h"
 
 using base::Time;
 using base::TimeDelta;
@@ -90,6 +90,15 @@
   memset(stats, 0, sizeof(*stats));
   stats->access = Time::Now();
 
+  content::RenderProcessHost* host =
+      content::RenderProcessHost::FromID(renderer_id);
+  if (host) {
+    mojom::WebCachePtr service;
+    host->GetServiceRegistry()->ConnectToRemoteService(
+        mojo::GetProxy(&service));
+    web_cache_services_[renderer_id] = std::move(service);
+  }
+
   // Revise our allocation strategy to account for this new renderer.
   ReviseAllocationStrategyLater();
 }
@@ -100,6 +109,8 @@
   inactive_renderers_.erase(renderer_id);
   stats_.erase(renderer_id);
 
+  web_cache_services_.erase(renderer_id);
+
   // Reallocate the resources used by this renderer
   ReviseAllocationStrategyLater();
 }
@@ -329,9 +340,13 @@
                                      max_dead_capacity);
       }
 
-      host->Send(new WebCacheMsg_SetCacheCapacities(min_dead_capacity,
-                                                    max_dead_capacity,
-                                                    capacity));
+      // Find the WebCachePtr by renderer process id.
+      auto it = web_cache_services_.find(allocation->first);
+      DCHECK(it != web_cache_services_.end());
+      const mojom::WebCachePtr& service = it->second;
+      DCHECK(service);
+      service->SetCacheCapacities(min_dead_capacity, max_dead_capacity,
+                                  capacity);
     }
     ++allocation;
   }
@@ -350,8 +365,14 @@
   for (; iter != renderers.end(); ++iter) {
     content::RenderProcessHost* host =
         content::RenderProcessHost::FromID(*iter);
-    if (host)
-      host->Send(new WebCacheMsg_ClearCache(occasion == ON_NAVIGATION));
+    if (host) {
+      // Find the WebCachePtr by renderer process id.
+      auto it = web_cache_services_.find(*iter);
+      DCHECK(it != web_cache_services_.end());
+      const mojom::WebCachePtr& service = it->second;
+      DCHECK(service);
+      service->ClearCache(occasion == ON_NAVIGATION);
+    }
   }
 }
 
diff --git a/components/web_cache/browser/web_cache_manager.h b/components/web_cache/browser/web_cache_manager.h
index a0c19073..e93af65 100644
--- a/components/web_cache/browser/web_cache_manager.h
+++ b/components/web_cache/browser/web_cache_manager.h
@@ -19,6 +19,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
+#include "components/web_cache/public/interfaces/web_cache.mojom.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 
@@ -100,6 +101,7 @@
   void ClearCache();
 
   // Instantly clears renderer cache for a process.
+  // Must be called between Add(process_id) and Remove(process_id).
   void ClearCacheForProcess(int process_id);
 
   // Clears all in-memory caches when a tab is reloaded or the user navigates
@@ -140,6 +142,9 @@
   // each renderer is permitted to consume for its cache.
   typedef std::list<Allocation> AllocationStrategy;
 
+  // The key is the unique id of every render process host.
+  typedef std::map<int, mojom::WebCachePtr> WebCacheServicesMap;
+
   // This class is a singleton.  Do not instantiate directly.
   WebCacheManager();
   friend struct base::DefaultSingletonTraits<WebCacheManager>;
@@ -257,6 +262,9 @@
 
   content::NotificationRegistrar registrar_;
 
+  // Maps every renderer_id with its corresponding mojom::WebCachePtr.
+  WebCacheServicesMap web_cache_services_;
+
   base::WeakPtrFactory<WebCacheManager> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(WebCacheManager);
diff --git a/components/web_cache/common/BUILD.gn b/components/web_cache/common/BUILD.gn
deleted file mode 100644
index d4b7ac7..0000000
--- a/components/web_cache/common/BUILD.gn
+++ /dev/null
@@ -1,15 +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.
-
-source_set("common") {
-  sources = [
-    "web_cache_message_generator.cc",
-    "web_cache_message_generator.h",
-    "web_cache_messages.h",
-  ]
-
-  deps = [
-    "//ipc",
-  ]
-}
diff --git a/components/web_cache/common/DEPS b/components/web_cache/common/DEPS
deleted file mode 100644
index 1c40d98..0000000
--- a/components/web_cache/common/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
-  "+ipc",
-]
diff --git a/components/web_cache/common/OWNERS b/components/web_cache/common/OWNERS
deleted file mode 100644
index 5ecb406..0000000
--- a/components/web_cache/common/OWNERS
+++ /dev/null
@@ -1,11 +0,0 @@
-# Changes to IPC messages require a security review to avoid introducing
-# new sandbox escapes.
-per-file *_messages*.h=set noparent
-per-file *_messages*.h=dcheng@chromium.org
-per-file *_messages*.h=inferno@chromium.org
-per-file *_messages*.h=jln@chromium.org
-per-file *_messages*.h=jschuh@chromium.org
-per-file *_messages*.h=kenrb@chromium.org
-per-file *_messages*.h=nasko@chromium.org
-per-file *_messages*.h=tsepez@chromium.org
-per-file *_messages*.h=wfh@chromium.org
diff --git a/components/web_cache/common/web_cache_message_generator.cc b/components/web_cache/common/web_cache_message_generator.cc
deleted file mode 100644
index b4b2d26..0000000
--- a/components/web_cache/common/web_cache_message_generator.cc
+++ /dev/null
@@ -1,33 +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.
-
-// Get basic type definitions.
-#define IPC_MESSAGE_IMPL
-#include "components/web_cache/common/web_cache_message_generator.h"
-
-// Generate constructors.
-#include "ipc/struct_constructor_macros.h"
-#include "components/web_cache/common/web_cache_message_generator.h"
-
-// Generate destructors.
-#include "ipc/struct_destructor_macros.h"
-#include "components/web_cache/common/web_cache_message_generator.h"
-
-// Generate param traits write methods.
-#include "ipc/param_traits_write_macros.h"
-namespace IPC {
-#include "components/web_cache/common/web_cache_message_generator.h"
-}  // namespace IPC
-
-// Generate param traits read methods.
-#include "ipc/param_traits_read_macros.h"
-namespace IPC {
-#include "components/web_cache/common/web_cache_message_generator.h"
-}  // namespace IPC
-
-// Generate param traits log methods.
-#include "ipc/param_traits_log_macros.h"
-namespace IPC {
-#include "components/web_cache/common/web_cache_message_generator.h"
-}  // namespace IPC
diff --git a/components/web_cache/common/web_cache_message_generator.h b/components/web_cache/common/web_cache_message_generator.h
deleted file mode 100644
index d88eb86..0000000
--- a/components/web_cache/common/web_cache_message_generator.h
+++ /dev/null
@@ -1,7 +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.
-
-// Multiply-included file, no traditional include guard.
-
-#include "components/web_cache/common/web_cache_messages.h"
diff --git a/components/web_cache/common/web_cache_messages.h b/components/web_cache/common/web_cache_messages.h
deleted file mode 100644
index 44f48b6a..0000000
--- a/components/web_cache/common/web_cache_messages.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 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.
-
-// Multiply-included file, no traditional include guard.
-
-#include <stddef.h>
-
-#include "ipc/ipc_message_macros.h"
-#include "ipc/ipc_message_utils.h"
-
-#define IPC_MESSAGE_START WebCacheMsgStart
-
-//-----------------------------------------------------------------------------
-// RenderView messages
-// These are messages sent from the browser to the renderer process.
-
-// Tells the renderer to set its maximum cache size to the supplied value.
-IPC_MESSAGE_CONTROL3(WebCacheMsg_SetCacheCapacities,
-                     uint64_t /* min_dead_capacity */,
-                     uint64_t /* max_dead_capacity */,
-                     uint64_t /* capacity */)
-
-// Tells the renderer to clear the cache.
-IPC_MESSAGE_CONTROL1(WebCacheMsg_ClearCache,
-                     bool /* on_navigation */)
diff --git a/components/web_cache/public/interfaces/BUILD.gn b/components/web_cache/public/interfaces/BUILD.gn
new file mode 100644
index 0000000..4da8e47
--- /dev/null
+++ b/components/web_cache/public/interfaces/BUILD.gn
@@ -0,0 +1,11 @@
+# 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.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("interfaces") {
+  sources = [
+    "web_cache.mojom",
+  ]
+}
diff --git a/components/web_cache/public/interfaces/OWNERS b/components/web_cache/public/interfaces/OWNERS
new file mode 100644
index 0000000..e5c69a9
--- /dev/null
+++ b/components/web_cache/public/interfaces/OWNERS
@@ -0,0 +1,11 @@
+# Changes to mojom files require a security review to avoid introducing
+# new sandbox escapes.
+per-file *.mojom=set noparent
+per-file *.mojom=dcheng@chromium.org
+per-file *.mojom=inferno@chromium.org
+per-file *.mojom=jln@chromium.org
+per-file *.mojom=jschuh@chromium.org
+per-file *.mojom=kenrb@chromium.org
+per-file *.mojom=nasko@chromium.org
+per-file *.mojom=tsepez@chromium.org
+per-file *.mojom=wfh@chromium.org
diff --git a/components/web_cache/public/interfaces/web_cache.mojom b/components/web_cache/public/interfaces/web_cache.mojom
new file mode 100644
index 0000000..64af4fc3
--- /dev/null
+++ b/components/web_cache/public/interfaces/web_cache.mojom
@@ -0,0 +1,14 @@
+// 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 web_cache.mojom;
+
+interface WebCache {
+  // Set cache capacity values.
+  SetCacheCapacities(uint64 min_dead_capacity,
+                     uint64 max_dead_capacity,
+                     uint64 capacity);
+  // Clear cache.
+  ClearCache(bool on_navigation);
+};
diff --git a/components/web_cache/renderer/BUILD.gn b/components/web_cache/renderer/BUILD.gn
index a9e89683..c803783f 100644
--- a/components/web_cache/renderer/BUILD.gn
+++ b/components/web_cache/renderer/BUILD.gn
@@ -10,7 +10,8 @@
 
   deps = [
     "//base",
-    "//components/web_cache/common",
+    "//components/web_cache/public/interfaces",
+    "//content/public/common",
     "//content/public/renderer",
     "//third_party/WebKit/public:blink",
   ]
diff --git a/components/web_cache/renderer/DEPS b/components/web_cache/renderer/DEPS
index 100b3d3a..6df06f7 100644
--- a/components/web_cache/renderer/DEPS
+++ b/components/web_cache/renderer/DEPS
@@ -1,4 +1,6 @@
 include_rules = [
+  "+content/public/common",
   "+content/public/renderer",
+  "+mojo/public",
   "+third_party/WebKit/public/web",
 ]
diff --git a/components/web_cache/renderer/web_cache_render_process_observer.cc b/components/web_cache/renderer/web_cache_render_process_observer.cc
index 1d12253..f6ec4d5 100644
--- a/components/web_cache/renderer/web_cache_render_process_observer.cc
+++ b/components/web_cache/renderer/web_cache_render_process_observer.cc
@@ -6,12 +6,12 @@
 
 #include <limits>
 
+#include "base/bind.h"
 #include "base/numerics/safe_conversions.h"
-#include "components/web_cache/common/web_cache_messages.h"
+#include "content/public/common/service_registry.h"
+#include "content/public/renderer/render_thread.h"
 #include "third_party/WebKit/public/web/WebCache.h"
 
-using blink::WebCache;
-
 namespace web_cache {
 
 namespace {
@@ -24,35 +24,35 @@
     pending_cache_min_dead_capacity_(0),
     pending_cache_max_dead_capacity_(0),
     pending_cache_capacity_(kUnitializedCacheCapacity) {
+  content::ServiceRegistry* service_registry =
+      content::RenderThread::Get()->GetServiceRegistry();
+  if (service_registry) {
+    service_registry->AddService(base::Bind(
+        &WebCacheRenderProcessObserver::BindRequest, base::Unretained(this)));
+  }
 }
 
 WebCacheRenderProcessObserver::~WebCacheRenderProcessObserver() {
 }
 
+void WebCacheRenderProcessObserver::BindRequest(
+    mojo::InterfaceRequest<mojom::WebCache> web_cache_request) {
+  bindings_.AddBinding(this, std::move(web_cache_request));
+}
+
 void WebCacheRenderProcessObserver::ExecutePendingClearCache() {
   if (clear_cache_pending_ && webkit_initialized_) {
     clear_cache_pending_ = false;
-    WebCache::clear();
+    blink::WebCache::clear();
   }
 }
 
-bool WebCacheRenderProcessObserver::OnControlMessageReceived(
-    const IPC::Message& message) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(WebCacheRenderProcessObserver, message)
-    IPC_MESSAGE_HANDLER(WebCacheMsg_SetCacheCapacities, OnSetCacheCapacities)
-    IPC_MESSAGE_HANDLER(WebCacheMsg_ClearCache, OnClearCache)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return handled;
-}
-
 void WebCacheRenderProcessObserver::WebKitInitialized() {
   webkit_initialized_ = true;
   if (pending_cache_capacity_ != kUnitializedCacheCapacity) {
-    WebCache::setCapacities(pending_cache_min_dead_capacity_,
-                            pending_cache_max_dead_capacity_,
-                            pending_cache_capacity_);
+    blink::WebCache::setCapacities(pending_cache_min_dead_capacity_,
+                                   pending_cache_max_dead_capacity_,
+                                   pending_cache_capacity_);
   }
 }
 
@@ -60,13 +60,14 @@
   webkit_initialized_ = false;
 }
 
-void WebCacheRenderProcessObserver::OnSetCacheCapacities(
+void WebCacheRenderProcessObserver::SetCacheCapacities(
     uint64_t min_dead_capacity,
     uint64_t max_dead_capacity,
     uint64_t capacity64) {
   size_t min_dead_capacity2 = base::checked_cast<size_t>(min_dead_capacity);
   size_t max_dead_capacity2 = base::checked_cast<size_t>(max_dead_capacity);
   size_t capacity = base::checked_cast<size_t>(capacity64);
+
   if (!webkit_initialized_) {
     pending_cache_min_dead_capacity_ = min_dead_capacity2;
     pending_cache_max_dead_capacity_ = max_dead_capacity2;
@@ -74,15 +75,15 @@
     return;
   }
 
-  WebCache::setCapacities(
-      min_dead_capacity2, max_dead_capacity2, capacity);
+  blink::WebCache::setCapacities(min_dead_capacity2, max_dead_capacity2,
+                                 capacity);
 }
 
-void WebCacheRenderProcessObserver::OnClearCache(bool on_navigation) {
+void WebCacheRenderProcessObserver::ClearCache(bool on_navigation) {
   if (on_navigation || !webkit_initialized_)
     clear_cache_pending_ = true;
   else
-    WebCache::clear();
+    blink::WebCache::clear();
 }
 
 }  // namespace web_cache
diff --git a/components/web_cache/renderer/web_cache_render_process_observer.h b/components/web_cache/renderer/web_cache_render_process_observer.h
index 714ef231..d0b7d8c 100644
--- a/components/web_cache/renderer/web_cache_render_process_observer.h
+++ b/components/web_cache/renderer/web_cache_render_process_observer.h
@@ -10,33 +10,37 @@
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
+#include "components/web_cache/public/interfaces/web_cache.mojom.h"
 #include "content/public/renderer/render_process_observer.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
 
 namespace web_cache {
 
-// This class filters the incoming cache related control messages.
-class WebCacheRenderProcessObserver : public content::RenderProcessObserver {
+// This class implements the Mojo interface mojom::WebCache.
+class WebCacheRenderProcessObserver : public mojom::WebCache,
+                                      public content::RenderProcessObserver {
  public:
   WebCacheRenderProcessObserver();
   ~WebCacheRenderProcessObserver() override;
 
+  void BindRequest(mojo::InterfaceRequest<mojom::WebCache> web_cache_request);
+
   // Needs to be called by RenderViews in case of navigations to execute
   // any 'clear cache' commands that were delayed until the next navigation.
   void ExecutePendingClearCache();
 
  private:
   // RenderProcessObserver implementation.
-  bool OnControlMessageReceived(const IPC::Message& message) override;
   void WebKitInitialized() override;
   void OnRenderProcessShutdown() override;
 
-  // Message handlers.
-  void OnSetCacheCapacities(uint64_t min_dead_capacity,
-                            uint64_t max_dead_capacity,
-                            uint64_t capacity);
+  // mojom::WebCache methods:
+  void SetCacheCapacities(uint64_t min_dead_capacity,
+                          uint64_t max_dead_capacity,
+                          uint64_t capacity) override;
   // If |on_navigation| is true, the clearing is delayed until the next
   // navigation event.
-  void OnClearCache(bool on_navigation);
+  void ClearCache(bool on_navigation) override;
 
   // If true, the web cache shall be cleared before the next navigation event.
   bool clear_cache_pending_;
@@ -45,6 +49,8 @@
   size_t pending_cache_max_dead_capacity_;
   size_t pending_cache_capacity_;
 
+  mojo::BindingSet<mojom::WebCache> bindings_;
+
   DISALLOW_COPY_AND_ASSIGN(WebCacheRenderProcessObserver);
 };
 
diff --git a/components/wifi/wifi_service_mac.mm b/components/wifi/wifi_service_mac.mm
index 576d09f..ea2961c 100644
--- a/components/wifi/wifi_service_mac.mm
+++ b/components/wifi/wifi_service_mac.mm
@@ -101,9 +101,6 @@
   void NetworkPropertiesFromCWNetwork(const CWNetwork* network,
                                       NetworkProperties* properties) const;
 
-  // Converts |CWSecurityMode| into onc::wifi::k{WPA|WEP}* security constant.
-  std::string SecurityFromCWSecurityMode(CWSecurityMode security) const;
-
   // Returns onc::wifi::k{WPA|WEP}* security constant supported by the
   // |CWNetwork|.
   std::string SecurityFromCWNetwork(const CWNetwork* network) const;
@@ -521,46 +518,8 @@
       static_cast<CWChannelBand>([[network wlanChannel] channelBand]));
   properties->frequency_set.insert(properties->frequency);
 
-  // -[CWNetwork supportsSecurity:] is available from 10.7 SDK while
-  // -[CWNetwork securityMode] is deprecated and hidden as private since
-  // 10.9 SDK. The latter is kept for now to support running on 10.6. It
-  // should be removed when 10.6 support is dropped.
-  if ([network respondsToSelector:@selector(supportsSecurity:)]) {
-    properties->security = SecurityFromCWNetwork(network);
-  } else {
-    properties->security = SecurityFromCWSecurityMode(
-        static_cast<CWSecurityMode>([[network securityMode] intValue]));
-  }
-
-  // rssiValue property of CWNetwork is available from 10.7 SDK while
-  // -[CWNetwork rssi] is deprecated and hidden as private since 10.9 SDK.
-  // The latter is kept for now to support running on 10.6. It should be
-  // removed when 10.6 support is dropped.
-  if ([network respondsToSelector:@selector(rssiValue)])
-    properties->signal_strength = [network rssiValue];
-  else
-    properties->signal_strength = [[network rssi] intValue];
-}
-
-std::string WiFiServiceMac::SecurityFromCWSecurityMode(
-    CWSecurityMode security) const {
-  switch (security) {
-    case kCWSecurityModeWPA_Enterprise:
-    case kCWSecurityModeWPA2_Enterprise:
-      return onc::wifi::kWPA_EAP;
-    case kCWSecurityModeWPA_PSK:
-    case kCWSecurityModeWPA2_PSK:
-      return onc::wifi::kWPA_PSK;
-    case kCWSecurityModeWEP:
-      return onc::wifi::kWEP_PSK;
-    case kCWSecurityModeOpen:
-      return onc::wifi::kSecurityNone;
-    // TODO(mef): Figure out correct mapping.
-    case kCWSecurityModeWPS:
-    case kCWSecurityModeDynamicWEP:
-      return onc::wifi::kWPA_EAP;
-  }
-  return onc::wifi::kWPA_EAP;
+  properties->security = SecurityFromCWNetwork(network);
+  properties->signal_strength = [network rssiValue];
 }
 
 std::string WiFiServiceMac::SecurityFromCWNetwork(
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index ee3874a..b45b196 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -792,21 +792,48 @@
   return parent->GetRole() == ui::AX_ROLE_IFRAME_PRESENTATIONAL;
 }
 
+bool BrowserAccessibility::IsClickable() const {
+  switch (GetRole()) {
+    case ui::AX_ROLE_BUTTON:
+    case ui::AX_ROLE_CHECK_BOX:
+    case ui::AX_ROLE_COLOR_WELL:
+    case ui::AX_ROLE_DISCLOSURE_TRIANGLE:
+    case ui::AX_ROLE_IMAGE_MAP_LINK:
+    case ui::AX_ROLE_LINK:
+    case ui::AX_ROLE_LIST_BOX_OPTION:
+    case ui::AX_ROLE_MENU_BUTTON:
+    case ui::AX_ROLE_MENU_ITEM:
+    case ui::AX_ROLE_MENU_ITEM_CHECK_BOX:
+    case ui::AX_ROLE_MENU_ITEM_RADIO:
+    case ui::AX_ROLE_MENU_LIST_OPTION:
+    case ui::AX_ROLE_MENU_LIST_POPUP:
+    case ui::AX_ROLE_POP_UP_BUTTON:
+    case ui::AX_ROLE_RADIO_BUTTON:
+    case ui::AX_ROLE_SWITCH:
+    case ui::AX_ROLE_TAB:
+    case ui::AX_ROLE_TOGGLE_BUTTON:
+      return true;
+    default:
+      return false;
+  }
+}
+
 bool BrowserAccessibility::IsControl() const {
   switch (GetRole()) {
     case ui::AX_ROLE_BUTTON:
-    case ui::AX_ROLE_BUTTON_DROP_DOWN:
     case ui::AX_ROLE_CHECK_BOX:
     case ui::AX_ROLE_COLOR_WELL:
     case ui::AX_ROLE_COMBO_BOX:
     case ui::AX_ROLE_DISCLOSURE_TRIANGLE:
     case ui::AX_ROLE_LIST_BOX:
+    case ui::AX_ROLE_MENU:
     case ui::AX_ROLE_MENU_BAR:
     case ui::AX_ROLE_MENU_BUTTON:
     case ui::AX_ROLE_MENU_ITEM:
     case ui::AX_ROLE_MENU_ITEM_CHECK_BOX:
     case ui::AX_ROLE_MENU_ITEM_RADIO:
-    case ui::AX_ROLE_MENU:
+    case ui::AX_ROLE_MENU_LIST_OPTION:
+    case ui::AX_ROLE_MENU_LIST_POPUP:
     case ui::AX_ROLE_POP_UP_BUTTON:
     case ui::AX_ROLE_RADIO_BUTTON:
     case ui::AX_ROLE_SCROLL_BAR:
@@ -824,6 +851,22 @@
   }
 }
 
+bool BrowserAccessibility::IsMenuRelated() const {
+  switch (GetRole()) {
+    case ui::AX_ROLE_MENU:
+    case ui::AX_ROLE_MENU_BAR:
+    case ui::AX_ROLE_MENU_BUTTON:
+    case ui::AX_ROLE_MENU_ITEM:
+    case ui::AX_ROLE_MENU_ITEM_CHECK_BOX:
+    case ui::AX_ROLE_MENU_ITEM_RADIO:
+    case ui::AX_ROLE_MENU_LIST_OPTION:
+    case ui::AX_ROLE_MENU_LIST_POPUP:
+      return true;
+    default:
+      return false;
+  }
+}
+
 bool BrowserAccessibility::IsSimpleTextControl() const {
   // Time fields, color wells and spinner buttons might also use text fields as
   // constituent parts, but they are not considered text fields as a whole.
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h
index b2f14f9..ff17bc5 100644
--- a/content/browser/accessibility/browser_accessibility.h
+++ b/content/browser/accessibility/browser_accessibility.h
@@ -302,7 +302,10 @@
   // True if this is a web area, and its grandparent is a presentational iframe.
   bool IsWebAreaForPresentationalIframe() const;
 
+  virtual bool IsClickable() const;
   bool IsControl() const;
+  bool IsMenuRelated() const;
+  bool IsRangeControl() const;
   bool IsSimpleTextControl() const;
   // Indicates if this object is at the root of a rich edit text control.
   bool IsRichTextControl() const;
diff --git a/content/browser/accessibility/browser_accessibility_android.cc b/content/browser/accessibility/browser_accessibility_android.cc
index 09daafe..8257c74 100644
--- a/content/browser/accessibility/browser_accessibility_android.cc
+++ b/content/browser/accessibility/browser_accessibility_android.cc
@@ -135,6 +135,8 @@
   if (!PlatformIsLeaf())
     return false;
 
+  // We are very aggressive about returning true with IsClickable on Android
+  // because there is no way to know for sure what might have a click handler.
   return IsFocusable() || !GetText().empty();
 }
 
diff --git a/content/browser/accessibility/browser_accessibility_android.h b/content/browser/accessibility/browser_accessibility_android.h
index e5c60d77..56a5b63 100644
--- a/content/browser/accessibility/browser_accessibility_android.h
+++ b/content/browser/accessibility/browser_accessibility_android.h
@@ -25,7 +25,7 @@
 
   bool IsCheckable() const;
   bool IsChecked() const;
-  bool IsClickable() const;
+  bool IsClickable() const override;
   bool IsCollection() const;
   bool IsCollectionItem() const;
   bool IsContentInvalid() const;
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.h b/content/browser/accessibility/browser_accessibility_cocoa.h
index eaa99c5..99237345 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.h
+++ b/content/browser/accessibility/browser_accessibility_cocoa.h
@@ -22,8 +22,8 @@
 }
 
 // This creates a cocoa browser accessibility object around
-// the cross platform BrowserAccessibility object, which can't be null.
-- (id)initWithObject:(content::BrowserAccessibility*)accessibility;
+// the cross platform BrowserAccessibility object, which can't be nullptr.
+- (instancetype)initWithObject:(content::BrowserAccessibility*)accessibility;
 
 // Clear this object's pointer to the wrapped BrowserAccessibility object
 // because the wrapped object has been deleted, but this object may
@@ -39,7 +39,7 @@
 
 // Convenience method to determine if this object should expose its
 // accessible name in AXValue (as opposed to AXTitle/AXDescription).
-- (bool)shouldExposeNameInAXValue;
+- (BOOL)shouldExposeNameInAXValue;
 
 // Convenience method to get the BrowserAccessibilityDelegate from
 // the manager.
@@ -48,6 +48,9 @@
 // Get the BrowserAccessibility that this object wraps.
 - (content::BrowserAccessibility*)browserAccessibility;
 
+// Determines if this object is alive, i.e. it hasn't been detached.
+- (BOOL)instanceActive;
+
 // Convert the local objet's origin to a global point.
 - (NSPoint)pointInScreen:(NSPoint)origin
                     size:(NSSize)size;
@@ -61,16 +64,16 @@
 // Returns the requested text range from this object's value attribute.
 - (NSString*)valueForRange:(NSRange)range;
 
-// Internally-used method.
+// Internally-used property.
 @property(nonatomic, readonly) NSPoint origin;
 
-// Children is an array of BrowserAccessibility objects, representing
-// the accessibility children of this object.
 @property(nonatomic, readonly) NSString* accessKey;
 @property(nonatomic, readonly) NSNumber* ariaAtomic;
 @property(nonatomic, readonly) NSNumber* ariaBusy;
 @property(nonatomic, readonly) NSString* ariaLive;
+@property(nonatomic, readonly) NSNumber* ariaPosInSet;
 @property(nonatomic, readonly) NSString* ariaRelevant;
+@property(nonatomic, readonly) NSNumber* ariaSetSize;
 @property(nonatomic, readonly) NSArray* children;
 @property(nonatomic, readonly) NSArray* columns;
 @property(nonatomic, readonly) NSArray* columnHeaders;
@@ -87,13 +90,17 @@
 @property(nonatomic, readonly) id endTextMarker;
 @property(nonatomic, readonly) NSNumber* expanded;
 @property(nonatomic, readonly) NSNumber* focused;
+@property(nonatomic, readonly) NSNumber* grabbed;
+@property(nonatomic, readonly) id header;
 @property(nonatomic, readonly) NSString* help;
 // isIgnored returns whether or not the accessibility object
 // should be ignored by the accessibility hierarchy.
 @property(nonatomic, readonly, getter=isIgnored) BOOL ignored;
 // Index of a row, column, or tree item.
 @property(nonatomic, readonly) NSNumber* index;
+@property(nonatomic, readonly) NSNumber* insertionPointLineNumber;
 @property(nonatomic, readonly) NSString* invalid;
+@property(nonatomic, readonly) NSNumber* isMultiSelectable;
 @property(nonatomic, readonly) NSString* placeholderValue;
 @property(nonatomic, readonly) NSNumber* loaded;
 @property(nonatomic, readonly) NSNumber* loadingProgress;
@@ -111,9 +118,14 @@
 @property(nonatomic, readonly) NSArray* rowHeaders;
 @property(nonatomic, readonly) NSValue* rowIndexRange;
 @property(nonatomic, readonly) NSArray* rows;
+// The object is selected as a whole.
+@property(nonatomic, readonly) NSNumber* selected;
 @property(nonatomic, readonly) NSArray* selectedChildren;
+@property(nonatomic, readonly) NSString* selectedText;
+@property(nonatomic, readonly) NSValue* selectedTextRange;
 @property(nonatomic, readonly) id selectedTextMarkerRange;
 @property(nonatomic, readonly) NSValue* size;
+@property(nonatomic, readonly) NSString* sortDirection;
 // Returns a text marker that points to the first character in the document that
 // can be selected with Voiceover.
 @property(nonatomic, readonly) id startTextMarker;
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
index 80af6fd3..0574c25 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -39,8 +39,19 @@
 namespace {
 
 // Private WebKit accessibility attributes.
+NSString* const NSAccessibilityARIAAtomicAttribute = @"AXARIAAtomic";
+NSString* const NSAccessibilityARIABusyAttribute = @"AXARIABusy";
+NSString* const NSAccessibilityARIALiveAttribute = @"AXARIALive";
+NSString* const NSAccessibilityARIAPosInSetAttribute = @"AXARIAPosInSet";
+NSString* const NSAccessibilityARIARelevantAttribute = @"AXARIARelevant";
+NSString* const NSAccessibilityARIASetSizeAttribute = @"AXARIASetSize";
 NSString* const NSAccessibilityAccessKeyAttribute = @"AXAccessKey";
+NSString* const NSAccessibilityDropEffectsAttribute = @"AXDropEffects";
+NSString* const NSAccessibilityGrabbedAttribute = @"AXGrabbed";
 NSString* const NSAccessibilityInvalidAttribute = @"AXInvalid";
+NSString* const NSAccessibilityIsMultiSelectableAttribute =
+    @"AXIsMultiSelectable";
+NSString* const NSAccessibilityLoadingProgressAttribute = @"AXLoadingProgress";
 NSString* const NSAccessibilityRequiredAttribute = @"AXRequired";
 NSString* const
     NSAccessibilityUIElementCountForSearchPredicateParameterizedAttribute =
@@ -71,6 +82,9 @@
 NSString* const NSAccessibilitySelectTextWithCriteriaParameterizedAttribute =
     @"AXSelectTextWithCriteria";
 
+// Actions.
+NSString* const NSAccessibilityScrollToVisibleAction = @"AXScrollToVisible";
+
 // A mapping from an accessibility attribute to its method name.
 NSDictionary* attributeToMethodNameMap = nil;
 
@@ -395,7 +409,7 @@
   return true;
 }
 
-} // namespace
+}  // namespace
 
 @implementation BrowserAccessibilityCocoa
 
@@ -404,6 +418,12 @@
     NSString* attribute;
     NSString* methodName;
   } attributeToMethodNameContainer[] = {
+      {NSAccessibilityARIAAtomicAttribute, @"ariaAtomic"},
+      {NSAccessibilityARIABusyAttribute, @"ariaBusy"},
+      {NSAccessibilityARIALiveAttribute, @"ariaLive"},
+      {NSAccessibilityARIAPosInSetAttribute, @"ariaPosInSet"},
+      {NSAccessibilityARIARelevantAttribute, @"ariaRelevant"},
+      {NSAccessibilityARIASetSizeAttribute, @"ariaSetSize"},
       {NSAccessibilityAccessKeyAttribute, @"accessKey"},
       {NSAccessibilityChildrenAttribute, @"children"},
       {NSAccessibilityColumnsAttribute, @"columns"},
@@ -415,15 +435,21 @@
       {NSAccessibilityDisclosedByRowAttribute, @"disclosedByRow"},
       {NSAccessibilityDisclosureLevelAttribute, @"disclosureLevel"},
       {NSAccessibilityDisclosedRowsAttribute, @"disclosedRows"},
+      {NSAccessibilityDropEffectsAttribute, @"dropEffects"},
       {NSAccessibilityEnabledAttribute, @"enabled"},
       {NSAccessibilityEndTextMarkerAttribute, @"endTextMarker"},
       {NSAccessibilityExpandedAttribute, @"expanded"},
       {NSAccessibilityFocusedAttribute, @"focused"},
+      {NSAccessibilityGrabbedAttribute, @"grabbed"},
       {NSAccessibilityHeaderAttribute, @"header"},
       {NSAccessibilityHelpAttribute, @"help"},
       {NSAccessibilityIndexAttribute, @"index"},
+      {NSAccessibilityInsertionPointLineNumberAttribute,
+       @"insertionPointLineNumber"},
       {NSAccessibilityInvalidAttribute, @"invalid"},
+      {NSAccessibilityIsMultiSelectableAttribute, @"isMultiSelectable"},
       {NSAccessibilityLinkedUIElementsAttribute, @"linkedUIElements"},
+      {NSAccessibilityLoadingProgressAttribute, @"loadingProgress"},
       {NSAccessibilityMaxValueAttribute, @"maxValue"},
       {NSAccessibilityMinValueAttribute, @"minValue"},
       {NSAccessibilityNumberOfCharactersAttribute, @"numberOfCharacters"},
@@ -440,7 +466,10 @@
       // TODO(aboxhall): expose
       // NSAccessibilityServesAsTitleForUIElementsAttribute
       {NSAccessibilityStartTextMarkerAttribute, @"startTextMarker"},
+      {NSAccessibilitySelectedAttribute, @"selected"},
       {NSAccessibilitySelectedChildrenAttribute, @"selectedChildren"},
+      {NSAccessibilitySelectedTextAttribute, @"selectedText"},
+      {NSAccessibilitySelectedTextRangeAttribute, @"selectedTextRange"},
       {NSAccessibilitySelectedTextMarkerRangeAttribute,
        @"selectedTextMarkerRange"},
       {NSAccessibilitySizeAttribute, @"size"},
@@ -460,16 +489,7 @@
       {NSAccessibilityVisibleRowsAttribute, @"visibleRows"},
       {NSAccessibilityVisitedAttribute, @"visited"},
       {NSAccessibilityWindowAttribute, @"window"},
-      {@"AXARIAAtomic", @"ariaAtomic"},
-      {@"AXARIABusy", @"ariaBusy"},
-      {@"AXARIALive", @"ariaLive"},
-      {@"AXARIASetSize", @"ariaSetSize"},
-      {@"AXARIAPosInSet", @"ariaPosInSet"},
-      {@"AXARIARelevant", @"ariaRelevant"},
-      {@"AXDropEffects", @"dropEffects"},
-      {@"AXGrabbed", @"grabbed"},
       {@"AXLoaded", @"loaded"},
-      {@"AXLoadingProgress", @"loadingProgress"},
   };
 
   NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];
@@ -483,51 +503,64 @@
   dict = nil;
 }
 
-- (id)initWithObject:(BrowserAccessibility*)accessibility {
+- (instancetype)initWithObject:(BrowserAccessibility*)accessibility {
   if ((self = [super init]))
     browserAccessibility_ = accessibility;
   return self;
 }
 
 - (void)detach {
-  if (browserAccessibility_) {
+  if (browserAccessibility_)
     NSAccessibilityUnregisterUniqueIdForUIElement(self);
-    browserAccessibility_ = NULL;
-  }
+  browserAccessibility_ = nullptr;
 }
 
 - (NSString*)accessKey {
+  if (![self instanceActive])
+    return nil;
   return NSStringForStringAttribute(
       browserAccessibility_, ui::AX_ATTR_ACCESS_KEY);
 }
 
 - (NSNumber*)ariaAtomic {
+  if (![self instanceActive])
+    return nil;
   bool boolValue = browserAccessibility_->GetBoolAttribute(
       ui::AX_ATTR_LIVE_ATOMIC);
   return [NSNumber numberWithBool:boolValue];
 }
 
 - (NSNumber*)ariaBusy {
+  if (![self instanceActive])
+    return nil;
   return [NSNumber numberWithBool:
       GetState(browserAccessibility_, ui::AX_STATE_BUSY)];
 }
 
 - (NSString*)ariaLive {
+  if (![self instanceActive])
+    return nil;
   return NSStringForStringAttribute(
       browserAccessibility_, ui::AX_ATTR_LIVE_STATUS);
 }
 
-- (NSString*)ariaRelevant {
-  return NSStringForStringAttribute(
-      browserAccessibility_, ui::AX_ATTR_LIVE_RELEVANT);
-}
-
 - (NSNumber*)ariaPosInSet {
+  if (![self instanceActive])
+    return nil;
   return [NSNumber numberWithInt:
       browserAccessibility_->GetIntAttribute(ui::AX_ATTR_POS_IN_SET)];
 }
 
+- (NSString*)ariaRelevant {
+  if (![self instanceActive])
+    return nil;
+  return NSStringForStringAttribute(browserAccessibility_,
+                                    ui::AX_ATTR_LIVE_RELEVANT);
+}
+
 - (NSNumber*)ariaSetSize {
+  if (![self instanceActive])
+    return nil;
   return [NSNumber numberWithInt:
       browserAccessibility_->GetIntAttribute(ui::AX_ATTR_SET_SIZE)];
 }
@@ -535,6 +568,8 @@
 // Returns an array of BrowserAccessibilityCocoa objects, representing the
 // accessibility children of this object.
 - (NSArray*)children {
+  if (![self instanceActive])
+    return nil;
   if (!children_) {
     uint32_t childCount = browserAccessibility_->PlatformChildCount();
     children_.reset([[NSMutableArray alloc] initWithCapacity:childCount]);
@@ -570,6 +605,8 @@
 }
 
 - (void)childrenChanged {
+  if (![self instanceActive])
+    return;
   if (![self isIgnored]) {
     children_.reset();
   } else {
@@ -579,6 +616,8 @@
 }
 
 - (NSArray*)columnHeaders {
+  if (![self instanceActive])
+    return nil;
   if ([self internalRole] != ui::AX_ROLE_TABLE &&
       [self internalRole] != ui::AX_ROLE_GRID) {
     return nil;
@@ -598,6 +637,8 @@
 }
 
 - (NSValue*)columnIndexRange {
+  if (![self instanceActive])
+    return nil;
   if (!browserAccessibility_->IsCellOrTableHeaderRole())
     return nil;
 
@@ -613,6 +654,8 @@
 }
 
 - (NSArray*)columns {
+  if (![self instanceActive])
+    return nil;
   NSMutableArray* ret = [[[NSMutableArray alloc] init] autorelease];
   for (BrowserAccessibilityCocoa* child in [self children]) {
     if ([[child role] isEqualToString:NSAccessibilityColumnRole])
@@ -622,6 +665,9 @@
 }
 
 - (NSString*)description {
+  if (![self instanceActive])
+    return nil;
+
   // Mac OS X wants static text exposed in AXValue.
   if ([self shouldExposeNameInAXValue])
     return @"";
@@ -694,6 +740,8 @@
 }
 
 - (NSNumber*)disclosing {
+  if (![self instanceActive])
+    return nil;
   if ([self internalRole] == ui::AX_ROLE_TREE_ITEM) {
     return [NSNumber numberWithBool:
         GetState(browserAccessibility_, ui::AX_STATE_EXPANDED)];
@@ -703,12 +751,17 @@
 }
 
 - (id)disclosedByRow {
+  if (![self instanceActive])
+    return nil;
+
   // The row that contains this row.
   // It should be the same as the first parent that is a treeitem.
   return nil;
 }
 
 - (NSNumber*)disclosureLevel {
+  if (![self instanceActive])
+    return nil;
   ui::AXRole role = [self internalRole];
   if (role == ui::AX_ROLE_ROW ||
       role == ui::AX_ROLE_TREE_ITEM) {
@@ -724,11 +777,17 @@
 }
 
 - (id)disclosedRows {
+  if (![self instanceActive])
+    return nil;
+
   // The rows that are considered inside this row.
   return nil;
 }
 
 - (NSString*)dropEffects {
+  if (![self instanceActive])
+    return nil;
+
   std::string dropEffects;
   if (browserAccessibility_->GetHtmlAttribute("aria-dropeffect", &dropEffects))
     return base::SysUTF8ToNSString(dropEffects);
@@ -737,6 +796,8 @@
 }
 
 - (NSNumber*)enabled {
+  if (![self instanceActive])
+    return nil;
   return [NSNumber numberWithBool:
       GetState(browserAccessibility_, ui::AX_STATE_ENABLED)];
 }
@@ -744,7 +805,7 @@
 // Returns a text marker that points to the last character in the document that
 // can be selected with VoiceOver.
 - (id)endTextMarker {
-  if (!browserAccessibility_ || !browserAccessibility_->manager())
+  if (![self instanceActive])
     return nil;
 
   const BrowserAccessibility* root =
@@ -770,11 +831,15 @@
 }
 
 - (NSNumber*)expanded {
+  if (![self instanceActive])
+    return nil;
   return [NSNumber numberWithBool:
       GetState(browserAccessibility_, ui::AX_STATE_EXPANDED)];
 }
 
 - (NSNumber*)focused {
+  if (![self instanceActive])
+    return nil;
   BrowserAccessibilityManager* manager = browserAccessibility_->manager();
   NSNumber* ret = [NSNumber numberWithBool:
       manager->GetFocus() == browserAccessibility_];
@@ -782,6 +847,8 @@
 }
 
 - (NSNumber*)grabbed {
+  if (![self instanceActive])
+    return nil;
   std::string grabbed;
   if (browserAccessibility_->GetHtmlAttribute("aria-grabbed", &grabbed) &&
       grabbed == "true")
@@ -791,6 +858,8 @@
 }
 
 - (id)header {
+  if (![self instanceActive])
+    return nil;
   int headerElementId = -1;
   if ([self internalRole] == ui::AX_ROLE_TABLE ||
       [self internalRole] == ui::AX_ROLE_GRID) {
@@ -814,11 +883,15 @@
 }
 
 - (NSString*)help {
+  if (![self instanceActive])
+    return nil;
   return NSStringForStringAttribute(
       browserAccessibility_, ui::AX_ATTR_DESCRIPTION);
 }
 
 - (NSNumber*)index {
+  if (![self instanceActive])
+    return nil;
   if ([self internalRole] == ui::AX_ROLE_COLUMN) {
     int columnIndex = browserAccessibility_->GetIntAttribute(
           ui::AX_ATTR_TABLE_COLUMN_INDEX);
@@ -832,13 +905,43 @@
   return nil;
 }
 
+- (NSNumber*)insertionPointLineNumber {
+  if (![self instanceActive])
+    return nil;
+
+  // TODO(nektar): Deprecate sel_start and sel_end attributes.
+  int selStart, selEnd;
+  if (!browserAccessibility_->GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START,
+                                              &selStart) ||
+      !browserAccessibility_->GetIntAttribute(ui::AX_ATTR_TEXT_SEL_END,
+                                              &selEnd)) {
+    return nil;
+  }
+
+  if (selStart > selEnd)
+    std::swap(selStart, selEnd);
+
+  const std::vector<int32_t>& line_breaks =
+      browserAccessibility_->GetIntListAttribute(ui::AX_ATTR_LINE_BREAKS);
+  for (int i = 0; i < static_cast<int>(line_breaks.size()); ++i) {
+    if (line_breaks[i] > selStart)
+      return [NSNumber numberWithInt:i];
+  }
+
+  return [NSNumber numberWithInt:static_cast<int>(line_breaks.size())];
+}
+
 // Returns whether or not this node should be ignored in the
 // accessibility tree.
 - (BOOL)isIgnored {
+  if (![self instanceActive])
+    return YES;
   return [[self role] isEqualToString:NSAccessibilityUnknownRole];
 }
 
 - (NSString*)invalid {
+  if (![self instanceActive])
+    return nil;
   int invalidState;
   if (!browserAccessibility_->GetIntAttribute(
       ui::AX_ATTR_INVALID_STATE, &invalidState))
@@ -870,7 +973,16 @@
   return @"false";
 }
 
+- (NSNumber*)isMultiSelectable {
+  if (![self instanceActive])
+    return nil;
+  return [NSNumber numberWithBool:GetState(browserAccessibility_,
+                                           ui::AX_STATE_MULTISELECTABLE)];
+}
+
 - (NSString*)placeholderValue {
+  if (![self instanceActive])
+    return nil;
   ui::AXNameFrom nameFrom = static_cast<ui::AXNameFrom>(
       browserAccessibility_->GetIntAttribute(ui::AX_ATTR_NAME_FROM));
   if (nameFrom == ui::AX_NAME_FROM_PLACEHOLDER) {
@@ -889,6 +1001,7 @@
       browserAccessibility_, ui::AX_ATTR_PLACEHOLDER);
 }
 
+// private
 - (void)addLinkedUIElementsFromAttribute:(ui::AXIntListAttribute)attribute
                                    addTo:(NSMutableArray*)outArray {
   const std::vector<int32_t>& attributeValues =
@@ -901,6 +1014,7 @@
   }
 }
 
+// private
 - (NSArray*)linkedUIElements {
   NSMutableArray* ret = [[[NSMutableArray alloc] init] autorelease];
   [self addLinkedUIElementsFromAttribute:ui::AX_ATTR_CONTROLS_IDS addTo:ret];
@@ -911,28 +1025,38 @@
 }
 
 - (NSNumber*)loaded {
+  if (![self instanceActive])
+    return nil;
   return [NSNumber numberWithBool:YES];
 }
 
 - (NSNumber*)loadingProgress {
+  if (![self instanceActive])
+    return nil;
   BrowserAccessibilityManager* manager = browserAccessibility_->manager();
   float floatValue = manager->GetTreeData().loading_progress;
   return [NSNumber numberWithFloat:floatValue];
 }
 
 - (NSNumber*)maxValue {
+  if (![self instanceActive])
+    return nil;
   float floatValue = browserAccessibility_->GetFloatAttribute(
       ui::AX_ATTR_MAX_VALUE_FOR_RANGE);
   return [NSNumber numberWithFloat:floatValue];
 }
 
 - (NSNumber*)minValue {
+  if (![self instanceActive])
+    return nil;
   float floatValue = browserAccessibility_->GetFloatAttribute(
       ui::AX_ATTR_MIN_VALUE_FOR_RANGE);
   return [NSNumber numberWithFloat:floatValue];
 }
 
 - (NSString*)orientation {
+  if (![self instanceActive])
+    return nil;
   if (GetState(browserAccessibility_, ui::AX_STATE_VERTICAL))
     return NSAccessibilityVerticalOrientationValue;
   else if (GetState(browserAccessibility_, ui::AX_STATE_HORIZONTAL))
@@ -942,19 +1066,25 @@
 }
 
 - (NSNumber*)numberOfCharacters {
+  if (![self instanceActive])
+    return nil;
   base::string16 value = browserAccessibility_->GetValue();
-  return [NSNumber numberWithInt:value.size()];
+  return [NSNumber numberWithUnsignedInt:value.size()];
 }
 
 // The origin of this accessibility object in the page's document.
 // This is relative to webkit's top-left origin, not Cocoa's
 // bottom-left origin.
 - (NSPoint)origin {
+  if (![self instanceActive])
+    return NSMakePoint(0, 0);
   gfx::Rect bounds = browserAccessibility_->GetLocalBoundsRect();
   return NSMakePoint(bounds.x(), bounds.y());
 }
 
 - (id)parent {
+  if (![self instanceActive])
+    return nil;
   // A nil parent means we're the root.
   if (browserAccessibility_->GetParent()) {
     return NSAccessibilityUnignoredAncestor(
@@ -969,6 +1099,8 @@
 }
 
 - (NSValue*)position {
+  if (![self instanceActive])
+    return nil;
   NSPoint origin = [self origin];
   NSSize size = [[self size] sizeValue];
   NSPoint pointInScreen = [self pointInScreen:origin size:size];
@@ -976,17 +1108,21 @@
 }
 
 - (NSNumber*)required {
+  if (![self instanceActive])
+    return nil;
   return [NSNumber numberWithBool:
       GetState(browserAccessibility_, ui::AX_STATE_REQUIRED)];
 }
 
 // Returns an enum indicating the role from browserAccessibility_.
+// internal
 - (ui::AXRole)internalRole {
   return static_cast<ui::AXRole>(browserAccessibility_->GetRole());
 }
 
 // Returns true if this should expose its accessible name in AXValue.
-- (bool)shouldExposeNameInAXValue {
+// internal
+- (BOOL)shouldExposeNameInAXValue {
   switch ([self internalRole]) {
     case ui::AX_ROLE_LIST_BOX_OPTION:
     case ui::AX_ROLE_LIST_MARKER:
@@ -998,19 +1134,24 @@
   }
 }
 
+// internal
 - (content::BrowserAccessibilityDelegate*)delegate {
-  return browserAccessibility_->manager() ?
-      browserAccessibility_->manager()->delegate() :
-      nil;
+  return [self instanceActive] ? browserAccessibility_->manager()->delegate()
+                               : nil;
 }
 
 - (content::BrowserAccessibility*)browserAccessibility {
   return browserAccessibility_;
 }
 
+- (BOOL)instanceActive {
+  return browserAccessibility_ && browserAccessibility_->instance_active();
+}
+
+// internal
 - (NSPoint)pointInScreen:(NSPoint)origin
                     size:(NSSize)size {
-  if (!browserAccessibility_)
+  if (![self instanceActive])
     return NSZeroPoint;
 
   // Get the delegate for the topmost BrowserAccessibilityManager, because
@@ -1028,7 +1169,7 @@
 
 // Returns a string indicating the NSAccessibility role of this object.
 - (NSString*)role {
-  if (!browserAccessibility_)
+  if (![self instanceActive])
     return nil;
 
   ui::AXRole role = [self internalRole];
@@ -1065,6 +1206,8 @@
 
 // Returns a string indicating the role description of this object.
 - (NSString*)roleDescription {
+  if (![self instanceActive])
+    return nil;
   NSString* role = [self role];
 
   ContentClient* content_client = content::GetContentClient();
@@ -1173,6 +1316,8 @@
 }
 
 - (NSArray*)rowHeaders {
+  if (![self instanceActive])
+    return nil;
   if ([self internalRole] != ui::AX_ROLE_TABLE &&
       [self internalRole] != ui::AX_ROLE_GRID) {
     return nil;
@@ -1192,6 +1337,8 @@
 }
 
 - (NSValue*)rowIndexRange {
+  if (![self instanceActive])
+    return nil;
   if (!browserAccessibility_->IsCellOrTableHeaderRole())
     return nil;
 
@@ -1207,6 +1354,8 @@
 }
 
 - (NSArray*)rows {
+  if (![self instanceActive])
+    return nil;
   NSMutableArray* ret = [[[NSMutableArray alloc] init] autorelease];
 
   if ([self internalRole] == ui::AX_ROLE_TABLE||
@@ -1231,7 +1380,16 @@
   return ret;
 }
 
+- (NSNumber*)selected {
+  if (![self instanceActive])
+    return nil;
+  // TODO(nektar): Implement.
+  return [NSNumber numberWithBool:NO];
+}
+
 - (NSArray*)selectedChildren {
+  if (![self instanceActive])
+    return nil;
   NSMutableArray* ret = [[[NSMutableArray alloc] init] autorelease];
   BrowserAccessibilityManager* manager = browserAccessibility_->manager();
   BrowserAccessibility* focusedChild = manager->GetFocus();
@@ -1281,8 +1439,49 @@
   return ret;
 }
 
+- (NSString*)selectedText {
+  if (![self instanceActive])
+    return nil;
+
+  // TODO(nektar): Deprecate sel_start and sel_end attributes.
+  int selStart, selEnd;
+  if (!browserAccessibility_->GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START,
+                                              &selStart) ||
+      !browserAccessibility_->GetIntAttribute(ui::AX_ATTR_TEXT_SEL_END,
+                                              &selEnd)) {
+    return nil;
+  }
+
+  if (selStart > selEnd)
+    std::swap(selStart, selEnd);
+
+  int selLength = selEnd - selStart;
+  base::string16 value = browserAccessibility_->GetValue();
+  return base::SysUTF16ToNSString(value.substr(selStart, selLength));
+}
+
+- (NSValue*)selectedTextRange {
+  if (![self instanceActive])
+    return nil;
+
+  // TODO(nektar): Deprecate sel_start and sel_end attributes.
+  int selStart, selEnd;
+  if (!browserAccessibility_->GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START,
+                                              &selStart) ||
+      !browserAccessibility_->GetIntAttribute(ui::AX_ATTR_TEXT_SEL_END,
+                                              &selEnd)) {
+    return nil;
+  }
+
+  if (selStart > selEnd)
+    std::swap(selStart, selEnd);
+
+  int selLength = selEnd - selStart;
+  return [NSValue valueWithRange:NSMakeRange(selStart, selLength)];
+}
+
 - (id)selectedTextMarkerRange {
-  if (!browserAccessibility_)
+  if (![self instanceActive])
     return nil;
 
   BrowserAccessibilityManager* manager = browserAccessibility_->manager();
@@ -1309,22 +1508,23 @@
 }
 
 - (NSValue*)size {
+  if (![self instanceActive])
+    return nil;
   gfx::Rect bounds = browserAccessibility_->GetLocalBoundsRect();
   return  [NSValue valueWithSize:NSMakeSize(bounds.width(), bounds.height())];
 }
 
 - (NSString*)sortDirection {
-  if (!browserAccessibility_)
+  if (![self instanceActive])
     return nil;
-
   int sortDirection;
   if (!browserAccessibility_->GetIntAttribute(
       ui::AX_ATTR_SORT_DIRECTION, &sortDirection))
-    return @"";
+    return nil;
 
   switch (sortDirection) {
   case ui::AX_SORT_DIRECTION_UNSORTED:
-    return @"";
+    return nil;
   case ui::AX_SORT_DIRECTION_ASCENDING:
     return NSAccessibilityAscendingSortDirectionValue;
   case ui::AX_SORT_DIRECTION_DESCENDING:
@@ -1341,7 +1541,7 @@
 // Returns a text marker that points to the first character in the document that
 // can be selected with VoiceOver.
 - (id)startTextMarker {
-  if (!browserAccessibility_ || !browserAccessibility_->manager())
+  if (![self instanceActive])
     return nil;
 
   const BrowserAccessibility* root =
@@ -1367,6 +1567,8 @@
 
 // Returns a subrole based upon the role.
 - (NSString*) subrole {
+  if (![self instanceActive])
+    return nil;
   ui::AXRole browserAccessibilityRole = [self internalRole];
   if (browserAccessibilityRole == ui::AX_ROLE_TEXT_FIELD &&
       GetState(browserAccessibility_, ui::AX_STATE_PROTECTED)) {
@@ -1384,6 +1586,8 @@
 
 // Returns all tabs in this subtree.
 - (NSArray*)tabs {
+  if (![self instanceActive])
+    return nil;
   NSMutableArray* tabSubtree = [[[NSMutableArray alloc] init] autorelease];
 
   if ([self internalRole] == ui::AX_ROLE_TAB)
@@ -1399,6 +1603,8 @@
 }
 
 - (NSString*)title {
+  if (![self instanceActive])
+    return nil;
   // Mac OS X wants static text exposed in AXValue.
   if ([self shouldExposeNameInAXValue])
     return @"";
@@ -1429,6 +1635,8 @@
 }
 
 - (id)titleUIElement {
+  if (![self instanceActive])
+    return nil;
   std::vector<int32_t> labelledby_ids =
       browserAccessibility_->GetIntListAttribute(ui::AX_ATTR_LABELLEDBY_IDS);
   ui::AXNameFrom nameFrom = static_cast<ui::AXNameFrom>(
@@ -1445,6 +1653,8 @@
 }
 
 - (NSURL*)url {
+  if (![self instanceActive])
+    return nil;
   std::string url;
   if ([[self role] isEqualToString:@"AXWebArea"])
     url = browserAccessibility_->manager()->GetTreeData().url;
@@ -1458,6 +1668,8 @@
 }
 
 - (id)value {
+  if (![self instanceActive])
+    return nil;
   NSString* role = [self role];
   if ([self shouldExposeNameInAXValue]) {
     return NSStringForStringAttribute(
@@ -1521,17 +1733,23 @@
 }
 
 - (NSString*)valueDescription {
+  if (![self instanceActive])
+    return nil;
   if (browserAccessibility_)
     return base::SysUTF16ToNSString(browserAccessibility_->GetValue());
   return nil;
 }
 
 - (NSValue*)visibleCharacterRange {
+  if (![self instanceActive])
+    return nil;
   base::string16 value = browserAccessibility_->GetValue();
   return [NSValue valueWithRange:NSMakeRange(0, value.size())];
 }
 
 - (NSArray*)visibleCells {
+  if (![self instanceActive])
+    return nil;
   NSMutableArray* ret = [[[NSMutableArray alloc] init] autorelease];
   const std::vector<int32_t>& uniqueCellIds =
       browserAccessibility_->GetIntListAttribute(ui::AX_ATTR_UNIQUE_CELL_IDS);
@@ -1546,6 +1764,8 @@
 }
 
 - (NSArray*)visibleChildren {
+  if (![self instanceActive])
+    return nil;
   NSMutableArray* ret = [[[NSMutableArray alloc] init] autorelease];
   uint32_t childCount = browserAccessibility_->PlatformChildCount();
   for (uint32_t index = 0; index < childCount; ++index) {
@@ -1557,20 +1777,26 @@
 }
 
 - (NSArray*)visibleColumns {
+  if (![self instanceActive])
+    return nil;
   return [self columns];
 }
 
 - (NSArray*)visibleRows {
+  if (![self instanceActive])
+    return nil;
   return [self rows];
 }
 
 - (NSNumber*)visited {
+  if (![self instanceActive])
+    return nil;
   return [NSNumber numberWithBool:
       GetState(browserAccessibility_, ui::AX_STATE_VISITED)];
 }
 
 - (id)window {
-  if (!browserAccessibility_)
+  if (![self instanceActive])
     return nil;
 
   BrowserAccessibilityManagerMac* manager =
@@ -1592,7 +1818,7 @@
 
 // Returns the requested text range from this object's value attribute.
 - (NSString*)valueForRange:(NSRange)range {
-  if (!browserAccessibility_)
+  if (![self instanceActive])
     return nil;
 
   base::string16 value = browserAccessibility_->GetValue();
@@ -1605,7 +1831,7 @@
 // Returns the accessibility value for the given attribute.  If the value isn't
 // supported this will return nil.
 - (id)accessibilityAttributeValue:(NSString*)attribute {
-  if (!browserAccessibility_)
+  if (![self instanceActive])
     return nil;
 
   SEL selector =
@@ -1613,33 +1839,6 @@
   if (selector)
     return [self performSelector:selector];
 
-  // TODO(dtseng): refactor remaining attributes.
-  int selStart, selEnd;
-  if (browserAccessibility_->GetIntAttribute(
-          ui::AX_ATTR_TEXT_SEL_START, &selStart) &&
-      browserAccessibility_->
-          GetIntAttribute(ui::AX_ATTR_TEXT_SEL_END, &selEnd)) {
-    if (selStart > selEnd)
-      std::swap(selStart, selEnd);
-    int selLength = selEnd - selStart;
-    if ([attribute isEqualToString:
-        NSAccessibilityInsertionPointLineNumberAttribute]) {
-      const std::vector<int32_t>& line_breaks =
-          browserAccessibility_->GetIntListAttribute(ui::AX_ATTR_LINE_BREAKS);
-      for (int i = 0; i < static_cast<int>(line_breaks.size()); ++i) {
-        if (line_breaks[i] > selStart)
-          return [NSNumber numberWithInt:i];
-      }
-      return [NSNumber numberWithInt:static_cast<int>(line_breaks.size())];
-    }
-    if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]) {
-      base::string16 value = browserAccessibility_->GetValue();
-      return base::SysUTF16ToNSString(value.substr(selStart, selLength));
-    }
-    if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) {
-      return [NSValue valueWithRange:NSMakeRange(selStart, selLength)];
-    }
-  }
   return nil;
 }
 
@@ -1648,7 +1847,7 @@
 // TODO(nektar): Implement all unimplemented attributes, e.g. text markers.
 - (id)accessibilityAttributeValue:(NSString*)attribute
                      forParameter:(id)parameter {
-  if (!browserAccessibility_)
+  if (![self instanceActive])
     return nil;
 
   const std::vector<int32_t>& line_breaks =
@@ -1877,7 +2076,7 @@
 // Returns an array of parameterized attributes names that this object will
 // respond to.
 - (NSArray*)accessibilityParameterizedAttributeNames {
-  if (!browserAccessibility_)
+  if (![self instanceActive])
     return nil;
 
   // General attributes.
@@ -1955,20 +2154,27 @@
 
 // Returns an array of action names that this object will respond to.
 - (NSArray*)accessibilityActionNames {
-  if (!browserAccessibility_)
+  if (![self instanceActive])
     return nil;
 
-  NSMutableArray* ret =
-      [NSMutableArray arrayWithObject:NSAccessibilityShowMenuAction];
-  NSString* role = [self role];
-  // TODO(dtseng): this should only get set when there's a default action.
-  if (![role isEqualToString:NSAccessibilityStaticTextRole] &&
-      ![role isEqualToString:NSAccessibilityTextFieldRole] &&
-      ![role isEqualToString:NSAccessibilityTextAreaRole]) {
-    [ret addObject:NSAccessibilityPressAction];
+  NSMutableArray* actions = [NSMutableArray
+      arrayWithObjects:NSAccessibilityShowMenuAction,
+                       NSAccessibilityScrollToVisibleAction, nil];
+
+  // VoiceOver expects the "press" action to be first.
+  if (browserAccessibility_->IsClickable())
+    [actions insertObject:NSAccessibilityPressAction atIndex:0];
+
+  if (browserAccessibility_->IsMenuRelated())
+    [actions addObject:NSAccessibilityCancelAction];
+
+  if ([self internalRole] == ui::AX_ROLE_SLIDER) {
+    [actions addObjectsFromArray:@[
+      NSAccessibilityIncrementAction, NSAccessibilityDecrementAction
+    ]];
   }
 
-  return ret;
+  return actions;
 }
 
 // Returns a sub-array of values for the given attribute value, starting at
@@ -1980,7 +2186,7 @@
 - (NSArray*)accessibilityArrayAttributeValues:(NSString*)attribute
                                         index:(NSUInteger)index
                                      maxCount:(NSUInteger)maxCount {
-  if (!browserAccessibility_)
+  if (![self instanceActive])
     return nil;
 
   NSArray* fullArray = [self accessibilityAttributeValue:attribute];
@@ -2000,7 +2206,7 @@
 
 // Returns the count of the specified accessibility array attribute.
 - (NSUInteger)accessibilityArrayAttributeCount:(NSString*)attribute {
-  if (!browserAccessibility_)
+  if (![self instanceActive])
     return 0;
 
   NSArray* fullArray = [self accessibilityAttributeValue:attribute];
@@ -2009,7 +2215,7 @@
 
 // Returns the list of accessibility attributes that this object supports.
 - (NSArray*)accessibilityAttributeNames {
-  if (!browserAccessibility_)
+  if (![self instanceActive])
     return nil;
 
   // General attributes.
@@ -2061,7 +2267,9 @@
       NSAccessibilityRowIndexRangeAttribute, @"AXSortDirection"
     ]];
   } else if ([role isEqualToString:@"AXWebArea"]) {
-    [ret addObjectsFromArray:@[ @"AXLoaded", @"AXLoadingProgress" ]];
+    [ret addObjectsFromArray:@[
+      @"AXLoaded", NSAccessibilityLoadingProgressAttribute
+    ]];
   } else if ([role isEqualToString:NSAccessibilityTabGroupRole]) {
     [ret addObject:NSAccessibilityTabsAttribute];
   } else if ([role isEqualToString:NSAccessibilityProgressIndicatorRole] ||
@@ -2121,38 +2329,38 @@
 
   // Position in set and Set size
   if (browserAccessibility_->HasIntAttribute(ui::AX_ATTR_POS_IN_SET)) {
-    [ret addObjectsFromArray:@[ @"AXARIAPosInSet" ]];
+    [ret addObjectsFromArray:@[ NSAccessibilityARIAPosInSetAttribute ]];
   }
   if (browserAccessibility_->HasIntAttribute(ui::AX_ATTR_SET_SIZE)) {
-    [ret addObjectsFromArray:@[ @"AXARIASetSize" ]];
+    [ret addObjectsFromArray:@[ NSAccessibilityARIASetSizeAttribute ]];
   }
 
   // Live regions.
   if (browserAccessibility_->HasStringAttribute(
           ui::AX_ATTR_LIVE_STATUS)) {
-    [ret addObjectsFromArray:@[ @"AXARIALive" ]];
+    [ret addObjectsFromArray:@[ NSAccessibilityARIALiveAttribute ]];
   }
   if (browserAccessibility_->HasStringAttribute(
           ui::AX_ATTR_LIVE_RELEVANT)) {
-    [ret addObjectsFromArray:@[ @"AXARIARelevant" ]];
+    [ret addObjectsFromArray:@[ NSAccessibilityARIARelevantAttribute ]];
   }
   if (browserAccessibility_->HasBoolAttribute(
           ui::AX_ATTR_LIVE_ATOMIC)) {
-    [ret addObjectsFromArray:@[ @"AXARIAAtomic" ]];
+    [ret addObjectsFromArray:@[ NSAccessibilityARIAAtomicAttribute ]];
   }
   if (browserAccessibility_->HasBoolAttribute(
           ui::AX_ATTR_LIVE_BUSY)) {
-    [ret addObjectsFromArray:@[ @"AXARIABusy" ]];
+    [ret addObjectsFromArray:@[ NSAccessibilityARIABusyAttribute ]];
   }
 
   std::string dropEffect;
   if (browserAccessibility_->GetHtmlAttribute("aria-dropeffect", &dropEffect)) {
-    [ret addObjectsFromArray:@[ @"AXDropEffects" ]];
+    [ret addObjectsFromArray:@[ NSAccessibilityDropEffectsAttribute ]];
   }
 
   std::string grabbed;
   if (browserAccessibility_->GetHtmlAttribute("aria-grabbed", &grabbed)) {
-    [ret addObjectsFromArray:@[ @"AXGrabbed" ]];
+    [ret addObjectsFromArray:@[ NSAccessibilityGrabbedAttribute ]];
   }
 
   // Add expanded attribute only if it has expanded or collapsed state.
@@ -2188,7 +2396,7 @@
 
 // Returns the index of the child in this objects array of children.
 - (NSUInteger)accessibilityGetIndexOf:(id)child {
-  if (!browserAccessibility_)
+  if (![self instanceActive])
     return 0;
 
   NSUInteger index = 0;
@@ -2203,7 +2411,7 @@
 // Returns whether or not the specified attribute can be set by the
 // accessibility API via |accessibilitySetValue:forAttribute:|.
 - (BOOL)accessibilityIsAttributeSettable:(NSString*)attribute {
-  if (!browserAccessibility_)
+  if (![self instanceActive])
     return NO;
 
   if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
@@ -2229,7 +2437,7 @@
 // Returns whether or not this object should be ignored in the accessibility
 // tree.
 - (BOOL)accessibilityIsIgnored {
-  if (!browserAccessibility_)
+  if (![self instanceActive])
     return YES;
 
   return [self isIgnored];
@@ -2238,7 +2446,7 @@
 // Performs the given accessibility action on the webkit accessibility object
 // that backs this object.
 - (void)accessibilityPerformAction:(NSString*)action {
-  if (!browserAccessibility_)
+  if (![self instanceActive])
     return;
 
   // TODO(dmazzoni): Support more actions.
@@ -2253,7 +2461,7 @@
 
 // Returns the description of the given action.
 - (NSString*)accessibilityActionDescription:(NSString*)action {
-  if (!browserAccessibility_)
+  if (![self instanceActive])
     return nil;
 
   return NSAccessibilityActionDescription(action);
@@ -2263,12 +2471,14 @@
 // This class does not support this.
 - (BOOL)accessibilitySetOverrideValue:(id)value
                          forAttribute:(NSString*)attribute {
+  if (![self instanceActive])
+    return NO;
   return NO;
 }
 
 // Sets the value for an accessibility attribute via the accessibility API.
 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute {
-  if (!browserAccessibility_)
+  if (![self instanceActive])
     return;
 
   if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
@@ -2291,7 +2501,7 @@
 // or one of its children, so this will never return nil unless this
 // object is invalid.
 - (id)accessibilityHitTest:(NSPoint)point {
-  if (!browserAccessibility_)
+  if (![self instanceActive])
     return nil;
 
   BrowserAccessibilityCocoa* hit = self;
@@ -2323,7 +2533,7 @@
 
 - (NSUInteger)hash {
   // Potentially called during dealloc.
-  if (!browserAccessibility_)
+  if (![self instanceActive])
     return [super hash];
   return browserAccessibility_->GetId();
 }
diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc
index 0a8867049..1d05689 100644
--- a/content/browser/compositor/gpu_process_transport_factory.cc
+++ b/content/browser/compositor/gpu_process_transport_factory.cc
@@ -54,7 +54,6 @@
 #include "ui/compositor/compositor_switches.h"
 #include "ui/compositor/layer.h"
 #include "ui/gfx/geometry/size.h"
-#include "ui/gfx/native_widget_types.h"
 
 #if defined(MOJO_RUNNER_CLIENT)
 #include "content/common/mojo/mojo_shell_connection_impl.h"
@@ -126,7 +125,7 @@
       CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE;
   scoped_refptr<GpuChannelHost> gpu_channel_host(
       BrowserGpuChannelHostFactory::instance()->EstablishGpuChannelSync(cause));
-  return CreateContextCommon(gpu_channel_host, 0);
+  return CreateContextCommon(gpu_channel_host, gpu::kNullSurfaceHandle);
 }
 
 scoped_ptr<cc::SoftwareOutputDevice>
@@ -282,17 +281,21 @@
     scoped_refptr<GpuChannelHost> gpu_channel_host =
         BrowserGpuChannelHostFactory::instance()->GetGpuChannel();
     if (gpu_channel_host.get()) {
+      GpuSurfaceTracker* tracker = GpuSurfaceTracker::Get();
+      gpu::SurfaceHandle surface_handle =
+          data->surface_id ? tracker->GetSurfaceHandle(data->surface_id)
+                           : gpu::kNullSurfaceHandle;
       context_provider = ContextProviderCommandBuffer::Create(
           GpuProcessTransportFactory::CreateContextCommon(gpu_channel_host,
-                                                          data->surface_id),
+                                                          surface_handle),
           BROWSER_COMPOSITOR_ONSCREEN_CONTEXT);
       if (context_provider && !context_provider->BindToCurrentThread())
         context_provider = nullptr;
       if (!shared_worker_context_provider_ ||
           shared_worker_context_provider_lost) {
         shared_worker_context_provider_ = ContextProviderCommandBuffer::Create(
-            GpuProcessTransportFactory::CreateContextCommon(gpu_channel_host,
-                                                            0),
+            GpuProcessTransportFactory::CreateContextCommon(
+                gpu_channel_host, gpu::kNullSurfaceHandle),
             BROWSER_WORKER_CONTEXT);
         if (shared_worker_context_provider_ &&
             !shared_worker_context_provider_->BindToCurrentThread())
@@ -588,24 +591,13 @@
   DCHECK(!per_compositor_data_[compositor]);
 
   gfx::AcceleratedWidget widget = compositor->widget();
-  GpuSurfaceTracker* tracker = GpuSurfaceTracker::Get();
 
   PerCompositorData* data = new PerCompositorData;
   if (compositor->widget() == gfx::kNullAcceleratedWidget) {
     data->surface_id = 0;
   } else {
+    GpuSurfaceTracker* tracker = GpuSurfaceTracker::Get();
     data->surface_id = tracker->AddSurfaceForNativeWidget(widget);
-#if defined(OS_MACOSX) || defined(OS_ANDROID)
-    // On Mac and Android, we can't pass the AcceleratedWidget, which is
-    // process-local, so instead we pass the surface_id, so that we can look up
-    // the AcceleratedWidget on the GPU side or when we receive
-    // GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params.
-    gfx::PluginWindowHandle handle = data->surface_id;
-#else
-    gfx::PluginWindowHandle handle = widget;
-#endif
-    tracker->SetSurfaceHandle(data->surface_id,
-                              gfx::GLSurfaceHandle(handle, gfx::NATIVE_DIRECT));
   }
 
   per_compositor_data_[compositor] = data;
@@ -616,7 +608,7 @@
 scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
 GpuProcessTransportFactory::CreateContextCommon(
     scoped_refptr<GpuChannelHost> gpu_channel_host,
-    int surface_id) {
+    gpu::SurfaceHandle surface_handle) {
   if (!GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor())
     return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
   blink::WebGraphicsContext3D::Attributes attrs;
@@ -633,7 +625,7 @@
   GURL url("chrome://gpu/GpuProcessTransportFactory::CreateContextCommon");
   scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context(
       new WebGraphicsContext3DCommandBufferImpl(
-          surface_id,
+          surface_handle,
           url,
           gpu_channel_host.get(),
           attrs,
diff --git a/content/browser/compositor/gpu_process_transport_factory.h b/content/browser/compositor/gpu_process_transport_factory.h
index ee8d60e..6f5e034 100644
--- a/content/browser/compositor/gpu_process_transport_factory.h
+++ b/content/browser/compositor/gpu_process_transport_factory.h
@@ -18,6 +18,7 @@
 #include "build/build_config.h"
 #include "content/browser/compositor/image_transport_factory.h"
 #include "content/common/gpu/client/gpu_channel_host.h"
+#include "gpu/ipc/common/surface_handle.h"
 #include "ui/compositor/compositor.h"
 
 namespace base {
@@ -95,7 +96,7 @@
                              int num_attempts);
   scoped_ptr<WebGraphicsContext3DCommandBufferImpl> CreateContextCommon(
       scoped_refptr<GpuChannelHost> gpu_channel_host,
-      int surface_id);
+      gpu::SurfaceHandle surface_handle);
 
   void OnLostMainThreadSharedContextInsideCallback();
   void OnLostMainThreadSharedContext();
diff --git a/content/browser/geolocation/wifi_data_provider_corewlan_mac.mm b/content/browser/geolocation/wifi_data_provider_corewlan_mac.mm
index 036c761..bbe099f 100644
--- a/content/browser/geolocation/wifi_data_provider_corewlan_mac.mm
+++ b/content/browser/geolocation/wifi_data_provider_corewlan_mac.mm
@@ -39,6 +39,7 @@
 @property (nonatomic, readonly) NSNumber* phyMode;
 @property (nonatomic, readonly) NSNumber* channel;
 @property (nonatomic, readonly) NSNumber* rssi;
+@property (nonatomic, readonly) NSInteger rssiValue;
 @property (nonatomic, readonly) NSNumber* noise;
 @property (nonatomic, readonly) NSData* ieData;
 @property (nonatomic, readonly) BOOL isIBSS;
@@ -158,7 +159,7 @@
         continue;  // crbug.com/545501
       access_point_data.mac_address =
           MacAddressAsString16(static_cast<const uint8_t*>([mac bytes]));
-      access_point_data.radio_signal_strength = [[network rssi] intValue];
+      access_point_data.radio_signal_strength = [network rssiValue];
       access_point_data.channel = [[network channel] intValue];
       access_point_data.signal_to_noise =
           access_point_data.radio_signal_strength - [[network noise] intValue];
diff --git a/content/browser/gpu/browser_gpu_channel_host_factory.cc b/content/browser/gpu/browser_gpu_channel_host_factory.cc
index 7544f7e..806ae80 100644
--- a/content/browser/gpu/browser_gpu_channel_host_factory.cc
+++ b/content/browser/gpu/browser_gpu_channel_host_factory.cc
@@ -18,7 +18,6 @@
 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
 #include "content/browser/gpu/gpu_data_manager_impl.h"
 #include "content/browser/gpu/gpu_process_host.h"
-#include "content/browser/gpu/gpu_surface_tracker.h"
 #include "content/browser/gpu/shader_disk_cache.h"
 #include "content/common/child_process_host_impl.h"
 #include "content/common/gpu/gpu_messages.h"
@@ -277,11 +276,6 @@
   return shm;
 }
 
-gfx::GLSurfaceHandle BrowserGpuChannelHostFactory::GetSurfaceHandle(
-    int32_t surface_id) {
-  return GpuSurfaceTracker::Get()->GetSurfaceHandle(surface_id);
-}
-
 // Blocking the UI thread to open a GPU channel is not supported on Android.
 // (Opening the initial channel to a child process involves handling a reply
 // task on the UI thread first, so we cannot block here.)
diff --git a/content/browser/gpu/browser_gpu_channel_host_factory.h b/content/browser/gpu/browser_gpu_channel_host_factory.h
index fa071d35..e8919d2 100644
--- a/content/browser/gpu/browser_gpu_channel_host_factory.h
+++ b/content/browser/gpu/browser_gpu_channel_host_factory.h
@@ -32,7 +32,6 @@
   bool IsMainThread() override;
   scoped_refptr<base::SingleThreadTaskRunner> GetIOThreadTaskRunner() override;
   scoped_ptr<base::SharedMemory> AllocateSharedMemory(size_t size) override;
-  gfx::GLSurfaceHandle GetSurfaceHandle(int32_t surface_id) override;
 
   int GpuProcessHostId() { return gpu_host_id_; }
 #if !defined(OS_ANDROID)
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 760a379..dbc3da5 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -642,8 +642,8 @@
 
 #if defined(OS_WIN)
 void GpuProcessHost::OnAcceleratedSurfaceCreatedChildWindow(
-    const gfx::PluginWindowHandle& parent_handle,
-    const gfx::PluginWindowHandle& window_handle) {
+    gpu::SurfaceHandle parent_handle,
+    gpu::SurfaceHandle window_handle) {
   if (!in_process_) {
     DCHECK(process_);
     {
@@ -744,7 +744,9 @@
   params.usage = usage;
   params.client_id = client_id;
   params.surface_handle =
-      GpuSurfaceTracker::GetInstance()->GetSurfaceHandle(surface_id).handle;
+      surface_id
+          ? GpuSurfaceTracker::GetInstance()->GetSurfaceHandle(surface_id)
+          : gpu::kNullSurfaceHandle;
   if (Send(new GpuMsg_CreateGpuMemoryBuffer(params))) {
     create_gpu_memory_buffer_requests_.push(callback);
   } else {
diff --git a/content/browser/gpu/gpu_process_host.h b/content/browser/gpu/gpu_process_host.h
index 90703a7..04dc52c 100644
--- a/content/browser/gpu/gpu_process_host.h
+++ b/content/browser/gpu/gpu_process_host.h
@@ -26,11 +26,11 @@
 #include "content/public/browser/gpu_data_manager.h"
 #include "gpu/command_buffer/common/constants.h"
 #include "gpu/config/gpu_info.h"
+#include "gpu/ipc/common/surface_handle.h"
 #include "ipc/ipc_sender.h"
 #include "ipc/message_filter.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/gpu_memory_buffer.h"
-#include "ui/gfx/native_widget_types.h"
 #include "url/gurl.h"
 
 struct GPUCreateCommandBufferConfig;
@@ -199,8 +199,8 @@
 
 #if defined(OS_WIN)
   void OnAcceleratedSurfaceCreatedChildWindow(
-      const gfx::PluginWindowHandle& parent_handle,
-      const gfx::PluginWindowHandle& window_handle);
+      gpu::SurfaceHandle parent_handle,
+      gpu::SurfaceHandle window_handle);
 #endif
 
   void CreateChannelCache(int32_t client_id);
diff --git a/content/browser/gpu/gpu_surface_tracker.cc b/content/browser/gpu/gpu_surface_tracker.cc
index bd4e91d..7c24249 100644
--- a/content/browser/gpu/gpu_surface_tracker.cc
+++ b/content/browser/gpu/gpu_surface_tracker.cc
@@ -30,7 +30,7 @@
     gfx::AcceleratedWidget widget) {
   base::AutoLock lock(lock_);
   int surface_id = next_surface_id_++;
-  surface_map_[surface_id] = SurfaceInfo(widget, gfx::GLSurfaceHandle());
+  surface_map_[surface_id] = widget;
   return surface_id;
 }
 
@@ -40,20 +40,24 @@
   surface_map_.erase(surface_id);
 }
 
-void GpuSurfaceTracker::SetSurfaceHandle(int surface_id,
-                                         const gfx::GLSurfaceHandle& handle) {
+gpu::SurfaceHandle GpuSurfaceTracker::GetSurfaceHandle(int surface_id) {
+  DCHECK(surface_id);
+#if defined(OS_MACOSX) || defined(OS_ANDROID)
+#if DCHECK_IS_ON()
   base::AutoLock lock(lock_);
   DCHECK(surface_map_.find(surface_id) != surface_map_.end());
-  SurfaceInfo& info = surface_map_[surface_id];
-  info.handle = handle;
-}
-
-gfx::GLSurfaceHandle GpuSurfaceTracker::GetSurfaceHandle(int surface_id) {
+#endif
+  // On Mac and Android, we can't pass the AcceleratedWidget, which is
+  // process-local, so instead we pass the surface_id, so that we can look up
+  // the AcceleratedWidget on the GPU side or when we receive
+  // GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params.
+  return surface_id;
+#else
   base::AutoLock lock(lock_);
   SurfaceMap::iterator it = surface_map_.find(surface_id);
-  if (it == surface_map_.end())
-    return gfx::GLSurfaceHandle();
-  return it->second.handle;
+  DCHECK(it != surface_map_.end());
+  return it->second;
+#endif
 }
 
 gfx::AcceleratedWidget GpuSurfaceTracker::AcquireNativeWidget(int surface_id) {
@@ -63,11 +67,11 @@
     return gfx::kNullAcceleratedWidget;
 
 #if defined(OS_ANDROID)
-  if (it->second.native_widget != gfx::kNullAcceleratedWidget)
-    ANativeWindow_acquire(it->second.native_widget);
+  if (it->second != gfx::kNullAcceleratedWidget)
+    ANativeWindow_acquire(it->second);
 #endif  // defined(OS_ANDROID)
 
-  return it->second.native_widget;
+  return it->second;
 }
 
 std::size_t GpuSurfaceTracker::GetSurfaceCount() {
@@ -75,15 +79,4 @@
   return surface_map_.size();
 }
 
-GpuSurfaceTracker::SurfaceInfo::SurfaceInfo()
-    : native_widget(gfx::kNullAcceleratedWidget) {}
-
-GpuSurfaceTracker::SurfaceInfo::SurfaceInfo(
-    const gfx::AcceleratedWidget& native_widget,
-    const gfx::GLSurfaceHandle& handle)
-    : native_widget(native_widget), handle(handle) {}
-
-GpuSurfaceTracker::SurfaceInfo::~SurfaceInfo() { }
-
-
 }  // namespace content
diff --git a/content/browser/gpu/gpu_surface_tracker.h b/content/browser/gpu/gpu_surface_tracker.h
index 386eeea..22ad7143 100644
--- a/content/browser/gpu/gpu_surface_tracker.h
+++ b/content/browser/gpu/gpu_surface_tracker.h
@@ -15,6 +15,7 @@
 #include "base/synchronization/lock.h"
 #include "content/common/content_export.h"
 #include "content/common/gpu/gpu_surface_lookup.h"
+#include "gpu/ipc/common/surface_handle.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/native_widget_types.h"
 
@@ -44,13 +45,9 @@
   // Removes a given existing surface.
   void RemoveSurface(int surface_id);
 
-  // Sets the native handle for the given surface.
-  // Note: This is an O(log N) lookup.
-  void SetSurfaceHandle(int surface_id, const gfx::GLSurfaceHandle& handle);
-
   // Gets the native handle for the given surface.
   // Note: This is an O(log N) lookup.
-  gfx::GLSurfaceHandle GetSurfaceHandle(int surface_id);
+  gpu::SurfaceHandle GetSurfaceHandle(int surface_id);
 
   // Returns the number of surfaces currently registered with the tracker.
   std::size_t GetSurfaceCount();
@@ -60,15 +57,7 @@
   static GpuSurfaceTracker* GetInstance();
 
  private:
-  struct SurfaceInfo {
-    SurfaceInfo();
-    SurfaceInfo(const gfx::AcceleratedWidget& native_widget,
-                const gfx::GLSurfaceHandle& handle);
-    ~SurfaceInfo();
-    gfx::AcceleratedWidget native_widget;
-    gfx::GLSurfaceHandle handle;
-  };
-  typedef std::map<int, SurfaceInfo> SurfaceMap;
+  typedef std::map<int, gfx::AcceleratedWidget> SurfaceMap;
 
   friend struct base::DefaultSingletonTraits<GpuSurfaceTracker>;
 
diff --git a/content/browser/media/android/browser_media_player_manager.cc b/content/browser/media/android/browser_media_player_manager.cc
index a42c31c2..eba80da 100644
--- a/content/browser/media/android/browser_media_player_manager.cc
+++ b/content/browser/media/android/browser_media_player_manager.cc
@@ -144,16 +144,13 @@
     case MEDIA_PLAYER_TYPE_URL: {
       const std::string user_agent = GetContentClient()->GetUserAgent();
       MediaPlayerBridge* media_player_bridge = new MediaPlayerBridge(
-          media_player_params.player_id,
-          media_player_params.url,
-          media_player_params.first_party_for_cookies,
-          user_agent,
-          hide_url_log,
+          media_player_params.player_id, media_player_params.url,
+          media_player_params.first_party_for_cookies, user_agent, hide_url_log,
           this,
           base::Bind(&BrowserMediaPlayerManager::OnDecoderResourcesReleased,
                      weak_ptr_factory_.GetWeakPtr()),
-          media_player_params.frame_url,
-          media_player_params.allow_credentials);
+          media_player_params.frame_url, media_player_params.allow_credentials,
+          media_player_params.media_session_id);
 
       if (media_player_params.type == MEDIA_PLAYER_TYPE_REMOTE_ONLY)
         return media_player_bridge;
@@ -190,20 +187,20 @@
     case MEDIA_PLAYER_TYPE_MEDIA_SOURCE: {
       if (media::UseMediaThreadForMediaPlayback()) {
         return new MediaCodecPlayer(
-            media_player_params.player_id,
-            weak_ptr_factory_.GetWeakPtr(),
+            media_player_params.player_id, weak_ptr_factory_.GetWeakPtr(),
             base::Bind(&BrowserMediaPlayerManager::OnDecoderResourcesReleased,
                        weak_ptr_factory_.GetWeakPtr()),
             demuxer->CreateDemuxer(media_player_params.demuxer_client_id),
-            media_player_params.frame_url);
+            media_player_params.frame_url,
+            media_player_params.media_session_id);
       } else {
         return new MediaSourcePlayer(
-            media_player_params.player_id,
-            this,
+            media_player_params.player_id, this,
             base::Bind(&BrowserMediaPlayerManager::OnDecoderResourcesReleased,
                        weak_ptr_factory_.GetWeakPtr()),
             demuxer->CreateDemuxer(media_player_params.demuxer_client_id),
-            media_player_params.frame_url);
+            media_player_params.frame_url,
+            media_player_params.media_session_id);
       }
     }
   }
diff --git a/content/browser/media/media_canplaytype_browsertest.cc b/content/browser/media/media_canplaytype_browsertest.cc
index 0b70f41..1a3af5a3 100644
--- a/content/browser/media/media_canplaytype_browsertest.cc
+++ b/content/browser/media/media_canplaytype_browsertest.cc
@@ -42,8 +42,8 @@
 const char* kTheoraProbably = kNot;
 const char* kOggOpusProbably = kNot;
 const char* kMpeg2AacProbably = kNot;  // https://crbug.com/544268.
-const char* kHlsProbably = kProbably;
-const char* kHlsMaybe = kMaybe;
+const char* kHlsProbably = kPropProbably;
+const char* kHlsMaybe = kPropMaybe;
 #endif  // !OS_ANDROID
 
 #if BUILDFLAG(ENABLE_HEVC_DEMUXING)
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index 840afac..681db0f 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -319,9 +319,6 @@
     window_ = window;
     ANativeWindow_acquire(window);
     surface_id_ = tracker->AddSurfaceForNativeWidget(window);
-    tracker->SetSurfaceHandle(
-        surface_id_,
-        gfx::GLSurfaceHandle(surface_id_, gfx::NATIVE_DIRECT));
     // Register first, SetVisible() might create an OutputSurface.
     RegisterViewSurface(surface_id_, j_surface.obj());
     SetVisible(true);
@@ -433,8 +430,10 @@
       3 * full_screen_texture_size_in_bytes, kDefaultMaxTransferBufferSize);
   limits.mapped_memory_reclaim_limit = 2 * 1024 * 1024;
   bool lose_context_when_out_of_memory = true;
+  GpuSurfaceTracker* tracker = GpuSurfaceTracker::Get();
+  gpu::SurfaceHandle surface_handle = tracker->GetSurfaceHandle(surface_id);
   return make_scoped_ptr(
-      new WebGraphicsContext3DCommandBufferImpl(surface_id,
+      new WebGraphicsContext3DCommandBufferImpl(surface_handle,
                                                 url,
                                                 gpu_channel_host.get(),
                                                 attributes,
diff --git a/content/browser/renderer_host/input/composited_scrolling_browsertest.cc b/content/browser/renderer_host/input/composited_scrolling_browsertest.cc
index cbf48e8..fdca6bc 100644
--- a/content/browser/renderer_host/input/composited_scrolling_browsertest.cc
+++ b/content/browser/renderer_host/input/composited_scrolling_browsertest.cc
@@ -84,7 +84,7 @@
 
     RenderWidgetHostImpl* host = GetWidgetHost();
     scoped_refptr<FrameWatcher> frame_watcher(new FrameWatcher());
-    host->GetProcess()->AddFilter(frame_watcher.get());
+    frame_watcher->AttachTo(shell()->web_contents());
     host->GetView()->SetSize(gfx::Size(400, 400));
 
     base::string16 ready_title(base::ASCIIToUTF16("ready"));
diff --git a/content/browser/renderer_host/input/mouse_wheel_event_queue.cc b/content/browser/renderer_host/input/mouse_wheel_event_queue.cc
index 48dbad23..5e56e9b 100644
--- a/content/browser/renderer_host/input/mouse_wheel_event_queue.cc
+++ b/content/browser/renderer_host/input/mouse_wheel_event_queue.cc
@@ -37,6 +37,7 @@
                                            int64_t scroll_transaction_ms)
     : client_(client),
       needs_scroll_begin_(true),
+      needs_scroll_end_(false),
       send_gestures_(send_gestures),
       scroll_transaction_ms_(scroll_transaction_ms),
       scrolling_device_(blink::WebGestureDeviceUninitialized) {
@@ -85,6 +86,9 @@
       (scrolling_device_ == blink::WebGestureDeviceUninitialized ||
        scrolling_device_ == blink::WebGestureDeviceTouchpad)) {
     GestureEventWithLatencyInfo scroll_update;
+    scroll_update.event.timeStampSeconds =
+        event_sent_for_gesture_ack_->event.timeStampSeconds;
+
     scroll_update.event.x = event_sent_for_gesture_ack_->event.x;
     scroll_update.event.y = event_sent_for_gesture_ack_->event.y;
     scroll_update.event.globalX = event_sent_for_gesture_ack_->event.globalX;
@@ -96,6 +100,11 @@
         event_sent_for_gesture_ack_->event.deltaX;
     scroll_update.event.data.scrollUpdate.deltaY =
         event_sent_for_gesture_ack_->event.deltaY;
+    // Only OSX populates the momentumPhase; so expect this to
+    // always be PhaseNone on all other platforms.
+    scroll_update.event.data.scrollUpdate.inertial =
+        event_sent_for_gesture_ack_->event.momentumPhase !=
+        blink::WebMouseWheelEvent::PhaseNone;
     if (event_sent_for_gesture_ack_->event.scrollByPage) {
       scroll_update.event.data.scrollUpdate.deltaUnits =
           blink::WebGestureEvent::Page;
@@ -114,7 +123,67 @@
               ? blink::WebGestureEvent::PrecisePixels
               : blink::WebGestureEvent::Pixels;
     }
-    SendGesture(scroll_update);
+
+    bool current_phase_ended = false;
+    bool has_phase_info = false;
+
+    if (event_sent_for_gesture_ack_->event.phase !=
+            blink::WebMouseWheelEvent::PhaseNone ||
+        event_sent_for_gesture_ack_->event.momentumPhase !=
+            blink::WebMouseWheelEvent::PhaseNone) {
+      has_phase_info = true;
+      current_phase_ended = event_sent_for_gesture_ack_->event.phase ==
+                                blink::WebMouseWheelEvent::PhaseEnded ||
+                            event_sent_for_gesture_ack_->event.phase ==
+                                blink::WebMouseWheelEvent::PhaseCancelled ||
+                            event_sent_for_gesture_ack_->event.momentumPhase ==
+                                blink::WebMouseWheelEvent::PhaseEnded ||
+                            event_sent_for_gesture_ack_->event.momentumPhase ==
+                                blink::WebMouseWheelEvent::PhaseCancelled;
+    }
+
+    bool needs_update = scroll_update.event.data.scrollUpdate.deltaX != 0 ||
+                        scroll_update.event.data.scrollUpdate.deltaY != 0;
+
+    // If there is no update to send and the current phase is ended yet a GSB
+    // needs to be sent, this event sequence doesn't need to be generated
+    // because the events generated will be a GSB (non-synthetic) and GSE
+    // (non-synthetic). This situation arises when OSX generates double
+    // phase end information.
+    bool empty_sequence =
+        !needs_update && needs_scroll_begin_ && current_phase_ended;
+
+    if (needs_update || !empty_sequence) {
+      if (needs_scroll_begin_) {
+        // If no GSB has been sent, it will be a non-synthetic GSB.
+        SendScrollBegin(scroll_update, false);
+      } else if (has_phase_info) {
+        // If a GSB has been sent, generate a synthetic GSB if we have phase
+        // information. This should be removed once crbug.com/526463 is fully
+        // implemented.
+        SendScrollBegin(scroll_update, true);
+      }
+
+      if (needs_update)
+        client_->SendGestureEvent(scroll_update);
+
+      if (current_phase_ended) {
+        // Non-synthetic GSEs are sent when the current phase is canceled or
+        // ended.
+        SendScrollEnd(scroll_update.event, false);
+      } else if (has_phase_info) {
+        // Generate a synthetic GSE for every update to force hit testing so
+        // that the non-latching behavior is preserved. Remove once
+        // crbug.com/526463 is fully implemented.
+        SendScrollEnd(scroll_update.event, true);
+      } else {
+        scroll_end_timer_.Start(
+            FROM_HERE,
+            base::TimeDelta::FromMilliseconds(scroll_transaction_ms_),
+            base::Bind(&MouseWheelEventQueue::SendScrollEnd,
+                       base::Unretained(this), scroll_update.event, false));
+      }
+    }
   }
 
   event_sent_for_gesture_ack_.reset();
@@ -158,62 +227,52 @@
   client_->SendMouseWheelEventImmediately(send_event);
 }
 
-void MouseWheelEventQueue::SendScrollEnd(blink::WebGestureEvent update_event) {
-  GestureEventWithLatencyInfo scroll_end;
+void MouseWheelEventQueue::SendScrollEnd(blink::WebGestureEvent update_event,
+                                         bool synthetic) {
+  DCHECK((synthetic && !needs_scroll_end_) || needs_scroll_end_);
+
+  GestureEventWithLatencyInfo scroll_end(update_event);
+  scroll_end.event.timeStampSeconds =
+      (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF();
   scroll_end.event.type = WebInputEvent::GestureScrollEnd;
-  scroll_end.event.sourceDevice = blink::WebGestureDeviceTouchpad;
   scroll_end.event.resendingPluginId = -1;
+  scroll_end.event.data.scrollEnd.synthetic = synthetic;
+  scroll_end.event.data.scrollEnd.inertial =
+      update_event.data.scrollUpdate.inertial;
   scroll_end.event.data.scrollEnd.deltaUnits =
       update_event.data.scrollUpdate.deltaUnits;
-  scroll_end.event.x = update_event.x;
-  scroll_end.event.y = update_event.y;
-  scroll_end.event.globalX = update_event.globalX;
-  scroll_end.event.globalY = update_event.globalY;
 
-  SendGesture(scroll_end);
+  if (!synthetic) {
+    needs_scroll_begin_ = true;
+    needs_scroll_end_ = false;
+
+    if (scroll_end_timer_.IsRunning())
+      scroll_end_timer_.Reset();
+  }
+  client_->SendGestureEvent(scroll_end);
 }
 
-void MouseWheelEventQueue::SendGesture(
-    const GestureEventWithLatencyInfo& gesture) {
-  switch (gesture.event.type) {
-    case WebInputEvent::GestureScrollUpdate:
-      if (needs_scroll_begin_) {
-        GestureEventWithLatencyInfo scroll_begin(gesture);
-        scroll_begin.event.x = gesture.event.x;
-        scroll_begin.event.y = gesture.event.y;
-        scroll_begin.event.globalX = gesture.event.globalX;
-        scroll_begin.event.globalY = gesture.event.globalY;
-        scroll_begin.event.type = WebInputEvent::GestureScrollBegin;
-        scroll_begin.event.data.scrollBegin.deltaXHint =
-            gesture.event.data.scrollUpdate.deltaX;
-        scroll_begin.event.data.scrollBegin.deltaYHint =
-            gesture.event.data.scrollUpdate.deltaY;
-        scroll_begin.event.data.scrollBegin.targetViewport = false;
-        scroll_begin.event.data.scrollBegin.deltaHintUnits =
-            gesture.event.data.scrollUpdate.deltaUnits;
+void MouseWheelEventQueue::SendScrollBegin(
+    const GestureEventWithLatencyInfo& gesture_update,
+    bool synthetic) {
+  DCHECK((synthetic && !needs_scroll_begin_) || needs_scroll_begin_);
 
-        SendGesture(scroll_begin);
-      }
-      if (scroll_end_timer_.IsRunning()) {
-        scroll_end_timer_.Reset();
-      } else {
-        scroll_end_timer_.Start(
-            FROM_HERE,
-            base::TimeDelta::FromMilliseconds(scroll_transaction_ms_),
-            base::Bind(&MouseWheelEventQueue::SendScrollEnd,
-                       base::Unretained(this), gesture.event));
-      }
-      break;
-    case WebInputEvent::GestureScrollEnd:
-      needs_scroll_begin_ = true;
-      break;
-    case WebInputEvent::GestureScrollBegin:
-      needs_scroll_begin_ = false;
-      break;
-    default:
-      return;
-  }
-  client_->SendGestureEvent(gesture);
+  GestureEventWithLatencyInfo scroll_begin(gesture_update);
+  scroll_begin.event.type = WebInputEvent::GestureScrollBegin;
+  scroll_begin.event.data.scrollBegin.synthetic = synthetic;
+  scroll_begin.event.data.scrollBegin.inertial =
+      gesture_update.event.data.scrollUpdate.inertial;
+  scroll_begin.event.data.scrollBegin.deltaXHint =
+      gesture_update.event.data.scrollUpdate.deltaX;
+  scroll_begin.event.data.scrollBegin.deltaYHint =
+      gesture_update.event.data.scrollUpdate.deltaY;
+  scroll_begin.event.data.scrollBegin.targetViewport = false;
+  scroll_begin.event.data.scrollBegin.deltaHintUnits =
+      gesture_update.event.data.scrollUpdate.deltaUnits;
+
+  needs_scroll_begin_ = false;
+  needs_scroll_end_ = true;
+  client_->SendGestureEvent(scroll_begin);
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/input/mouse_wheel_event_queue.h b/content/browser/renderer_host/input/mouse_wheel_event_queue.h
index b5ad7f2..a224b9e 100644
--- a/content/browser/renderer_host/input/mouse_wheel_event_queue.h
+++ b/content/browser/renderer_host/input/mouse_wheel_event_queue.h
@@ -17,7 +17,9 @@
 
 // The duration in which a ScrollEnd will be sent after the last
 // ScrollUpdate was sent for wheel based gesture scrolls.
-const int64_t kDefaultWheelScrollTransactionMs = 100;
+// Set the default wheel transaction to 0ms until
+// crbug.com/526463 is fully implemented.
+const int64_t kDefaultWheelScrollTransactionMs = 0;  // 100;
 
 class QueuedWebMouseWheelEvent;
 
@@ -76,16 +78,24 @@
 
  private:
   void TryForwardNextEventToRenderer();
-  void SendScrollEnd(blink::WebGestureEvent update_event);
-  void SendGesture(const GestureEventWithLatencyInfo& gesture);
+  void SendScrollEnd(blink::WebGestureEvent update_event, bool synthetic);
+  void SendScrollBegin(const GestureEventWithLatencyInfo& gesture_update,
+                       bool synthetic);
 
   MouseWheelEventQueueClient* client_;
-  bool needs_scroll_begin_;
   base::OneShotTimer scroll_end_timer_;
 
   typedef std::deque<QueuedWebMouseWheelEvent*> WheelEventQueue;
   WheelEventQueue wheel_queue_;
   scoped_ptr<QueuedWebMouseWheelEvent> event_sent_for_gesture_ack_;
+
+  // True if a non-synthetic GSB needs to be sent before a GSU is sent.
+  bool needs_scroll_begin_;
+
+  // True if a non-synthetic GSE needs to be sent because a non-synthetic
+  // GSB has been sent in the past.
+  bool needs_scroll_end_;
+
   bool send_gestures_;
   int64_t scroll_transaction_ms_;
   blink::WebGestureDevice scrolling_device_;
diff --git a/content/browser/renderer_host/input/mouse_wheel_event_queue_unittest.cc b/content/browser/renderer_host/input/mouse_wheel_event_queue_unittest.cc
index f9e10a901..f14b6e6 100644
--- a/content/browser/renderer_host/input/mouse_wheel_event_queue_unittest.cc
+++ b/content/browser/renderer_host/input/mouse_wheel_event_queue_unittest.cc
@@ -34,6 +34,81 @@
   return base::TimeDelta::FromMilliseconds(kScrollEndTimeoutMs);
 }
 
+#define EXPECT_GESTURE_SCROLL_BEGIN_IMPL(event)              \
+  EXPECT_EQ(WebInputEvent::GestureScrollBegin, event->type); \
+  EXPECT_EQ(kWheelScrollX, event->x);                        \
+  EXPECT_EQ(kWheelScrollY, event->y);                        \
+  EXPECT_EQ(kWheelScrollGlobalX, event->globalX);            \
+  EXPECT_EQ(kWheelScrollGlobalY, event->globalY);            \
+  EXPECT_EQ(scroll_units, event->data.scrollBegin.deltaHintUnits);
+
+#define EXPECT_GESTURE_SCROLL_BEGIN(event)         \
+  EXPECT_GESTURE_SCROLL_BEGIN_IMPL(event);         \
+  EXPECT_FALSE(event->data.scrollBegin.synthetic); \
+  EXPECT_FALSE(event->data.scrollBegin.inertial);
+
+#define EXPECT_SYNTHETIC_GESTURE_SCROLL_BEGIN(event) \
+  EXPECT_GESTURE_SCROLL_BEGIN_IMPL(event);           \
+  EXPECT_TRUE(event->data.scrollBegin.synthetic);    \
+  EXPECT_FALSE(event->data.scrollBegin.inertial);
+
+#define EXPECT_INERTIAL_GESTURE_SCROLL_BEGIN(event) \
+  EXPECT_GESTURE_SCROLL_BEGIN_IMPL(event);          \
+  EXPECT_FALSE(event->data.scrollBegin.synthetic);  \
+  EXPECT_TRUE(event->data.scrollBegin.inertial);
+
+#define EXPECT_SYNTHETIC_INERTIAL_GESTURE_SCROLL_BEGIN(event) \
+  EXPECT_GESTURE_SCROLL_BEGIN_IMPL(event);                    \
+  EXPECT_TRUE(event->data.scrollBegin.synthetic);             \
+  EXPECT_TRUE(event->data.scrollBegin.inertial);
+
+#define EXPECT_GESTURE_SCROLL_UPDATE_IMPL(event)                \
+  EXPECT_EQ(WebInputEvent::GestureScrollUpdate, event->type);   \
+  EXPECT_EQ(scroll_units, event->data.scrollUpdate.deltaUnits); \
+  EXPECT_EQ(kWheelScrollX, event->x);                           \
+  EXPECT_EQ(kWheelScrollY, event->y);                           \
+  EXPECT_EQ(kWheelScrollGlobalX, event->globalX);               \
+  EXPECT_EQ(kWheelScrollGlobalY, event->globalY);
+
+#define EXPECT_GESTURE_SCROLL_UPDATE(event) \
+  EXPECT_GESTURE_SCROLL_UPDATE_IMPL(event); \
+  EXPECT_FALSE(event->data.scrollUpdate.inertial);
+
+#define EXPECT_INERTIAL_GESTURE_SCROLL_UPDATE(event) \
+  EXPECT_GESTURE_SCROLL_UPDATE_IMPL(event);          \
+  EXPECT_TRUE(event->data.scrollUpdate.inertial);
+
+#define EXPECT_GESTURE_SCROLL_END_IMPL(event)                \
+  EXPECT_EQ(WebInputEvent::GestureScrollEnd, event->type);   \
+  EXPECT_EQ(scroll_units, event->data.scrollEnd.deltaUnits); \
+  EXPECT_EQ(kWheelScrollX, event->x);                        \
+  EXPECT_EQ(kWheelScrollY, event->y);                        \
+  EXPECT_EQ(kWheelScrollGlobalX, event->globalX);            \
+  EXPECT_EQ(kWheelScrollGlobalY, event->globalY);
+
+#define EXPECT_GESTURE_SCROLL_END(event)         \
+  EXPECT_GESTURE_SCROLL_END_IMPL(event);         \
+  EXPECT_FALSE(event->data.scrollEnd.synthetic); \
+  EXPECT_FALSE(event->data.scrollEnd.inertial);
+
+#define EXPECT_SYNTHETIC_GESTURE_SCROLL_END(event) \
+  EXPECT_GESTURE_SCROLL_END_IMPL(event);           \
+  EXPECT_TRUE(event->data.scrollEnd.synthetic);    \
+  EXPECT_FALSE(event->data.scrollEnd.inertial);
+
+#define EXPECT_INERTIAL_GESTURE_SCROLL_END(event) \
+  EXPECT_GESTURE_SCROLL_END_IMPL(event);          \
+  EXPECT_FALSE(event->data.scrollEnd.synthetic);  \
+  EXPECT_TRUE(event->data.scrollEnd.inertial);
+
+#define EXPECT_SYNTHETIC_INERTIAL_GESTURE_SCROLL_END(event) \
+  EXPECT_GESTURE_SCROLL_END_IMPL(event);                    \
+  EXPECT_TRUE(event->data.scrollEnd.synthetic);             \
+  EXPECT_TRUE(event->data.scrollEnd.inertial);
+
+#define EXPECT_MOUSE_WHEEL(event) \
+  EXPECT_EQ(WebInputEvent::MouseWheel, event->type);
+
 }  // namespace
 
 class MouseWheelEventQueueTest : public testing::Test,
@@ -50,12 +125,17 @@
   // MouseWheelEventQueueClient
   void SendMouseWheelEventImmediately(
       const MouseWheelEventWithLatencyInfo& event) override {
-    sent_events_.push_back(event.event);
+    WebMouseWheelEvent* cloned_event = new WebMouseWheelEvent();
+    scoped_ptr<WebInputEvent> cloned_event_holder(cloned_event);
+    *cloned_event = event.event;
+    sent_events_.push_back(std::move(cloned_event_holder));
   }
 
   void SendGestureEvent(const GestureEventWithLatencyInfo& event) override {
-    sent_events_.push_back(event.event);
-    sent_gesture_events_.push_back(event.event);
+    WebGestureEvent* cloned_event = new WebGestureEvent();
+    scoped_ptr<WebInputEvent> cloned_event_holder(cloned_event);
+    *cloned_event = event.event;
+    sent_events_.push_back(std::move(cloned_event_holder));
   }
 
   void OnMouseWheelEventAck(const MouseWheelEventWithLatencyInfo& event,
@@ -75,10 +155,15 @@
 
   bool event_in_flight() const { return queue_->event_in_flight(); }
 
-  std::vector<WebInputEvent>& all_sent_events() { return sent_events_; }
+  std::vector<scoped_ptr<WebInputEvent>>& all_sent_events() {
+    return sent_events_;
+  }
 
-  std::vector<WebGestureEvent>& sent_gesture_events() {
-    return sent_gesture_events_;
+  const scoped_ptr<WebInputEvent>& sent_input_event(size_t index) {
+    return sent_events_[index];
+  }
+  const WebGestureEvent* sent_gesture_event(size_t index) {
+    return static_cast<WebGestureEvent*>(sent_events_[index].get());
   }
 
   const WebMouseWheelEvent& acked_event() const { return last_acked_event_; }
@@ -86,7 +171,6 @@
   size_t GetAndResetSentEventCount() {
     size_t count = sent_events_.size();
     sent_events_.clear();
-    sent_gesture_events_.clear();
     return count;
   }
 
@@ -113,6 +197,24 @@
             x, y, global_x, global_y, dX, dY, modifiers, high_precision)));
   }
 
+  void SendMouseWheelWithPhase(
+      float x,
+      float y,
+      float global_x,
+      float global_y,
+      float dX,
+      float dY,
+      int modifiers,
+      bool high_precision,
+      blink::WebMouseWheelEvent::Phase phase,
+      blink::WebMouseWheelEvent::Phase momentum_phase) {
+    WebMouseWheelEvent event = SyntheticWebMouseWheelEventBuilder::Build(
+        x, y, global_x, global_y, dX, dY, modifiers, high_precision);
+    event.phase = phase;
+    event.momentumPhase = momentum_phase;
+    queue_->QueueEvent(MouseWheelEventWithLatencyInfo(event));
+  }
+
   void SendGestureEvent(WebInputEvent::Type type) {
     WebGestureEvent event;
     event.type = type;
@@ -137,7 +239,8 @@
     EXPECT_TRUE(event_in_flight());
     EXPECT_EQ(1U, GetAndResetSentEventCount());
 
-    // The second mouse wheel should not be sent since one is already in queue.
+    // The second mouse wheel should not be sent since one is already in
+    // queue.
     SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
                    kWheelScrollGlobalY, 5, 5, 0, high_precision);
     EXPECT_EQ(1U, queued_event_count());
@@ -152,36 +255,104 @@
     EXPECT_EQ(WebInputEvent::MouseWheel, acked_event().type);
     EXPECT_EQ(1U, GetAndResetAckedEventCount());
     EXPECT_EQ(3U, all_sent_events().size());
-    EXPECT_EQ(WebInputEvent::GestureScrollBegin, all_sent_events()[0].type);
-    EXPECT_EQ(scroll_units,
-              sent_gesture_events()[0].data.scrollBegin.deltaHintUnits);
-    EXPECT_EQ(kWheelScrollX, sent_gesture_events()[0].x);
-    EXPECT_EQ(kWheelScrollY, sent_gesture_events()[0].y);
-    EXPECT_EQ(kWheelScrollGlobalX, sent_gesture_events()[0].globalX);
-    EXPECT_EQ(kWheelScrollGlobalY, sent_gesture_events()[0].globalY);
-    EXPECT_EQ(WebInputEvent::GestureScrollUpdate, all_sent_events()[1].type);
-    EXPECT_EQ(scroll_units,
-              sent_gesture_events()[1].data.scrollUpdate.deltaUnits);
-    EXPECT_EQ(kWheelScrollX, sent_gesture_events()[1].x);
-    EXPECT_EQ(kWheelScrollY, sent_gesture_events()[1].y);
-    EXPECT_EQ(kWheelScrollGlobalX, sent_gesture_events()[1].globalX);
-    EXPECT_EQ(kWheelScrollGlobalY, sent_gesture_events()[1].globalY);
-    EXPECT_EQ(WebInputEvent::MouseWheel, all_sent_events()[2].type);
+    EXPECT_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
+    EXPECT_GESTURE_SCROLL_UPDATE(sent_gesture_event(1));
+    EXPECT_MOUSE_WHEEL(sent_input_event(2));
     EXPECT_EQ(3U, GetAndResetSentEventCount());
 
     RunTasksAndWait(DefaultScrollEndTimeoutDelay() * 2);
     EXPECT_EQ(1U, all_sent_events().size());
-    EXPECT_EQ(WebInputEvent::GestureScrollEnd, all_sent_events()[0].type);
-    EXPECT_EQ(scroll_units, sent_gesture_events()[0].data.scrollEnd.deltaUnits);
-    EXPECT_EQ(kWheelScrollX, sent_gesture_events()[0].x);
-    EXPECT_EQ(kWheelScrollY, sent_gesture_events()[0].y);
-    EXPECT_EQ(kWheelScrollGlobalX, sent_gesture_events()[0].globalX);
-    EXPECT_EQ(kWheelScrollGlobalY, sent_gesture_events()[0].globalY);
+    EXPECT_GESTURE_SCROLL_END(sent_gesture_event(0));
+  }
+
+  void PhaseGestureSendingTest(bool high_precision) {
+    const WebGestureEvent::ScrollUnits scroll_units =
+        high_precision ? WebGestureEvent::PrecisePixels
+                       : WebGestureEvent::Pixels;
+
+    SendMouseWheelWithPhase(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+                            kWheelScrollGlobalY, 1, 1, 0, high_precision,
+                            WebMouseWheelEvent::PhaseBegan,
+                            WebMouseWheelEvent::PhaseNone);
+    EXPECT_EQ(1U, GetAndResetSentEventCount());
+    SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+    EXPECT_EQ(3U, all_sent_events().size());
+    EXPECT_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
+    EXPECT_GESTURE_SCROLL_UPDATE(sent_gesture_event(1));
+    EXPECT_SYNTHETIC_GESTURE_SCROLL_END(sent_gesture_event(2));
+    EXPECT_EQ(3U, GetAndResetSentEventCount());
+
+    SendMouseWheelWithPhase(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+                            kWheelScrollGlobalY, 5, 5, 0, high_precision,
+                            WebMouseWheelEvent::PhaseChanged,
+                            WebMouseWheelEvent::PhaseNone);
+    EXPECT_EQ(1U, GetAndResetSentEventCount());
+    SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+    EXPECT_EQ(3U, all_sent_events().size());
+    EXPECT_SYNTHETIC_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
+    EXPECT_GESTURE_SCROLL_UPDATE(sent_gesture_event(1));
+    EXPECT_SYNTHETIC_GESTURE_SCROLL_END(sent_gesture_event(2));
+    EXPECT_EQ(3U, GetAndResetSentEventCount());
+
+    SendMouseWheelWithPhase(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+                            kWheelScrollGlobalY, 0, 0, 0, high_precision,
+                            WebMouseWheelEvent::PhaseEnded,
+                            WebMouseWheelEvent::PhaseNone);
+    EXPECT_EQ(1U, GetAndResetSentEventCount());
+    SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+    EXPECT_EQ(2U, all_sent_events().size());
+    EXPECT_SYNTHETIC_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
+    EXPECT_GESTURE_SCROLL_END(sent_gesture_event(1));
+    EXPECT_EQ(2U, GetAndResetSentEventCount());
+
+    // Send a double phase end; OSX does it consistently.
+    SendMouseWheelWithPhase(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+                            kWheelScrollGlobalY, 0, 0, 0, high_precision,
+                            WebMouseWheelEvent::PhaseEnded,
+                            WebMouseWheelEvent::PhaseNone);
+    EXPECT_EQ(1U, GetAndResetSentEventCount());
+    SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+    EXPECT_EQ(0U, all_sent_events().size());
+    EXPECT_EQ(0U, GetAndResetSentEventCount());
+
+    SendMouseWheelWithPhase(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+                            kWheelScrollGlobalY, 5, 5, 0, high_precision,
+                            WebMouseWheelEvent::PhaseNone,
+                            WebMouseWheelEvent::PhaseBegan);
+    EXPECT_EQ(1U, GetAndResetSentEventCount());
+    SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+    EXPECT_EQ(3U, all_sent_events().size());
+    EXPECT_INERTIAL_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
+    EXPECT_INERTIAL_GESTURE_SCROLL_UPDATE(sent_gesture_event(1));
+    EXPECT_SYNTHETIC_INERTIAL_GESTURE_SCROLL_END(sent_gesture_event(2));
+    EXPECT_EQ(3U, GetAndResetSentEventCount());
+
+    SendMouseWheelWithPhase(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+                            kWheelScrollGlobalY, 5, 5, 0, high_precision,
+                            WebMouseWheelEvent::PhaseNone,
+                            WebMouseWheelEvent::PhaseChanged);
+    EXPECT_EQ(1U, GetAndResetSentEventCount());
+    SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+    EXPECT_EQ(3U, all_sent_events().size());
+    EXPECT_SYNTHETIC_INERTIAL_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
+    EXPECT_INERTIAL_GESTURE_SCROLL_UPDATE(sent_gesture_event(1));
+    EXPECT_SYNTHETIC_INERTIAL_GESTURE_SCROLL_END(sent_gesture_event(2));
+    EXPECT_EQ(3U, GetAndResetSentEventCount());
+
+    SendMouseWheelWithPhase(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+                            kWheelScrollGlobalY, 0, 0, 0, high_precision,
+                            WebMouseWheelEvent::PhaseNone,
+                            WebMouseWheelEvent::PhaseEnded);
+    EXPECT_EQ(1U, GetAndResetSentEventCount());
+    SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+    EXPECT_EQ(2U, all_sent_events().size());
+    EXPECT_SYNTHETIC_INERTIAL_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
+    EXPECT_INERTIAL_GESTURE_SCROLL_END(sent_gesture_event(1));
+    EXPECT_EQ(2U, GetAndResetSentEventCount());
   }
 
   scoped_ptr<MouseWheelEventQueue> queue_;
-  std::vector<WebInputEvent> sent_events_;
-  std::vector<WebGestureEvent> sent_gesture_events_;
+  std::vector<scoped_ptr<WebInputEvent>> sent_events_;
   size_t acked_event_count_;
   InputEventAckState last_acked_event_state_;
   base::MessageLoopForUI message_loop_;
@@ -230,8 +401,21 @@
   GestureSendingTest(false);
 }
 
+TEST_F(MouseWheelEventQueueTest, GestureSendingWithPhaseInformation) {
+  SetUpForGestureTesting(true);
+  PhaseGestureSendingTest(false);
+}
+
+TEST_F(MouseWheelEventQueueTest,
+       GestureSendingWithPhaseInformationPrecisePixels) {
+  SetUpForGestureTesting(true);
+  PhaseGestureSendingTest(true);
+}
+
 TEST_F(MouseWheelEventQueueTest, GestureSendingInterrupted) {
   SetUpForGestureTesting(true);
+  const WebGestureEvent::ScrollUnits scroll_units = WebGestureEvent::Pixels;
+
   SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
                  kWheelScrollGlobalY, 1, 1, 0, false);
   EXPECT_EQ(0U, queued_event_count());
@@ -245,14 +429,14 @@
   EXPECT_EQ(WebInputEvent::MouseWheel, acked_event().type);
   EXPECT_EQ(1U, GetAndResetAckedEventCount());
   EXPECT_EQ(2U, all_sent_events().size());
-  EXPECT_EQ(WebInputEvent::GestureScrollBegin, all_sent_events()[0].type);
-  EXPECT_EQ(WebInputEvent::GestureScrollUpdate, all_sent_events()[1].type);
+  EXPECT_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
+  EXPECT_GESTURE_SCROLL_UPDATE(sent_gesture_event(1));
   EXPECT_EQ(2U, GetAndResetSentEventCount());
 
   // Ensure that a gesture scroll begin terminates the current scroll event.
   SendGestureEvent(WebInputEvent::GestureScrollBegin);
   EXPECT_EQ(1U, all_sent_events().size());
-  EXPECT_EQ(WebInputEvent::GestureScrollEnd, all_sent_events()[0].type);
+  EXPECT_GESTURE_SCROLL_END(sent_gesture_event(0));
   EXPECT_EQ(1U, GetAndResetSentEventCount());
 
   SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
@@ -286,8 +470,8 @@
   EXPECT_EQ(WebInputEvent::MouseWheel, acked_event().type);
   EXPECT_EQ(1U, GetAndResetAckedEventCount());
   EXPECT_EQ(2U, all_sent_events().size());
-  EXPECT_EQ(WebInputEvent::GestureScrollBegin, all_sent_events()[0].type);
-  EXPECT_EQ(WebInputEvent::GestureScrollUpdate, all_sent_events()[1].type);
+  EXPECT_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
+  EXPECT_GESTURE_SCROLL_UPDATE(sent_gesture_event(1));
   EXPECT_EQ(2U, GetAndResetSentEventCount());
 }
 
diff --git a/content/browser/renderer_host/input/non_blocking_event_browsertest.cc b/content/browser/renderer_host/input/non_blocking_event_browsertest.cc
index c6819140..abed148 100644
--- a/content/browser/renderer_host/input/non_blocking_event_browsertest.cc
+++ b/content/browser/renderer_host/input/non_blocking_event_browsertest.cc
@@ -113,7 +113,7 @@
     EXPECT_EQ(1000, scrollHeight);
 
     scoped_refptr<FrameWatcher> frame_watcher(new FrameWatcher());
-    GetWidgetHost()->GetProcess()->AddFilter(frame_watcher.get());
+    frame_watcher->AttachTo(shell()->web_contents());
     scoped_refptr<InputMsgWatcher> input_msg_watcher(
         new InputMsgWatcher(GetWidgetHost(), blink::WebInputEvent::MouseWheel));
 
@@ -138,7 +138,7 @@
     EXPECT_EQ(1000, scrollHeight);
 
     scoped_refptr<FrameWatcher> frame_watcher(new FrameWatcher());
-    GetWidgetHost()->GetProcess()->AddFilter(frame_watcher.get());
+    frame_watcher->AttachTo(shell()->web_contents());
 
     SyntheticSmoothScrollGestureParams params;
     params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT;
@@ -162,18 +162,12 @@
   DISALLOW_COPY_AND_ASSIGN(NonBlockingEventBrowserTest);
 };
 
-// Disabled on MacOS because it doesn't support wheel gestures
-// just yet.
-#if defined(OS_MACOSX)
-#define MAYBE_MouseWheel DISABLED_MouseWheel
-#else
 // Also appears to be flaky under TSan. crbug.com/588199
 #if defined(THREAD_SANITIZER)
 #define MAYBE_MouseWheel DISABLED_MouseWheel
 #else
 #define MAYBE_MouseWheel MouseWheel
 #endif
-#endif
 IN_PROC_BROWSER_TEST_F(NonBlockingEventBrowserTest, MAYBE_MouseWheel) {
   LoadURL();
   DoWheelScroll();
diff --git a/content/browser/renderer_host/input/touch_action_browsertest.cc b/content/browser/renderer_host/input/touch_action_browsertest.cc
index 72c8bc9..a1a9e837 100644
--- a/content/browser/renderer_host/input/touch_action_browsertest.cc
+++ b/content/browser/renderer_host/input/touch_action_browsertest.cc
@@ -94,7 +94,7 @@
 
     RenderWidgetHostImpl* host = GetWidgetHost();
     scoped_refptr<FrameWatcher> frame_watcher(new FrameWatcher());
-    host->GetProcess()->AddFilter(frame_watcher.get());
+    frame_watcher->AttachTo(shell()->web_contents());
     host->GetView()->SetSize(gfx::Size(400, 400));
 
     base::string16 ready_title(base::ASCIIToUTF16("ready"));
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index ffa20688..53c60bf 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1403,6 +1403,7 @@
     switches::kBlinkSettings,
     switches::kDefaultTileWidth,
     switches::kDefaultTileHeight,
+    switches::kDisable2dCanvasImageChromium,
     switches::kDisable3DAPIs,
     switches::kDisableAcceleratedJpegDecoding,
     switches::kDisableAcceleratedVideoDecode,
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc
index ff0a359..9c739b6 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -203,7 +203,7 @@
   bool lose_context_when_out_of_memory = false;
   scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context(
       new WebGraphicsContext3DCommandBufferImpl(
-          0,  // offscreen
+          gpu::kNullSurfaceHandle,  // offscreen
           url, gpu_channel_host.get(), attrs, lose_context_when_out_of_memory,
           limits, nullptr));
   context->SetContextType(BROWSER_OFFSCREEN_MAINTHREAD_CONTEXT);
diff --git a/content/browser/renderer_host/sandbox_ipc_linux.cc b/content/browser/renderer_host/sandbox_ipc_linux.cc
index 186c4f4c..bbea7e9 100644
--- a/content/browser/renderer_host/sandbox_ipc_linux.cc
+++ b/content/browser/renderer_host/sandbox_ipc_linux.cc
@@ -121,7 +121,7 @@
   }
 
   if (blink_platform_impl_)
-    blink::shutdownWithoutV8();
+    blink::Platform::shutdown();
 
   VLOG(1) << "SandboxIPCHandler stopping.";
 }
@@ -447,7 +447,7 @@
   if (blink_platform_impl_)
     return;
   blink_platform_impl_.reset(new BlinkPlatformImpl);
-  blink::initializeWithoutV8(blink_platform_impl_.get());
+  blink::Platform::initialize(blink_platform_impl_.get());
 }
 
 }  // namespace content
diff --git a/content/browser/service_worker/service_worker_dispatcher_host.cc b/content/browser/service_worker/service_worker_dispatcher_host.cc
index 6f756817..ec8c364 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host.cc
+++ b/content/browser/service_worker/service_worker_dispatcher_host.cc
@@ -245,7 +245,7 @@
       return handle;
     }
   }
-  return NULL;
+  return nullptr;
 }
 
 ServiceWorkerRegistrationHandle*
@@ -336,11 +336,9 @@
     return;
   }
 
-  TRACE_EVENT_ASYNC_BEGIN2("ServiceWorker",
-                           "ServiceWorkerDispatcherHost::RegisterServiceWorker",
-                           request_id,
-                           "Pattern", pattern.spec(),
-                           "Script URL", script_url.spec());
+  TRACE_EVENT_ASYNC_BEGIN2(
+      "ServiceWorker", "ServiceWorkerDispatcherHost::RegisterServiceWorker",
+      request_id, "Scope", pattern.spec(), "Script URL", script_url.spec());
   GetContext()->RegisterServiceWorker(
       pattern,
       script_url,
@@ -426,6 +424,9 @@
     return;
   }
 
+  TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
+                           "ServiceWorkerDispatcherHost::UpdateServiceWorker",
+                           request_id, "Scope", registration->pattern().spec());
   GetContext()->UpdateServiceWorker(
       registration, false /* force_bypass_cache */,
       false /* skip_script_comparison */, provider_host,
@@ -495,7 +496,7 @@
 
   TRACE_EVENT_ASYNC_BEGIN1(
       "ServiceWorker", "ServiceWorkerDispatcherHost::UnregisterServiceWorker",
-      request_id, "Pattern", registration->pattern().spec());
+      request_id, "Scope", registration->pattern().spec());
   GetContext()->UnregisterServiceWorker(
       registration->pattern(),
       base::Bind(&ServiceWorkerDispatcherHost::UnregistrationComplete, this,
@@ -507,11 +508,10 @@
     int request_id,
     int provider_id,
     const GURL& document_url) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   TRACE_EVENT0("ServiceWorker",
                "ServiceWorkerDispatcherHost::OnGetRegistration");
 
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
   if (!GetContext()) {
     Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
         thread_id, request_id, blink::WebServiceWorkerError::ErrorTypeAbort,
@@ -565,12 +565,9 @@
     return;
   }
 
-  TRACE_EVENT_ASYNC_BEGIN1(
-      "ServiceWorker",
-      "ServiceWorkerDispatcherHost::GetRegistration",
-      request_id,
-      "Document URL", document_url.spec());
-
+  TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
+                           "ServiceWorkerDispatcherHost::GetRegistration",
+                           request_id, "Document URL", document_url.spec());
   GetContext()->storage()->FindRegistrationForDocument(
       document_url,
       base::Bind(&ServiceWorkerDispatcherHost::GetRegistrationComplete,
@@ -584,6 +581,8 @@
                                                      int request_id,
                                                      int provider_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  TRACE_EVENT0("ServiceWorker",
+               "ServiceWorkerDispatcherHost::OnGetRegistrations");
 
   if (!GetContext()) {
     Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationsError(
@@ -636,7 +635,6 @@
   TRACE_EVENT_ASYNC_BEGIN0("ServiceWorker",
                            "ServiceWorkerDispatcherHost::GetRegistrations",
                            request_id);
-
   GetContext()->storage()->GetRegistrationsForOrigin(
       provider_host->document_url().GetOrigin(),
       base::Bind(&ServiceWorkerDispatcherHost::GetRegistrationsComplete, this,
@@ -662,10 +660,8 @@
     return;
 
   TRACE_EVENT_ASYNC_BEGIN0(
-      "ServiceWorker",
-      "ServiceWorkerDispatcherHost::GetRegistrationForReady",
+      "ServiceWorker", "ServiceWorkerDispatcherHost::GetRegistrationForReady",
       request_id);
-
   if (!provider_host->GetRegistrationForReady(base::Bind(
           &ServiceWorkerDispatcherHost::GetRegistrationForReadyComplete,
           this, thread_id, request_id, provider_host->AsWeakPtr()))) {
@@ -872,6 +868,9 @@
     ServiceWorkerStatusCode status,
     const std::string& status_message,
     int64_t registration_id) {
+  TRACE_EVENT_ASYNC_END2(
+      "ServiceWorker", "ServiceWorkerDispatcherHost::RegisterServiceWorker",
+      request_id, "Status", status, "Registration ID", registration_id);
   if (!GetContext())
     return;
 
@@ -881,7 +880,13 @@
     return;  // The provider has already been destroyed.
 
   if (status != SERVICE_WORKER_OK) {
-    SendRegistrationError(thread_id, request_id, status, status_message);
+    base::string16 error_message;
+    blink::WebServiceWorkerError::ErrorType error_type;
+    GetServiceWorkerRegistrationStatusResponse(status, status_message,
+                                               &error_type, &error_message);
+    Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
+        thread_id, request_id, error_type,
+        base::ASCIIToUTF16(kServiceWorkerRegisterErrorPrefix) + error_message));
     return;
   }
 
@@ -896,11 +901,6 @@
 
   Send(new ServiceWorkerMsg_ServiceWorkerRegistered(
       thread_id, request_id, info, attrs));
-  TRACE_EVENT_ASYNC_END1("ServiceWorker",
-                         "ServiceWorkerDispatcherHost::RegisterServiceWorker",
-                         request_id,
-                         "Registration ID",
-                         registration_id);
 }
 
 void ServiceWorkerDispatcherHost::UpdateComplete(
@@ -910,6 +910,9 @@
     ServiceWorkerStatusCode status,
     const std::string& status_message,
     int64_t registration_id) {
+  TRACE_EVENT_ASYNC_END2(
+      "ServiceWorker", "ServiceWorkerDispatcherHost::UpdateServiceWorker",
+      request_id, "Status", status, "Registration ID", registration_id);
   if (!GetContext())
     return;
 
@@ -919,7 +922,13 @@
     return;  // The provider has already been destroyed.
 
   if (status != SERVICE_WORKER_OK) {
-    SendUpdateError(thread_id, request_id, status, status_message);
+    base::string16 error_message;
+    blink::WebServiceWorkerError::ErrorType error_type;
+    GetServiceWorkerRegistrationStatusResponse(status, status_message,
+                                               &error_type, &error_message);
+    Send(new ServiceWorkerMsg_ServiceWorkerUpdateError(
+        thread_id, request_id, error_type,
+        base::ASCIIToUTF16(kServiceWorkerUpdateErrorPrefix) + error_message));
     return;
   }
 
@@ -933,9 +942,6 @@
                                                 registration, &info, &attrs);
 
   Send(new ServiceWorkerMsg_ServiceWorkerUpdated(thread_id, request_id));
-  TRACE_EVENT_ASYNC_END1("ServiceWorker",
-                         "ServiceWorkerDispatcherHost::UpdateServiceWorker",
-                         request_id, "Registration ID", registration_id);
 }
 
 void ServiceWorkerDispatcherHost::OnWorkerReadyForInspection(
@@ -1135,19 +1141,24 @@
     int thread_id,
     int request_id,
     ServiceWorkerStatusCode status) {
+  TRACE_EVENT_ASYNC_END1("ServiceWorker",
+                         "ServiceWorkerDispatcherHost::UnregisterServiceWorker",
+                         request_id, "Status", status);
   if (status != SERVICE_WORKER_OK && status != SERVICE_WORKER_ERROR_NOT_FOUND) {
-    SendUnregistrationError(thread_id, request_id, status);
+    base::string16 error_message;
+    blink::WebServiceWorkerError::ErrorType error_type;
+    GetServiceWorkerRegistrationStatusResponse(status, std::string(),
+                                               &error_type, &error_message);
+    Send(new ServiceWorkerMsg_ServiceWorkerUnregistrationError(
+        thread_id, request_id, error_type,
+        base::ASCIIToUTF16(kServiceWorkerUnregisterErrorPrefix) +
+            error_message));
     return;
   }
   const bool is_success = (status == SERVICE_WORKER_OK);
   Send(new ServiceWorkerMsg_ServiceWorkerUnregistered(thread_id,
                                                       request_id,
                                                       is_success));
-  TRACE_EVENT_ASYNC_END1(
-      "ServiceWorker",
-      "ServiceWorkerDispatcherHost::UnregisterServiceWorker",
-      request_id,
-      "Status", status);
 }
 
 void ServiceWorkerDispatcherHost::GetRegistrationComplete(
@@ -1156,13 +1167,10 @@
     int request_id,
     ServiceWorkerStatusCode status,
     const scoped_refptr<ServiceWorkerRegistration>& registration) {
-  TRACE_EVENT_ASYNC_END1("ServiceWorker",
-                         "ServiceWorkerDispatcherHost::GetRegistration",
-                         request_id,
-                         "Registration ID",
-                         registration.get() ? registration->id()
-                             : kInvalidServiceWorkerRegistrationId);
-
+  TRACE_EVENT_ASYNC_END2(
+      "ServiceWorker", "ServiceWorkerDispatcherHost::GetRegistration",
+      request_id, "Status", status, "Registration ID",
+      registration ? registration->id() : kInvalidServiceWorkerRegistrationId);
   if (!GetContext())
     return;
 
@@ -1172,7 +1180,15 @@
     return;  // The provider has already been destroyed.
 
   if (status != SERVICE_WORKER_OK && status != SERVICE_WORKER_ERROR_NOT_FOUND) {
-    SendGetRegistrationError(thread_id, request_id, status);
+    base::string16 error_message;
+    blink::WebServiceWorkerError::ErrorType error_type;
+    GetServiceWorkerRegistrationStatusResponse(status, std::string(),
+                                               &error_type, &error_message);
+    Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
+        thread_id, request_id, error_type,
+        base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix) +
+            error_message));
+
     return;
   }
 
@@ -1197,9 +1213,9 @@
     ServiceWorkerStatusCode status,
     const std::vector<scoped_refptr<ServiceWorkerRegistration>>&
         registrations) {
-  TRACE_EVENT_ASYNC_END0("ServiceWorker",
+  TRACE_EVENT_ASYNC_END1("ServiceWorker",
                          "ServiceWorkerDispatcherHost::GetRegistrations",
-                         request_id);
+                         request_id, "Status", status);
   if (!GetContext())
     return;
 
@@ -1209,7 +1225,14 @@
     return;  // The provider has already been destroyed.
 
   if (status != SERVICE_WORKER_OK) {
-    SendGetRegistrationsError(thread_id, request_id, status);
+    base::string16 error_message;
+    blink::WebServiceWorkerError::ErrorType error_type;
+    GetServiceWorkerRegistrationStatusResponse(status, std::string(),
+                                               &error_type, &error_message);
+    Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationsError(
+        thread_id, request_id, error_type,
+        base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix) +
+            error_message));
     return;
   }
 
@@ -1239,13 +1262,10 @@
     base::WeakPtr<ServiceWorkerProviderHost> provider_host,
     ServiceWorkerRegistration* registration) {
   DCHECK(registration);
-  TRACE_EVENT_ASYNC_END1("ServiceWorker",
-                         "ServiceWorkerDispatcherHost::GetRegistrationForReady",
-                         request_id,
-                         "Registration ID",
-                         registration ? registration->id()
-                             : kInvalidServiceWorkerRegistrationId);
-
+  TRACE_EVENT_ASYNC_END1(
+      "ServiceWorker", "ServiceWorkerDispatcherHost::GetRegistrationForReady",
+      request_id, "Registration ID",
+      registration ? registration->id() : kInvalidServiceWorkerRegistrationId);
   if (!GetContext())
     return;
 
@@ -1257,75 +1277,6 @@
         thread_id, request_id, info, attrs));
 }
 
-void ServiceWorkerDispatcherHost::SendRegistrationError(
-    int thread_id,
-    int request_id,
-    ServiceWorkerStatusCode status,
-    const std::string& status_message) {
-  base::string16 error_message;
-  blink::WebServiceWorkerError::ErrorType error_type;
-  GetServiceWorkerRegistrationStatusResponse(status, status_message,
-                                             &error_type, &error_message);
-  Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
-      thread_id, request_id, error_type,
-      base::ASCIIToUTF16(kServiceWorkerRegisterErrorPrefix) + error_message));
-}
-
-void ServiceWorkerDispatcherHost::SendUpdateError(
-    int thread_id,
-    int request_id,
-    ServiceWorkerStatusCode status,
-    const std::string& status_message) {
-  base::string16 error_message;
-  blink::WebServiceWorkerError::ErrorType error_type;
-  GetServiceWorkerRegistrationStatusResponse(status, status_message,
-                                             &error_type, &error_message);
-  Send(new ServiceWorkerMsg_ServiceWorkerUpdateError(
-      thread_id, request_id, error_type,
-      base::ASCIIToUTF16(kServiceWorkerUpdateErrorPrefix) + error_message));
-}
-
-void ServiceWorkerDispatcherHost::SendUnregistrationError(
-    int thread_id,
-    int request_id,
-    ServiceWorkerStatusCode status) {
-  base::string16 error_message;
-  blink::WebServiceWorkerError::ErrorType error_type;
-  GetServiceWorkerRegistrationStatusResponse(status, std::string(), &error_type,
-                                             &error_message);
-  Send(new ServiceWorkerMsg_ServiceWorkerUnregistrationError(
-      thread_id, request_id, error_type,
-      base::ASCIIToUTF16(kServiceWorkerUnregisterErrorPrefix) + error_message));
-}
-
-void ServiceWorkerDispatcherHost::SendGetRegistrationError(
-    int thread_id,
-    int request_id,
-    ServiceWorkerStatusCode status) {
-  base::string16 error_message;
-  blink::WebServiceWorkerError::ErrorType error_type;
-  GetServiceWorkerRegistrationStatusResponse(status, std::string(), &error_type,
-                                             &error_message);
-  Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
-      thread_id, request_id, error_type,
-      base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix) +
-          error_message));
-}
-
-void ServiceWorkerDispatcherHost::SendGetRegistrationsError(
-    int thread_id,
-    int request_id,
-    ServiceWorkerStatusCode status) {
-  base::string16 error_message;
-  blink::WebServiceWorkerError::ErrorType error_type;
-  GetServiceWorkerRegistrationStatusResponse(status, std::string(), &error_type,
-                                             &error_message);
-  Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationsError(
-      thread_id, request_id, error_type,
-      base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix) +
-          error_message));
-}
-
 ServiceWorkerContextCore* ServiceWorkerDispatcherHost::GetContext() {
   if (!context_wrapper_.get())
     return nullptr;
diff --git a/content/browser/service_worker/service_worker_dispatcher_host.h b/content/browser/service_worker/service_worker_dispatcher_host.h
index b5b1d06d1..4b1fb949 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host.h
+++ b/content/browser/service_worker/service_worker_dispatcher_host.h
@@ -171,25 +171,21 @@
                             ServiceWorkerStatusCode status,
                             const std::string& status_message,
                             int64_t registration_id);
-
   void UpdateComplete(int thread_id,
                       int provider_id,
                       int request_id,
                       ServiceWorkerStatusCode status,
                       const std::string& status_message,
                       int64_t registration_id);
-
   void UnregistrationComplete(int thread_id,
                               int request_id,
                               ServiceWorkerStatusCode status);
-
   void GetRegistrationComplete(
       int thread_id,
       int provider_id,
       int request_id,
       ServiceWorkerStatusCode status,
       const scoped_refptr<ServiceWorkerRegistration>& registration);
-
   void GetRegistrationsComplete(
       int thread_id,
       int provider_id,
@@ -197,38 +193,15 @@
       ServiceWorkerStatusCode status,
       const std::vector<scoped_refptr<ServiceWorkerRegistration>>&
           registrations);
-
   void GetRegistrationForReadyComplete(
       int thread_id,
       int request_id,
       base::WeakPtr<ServiceWorkerProviderHost> provider_host,
       ServiceWorkerRegistration* registration);
 
-  void SendRegistrationError(int thread_id,
-                             int request_id,
-                             ServiceWorkerStatusCode status,
-                             const std::string& status_message);
-
-  void SendUpdateError(int thread_id,
-                       int request_id,
-                       ServiceWorkerStatusCode status,
-                       const std::string& status_message);
-
-  void SendUnregistrationError(int thread_id,
-                               int request_id,
-                               ServiceWorkerStatusCode status);
-
-  void SendGetRegistrationError(int thread_id,
-                                int request_id,
-                                ServiceWorkerStatusCode status);
-
-  void SendGetRegistrationsError(int thread_id,
-                                 int request_id,
-                                 ServiceWorkerStatusCode status);
-
   ServiceWorkerContextCore* GetContext();
 
-  int render_process_id_;
+  const int render_process_id_;
   MessagePortMessageFilter* const message_port_message_filter_;
   ResourceContext* resource_context_;
   scoped_refptr<ServiceWorkerContextWrapper> context_wrapper_;
diff --git a/content/browser/web_contents/aura/shadow_layer_delegate.cc b/content/browser/web_contents/aura/shadow_layer_delegate.cc
index 067a147..a4a1660 100644
--- a/content/browser/web_contents/aura/shadow_layer_delegate.cc
+++ b/content/browser/web_contents/aura/shadow_layer_delegate.cc
@@ -42,14 +42,12 @@
   points[0].iset(0, 0);
   points[1].iset(kShadowThick, 0);
 
-  skia::RefPtr<SkShader> shader = skia::AdoptRef(
-      SkGradientShader::CreateLinear(points, kShadowColors, NULL,
-          arraysize(points), SkShader::kRepeat_TileMode));
-
   gfx::Rect paint_rect = gfx::Rect(0, 0, kShadowThick,
                                    layer_->bounds().height());
   SkPaint paint;
-  paint.setShader(shader.get());
+  paint.setShader(SkGradientShader::MakeLinear(points, kShadowColors, NULL,
+                                               arraysize(points),
+                                               SkShader::kRepeat_TileMode));
   ui::PaintRecorder recorder(context, layer_->size());
   recorder.canvas()->DrawRect(paint_rect, paint);
 }
diff --git a/content/browser/web_contents/web_contents_view_aura_browsertest.cc b/content/browser/web_contents/web_contents_view_aura_browsertest.cc
index 8d08134b..b896035 100644
--- a/content/browser/web_contents/web_contents_view_aura_browsertest.cc
+++ b/content/browser/web_contents/web_contents_view_aura_browsertest.cc
@@ -272,7 +272,7 @@
     controller->SetScreenshotManager(make_scoped_ptr(screenshot_manager_));
 
     frame_watcher_ = new FrameWatcher();
-    GetRenderWidgetHost()->GetProcess()->AddFilter(frame_watcher_.get());
+    frame_watcher_->AttachTo(shell()->web_contents());
   }
 
   void SetUpCommandLine(base::CommandLine* cmd) override {
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index b627ef1..1196ffe 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -107,6 +107,17 @@
   if (command_line.HasSwitch(switches::kEnableWebGLDraftExtensions))
     WebRuntimeFeatures::enableWebGLDraftExtensions(true);
 
+#if defined(OS_MACOSX)
+  bool enable_canvas_2d_image_chromium = command_line.HasSwitch(
+      switches::kEnableGpuMemoryBufferCompositorResources) &&
+      !command_line.HasSwitch(switches::kDisable2dCanvasImageChromium) &&
+      !command_line.HasSwitch(switches::kDisableGpu);
+#else
+  bool enable_canvas_2d_image_chromium = false;
+#endif
+  WebRuntimeFeatures::enableCanvas2dImageChromium(
+      enable_canvas_2d_image_chromium);
+
   if (command_line.HasSwitch(switches::kEnableWebGLImageChromium))
     WebRuntimeFeatures::enableWebGLImageChromium(true);
 
diff --git a/content/common/gpu/client/gpu_channel_host.cc b/content/common/gpu/client/gpu_channel_host.cc
index 37dd35e..ebf552c9 100644
--- a/content/common/gpu/client/gpu_channel_host.cc
+++ b/content/common/gpu/client/gpu_channel_host.cc
@@ -190,16 +190,17 @@
 }
 
 scoped_ptr<CommandBufferProxyImpl> GpuChannelHost::CreateViewCommandBuffer(
-    int32_t surface_id,
+    gpu::SurfaceHandle surface_handle,
     CommandBufferProxyImpl* share_group,
     int32_t stream_id,
     GpuStreamPriority stream_priority,
     const std::vector<int32_t>& attribs,
     const GURL& active_url,
     gfx::GpuPreference gpu_preference) {
+  DCHECK_NE(gpu::kNullSurfaceHandle, surface_handle);
   DCHECK(!share_group || (stream_id == share_group->stream_id()));
-  TRACE_EVENT1("gpu", "GpuChannelHost::CreateViewCommandBuffer", "surface_id",
-               surface_id);
+  TRACE_EVENT1("gpu", "GpuChannelHost::CreateViewCommandBuffer",
+               "surface_handle", surface_handle);
 
   GPUCreateCommandBufferConfig init_params;
   init_params.share_group_id =
@@ -212,9 +213,6 @@
 
   int32_t route_id = GenerateRouteID();
 
-  gfx::GLSurfaceHandle surface_handle = factory_->GetSurfaceHandle(surface_id);
-  DCHECK(!surface_handle.is_null());
-
   // TODO(vadimt): Remove ScopedTracker below once crbug.com/125248 is fixed.
   tracked_objects::ScopedTracker tracking_profile(
       FROM_HERE_WITH_EXPLICIT_FUNCTION(
diff --git a/content/common/gpu/client/gpu_channel_host.h b/content/common/gpu/client/gpu_channel_host.h
index 2a1f368..ce9284e 100644
--- a/content/common/gpu/client/gpu_channel_host.h
+++ b/content/common/gpu/client/gpu_channel_host.h
@@ -23,6 +23,7 @@
 #include "content/common/gpu/gpu_process_launch_causes.h"
 #include "content/common/gpu/gpu_stream_constants.h"
 #include "gpu/config/gpu_info.h"
+#include "gpu/ipc/common/surface_handle.h"
 #include "ipc/ipc_channel_handle.h"
 #include "ipc/ipc_sync_channel.h"
 #include "ipc/message_filter.h"
@@ -31,15 +32,11 @@
 #include "ui/events/latency_info.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/gpu_memory_buffer.h"
-#include "ui/gfx/native_widget_types.h"
 #include "ui/gl/gpu_preference.h"
 
 class GURL;
-class TransportTextureService;
-struct GPUCreateCommandBufferConfig;
 
 namespace base {
-class MessageLoop;
 class WaitableEvent;
 }
 
@@ -49,8 +46,6 @@
 
 namespace media {
 class JpegDecodeAccelerator;
-class VideoDecodeAccelerator;
-class VideoEncodeAccelerator;
 }
 
 namespace gpu {
@@ -69,7 +64,6 @@
   virtual scoped_refptr<base::SingleThreadTaskRunner>
   GetIOThreadTaskRunner() = 0;
   virtual scoped_ptr<base::SharedMemory> AllocateSharedMemory(size_t size) = 0;
-  virtual gfx::GLSurfaceHandle GetSurfaceHandle(int32_t surface_id) = 0;
 };
 
 // Encapsulates an IPC channel between the client and one GPU process.
@@ -120,7 +114,7 @@
 
   // Create and connect to a command buffer in the GPU process.
   scoped_ptr<CommandBufferProxyImpl> CreateViewCommandBuffer(
-      int32_t surface_id,
+      gpu::SurfaceHandle surface_handle,
       CommandBufferProxyImpl* share_group,
       int32_t stream_id,
       GpuStreamPriority stream_priority,
diff --git a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc
index f778339..4b5ddb2a 100644
--- a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc
+++ b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc
@@ -84,7 +84,7 @@
 }
 
 WebGraphicsContext3DCommandBufferImpl::WebGraphicsContext3DCommandBufferImpl(
-    int surface_id,
+    gpu::SurfaceHandle surface_handle,
     const GURL& active_url,
     GpuChannelHost* host,
     const Attributes& attributes,
@@ -95,7 +95,7 @@
       attributes_(attributes),
       visible_(false),
       host_(host),
-      surface_id_(surface_id),
+      surface_handle_(surface_handle),
       active_url_(active_url),
       context_type_(CONTEXT_TYPE_UNKNOWN),
       gpu_preference_(attributes.preferDiscreteGPU ? gfx::PreferDiscreteGpu
@@ -138,7 +138,7 @@
       FROM_HERE_WITH_EXPLICIT_FUNCTION(
           "125248 WebGraphicsContext3DCommandBufferImpl::MaybeInitializeGL"));
 
-  if (!CreateContext(surface_id_ != 0)) {
+  if (!CreateContext()) {
     Destroy();
 
     initialize_failed_ = true;
@@ -163,7 +163,7 @@
 }
 
 bool WebGraphicsContext3DCommandBufferImpl::InitializeCommandBuffer(
-    bool onscreen, WebGraphicsContext3DCommandBufferImpl* share_context) {
+    WebGraphicsContext3DCommandBufferImpl* share_context) {
   if (!host_.get())
     return false;
 
@@ -182,12 +182,12 @@
   attribs_for_gles2.Serialize(&attribs);
 
   // Create a proxy to a command buffer in the GPU process.
-  if (onscreen) {
-    command_buffer_ =
-        host_->CreateViewCommandBuffer(surface_id_, share_group_command_buffer,
-                                       GpuChannelHost::kDefaultStreamId,
-                                       GpuChannelHost::kDefaultStreamPriority,
-                                       attribs, active_url_, gpu_preference_);
+  if (surface_handle_ != gpu::kNullSurfaceHandle) {
+    command_buffer_ = host_->CreateViewCommandBuffer(
+        surface_handle_, share_group_command_buffer,
+        GpuChannelHost::kDefaultStreamId,
+        GpuChannelHost::kDefaultStreamPriority, attribs, active_url_,
+        gpu_preference_);
   } else {
     command_buffer_ = host_->CreateOffscreenCommandBuffer(
         gfx::Size(1, 1), share_group_command_buffer,
@@ -213,7 +213,7 @@
   return result;
 }
 
-bool WebGraphicsContext3DCommandBufferImpl::CreateContext(bool onscreen) {
+bool WebGraphicsContext3DCommandBufferImpl::CreateContext() {
   TRACE_EVENT0("gpu", "WebGfxCtx3DCmdBfrImpl::CreateContext");
   scoped_refptr<gpu::gles2::ShareGroup> gles2_share_group;
 
@@ -225,7 +225,7 @@
     share_group_lock.reset(new base::AutoLock(share_group_->lock()));
     share_context = share_group_->GetAnyContextLocked();
 
-    if (!InitializeCommandBuffer(onscreen, share_context)) {
+    if (!InitializeCommandBuffer(share_context)) {
       LOG(ERROR) << "Failed to initialize command buffer.";
       return false;
     }
@@ -349,7 +349,7 @@
     return NULL;
 
   return new WebGraphicsContext3DCommandBufferImpl(
-      0,
+      gpu::kNullSurfaceHandle,
       active_url,
       host,
       attributes,
diff --git a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h
index b556c1b..e0260edb 100644
--- a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h
+++ b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h
@@ -20,9 +20,9 @@
 #include "content/common/gpu/client/command_buffer_metrics.h"
 #include "content/common/gpu/client/command_buffer_proxy_impl.h"
 #include "gpu/blink/webgraphicscontext3d_impl.h"
+#include "gpu/ipc/common/surface_handle.h"
 #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
 #include "third_party/WebKit/public/platform/WebString.h"
-#include "ui/gfx/native_widget_types.h"
 #include "ui/gl/gpu_preference.h"
 #include "url/gurl.h"
 
@@ -108,7 +108,7 @@
   };
 
   WebGraphicsContext3DCommandBufferImpl(
-      int surface_id,
+      gpu::SurfaceHandle surface_handle,
       const GURL& active_url,
       GpuChannelHost* host,
       const Attributes& attributes,
@@ -166,7 +166,7 @@
   // thread).
   bool MaybeInitializeGL();
 
-  bool InitializeCommandBuffer(bool onscreen,
+  bool InitializeCommandBuffer(
       WebGraphicsContext3DCommandBufferImpl* share_context);
 
   void Destroy();
@@ -178,13 +178,13 @@
   //
   // NOTE: on Mac OS X, this entry point is only used to set up the
   // accelerated compositor's output. On this platform, we actually pass
-  // a gfx::PluginWindowHandle in place of the gfx::NativeViewId,
+  // a gpu::SurfaceHandle in place of the gfx::NativeViewId,
   // because the facility to allocate a fake PluginWindowHandle is
   // already in place. We could add more entry points and messages to
   // allocate both fake PluginWindowHandles and NativeViewIds and map
   // from fake NativeViewIds to PluginWindowHandles, but this seems like
   // unnecessary complexity at the moment.
-  bool CreateContext(bool onscreen);
+  bool CreateContext();
 
   virtual void OnContextLost();
 
@@ -195,7 +195,7 @@
 
   // State needed by MaybeInitializeGL.
   scoped_refptr<GpuChannelHost> host_;
-  int32_t surface_id_;
+  gpu::SurfaceHandle surface_handle_;
   GURL active_url_;
   CommandBufferContextType context_type_;
 
diff --git a/content/common/gpu/gpu_channel.cc b/content/common/gpu/gpu_channel.cc
index 21ea23d..68cac78 100644
--- a/content/common/gpu/gpu_channel.cc
+++ b/content/common/gpu/gpu_channel.cc
@@ -905,16 +905,17 @@
 #endif
 
 void GpuChannel::OnCreateViewCommandBuffer(
-    const gfx::GLSurfaceHandle& window,
+    gpu::SurfaceHandle surface_handle,
     const GPUCreateCommandBufferConfig& init_params,
     int32_t route_id,
     bool* succeeded) {
   TRACE_EVENT1("gpu", "GpuChannel::CreateViewCommandBuffer", "route_id",
                route_id);
   *succeeded = false;
-  if (allow_view_command_buffers_ && !window.is_null()) {
+  if (allow_view_command_buffers_ &&
+      surface_handle != gpu::kNullSurfaceHandle) {
     *succeeded =
-        CreateCommandBuffer(window, gfx::Size(), init_params, route_id);
+        CreateCommandBuffer(surface_handle, gfx::Size(), init_params, route_id);
   }
 }
 
@@ -926,11 +927,11 @@
   TRACE_EVENT1("gpu", "GpuChannel::OnCreateOffscreenCommandBuffer", "route_id",
                route_id);
   *succeeded =
-      CreateCommandBuffer(gfx::GLSurfaceHandle(), size, init_params, route_id);
+      CreateCommandBuffer(gpu::kNullSurfaceHandle, size, init_params, route_id);
 }
 
 bool GpuChannel::CreateCommandBuffer(
-    const gfx::GLSurfaceHandle& window,
+    gpu::SurfaceHandle surface_handle,
     const gfx::Size& size,
     const GPUCreateCommandBufferConfig& init_params,
     int32_t route_id) {
@@ -957,10 +958,10 @@
     return false;
   }
 
-  bool offscreen = window.is_null();
+  bool offscreen = (surface_handle == gpu::kNullSurfaceHandle);
   scoped_ptr<GpuCommandBufferStub> stub(new GpuCommandBufferStub(
-      this, sync_point_manager_, task_runner_.get(), share_group, window,
-      mailbox_manager_.get(), preempted_flag_.get(),
+      this, sync_point_manager_, task_runner_.get(), share_group,
+      surface_handle, mailbox_manager_.get(), preempted_flag_.get(),
       subscription_ref_set_.get(), pending_valuebuffer_state_.get(), size,
       disallowed_features_, init_params.attribs, init_params.gpu_preference,
       init_params.stream_id, route_id, offscreen, watchdog_,
diff --git a/content/common/gpu/gpu_channel.h b/content/common/gpu/gpu_channel.h
index 401c4f4c..6bcf5987 100644
--- a/content/common/gpu/gpu_channel.h
+++ b/content/common/gpu/gpu_channel.h
@@ -210,7 +210,7 @@
 
   // Message handlers for control messages.
   void OnCreateViewCommandBuffer(
-      const gfx::GLSurfaceHandle& window,
+      gpu::SurfaceHandle surface_handle,
       const GPUCreateCommandBufferConfig& init_params,
       int32_t route_id,
       bool* succeeded);
@@ -221,7 +221,7 @@
       bool* succeeded);
   void OnDestroyCommandBuffer(int32_t route_id);
 
-  bool CreateCommandBuffer(const gfx::GLSurfaceHandle& window,
+  bool CreateCommandBuffer(gpu::SurfaceHandle surface_handle,
                            const gfx::Size& size,
                            const GPUCreateCommandBufferConfig& init_params,
                            int32_t route_id);
diff --git a/content/common/gpu/gpu_channel_manager_delegate.h b/content/common/gpu/gpu_channel_manager_delegate.h
index 1183cbb..c89a165 100644
--- a/content/common/gpu/gpu_channel_manager_delegate.h
+++ b/content/common/gpu/gpu_channel_manager_delegate.h
@@ -6,7 +6,7 @@
 #define CONTENT_COMMON_GPU_GPU_CHANNEL_MANAGER_DELEGATE_H_
 
 #include "gpu/command_buffer/common/constants.h"
-#include "ui/gfx/native_widget_types.h"
+#include "gpu/ipc/common/surface_handle.h"
 
 class GURL;
 
@@ -21,6 +21,9 @@
 
 class GpuChannelManagerDelegate {
  public:
+  // Sets the currently active URL.  Use GURL() to clear the URL.
+  virtual void SetActiveURL(const GURL& url) = 0;
+
   // Tells the delegate that a context has subscribed to a new target and
   // the browser should start sending the corresponding information
   virtual void AddSubscription(int32_t client_id, unsigned int target) = 0;
@@ -63,8 +66,8 @@
 
 #if defined(OS_WIN)
   virtual void SendAcceleratedSurfaceCreatedChildWindow(
-      const gfx::PluginWindowHandle& parent_window,
-      const gfx::PluginWindowHandle& child_window) = 0;
+      gpu::SurfaceHandle parent_window,
+      gpu::SurfaceHandle child_window) = 0;
 #endif
 
  protected:
diff --git a/content/common/gpu/gpu_channel_test_common.cc b/content/common/gpu/gpu_channel_test_common.cc
index 0498fe8e..dbf15f3 100644
--- a/content/common/gpu/gpu_channel_test_common.cc
+++ b/content/common/gpu/gpu_channel_test_common.cc
@@ -9,6 +9,7 @@
 #include "content/common/gpu/gpu_channel_manager_delegate.h"
 #include "gpu/command_buffer/service/sync_point_manager.h"
 #include "ipc/ipc_test_sink.h"
+#include "url/gurl.h"
 
 namespace content {
 
@@ -16,6 +17,8 @@
 
 TestGpuChannelManagerDelegate::~TestGpuChannelManagerDelegate() {}
 
+void TestGpuChannelManagerDelegate::SetActiveURL(const GURL& url) {}
+
 void TestGpuChannelManagerDelegate::AddSubscription(int32_t client_id,
                                                     unsigned int target) {}
 
@@ -50,8 +53,8 @@
 
 #if defined(OS_WIN)
 void TestGpuChannelManagerDelegate::SendAcceleratedSurfaceCreatedChildWindow(
-    const gfx::PluginWindowHandle& parent_window,
-    const gfx::PluginWindowHandle& child_window) {}
+    gpu::SurfaceHandle parent_window,
+    gpu::SurfaceHandle child_window) {}
 #endif
 
 TestGpuChannelManager::TestGpuChannelManager(
diff --git a/content/common/gpu/gpu_channel_test_common.h b/content/common/gpu/gpu_channel_test_common.h
index 65fcc777..d60e5dde 100644
--- a/content/common/gpu/gpu_channel_test_common.h
+++ b/content/common/gpu/gpu_channel_test_common.h
@@ -12,6 +12,8 @@
 #include "ipc/ipc_test_sink.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+class GURL;
+
 namespace base {
 class TestSimpleTaskRunner;
 }  // namespace base
@@ -31,6 +33,7 @@
 
  private:
   // GpuChannelManagerDelegate implementation:
+  void SetActiveURL(const GURL& url) override;
   void AddSubscription(int32_t client_id, unsigned int target) override;
   void DidCreateOffscreenContext(const GURL& active_url) override;
   void DidDestroyChannel(int client_id) override;
@@ -49,8 +52,8 @@
 #endif
 #if defined(OS_WIN)
   void SendAcceleratedSurfaceCreatedChildWindow(
-      const gfx::PluginWindowHandle& parent_window,
-      const gfx::PluginWindowHandle& child_window) override;
+      gpu::SurfaceHandle parent_window,
+      gpu::SurfaceHandle child_window) override;
 #endif
 
   DISALLOW_COPY_AND_ASSIGN(TestGpuChannelManagerDelegate);
diff --git a/content/common/gpu/gpu_channel_unittest.cc b/content/common/gpu/gpu_channel_unittest.cc
index 2b0ba2c..6968adb 100644
--- a/content/common/gpu/gpu_channel_unittest.cc
+++ b/content/common/gpu/gpu_channel_unittest.cc
@@ -59,6 +59,13 @@
   }
 };
 
+#if defined(OS_WIN)
+const gpu::SurfaceHandle kFakeSurfaceHandle =
+    reinterpret_cast<gpu::SurfaceHandle>(1);
+#else
+const gpu::SurfaceHandle kFakeSurfaceHandle = 1;
+#endif
+
 TEST_F(GpuChannelTest, CreateViewCommandBufferAllowed) {
   int32_t kClientId = 1;
   bool allow_view_command_buffers = true;
@@ -66,7 +73,9 @@
       CreateChannel(kClientId, allow_view_command_buffers, false);
   ASSERT_TRUE(channel);
 
-  gfx::GLSurfaceHandle surface_handle;
+  gpu::SurfaceHandle surface_handle = kFakeSurfaceHandle;
+  DCHECK_NE(surface_handle, gpu::kNullSurfaceHandle);
+
   int32_t kRouteId = 1;
   GPUCreateCommandBufferConfig init_params;
   init_params.share_group_id = MSG_ROUTING_NONE;
@@ -76,10 +85,9 @@
   init_params.active_url = GURL();
   init_params.gpu_preference = gfx::PreferIntegratedGpu;
   bool succeeded = false;
-  HandleMessage(channel, new GpuChannelMsg_CreateViewCommandBuffer(
-                             gfx::GLSurfaceHandle(gfx::kNullPluginWindow,
-                                                  gfx::NULL_TRANSPORT),
-                             init_params, kRouteId, &succeeded));
+  HandleMessage(channel,
+                new GpuChannelMsg_CreateViewCommandBuffer(
+                    surface_handle, init_params, kRouteId, &succeeded));
   EXPECT_TRUE(succeeded);
 
   GpuCommandBufferStub* stub = channel->LookupCommandBuffer(kRouteId);
@@ -93,7 +101,9 @@
       CreateChannel(kClientId, allow_view_command_buffers, false);
   ASSERT_TRUE(channel);
 
-  gfx::GLSurfaceHandle surface_handle;
+  gpu::SurfaceHandle surface_handle = kFakeSurfaceHandle;
+  DCHECK_NE(surface_handle, gpu::kNullSurfaceHandle);
+
   int32_t kRouteId = 1;
   GPUCreateCommandBufferConfig init_params;
   init_params.share_group_id = MSG_ROUTING_NONE;
@@ -103,10 +113,9 @@
   init_params.active_url = GURL();
   init_params.gpu_preference = gfx::PreferIntegratedGpu;
   bool succeeded = false;
-  HandleMessage(channel, new GpuChannelMsg_CreateViewCommandBuffer(
-                             gfx::GLSurfaceHandle(gfx::kNullPluginWindow,
-                                                  gfx::NULL_TRANSPORT),
-                             init_params, kRouteId, &succeeded));
+  HandleMessage(channel,
+                new GpuChannelMsg_CreateViewCommandBuffer(
+                    surface_handle, init_params, kRouteId, &succeeded));
   EXPECT_FALSE(succeeded);
 
   GpuCommandBufferStub* stub = channel->LookupCommandBuffer(kRouteId);
@@ -118,7 +127,6 @@
   GpuChannel* channel = CreateChannel(kClientId, true, false);
   ASSERT_TRUE(channel);
 
-  gfx::GLSurfaceHandle surface_handle;
   int32_t kRouteId = 1;
   GPUCreateCommandBufferConfig init_params;
   init_params.share_group_id = MSG_ROUTING_NONE;
diff --git a/content/common/gpu/gpu_command_buffer_stub.cc b/content/common/gpu/gpu_command_buffer_stub.cc
index 4f75aa9..275ab6ea3 100644
--- a/content/common/gpu/gpu_command_buffer_stub.cc
+++ b/content/common/gpu/gpu_command_buffer_stub.cc
@@ -23,7 +23,6 @@
 #include "content/common/gpu/gpu_messages.h"
 #include "content/common/gpu/gpu_watchdog.h"
 #include "content/common/gpu/image_transport_surface.h"
-#include "content/public/common/content_client.h"
 #include "gpu/command_buffer/common/constants.h"
 #include "gpu/command_buffer/common/mailbox.h"
 #include "gpu/command_buffer/common/sync_token.h"
@@ -104,7 +103,7 @@
 
 // FastSetActiveURL will shortcut the expensive call to SetActiveURL when the
 // url_hash matches.
-void FastSetActiveURL(const GURL& url, size_t url_hash) {
+void FastSetActiveURL(const GURL& url, size_t url_hash, GpuChannel* channel) {
   // Leave the previously set URL in the empty case -- empty URLs are given by
   // BlinkPlatformImpl::createOffscreenGraphicsContext3D. Hopefully the
   // onscreen context URL was set previously and will show up even when a crash
@@ -114,7 +113,9 @@
   static size_t g_last_url_hash = 0;
   if (url_hash != g_last_url_hash) {
     g_last_url_hash = url_hash;
-    GetContentClient()->SetActiveURL(url);
+    DCHECK(channel && channel->gpu_channel_manager() &&
+           channel->gpu_channel_manager()->delegate());
+    channel->gpu_channel_manager()->delegate()->SetActiveURL(url);
   }
 }
 
@@ -165,7 +166,7 @@
     gpu::SyncPointManager* sync_point_manager,
     base::SingleThreadTaskRunner* task_runner,
     GpuCommandBufferStub* share_group,
-    const gfx::GLSurfaceHandle& handle,
+    gpu::SurfaceHandle surface_handle,
     gpu::gles2::MailboxManager* mailbox_manager,
     gpu::PreemptionFlag* preempt_by_flag,
     gpu::gles2::SubscriptionRefSet* subscription_ref_set,
@@ -183,7 +184,7 @@
       sync_point_manager_(sync_point_manager),
       task_runner_(task_runner),
       initialized_(false),
-      handle_(handle),
+      surface_handle_(surface_handle),
       initial_size_(size),
       disallowed_features_(disallowed_features),
       requested_attribs_(attribs),
@@ -201,7 +202,7 @@
       preemption_flag_(preempt_by_flag),
       active_url_(active_url) {
   active_url_hash_ = base::Hash(active_url.possibly_invalid_spec());
-  FastSetActiveURL(active_url_, active_url_hash_);
+  FastSetActiveURL(active_url_, active_url_hash_, channel_);
 
   gpu::gles2::ContextCreationAttribHelper attrib_parser;
   attrib_parser.Parse(requested_attribs_);
@@ -269,7 +270,7 @@
                "GPUTask",
                "data",
                DevToolsChannelData::CreateForChannel(channel()));
-  FastSetActiveURL(active_url_, active_url_hash_);
+  FastSetActiveURL(active_url_, active_url_hash_, channel_);
 
   bool have_context = false;
   // Ensure the appropriate GL context is current before handling any IPC
@@ -357,7 +358,7 @@
 void GpuCommandBufferStub::PerformWork() {
   TRACE_EVENT0("gpu", "GpuCommandBufferStub::PerformWork");
 
-  FastSetActiveURL(active_url_, active_url_hash_);
+  FastSetActiveURL(active_url_, active_url_hash_, channel_);
   if (decoder_.get() && !MakeCurrent())
     return;
 
@@ -460,7 +461,7 @@
 
   if (initialized_) {
     GpuChannelManager* gpu_channel_manager = channel_->gpu_channel_manager();
-    if (handle_.is_null() && !active_url_.is_empty())
+    if ((surface_handle_ == gpu::kNullSurfaceHandle) && !active_url_.is_empty())
       gpu_channel_manager->delegate()->DidDestroyOffscreenContext(active_url_);
   }
 
@@ -501,6 +502,20 @@
   Send(reply_message);
 }
 
+scoped_refptr<gfx::GLSurface> GpuCommandBufferStub::CreateSurface() {
+  GpuChannelManager* manager = channel_->gpu_channel_manager();
+  scoped_refptr<gfx::GLSurface> surface;
+  if (surface_handle_ != gpu::kNullSurfaceHandle) {
+    surface = ImageTransportSurface::CreateNativeSurface(
+        manager, this, surface_handle_, surface_format_);
+    if (!surface || !surface->Initialize(surface_format_))
+      return nullptr;
+  } else {
+    surface = manager->GetDefaultOffscreenSurface();
+  }
+  return surface;
+}
+
 void GpuCommandBufferStub::OnInitialize(
     base::SharedMemoryHandle shared_state_handle,
     IPC::Message* reply_message) {
@@ -532,16 +547,7 @@
 
   decoder_->set_engine(scheduler_.get());
 
-  if (!handle_.is_null()) {
-    surface_ = ImageTransportSurface::CreateSurface(
-        channel_->gpu_channel_manager(),
-        this,
-        handle_,
-        surface_format_);
-  } else {
-    surface_ = manager->GetDefaultOffscreenSurface();
-  }
-
+  surface_ = CreateSurface();
   if (!surface_.get()) {
     DLOG(ERROR) << "Failed to create surface.";
     OnInitializeFailed(reply_message);
@@ -660,7 +666,7 @@
       reply_message, true, capabilities);
   Send(reply_message);
 
-  if (handle_.is_null() && !active_url_.is_empty())
+  if ((surface_handle_ == gpu::kNullSurfaceHandle) && !active_url_.is_empty())
     manager->delegate()->DidCreateOffscreenContext(active_url_);
 
   initialized_ = true;
@@ -725,7 +731,8 @@
   // blocked from automatically running.
   GpuChannelManager* gpu_channel_manager = channel_->gpu_channel_manager();
   gpu_channel_manager->delegate()->DidLoseContext(
-      handle_.is_null(), state.context_lost_reason, active_url_);
+      (surface_handle_ == gpu::kNullSurfaceHandle), state.context_lost_reason,
+      active_url_);
 
   CheckContextLost();
 }
@@ -862,7 +869,7 @@
 void GpuCommandBufferStub::ReportState() { command_buffer_->UpdateState(); }
 
 void GpuCommandBufferStub::PutChanged() {
-  FastSetActiveURL(active_url_, active_url_hash_);
+  FastSetActiveURL(active_url_, active_url_hash_, channel_);
   scheduler_->PutChanged();
 }
 
diff --git a/content/common/gpu/gpu_command_buffer_stub.h b/content/common/gpu/gpu_command_buffer_stub.h
index e203887..5c6ec8fb 100644
--- a/content/common/gpu/gpu_command_buffer_stub.h
+++ b/content/common/gpu/gpu_command_buffer_stub.h
@@ -24,13 +24,13 @@
 #include "gpu/command_buffer/service/command_buffer_service.h"
 #include "gpu/command_buffer/service/context_group.h"
 #include "gpu/command_buffer/service/gpu_scheduler.h"
+#include "gpu/ipc/common/surface_handle.h"
 #include "ipc/ipc_listener.h"
 #include "ipc/ipc_sender.h"
 #include "media/video/video_decode_accelerator.h"
 #include "ui/events/latency_info.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/gpu_memory_buffer.h"
-#include "ui/gfx/native_widget_types.h"
 #include "ui/gfx/swap_result.h"
 #include "ui/gl/gl_surface.h"
 #include "ui/gl/gpu_preference.h"
@@ -80,7 +80,7 @@
       gpu::SyncPointManager* sync_point_manager,
       base::SingleThreadTaskRunner* task_runner,
       GpuCommandBufferStub* share_group,
-      const gfx::GLSurfaceHandle& handle,
+      gpu::SurfaceHandle surface_handle,
       gpu::gles2::MailboxManager* mailbox_manager,
       gpu::PreemptionFlag* preempt_by_flag,
       gpu::gles2::SubscriptionRefSet* subscription_ref_set,
@@ -161,6 +161,8 @@
   // Cleans up and sends reply if OnInitialize failed.
   void OnInitializeFailed(IPC::Message* reply_message);
 
+  scoped_refptr<gfx::GLSurface> CreateSurface();
+
   // Message handlers:
   void OnInitialize(base::SharedMemoryHandle shared_state_shm,
                     IPC::Message* reply_message);
@@ -242,7 +244,7 @@
   scoped_refptr<gpu::gles2::ContextGroup> context_group_;
 
   bool initialized_;
-  gfx::GLSurfaceHandle handle_;
+  const gpu::SurfaceHandle surface_handle_;
   gfx::Size initial_size_;
   gpu::gles2::DisallowedFeatures disallowed_features_;
   std::vector<int32_t> requested_attribs_;
diff --git a/content/common/gpu/gpu_host_messages.h b/content/common/gpu/gpu_host_messages.h
index 7ba30f4..21d6c000 100644
--- a/content/common/gpu/gpu_host_messages.h
+++ b/content/common/gpu/gpu_host_messages.h
@@ -17,12 +17,12 @@
 #include "gpu/command_buffer/service/gpu_preferences.h"
 #include "gpu/config/gpu_info.h"
 #include "gpu/ipc/common/memory_stats.h"
+#include "gpu/ipc/common/surface_handle.h"
 #include "ipc/ipc_channel_handle.h"
 #include "ipc/ipc_message_macros.h"
 #include "ipc/ipc_message_start.h"
 #include "ui/gfx/gpu_memory_buffer.h"
 #include "ui/gfx/ipc/gfx_param_traits.h"
-#include "ui/gfx/native_widget_types.h"
 #include "url/gurl.h"
 #include "url/ipc/url_param_traits.h"
 
@@ -63,7 +63,7 @@
   IPC_STRUCT_MEMBER(gfx::BufferFormat, format)
   IPC_STRUCT_MEMBER(gfx::BufferUsage, usage)
   IPC_STRUCT_MEMBER(int32_t, client_id)
-  IPC_STRUCT_MEMBER(gfx::PluginWindowHandle, surface_handle)
+  IPC_STRUCT_MEMBER(gpu::SurfaceHandle, surface_handle)
 IPC_STRUCT_END()
 
 IPC_STRUCT_BEGIN(GpuMsg_CreateGpuMemoryBufferFromHandle_Params)
@@ -269,8 +269,8 @@
 
 #if defined(OS_WIN)
 IPC_MESSAGE_CONTROL2(GpuHostMsg_AcceleratedSurfaceCreatedChildWindow,
-                     gfx::PluginWindowHandle /* parent_window */,
-                     gfx::PluginWindowHandle /* child_window */)
+                     gpu::SurfaceHandle /* parent_window */,
+                     gpu::SurfaceHandle /* child_window */)
 #endif
 
 IPC_MESSAGE_CONTROL1(GpuHostMsg_DidCreateOffscreenContext, GURL /* url */)
diff --git a/content/common/gpu/gpu_memory_buffer_factory.h b/content/common/gpu/gpu_memory_buffer_factory.h
index 77a50f2..b02ae20d 100644
--- a/content/common/gpu/gpu_memory_buffer_factory.h
+++ b/content/common/gpu/gpu_memory_buffer_factory.h
@@ -11,9 +11,9 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "content/common/content_export.h"
+#include "gpu/ipc/common/surface_handle.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/gpu_memory_buffer.h"
-#include "ui/gfx/native_widget_types.h"
 
 namespace gpu {
 class ImageFactory;
@@ -40,7 +40,7 @@
       gfx::BufferFormat format,
       gfx::BufferUsage usage,
       int client_id,
-      gfx::PluginWindowHandle surface_handle) = 0;
+      gpu::SurfaceHandle surface_handle) = 0;
 
   // Creates a new GPU memory buffer instance from an existing handle. A valid
   // handle is returned on success. It can be called on any thread.
diff --git a/content/common/gpu/gpu_memory_buffer_factory_io_surface.cc b/content/common/gpu/gpu_memory_buffer_factory_io_surface.cc
index 49fab37..4db0fb06 100644
--- a/content/common/gpu/gpu_memory_buffer_factory_io_surface.cc
+++ b/content/common/gpu/gpu_memory_buffer_factory_io_surface.cc
@@ -47,7 +47,7 @@
     gfx::BufferFormat format,
     gfx::BufferUsage usage,
     int client_id,
-    gfx::PluginWindowHandle surface_handle) {
+    gpu::SurfaceHandle surface_handle) {
   base::ScopedCFTypeRef<IOSurfaceRef> io_surface(
       gfx::CreateIOSurface(size, format));
   if (!io_surface)
diff --git a/content/common/gpu/gpu_memory_buffer_factory_io_surface.h b/content/common/gpu/gpu_memory_buffer_factory_io_surface.h
index d2fd00d..984438b9 100644
--- a/content/common/gpu/gpu_memory_buffer_factory_io_surface.h
+++ b/content/common/gpu/gpu_memory_buffer_factory_io_surface.h
@@ -44,7 +44,7 @@
       gfx::BufferFormat format,
       gfx::BufferUsage usage,
       int client_id,
-      gfx::PluginWindowHandle surface_handle) override;
+      gpu::SurfaceHandle surface_handle) override;
   gfx::GpuMemoryBufferHandle CreateGpuMemoryBufferFromHandle(
       const gfx::GpuMemoryBufferHandle& handle,
       gfx::GpuMemoryBufferId id,
diff --git a/content/common/gpu/gpu_memory_buffer_factory_ozone_native_pixmap.cc b/content/common/gpu/gpu_memory_buffer_factory_ozone_native_pixmap.cc
index d28fbac..90ecdabb 100644
--- a/content/common/gpu/gpu_memory_buffer_factory_ozone_native_pixmap.cc
+++ b/content/common/gpu/gpu_memory_buffer_factory_ozone_native_pixmap.cc
@@ -37,7 +37,7 @@
     gfx::BufferFormat format,
     gfx::BufferUsage usage,
     int client_id,
-    gfx::PluginWindowHandle surface_handle) {
+    gpu::SurfaceHandle surface_handle) {
   scoped_refptr<ui::NativePixmap> pixmap =
       ui::OzonePlatform::GetInstance()
           ->GetSurfaceFactoryOzone()
diff --git a/content/common/gpu/gpu_memory_buffer_factory_ozone_native_pixmap.h b/content/common/gpu/gpu_memory_buffer_factory_ozone_native_pixmap.h
index f9ea0d2..943d189 100644
--- a/content/common/gpu/gpu_memory_buffer_factory_ozone_native_pixmap.h
+++ b/content/common/gpu/gpu_memory_buffer_factory_ozone_native_pixmap.h
@@ -36,7 +36,7 @@
       gfx::BufferFormat format,
       gfx::BufferUsage usage,
       int client_id,
-      gfx::PluginWindowHandle surface_handle) override;
+      gpu::SurfaceHandle surface_handle) override;
   gfx::GpuMemoryBufferHandle CreateGpuMemoryBufferFromHandle(
       const gfx::GpuMemoryBufferHandle& handle,
       gfx::GpuMemoryBufferId id,
diff --git a/content/common/gpu/gpu_memory_buffer_factory_surface_texture.cc b/content/common/gpu/gpu_memory_buffer_factory_surface_texture.cc
index d9fd7d5c..1bef37e 100644
--- a/content/common/gpu/gpu_memory_buffer_factory_surface_texture.cc
+++ b/content/common/gpu/gpu_memory_buffer_factory_surface_texture.cc
@@ -39,7 +39,7 @@
     gfx::BufferFormat format,
     gfx::BufferUsage usage,
     int client_id,
-    gfx::PluginWindowHandle surface_handle) {
+    gpu::SurfaceHandle surface_handle) {
   // Note: this needs to be 0 as the surface texture implemenation will take
   // ownership of the texture and call glDeleteTextures when the GPU service
   // attaches the surface texture to a real texture id. glDeleteTextures
diff --git a/content/common/gpu/gpu_memory_buffer_factory_surface_texture.h b/content/common/gpu/gpu_memory_buffer_factory_surface_texture.h
index b9eda55..35ff16f6 100644
--- a/content/common/gpu/gpu_memory_buffer_factory_surface_texture.h
+++ b/content/common/gpu/gpu_memory_buffer_factory_surface_texture.h
@@ -43,7 +43,7 @@
       gfx::BufferFormat format,
       gfx::BufferUsage usage,
       int client_id,
-      gfx::PluginWindowHandle surface_handle) override;
+      gpu::SurfaceHandle surface_handle) override;
   gfx::GpuMemoryBufferHandle CreateGpuMemoryBufferFromHandle(
       const gfx::GpuMemoryBufferHandle& handle,
       gfx::GpuMemoryBufferId id,
diff --git a/content/common/gpu/gpu_messages.h b/content/common/gpu/gpu_messages.h
index 47cf56b6..314d69d 100644
--- a/content/common/gpu/gpu_messages.h
+++ b/content/common/gpu/gpu_messages.h
@@ -26,6 +26,7 @@
 #include "gpu/command_buffer/common/value_state.h"
 #include "gpu/config/gpu_info.h"
 #include "gpu/ipc/common/gpu_command_buffer_traits.h"
+#include "gpu/ipc/common/surface_handle.h"
 #include "ipc/ipc_channel_handle.h"
 #include "ipc/ipc_message_macros.h"
 #include "ui/events/latency_info.h"
@@ -53,8 +54,6 @@
                           gfx::GpuPreferenceLast)
 IPC_ENUM_TRAITS_MAX_VALUE(content::GpuStreamPriority,
                           content::GpuStreamPriority::LAST)
-IPC_ENUM_TRAITS_MAX_VALUE(gfx::SurfaceType,
-                          gfx::SURFACE_TYPE_LAST)
 IPC_ENUM_TRAITS_MAX_VALUE(gfx::SwapResult, gfx::SwapResult::SWAP_RESULT_LAST)
 IPC_ENUM_TRAITS_MAX_VALUE(gpu::MemoryAllocation::PriorityCutoff,
                           gpu::MemoryAllocation::CUTOFF_LAST)
@@ -170,11 +169,6 @@
   IPC_STRUCT_TRAITS_MEMBER(priority_cutoff_when_visible)
 IPC_STRUCT_TRAITS_END()
 
-IPC_STRUCT_TRAITS_BEGIN(gfx::GLSurfaceHandle)
-  IPC_STRUCT_TRAITS_MEMBER(handle)
-  IPC_STRUCT_TRAITS_MEMBER(transport_type)
-IPC_STRUCT_TRAITS_END()
-
 //------------------------------------------------------------------------------
 // GPU Channel Messages
 // These are messages from a renderer process to the GPU process.
@@ -182,7 +176,7 @@
 // Tells the GPU process to create a new command buffer that renders directly
 // to a native view. A corresponding GpuCommandBufferStub is created.
 IPC_SYNC_MESSAGE_CONTROL3_1(GpuChannelMsg_CreateViewCommandBuffer,
-                            gfx::GLSurfaceHandle, /* compositing_surface */
+                            gpu::SurfaceHandle, /* surface_handle */
                             GPUCreateCommandBufferConfig, /* init_params */
                             int32_t /* route_id */,
                             bool /* succeeded */)
diff --git a/content/common/gpu/image_transport_surface.cc b/content/common/gpu/image_transport_surface.cc
deleted file mode 100644
index 1606f090a..0000000
--- a/content/common/gpu/image_transport_surface.cc
+++ /dev/null
@@ -1,29 +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 "content/common/gpu/image_transport_surface.h"
-
-#include "content/common/gpu/gpu_channel_manager.h"
-
-namespace content {
-
-// static
-scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateSurface(
-    GpuChannelManager* manager,
-    GpuCommandBufferStub* stub,
-    const gfx::GLSurfaceHandle& handle,
-    gfx::GLSurface::Format format) {
-  scoped_refptr<gfx::GLSurface> surface;
-  if (handle.transport_type == gfx::NULL_TRANSPORT) {
-    surface = manager->GetDefaultOffscreenSurface();
-  } else {
-    surface = CreateNativeSurface(manager, stub, handle, format);
-    if (!surface.get() || !surface->Initialize(format))
-      return NULL;
-  }
-
-  return surface;
-}
-
-}  // namespace content
diff --git a/content/common/gpu/image_transport_surface.h b/content/common/gpu/image_transport_surface.h
index 7df0193..8cb2967 100644
--- a/content/common/gpu/image_transport_surface.h
+++ b/content/common/gpu/image_transport_surface.h
@@ -11,6 +11,7 @@
 #include "base/macros.h"
 #include "build/build_config.h"
 #include "content/common/content_export.h"
+#include "gpu/ipc/common/surface_handle.h"
 #include "ui/gl/gl_surface.h"
 
 namespace content {
@@ -21,42 +22,23 @@
 // it renders directly to window. On others it renders offscreen and transports
 // the results to the browser process to display. This file provides a simple
 // framework for making the offscreen path seem more like the onscreen path.
-//
-// The ImageTransportSurface class defines an simple interface for events that
-// should be responded to. The factory returns an offscreen surface that looks
-// a lot like an onscreen surface to the GPU process.
-//
-// The ImageTransportSurfaceHelper provides some glue to the outside world:
-// making sure outside events reach the ImageTransportSurface and
-// allowing the ImageTransportSurface to send events to the outside world.
 
 class ImageTransportSurface {
  public:
-  // Creates a surface with the given attributes.
-  static scoped_refptr<gfx::GLSurface> CreateSurface(
-      GpuChannelManager* manager,
-      GpuCommandBufferStub* stub,
-      const gfx::GLSurfaceHandle& handle,
-      gfx::GLSurface::Format format);
-
 #if defined(OS_MACOSX)
   CONTENT_EXPORT static void SetAllowOSMesaForTesting(bool allow);
 #endif
 
- private:
   // Creates the appropriate native surface depending on the GL implementation.
-  // This will be implemented separately by each platform.
-  //
-  // This will not be called for texture transport surfaces which are
-  // cross-platform. The platform implementation should only create the
-  // surface and should not initialize it. On failure, a null scoped_refptr
-  // should be returned.
+  // This will be implemented separately by each platform. On failure, a null
+  // scoped_refptr should be returned.
   static scoped_refptr<gfx::GLSurface> CreateNativeSurface(
       GpuChannelManager* manager,
       GpuCommandBufferStub* stub,
-      const gfx::GLSurfaceHandle& handle,
+      gpu::SurfaceHandle surface_handle,
       gfx::GLSurface::Format format);
 
+ private:
   DISALLOW_COPY_AND_ASSIGN(ImageTransportSurface);
 };
 
diff --git a/content/common/gpu/image_transport_surface_android.cc b/content/common/gpu/image_transport_surface_android.cc
index d24ee5b..9362b67 100644
--- a/content/common/gpu/image_transport_surface_android.cc
+++ b/content/common/gpu/image_transport_surface_android.cc
@@ -20,15 +20,17 @@
 scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateNativeSurface(
     GpuChannelManager* manager,
     GpuCommandBufferStub* stub,
-    const gfx::GLSurfaceHandle& handle,
+    gpu::SurfaceHandle surface_handle,
     gfx::GLSurface::Format format) {
   DCHECK(GpuSurfaceLookup::GetInstance());
-  DCHECK_EQ(handle.transport_type, gfx::NATIVE_DIRECT);
+  DCHECK_NE(surface_handle, gpu::kNullSurfaceHandle);
+  // On Android, the surface_handle is the id of the surface in the
+  // GpuSurfaceTracker/GpuSurfaceLookup
   ANativeWindow* window =
-      GpuSurfaceLookup::GetInstance()->AcquireNativeWidget(handle.handle);
+      GpuSurfaceLookup::GetInstance()->AcquireNativeWidget(surface_handle);
   if (!window) {
     LOG(WARNING) << "Failed to acquire native widget.";
-    return scoped_refptr<gfx::GLSurface>();
+    return nullptr;
   }
   scoped_refptr<gfx::GLSurface> surface =
       new gfx::NativeViewGLSurfaceEGL(window);
diff --git a/content/common/gpu/image_transport_surface_linux.cc b/content/common/gpu/image_transport_surface_linux.cc
index e9412a7b..7cd4ce3 100644
--- a/content/common/gpu/image_transport_surface_linux.cc
+++ b/content/common/gpu/image_transport_surface_linux.cc
@@ -12,16 +12,15 @@
 scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateNativeSurface(
     GpuChannelManager* manager,
     GpuCommandBufferStub* stub,
-    const gfx::GLSurfaceHandle& handle,
+    gpu::SurfaceHandle surface_handle,
     gfx::GLSurface::Format format) {
-  DCHECK(handle.handle);
-  DCHECK(handle.transport_type == gfx::NATIVE_DIRECT);
+  DCHECK_NE(surface_handle, gpu::kNullSurfaceHandle);
   scoped_refptr<gfx::GLSurface> surface;
 #if defined(USE_OZONE)
-  surface = gfx::GLSurface::CreateSurfacelessViewGLSurface(handle.handle);
+  surface = gfx::GLSurface::CreateSurfacelessViewGLSurface(surface_handle);
 #endif
   if (!surface)
-    surface = gfx::GLSurface::CreateViewGLSurface(handle.handle);
+    surface = gfx::GLSurface::CreateViewGLSurface(surface_handle);
   if (!surface)
     return surface;
   return scoped_refptr<gfx::GLSurface>(new PassThroughImageTransportSurface(
diff --git a/content/common/gpu/image_transport_surface_mac.mm b/content/common/gpu/image_transport_surface_mac.mm
index 25131cc..9d92bb8 100644
--- a/content/common/gpu/image_transport_surface_mac.mm
+++ b/content/common/gpu/image_transport_surface_mac.mm
@@ -14,7 +14,7 @@
 scoped_refptr<gfx::GLSurface> ImageTransportSurfaceCreateNativeSurface(
     GpuChannelManager* manager,
     GpuCommandBufferStub* stub,
-    gfx::PluginWindowHandle handle);
+    gpu::SurfaceHandle handle);
 
 namespace {
 
@@ -46,24 +46,23 @@
 scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateNativeSurface(
     GpuChannelManager* manager,
     GpuCommandBufferStub* stub,
-    const gfx::GLSurfaceHandle& surface_handle,
+    gpu::SurfaceHandle surface_handle,
     gfx::GLSurface::Format format) {
-  DCHECK(surface_handle.transport_type == gfx::NATIVE_DIRECT ||
-         surface_handle.transport_type == gfx::NULL_TRANSPORT);
+  DCHECK_NE(surface_handle, gpu::kNullSurfaceHandle);
 
   switch (gfx::GetGLImplementation()) {
     case gfx::kGLImplementationDesktopGL:
     case gfx::kGLImplementationDesktopGLCoreProfile:
     case gfx::kGLImplementationAppleGL:
       return ImageTransportSurfaceCreateNativeSurface(manager, stub,
-                                                      surface_handle.handle);
+                                                      surface_handle);
     default:
       // Content shell in DRT mode spins up a gpu process which needs an
       // image transport surface, but that surface isn't used to read pixel
       // baselines. So this is mostly a dummy surface.
       if (!g_allow_os_mesa) {
         NOTREACHED();
-        return scoped_refptr<gfx::GLSurface>();
+        return nullptr;
       }
       scoped_refptr<gfx::GLSurface> surface(new DRTSurfaceOSMesa());
       if (!surface.get() || !surface->Initialize(format))
diff --git a/content/common/gpu/image_transport_surface_overlay_mac.h b/content/common/gpu/image_transport_surface_overlay_mac.h
index 4254749b..4ea4cb7 100644
--- a/content/common/gpu/image_transport_surface_overlay_mac.h
+++ b/content/common/gpu/image_transport_surface_overlay_mac.h
@@ -31,7 +31,7 @@
  public:
   ImageTransportSurfaceOverlayMac(GpuChannelManager* manager,
                                   GpuCommandBufferStub* stub,
-                                  gfx::PluginWindowHandle handle);
+                                  gpu::SurfaceHandle handle);
 
   // GLSurface implementation
   bool Initialize(gfx::GLSurface::Format format) override;
@@ -106,7 +106,7 @@
 
   GpuChannelManager* manager_;
   base::WeakPtr<GpuCommandBufferStub> stub_;
-  gfx::PluginWindowHandle handle_;
+  gpu::SurfaceHandle handle_;
   std::vector<ui::LatencyInfo> latency_info_;
 
   bool use_remote_layer_api_;
diff --git a/content/common/gpu/image_transport_surface_overlay_mac.mm b/content/common/gpu/image_transport_surface_overlay_mac.mm
index 2a95abc..bbd3264 100644
--- a/content/common/gpu/image_transport_surface_overlay_mac.mm
+++ b/content/common/gpu/image_transport_surface_overlay_mac.mm
@@ -84,7 +84,7 @@
 scoped_refptr<gfx::GLSurface> ImageTransportSurfaceCreateNativeSurface(
     GpuChannelManager* manager,
     GpuCommandBufferStub* stub,
-    gfx::PluginWindowHandle handle) {
+    gpu::SurfaceHandle handle) {
   return new ImageTransportSurfaceOverlayMac(manager, stub, handle);
 }
 
@@ -118,7 +118,7 @@
 ImageTransportSurfaceOverlayMac::ImageTransportSurfaceOverlayMac(
     GpuChannelManager* manager,
     GpuCommandBufferStub* stub,
-    gfx::PluginWindowHandle handle)
+    gpu::SurfaceHandle handle)
     : manager_(manager),
       stub_(stub->AsWeakPtr()),
       handle_(handle),
diff --git a/content/common/gpu/image_transport_surface_win.cc b/content/common/gpu/image_transport_surface_win.cc
index 3bdbe25..b23a4947 100644
--- a/content/common/gpu/image_transport_surface_win.cc
+++ b/content/common/gpu/image_transport_surface_win.cc
@@ -27,25 +27,24 @@
 scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateNativeSurface(
     GpuChannelManager* manager,
     GpuCommandBufferStub* stub,
-    const gfx::GLSurfaceHandle& handle,
+    gpu::SurfaceHandle surface_handle,
     gfx::GLSurface::Format format) {
-  DCHECK(handle.handle);
-  DCHECK_EQ(handle.transport_type, gfx::NATIVE_DIRECT);
+  DCHECK_NE(surface_handle, gpu::kNullSurfaceHandle);
 
   scoped_refptr<gfx::GLSurface> surface;
   if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2 &&
       gfx::GLSurfaceEGL::IsDirectCompositionSupported()) {
     scoped_refptr<ChildWindowSurfaceWin> egl_surface(
-        new ChildWindowSurfaceWin(manager, handle.handle));
+        new ChildWindowSurfaceWin(manager, surface_handle));
     surface = egl_surface;
 
     // TODO(jbauman): Get frame statistics from DirectComposition
     scoped_ptr<gfx::VSyncProvider> vsync_provider(
-        new gfx::VSyncProviderWin(handle.handle));
+        new gfx::VSyncProviderWin(surface_handle));
     if (!egl_surface->Initialize(std::move(vsync_provider)))
       return nullptr;
   } else {
-    surface = gfx::GLSurface::CreateViewGLSurface(handle.handle);
+    surface = gfx::GLSurface::CreateViewGLSurface(surface_handle);
     if (!surface)
       return nullptr;
   }
diff --git a/content/content_common.gypi b/content/content_common.gypi
index 4669acc..6fb7d99 100644
--- a/content/content_common.gypi
+++ b/content/content_common.gypi
@@ -401,7 +401,6 @@
       'common/gpu/gpu_surface_lookup.cc',
       'common/gpu/gpu_surface_lookup.h',
       'common/gpu/gpu_watchdog.h',
-      'common/gpu/image_transport_surface.cc',
       'common/gpu/image_transport_surface.h',
       'common/gpu/image_transport_surface_android.cc',
       'common/gpu/image_transport_surface_linux.cc',
diff --git a/content/gpu/gpu_child_thread.cc b/content/gpu/gpu_child_thread.cc
index 2452579..7422c464 100644
--- a/content/gpu/gpu_child_thread.cc
+++ b/content/gpu/gpu_child_thread.cc
@@ -34,6 +34,7 @@
 #include "ui/gl/gl_implementation.h"
 #include "ui/gl/gl_switches.h"
 #include "ui/gl/gpu_switching_manager.h"
+#include "url/gurl.h"
 
 #if defined(USE_OZONE)
 #include "ui/ozone/public/gpu_platform_support.h"
@@ -293,6 +294,10 @@
   return false;
 }
 
+void GpuChildThread::SetActiveURL(const GURL& url) {
+  GetContentClient()->SetActiveURL(url);
+}
+
 void GpuChildThread::AddSubscription(int32_t client_id, unsigned int target) {
   Send(new GpuHostMsg_AddSubscription(client_id, target));
 }
@@ -334,8 +339,8 @@
 
 #if defined(OS_WIN)
 void GpuChildThread::SendAcceleratedSurfaceCreatedChildWindow(
-    const gfx::PluginWindowHandle& parent_window,
-    const gfx::PluginWindowHandle& child_window) {
+    gpu::SurfaceHandle parent_window,
+    gpu::SurfaceHandle child_window) {
   Send(new GpuHostMsg_AcceleratedSurfaceCreatedChildWindow(parent_window,
                                                            child_window));
 }
diff --git a/content/gpu/gpu_child_thread.h b/content/gpu/gpu_child_thread.h
index 80a2412..31daaeb8 100644
--- a/content/gpu/gpu_child_thread.h
+++ b/content/gpu/gpu_child_thread.h
@@ -78,6 +78,7 @@
   bool OnMessageReceived(const IPC::Message& msg) override;
 
   // GpuChannelManagerDelegate implementation.
+  void SetActiveURL(const GURL& url) override;
   void AddSubscription(int32_t client_id, unsigned int target) override;
   void DidCreateOffscreenContext(const GURL& active_url) override;
   void DidDestroyChannel(int client_id) override;
@@ -93,8 +94,8 @@
 #endif
 #if defined(OS_WIN)
   void SendAcceleratedSurfaceCreatedChildWindow(
-      const gfx::PluginWindowHandle& parent_window,
-      const gfx::PluginWindowHandle& child_window) override;
+      gpu::SurfaceHandle parent_window,
+      gpu::SurfaceHandle child_window) override;
 #endif
   void StoreShaderToDisk(int32_t client_id,
                          const std::string& key,
diff --git a/content/ppapi_plugin/ppapi_thread.cc b/content/ppapi_plugin/ppapi_thread.cc
index 35d56e27..96770b5 100644
--- a/content/ppapi_plugin/ppapi_thread.cc
+++ b/content/ppapi_plugin/ppapi_thread.cc
@@ -118,7 +118,7 @@
       command_line.GetSwitchValueASCII(switches::kPpapiFlashArgs));
 
   blink_platform_impl_.reset(new PpapiBlinkPlatformImpl);
-  blink::initializeWithoutV8(blink_platform_impl_.get());
+  blink::Platform::initialize(blink_platform_impl_.get());
 
   if (!is_broker_) {
     scoped_refptr<ppapi::proxy::PluginMessageFilter> plugin_filter(
@@ -146,7 +146,7 @@
   if (plugin_entry_points_.shutdown_module)
     plugin_entry_points_.shutdown_module();
   blink_platform_impl_->Shutdown();
-  blink::shutdownWithoutV8();
+  blink::Platform::shutdown();
 }
 
 bool PpapiThread::Send(IPC::Message* msg) {
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 4a50997..2e2b36a3 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
@@ -37,7 +37,6 @@
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
 import android.view.accessibility.AccessibilityNodeProvider;
-import android.view.animation.AnimationUtils;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
@@ -58,13 +57,11 @@
 import org.chromium.content.browser.accessibility.captioning.CaptioningBridgeFactory;
 import org.chromium.content.browser.accessibility.captioning.SystemCaptioningBridge;
 import org.chromium.content.browser.accessibility.captioning.TextTrackSettings;
-import org.chromium.content.browser.input.AnimationIntervalProvider;
 import org.chromium.content.browser.input.FloatingPastePopupMenu;
 import org.chromium.content.browser.input.GamepadList;
 import org.chromium.content.browser.input.ImeAdapter;
 import org.chromium.content.browser.input.InputMethodManagerWrapper;
 import org.chromium.content.browser.input.JoystickScrollProvider;
-import org.chromium.content.browser.input.JoystickZoomProvider;
 import org.chromium.content.browser.input.LegacyPastePopupMenu;
 import org.chromium.content.browser.input.PastePopupMenu;
 import org.chromium.content.browser.input.PastePopupMenu.PastePopupMenuDelegate;
@@ -352,16 +349,6 @@
     }
 
     /**
-     * Returns interval between consecutive animation frames.
-     */
-    private static class SystemAnimationIntervalProvider implements AnimationIntervalProvider {
-        @Override
-        public long getLastAnimationFrameInterval() {
-            return AnimationUtils.currentAnimationTimeMillis();
-        }
-    }
-
-    /**
      * Interface that consumers of {@link ContentViewCore} must implement to allow the proper
      * dispatching of view methods through the containing view.
      *
@@ -485,9 +472,6 @@
     // Provides smooth gamepad joystick-driven scrolling.
     private final JoystickScrollProvider mJoystickScrollProvider;
 
-    // Provides smooth gamepad joystick-driven zooming.
-    private JoystickZoomProvider mJoystickZoomProvider;
-
     private boolean mIsMobileOptimizedHint;
 
     // Tracks whether a selection is currently active.  When applied to selected text, indicates
@@ -1736,11 +1720,6 @@
             }
         } else if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
             if (mJoystickScrollProvider.onMotion(event)) return true;
-            if (mJoystickZoomProvider == null) {
-                mJoystickZoomProvider =
-                        new JoystickZoomProvider(this, new SystemAnimationIntervalProvider());
-            }
-            if (mJoystickZoomProvider.onMotion(event)) return true;
         }
         return mContainerViewInternals.super_onGenericMotionEvent(event);
     }
@@ -2758,44 +2737,6 @@
     }
 
     /**
-     * Send start of pinch zoom gesture.
-     *
-     * @param xPix X-coordinate of location from which pinch zoom would start.
-     * @param yPix Y-coordinate of location from which pinch zoom would start.
-     * @return whether the pinch zoom start gesture was sent.
-     */
-    public boolean pinchBegin(int xPix, int yPix) {
-        if (mNativeContentViewCore == 0) return false;
-        nativePinchBegin(mNativeContentViewCore, SystemClock.uptimeMillis(), xPix, yPix);
-        return true;
-    }
-
-    /**
-     * Send pinch zoom gesture.
-     *
-     * @param xPix X-coordinate of pinch zoom location.
-     * @param yPix Y-coordinate of pinch zoom location.
-     * @param delta the factor by which the current page scale should be multiplied by.
-     * @return whether the pinchby gesture was sent.
-     */
-    public boolean pinchBy(int xPix, int yPix, float delta) {
-        if (mNativeContentViewCore == 0) return false;
-        nativePinchBy(mNativeContentViewCore, SystemClock.uptimeMillis(), xPix, yPix, delta);
-        return true;
-    }
-
-    /**
-     * Stop pinch zoom gesture.
-     *
-     * @return whether the pinch stop gesture was sent.
-     */
-    public boolean pinchEnd() {
-        if (mNativeContentViewCore == 0) return false;
-        nativePinchEnd(mNativeContentViewCore, SystemClock.uptimeMillis());
-        return true;
-    }
-
-    /**
      * Invokes the graphical zoom picker widget for this ContentView.
      */
     public void invokeZoomPicker() {
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/AnimationIntervalProvider.java b/content/public/android/java/src/org/chromium/content/browser/input/AnimationIntervalProvider.java
deleted file mode 100644
index df9a692..0000000
--- a/content/public/android/java/src/org/chromium/content/browser/input/AnimationIntervalProvider.java
+++ /dev/null
@@ -1,15 +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.
-
-package org.chromium.content.browser.input;
-
-/**
- * This is an interface which provides last animation interval.
- */
-public interface AnimationIntervalProvider {
-    /**
-     * Returns last animation interval.
-     */
-    public long getLastAnimationFrameInterval();
-}
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/JoystickZoomProvider.java b/content/public/android/java/src/org/chromium/content/browser/input/JoystickZoomProvider.java
deleted file mode 100644
index 489eb245..0000000
--- a/content/public/android/java/src/org/chromium/content/browser/input/JoystickZoomProvider.java
+++ /dev/null
@@ -1,131 +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.
-
-package org.chromium.content.browser.input;
-
-import android.view.InputDevice;
-import android.view.MotionEvent;
-
-import org.chromium.content.browser.ContentViewCore;
-
-/**
- * This class controls page zoomin/out using trigger joystick events.
- * Page Zoomin is proportional to RTRIGGER axis movement.
- * Page Zoomout is proportional to LTRIGGER axis movement.
- */
-public class JoystickZoomProvider {
-    private static final String TAG = "JoystickZoomProvider";
-
-    private static final float JOYSTICK_NOISE_THRESHOLD = 0.2f;
-
-    private static final float ZOOM_SPEED = 1.65f;
-
-    private long mLastAnimateTimeMillis;
-
-    private float mZoomInVelocity;
-
-    private float mZoomOutVelocity;
-
-    protected final ContentViewCore mContentViewCore;
-
-    protected float mDeviceScaleFactor;
-
-    private int mZoomXcoord;
-
-    private int mZoomYcoord;
-
-    protected Runnable mZoomRunnable;
-
-    private AnimationIntervalProvider mSystemAnimationIntervalProvider;
-
-    /**
-     * Constructs a new JoystickZoomProvider.
-     *
-     * @param cvc The ContentViewCore used to create this.
-     */
-    public JoystickZoomProvider(
-            ContentViewCore cvc, AnimationIntervalProvider animationTimeProvider) {
-        mContentViewCore = cvc;
-        mDeviceScaleFactor = mContentViewCore.getRenderCoordinates().getDeviceScaleFactor();
-        mZoomXcoord = mContentViewCore.getViewportWidthPix() / 2;
-        mZoomYcoord = mContentViewCore.getViewportHeightPix() / 2;
-        mSystemAnimationIntervalProvider = animationTimeProvider;
-    }
-
-    /**
-     * This function processes motion event and computes new
-     * page scale factor which is proportional to *_TRIGGER axes movement.
-     * It also starts runnable to update current page scale to new page scale.
-     *
-     * @param event Motion event to be processed for zooming.
-     * @return Whether zooming using *_TRIGGER axes is performed or not.
-     */
-    public boolean onMotion(MotionEvent event) {
-        if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0) return false;
-
-        computeNewZoomVelocity(event);
-        if (mZoomInVelocity == 0 && mZoomOutVelocity == 0) {
-            stop();
-            return false;
-        }
-        if (mZoomRunnable == null) {
-            mZoomRunnable = new Runnable() {
-                @Override
-                public void run() {
-                    animateZoom();
-                }
-            };
-        }
-        if (mLastAnimateTimeMillis == 0) {
-            mLastAnimateTimeMillis =
-                    mSystemAnimationIntervalProvider.getLastAnimationFrameInterval();
-            mContentViewCore.getContainerView().postOnAnimation(mZoomRunnable);
-            mContentViewCore.pinchBegin(mZoomXcoord, mZoomYcoord);
-        }
-        return true;
-    }
-
-    protected void stop() {
-        if (mLastAnimateTimeMillis != 0) {
-            mContentViewCore.pinchEnd();
-            mLastAnimateTimeMillis = 0;
-        }
-    }
-
-    private void computeNewZoomVelocity(MotionEvent event) {
-        mZoomInVelocity = getFilteredAxisValue(event, MotionEvent.AXIS_RTRIGGER);
-        mZoomOutVelocity = getFilteredAxisValue(event, MotionEvent.AXIS_LTRIGGER);
-    }
-
-    protected void animateZoom() {
-        if (!mContentViewCore.getContainerView().hasFocus()) {
-            stop();
-            return;
-        }
-        if (mLastAnimateTimeMillis == 0) return;
-
-        final long timeMillis = mSystemAnimationIntervalProvider.getLastAnimationFrameInterval();
-        final long dt = timeMillis - mLastAnimateTimeMillis;
-        final float zoomFactor = (float) Math.pow(
-                ZOOM_SPEED, mDeviceScaleFactor * (mZoomInVelocity - mZoomOutVelocity) * dt / 1000f);
-        mContentViewCore.pinchBy(mZoomXcoord, mZoomYcoord, zoomFactor);
-        mLastAnimateTimeMillis = timeMillis;
-        mContentViewCore.getContainerView().postOnAnimation(mZoomRunnable);
-    }
-
-    /**
-     * This function removes noise from motion events.
-     * Joystick is very senstitive, it produces value (noise) along X/Y directions
-     * even if gamepad button is pressed which is not acceptable.
-     * Returns non-zero value only if event value is above noise threshold.
-     *
-     * @param event Motion event which needs noise processing.
-     * @param axis Joystick axis (whether X_AXIS of Y_AXIS)
-     * @return Processed joystick value.
-     */
-    private float getFilteredAxisValue(MotionEvent event, int axis) {
-        float axisValWithNoise = event.getAxisValue(axis);
-        return (axisValWithNoise > JOYSTICK_NOISE_THRESHOLD) ? axisValWithNoise : 0f;
-    }
-}
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewZoomingTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewZoomingTest.java
deleted file mode 100644
index 4e7b2405..0000000
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewZoomingTest.java
+++ /dev/null
@@ -1,143 +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.
-
-package org.chromium.content.browser;
-
-import android.os.SystemClock;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.view.InputDevice;
-import android.view.MotionEvent;
-
-import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.UrlUtils;
-import org.chromium.content.browser.input.AnimationIntervalProvider;
-import org.chromium.content.browser.input.JoystickZoomProvider;
-import org.chromium.content_shell_apk.ContentShellTestBase;
-
-/**
- * Tests that ContentView running inside ContentShell can be zoomed using gamepad joystick.
- */
-public class ContentViewZoomingTest extends ContentShellTestBase {
-    private static final String LARGE_PAGE = UrlUtils.encodeHtmlDataUri("<html><head>"
-            + "<meta name=\"viewport\" content=\"width=device-width, "
-            + "initial-scale=2.0, minimum-scale=2.0, maximum-scale=5.0\" />"
-            + "<style>body { width: 5000px; height: 5000px; }</style></head>"
-            + "<body>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</body>"
-            + "</html>");
-
-    private class TestAnimationIntervalProvider implements AnimationIntervalProvider {
-        private long mAnimationTime;
-        @Override
-        public long getLastAnimationFrameInterval() {
-            mAnimationTime += 16;
-            return mAnimationTime;
-        }
-    }
-
-    private class TestJoystickZoomProvider extends JoystickZoomProvider {
-        TestJoystickZoomProvider(ContentViewCore cvc, AnimationIntervalProvider intervalProvider) {
-            super(cvc, intervalProvider);
-            mDeviceScaleFactor = 2.0f;
-
-            mZoomRunnable = new Runnable() {
-                @Override
-                public void run() {}
-            };
-        }
-
-        public void animateZoomTest(final MotionEvent joystickZoomEvent, final long animationTicks)
-                throws Throwable {
-            runTestOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    onMotion(joystickZoomEvent);
-                    for (int index = 0; index < animationTicks; index++) {
-                        animateZoom();
-                    }
-                    stop();
-                }
-            });
-        }
-    }
-
-    private MotionEvent simulateJoystickEvent(final float delta, final boolean isZoomInRequest) {
-        // Synthesize joystick motion event and send to ContentViewCore.
-        final int axisVal =
-                (isZoomInRequest) ? MotionEvent.AXIS_RTRIGGER : MotionEvent.AXIS_LTRIGGER;
-        MotionEvent.PointerCoords[] cords = new MotionEvent.PointerCoords[1];
-        MotionEvent.PointerProperties[] pPts = new MotionEvent.PointerProperties[1];
-        cords[0] = new MotionEvent.PointerCoords();
-        pPts[0] = new MotionEvent.PointerProperties();
-        cords[0].setAxisValue(axisVal, delta);
-        pPts[0].id = 0;
-        MotionEvent joystickMotionEvent = MotionEvent.obtain((long) 0, SystemClock.uptimeMillis(),
-                MotionEvent.ACTION_MOVE, 1, pPts, cords, 0, 0, 0.01f, 0.01f, 3, 0,
-                InputDevice.SOURCE_CLASS_JOYSTICK, 0);
-        return joystickMotionEvent;
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        launchContentShellWithUrl(LARGE_PAGE);
-        waitForActiveShellToBeDoneLoading();
-        assertWaitForPageScaleFactorMatch(2.0f);
-    }
-
-    @SmallTest
-    @Feature({"JoystickZoom"})
-    public void testJoystickZoomIn() throws Throwable {
-        MotionEvent rTriggerEvent;
-        AnimationIntervalProvider intervalProvider = new TestAnimationIntervalProvider();
-        TestJoystickZoomProvider rtJoystickZoomProvider =
-                new TestJoystickZoomProvider(getContentViewCore(), intervalProvider);
-        // Verify page does not zoom-in if trigger motion falls in deadzone.
-        rTriggerEvent = simulateJoystickEvent(0.1f, true);
-        rtJoystickZoomProvider.animateZoomTest(rTriggerEvent, 20);
-        assertWaitForPageScaleFactorMatch(2.0f);
-
-        rTriggerEvent = simulateJoystickEvent(0.3f, true);
-        rtJoystickZoomProvider.animateZoomTest(rTriggerEvent, 20);
-        assertWaitForPageScaleFactorMatch(2.2018466f);
-
-        rTriggerEvent = simulateJoystickEvent(0.5f, true);
-        rtJoystickZoomProvider.animateZoomTest(rTriggerEvent, 40);
-        assertWaitForPageScaleFactorMatch(3.033731f);
-
-        rTriggerEvent = simulateJoystickEvent(0.75f, true);
-        rtJoystickZoomProvider.animateZoomTest(rTriggerEvent, 50);
-        assertWaitForPageScaleFactorMatch(5.0f);
-    }
-
-    @SmallTest
-    @Feature({"JoystickZoom"})
-    public void testJoystickZoomOut() throws Throwable {
-        MotionEvent lTriggerEvent;
-        AnimationIntervalProvider intervalProvider = new TestAnimationIntervalProvider();
-        TestJoystickZoomProvider ltJoystickZoomProvider =
-                new TestJoystickZoomProvider(getContentViewCore(), intervalProvider);
-
-        // Zoom page to max size.
-        lTriggerEvent = simulateJoystickEvent(1.0f, true);
-        ltJoystickZoomProvider.animateZoomTest(lTriggerEvent, 60);
-        assertWaitForPageScaleFactorMatch(5.0f);
-
-        // Verify page does not zoom-out if trigger motion falls in deadzone.
-        lTriggerEvent = simulateJoystickEvent(0.1f, false);
-        ltJoystickZoomProvider.animateZoomTest(lTriggerEvent, 20);
-        assertWaitForPageScaleFactorMatch(5.0f);
-
-        lTriggerEvent = simulateJoystickEvent(0.3f, false);
-        ltJoystickZoomProvider.animateZoomTest(lTriggerEvent, 40);
-        assertWaitForPageScaleFactorMatch(4.125306f);
-
-        lTriggerEvent = simulateJoystickEvent(0.5f, false);
-        ltJoystickZoomProvider.animateZoomTest(lTriggerEvent, 50);
-        assertWaitForPageScaleFactorMatch(2.7635581f);
-
-        lTriggerEvent = simulateJoystickEvent(0.75f, false);
-        ltJoystickZoomProvider.animateZoomTest(lTriggerEvent, 60);
-        assertWaitForPageScaleFactorMatch(2.0f);
-    }
-}
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 6037c18..88fc00b 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -73,6 +73,9 @@
 // Disable antialiasing on 2d canvas.
 const char kDisable2dCanvasAntialiasing[]   = "disable-canvas-aa";
 
+// Disables Canvas2D rendering into a scanout buffer for overlay support.
+const char kDisable2dCanvasImageChromium[] = "disable-2d-canvas-image-chromium";
+
 // Disables client-visible 3D APIs, in particular WebGL and Pepper 3D.
 // This is controlled by policy and is kept separate from the other
 // enable/disable switches to avoid accidentally regressing the policy
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index e4a1ef00..1ac14c5 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -30,6 +30,7 @@
 CONTENT_EXPORT extern const char kDefaultTileWidth[];
 CONTENT_EXPORT extern const char kDefaultTileHeight[];
 CONTENT_EXPORT extern const char kDisable2dCanvasAntialiasing[];
+CONTENT_EXPORT extern const char kDisable2dCanvasImageChromium[];
 CONTENT_EXPORT extern const char kDisable3DAPIs[];
 CONTENT_EXPORT extern const char kDisableAccelerated2dCanvas[];
 CONTENT_EXPORT extern const char kDisableAcceleratedJpegDecoding[];
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index 51ac846..1761a9c 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -1067,9 +1067,7 @@
       ->ScheduleComposite();
 }
 
-FrameWatcher::FrameWatcher()
-    : BrowserMessageFilter(ViewMsgStart), frames_to_wait_(0) {
-}
+FrameWatcher::FrameWatcher() : MessageFilter(), frames_to_wait_(0) {}
 
 FrameWatcher::~FrameWatcher() {
 }
@@ -1100,7 +1098,7 @@
   DCHECK(web_contents);
   RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::From(
       web_contents->GetRenderViewHost()->GetWidget());
-  widget_host->GetProcess()->AddFilter(this);
+  widget_host->GetProcess()->GetChannel()->AddFilter(this);
 }
 
 void FrameWatcher::WaitFrames(int frames_to_wait) {
diff --git a/content/public/test/browser_test_utils.h b/content/public/test/browser_test_utils.h
index 1793726..203c6f80 100644
--- a/content/public/test/browser_test_utils.h
+++ b/content/public/test/browser_test_utils.h
@@ -24,6 +24,7 @@
 #include "content/public/browser/render_process_host_observer.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/page_type.h"
+#include "ipc/message_filter.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
 #include "ui/events/keycodes/keyboard_codes.h"
 #include "url/gurl.h"
@@ -416,7 +417,7 @@
 // Watches compositor frame changes, blocking until a frame has been
 // composited. This class is intended to be run on the main thread; to
 // synchronize the main thread against the impl thread.
-class FrameWatcher : public BrowserMessageFilter {
+class FrameWatcher : public IPC::MessageFilter {
  public:
   FrameWatcher();
 
diff --git a/content/renderer/input/input_handler_manager.cc b/content/renderer/input/input_handler_manager.cc
index 5f1bfe04..b249a645 100644
--- a/content/renderer/input/input_handler_manager.cc
+++ b/content/renderer/input/input_handler_manager.cc
@@ -144,6 +144,7 @@
     int routing_id,
     const blink::WebMouseWheelEvent& wheel_event,
     const cc::InputHandlerScrollResult& scroll_result) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
   auto it = input_handlers_.find(routing_id);
   if (it == input_handlers_.end())
     return;
@@ -154,6 +155,32 @@
       wheel_event, scroll_result);
 }
 
+void InputHandlerManager::ObserveGestureEventAndResultOnMainThread(
+    int routing_id,
+    const blink::WebGestureEvent& gesture_event,
+    const cc::InputHandlerScrollResult& scroll_result) {
+  task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(
+          &InputHandlerManager::ObserveGestureEventAndResultOnCompositorThread,
+          base::Unretained(this), routing_id, gesture_event, scroll_result));
+}
+
+void InputHandlerManager::ObserveGestureEventAndResultOnCompositorThread(
+    int routing_id,
+    const blink::WebGestureEvent& gesture_event,
+    const cc::InputHandlerScrollResult& scroll_result) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  auto it = input_handlers_.find(routing_id);
+  if (it == input_handlers_.end())
+    return;
+
+  InputHandlerProxy* proxy = it->second->input_handler_proxy();
+  DCHECK(proxy->scroll_elasticity_controller());
+  proxy->scroll_elasticity_controller()->ObserveGestureEventAndResult(
+      gesture_event, scroll_result);
+}
+
 void InputHandlerManager::NonBlockingInputEventHandledOnMainThread(
     int routing_id,
     blink::WebInputEvent::Type type) {
diff --git a/content/renderer/input/input_handler_manager.h b/content/renderer/input/input_handler_manager.h
index 3211a1f..e9165d5 100644
--- a/content/renderer/input/input_handler_manager.h
+++ b/content/renderer/input/input_handler_manager.h
@@ -64,6 +64,11 @@
       const blink::WebMouseWheelEvent& wheel_event,
       const cc::InputHandlerScrollResult& scroll_result);
 
+  void ObserveGestureEventAndResultOnMainThread(
+      int routing_id,
+      const blink::WebGestureEvent& gesture_event,
+      const cc::InputHandlerScrollResult& scroll_result);
+
   void NonBlockingInputEventHandledOnMainThread(int routing_id,
                                                 blink::WebInputEvent::Type);
 
@@ -99,6 +104,11 @@
       const blink::WebMouseWheelEvent& wheel_event,
       const cc::InputHandlerScrollResult& scroll_result);
 
+  void ObserveGestureEventAndResultOnCompositorThread(
+      int routing_id,
+      const blink::WebGestureEvent& gesture_event,
+      const cc::InputHandlerScrollResult& scroll_result);
+
   void NonBlockingInputEventHandledOnCompositorThread(
       int routing_id,
       blink::WebInputEvent::Type);
diff --git a/content/renderer/input/render_widget_input_handler.cc b/content/renderer/input/render_widget_input_handler.cc
index 215f1f4..6a0a652 100644
--- a/content/renderer/input/render_widget_input_handler.cc
+++ b/content/renderer/input/render_widget_input_handler.cc
@@ -364,6 +364,18 @@
                            : gfx::Vector2dF(),
           processed != WebInputEventResult::NotHandled);
     }
+  } else if (input_event.type == WebInputEvent::GestureScrollBegin ||
+             input_event.type == WebInputEvent::GestureScrollEnd ||
+             input_event.type == WebInputEvent::GestureScrollUpdate) {
+    const WebGestureEvent& gesture_event =
+        static_cast<const WebGestureEvent&>(input_event);
+    if (gesture_event.sourceDevice == blink::WebGestureDeviceTouchpad) {
+      delegate_->ObserveGestureEventAndResult(
+          gesture_event,
+          event_overscroll ? event_overscroll->latest_overscroll_delta
+                           : gfx::Vector2dF(),
+          processed != WebInputEventResult::NotHandled);
+    }
   }
 
   bool frame_pending =
diff --git a/content/renderer/input/render_widget_input_handler_delegate.h b/content/renderer/input/render_widget_input_handler_delegate.h
index 7a7f544..0676b50 100644
--- a/content/renderer/input/render_widget_input_handler_delegate.h
+++ b/content/renderer/input/render_widget_input_handler_delegate.h
@@ -49,6 +49,13 @@
       const gfx::Vector2dF& wheel_unused_delta,
       bool event_processed) = 0;
 
+  // Called to forward a gesture event to the compositor thread, to effect
+  // the elastic overscroll effect.
+  virtual void ObserveGestureEventAndResult(
+      const blink::WebGestureEvent& gesture_event,
+      const gfx::Vector2dF& unused_delta,
+      bool event_processed) = 0;
+
   // Notifies that a key event was just handled.
   virtual void OnDidHandleKeyEvent() = 0;
 
diff --git a/content/renderer/mus/render_widget_mus_connection.cc b/content/renderer/mus/render_widget_mus_connection.cc
index c2dc1d1..73f17f6 100644
--- a/content/renderer/mus/render_widget_mus_connection.cc
+++ b/content/renderer/mus/render_widget_mus_connection.cc
@@ -106,6 +106,13 @@
   NOTIMPLEMENTED();
 }
 
+void RenderWidgetMusConnection::ObserveGestureEventAndResult(
+    const blink::WebGestureEvent& gesture_event,
+    const gfx::Vector2dF& wheel_unused_delta,
+    bool event_processed) {
+  NOTIMPLEMENTED();
+}
+
 void RenderWidgetMusConnection::OnDidHandleKeyEvent() {
   NOTIMPLEMENTED();
 }
diff --git a/content/renderer/mus/render_widget_mus_connection.h b/content/renderer/mus/render_widget_mus_connection.h
index fea8db3b..bd8572b6 100644
--- a/content/renderer/mus/render_widget_mus_connection.h
+++ b/content/renderer/mus/render_widget_mus_connection.h
@@ -45,6 +45,9 @@
   void ObserveWheelEventAndResult(const blink::WebMouseWheelEvent& wheel_event,
                                   const gfx::Vector2dF& wheel_unused_delta,
                                   bool event_processed) override;
+  void ObserveGestureEventAndResult(const blink::WebGestureEvent& gesture_event,
+                                    const gfx::Vector2dF& gesture_unused_delta,
+                                    bool event_processed) override;
   void OnDidHandleKeyEvent() override;
   void OnDidOverscroll(const DidOverscrollParams& params) override;
   void OnInputEventAck(scoped_ptr<InputEventAck> input_event_ack) override;
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index b1b76c9..37c33e40 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -1745,11 +1745,6 @@
   return HostAllocateSharedMemoryBuffer(size);
 }
 
-gfx::GLSurfaceHandle RenderThreadImpl::GetSurfaceHandle(int32_t surface_id) {
-  NOTREACHED();
-  return gfx::GLSurfaceHandle();
-}
-
 void RenderThreadImpl::DoNotNotifyWebKitOfModalLoop() {
   notify_webkit_of_modal_loop_ = false;
 }
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index f2f2b1e7..fc6734c 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -475,7 +475,6 @@
   bool IsMainThread() override;
   scoped_refptr<base::SingleThreadTaskRunner> GetIOThreadTaskRunner() override;
   scoped_ptr<base::SharedMemory> AllocateSharedMemory(size_t size) override;
-  gfx::GLSurfaceHandle GetSurfaceHandle(int32_t surface_id) override;
 
   void Init();
 
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index b8b4ad4f..fc404aa 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -959,6 +959,27 @@
   }
 }
 
+void RenderWidget::ObserveGestureEventAndResult(
+    const blink::WebGestureEvent& gesture_event,
+    const gfx::Vector2dF& unused_delta,
+    bool event_processed) {
+  if (!compositor_deps_->IsElasticOverscrollEnabled())
+    return;
+
+  cc::InputHandlerScrollResult scroll_result;
+  scroll_result.did_scroll = event_processed;
+  scroll_result.did_overscroll_root = !unused_delta.IsZero();
+  scroll_result.unused_scroll_delta = unused_delta;
+
+  RenderThreadImpl* render_thread = RenderThreadImpl::current();
+  InputHandlerManager* input_handler_manager =
+      render_thread ? render_thread->input_handler_manager() : NULL;
+  if (input_handler_manager) {
+    input_handler_manager->ObserveGestureEventAndResultOnMainThread(
+        routing_id_, gesture_event, scroll_result);
+  }
+}
+
 void RenderWidget::OnDidHandleKeyEvent() {
   if (owner_delegate_)
     owner_delegate_->RenderWidgetDidHandleKeyEvent();
@@ -2127,8 +2148,8 @@
   limits.min_transfer_buffer_size = 64 * 1024;
 
   return make_scoped_ptr(new WebGraphicsContext3DCommandBufferImpl(
-          0, GetURLForGraphicsContext3D(), gpu_channel_host, attributes,
-          lose_context_when_out_of_memory, limits, NULL));
+      gpu::kNullSurfaceHandle, GetURLForGraphicsContext3D(), gpu_channel_host,
+      attributes, lose_context_when_out_of_memory, limits, NULL));
 }
 
 void RenderWidget::RegisterRenderFrameProxy(RenderFrameProxy* proxy) {
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index a239554..fb2e39f3 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -213,6 +213,10 @@
   void ObserveWheelEventAndResult(const blink::WebMouseWheelEvent& wheel_event,
                                   const gfx::Vector2dF& wheel_unused_delta,
                                   bool event_processed) override;
+  void ObserveGestureEventAndResult(const blink::WebGestureEvent& gesture_event,
+                                    const gfx::Vector2dF& unused_delta,
+                                    bool event_processed) override;
+
   void OnDidHandleKeyEvent() override;
   void OnDidOverscroll(const DidOverscrollParams& params) override;
   void OnInputEventAck(scoped_ptr<InputEventAck> input_event_ack) override;
diff --git a/content/test/data/gpu/pixel_canvas2d_accelerated.html b/content/test/data/gpu/pixel_canvas2d_accelerated.html
new file mode 100644
index 0000000..700179c
--- /dev/null
+++ b/content/test/data/gpu/pixel_canvas2d_accelerated.html
@@ -0,0 +1,58 @@
+<!DOCTYPE HTML>
+
+<!-- READ BEFORE UPDATING:
+If this test is updated make sure to increment the "revision" value of the
+associated test in content/test/gpu/page_sets/pixel_tests.py. This will ensure
+that the baseline images are regenerated on the next run.
+-->
+
+<html>
+<head>
+<title>Accelerated Canvas 2D Test: Red Box over Black Background</title>
+<style type="text/css">
+.nomargin {
+  margin: 0px auto;
+}
+</style>
+<script>
+var g_swapsBeforeAck = 15;
+
+function main()
+{
+  draw();
+  waitForFinish();
+}
+
+function draw()
+{
+  var canvas = document.getElementById("c");
+  var c2d = canvas.getContext("2d");
+  c2d.clearRect(0, 0, canvas.width, canvas.height);
+  c2d.fillStyle = "rgba(255, 0, 0, 0.5)";
+  c2d.fillRect(50, 50, 100, 100);
+}
+
+function waitForFinish()
+{
+  if (g_swapsBeforeAck == 0) {
+    domAutomationController.setAutomationId(1);
+    domAutomationController.send("SUCCESS");
+  } else {
+    g_swapsBeforeAck--;
+    document.getElementById('container').style.zIndex = g_swapsBeforeAck + 1;
+    window.webkitRequestAnimationFrame(waitForFinish);
+  }
+}
+</script>
+</head>
+<body onload="main()">
+<div style="position:relative; width:300px; height:300px; background-color:black">
+</div>
+<div id="container" style="position:absolute; top:0px; left:0px">
+<!--
+Canvas acceleration requires that the canvas be at least 256x257.
+-->
+<canvas id="c" width="300" height="300" class="nomargin"></canvas>
+</div>
+</body>
+</html>
diff --git a/content/test/gpu/gpu_tests/pixel_expectations.py b/content/test/gpu/gpu_tests/pixel_expectations.py
index e4875a48..0683818 100644
--- a/content/test/gpu/gpu_tests/pixel_expectations.py
+++ b/content/test/gpu/gpu_tests/pixel_expectations.py
@@ -23,3 +23,6 @@
     # TODO(ccameron): Remove suppression after rebaseline.
     self.Fail('Pixel.CSS3DBlueBox', ['mac'], bug=533690)
     self.Fail('Pixel.CSS3DBlueBoxES3', ['mac'], bug=533690)
+
+    # TODO(erikchen): Remove suppression after generating reference images.
+    self.Fail('Pixel.IOSurface2DCanvas', ['mac'], bug=579664)
diff --git a/content/test/gpu/page_sets/pixel_tests.py b/content/test/gpu/page_sets/pixel_tests.py
index 0f7ae64..4b1d3f18 100644
--- a/content/test/gpu/page_sets/pixel_tests.py
+++ b/content/test/gpu/page_sets/pixel_tests.py
@@ -36,6 +36,15 @@
       ['--enable-unsafe-es3-apis'])
 
 
+class IOSurface2DCanvasSharedPageState(gpu_test_base.GpuSharedPageState):
+  def __init__(self, test, finder_options, story_set):
+    super(IOSurface2DCanvasSharedPageState, self).__init__(
+      test, finder_options, story_set)
+    finder_options.browser_options.AppendExtraBrowserArgs(
+      ['--enable-accelerated-2d-canvas',
+       '--disable-display-list-2d-canvas'])
+
+
 class PixelTestsStorySet(story_set_module.StorySet):
 
   """ Some basic test cases for GPU. """
@@ -52,6 +61,17 @@
       # OS.
       self._AddAllPages(expectations, base_name, True)
 
+    # On OS X, test the IOSurface 2D Canvas compositing path.
+    if sys.platform.startswith('darwin'):
+      self.AddStory(PixelTestsPage(
+        url='file://../../data/gpu/pixel_canvas2d_accelerated.html',
+        name=base_name + '.IOSurface2DCanvas',
+        test_rect=[0, 0, 400, 400],
+        revision=1,
+        story_set=self,
+        shared_page_state_class=IOSurface2DCanvasSharedPageState,
+        expectations=expectations))
+
   def _AddAllPages(self, expectations, base_name, use_es3):
     if use_es3:
       es3_suffix = 'ES3'
diff --git a/content/utility/utility_thread_impl.cc b/content/utility/utility_thread_impl.cc
index b6587f5..fc779a02 100644
--- a/content/utility/utility_thread_impl.cc
+++ b/content/utility/utility_thread_impl.cc
@@ -57,7 +57,7 @@
   ChildThreadImpl::Shutdown();
 
   if (blink_platform_impl_)
-    blink::shutdownWithoutV8();
+    blink::Platform::shutdown();
 }
 
 void UtilityThreadImpl::ReleaseProcessIfNeeded() {
@@ -85,7 +85,7 @@
   }
 
   blink_platform_impl_.reset(new UtilityBlinkPlatformImpl);
-  blink::initializeWithoutV8(blink_platform_impl_.get());
+  blink::Platform::initialize(blink_platform_impl_.get());
 }
 
 void UtilityThreadImpl::Init() {
diff --git a/extensions/browser/guest_view/web_view/web_view_guest.cc b/extensions/browser/guest_view/web_view/web_view_guest.cc
index b1ae0a52..95aefd2 100644
--- a/extensions/browser/guest_view/web_view/web_view_guest.cc
+++ b/extensions/browser/guest_view/web_view/web_view_guest.cc
@@ -747,9 +747,9 @@
     int render_process_id = web_contents()->GetRenderProcessHost()->GetID();
     // We need to clear renderer cache separately for our process because
     // StoragePartitionHttpCacheDataRemover::ClearData() does not clear that.
-    web_cache::WebCacheManager::GetInstance()->Remove(render_process_id);
     web_cache::WebCacheManager::GetInstance()->ClearCacheForProcess(
         render_process_id);
+    web_cache::WebCacheManager::GetInstance()->Remove(render_process_id);
 
     base::Closure cache_removal_done_callback = base::Bind(
         &WebViewGuest::ClearDataInternal, weak_ptr_factory_.GetWeakPtr(),
diff --git a/extensions/renderer/i18n_custom_bindings.cc b/extensions/renderer/i18n_custom_bindings.cc
index 365f50a..08d9e75aa 100644
--- a/extensions/renderer/i18n_custom_bindings.cc
+++ b/extensions/renderer/i18n_custom_bindings.cc
@@ -11,6 +11,7 @@
 
 #include "base/bind.h"
 #include "base/macros.h"
+#include "content/public/child/v8_value_converter.h"
 #include "content/public/renderer/render_frame.h"
 #include "content/public/renderer/render_thread.h"
 #include "extensions/common/extension_messages.h"
@@ -36,7 +37,7 @@
 
   // Returns a new v8::Local<v8::Value> representing the serialized form of
   // this DetectedLanguage object.
-  v8::Local<v8::Value> ToValue(ScriptContext* context);
+  scoped_ptr<base::DictionaryValue> ToDictionary() const;
 
   std::string language;
   int percentage;
@@ -67,40 +68,28 @@
   DISALLOW_COPY_AND_ASSIGN(LanguageDetectionResult);
 };
 
-v8::Local<v8::Value> DetectedLanguage::ToValue(ScriptContext* context) {
-  v8::Local<v8::Context> v8_context = context->v8_context();
-  v8::Isolate* isolate = v8_context->GetIsolate();
-  v8::EscapableHandleScope handle_scope(isolate);
-
-  v8::Local<v8::Object> value(v8::Object::New(isolate));
-  SetProperty(v8_context, value, ToV8StringUnsafe(isolate, "language"),
-              ToV8StringUnsafe(isolate, language.c_str()));
-
-  SetProperty(v8_context, value, ToV8StringUnsafe(isolate, "percentage"),
-              v8::Number::New(isolate, percentage));
-
-  v8::Local<v8::Value> result = v8::Local<v8::Value>::Cast(value);
-  return handle_scope.Escape(result);
+scoped_ptr<base::DictionaryValue> DetectedLanguage::ToDictionary() const {
+  scoped_ptr<base::DictionaryValue> dict_value(new base::DictionaryValue());
+  dict_value->SetString("language", language.c_str());
+  dict_value->SetInteger("percentage", percentage);
+  return dict_value;
 }
 
 v8::Local<v8::Value> LanguageDetectionResult::ToValue(ScriptContext* context) {
+  base::DictionaryValue dict_value;
+  dict_value.SetBoolean("isReliable", is_reliable);
+  scoped_ptr<base::ListValue> languages_list(new base::ListValue());
+  for (const auto& language : languages)
+    languages_list->Append(language->ToDictionary());
+  dict_value.Set("languages", std::move(languages_list));
+
   v8::Local<v8::Context> v8_context = context->v8_context();
   v8::Isolate* isolate = v8_context->GetIsolate();
   v8::EscapableHandleScope handle_scope(isolate);
 
-  v8::Local<v8::Object> value(v8::Object::New(isolate));
-  SetProperty(v8_context, value, ToV8StringUnsafe(isolate, "isReliable"),
-              v8::Boolean::New(isolate, is_reliable));
-
-  v8::Local<v8::Array> langs(v8::Array::New(isolate, languages.size()));
-  for (size_t i = 0; i < languages.size(); ++i) {
-    SetProperty(v8_context, langs, i, languages[i]->ToValue(context));
-  }
-
-  SetProperty(isolate->GetCurrentContext(), value,
-              ToV8StringUnsafe(isolate, "languages"), langs);
-
-  v8::Local<v8::Value> result = v8::Local<v8::Value>::Cast(value);
+  scoped_ptr<content::V8ValueConverter> converter(
+      content::V8ValueConverter::create());
+  v8::Local<v8::Value> result = converter->ToV8Value(&dict_value, v8_context);
   return handle_scope.Escape(result);
 }
 
diff --git a/extensions/renderer/v8_helpers.h b/extensions/renderer/v8_helpers.h
index 560beee..b0dd17a 100644
--- a/extensions/renderer/v8_helpers.h
+++ b/extensions/renderer/v8_helpers.h
@@ -71,23 +71,6 @@
   return IsTrue(object->DefineOwnProperty(context, key, value));
 }
 
-inline bool SetProperty(v8::Local<v8::Context> context,
-                        v8::Local<v8::Object> object,
-                        const char* key,
-                        v8::Local<v8::Value> value) {
-  v8::Local<v8::String> v8_key;
-  if (!ToV8String(context->GetIsolate(), key, &v8_key))
-    return false;
-  return SetProperty(context, object, v8_key, value);
-}
-
-inline bool SetProperty(v8::Local<v8::Context> context,
-                        v8::Local<v8::Object> object,
-                        uint32_t index,
-                        v8::Local<v8::Value> value) {
-  return SetProperty(context, object, base::UintToString(index).c_str(), value);
-}
-
 // Wraps v8::Object::SetPrivate(). When possible, prefer this to SetProperty().
 inline bool SetPrivateProperty(v8::Local<v8::Context> context,
                                v8::Local<v8::Object> object,
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index 81d796a..3ee217d 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -1533,6 +1533,18 @@
       'GL_COMPARE_REF_TO_TEXTURE',
     ],
   },
+  'TextureSwizzle': {
+    'type': 'GLenum',
+    'is_complete': True,
+    'valid': [
+      'GL_RED',
+      'GL_GREEN',
+      'GL_BLUE',
+      'GL_ALPHA',
+      'GL_ZERO',
+      'GL_ONE',
+    ],
+  },
   'TextureUsage': {
     'type': 'GLenum',
     'is_complete': True,
@@ -2406,6 +2418,7 @@
     'type': 'Bind',
     'decoder_func': 'DoBindBufferBase',
     'gen_func': 'GenBuffersARB',
+    'unit_test': False,
     'unsafe': True,
   },
   'BindBufferRange': {
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index b54561d..4c1194c 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -1279,7 +1279,7 @@
       << count << ", "
       << GLES2Util::GetStringIndexType(type) << ", "
       << static_cast<const void*>(indices) << ")");
-  DrawElementsImpl(mode, count, type, indices, "glDrawRangeElements");
+  DrawElementsImpl(mode, count, type, indices, "glDrawElements");
 }
 
 void GLES2Implementation::DrawRangeElements(
@@ -3904,6 +3904,34 @@
     GLenum target, GLuint index, GLuint buffer_id) {
   // TODO(zmo): See note #1 above.
   // TODO(zmo): See note #2 above.
+  switch (target) {
+    case GL_TRANSFORM_FEEDBACK_BUFFER:
+      if (index >=
+          static_cast<GLuint>(
+              capabilities_.max_transform_feedback_separate_attribs)) {
+        SetGLError(GL_INVALID_VALUE,
+                   "glBindBufferBase", "index out of range");
+        return;
+      }
+      if (bound_transform_feedback_buffer_ != buffer_id) {
+        bound_transform_feedback_buffer_ = buffer_id;
+      }
+      break;
+    case GL_UNIFORM_BUFFER:
+      if (index >=
+          static_cast<GLuint>(capabilities_.max_uniform_buffer_bindings)) {
+        SetGLError(GL_INVALID_VALUE,
+                   "glBindBufferBase", "index out of range");
+        return;
+      }
+      if (bound_uniform_buffer_ != buffer_id) {
+        bound_uniform_buffer_ = buffer_id;
+      }
+      break;
+    default:
+      SetGLError(GL_INVALID_ENUM, "glBindBufferBase", "invalid target");
+      return;
+  }
   GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
       this, target, index, buffer_id, &GLES2Implementation::BindBufferBaseStub);
 }
diff --git a/gpu/command_buffer/common/gles2_cmd_utils_autogen.h b/gpu/command_buffer/common/gles2_cmd_utils_autogen.h
index 1ba42ab..fb7fbebd 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils_autogen.h
@@ -98,6 +98,7 @@
     uint32_t value);
 static std::string GetStringTextureStencilRenderableInternalFormat(
     uint32_t value);
+static std::string GetStringTextureSwizzle(uint32_t value);
 static std::string GetStringTextureTarget(uint32_t value);
 static std::string GetStringTextureUnsizedInternalFormat(uint32_t value);
 static std::string GetStringTextureUsage(uint32_t value);
diff --git a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
index 0260dd5..a9f0cb8b 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
@@ -4870,6 +4870,15 @@
                                            arraysize(string_table), value);
 }
 
+std::string GLES2Util::GetStringTextureSwizzle(uint32_t value) {
+  static const EnumToString string_table[] = {
+      {GL_RED, "GL_RED"},     {GL_GREEN, "GL_GREEN"}, {GL_BLUE, "GL_BLUE"},
+      {GL_ALPHA, "GL_ALPHA"}, {GL_ZERO, "GL_ZERO"},   {GL_ONE, "GL_ONE"},
+  };
+  return GLES2Util::GetQualifiedEnumString(string_table,
+                                           arraysize(string_table), value);
+}
+
 std::string GLES2Util::GetStringTextureTarget(uint32_t value) {
   static const EnumToString string_table[] = {
       {GL_TEXTURE_2D, "GL_TEXTURE_2D"},
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 743e618..f7bef77 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -4558,6 +4558,36 @@
     // TODO(kbr): track indexed bound buffers.
     service_id = buffer->service_id();
   }
+  switch (target) {
+    case GL_TRANSFORM_FEEDBACK_BUFFER: {
+      GLint max_transform_feedback_separate_attribs = 0;
+      DoGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
+                    &max_transform_feedback_separate_attribs);
+      if (index >=
+          static_cast<GLuint>(max_transform_feedback_separate_attribs)) {
+        LOCAL_SET_GL_ERROR(GL_INVALID_VALUE,
+                           "glBindBufferBase", "index out of range");
+        return;
+      }
+      break;
+    }
+    case GL_UNIFORM_BUFFER: {
+      GLint max_uniform_buffer_bindings = 0;
+      DoGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS,
+                    &max_uniform_buffer_bindings);
+      if (index >= static_cast<GLuint>(max_uniform_buffer_bindings)) {
+        LOCAL_SET_GL_ERROR(GL_INVALID_VALUE,
+                           "glBindBufferBase", "index out of range");
+        return;
+      }
+      break;
+    }
+    default:
+      LOCAL_SET_GL_ERROR_INVALID_ENUM(
+          "glBindBufferBase", target, "invalid target");
+      return;
+  }
+  state_.SetBoundBuffer(target, buffer);
   glBindBufferBase(target, index, service_id);
 }
 
@@ -7878,7 +7908,7 @@
   }
 
   LOCAL_PERFORMANCE_WARNING(
-      "Attribute 0 is disabled. This has signficant performance penalty");
+      "Attribute 0 is disabled. This has significant performance penalty");
 
   LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER(function_name);
   glBindBuffer(GL_ARRAY_BUFFER, attrib_0_buffer_id_);
@@ -7967,7 +7997,7 @@
   }
 
   LOCAL_PERFORMANCE_WARNING(
-      "GL_FIXED attributes have a signficant performance penalty");
+      "GL_FIXED attributes have a significant performance penalty");
 
   // NOTE: we could be smart and try to check if a buffer is used
   // twice in 2 different attribs, find the overlapping parts and therefore
@@ -11537,8 +11567,9 @@
     // some part was clipped so clear the rect.
     scoped_ptr<char[]> zero(new char[pixels_size]);
     memset(zero.get(), 0, pixels_size);
-    glTexImage2D(target, level, internal_format, width, height, border,
-                 format, type, zero.get());
+    glTexImage2D(target, level,
+                 texture_manager()->AdjustTexInternalFormat(internal_format),
+                 width, height, border, format, type, zero.get());
     if (copyHeight > 0 && copyWidth > 0) {
       GLint dx = copyX - x;
       GLint dy = copyY - y;
@@ -11549,7 +11580,8 @@
                           copyWidth, copyHeight);
     }
   } else {
-    glCopyTexImage2D(target, level, internal_format,
+    glCopyTexImage2D(target, level, texture_manager()->AdjustTexInternalFormat(
+                                        internal_format),
                      copyX, copyY, copyWidth, copyHeight, border);
   }
   GLenum error = LOCAL_PEEK_GL_ERROR("glCopyTexImage2D");
@@ -11557,6 +11589,7 @@
     texture_manager()->SetLevelInfo(texture_ref, target, level, internal_format,
                                     width, height, 1, border, format,
                                     type, gfx::Rect(width, height));
+    texture->ApplyFormatWorkarounds(feature_info_.get());
   }
 
   // This may be a slow command.  Exit command processing to allow for
@@ -13542,8 +13575,11 @@
     // Ensure that the glTexImage2D succeeds.
     LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glCopyTextureCHROMIUM");
     glBindTexture(dest_target, dest_texture->service_id());
-    glTexImage2D(dest_target, 0, internal_format, source_width, source_height,
-                 0, internal_format, dest_type, NULL);
+    glTexImage2D(dest_target, 0,
+                 texture_manager()->AdjustTexInternalFormat(internal_format),
+                 source_width, source_height, 0,
+                 texture_manager()->AdjustTexFormat(internal_format), dest_type,
+                 NULL);
     GLenum error = LOCAL_PEEK_GL_ERROR("glCopyTextureCHROMIUM");
     if (error != GL_NO_ERROR) {
       RestoreCurrentTextureBindings(&state_, dest_target);
@@ -13554,6 +13590,7 @@
         dest_texture_ref, dest_target, 0, internal_format, source_width,
         source_height, 1, 0, internal_format, dest_type,
         gfx::Rect(source_width, source_height));
+    dest_texture->ApplyFormatWorkarounds(feature_info_.get());
   } else {
     texture_manager()->SetLevelCleared(dest_texture_ref, dest_target, 0,
                                        true);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h
index 0c6f1a60..06d220a 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h
@@ -51,35 +51,6 @@
   EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
 }
 
-TEST_P(GLES2DecoderTest1, BindBufferBaseValidArgs) {
-  EXPECT_CALL(
-      *gl_, BindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 2, kServiceBufferId));
-  SpecializedSetup<cmds::BindBufferBase, 0>(true);
-  cmds::BindBufferBase cmd;
-  cmd.Init(GL_TRANSFORM_FEEDBACK_BUFFER, 2, client_buffer_id_);
-  decoder_->set_unsafe_es3_apis_enabled(true);
-  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(GL_NO_ERROR, GetGLError());
-  decoder_->set_unsafe_es3_apis_enabled(false);
-  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
-}
-
-TEST_P(GLES2DecoderTest1, BindBufferBaseValidArgsNewId) {
-  EXPECT_CALL(*gl_,
-              BindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 2, kNewServiceId));
-  EXPECT_CALL(*gl_, GenBuffersARB(1, _))
-      .WillOnce(SetArgumentPointee<1>(kNewServiceId));
-  SpecializedSetup<cmds::BindBufferBase, 0>(true);
-  cmds::BindBufferBase cmd;
-  cmd.Init(GL_TRANSFORM_FEEDBACK_BUFFER, 2, kNewClientId);
-  decoder_->set_unsafe_es3_apis_enabled(true);
-  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(GL_NO_ERROR, GetGLError());
-  EXPECT_TRUE(GetBuffer(kNewClientId) != NULL);
-  decoder_->set_unsafe_es3_apis_enabled(false);
-  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
-}
-
 TEST_P(GLES2DecoderTest1, BindBufferRangeValidArgs) {
   EXPECT_CALL(*gl_, BindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 2,
                                     kServiceBufferId, 4, 4));
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_buffers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_buffers.cc
index 5af242b..b6c0162 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_buffers.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_buffers.cc
@@ -21,6 +21,41 @@
 
 }  // namespace anonymous
 
+TEST_P(GLES2DecoderTest, BindBufferBaseValidArgs) {
+  EXPECT_CALL(
+      *gl_, BindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 2, kServiceBufferId));
+  EXPECT_CALL(*gl_, GetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, _))
+      .WillOnce(SetArgPointee<1>(4))
+      .RetiresOnSaturation();
+  SpecializedSetup<cmds::BindBufferBase, 0>(true);
+  cmds::BindBufferBase cmd;
+  cmd.Init(GL_TRANSFORM_FEEDBACK_BUFFER, 2, client_buffer_id_);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES2DecoderTest, BindBufferBaseValidArgsNewId) {
+  EXPECT_CALL(*gl_,
+              BindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 2, kNewServiceId));
+  EXPECT_CALL(*gl_, GetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, _))
+      .WillOnce(SetArgPointee<1>(4))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, GenBuffersARB(1, _))
+      .WillOnce(SetArgPointee<1>(kNewServiceId));
+  SpecializedSetup<cmds::BindBufferBase, 0>(true);
+  cmds::BindBufferBase cmd;
+  cmd.Init(GL_TRANSFORM_FEEDBACK_BUFFER, 2, kNewClientId);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  EXPECT_TRUE(GetBuffer(kNewClientId) != NULL);
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+}
+
 TEST_P(GLES2DecoderTest, MapBufferRangeUnmapBufferReadSucceeds) {
   const GLenum kTarget = GL_ARRAY_BUFFER;
   const GLintptr kOffset = 10;
diff --git a/gpu/command_buffer/service/gles2_cmd_validation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
index 577dc28..99161c6 100644
--- a/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
@@ -350,6 +350,12 @@
 ValueValidator<GLenum> texture_sized_color_renderable_internal_format;
 ValueValidator<GLenum> texture_sized_texture_filterable_internal_format;
 ValueValidator<GLenum> texture_stencil_renderable_internal_format;
+class TextureSwizzleValidator {
+ public:
+  bool IsValid(const GLenum value) const;
+};
+TextureSwizzleValidator texture_swizzle;
+
 ValueValidator<GLenum> texture_target;
 ValueValidator<GLenum> texture_unsized_internal_format;
 class TextureUsageValidator {
diff --git a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
index 7e6122cc..8cbb4bf 100644
--- a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
@@ -1240,6 +1240,19 @@
         GL_STENCIL_INDEX8, GL_DEPTH24_STENCIL8, GL_DEPTH32F_STENCIL8,
 };
 
+bool Validators::TextureSwizzleValidator::IsValid(const GLenum value) const {
+  switch (value) {
+    case GL_RED:
+    case GL_GREEN:
+    case GL_BLUE:
+    case GL_ALPHA:
+    case GL_ZERO:
+    case GL_ONE:
+      return true;
+  }
+  return false;
+};
+
 static const GLenum valid_texture_target_table[] = {
     GL_TEXTURE_2D,
     GL_TEXTURE_CUBE_MAP_POSITIVE_X,
diff --git a/gpu/command_buffer/service/test_helper.cc b/gpu/command_buffer/service/test_helper.cc
index a18b7016..7d22557 100644
--- a/gpu/command_buffer/service/test_helper.cc
+++ b/gpu/command_buffer/service/test_helper.cc
@@ -196,6 +196,7 @@
 void TestHelper::SetupTextureManagerInitExpectations(
     ::gfx::MockGLInterface* gl,
     bool is_es3_enabled,
+    bool is_desktop_core_profile,
     const char* extensions,
     bool use_default_textures) {
   InSequence sequence;
@@ -213,7 +214,7 @@
   }
 
   bool ext_image_external = false;
-  bool arb_texture_rectangle = false;
+  bool arb_texture_rectangle = is_desktop_core_profile;
   base::CStringTokenizer t(extensions, extensions + strlen(extensions), " ");
   while (t.GetNext()) {
     if (t.token() == "GL_OES_EGL_image_external") {
@@ -275,6 +276,7 @@
 void TestHelper::SetupTextureManagerDestructionExpectations(
     ::gfx::MockGLInterface* gl,
     bool is_es3_enabled,
+    bool is_desktop_core_profile,
     const char* extensions,
     bool use_default_textures) {
   SetupTextureDestructionExpectations(gl, GL_TEXTURE_2D, use_default_textures);
@@ -306,7 +308,7 @@
     SetupTextureDestructionExpectations(
         gl, GL_TEXTURE_EXTERNAL_OES, use_default_textures);
   }
-  if (arb_texture_rectangle) {
+  if (arb_texture_rectangle || is_desktop_core_profile) {
     SetupTextureDestructionExpectations(
         gl, GL_TEXTURE_RECTANGLE_ARB, use_default_textures);
   }
@@ -405,7 +407,8 @@
 
   bool use_default_textures = bind_generates_resource;
   SetupTextureManagerInitExpectations(
-      gl, false, extensions, use_default_textures);
+      gl, false, gl_info.is_desktop_core_profile, extensions,
+      use_default_textures);
 }
 
 void TestHelper::SetupFeatureInfoInitExpectations(
@@ -417,7 +420,8 @@
      ::gfx::MockGLInterface* gl,
      const char* extensions,
      const char* gl_renderer,
-     const char* gl_version) {
+     const char* gl_version,
+     bool enable_es3) {
   InSequence sequence;
 
   EXPECT_CALL(*gl, GetString(GL_VERSION))
@@ -506,7 +510,54 @@
       EXPECT_CALL(*gl, CheckFramebufferStatusEXT(GL_FRAMEBUFFER))
           .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
           .RetiresOnSaturation();
+
+      if (enable_es3 && gl_info.IsES3Capable()) {
+        EXPECT_CALL(*gl, TexImage2D(GL_TEXTURE_2D, 0, GL_R16F, width, width,
+            0, GL_RED, GL_FLOAT, _))
+            .Times(1)
+            .RetiresOnSaturation();
+        EXPECT_CALL(*gl, CheckFramebufferStatusEXT(GL_FRAMEBUFFER))
+            .Times(1)
+            .RetiresOnSaturation();
+        EXPECT_CALL(*gl, TexImage2D(GL_TEXTURE_2D, 0, GL_RG16F, width, width,
+            0, GL_RG, GL_FLOAT, _))
+            .Times(1)
+            .RetiresOnSaturation();
+        EXPECT_CALL(*gl, CheckFramebufferStatusEXT(GL_FRAMEBUFFER))
+            .Times(1)
+            .RetiresOnSaturation();
+        EXPECT_CALL(*gl, TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, width,
+            0, GL_RGBA, GL_FLOAT, _))
+            .Times(1)
+            .RetiresOnSaturation();
+        EXPECT_CALL(*gl, CheckFramebufferStatusEXT(GL_FRAMEBUFFER))
+            .Times(1)
+            .RetiresOnSaturation();
+        EXPECT_CALL(*gl, TexImage2D(GL_TEXTURE_2D, 0, GL_R32F, width, width,
+            0, GL_RED, GL_FLOAT, _))
+            .Times(1)
+            .RetiresOnSaturation();
+        EXPECT_CALL(*gl, CheckFramebufferStatusEXT(GL_FRAMEBUFFER))
+            .Times(1)
+            .RetiresOnSaturation();
+        EXPECT_CALL(*gl, TexImage2D(GL_TEXTURE_2D, 0, GL_RG32F, width, width,
+            0, GL_RG, GL_FLOAT, _))
+            .Times(1)
+            .RetiresOnSaturation();
+        EXPECT_CALL(*gl, CheckFramebufferStatusEXT(GL_FRAMEBUFFER))
+            .Times(1)
+            .RetiresOnSaturation();
+        EXPECT_CALL(*gl, TexImage2D(GL_TEXTURE_2D, 0, GL_R11F_G11F_B10F,
+            width, width, 0, GL_RGB, GL_FLOAT, _))
+            .Times(1)
+            .RetiresOnSaturation();
+        EXPECT_CALL(*gl, CheckFramebufferStatusEXT(GL_FRAMEBUFFER))
+            .Times(1)
+            .RetiresOnSaturation();
+      }
     }
+
+
     EXPECT_CALL(*gl, DeleteFramebuffersEXT(1, _))
         .Times(1)
         .RetiresOnSaturation();
diff --git a/gpu/command_buffer/service/test_helper.h b/gpu/command_buffer/service/test_helper.h
index f285c2c..84bab2f 100644
--- a/gpu/command_buffer/service/test_helper.h
+++ b/gpu/command_buffer/service/test_helper.h
@@ -104,14 +104,18 @@
       ::gfx::MockGLInterface* gl,
       const char* extensions,
       const char* gl_renderer,
-      const char* gl_version);
-  static void SetupTextureManagerInitExpectations(::gfx::MockGLInterface* gl,
-                                                  bool is_es3_enabled,
-                                                  const char* extensions,
-                                                  bool use_default_textures);
+      const char* gl_version,
+      bool enable_es3 = false);
+  static void SetupTextureManagerInitExpectations(
+      ::gfx::MockGLInterface* gl,
+      bool is_es3_enabled,
+      bool is_desktop_core_profile,
+      const char* extensions,
+      bool use_default_textures);
   static void SetupTextureManagerDestructionExpectations(
       ::gfx::MockGLInterface* gl,
       bool is_es3_enabled,
+      bool is_desktop_core_profile,
       const char* extensions,
       bool use_default_textures);
 
diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc
index 5f93ce4..7e8ea5a 100644
--- a/gpu/command_buffer/service/texture_manager.cc
+++ b/gpu/command_buffer/service/texture_manager.cc
@@ -263,6 +263,45 @@
   std::set<FormatType, FormatTypeCompare> supported_combinations_;
 };
 
+static const Texture::CompatibilitySwizzle kSwizzledFormats[] = {
+    {GL_ALPHA, GL_RED, GL_ZERO, GL_ZERO, GL_ZERO, GL_RED},
+    {GL_LUMINANCE, GL_RED, GL_RED, GL_RED, GL_RED, GL_ONE},
+    {GL_LUMINANCE_ALPHA, GL_RG, GL_RED, GL_RED, GL_RED, GL_GREEN},
+};
+
+const Texture::CompatibilitySwizzle* GetCompatibilitySwizzle(GLenum format) {
+  size_t count = arraysize(kSwizzledFormats);
+  for (size_t i = 0; i < count; ++i) {
+    if (kSwizzledFormats[i].format == format)
+      return &kSwizzledFormats[i];
+  }
+  return nullptr;
+}
+
+GLenum GetSwizzleForChannel(GLenum channel,
+                            const Texture::CompatibilitySwizzle* swizzle) {
+  if (!swizzle)
+    return channel;
+
+  switch (channel) {
+    case GL_ZERO:
+      return GL_ZERO;
+    case GL_ONE:
+      return GL_ONE;
+    case GL_RED:
+      return swizzle->red;
+    case GL_GREEN:
+      return swizzle->green;
+    case GL_BLUE:
+      return swizzle->blue;
+    case GL_ALPHA:
+      return swizzle->alpha;
+    default:
+      NOTREACHED();
+      return GL_NONE;
+  }
+}
+
 base::LazyInstance<const FormatTypeValidator>::Leaky g_format_type_validator =
     LAZY_INSTANCE_INITIALIZER;
 
@@ -316,6 +355,10 @@
       usage_(GL_NONE),
       base_level_(0),
       max_level_(1000),
+      swizzle_r_(GL_RED),
+      swizzle_g_(GL_GREEN),
+      swizzle_b_(GL_BLUE),
+      swizzle_a_(GL_ALPHA),
       max_level_set_(-1),
       texture_complete_(false),
       texture_mips_dirty_(false),
@@ -327,7 +370,8 @@
       has_images_(false),
       estimated_size_(0),
       can_render_condition_(CAN_RENDER_ALWAYS),
-      texture_max_anisotropy_initialized_(false) {}
+      texture_max_anisotropy_initialized_(false),
+      compatibility_swizzle_(nullptr) {}
 
 Texture::~Texture() {
   if (mailbox_manager_)
@@ -1101,6 +1145,30 @@
       }
       usage_ = param;
       break;
+    case GL_TEXTURE_SWIZZLE_R:
+      if (!feature_info->validators()->texture_swizzle.IsValid(param)) {
+        return GL_INVALID_ENUM;
+      }
+      swizzle_r_ = param;
+      break;
+    case GL_TEXTURE_SWIZZLE_G:
+      if (!feature_info->validators()->texture_swizzle.IsValid(param)) {
+        return GL_INVALID_ENUM;
+      }
+      swizzle_g_ = param;
+      break;
+    case GL_TEXTURE_SWIZZLE_B:
+      if (!feature_info->validators()->texture_swizzle.IsValid(param)) {
+        return GL_INVALID_ENUM;
+      }
+      swizzle_b_ = param;
+      break;
+    case GL_TEXTURE_SWIZZLE_A:
+      if (!feature_info->validators()->texture_swizzle.IsValid(param)) {
+        return GL_INVALID_ENUM;
+      }
+      swizzle_a_ = param;
+      break;
     default:
       NOTREACHED();
       return GL_INVALID_ENUM;
@@ -1520,6 +1588,34 @@
   }
 }
 
+GLenum Texture::GetCompatibilitySwizzleForChannel(GLenum channel) {
+  return GetSwizzleForChannel(channel, compatibility_swizzle_);
+}
+
+void Texture::SetCompatibilitySwizzle(const CompatibilitySwizzle* swizzle) {
+  if (compatibility_swizzle_ == swizzle)
+    return;
+
+  compatibility_swizzle_ = swizzle;
+  glTexParameteri(target_, GL_TEXTURE_SWIZZLE_R,
+                  GetSwizzleForChannel(swizzle_r_, swizzle));
+  glTexParameteri(target_, GL_TEXTURE_SWIZZLE_G,
+                  GetSwizzleForChannel(swizzle_g_, swizzle));
+  glTexParameteri(target_, GL_TEXTURE_SWIZZLE_B,
+                  GetSwizzleForChannel(swizzle_b_, swizzle));
+  glTexParameteri(target_, GL_TEXTURE_SWIZZLE_A,
+                  GetSwizzleForChannel(swizzle_a_, swizzle));
+}
+
+void Texture::ApplyFormatWorkarounds(FeatureInfo* feature_info) {
+  if (feature_info->gl_version_info().is_desktop_core_profile) {
+    if (static_cast<size_t>(base_level_) >= face_infos_[0].level_infos.size())
+      return;
+    const Texture::LevelInfo& info = face_infos_[0].level_infos[base_level_];
+    SetCompatibilitySwizzle(GetCompatibilitySwizzle(info.format));
+  }
+}
+
 TextureRef::TextureRef(TextureManager* manager,
                        GLuint client_id,
                        Texture* texture)
@@ -1795,7 +1891,18 @@
           error_state, result, function_name, pname, param);
     }
   } else {
-    glTexParameteri(texture->target(), pname, param);
+    switch (pname) {
+      case GL_TEXTURE_SWIZZLE_R:
+      case GL_TEXTURE_SWIZZLE_G:
+      case GL_TEXTURE_SWIZZLE_B:
+      case GL_TEXTURE_SWIZZLE_A:
+        glTexParameteri(texture->target(), pname,
+                        texture->GetCompatibilitySwizzleForChannel(param));
+        break;
+      default:
+        glTexParameteri(texture->target(), pname, param);
+        break;
+    }
   }
 }
 
@@ -2332,7 +2439,8 @@
                    args.height, args.depth, 0, AdjustTexFormat(args.format),
                    args.type, args.pixels);
     } else {
-      glTexImage2D(args.target, args.level, internal_format, args.width,
+      glTexImage2D(args.target, args.level,
+                   AdjustTexInternalFormat(internal_format), args.width,
                    args.height, 0, AdjustTexFormat(args.format), args.type,
                    args.pixels);
     }
@@ -2351,6 +2459,16 @@
   SetLevelCleared(texture_ref, args.target, args.level, true);
 }
 
+GLenum TextureManager::AdjustTexInternalFormat(GLenum format) const {
+  if (feature_info_->gl_version_info().is_desktop_core_profile) {
+    const Texture::CompatibilitySwizzle* swizzle =
+        GetCompatibilitySwizzle(format);
+    if (swizzle)
+      return swizzle->dest_format;
+  }
+  return format;
+}
+
 GLenum TextureManager::AdjustTexFormat(GLenum format) const {
   // TODO(bajones): GLES 3 allows for internal format and format to differ.
   // This logic may need to change as a result.
@@ -2360,6 +2478,12 @@
     if (format == GL_SRGB_ALPHA_EXT)
       return GL_RGBA;
   }
+  if (feature_info_->gl_version_info().is_desktop_core_profile) {
+    const Texture::CompatibilitySwizzle* swizzle =
+        GetCompatibilitySwizzle(format);
+    if (swizzle)
+      return swizzle->dest_format;
+  }
   return format;
 }
 
@@ -2427,7 +2551,8 @@
                    args.height, args.depth, args.border, args.format,
                    args.type, args.pixels);
     } else {
-      glTexImage2D(args.target, args.level, args.internal_format, args.width,
+      glTexImage2D(args.target, args.level,
+                   AdjustTexInternalFormat(args.internal_format), args.width,
                    args.height, args.border, AdjustTexFormat(args.format),
                    args.type, args.pixels);
     }
@@ -2446,6 +2571,7 @@
         texture_ref, args.target, args.level, args.internal_format, args.width,
         args.height, args.depth, args.border, args.format, args.type,
         set_as_cleared ? gfx::Rect(args.width, args.height) : gfx::Rect());
+    texture->ApplyFormatWorkarounds(feature_info_.get());
     texture_state->tex_image_failed = false;
   }
 }
diff --git a/gpu/command_buffer/service/texture_manager.h b/gpu/command_buffer/service/texture_manager.h
index f521333..09ad3df 100644
--- a/gpu/command_buffer/service/texture_manager.h
+++ b/gpu/command_buffer/service/texture_manager.h
@@ -60,6 +60,15 @@
     COPIED
   };
 
+  struct CompatibilitySwizzle {
+    GLenum format;
+    GLenum dest_format;
+    GLenum red;
+    GLenum green;
+    GLenum blue;
+    GLenum alpha;
+  };
+
   explicit Texture(GLuint service_id);
 
   const SamplerState& sampler_state() const {
@@ -114,6 +123,14 @@
     return max_level_;
   }
 
+  GLenum swizzle_r() const { return swizzle_r_; }
+
+  GLenum swizzle_g() const { return swizzle_g_; }
+
+  GLenum swizzle_b() const { return swizzle_b_; }
+
+  GLenum swizzle_a() const { return swizzle_a_; }
+
   int num_uncleared_mips() const {
     return num_uncleared_mips_;
   }
@@ -250,6 +267,8 @@
                        uint64_t client_tracing_id,
                        const std::string& dump_name) const;
 
+  void ApplyFormatWorkarounds(FeatureInfo* feature_info);
+
  private:
   friend class MailboxManagerImpl;
   friend class MailboxManagerSync;
@@ -486,6 +505,9 @@
   // overridden by SetUnownedServiceId.
   GLuint owned_service_id() const { return owned_service_id_; }
 
+  GLenum GetCompatibilitySwizzleForChannel(GLenum channel);
+  void SetCompatibilitySwizzle(const CompatibilitySwizzle* swizzle);
+
   MailboxManager* mailbox_manager_;
 
   // Info about each face and level of texture.
@@ -526,6 +548,10 @@
   GLenum usage_;
   GLint base_level_;
   GLint max_level_;
+  GLenum swizzle_r_;
+  GLenum swizzle_g_;
+  GLenum swizzle_b_;
+  GLenum swizzle_a_;
 
   // The maximum level that has been set.
   GLint max_level_set_;
@@ -564,6 +590,8 @@
   // Whether we have initialized TEXTURE_MAX_ANISOTROPY to 1.
   bool texture_max_anisotropy_initialized_;
 
+  const CompatibilitySwizzle* compatibility_swizzle_;
+
   DISALLOW_COPY_AND_ASSIGN(Texture);
 };
 
@@ -1010,6 +1038,9 @@
   uint32_t GetServiceIdGeneration() const;
   void IncrementServiceIdGeneration();
 
+  GLenum AdjustTexInternalFormat(GLenum format) const;
+  GLenum AdjustTexFormat(GLenum format) const;
+
  private:
   friend class Texture;
   friend class TextureRef;
@@ -1037,8 +1068,6 @@
   void UpdateNumImages(int delta);
   void IncFramebufferStateChangeCount();
 
-  GLenum AdjustTexFormat(GLenum format) const;
-
   // Helper function called by OnMemoryDump.
   void DumpTextureRef(base::trace_event::ProcessMemoryDump* pmd,
                       TextureRef* ref);
diff --git a/gpu/command_buffer/service/texture_manager_unittest.cc b/gpu/command_buffer/service/texture_manager_unittest.cc
index 71a771d..322e2dc 100644
--- a/gpu/command_buffer/service/texture_manager_unittest.cc
+++ b/gpu/command_buffer/service/texture_manager_unittest.cc
@@ -87,7 +87,7 @@
                                       kMax3DTextureSize,
                                       kUseDefaultTextures));
     TestHelper::SetupTextureManagerInitExpectations(
-        gl_.get(), false, "", kUseDefaultTextures);
+        gl_.get(), false, false, "", kUseDefaultTextures);
     manager_->Initialize();
     error_state_.reset(new ::testing::StrictMock<gles2::MockErrorState>());
   }
@@ -109,7 +109,7 @@
                         const char* gl_version,
                         bool enable_es3) {
     TestHelper::SetupFeatureInfoInitExpectationsWithGLVersion(
-        gl_.get(), gl_extensions, "", gl_version);
+        gl_.get(), gl_extensions, "", gl_version, enable_es3);
     feature_info_->InitializeForTesting();
     if (enable_es3) {
       EXPECT_CALL(*gl_, GetIntegerv(GL_MAX_COLOR_ATTACHMENTS, _))
@@ -237,7 +237,7 @@
 TEST_F(TextureManagerTest, UseDefaultTexturesTrue) {
   bool use_default_textures = true;
   TestHelper::SetupTextureManagerInitExpectations(gl_.get(),
-      false, "GL_ANGLE_texture_usage", use_default_textures);
+      false, false, "GL_ANGLE_texture_usage", use_default_textures);
   TextureManager manager(NULL,
                          feature_info_.get(),
                          kMaxTextureSize,
@@ -258,7 +258,7 @@
 TEST_F(TextureManagerTest, UseDefaultTexturesFalse) {
   bool use_default_textures = false;
   TestHelper::SetupTextureManagerInitExpectations(gl_.get(),
-      false, "GL_ANGLE_texture_usage", use_default_textures);
+      false, false, "GL_ANGLE_texture_usage", use_default_textures);
   TextureManager manager(NULL,
                          feature_info_.get(),
                          kMaxTextureSize,
@@ -280,7 +280,7 @@
   bool use_default_textures = true;
   SetupFeatureInfo("", "OpenGL ES 3.0", true);
   TestHelper::SetupTextureManagerInitExpectations(gl_.get(),
-      true, "", use_default_textures);
+      true, false, "", use_default_textures);
   TextureManager manager(NULL,
                          feature_info_.get(),
                          kMaxTextureSize,
@@ -300,7 +300,7 @@
   bool use_default_textures = false;
   SetupFeatureInfo("", "OpenGL ES 3.0", true);
   TestHelper::SetupTextureManagerInitExpectations(gl_.get(),
-      true, "", use_default_textures);
+      true, false, "", use_default_textures);
   TextureManager manager(NULL,
                          feature_info_.get(),
                          kMaxTextureSize,
@@ -318,7 +318,7 @@
 
 TEST_F(TextureManagerTest, TextureUsageExt) {
   TestHelper::SetupTextureManagerInitExpectations(
-      gl_.get(), false, "GL_ANGLE_texture_usage", kUseDefaultTextures);
+      gl_.get(), false, false, "GL_ANGLE_texture_usage", kUseDefaultTextures);
   TextureManager manager(NULL,
                          feature_info_.get(),
                          kMaxTextureSize,
@@ -346,7 +346,7 @@
   const GLuint kClient1Id = 1;
   const GLuint kService1Id = 11;
   TestHelper::SetupTextureManagerInitExpectations(
-      gl_.get(), false, "", kUseDefaultTextures);
+      gl_.get(), false, false, "", kUseDefaultTextures);
   TextureManager manager(NULL,
                          feature_info_.get(),
                          kMaxTextureSize,
@@ -364,7 +364,7 @@
       .Times(1)
       .RetiresOnSaturation();
   TestHelper::SetupTextureManagerDestructionExpectations(
-      gl_.get(), false, "", kUseDefaultTextures);
+      gl_.get(), false, false, "", kUseDefaultTextures);
   manager.Destroy(true);
   // Check that resources got freed.
   texture = manager.GetTexture(kClient1Id);
@@ -551,6 +551,150 @@
   manager_->RemoveTexture(kClientId);
 }
 
+TEST_F(TextureManagerTest, AlphaLuminanceCompatibilityProfile) {
+  const GLuint kClientId = 1;
+  const GLuint kServiceId = 11;
+
+  SetupFeatureInfo("", "2.1", false);
+  TestHelper::SetupTextureManagerInitExpectations(gl_.get(), false, false, "",
+      kUseDefaultTextures);
+  TextureManager manager(NULL,
+                         feature_info_.get(),
+                         kMaxTextureSize,
+                         kMaxCubeMapTextureSize,
+                         kMaxRectangleTextureSize,
+                         kMax3DTextureSize,
+                         kUseDefaultTextures);
+  manager.Initialize();
+
+  // Create a texture.
+  manager.CreateTexture(kClientId, kServiceId);
+  scoped_refptr<TextureRef> texture_ref(manager.GetTexture(kClientId));
+  manager.SetTarget(texture_ref.get(), GL_TEXTURE_2D);
+
+  Texture* texture = texture_ref->texture();
+
+  // GL_ALPHA emulation
+  manager.SetLevelInfo(texture_ref.get(), GL_TEXTURE_2D, 0, GL_ALPHA, 1, 1, 1,
+      0, GL_ALPHA, GL_UNSIGNED_BYTE, gfx::Rect(1, 1));
+  texture->ApplyFormatWorkarounds(feature_info_.get());
+
+  // GL_LUMINANCE emulation
+  manager.SetLevelInfo(texture_ref.get(), GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1,
+      1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, gfx::Rect(1, 1));
+  texture->ApplyFormatWorkarounds(feature_info_.get());
+
+  // GL_LUMINANCE_ALPHA emulation
+  manager.SetLevelInfo(texture_ref.get(), GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA,
+      1, 1, 1, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, gfx::Rect(1, 1));
+  texture->ApplyFormatWorkarounds(feature_info_.get());
+
+  EXPECT_CALL(*gl_, DeleteTextures(1, ::testing::Pointee(kServiceId)))
+      .Times(1)
+      .RetiresOnSaturation();
+  manager.RemoveTexture(kClientId);
+}
+
+TEST_F(TextureManagerTest, AlphaLuminanceCoreProfileEmulation) {
+  const GLuint kClientId = 1;
+  const GLuint kServiceId = 11;
+
+  SetupFeatureInfo("", "4.2", true);
+  TestHelper::SetupTextureManagerInitExpectations(gl_.get(), true, true, "",
+      kUseDefaultTextures);
+  TextureManager manager(NULL,
+                         feature_info_.get(),
+                         kMaxTextureSize,
+                         kMaxCubeMapTextureSize,
+                         kMaxRectangleTextureSize,
+                         kMax3DTextureSize,
+                         kUseDefaultTextures);
+  manager.Initialize();
+
+  // Create a texture.
+  manager.CreateTexture(kClientId, kServiceId);
+  scoped_refptr<TextureRef> texture_ref(manager.GetTexture(kClientId));
+  manager.SetTarget(texture_ref.get(), GL_TEXTURE_2D);
+
+  Texture* texture = texture_ref->texture();
+
+  // GL_ALPHA emulation
+  EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_NONE))
+      .Times(1)
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_NONE))
+      .Times(1)
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_NONE))
+      .Times(1)
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_RED))
+      .Times(1)
+      .RetiresOnSaturation();
+
+  manager.SetLevelInfo(texture_ref.get(), GL_TEXTURE_2D, 0, GL_ALPHA, 1, 1, 1,
+      0, GL_ALPHA, GL_UNSIGNED_BYTE, gfx::Rect(1, 1));
+  texture->ApplyFormatWorkarounds(feature_info_.get());
+
+  // GL_LUMINANCE emulation
+  EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED))
+      .Times(1)
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED))
+      .Times(1)
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED))
+      .Times(1)
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE))
+      .Times(1)
+      .RetiresOnSaturation();
+
+  manager.SetLevelInfo(texture_ref.get(), GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1,
+      1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, gfx::Rect(1, 1));
+  texture->ApplyFormatWorkarounds(feature_info_.get());
+
+  // GL_LUMINANCE_ALPHA emulation
+  EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED))
+      .Times(1)
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED))
+      .Times(1)
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED))
+      .Times(1)
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A,
+              GL_GREEN))
+      .Times(1)
+      .RetiresOnSaturation();
+
+  manager.SetLevelInfo(texture_ref.get(), GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA,
+      1, 1, 1, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, gfx::Rect(1, 1));
+  texture->ApplyFormatWorkarounds(feature_info_.get());
+
+  // Ensure explicitly setting swizzles while using emulated settings properly
+  // swizzles the swizzle.
+  EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R,
+              GL_GREEN))
+      .Times(1)
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A,
+              GL_RED))
+      .Times(1)
+      .RetiresOnSaturation();
+
+  manager.SetParameteri("TexParameteri", error_state_.get(), texture_ref.get(),
+      GL_TEXTURE_SWIZZLE_R, GL_ALPHA);
+  manager.SetParameteri("TexParameteri", error_state_.get(), texture_ref.get(),
+      GL_TEXTURE_SWIZZLE_A, GL_GREEN);
+
+  EXPECT_CALL(*gl_, DeleteTextures(1, ::testing::Pointee(kServiceId)))
+      .Times(1)
+      .RetiresOnSaturation();
+  manager.RemoveTexture(kClientId);
+}
+
 class TextureTestBase : public GpuServiceTest {
  public:
   static const GLint kMaxTextureSize = 32;
@@ -2032,10 +2176,10 @@
                            TextureManagerTest::kMax3DTextureSize,
                            kUseDefaultTextures));
     TestHelper::SetupTextureManagerInitExpectations(
-        gl_.get(), false, "", kUseDefaultTextures);
+        gl_.get(), false, false, "", kUseDefaultTextures);
     texture_manager1_->Initialize();
     TestHelper::SetupTextureManagerInitExpectations(
-        gl_.get(), false, "", kUseDefaultTextures);
+        gl_.get(), false, false, "", kUseDefaultTextures);
     texture_manager2_->Initialize();
   }
 
diff --git a/gpu/gpu_ipc_common.gypi b/gpu/gpu_ipc_common.gypi
index a986b289..2b261f1 100644
--- a/gpu/gpu_ipc_common.gypi
+++ b/gpu/gpu_ipc_common.gypi
@@ -17,6 +17,7 @@
     'ipc/common/id_type_traits.h',
     'ipc/common/memory_stats.cc',
     'ipc/common/memory_stats.h',
+    'ipc/common/surface_handle.h',
   ],
   'conditions': [
     # This section applies to gpu_ipc_win64, used by the NaCl Win64 helper
diff --git a/gpu/ipc/common/surface_handle.h b/gpu/ipc/common/surface_handle.h
new file mode 100644
index 0000000..917c8947
--- /dev/null
+++ b/gpu/ipc/common/surface_handle.h
@@ -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.
+
+#ifndef GPU_IPC_COMMON_SURFACE_HANDLE_H_
+#define GPU_IPC_COMMON_SURFACE_HANDLE_H_
+
+#include "ui/gfx/native_widget_types.h"
+
+namespace gpu {
+
+// TODO(piman): remove PluginWindowHandle and move here when NPAPI is gone.
+using SurfaceHandle = gfx::PluginWindowHandle;
+const SurfaceHandle kNullSurfaceHandle = gfx::kNullPluginWindow;
+
+}  // namespace gpu
+
+#endif  // GPU_IPC_COMMON_SURFACE_HANDLE_H_
diff --git a/headless/lib/browser/headless_browser_context.cc b/headless/lib/browser/headless_browser_context.cc
index aca8351..dd42317 100644
--- a/headless/lib/browser/headless_browser_context.cc
+++ b/headless/lib/browser/headless_browser_context.cc
@@ -74,6 +74,7 @@
 void HeadlessBrowserContext::InitWhileIOAllowed() {
   // TODO(skyostil): Allow the embedder to override this.
   PathService::Get(base::DIR_EXE, &path_);
+  BrowserContext::Initialize(this, path_);
 }
 
 scoped_ptr<content::ZoomLevelDelegate>
diff --git a/ios/chrome/browser/suggestions/suggestions_service_factory.mm b/ios/chrome/browser/suggestions/suggestions_service_factory.mm
index 56d83ed8..52e03d0db 100644
--- a/ios/chrome/browser/suggestions/suggestions_service_factory.mm
+++ b/ios/chrome/browser/suggestions/suggestions_service_factory.mm
@@ -10,6 +10,7 @@
 #include "base/memory/singleton.h"
 #include "base/sequenced_task_runner.h"
 #include "base/threading/sequenced_worker_pool.h"
+#include "components/browser_sync/browser/profile_sync_service.h"
 #include "components/keyed_service/ios/browser_state_dependency_manager.h"
 #include "components/leveldb_proto/proto_database_impl.h"
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
@@ -23,6 +24,7 @@
 #include "ios/chrome/browser/signin/oauth2_token_service_factory.h"
 #include "ios/chrome/browser/signin/signin_manager_factory.h"
 #include "ios/chrome/browser/suggestions/image_fetcher_impl.h"
+#include "ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory.h"
 #include "ios/web/public/browser_state.h"
 #include "ios/web/public/web_thread.h"
 
@@ -50,6 +52,7 @@
           BrowserStateDependencyManager::GetInstance()) {
   DependsOn(ios::SigninManagerFactory::GetInstance());
   DependsOn(OAuth2TokenServiceFactory::GetInstance());
+  DependsOn(IOSChromeProfileSyncServiceFactory::GetInstance());
 }
 
 SuggestionsServiceFactory::~SuggestionsServiceFactory() {
@@ -69,6 +72,8 @@
       ios::SigninManagerFactory::GetForBrowserState(browser_state);
   ProfileOAuth2TokenService* token_service =
       OAuth2TokenServiceFactory::GetForBrowserState(browser_state);
+  ProfileSyncService* sync_service =
+      IOSChromeProfileSyncServiceFactory::GetForBrowserState(browser_state);
   base::FilePath database_dir(
       browser_state->GetStatePath().Append(kThumbnailDirectory));
   scoped_ptr<SuggestionsStore> suggestions_store(
@@ -83,9 +88,9 @@
       std::move(image_fetcher), std::move(db), database_dir,
       web::WebThread::GetTaskRunnerForThread(web::WebThread::DB)));
   return make_scoped_ptr(new SuggestionsService(
-      signin_manager, token_service, browser_state->GetRequestContext(),
-      std::move(suggestions_store), std::move(thumbnail_manager),
-      std::move(blacklist_store)));
+      signin_manager, token_service, sync_service,
+      browser_state->GetRequestContext(), std::move(suggestions_store),
+      std::move(thumbnail_manager), std::move(blacklist_store)));
 }
 
 void SuggestionsServiceFactory::RegisterBrowserStatePrefs(
diff --git a/ios/chrome/browser/ui/commands/ios_command_ids.h b/ios/chrome/browser/ui/commands/ios_command_ids.h
index 293fa65..3128fc21 100644
--- a/ios/chrome/browser/ui/commands/ios_command_ids.h
+++ b/ios/chrome/browser/ui/commands/ios_command_ids.h
@@ -74,6 +74,7 @@
 #define IDC_RATE_THIS_APP                              40948
 #define IDC_ADD_READING_LIST                           40949
 #define IDC_SHOW_READING_LIST                          40950
+#define IDC_SHOW_CLEAR_BROWSING_DATA_SETTINGS          40951
 // clang-format on
 
 #endif  // IOS_CHROME_BROWSER_UI_COMMANDS_IOS_COMMAND_IDS_H_
diff --git a/ios/chrome/browser/ui/show_privacy_settings_util.mm b/ios/chrome/browser/ui/show_privacy_settings_util.mm
index 12e878c..1555ab1 100644
--- a/ios/chrome/browser/ui/show_privacy_settings_util.mm
+++ b/ios/chrome/browser/ui/show_privacy_settings_util.mm
@@ -11,7 +11,8 @@
 
 void ShowClearBrowsingData() {
   base::scoped_nsobject<GenericChromeCommand> command(
-      [[GenericChromeCommand alloc] initWithTag:IDC_SHOW_PRIVACY_SETTINGS]);
+      [[GenericChromeCommand alloc]
+          initWithTag:IDC_SHOW_CLEAR_BROWSING_DATA_SETTINGS]);
   UIWindow* main_window = [[UIApplication sharedApplication] keyWindow];
   [main_window chromeExecuteCommand:command];
 }
diff --git a/ios/third_party/ochamcrest/BUILD.gn b/ios/third_party/ochamcrest/BUILD.gn
index 28c1795..527e5f29 100644
--- a/ios/third_party/ochamcrest/BUILD.gn
+++ b/ios/third_party/ochamcrest/BUILD.gn
@@ -183,10 +183,6 @@
 
 config("ochamcrest_private_config") {
   visibility = [ ":ochamcrest" ]
-
-  # TODO(crbug.com/589097): remove this once OCHamcrest source has been fixed
-  # by removing the semicolon in HCGenericTestFailureReporter.m.
-  cflags = [ "-Wno-semicolon-before-method-body" ]
   cflags_objc = [ "-fobjc-arc" ]
 }
 
diff --git a/ios/third_party/ochamcrest/ochamcrest.gyp b/ios/third_party/ochamcrest/ochamcrest.gyp
index 993cee66..95d5a6c 100644
--- a/ios/third_party/ochamcrest/ochamcrest.gyp
+++ b/ios/third_party/ochamcrest/ochamcrest.gyp
@@ -213,9 +213,6 @@
       ],
       'xcode_settings': {
         'CLANG_ENABLE_OBJC_ARC': 'YES',
-        # TODO(crbug.com/589097): remove this once OCHamcrest source has been
-        # fixed by removing the semicolon in HCGenericTestFailureReporter.m.
-       'WARNING_CFLAGS': [ '-Wno-semicolon-before-method-body' ]
       },
       'link_settings': {
         'libraries': [
diff --git a/ios/web/web_state/ui/web_view_js_utils.h b/ios/web/web_state/ui/web_view_js_utils.h
index a51dd55c..37d8be31 100644
--- a/ios/web/web_state/ui/web_view_js_utils.h
+++ b/ios/web/web_state/ui/web_view_js_utils.h
@@ -18,14 +18,27 @@
 // an error. The |completion_handler| can be nil.
 namespace web {
 
+// The domain for JS evaluation NSErrors in web.
+extern NSString* const kJSEvaluationErrorDomain;
+
+// The type of errors that can occur while evaluating JS.
+enum JSEvaluationErrorCode {
+  // No web view present to evaluate JS.
+  JS_EVALUATION_ERROR_CODE_NO_WEB_VIEW = 1,
+};
+
+// The error code for JS evaluation NSErrors.
+extern const NSInteger kJSEvaluationErrorCode;
+
 // Asynchronous adaptor to evaluate JavaScript on UIWebView. Provides evaluation
 // result as it is, without modifications.
 void EvaluateJavaScript(UIWebView* web_view,
                         NSString* script,
                         JavaScriptCompletion completion_handler);
 
-// Evaluates JavaScript on WKWebView. Provides evaluation result is the same
-// format as UIWebView.
+// Evaluates JavaScript on WKWebView. Provides evaluation result in the same
+// format as UIWebView. If the web view cannot evaluate JS at the moment,
+// |completion_handler| is called with an NSError.
 void EvaluateJavaScript(WKWebView* web_view,
                         NSString* script,
                         JavaScriptCompletion completion_handler);
diff --git a/ios/web/web_state/ui/web_view_js_utils.mm b/ios/web/web_state/ui/web_view_js_utils.mm
index bd5b943..a97f04f 100644
--- a/ios/web/web_state/ui/web_view_js_utils.mm
+++ b/ios/web/web_state/ui/web_view_js_utils.mm
@@ -40,6 +40,8 @@
 
 namespace web {
 
+NSString* const kJSEvaluationErrorDomain = @"JSEvaluationError";
+
 void EvaluateJavaScript(UIWebView* web_view,
                         NSString* script,
                         JavaScriptCompletion completion_handler) {
@@ -56,6 +58,19 @@
                         NSString* script,
                         JavaScriptCompletion completion_handler) {
   DCHECK([script length]);
+  if (!web_view && completion_handler) {
+    dispatch_async(dispatch_get_main_queue(), ^{
+      NSString* error_message =
+          @"JS evaluation failed because there is no web view.";
+      base::scoped_nsobject<NSError> error([[NSError alloc]
+          initWithDomain:kJSEvaluationErrorDomain
+                    code:JS_EVALUATION_ERROR_CODE_NO_WEB_VIEW
+                userInfo:@{NSLocalizedDescriptionKey : error_message}]);
+      completion_handler(nil, error);
+    });
+    return;
+  }
+
   void (^web_view_completion_handler)(id, NSError*) = nil;
   // Do not create a web_view_completion_handler if no |completion_handler| is
   // passed to this function. WKWebView guarantees to call all completion
diff --git a/ipc/ipc_message_start.h b/ipc/ipc_message_start.h
index 17c704b..2fe7643 100644
--- a/ipc/ipc_message_start.h
+++ b/ipc/ipc_message_start.h
@@ -105,7 +105,6 @@
   PlatformNotificationMsgStart,
   CredentialManagerMsgStart,
   PDFMsgStart,
-  WebCacheMsgStart,
   ManifestManagerMsgStart,
   ExtensionUtilityMsgStart,
   GeofencingMsgStart,
diff --git a/media/BUILD.gn b/media/BUILD.gn
index 34f6759e..b0750196 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -642,19 +642,15 @@
     sources += [
       "ffmpeg/ffmpeg_common_unittest.cc",
       "filters/audio_decoder_unittest.cc",
+      "filters/audio_file_reader_unittest.cc",
       "filters/blocking_url_protocol_unittest.cc",
+      "filters/ffmpeg_demuxer_unittest.cc",
       "filters/ffmpeg_glue_unittest.cc",
       "filters/in_memory_url_protocol_unittest.cc",
     ]
 
     if (!is_android) {
       sources += [
-        # These tests are confused by Android always having proprietary
-        # codecs enabled, but ffmpeg_branding=Chromium.  These should be
-        # fixed, http://crbug.com/570762.
-        "filters/audio_file_reader_unittest.cc",
-        "filters/ffmpeg_demuxer_unittest.cc",
-
         # FFmpeg on Android does not include video decoders.
         "filters/ffmpeg_video_decoder_unittest.cc",
       ]
diff --git a/media/base/android/BUILD.gn b/media/base/android/BUILD.gn
index 7ac7d972..b9db10a8 100644
--- a/media/base/android/BUILD.gn
+++ b/media/base/android/BUILD.gn
@@ -83,7 +83,6 @@
   sources = [
     "access_unit_queue_unittest.cc",
     "media_codec_decoder_unittest.cc",
-    "media_codec_player_unittest.cc",
     "media_drm_bridge_unittest.cc",
     "media_player_bridge_unittest.cc",
     "media_source_player_unittest.cc",
@@ -92,6 +91,11 @@
     "test_data_factory.h",
     "test_statistics.h",
   ]
+
+  if (proprietary_codecs) {
+    sources += [ "media_codec_player_unittest.cc" ]
+  }
+
   deps = [
     ":android",
     "//media/base:test_support",
diff --git a/media/base/android/media_codec_player.cc b/media/base/android/media_codec_player.cc
index 7eb96442..b5c3b1b 100644
--- a/media/base/android/media_codec_player.cc
+++ b/media/base/android/media_codec_player.cc
@@ -41,11 +41,13 @@
     base::WeakPtr<MediaPlayerManager> manager,
     const OnDecoderResourcesReleasedCB& on_decoder_resources_released_cb,
     scoped_ptr<DemuxerAndroid> demuxer,
-    const GURL& frame_url)
+    const GURL& frame_url,
+    int media_session_id)
     : MediaPlayerAndroid(player_id,
                          manager.get(),
                          on_decoder_resources_released_cb,
-                         frame_url),
+                         frame_url,
+                         media_session_id),
       ui_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       demuxer_(std::move(demuxer)),
       state_(kStatePaused),
diff --git a/media/base/android/media_codec_player.h b/media/base/android/media_codec_player.h
index 30a4baf..83b4164 100644
--- a/media/base/android/media_codec_player.h
+++ b/media/base/android/media_codec_player.h
@@ -191,7 +191,8 @@
       base::WeakPtr<MediaPlayerManager> manager,
       const OnDecoderResourcesReleasedCB& on_decoder_resources_released_cb,
       scoped_ptr<DemuxerAndroid> demuxer,
-      const GURL& frame_url);
+      const GURL& frame_url,
+      int media_session_id);
   ~MediaCodecPlayer() override;
 
   // A helper method that performs the media thread part of initialization.
diff --git a/media/base/android/media_codec_player_unittest.cc b/media/base/android/media_codec_player_unittest.cc
index 5076e48..eb3f827 100644
--- a/media/base/android/media_codec_player_unittest.cc
+++ b/media/base/android/media_codec_player_unittest.cc
@@ -644,7 +644,7 @@
       manager_.GetWeakPtr(),
       base::Bind(&MockMediaPlayerManager::OnMediaResourcesRequested,
                  base::Unretained(&manager_)),
-      scoped_ptr<MockDemuxerAndroid>(demuxer_), GURL());
+      scoped_ptr<MockDemuxerAndroid>(demuxer_), GURL(), kDefaultMediaSessionId);
 
   DCHECK(player_);
 }
diff --git a/media/base/android/media_player_android.cc b/media/base/android/media_player_android.cc
index 8a77ab003..b8f4080 100644
--- a/media/base/android/media_player_android.cc
+++ b/media/base/android/media_player_android.cc
@@ -27,13 +27,15 @@
     int player_id,
     MediaPlayerManager* manager,
     const OnDecoderResourcesReleasedCB& on_decoder_resources_released_cb,
-    const GURL& frame_url)
+    const GURL& frame_url,
+    int media_session_id)
     : on_decoder_resources_released_cb_(on_decoder_resources_released_cb),
       player_id_(player_id),
       volume_(kDefaultVolume),
       volume_multiplier_(kDefaultVolumeMultiplier),
       manager_(manager),
       frame_url_(frame_url),
+      media_session_id_(media_session_id),
       weak_factory_(this) {
   listener_.reset(new MediaPlayerListener(base::ThreadTaskRunnerHandle::Get(),
                                           weak_factory_.GetWeakPtr()));
diff --git a/media/base/android/media_player_android.h b/media/base/android/media_player_android.h
index 16982d6..d33bb146 100644
--- a/media/base/android/media_player_android.h
+++ b/media/base/android/media_player_android.h
@@ -23,6 +23,19 @@
 class MediaKeys;
 class MediaPlayerManager;
 
+enum {
+  // Id used for players not participating in any media sessions
+  // because of undefined behavior in the specification. When all
+  // media session interactions have been worked out, this id should
+  // no longer be used.
+  kInvalidMediaSessionId = -1,
+
+  // The media session for media elements that don't have an explicit
+  // user created media session set. Must be in-sync with
+  // WebMediaSession::DefaultID in blink.
+  kDefaultMediaSessionId = 0
+};
+
 // This class serves as the base class for different media player
 // implementations on Android. Subclasses need to provide their own
 // MediaPlayerAndroid::Create() implementation.
@@ -108,6 +121,8 @@
 
   GURL frame_url() { return frame_url_; }
 
+  int media_session_id() { return media_session_id_; }
+
   // Attach/Detaches |listener_| for listening to all the media events. If
   // |j_media_player| is NULL, |listener_| only listens to the system media
   // events. Otherwise, it also listens to the events from |j_media_player|.
@@ -119,7 +134,8 @@
       int player_id,
       MediaPlayerManager* manager,
       const OnDecoderResourcesReleasedCB& on_decoder_resources_released_cb,
-      const GURL& frame_url);
+      const GURL& frame_url,
+      int media_session_id);
 
   // TODO(qinmin): Simplify the MediaPlayerListener class to only listen to
   // media interrupt events. And have a separate child class to listen to all
@@ -173,6 +189,9 @@
   // Listener object that listens to all the media player events.
   scoped_ptr<MediaPlayerListener> listener_;
 
+  // Media session ID assigned to this player.
+  int media_session_id_;
+
   // Weak pointer passed to |listener_| for callbacks.
   // NOTE: Weak pointers must be invalidated before all other member variables.
   base::WeakPtrFactory<MediaPlayerAndroid> weak_factory_;
diff --git a/media/base/android/media_player_bridge.cc b/media/base/android/media_player_bridge.cc
index dc9d147..50a0af3 100644
--- a/media/base/android/media_player_bridge.cc
+++ b/media/base/android/media_player_bridge.cc
@@ -43,11 +43,13 @@
     MediaPlayerManager* manager,
     const OnDecoderResourcesReleasedCB& on_decoder_resources_released_cb,
     const GURL& frame_url,
-    bool allow_credentials)
+    bool allow_credentials,
+    int media_session_id)
     : MediaPlayerAndroid(player_id,
                          manager,
                          on_decoder_resources_released_cb,
-                         frame_url),
+                         frame_url,
+                         media_session_id),
       prepared_(false),
       pending_play_(false),
       should_seek_on_prepare_(false),
diff --git a/media/base/android/media_player_bridge.h b/media/base/android/media_player_bridge.h
index 0652bc1e..21dc900 100644
--- a/media/base/android/media_player_bridge.h
+++ b/media/base/android/media_player_bridge.h
@@ -52,7 +52,8 @@
       MediaPlayerManager* manager,
       const OnDecoderResourcesReleasedCB& on_decoder_resources_released_cb,
       const GURL& frame_url,
-      bool allow_credentials);
+      bool allow_credentials,
+      int media_session_id);
   ~MediaPlayerBridge() override;
 
   // Initialize this object and extract the metadata from the media.
diff --git a/media/base/android/media_player_bridge_unittest.cc b/media/base/android/media_player_bridge_unittest.cc
index c2b2447b..d4db5ba 100644
--- a/media/base/android/media_player_bridge_unittest.cc
+++ b/media/base/android/media_player_bridge_unittest.cc
@@ -58,7 +58,8 @@
                 base::Bind(&MockMediaPlayerManager::OnMediaResourcesRequested,
                            base::Unretained(&manager_)),
                 GURL(),
-                false) {}
+                false,
+                kDefaultMediaSessionId) {}
 
   void SetCanSeekForward(bool can_seek_forward) {
     bridge_.can_seek_forward_ = can_seek_forward;
diff --git a/media/base/android/media_source_player.cc b/media/base/android/media_source_player.cc
index 0eb80391..30636f6 100644
--- a/media/base/android/media_source_player.cc
+++ b/media/base/android/media_source_player.cc
@@ -32,11 +32,13 @@
     MediaPlayerManager* manager,
     const OnDecoderResourcesReleasedCB& on_decoder_resources_released_cb,
     scoped_ptr<DemuxerAndroid> demuxer,
-    const GURL& frame_url)
+    const GURL& frame_url,
+    int media_session_id)
     : MediaPlayerAndroid(player_id,
                          manager,
                          on_decoder_resources_released_cb,
-                         frame_url),
+                         frame_url,
+                         media_session_id),
       demuxer_(std::move(demuxer)),
       pending_event_(NO_EVENT_PENDING),
       playing_(false),
diff --git a/media/base/android/media_source_player.h b/media/base/android/media_source_player.h
index c1cc2388..d6b26d7 100644
--- a/media/base/android/media_source_player.h
+++ b/media/base/android/media_source_player.h
@@ -45,7 +45,8 @@
       MediaPlayerManager* manager,
       const OnDecoderResourcesReleasedCB& on_decoder_resources_released_cb,
       scoped_ptr<DemuxerAndroid> demuxer,
-      const GURL& frame_url);
+      const GURL& frame_url,
+      int media_session_id);
   ~MediaSourcePlayer() override;
 
   // MediaPlayerAndroid implementation.
diff --git a/media/base/android/media_source_player_unittest.cc b/media/base/android/media_source_player_unittest.cc
index 0ce01abf..36fc679 100644
--- a/media/base/android/media_source_player_unittest.cc
+++ b/media/base/android/media_source_player_unittest.cc
@@ -162,11 +162,13 @@
   MediaSourcePlayerTest()
       : manager_(&message_loop_),
         demuxer_(new MockDemuxerAndroid(&message_loop_)),
-        player_(0, &manager_,
+        player_(0,
+                &manager_,
                 base::Bind(&MockMediaPlayerManager::OnDecorderResourcesReleased,
                            base::Unretained(&manager_)),
                 scoped_ptr<DemuxerAndroid>(demuxer_),
-                GURL()),
+                GURL(),
+                kDefaultMediaSessionId),
         decoder_callback_hook_executed_(false),
         surface_texture_a_is_next_(true) {}
 
diff --git a/media/base/mime_util_unittest.cc b/media/base/mime_util_unittest.cc
index da9877d..0690f85 100644
--- a/media/base/mime_util_unittest.cc
+++ b/media/base/mime_util_unittest.cc
@@ -131,7 +131,7 @@
   EXPECT_TRUE(IsSupportedMediaMimeType("video/ogg"));
 #endif  // OS_ANDROID
 
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) && defined(USE_PROPRIETARY_CODECS)
   // HLS is supported on Android API level 14 and higher and Chrome supports
   // API levels 15 and higher, so these are expected to be supported.
   bool kHlsSupported = true;
diff --git a/media/filters/audio_decoder_unittest.cc b/media/filters/audio_decoder_unittest.cc
index c4f727b..d29a68d 100644
--- a/media/filters/audio_decoder_unittest.cc
+++ b/media/filters/audio_decoder_unittest.cc
@@ -503,7 +503,6 @@
                         testing::ValuesIn(kOpusBehavioralTest));
 
 #if defined(OS_ANDROID)
-
 const DecoderTestData kMediaCodecTests[] = {
     {MEDIA_CODEC, kCodecOpus, "bear-opus.ogg", kBearOpusExpectations, 24, 48000,
      CHANNEL_LAYOUT_STEREO},
@@ -512,10 +511,7 @@
 INSTANTIATE_TEST_CASE_P(MediaCodecAudioDecoderTest,
                         AudioDecoderTest,
                         testing::ValuesIn(kMediaCodecTests));
-
-#else  // !defined(OS_ANDROID)
-
-// Disable all FFmpeg decoder tests on Android. http://crbug.com/570762.
+#endif  // defined(OS_ANDROID)
 
 #if defined(USE_PROPRIETARY_CODECS)
 const DecodedBufferExpectations kSfxMp3Expectations[] = {
@@ -598,6 +594,4 @@
                         FFmpegAudioDecoderBehavioralTest,
                         testing::ValuesIn(kFFmpegBehavioralTest));
 
-#endif  // !defined(OS_ANDROID)
-
 }  // namespace media
diff --git a/media/media.gyp b/media/media.gyp
index f254b8fd..1616b19 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -1160,7 +1160,6 @@
         '<@(capture_unittests_sources)',
         'base/android/access_unit_queue_unittest.cc',
         'base/android/media_codec_decoder_unittest.cc',
-        'base/android/media_codec_player_unittest.cc',
         'base/android/media_drm_bridge_unittest.cc',
         'base/android/media_player_bridge_unittest.cc',
         'base/android/media_source_player_unittest.cc',
@@ -1331,12 +1330,6 @@
             'filters/ffmpeg_video_decoder_unittest.cc',
             'test/pipeline_integration_test.cc',
             'test/pipeline_integration_test_base.cc',
-
-            # These tests are confused by Android always having proprietary
-            # codecs enabled, but ffmpeg_branding=Chromium. These should be
-            # fixed, see http://crbug.com/570762.
-            'filters/audio_file_reader_unittest.cc',
-            'filters/ffmpeg_demuxer_unittest.cc',
           ],
         }],
         ['OS=="android"', {
@@ -1370,6 +1363,7 @@
         }],
         ['proprietary_codecs==1', {
           'sources': [
+            'base/android/media_codec_player_unittest.cc',
             'cdm/cenc_utils_unittest.cc',
             'filters/ffmpeg_aac_bitstream_converter_unittest.cc',
             'filters/ffmpeg_h264_to_annex_b_bitstream_converter_unittest.cc',
diff --git a/mojo/mojo_shell.gyp b/mojo/mojo_shell.gyp
index 213857b4..5474664 100644
--- a/mojo/mojo_shell.gyp
+++ b/mojo/mojo_shell.gyp
@@ -13,8 +13,6 @@
       'services/catalog/catalog.h',
       'services/catalog/entry.cc',
       'services/catalog/entry.h',
-      'services/catalog/loader.cc',
-      'services/catalog/loader.h',
       'services/catalog/store.cc',
       'services/catalog/store.h',
       'shell/loader.h',
diff --git a/mojo/services/catalog/BUILD.gn b/mojo/services/catalog/BUILD.gn
index 633f6d1..f1eb63d 100644
--- a/mojo/services/catalog/BUILD.gn
+++ b/mojo/services/catalog/BUILD.gn
@@ -21,8 +21,6 @@
     "catalog.h",
     "entry.cc",
     "entry.h",
-    "loader.cc",
-    "loader.h",
     "store.cc",
     "store.h",
   ]
diff --git a/mojo/services/catalog/loader.cc b/mojo/services/catalog/loader.cc
deleted file mode 100644
index 7f1fccbe..0000000
--- a/mojo/services/catalog/loader.cc
+++ /dev/null
@@ -1,25 +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 "mojo/services/catalog/loader.h"
-
-#include "mojo/services/catalog/catalog.h"
-#include "mojo/shell/public/cpp/shell_client.h"
-#include "mojo/shell/public/cpp/shell_connection.h"
-
-namespace catalog {
-
-Loader::Loader(base::TaskRunner* blocking_pool, scoped_ptr<Store> store)
-    : blocking_pool_(blocking_pool),
-      store_(std::move(store)) {}
-Loader::~Loader() {}
-
-void Loader::Load(const std::string& name,
-                  mojo::shell::mojom::ShellClientRequest request) {
-  client_.reset(new catalog::Catalog(blocking_pool_, std::move(store_)));
-  connection_.reset(new mojo::ShellConnection(client_.get(),
-                                              std::move(request)));
-}
-
-}  // namespace catalog
diff --git a/mojo/services/catalog/loader.h b/mojo/services/catalog/loader.h
deleted file mode 100644
index ad02411..0000000
--- a/mojo/services/catalog/loader.h
+++ /dev/null
@@ -1,45 +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 MOJO_SERVICES_CATALOG_LOADER_H_
-#define MOJO_SERVICES_CATALOG_LOADER_H_
-
-#include "base/memory/scoped_ptr.h"
-#include "mojo/services/catalog/store.h"
-#include "mojo/shell/loader.h"
-
-namespace base {
-class BlockingPool;
-}
-
-namespace mojo {
-class ShellClient;
-class ShellConnection;
-}
-
-namespace catalog {
-
-class Store;
-
-class Loader : public mojo::shell::Loader {
- public:
-  Loader(base::TaskRunner* blocking_pool, scoped_ptr<Store> store);
-  ~Loader() override;
-
-  // mojo::shell::Loader:
-  void Load(const std::string& name,
-            mojo::shell::mojom::ShellClientRequest request) override;
-
- private:
-  base::TaskRunner* blocking_pool_;
-  scoped_ptr<Store> store_;
-  scoped_ptr<mojo::ShellClient> client_;
-  scoped_ptr<mojo::ShellConnection> connection_;
-
-  DISALLOW_COPY_AND_ASSIGN(Loader);
-};
-
-}  // namespace catalog
-
-#endif  // MOJO_SERVICES_CATALOG_LOADER_H_
diff --git a/mojo/shell/public/cpp/connection.h b/mojo/shell/public/cpp/connection.h
index d3b3b8a..edb4073 100644
--- a/mojo/shell/public/cpp/connection.h
+++ b/mojo/shell/public/cpp/connection.h
@@ -82,6 +82,11 @@
     mojo::GetInterface(GetRemoteInterfaces(), ptr);
   }
 
+  // Returns true if the remote application has the specified capability class
+  // specified in its manifest. Only valid for inbound connections. Will return
+  // false for outbound connections.
+  virtual bool HasCapabilityClass(const std::string& class_name) const = 0;
+
   // Returns the name that was used by the source application to establish a
   // connection to the destination application.
   //
diff --git a/mojo/shell/public/cpp/lib/connection_impl.cc b/mojo/shell/public/cpp/lib/connection_impl.cc
index d3585e7..5cfed52 100644
--- a/mojo/shell/public/cpp/lib/connection_impl.cc
+++ b/mojo/shell/public/cpp/lib/connection_impl.cc
@@ -25,7 +25,7 @@
     uint32_t remote_id,
     shell::mojom::InterfaceProviderPtr remote_interfaces,
     shell::mojom::InterfaceProviderRequest local_interfaces,
-    const std::set<std::string>& allowed_interfaces,
+    const CapabilityRequest& capability_request,
     State initial_state)
     : connection_name_(connection_name),
       remote_(remote),
@@ -33,9 +33,9 @@
       state_(initial_state),
       local_registry_(std::move(local_interfaces), this),
       remote_interfaces_(std::move(remote_interfaces)),
-      allowed_interfaces_(allowed_interfaces),
-      allow_all_interfaces_(allowed_interfaces_.size() == 1 &&
-                            allowed_interfaces_.count("*") == 1),
+      capability_request_(capability_request),
+      allow_all_interfaces_(capability_request.interfaces.size() == 1 &&
+                            capability_request.interfaces.count("*") == 1),
       weak_factory_(this) {}
 
 ConnectionImpl::ConnectionImpl()
@@ -53,6 +53,10 @@
 ////////////////////////////////////////////////////////////////////////////////
 // ConnectionImpl, Connection implementation:
 
+bool ConnectionImpl::HasCapabilityClass(const std::string& class_name) const {
+  return capability_request_.classes.count(class_name) > 0;
+}
+
 const std::string& ConnectionImpl::GetConnectionName() {
   return connection_name_;
 }
@@ -85,7 +89,8 @@
 }
 
 bool ConnectionImpl::AllowsInterface(const std::string& interface_name) const {
-  return allow_all_interfaces_ || allowed_interfaces_.count(interface_name);
+  return allow_all_interfaces_ ||
+         capability_request_.interfaces.count(interface_name);
 }
 
 shell::mojom::InterfaceProvider* ConnectionImpl::GetRemoteInterfaces() {
diff --git a/mojo/shell/public/cpp/lib/connection_impl.h b/mojo/shell/public/cpp/lib/connection_impl.h
index 3247a5a..2c58d86 100644
--- a/mojo/shell/public/cpp/lib/connection_impl.h
+++ b/mojo/shell/public/cpp/lib/connection_impl.h
@@ -11,6 +11,7 @@
 #include <string>
 
 #include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/shell/public/cpp/capabilities.h"
 #include "mojo/shell/public/cpp/connection.h"
 #include "mojo/shell/public/cpp/identity.h"
 #include "mojo/shell/public/interfaces/connector.mojom.h"
@@ -33,7 +34,7 @@
                  uint32_t remote_id,
                  shell::mojom::InterfaceProviderPtr remote_interfaces,
                  shell::mojom::InterfaceProviderRequest local_interfaces,
-                 const std::set<std::string>& allowed_interfaces,
+                 const CapabilityRequest& capability_request,
                  State initial_state);
   ~ConnectionImpl() override;
 
@@ -41,6 +42,7 @@
 
  private:
   // Connection:
+  bool HasCapabilityClass(const std::string& class_name) const override;
   const std::string& GetConnectionName() override;
   const Identity& GetRemoteIdentity() const override;
   void SetConnectionLostClosure(const Closure& handler) override;
@@ -68,7 +70,7 @@
   InterfaceRegistry local_registry_;
   shell::mojom::InterfaceProviderPtr remote_interfaces_;
 
-  const std::set<std::string> allowed_interfaces_;
+  const CapabilityRequest capability_request_;
   const bool allow_all_interfaces_;
 
   base::WeakPtrFactory<ConnectionImpl> weak_factory_;
diff --git a/mojo/shell/public/cpp/lib/connector_impl.cc b/mojo/shell/public/cpp/lib/connector_impl.cc
index 74edbe4..7ff56d4 100644
--- a/mojo/shell/public/cpp/lib/connector_impl.cc
+++ b/mojo/shell/public/cpp/lib/connector_impl.cc
@@ -46,11 +46,8 @@
   DCHECK(params);
   // We allow all interfaces on outgoing connections since we are presumably in
   // a position to know who we're talking to.
-  // TODO(beng): We should filter outgoing interfaces also. The shell must pass
-  //             the manifest CapabilityFilter to the ShellConnection via
-  //             Initialize(), it can be used here.
-  std::set<std::string> allowed;
-  allowed.insert("*");
+  CapabilityRequest request;
+  request.interfaces.insert("*");
   shell::mojom::InterfaceProviderPtr local_interfaces;
   shell::mojom::InterfaceProviderRequest local_request =
       GetProxy(&local_interfaces);
@@ -60,7 +57,7 @@
   scoped_ptr<internal::ConnectionImpl> registry(new internal::ConnectionImpl(
       params->target().name(), params->target(),
       shell::mojom::kInvalidInstanceID, std::move(remote_interfaces),
-      std::move(local_request), allowed, Connection::State::PENDING));
+      std::move(local_request), request, Connection::State::PENDING));
 
   shell::mojom::ShellClientFactoryPtr shell_client_factory;
   shell::mojom::PIDReceiverRequest pid_receiver_request;
diff --git a/mojo/shell/public/cpp/lib/interface_registry.cc b/mojo/shell/public/cpp/lib/interface_registry.cc
index c8f9703b..98a91cef 100644
--- a/mojo/shell/public/cpp/lib/interface_registry.cc
+++ b/mojo/shell/public/cpp/lib/interface_registry.cc
@@ -9,7 +9,7 @@
 namespace mojo {
 
 InterfaceRegistry::InterfaceRegistry(Connection* connection)
-    : InterfaceRegistry(GetProxy(&client_handle_), connection) {}
+    : InterfaceRegistry(nullptr, connection) {}
 
 InterfaceRegistry::InterfaceRegistry(
     shell::mojom::InterfaceProviderRequest request,
@@ -17,8 +17,9 @@
     : binding_(this),
       connection_(connection),
       default_binder_(nullptr) {
-  if (request.is_pending())
-    binding_.Bind(std::move(request));
+  if (!request.is_pending())
+    request = GetProxy(&client_handle_);
+  binding_.Bind(std::move(request));
 }
 
 InterfaceRegistry::~InterfaceRegistry() {
diff --git a/mojo/shell/public/cpp/lib/shell_connection.cc b/mojo/shell/public/cpp/lib/shell_connection.cc
index 2e2a7ec..b169895 100644
--- a/mojo/shell/public/cpp/lib/shell_connection.cc
+++ b/mojo/shell/public/cpp/lib/shell_connection.cc
@@ -55,7 +55,7 @@
   scoped_ptr<Connection> registry(new internal::ConnectionImpl(
       name, source.To<Identity>(), source_id, std::move(remote_interfaces),
       std::move(local_interfaces),
-      allowed_capabilities->interfaces.To<std::set<std::string>>(),
+      allowed_capabilities.To<CapabilityRequest>(),
       Connection::State::CONNECTED));
   if (!client_->AcceptConnection(registry.get()))
     return;
diff --git a/mojo/shell/public/cpp/tests/interface_registry_unittest.cc b/mojo/shell/public/cpp/tests/interface_registry_unittest.cc
index d93f63c..cf6441f 100644
--- a/mojo/shell/public/cpp/tests/interface_registry_unittest.cc
+++ b/mojo/shell/public/cpp/tests/interface_registry_unittest.cc
@@ -5,6 +5,7 @@
 #include "mojo/shell/public/cpp/interface_registry.h"
 
 #include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
 #include "mojo/shell/public/cpp/interface_binder.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -25,12 +26,12 @@
 };
 
 TEST(InterfaceRegistryTest, Ownership) {
+  base::MessageLoop message_loop_;
   int delete_count = 0;
 
   // Destruction.
   {
-    shell::mojom::InterfaceProviderRequest ir;
-    InterfaceRegistry registry(std::move(ir), nullptr);
+    InterfaceRegistry registry(nullptr);
     InterfaceRegistry::TestApi test_api(&registry);
     test_api.SetInterfaceBinderForName(new TestBinder(&delete_count), "TC1");
   }
@@ -38,9 +39,7 @@
 
   // Removal.
   {
-    shell::mojom::InterfaceProviderRequest ir;
-    scoped_ptr<InterfaceRegistry> registry(
-        new InterfaceRegistry(std::move(ir), nullptr));
+    scoped_ptr<InterfaceRegistry> registry(new InterfaceRegistry(nullptr));
     InterfaceBinder* b = new TestBinder(&delete_count);
     InterfaceRegistry::TestApi test_api(registry.get());
     test_api.SetInterfaceBinderForName(b, "TC1");
@@ -51,8 +50,7 @@
 
   // Multiple.
   {
-    shell::mojom::InterfaceProviderRequest ir;
-    InterfaceRegistry registry(std::move(ir), nullptr);
+    InterfaceRegistry registry(nullptr);
     InterfaceRegistry::TestApi test_api(&registry);
     test_api.SetInterfaceBinderForName(new TestBinder(&delete_count), "TC1");
     test_api.SetInterfaceBinderForName(new TestBinder(&delete_count), "TC2");
@@ -61,8 +59,7 @@
 
   // Re-addition.
   {
-    shell::mojom::InterfaceProviderRequest ir;
-    InterfaceRegistry registry(std::move(ir), nullptr);
+    InterfaceRegistry registry(nullptr);
     InterfaceRegistry::TestApi test_api(&registry);
     test_api.SetInterfaceBinderForName(new TestBinder(&delete_count), "TC1");
     test_api.SetInterfaceBinderForName(new TestBinder(&delete_count), "TC1");
diff --git a/mojo/shell/runner/host/child_process_base.cc b/mojo/shell/runner/host/child_process_base.cc
index d4d6870..538cf7d 100644
--- a/mojo/shell/runner/host/child_process_base.cc
+++ b/mojo/shell/runner/host/child_process_base.cc
@@ -106,7 +106,6 @@
     io_runner_ = io_thread_.task_runner().get();
     CHECK(io_runner_.get());
 
-    // TODO(vtl): This should be SLAVE, not NONE.
     // This must be created before controller_thread_ since MessagePumpMojo will
     // create a message pipe which requires this code to be run first.
     edk::InitIPCSupport(this, io_runner_);
diff --git a/mojo/shell/runner/host/native_application_support.h b/mojo/shell/runner/host/native_application_support.h
index 2371f65..d7ce8a2 100644
--- a/mojo/shell/runner/host/native_application_support.h
+++ b/mojo/shell/runner/host/native_application_support.h
@@ -32,7 +32,6 @@
 // should be called on the same thread as |LoadNativeApplication()|. Returns
 // true if |MojoMain()| was called (even if it returns an error), and false
 // otherwise.
-// TODO(vtl): Maybe this should also have a |MojoResult| as an out parameter?
 bool RunNativeApplication(base::NativeLibrary app_library,
                           InterfaceRequest<mojom::ShellClient> request);
 
diff --git a/mojo/shell/shell.cc b/mojo/shell/shell.cc
index 1daa93a4..ceb25e6 100644
--- a/mojo/shell/shell.cc
+++ b/mojo/shell/shell.cc
@@ -21,9 +21,9 @@
 #include "mojo/common/url_type_converters.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/services/catalog/loader.h"
+#include "mojo/services/catalog/catalog.h"
 #include "mojo/shell/connect_util.h"
-#include "mojo/shell/public/cpp/connect.h"
+#include "mojo/shell/public/cpp/connector.h"
 #include "mojo/shell/public/cpp/names.h"
 #include "mojo/shell/public/cpp/shell_connection.h"
 #include "mojo/shell/public/interfaces/connector.mojom.h"
@@ -35,6 +35,7 @@
 namespace shell {
 namespace {
 const char kCatalogName[] = "mojo:catalog";
+const char kShellName[] = "mojo:shell";
 
 void EmptyResolverCallback(const String& resolved_name,
                            const String& resolved_instance,
@@ -44,7 +45,7 @@
 }
 
 Identity CreateShellIdentity() {
-  return Identity("mojo:shell", mojom::kRootUserID);
+  return Identity(kShellName, mojom::kRootUserID);
 }
 
 CapabilitySpec GetPermissiveCapabilities() {
@@ -55,22 +56,39 @@
   return capabilities;
 }
 
-CapabilityRequest GetCapabilityRequest(const CapabilitySpec& spec,
-                                             const Identity& identity) {
+CapabilityRequest GetCapabilityRequest(const CapabilitySpec& source_spec,
+                                       const Identity& target) {
   // Start by looking for specs specific to the supplied identity.
-  auto it = spec.required.find(identity.name());
-  if (it != spec.required.end())
+  auto it = source_spec.required.find(target.name());
+  if (it != source_spec.required.end())
     return it->second;
 
   // Fall back to looking for a wildcard rule.
-  it = spec.required.find("*");
-  if (spec.required.size() == 1 && it != spec.required.end())
+  it = source_spec.required.find("*");
+  if (source_spec.required.size() == 1 && it != source_spec.required.end())
     return it->second;
 
   // Finally, nothing is allowed.
   return CapabilityRequest();
 }
 
+CapabilityRequest GenerateCapabilityRequestForConnection(
+    const CapabilitySpec& source_spec,
+    const Identity& target,
+    const CapabilitySpec& target_spec) {
+  CapabilityRequest request = GetCapabilityRequest(source_spec, target);
+  // Flatten all interfaces from classes requested by the source into the
+  // allowed interface set in the request.
+  for (const auto& class_name : request.classes) {
+    auto it = target_spec.provided.find(class_name);
+    if (it != target_spec.provided.end()) {
+      for (const auto& interface_name : it->second)
+        request.interfaces.insert(interface_name);
+    }
+  }
+  return request;
+}
+
 // Encapsulates a connection to an instance of an application, tracked by the
 // shell's Shell.
 class Shell::Instance : public mojom::Connector,
@@ -82,17 +100,17 @@
   Instance(mojom::ShellClientPtr shell_client,
            mojo::shell::Shell* shell,
            const Identity& identity,
-           const CapabilitySpec& capabilities)
+           const CapabilitySpec& capability_spec)
     : shell_(shell),
       id_(GenerateUniqueID()),
       identity_(identity),
-      capabilities_(capabilities),
-      allow_any_application_(capabilities.required.size() == 1 &&
-                             capabilities.required.count("*") == 1),
+      capability_spec_(capability_spec),
+      allow_any_application_(capability_spec.required.size() == 1 &&
+                             capability_spec.required.count("*") == 1),
       shell_client_(std::move(shell_client)),
       pid_receiver_binding_(this),
       weak_factory_(this) {
-    if (identity_.name() == "mojo:shell" ||
+    if (identity_.name() == kShellName ||
         shell_->GetLoaderForName(identity_.name())) {
       pid_ = base::Process::Current().Pid();
     }
@@ -117,7 +135,8 @@
     spec.interfaces.insert("*");
     Instance* source = shell_->GetExistingInstance(params->source());
     if (source) {
-      spec = GetCapabilityRequest(source->capabilities_, identity_);
+      spec = GenerateCapabilityRequestForConnection(
+          source->capability_spec_, identity_, capability_spec_);
       source_id = source->id();
     }
     shell_client_->AcceptConnection(
@@ -189,6 +208,9 @@
     if (!ValidateCapabilities(target, callback))
       return;
 
+    if (target.user_id() == mojom::kInheritUserID)
+      target.set_user_id(identity_.user_id());
+
     scoped_ptr<ConnectParams> params(new ConnectParams);
     params->set_source(identity_);
     params->set_target(target);
@@ -267,8 +289,8 @@
   bool ValidateCapabilities(const Identity& target,
                             const ConnectCallback& callback) {
     if (allow_any_application_ ||
-        capabilities_.required.find(target.name()) !=
-            capabilities_.required.end()) {
+        capability_spec_.required.find(target.name()) !=
+            capability_spec_.required.end()) {
       return true;
     }
     LOG(ERROR) << "Capabilities prevented connection from: " <<
@@ -296,7 +318,7 @@
   // process is launched.
   const uint32_t id_;
   const Identity identity_;
-  const CapabilitySpec capabilities_;
+  const CapabilitySpec capability_spec_;
   const bool allow_any_application_;
   mojom::ShellClientPtr shell_client_;
   Binding<mojom::PIDReceiver> pid_receiver_binding_;
@@ -334,6 +356,7 @@
   mojom::ShellClientRequest request;
   CreateInstance(CreateShellIdentity(), GetPermissiveCapabilities(), &request);
   shell_connection_.reset(new ShellConnection(this, std::move(request)));
+  shell_connection_->WaitForInitialize();
 
   InitCatalog(std::move(catalog_store));
 }
@@ -355,17 +378,8 @@
                        TRACE_EVENT_SCOPE_THREAD, "original_name",
                        params->target().name());
   DCHECK(IsValidName(params->target().name()));
-
-  if (params->target().user_id() == mojom::kInheritUserID) {
-    Instance* source = GetExistingInstance(params->source());
-    Identity target = params->target();
-    // TODO(beng): we should CHECK source.
-    target.set_user_id(source ? source->identity().user_id()
-                              : mojom::kRootUserID);
-    params->set_target(target);
-  }
-
-  CHECK(params->target().user_id() != mojom::kInheritUserID);
+  DCHECK(base::IsValidGUID(params->target().user_id()));
+  DCHECK_NE(mojom::kInheritUserID, params->target().user_id());
 
   // Connect to an existing matching instance, if possible.
   if (ConnectToExistingInstance(&params))
@@ -424,26 +438,23 @@
 // Shell, private:
 
 void Shell::InitCatalog(scoped_ptr<catalog::Store> store) {
-  scoped_ptr<Loader> loader(
-      new catalog::Loader(file_task_runner_, std::move(store)));
-  Loader* loader_raw = loader.get();
-  std::string name = kCatalogName;
-  SetLoaderForName(std::move(loader), name);
-
   mojom::ShellClientRequest request;
-  // TODO(beng): Does the catalog actually have to be run with a permissive
-  //             filter?
-  Identity identity(name, mojom::kRootUserID);
-  CreateInstance(identity, GetPermissiveCapabilities(), &request);
-  loader_raw->Load(name, std::move(request));
+  Identity identity(kCatalogName, mojom::kRootUserID);
+  CreateInstance(identity, CapabilitySpec(), &request);
 
-  ConnectToInterface(this, CreateShellIdentity(), name, &shell_resolver_);
+  catalog_shell_client_.reset(
+      new catalog::Catalog(file_task_runner_, std::move(store)));
+  catalog_connection_.reset(
+      new ShellConnection(catalog_shell_client_.get(), std::move(request)));
+  shell_connection_->connector()->ConnectToInterface(
+      kCatalogName, &shell_resolver_);
 
   // Seed the catalog with manifest info for the shell & catalog.
   if (file_task_runner_) {
-    shell_resolver_->ResolveMojoName(name, base::Bind(&EmptyResolverCallback));
-    shell_resolver_->ResolveMojoName("mojo:shell",
-                                     base::Bind(&EmptyResolverCallback));
+    shell_resolver_->ResolveMojoName(
+        kCatalogName, base::Bind(&EmptyResolverCallback));
+    shell_resolver_->ResolveMojoName(
+        kShellName, base::Bind(&EmptyResolverCallback));
   }
 }
 
@@ -542,7 +553,6 @@
     return it->second.get();
 
   mojom::ShellClientFactoryPtr factory;
-  // TODO(beng): we should forward the original source identity!
   ConnectToInterface(this, source_identity, shell_client_factory_identity,
                      &factory);
   mojom::ShellClientFactory* factory_interface = factory.get();
diff --git a/mojo/shell/shell.h b/mojo/shell/shell.h
index 2d66593e..e8f18fb7 100644
--- a/mojo/shell/shell.h
+++ b/mojo/shell/shell.h
@@ -34,6 +34,7 @@
 }
 
 namespace mojo {
+class ShellClient;
 class ShellConnection;
 namespace shell {
 
@@ -191,6 +192,8 @@
   scoped_ptr<NativeRunnerFactory> native_runner_factory_;
   std::vector<scoped_ptr<NativeRunner>> native_runners_;
   scoped_ptr<ShellConnection> shell_connection_;
+  scoped_ptr<ShellConnection> catalog_connection_;
+  scoped_ptr<ShellClient> catalog_shell_client_;
   base::WeakPtrFactory<Shell> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(Shell);
diff --git a/mojo/shell/standalone/context.cc b/mojo/shell/standalone/context.cc
index 23dc96b..4e847fb 100644
--- a/mojo/shell/standalone/context.cc
+++ b/mojo/shell/standalone/context.cc
@@ -134,7 +134,6 @@
   blocking_pool_ =
       new base::SequencedWorkerPool(kMaxBlockingPoolThreads, "blocking_pool");
 
-  // TODO(vtl): This should be MASTER, not NONE.
   edk::InitIPCSupport(this, io_thread_->task_runner().get());
 
   scoped_ptr<NativeRunnerFactory> runner_factory;
@@ -164,7 +163,7 @@
 
   scoped_ptr<ConnectParams> params(new ConnectParams);
   params->set_source(CreateShellIdentity());
-  params->set_target(Identity("mojo:tracing", mojom::kInheritUserID));
+  params->set_target(Identity("mojo:tracing", mojom::kRootUserID));
   params->set_remote_interfaces(GetProxy(&tracing_remote_interfaces));
   params->set_local_interfaces(std::move(tracing_local_interfaces));
   shell_->Connect(std::move(params));
diff --git a/mojo/shell/tests/connect/BUILD.gn b/mojo/shell/tests/connect/BUILD.gn
index d2818b2..f55c225 100644
--- a/mojo/shell/tests/connect/BUILD.gn
+++ b/mojo/shell/tests/connect/BUILD.gn
@@ -23,6 +23,7 @@
 
   data_deps = [
     ":connect_test_app",
+    ":connect_test_class_app",
     ":connect_test_package",
     ":manifest",
   ]
@@ -96,3 +97,23 @@
   application_name = "connect_test_app"
   source = "connect_test_app_manifest.json"
 }
+
+mojo_native_application("connect_test_class_app") {
+  testonly = true
+  sources = [
+    "connect_test_class_app.cc",
+  ]
+  deps = [
+    ":connect_test_class_app_manifest",
+    ":interfaces",
+    "//base",
+    "//mojo/common:common_base",
+    "//mojo/shell/public/cpp:sources",
+    "//mojo/shell/public/interfaces",
+  ]
+}
+
+mojo_application_manifest("connect_test_class_app_manifest") {
+  application_name = "connect_test_class_app"
+  source = "connect_test_class_app_manifest.json"
+}
diff --git a/mojo/shell/tests/connect/connect_test.mojom b/mojo/shell/tests/connect/connect_test.mojom
index ba29865..2598f3e 100644
--- a/mojo/shell/tests/connect/connect_test.mojom
+++ b/mojo/shell/tests/connect/connect_test.mojom
@@ -9,12 +9,25 @@
   GetInstance() => (string instance);
 };
 
-// Interface implemented by a standalone (non-package) app.
+interface ClassInterface {
+  Ping() => (string response);
+};
+
+// Interface implemented by a standalone (non-package) app,
+// mojo:connect_test_app.
 interface StandaloneApp {
   // Attempts to connect to an application whose name is explicitly allowed by
-  // the standalone app's CapabilityFilter, but whose enclosing package is not.
+  // the standalone app's CapabilitySpec, but whose enclosing package is not.
   // The connection should be blocked and title should be "uninitialized".
   ConnectToAllowedAppInBlockedPackage() => (string title);
+
+  // Connects to mojo:connect_test_class_app & requests ClassInterface from it.
+  // This should be permitted because mojo:connect_test_app requests class
+  // "class" from mojo:connect_test_class_app, which mojo:connect_test_class_app
+  // defines as including ClassInterface.
+  // The response contains the response from ClassInterface::Ping() and
+  // ConnectTestService::GetTitle().
+  ConnectToClassInterface() => (string class_interface_response, string title);
 };
 
 struct ConnectionState {
diff --git a/mojo/shell/tests/connect/connect_test_app.cc b/mojo/shell/tests/connect/connect_test_app.cc
index 86ae235..abf51dc 100644
--- a/mojo/shell/tests/connect/connect_test_app.cc
+++ b/mojo/shell/tests/connect/connect_test_app.cc
@@ -17,6 +17,13 @@
 
 namespace mojo {
 namespace shell {
+namespace {
+void ReceiveString(std::string* string, base::RunLoop* loop,
+                   const std::string& response) {
+  *string = response;
+  loop->Quit();
+}
+}
 
 using GetTitleCallback = test::mojom::ConnectTestService::GetTitleCallback;
 
@@ -119,6 +126,32 @@
       run_loop.Run();
     }
   }
+  void ConnectToClassInterface(
+      const ConnectToClassInterfaceCallback& callback) override {
+    scoped_ptr<Connection> connection =
+        connector_->Connect("mojo:connect_test_class_app");
+    test::mojom::ClassInterfacePtr class_interface;
+    connection->GetInterface(&class_interface);
+    std::string ping_response;
+    {
+      base::RunLoop loop;
+      class_interface->Ping(base::Bind(&ReceiveString, &ping_response, &loop));
+      base::MessageLoop::ScopedNestableTaskAllower allow(
+          base::MessageLoop::current());
+      loop.Run();
+    }
+    test::mojom::ConnectTestServicePtr service;
+    connection->GetInterface(&service);
+    std::string title_response;
+    {
+      base::RunLoop loop;
+      service->GetTitle(base::Bind(&ReceiveString, &title_response, &loop));
+      base::MessageLoop::ScopedNestableTaskAllower allow(
+          base::MessageLoop::current());
+      loop.Run();
+    }
+    callback.Run(ping_response, title_response);
+  }
 
   // test::mojom::BlockedInterface:
   void GetTitleBlocked(const GetTitleBlockedCallback& callback) override {
diff --git a/mojo/shell/tests/connect/connect_test_app_manifest.json b/mojo/shell/tests/connect/connect_test_app_manifest.json
index ae25a530..b70cb1b9 100644
--- a/mojo/shell/tests/connect/connect_test_app_manifest.json
+++ b/mojo/shell/tests/connect/connect_test_app_manifest.json
@@ -4,7 +4,11 @@
   "display_name": "Connect Test App",
   "capabilities": {
     "required": {
-      "mojo:connect_test_a": { "interfaces": ["*"] }
+      "mojo:connect_test_a": { "interfaces": ["*"] },
+      "mojo:connect_test_class_app": {
+        "classes": ["class"],
+        "interfaces": ["mojo::shell::test::mojom::ConnectTestService"]
+      }
     }
   }
 }
diff --git a/mojo/shell/tests/connect/connect_test_class_app.cc b/mojo/shell/tests/connect/connect_test_class_app.cc
new file mode 100644
index 0000000..5b22dbc
--- /dev/null
+++ b/mojo/shell/tests/connect/connect_test_class_app.cc
@@ -0,0 +1,101 @@
+// 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/bind.h"
+#include "base/macros.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "mojo/public/c/system/main.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/shell/public/cpp/application_runner.h"
+#include "mojo/shell/public/cpp/connector.h"
+#include "mojo/shell/public/cpp/interface_factory.h"
+#include "mojo/shell/public/cpp/shell_client.h"
+#include "mojo/shell/public/interfaces/connector.mojom.h"
+#include "mojo/shell/tests/connect/connect_test.mojom.h"
+
+namespace mojo {
+namespace shell {
+
+using GetTitleCallback = test::mojom::ConnectTestService::GetTitleCallback;
+
+class ConnectTestClassApp
+    : public ShellClient,
+      public InterfaceFactory<test::mojom::ConnectTestService>,
+      public InterfaceFactory<test::mojom::ClassInterface>,
+      public test::mojom::ConnectTestService,
+      public test::mojom::ClassInterface {
+ public:
+  ConnectTestClassApp() {}
+  ~ConnectTestClassApp() override {}
+
+ private:
+  // mojo::ShellClient:
+  void Initialize(Connector* connector, const Identity& identity,
+                  uint32_t id) override {
+    connector_ = connector;
+    identity_ = identity;
+  }
+  bool AcceptConnection(Connection* connection) override {
+    CHECK(connection->HasCapabilityClass("class"));
+    connection->AddInterface<test::mojom::ConnectTestService>(this);
+    connection->AddInterface<test::mojom::ClassInterface>(this);
+    inbound_connections_.insert(connection);
+    connection->SetConnectionLostClosure(
+        base::Bind(&ConnectTestClassApp::OnConnectionError,
+                   base::Unretained(this), connection));
+    return true;
+  }
+
+  // InterfaceFactory<test::mojom::ConnectTestService>:
+  void Create(Connection* connection,
+              test::mojom::ConnectTestServiceRequest request) override {
+    bindings_.AddBinding(this, std::move(request));
+  }
+
+  // InterfaceFactory<test::mojom::ClassInterface>:
+  void Create(Connection* connection,
+              test::mojom::ClassInterfaceRequest request) override {
+    class_interface_bindings_.AddBinding(this, std::move(request));
+  }
+
+  // test::mojom::ConnectTestService:
+  void GetTitle(const GetTitleCallback& callback) override {
+    callback.Run("CLASS APP");
+  }
+  void GetInstance(const GetInstanceCallback& callback) override {
+    callback.Run(identity_.instance());
+  }
+
+  // test::mojom::ClassInterface:
+  void Ping(const PingCallback& callback) override {
+    callback.Run("PONG");
+  }
+
+  void OnConnectionError(Connection* connection) {
+    auto it = inbound_connections_.find(connection);
+    DCHECK(it != inbound_connections_.end());
+    inbound_connections_.erase(it);
+    if (inbound_connections_.empty())
+      base::MessageLoop::current()->QuitWhenIdle();
+  }
+
+  Connector* connector_ = nullptr;
+  Identity identity_;
+  std::set<Connection*> inbound_connections_;
+  BindingSet<test::mojom::ConnectTestService> bindings_;
+  BindingSet<test::mojom::ClassInterface> class_interface_bindings_;
+
+  DISALLOW_COPY_AND_ASSIGN(ConnectTestClassApp);
+};
+
+}  // namespace shell
+}  // namespace mojo
+
+
+MojoResult MojoMain(MojoHandle shell_handle) {
+  MojoResult rv = mojo::ApplicationRunner(
+      new mojo::shell::ConnectTestClassApp).Run(shell_handle);
+  return rv;
+}
diff --git a/mojo/shell/tests/connect/connect_test_class_app_manifest.json b/mojo/shell/tests/connect/connect_test_class_app_manifest.json
new file mode 100644
index 0000000..9bb7bb8f
--- /dev/null
+++ b/mojo/shell/tests/connect/connect_test_class_app_manifest.json
@@ -0,0 +1,10 @@
+{
+  "manifest_version": 1,
+  "name": "mojo:connect_test_class_app",
+  "display_name": "Connect Test Class App",
+  "capabilities": {
+    "provided": {
+      "class": ["mojo::shell::test::mojom::ClassInterface"]
+    }
+  }
+}
diff --git a/mojo/shell/tests/connect/connect_unittest.cc b/mojo/shell/tests/connect/connect_unittest.cc
index 38aee7a..df6c6fa 100644
--- a/mojo/shell/tests/connect/connect_unittest.cc
+++ b/mojo/shell/tests/connect/connect_unittest.cc
@@ -29,10 +29,18 @@
 const char kTestAppAName[] = "mojo:connect_test_a";
 const char kTestAppBName[] = "mojo:connect_test_b";
 
-void ReceiveTitle(std::string* out_name,
-                 base::RunLoop* loop,
-                 const String& name) {
-  *out_name = name;
+void ReceiveOneString(std::string* out_string,
+                      base::RunLoop* loop,
+                      const String& in_string) {
+  *out_string = in_string;
+  loop->Quit();
+}
+
+void ReceiveTwoStrings(std::string* out_string_1, std::string* out_string_2,
+                       base::RunLoop* loop,
+                       const String& in_string_1, const String& in_string_2) {
+  *out_string_1 = in_string_1;
+  *out_string_2 = in_string_2;
   loop->Quit();
 }
 
@@ -93,7 +101,8 @@
     connection->GetInterface(&root_service);
     base::RunLoop run_loop;
     std::string root_name;
-    root_service->GetTitle(base::Bind(&ReceiveTitle, &root_name, &run_loop));
+    root_service->GetTitle(
+        base::Bind(&ReceiveOneString, &root_name, &run_loop));
     run_loop.Run();
   }
 
@@ -123,7 +132,7 @@
   connection->GetInterface(&service);
   base::RunLoop run_loop;
   std::string title;
-  service->GetTitle(base::Bind(&ReceiveTitle, &title, &run_loop));
+  service->GetTitle(base::Bind(&ReceiveOneString, &title, &run_loop));
   run_loop.Run();
   EXPECT_EQ("APP", title);
   EXPECT_FALSE(connection->IsPending());
@@ -141,14 +150,14 @@
   {
     connection_a1->GetInterface(&service_a1);
     base::RunLoop loop;
-    service_a1->GetInstance(base::Bind(&ReceiveTitle, &instance_a1, &loop));
+    service_a1->GetInstance(base::Bind(&ReceiveOneString, &instance_a1, &loop));
     loop.Run();
   }
   test::mojom::ConnectTestServicePtr service_a2;
   {
     connection_a2->GetInterface(&service_a2);
     base::RunLoop loop;
-    service_a2->GetInstance(base::Bind(&ReceiveTitle, &instance_a2, &loop));
+    service_a2->GetInstance(base::Bind(&ReceiveOneString, &instance_a2, &loop));
     loop.Run();
   }
   EXPECT_EQ(instance_a1, instance_a2);
@@ -161,7 +170,7 @@
   {
     connection_b->GetInterface(&service_b);
     base::RunLoop loop;
-    service_b->GetInstance(base::Bind(&ReceiveTitle, &instance_b, &loop));
+    service_b->GetInstance(base::Bind(&ReceiveOneString, &instance_b, &loop));
     loop.Run();
   }
 
@@ -188,7 +197,7 @@
     test::mojom::ConnectTestServicePtr service;
     connection->GetInterface(&service);
     base::RunLoop loop;
-    service->GetInstance(base::Bind(&ReceiveTitle, &instance, &loop));
+    service->GetInstance(base::Bind(&ReceiveOneString, &instance, &loop));
     loop.Run();
   }
   EXPECT_EQ(GetNamePath(kTestAppName), instance);
@@ -203,7 +212,7 @@
   connection->GetInterface(&blocked);
   blocked.set_connection_error_handler(base::Bind(&QuitLoop, &run_loop));
   std::string title = "unchanged";
-  blocked->GetTitleBlocked(base::Bind(&ReceiveTitle, &title, &run_loop));
+  blocked->GetTitleBlocked(base::Bind(&ReceiveOneString, &title, &run_loop));
   run_loop.Run();
   EXPECT_EQ("unchanged", title);
 }
@@ -215,7 +224,7 @@
   connection->GetInterface(&service_a);
   base::RunLoop run_loop;
   std::string a_name;
-  service_a->GetTitle(base::Bind(&ReceiveTitle, &a_name, &run_loop));
+  service_a->GetTitle(base::Bind(&ReceiveOneString, &a_name, &run_loop));
   run_loop.Run();
   EXPECT_EQ("A", a_name);
   EXPECT_FALSE(connection->IsPending());
@@ -234,7 +243,7 @@
   base::RunLoop run_loop;
   std::string title;
   standalone_app->ConnectToAllowedAppInBlockedPackage(
-      base::Bind(&ReceiveTitle, &title, &run_loop));
+      base::Bind(&ReceiveOneString, &title, &run_loop));
   run_loop.Run();
   EXPECT_EQ("uninitialized", title);
 }
@@ -264,9 +273,20 @@
   EXPECT_EQ(mojom::kInvalidInstanceID, connection->GetRemoteInstanceID());
 }
 
+TEST_F(ConnectTest, CapabilityClasses) {
+  scoped_ptr<Connection> connection = connector()->Connect(kTestAppName);
+  test::mojom::StandaloneAppPtr standalone_app;
+  connection->GetInterface(&standalone_app);
+  std::string string1, string2;
+  base::RunLoop loop;
+  standalone_app->ConnectToClassInterface(
+      base::Bind(&ReceiveTwoStrings, &string1, &string2, &loop));
+  loop.Run();
+  EXPECT_EQ("PONG", string1);
+  EXPECT_EQ("CLASS APP", string2);
+}
+
 // Tests that we can expose an interface to targets on outbound connections.
-// TODO(beng): Currently all interfaces on outbound connections are exposed.
-//             See ConnectorImpl::Connect().
 TEST_F(ConnectTest, LocalInterface) {
   // Connect to a standalone application.
   {
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 3788d21..511f645 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -1890,6 +1890,8 @@
     "//base",
     "//net",
   ]
+  dict = "base/unescape_url_component_fuzzer.dict"
+  libfuzzer_options = "base/unescape_url_component_fuzzer.options"
 }
 
 fuzzer_test("net_websocket_frame_parser_fuzzer") {
diff --git a/net/base/unescape_url_component_fuzzer.dict b/net/base/unescape_url_component_fuzzer.dict
new file mode 100644
index 0000000..4569ca15
--- /dev/null
+++ b/net/base/unescape_url_component_fuzzer.dict
@@ -0,0 +1,63 @@
+"%2F"
+"%2f"
+"%"
+"%0"
+"%00"
+"%1"
+"%2"
+"%3"
+"%4"
+"%5"
+"%6"
+"%7"
+"%8"
+"%9"
+"%10"
+"%A"
+"%a"
+"%B"
+"%b"
+"%C"
+"%c"
+"%D"
+"%d"
+"%E"
+"%e"
+"%F"
+"%f"
+"\x00"
+"#"
+"%D8"
+"%d8"
+"%9c"
+"%9C"
+"%E2"
+"%e2"
+"%80"
+"%81"
+"%8E"
+"%8F"
+"%AA"
+"%aa"
+"%Aa"
+"%aA"
+"%AE"
+"%ae"
+"%Ae"
+"%aE"
+"%AA"
+"%a6"
+"%A9"
+"%a9"
+"%9F"
+"%9f"
+"%90"
+"%92"
+"%93"
+"/"
+"\\"
+" "
+"x09"
+"\x13"
+"\x10"
+"+"
\ No newline at end of file
diff --git a/net/base/unescape_url_component_fuzzer.options b/net/base/unescape_url_component_fuzzer.options
new file mode 100644
index 0000000..0428c8e
--- /dev/null
+++ b/net/base/unescape_url_component_fuzzer.options
@@ -0,0 +1,2 @@
+[libfuzzer]
+max_len = random(1, 2048)
\ No newline at end of file
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
index 19a2d6ac7..1984bad6 100644
--- a/net/cookies/cookie_monster.cc
+++ b/net/cookies/cookie_monster.cc
@@ -1901,9 +1901,8 @@
       size_t quota = 0;
       for (size_t i = 0; i < arraysize(kQuotas) && purge_goal > 0; i++) {
         quota += kQuotas[i];
-        size_t just_deleted =
-            PurgeLeastRecentMatches(cookie_its, static_cast<CookiePriority>(i),
-                                    quota, purge_goal, safe_date);
+        size_t just_deleted = PurgeLeastRecentMatches(
+            cookie_its, static_cast<CookiePriority>(i), quota, purge_goal);
         DCHECK_LE(just_deleted, purge_goal);
         purge_goal -= just_deleted;
         num_deleted += just_deleted;
@@ -1959,8 +1958,7 @@
 size_t CookieMonster::PurgeLeastRecentMatches(CookieItVector* cookies,
                                               CookiePriority priority,
                                               size_t to_protect,
-                                              size_t purge_goal,
-                                              const base::Time& safe_date) {
+                                              size_t purge_goal) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   // Find the first protected cookie by walking down from the end of the list
@@ -1980,11 +1978,8 @@
   size_t current = 0;
   while (removed < purge_goal && current < protection_boundary) {
     if (cookies->at(current)->second->Priority() <= priority) {
-      InternalDeleteCookie(
-          cookies->at(current), true,
-          cookies->at(current)->second->LastAccessDate() > safe_date
-              ? DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE
-              : DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE);
+      InternalDeleteCookie(cookies->at(current), true,
+                           DELETE_COOKIE_EVICTED_DOMAIN);
       cookies->erase(cookies->begin() + current);
       removed++;
 
diff --git a/net/cookies/cookie_monster.h b/net/cookies/cookie_monster.h
index 421e7d0..d288a84 100644
--- a/net/cookies/cookie_monster.h
+++ b/net/cookies/cookie_monster.h
@@ -280,37 +280,37 @@
   // at the end of the list, just before DELETE_COOKIE_LAST_ENTRY.
   enum DeletionCause {
     DELETE_COOKIE_EXPLICIT = 0,
-    DELETE_COOKIE_OVERWRITE,
-    DELETE_COOKIE_EXPIRED,
-    DELETE_COOKIE_EVICTED,
-    DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE,
-    DELETE_COOKIE_DONT_RECORD,  // e.g. For final cleanup after flush to store.
-    DELETE_COOKIE_EVICTED_DOMAIN,
-    DELETE_COOKIE_EVICTED_GLOBAL,
+    DELETE_COOKIE_OVERWRITE = 1,
+    DELETE_COOKIE_EXPIRED = 2,
+    DELETE_COOKIE_EVICTED = 3,
+    DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE = 4,
+    DELETE_COOKIE_DONT_RECORD = 5,  // For final cleanup after flush to store.
 
-    // Cookies evicted during domain level garbage collection that
-    // were accessed longer ago than kSafeFromGlobalPurgeDays
-    DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE,
+    // Cookies evicted during domain-level garbage collection.
+    DELETE_COOKIE_EVICTED_DOMAIN = 6,
 
-    // Cookies evicted during domain level garbage collection that
-    // were accessed more recently than kSafeFromGlobalPurgeDays
-    // (and thus would have been preserved by global garbage collection).
-    DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE,
+    // Cookies evicted during global garbage collection (which takes place after
+    // domain-level garbage collection fails to bring the cookie store under
+    // the overall quota.
+    DELETE_COOKIE_EVICTED_GLOBAL = 7,
+
+    // #8 was DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE
+    // #9 was DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE
 
     // A common idiom is to remove a cookie by overwriting it with an
     // already-expired expiration date. This captures that case.
-    DELETE_COOKIE_EXPIRED_OVERWRITE,
+    DELETE_COOKIE_EXPIRED_OVERWRITE = 10,
 
     // Cookies are not allowed to contain control characters in the name or
     // value. However, we used to allow them, so we are now evicting any such
     // cookies as we load them. See http://crbug.com/238041.
-    DELETE_COOKIE_CONTROL_CHAR,
+    DELETE_COOKIE_CONTROL_CHAR = 11,
 
     // When strict secure cookies is enabled, non-secure cookies are evicted
     // right after expired cookies.
-    DELETE_COOKIE_NON_SECURE,
+    DELETE_COOKIE_NON_SECURE = 12,
 
-    DELETE_COOKIE_LAST_ENTRY
+    DELETE_COOKIE_LAST_ENTRY = 13
   };
 
   // This enum is used to generate a histogramed bitmask measureing the types
@@ -547,14 +547,11 @@
   //
   // |cookies| must be sorted from least-recent to most-recent.
   //
-  // |safe_date| is only used to determine the deletion cause for histograms.
-  //
   // Returns the number of cookies deleted.
   size_t PurgeLeastRecentMatches(CookieItVector* cookies,
                                  CookiePriority priority,
                                  size_t to_protect,
-                                 size_t purge_goal,
-                                 const base::Time& safe_date);
+                                 size_t purge_goal);
 
   // Helper for GarbageCollect(); can be called directly as well.  Deletes all
   // expired cookies in |itpair|.  If |cookie_its| is non-NULL, all the
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index 94361dac..14da6c7 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -1065,6 +1065,7 @@
 }
 
 int HttpNetworkTransaction::BuildTokenBindingHeader(std::string* out) {
+  base::TimeTicks start = base::TimeTicks::Now();
   std::vector<uint8_t> signed_ekm;
   int rv = stream_->GetSignedEKMForTokenBinding(token_binding_key_.get(),
                                                 &signed_ekm);
@@ -1083,6 +1084,11 @@
     return rv;
   base::Base64UrlEncode(header, base::Base64UrlEncodePolicy::INCLUDE_PADDING,
                         out);
+  base::TimeDelta header_creation_time = base::TimeTicks::Now() - start;
+  UMA_HISTOGRAM_CUSTOM_TIMES("Net.TokenBinding.HeaderCreationTime",
+                             header_creation_time,
+                             base::TimeDelta::FromMilliseconds(1),
+                             base::TimeDelta::FromMinutes(1), 50);
   return OK;
 }
 
diff --git a/remoting/protocol/BUILD.gn b/remoting/protocol/BUILD.gn
index 1d24f31..1415200 100644
--- a/remoting/protocol/BUILD.gn
+++ b/remoting/protocol/BUILD.gn
@@ -28,6 +28,7 @@
     "//remoting/base",
     "//remoting/codec",
     "//remoting/signaling",
+    "//third_party/boringssl",
     "//third_party/libyuv",
   ]
 
@@ -119,6 +120,7 @@
     "ppapi_module_stub.cc",
     "pseudotcp_adapter_unittest.cc",
     "session_config_unittest.cc",
+    "spake2_authenticator_unittest.cc",
     "ssl_hmac_channel_authenticator_unittest.cc",
     "third_party_authenticator_unittest.cc",
     "v2_authenticator_unittest.cc",
diff --git a/remoting/protocol/DEPS b/remoting/protocol/DEPS
index 35a9c671..20afa9ee 100644
--- a/remoting/protocol/DEPS
+++ b/remoting/protocol/DEPS
@@ -7,6 +7,7 @@
   "+ppapi/utility",
   "+remoting/codec",
   "+remoting/signaling",
+  "+third_party/boringssl",
   "+third_party/libjingle",
   "+third_party/webrtc",
   "+third_party/protobuf/src",
diff --git a/remoting/protocol/spake2_authenticator.cc b/remoting/protocol/spake2_authenticator.cc
new file mode 100644
index 0000000..d7c0a6c
--- /dev/null
+++ b/remoting/protocol/spake2_authenticator.cc
@@ -0,0 +1,317 @@
+// 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 "remoting/protocol/spake2_authenticator.h"
+
+#include <utility>
+
+#include "base/base64.h"
+#include "base/logging.h"
+#include "base/sys_byteorder.h"
+#include "crypto/hmac.h"
+#include "crypto/secure_util.h"
+#include "remoting/base/constants.h"
+#include "remoting/base/rsa_key_pair.h"
+#include "remoting/protocol/ssl_hmac_channel_authenticator.h"
+#include "third_party/boringssl/src/include/openssl/curve25519.h"
+#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+
+namespace remoting {
+namespace protocol {
+
+namespace {
+
+// Each peer sends 2 messages: <spake-message> and <verification-hash>. The
+// content of <spake-message> is the output of SPAKE2_generate_msg() and must
+// be passed to SPAKE2_process_msg() on the other end. This is enough to
+// generate authentication key. <verification-hash> is sent to confirm that both
+// ends get the same authentication key (which means they both know the
+// password). This verification hash is calculated in
+// CalculateVerificationHash() as follows:
+//    HMAC_SHA256(auth_key, ("host"|"client") + local_jid.length() + local_jid +
+//                remote_jid.length() + remote_jid)
+// where auth_key is the key produced by SPAKE2.
+
+const buzz::StaticQName kSpakeMessageTag = {kChromotingXmlNamespace,
+                                            "spake-message"};
+const buzz::StaticQName kVerificationHashTag = {kChromotingXmlNamespace,
+                                                "verification-hash"};
+const buzz::StaticQName kCertificateTag = {kChromotingXmlNamespace,
+                                           "certificate"};
+
+scoped_ptr<buzz::XmlElement> EncodeBinaryValueToXml(
+    const buzz::StaticQName& qname,
+    const std::string& content) {
+  std::string content_base64;
+  base::Base64Encode(content, &content_base64);
+
+  scoped_ptr<buzz::XmlElement> result(new buzz::XmlElement(qname));
+  result->SetBodyText(content_base64);
+  return result;
+}
+
+// Finds tag named |qname| in base_message and decodes it from base64 and stores
+// in |data|. If the element is not present then found is set to false otherwise
+// it's set to true. If the element is there and it's content cound't be decoded
+// then false is returned.
+bool DecodeBinaryValueFromXml(const buzz::XmlElement* message,
+                              const buzz::QName& qname,
+                              bool* found,
+                              std::string* data) {
+  const buzz::XmlElement* element = message->FirstNamed(qname);
+  *found = element != nullptr;
+  if (!*found)
+    return true;
+
+  if (!base::Base64Decode(element->BodyText(), data)) {
+    LOG(WARNING) << "Failed to parse " << qname.LocalPart();
+    return false;
+  }
+
+  return !data->empty();
+}
+
+std::string PrefixWithLength(const std::string& str) {
+  uint32_t length = base::HostToNet32(str.size());
+  return std::string(reinterpret_cast<char*>(&length), sizeof(length)) + str;
+}
+
+}  // namespace
+
+// static
+scoped_ptr<Authenticator> Spake2Authenticator::CreateForClient(
+    const std::string& local_id,
+    const std::string& remote_id,
+    const std::string& shared_secret,
+    Authenticator::State initial_state) {
+  return make_scoped_ptr(new Spake2Authenticator(
+      local_id, remote_id, shared_secret, false, initial_state));
+}
+
+// static
+scoped_ptr<Authenticator> Spake2Authenticator::CreateForHost(
+    const std::string& local_id,
+    const std::string& remote_id,
+    const std::string& shared_secret,
+    const std::string& local_cert,
+    scoped_refptr<RsaKeyPair> key_pair,
+    Authenticator::State initial_state) {
+  scoped_ptr<Spake2Authenticator> result(new Spake2Authenticator(
+      local_id, remote_id, shared_secret, true, initial_state));
+  result->local_cert_ = local_cert;
+  result->local_key_pair_ = key_pair;
+  return std::move(result);
+}
+
+Spake2Authenticator::Spake2Authenticator(const std::string& local_id,
+                                         const std::string& remote_id,
+                                         const std::string& shared_secret,
+                                         bool is_host,
+                                         Authenticator::State initial_state)
+    : local_id_(local_id),
+      remote_id_(remote_id),
+      shared_secret_(shared_secret),
+      is_host_(is_host),
+      state_(initial_state) {
+  spake2_context_ = SPAKE2_CTX_new(
+      is_host ? spake2_role_bob : spake2_role_alice,
+      reinterpret_cast<const uint8_t*>(local_id_.data()), local_id_.size(),
+      reinterpret_cast<const uint8_t*>(remote_id_.data()), remote_id_.size());
+
+  // Generate first message and push it to |pending_messages_|.
+  uint8_t message[SPAKE2_MAX_MSG_SIZE];
+  size_t message_size;
+  int result = SPAKE2_generate_msg(
+      spake2_context_, message, &message_size, sizeof(message),
+      reinterpret_cast<const uint8_t*>(shared_secret_.data()),
+      shared_secret_.size());
+  CHECK(result);
+  local_spake_message_.assign(reinterpret_cast<char*>(message), message_size);
+}
+
+Spake2Authenticator::~Spake2Authenticator() {
+  SPAKE2_CTX_free(spake2_context_);
+}
+
+Authenticator::State Spake2Authenticator::state() const {
+  if (state_ == ACCEPTED && !outgoing_verification_hash_.empty())
+    return MESSAGE_READY;
+  return state_;
+}
+
+bool Spake2Authenticator::started() const {
+  return started_;
+}
+
+Authenticator::RejectionReason Spake2Authenticator::rejection_reason() const {
+  DCHECK_EQ(state(), REJECTED);
+  return rejection_reason_;
+}
+
+void Spake2Authenticator::ProcessMessage(const buzz::XmlElement* message,
+                                         const base::Closure& resume_callback) {
+  ProcessMessageInternal(message);
+  resume_callback.Run();
+}
+
+void Spake2Authenticator::ProcessMessageInternal(
+    const buzz::XmlElement* message) {
+  DCHECK_EQ(state(), WAITING_MESSAGE);
+
+  // Parse the certificate.
+  bool cert_present;
+  if (!DecodeBinaryValueFromXml(message, kCertificateTag, &cert_present,
+                                &remote_cert_)) {
+    state_ = REJECTED;
+    rejection_reason_ = PROTOCOL_ERROR;
+    return;
+  }
+
+  // Client always expects certificate in the first message.
+  if (!is_host_ && remote_cert_.empty()) {
+    LOG(WARNING) << "No valid host certificate.";
+    state_ = REJECTED;
+    rejection_reason_ = PROTOCOL_ERROR;
+    return;
+  }
+
+  bool spake_message_present = false;
+  std::string spake_message;
+  bool verification_hash_present = false;
+  std::string verification_hash;
+  if (!DecodeBinaryValueFromXml(message, kSpakeMessageTag,
+                                &spake_message_present, &spake_message) ||
+      !DecodeBinaryValueFromXml(message, kVerificationHashTag,
+                                &verification_hash_present,
+                                &verification_hash)) {
+    state_ = REJECTED;
+    rejection_reason_ = PROTOCOL_ERROR;
+    return;
+  }
+
+  // |auth_key_| is generated when <spake-message> is received.
+  if (auth_key_.empty()) {
+    if (!spake_message_present) {
+      LOG(WARNING) << "<spake-message> not found.";
+      state_ = REJECTED;
+      rejection_reason_ = PROTOCOL_ERROR;
+      return;
+    }
+    uint8_t key[SPAKE2_MAX_KEY_SIZE];
+    size_t key_size;
+    started_ = true;
+    int result = SPAKE2_process_msg(
+        spake2_context_, key, &key_size, sizeof(key),
+        reinterpret_cast<const uint8_t*>(spake_message.data()),
+        spake_message.size());
+    if (!result) {
+      state_ = REJECTED;
+      rejection_reason_ = INVALID_CREDENTIALS;
+      return;
+    }
+    CHECK(key_size);
+    auth_key_.assign(reinterpret_cast<char*>(key), key_size);
+
+    outgoing_verification_hash_ =
+        CalculateVerificationHash(is_host_, local_id_, remote_id_);
+    expected_verification_hash_ =
+        CalculateVerificationHash(!is_host_, remote_id_, local_id_);
+  } else if (spake_message_present) {
+    LOG(WARNING) << "Received duplicate <spake-message>.";
+    state_ = REJECTED;
+    rejection_reason_ = PROTOCOL_ERROR;
+    return;
+  }
+
+  if (spake_message_sent_ && !verification_hash_present) {
+    LOG(WARNING) << "Didn't receive <verification-hash> when expected.";
+    state_ = REJECTED;
+    rejection_reason_ = PROTOCOL_ERROR;
+    return;
+  }
+
+  if (verification_hash_present) {
+    if (verification_hash.size() != expected_verification_hash_.size() ||
+        !crypto::SecureMemEqual(verification_hash.data(),
+                                expected_verification_hash_.data(),
+                                verification_hash.size())) {
+      state_ = REJECTED;
+      rejection_reason_ = INVALID_CREDENTIALS;
+      return;
+    }
+    state_ = ACCEPTED;
+    return;
+  }
+
+  state_ = MESSAGE_READY;
+}
+
+scoped_ptr<buzz::XmlElement> Spake2Authenticator::GetNextMessage() {
+  DCHECK_EQ(state(), MESSAGE_READY);
+
+  scoped_ptr<buzz::XmlElement> message = CreateEmptyAuthenticatorMessage();
+
+  if (!spake_message_sent_) {
+    if (!local_cert_.empty()) {
+      message->AddElement(
+          EncodeBinaryValueToXml(kCertificateTag, local_cert_).release());
+    }
+
+    message->AddElement(
+        EncodeBinaryValueToXml(kSpakeMessageTag, local_spake_message_)
+            .release());
+
+    spake_message_sent_ = true;
+  }
+
+  if (!outgoing_verification_hash_.empty()) {
+    message->AddElement(EncodeBinaryValueToXml(kVerificationHashTag,
+                                               outgoing_verification_hash_)
+                            .release());
+    outgoing_verification_hash_.clear();
+  }
+
+  if (state_ != ACCEPTED) {
+    state_ = WAITING_MESSAGE;
+  }
+  return message;
+}
+
+const std::string& Spake2Authenticator::GetAuthKey() const {
+  return auth_key_;
+}
+
+scoped_ptr<ChannelAuthenticator>
+Spake2Authenticator::CreateChannelAuthenticator() const {
+  DCHECK_EQ(state(), ACCEPTED);
+  CHECK(!auth_key_.empty());
+
+  if (is_host_) {
+    return SslHmacChannelAuthenticator::CreateForHost(
+        local_cert_, local_key_pair_, auth_key_);
+  } else {
+    return SslHmacChannelAuthenticator::CreateForClient(remote_cert_,
+                                                        auth_key_);
+  }
+}
+
+std::string Spake2Authenticator::CalculateVerificationHash(
+    bool from_host,
+    const std::string& local_id,
+    const std::string& remote_id) {
+  std::string message = (from_host ? "host" : "client") +
+                        PrefixWithLength(local_id) +
+                        PrefixWithLength(remote_id);
+  crypto::HMAC hmac(crypto::HMAC::SHA256);
+  std::string result(hmac.DigestLength(), '\0');
+  if (!hmac.Init(auth_key_) ||
+      !hmac.Sign(message, reinterpret_cast<uint8_t*>(&result[0]),
+                 result.length())) {
+    LOG(FATAL) << "Failed to calculate HMAC.";
+  }
+  return result;
+}
+
+}  // namespace protocol
+}  // namespace remoting
diff --git a/remoting/protocol/spake2_authenticator.h b/remoting/protocol/spake2_authenticator.h
new file mode 100644
index 0000000..b16d634
--- /dev/null
+++ b/remoting/protocol/spake2_authenticator.h
@@ -0,0 +1,99 @@
+// 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 REMOTING_PROTOCOL_SPAKE2_AUTHENTICATOR_H_
+#define REMOTING_PROTOCOL_SPAKE2_AUTHENTICATOR_H_
+
+#include <queue>
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "remoting/protocol/authenticator.h"
+
+typedef struct spake2_ctx_st SPAKE2_CTX;
+
+namespace remoting {
+
+class RsaKeyPair;
+
+namespace protocol {
+
+// Authenticator that uses SPAKE2 implementation from BoringSSL. It
+// implements SPAKE2 over Curve25519.
+class Spake2Authenticator : public Authenticator {
+ public:
+  static scoped_ptr<Authenticator> CreateForClient(
+      const std::string& local_id,
+      const std::string& remote_id,
+      const std::string& shared_secret,
+      State initial_state);
+
+  static scoped_ptr<Authenticator> CreateForHost(
+      const std::string& local_id,
+      const std::string& remote_id,
+      const std::string& shared_secret,
+      const std::string& local_cert,
+      scoped_refptr<RsaKeyPair> key_pair,
+      State initial_state);
+
+  ~Spake2Authenticator() override;
+
+  // Authenticator interface.
+  State state() const override;
+  bool started() const override;
+  RejectionReason rejection_reason() const override;
+  void ProcessMessage(const buzz::XmlElement* message,
+                      const base::Closure& resume_callback) override;
+  scoped_ptr<buzz::XmlElement> GetNextMessage() override;
+  const std::string& GetAuthKey() const override;
+  scoped_ptr<ChannelAuthenticator> CreateChannelAuthenticator() const override;
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(Spake2AuthenticatorTest, InvalidSecret);
+
+  Spake2Authenticator(const std::string& local_id,
+                      const std::string& remote_id,
+                      const std::string& shared_secret,
+                      bool is_host,
+                      State initial_state);
+
+  virtual void ProcessMessageInternal(const buzz::XmlElement* message);
+
+  std::string CalculateVerificationHash(bool from_host,
+                                        const std::string& local_id,
+                                        const std::string& remote_id);
+
+  const std::string local_id_;
+  const std::string remote_id_;
+  const std::string shared_secret_;
+  const bool is_host_;
+
+  // Used only for host authenticators.
+  std::string local_cert_;
+  scoped_refptr<RsaKeyPair> local_key_pair_;
+
+  // Used only for client authenticators.
+  std::string remote_cert_;
+
+  // Used for both host and client authenticators.
+  SPAKE2_CTX* spake2_context_;
+  State state_;
+  bool started_ = false;
+  RejectionReason rejection_reason_ = INVALID_CREDENTIALS;
+  std::string local_spake_message_;
+  bool spake_message_sent_ = false;
+  std::string outgoing_verification_hash_;
+  std::string auth_key_;
+  std::string expected_verification_hash_;
+
+  DISALLOW_COPY_AND_ASSIGN(Spake2Authenticator);
+};
+
+}  // namespace protocol
+}  // namespace remoting
+
+#endif  // REMOTING_PROTOCOL_SPAKE2_AUTHENTICATOR_H_
diff --git a/remoting/protocol/spake2_authenticator_unittest.cc b/remoting/protocol/spake2_authenticator_unittest.cc
new file mode 100644
index 0000000..9f5e5d0
--- /dev/null
+++ b/remoting/protocol/spake2_authenticator_unittest.cc
@@ -0,0 +1,98 @@
+// 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 "remoting/protocol/spake2_authenticator.h"
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "remoting/base/rsa_key_pair.h"
+#include "remoting/protocol/authenticator_test_base.h"
+#include "remoting/protocol/channel_authenticator.h"
+#include "remoting/protocol/connection_tester.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+
+using testing::_;
+using testing::DeleteArg;
+using testing::SaveArg;
+
+namespace remoting {
+namespace protocol {
+
+namespace {
+
+const int kMessageSize = 100;
+const int kMessages = 1;
+
+const char kClientId[] = "alice@gmail.com/abc";
+const char kHostId[] = "alice@gmail.com/123";
+
+const char kTestSharedSecret[] = "1234-1234-5678";
+const char kTestSharedSecretBad[] = "0000-0000-0001";
+
+}  // namespace
+
+class Spake2AuthenticatorTest : public AuthenticatorTestBase {
+ public:
+  Spake2AuthenticatorTest() {}
+  ~Spake2AuthenticatorTest() override {}
+
+ protected:
+  void InitAuthenticators(const std::string& client_secret,
+                          const std::string& host_secret) {
+    host_ = Spake2Authenticator::CreateForHost(kHostId, kClientId, host_secret,
+                                               host_cert_, key_pair_,
+                                               Authenticator::WAITING_MESSAGE);
+    client_ = Spake2Authenticator::CreateForClient(
+        kClientId, kHostId, client_secret, Authenticator::MESSAGE_READY);
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(Spake2AuthenticatorTest);
+};
+
+TEST_F(Spake2AuthenticatorTest, SuccessfulAuth) {
+  ASSERT_NO_FATAL_FAILURE(
+      InitAuthenticators(kTestSharedSecret, kTestSharedSecret));
+  ASSERT_NO_FATAL_FAILURE(RunAuthExchange());
+
+  ASSERT_EQ(Authenticator::ACCEPTED, host_->state());
+  ASSERT_EQ(Authenticator::ACCEPTED, client_->state());
+
+  client_auth_ = client_->CreateChannelAuthenticator();
+  host_auth_ = host_->CreateChannelAuthenticator();
+  RunChannelAuth(false);
+
+  StreamConnectionTester tester(host_socket_.get(), client_socket_.get(),
+                                kMessageSize, kMessages);
+
+  tester.Start();
+  message_loop_.Run();
+  tester.CheckResults();
+}
+
+// Verify that connection is rejected when secrets don't match.
+TEST_F(Spake2AuthenticatorTest, InvalidSecret) {
+  ASSERT_NO_FATAL_FAILURE(
+      InitAuthenticators(kTestSharedSecretBad, kTestSharedSecret));
+  ASSERT_NO_FATAL_FAILURE(RunAuthExchange());
+
+  ASSERT_EQ(Authenticator::REJECTED, client_->state());
+  ASSERT_EQ(Authenticator::INVALID_CREDENTIALS, client_->rejection_reason());
+
+  // Change |client_| so that we can get the last message.
+  reinterpret_cast<Spake2Authenticator*>(client_.get())->state_ =
+      Authenticator::MESSAGE_READY;
+
+  scoped_ptr<buzz::XmlElement> message(client_->GetNextMessage());
+  ASSERT_TRUE(message.get());
+
+  ASSERT_EQ(Authenticator::WAITING_MESSAGE, client_->state());
+  host_->ProcessMessage(message.get(), base::Bind(&base::DoNothing));
+  // This assumes that Spake2Authenticator::ProcessMessage runs synchronously.
+  ASSERT_EQ(Authenticator::REJECTED, host_->state());
+}
+
+}  // namespace protocol
+}  // namespace remoting
diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp
index 79057768c..9c7c8ca 100644
--- a/remoting/remoting.gyp
+++ b/remoting/remoting.gyp
@@ -236,6 +236,7 @@
         '../crypto/crypto.gyp:crypto',
         '../jingle/jingle.gyp:jingle_glue',
         '../net/net.gyp:net',
+        '../third_party/boringssl/boringssl.gyp:boringssl',
         '../third_party/expat/expat.gyp:expat',
         '../third_party/libjingle/libjingle.gyp:libjingle',
         '../third_party/libyuv/libyuv.gyp:libyuv',
@@ -250,7 +251,7 @@
         '<@(remoting_signaling_sources)',
       ],
       'conditions': [
-        ['enable_webrtc==1', {
+        ['enable_webrtc == 1', {
           'dependencies': [
             '../third_party/libjingle/libjingle.gyp:libjingle_webrtc',
             '../third_party/libjingle/libjingle.gyp:libpeerconnection',
diff --git a/remoting/remoting_srcs.gypi b/remoting/remoting_srcs.gypi
index 0788f88..59a0559 100644
--- a/remoting/remoting_srcs.gypi
+++ b/remoting/remoting_srcs.gypi
@@ -195,6 +195,8 @@
       'protocol/session_manager.h',
       'protocol/socket_util.cc',
       'protocol/socket_util.h',
+      'protocol/spake2_authenticator.cc',
+      'protocol/spake2_authenticator.h',
       'protocol/ssl_hmac_channel_authenticator.cc',
       'protocol/ssl_hmac_channel_authenticator.h',
       'protocol/stream_channel_factory.h',
diff --git a/remoting/remoting_test.gypi b/remoting/remoting_test.gypi
index 5e36aa0..7f6858d 100644
--- a/remoting/remoting_test.gypi
+++ b/remoting/remoting_test.gypi
@@ -337,6 +337,7 @@
         'protocol/ppapi_module_stub.cc',
         'protocol/pseudotcp_adapter_unittest.cc',
         'protocol/session_config_unittest.cc',
+        'protocol/spake2_authenticator_unittest.cc',
         'protocol/ssl_hmac_channel_authenticator_unittest.cc',
         'protocol/third_party_authenticator_unittest.cc',
         'protocol/v2_authenticator_unittest.cc',
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-element-auto-repeat-get-set-expected.txt b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-element-auto-repeat-get-set-expected.txt
index 4c70c74..3953b477 100644
--- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-element-auto-repeat-get-set-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-element-auto-repeat-get-set-expected.txt
@@ -4,30 +4,30 @@
 
 
 Test auto-repeat syntax.
-FAIL getComputedStyle(element, '').getPropertyValue('grid-template-columns') should be [foo bar] 10px. Was 0px.
-PASS element.style.gridTemplateColumns is "repeat(auto-fill, [foo bar] 10px)"
-FAIL getComputedStyle(element, '').getPropertyValue('grid-template-rows') should be 20px [foo bar]. Was 0px.
-PASS element.style.gridTemplateRows is "repeat(auto-fill, 2em [foo bar])"
-FAIL getComputedStyle(element, '').getPropertyValue('grid-template-columns') should be [foo bar] 800px. Was 0px.
-PASS element.style.gridTemplateColumns is "repeat(auto-fill, [foo bar] minmax(10px, 1fr))"
-FAIL getComputedStyle(element, '').getPropertyValue('grid-template-rows') should be [foo] 20px [bar]. Was 0px.
-PASS element.style.gridTemplateRows is "repeat(auto-fill, [foo] minmax(2em, max-content) [bar])"
-FAIL getComputedStyle(element, '').getPropertyValue('grid-template-columns') should be 100px 20px 20px. Was 20px 20px.
-PASS element.style.gridTemplateColumns is "repeat(auto-fill, minmax(10px, 100px)) 20px 20px"
-FAIL getComputedStyle(element, '').getPropertyValue('grid-template-rows') should be 70px 20px [bar foo] 10px [foo] 10px. Was 70px 10px [foo] 10px [foo].
-PASS element.style.gridTemplateRows is "70px repeat(auto-fill, minmax(2em, max-content) [bar]) [foo] 1em [foo] 1em"
-FAIL getComputedStyle(element, '').getPropertyValue('grid-template-columns') should be [foo bar] 10px. Was 0px.
-PASS element.style.gridTemplateColumns is "repeat(auto-fit, [foo bar] 10px)"
-FAIL getComputedStyle(element, '').getPropertyValue('grid-template-rows') should be 20px [foo bar]. Was 0px.
-PASS element.style.gridTemplateRows is "repeat(auto-fit, 2em [foo bar])"
-FAIL getComputedStyle(element, '').getPropertyValue('grid-template-columns') should be [foo bar] 800px. Was 0px.
-PASS element.style.gridTemplateColumns is "repeat(auto-fit, [foo bar] minmax(10px, 1fr))"
-FAIL getComputedStyle(element, '').getPropertyValue('grid-template-rows') should be [foo] 20px [bar]. Was 0px.
-PASS element.style.gridTemplateRows is "repeat(auto-fit, [foo] minmax(2em, max-content) [bar])"
-FAIL getComputedStyle(element, '').getPropertyValue('grid-template-columns') should be 10px 20px 20px. Was 20px 20px.
-PASS element.style.gridTemplateColumns is "repeat(auto-fit, minmax(10px, min-content)) 20px 20px"
-FAIL getComputedStyle(element, '').getPropertyValue('grid-template-rows') should be 60px 20px [bar foo] 10px [foo] 10px. Was 60px 10px [foo] 10px [foo].
-PASS element.style.gridTemplateRows is "10% repeat(auto-fit, minmax(2em, max-content) [bar]) [foo] 1em [foo] 1em"
+PASS getComputedStyle(element, '').getPropertyValue('grid-template-columns') is "[foo bar] 10px"
+PASS element.style.gridTemplateColumns is "[foo bar] 10px"
+PASS getComputedStyle(element, '').getPropertyValue('grid-template-rows') is "20px [foo bar]"
+PASS element.style.gridTemplateRows is "2em [foo bar]"
+PASS getComputedStyle(element, '').getPropertyValue('grid-template-columns') is "[foo bar] 800px"
+PASS element.style.gridTemplateColumns is "[foo bar] minmax(10px, 1fr)"
+PASS getComputedStyle(element, '').getPropertyValue('grid-template-rows') is "[foo] 20px [bar]"
+PASS element.style.gridTemplateRows is "[foo] minmax(2em, max-content) [bar]"
+PASS getComputedStyle(element, '').getPropertyValue('grid-template-columns') is "100px 20px 20px"
+PASS element.style.gridTemplateColumns is "minmax(10px, 100px) 20px 20px"
+PASS getComputedStyle(element, '').getPropertyValue('grid-template-rows') is "70px 20px [bar foo] 10px [foo] 10px"
+PASS element.style.gridTemplateRows is "70px minmax(2em, max-content) [bar] [foo] 1em [foo] 1em"
+PASS getComputedStyle(element, '').getPropertyValue('grid-template-columns') is "[foo bar] 10px"
+PASS element.style.gridTemplateColumns is "[foo bar] 10px"
+PASS getComputedStyle(element, '').getPropertyValue('grid-template-rows') is "20px [foo bar]"
+PASS element.style.gridTemplateRows is "2em [foo bar]"
+PASS getComputedStyle(element, '').getPropertyValue('grid-template-columns') is "[foo bar] 800px"
+PASS element.style.gridTemplateColumns is "[foo bar] minmax(10px, 1fr)"
+PASS getComputedStyle(element, '').getPropertyValue('grid-template-rows') is "[foo] 20px [bar]"
+PASS element.style.gridTemplateRows is "[foo] minmax(2em, max-content) [bar]"
+PASS getComputedStyle(element, '').getPropertyValue('grid-template-columns') is "10px 20px 20px"
+PASS element.style.gridTemplateColumns is "minmax(10px, min-content) 20px 20px"
+PASS getComputedStyle(element, '').getPropertyValue('grid-template-rows') is "60px 20px [bar foo] 10px [foo] 10px"
+PASS element.style.gridTemplateRows is "10% minmax(2em, max-content) [bar] [foo] 1em [foo] 1em"
 
 Test invalid repeat syntax.
 PASS window.getComputedStyle(element, '').getPropertyValue('grid-template-columns') is "none"
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-element-auto-repeat-get-set.html b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-element-auto-repeat-get-set.html
index ebfa116..94f18a54 100644
--- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-element-auto-repeat-get-set.html
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-element-auto-repeat-get-set.html
@@ -9,12 +9,12 @@
     description('Test that setting/getting grid-template-{columns|rows} with repeat(auto-fill|auto-fit,) works as expected');
 
     debug("Test auto-repeat syntax.");
-    testGridDefinitionsSetJSValues("repeat(auto-fill, [foo bar] 10px)", "repeat(auto-fill, 2em [foo bar])", "[foo bar] 10px", "20px [foo bar]", "repeat(auto-fill, [foo bar] 10px)", "repeat(auto-fill, 2em [foo bar])");
-    testGridDefinitionsSetJSValues("repeat(auto-fill, [foo bar] minmax(10px, 1fr))", "repeat(auto-fill, [foo] minmax(2em, max-content) [bar])", "[foo bar] 800px", "[foo] 20px [bar]", "repeat(auto-fill, [foo bar] minmax(10px, 1fr))", "repeat(auto-fill, [foo] minmax(2em, max-content) [bar])");
-    testGridDefinitionsSetJSValues("repeat(auto-fill, minmax(10px, 100px)) repeat(2, 20px)", "repeat(1, 70px) repeat(auto-fill, minmax(2em, max-content) [bar]) repeat(2, [foo] 1em)", "100px 20px 20px", "70px 20px [bar foo] 10px [foo] 10px", "repeat(auto-fill, minmax(10px, 100px)) 20px 20px", "70px repeat(auto-fill, minmax(2em, max-content) [bar]) [foo] 1em [foo] 1em");
-    testGridDefinitionsSetJSValues("repeat(auto-fit, [foo bar] 10px)", "repeat(auto-fit, 2em [foo bar])", "[foo bar] 10px", "20px [foo bar]", "repeat(auto-fit, [foo bar] 10px)", "repeat(auto-fit, 2em [foo bar])");
-    testGridDefinitionsSetJSValues("repeat(auto-fit, [foo bar] minmax(10px, 1fr))", "repeat(auto-fit, [foo] minmax(2em, max-content) [bar])", "[foo bar] 800px", "[foo] 20px [bar]", "repeat(auto-fit, [foo bar] minmax(10px, 1fr))", "repeat(auto-fit, [foo] minmax(2em, max-content) [bar])");
-    testGridDefinitionsSetJSValues("repeat(auto-fit, minmax(10px, min-content)) repeat(2, 20px)", "repeat(1, 10%) repeat(auto-fit, minmax(2em, max-content) [bar]) repeat(2, [foo] 1em)", "10px 20px 20px", "60px 20px [bar foo] 10px [foo] 10px", "repeat(auto-fit, minmax(10px, min-content)) 20px 20px", "10% repeat(auto-fit, minmax(2em, max-content) [bar]) [foo] 1em [foo] 1em");
+    testGridDefinitionsSetJSValues("repeat(auto-fill, [foo bar] 10px)", "repeat(auto-fill, 2em [foo bar])", "[foo bar] 10px", "20px [foo bar]", "[foo bar] 10px", "2em [foo bar]");
+    testGridDefinitionsSetJSValues("repeat(auto-fill, [foo bar] minmax(10px, 1fr))", "repeat(auto-fill, [foo] minmax(2em, max-content) [bar])", "[foo bar] 800px", "[foo] 20px [bar]", "[foo bar] minmax(10px, 1fr)", "[foo] minmax(2em, max-content) [bar]");
+    testGridDefinitionsSetJSValues("repeat(auto-fill, minmax(10px, 100px)) repeat(2, 20px)", "repeat(1, 70px) repeat(auto-fill, minmax(2em, max-content) [bar]) repeat(2, [foo] 1em)", "100px 20px 20px", "70px 20px [bar foo] 10px [foo] 10px", "minmax(10px, 100px) 20px 20px", "70px minmax(2em, max-content) [bar] [foo] 1em [foo] 1em");
+    testGridDefinitionsSetJSValues("repeat(auto-fit, [foo bar] 10px)", "repeat(auto-fit, 2em [foo bar])", "[foo bar] 10px", "20px [foo bar]", "[foo bar] 10px", "2em [foo bar]");
+    testGridDefinitionsSetJSValues("repeat(auto-fit, [foo bar] minmax(10px, 1fr))", "repeat(auto-fit, [foo] minmax(2em, max-content) [bar])", "[foo bar] 800px", "[foo] 20px [bar]", "[foo bar] minmax(10px, 1fr)", "[foo] minmax(2em, max-content) [bar]");
+    testGridDefinitionsSetJSValues("repeat(auto-fit, minmax(10px, min-content)) repeat(2, 20px)", "repeat(1, 10%) repeat(auto-fit, minmax(2em, max-content) [bar]) repeat(2, [foo] 1em)", "10px 20px 20px", "60px 20px [bar foo] 10px [foo] 10px", "minmax(10px, min-content) 20px 20px", "10% minmax(2em, max-content) [bar] [foo] 1em [foo] 1em");
 
     debug("");
     debug("Test invalid repeat syntax.");
diff --git a/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-createAnswer-expected.txt b/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-createAnswer-expected.txt
index a009b87..b8f0029 100644
--- a/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-createAnswer-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-createAnswer-expected.txt
@@ -3,10 +3,14 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS createOffer request failed.
-PASS pc.setRemoteDescription(sessionDescription, requestSucceeded2, requestFailed2); did not throw exception.
+PASS testExecutionOrderClosedConnection() did not throw exception.
+PASS error.name is "InvalidStateError"
+PASS error.toString() is "InvalidStateError: The RTCPeerConnection's signalingState is 'closed'."
+PASS events is [1,2,3]
+PASS createOffer request without remote description failed.
+PASS pc.setRemoteDescription(sessionDescription, descriptionSet, unexpectedCallback); did not throw exception.
 PASS setRemoteDescription request succeeded.
-PASS pc.createAnswer(requestSucceeded3, requestFailed3); did not throw exception.
+PASS pc.createAnswer(answerCreated, unexpectedCallback); did not throw exception.
 PASS createAnswer request succeeded.
 PASS successfullyParsed is true
 
diff --git a/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-createAnswer.html b/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-createAnswer.html
index d768376..64fb888 100644
--- a/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-createAnswer.html
+++ b/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-createAnswer.html
@@ -9,50 +9,53 @@
 
 var pc = null;
 
-function requestFailed3(error)
+function unexpectedCallback()
 {
-    testFailed('createAnswer request failed.');
-
+    testFailed('unexpectedCallback was called')
     finishJSTest();
 }
 
-function requestSucceeded3()
+function answerCreated()
 {
     testPassed('createAnswer request succeeded.');
-
     finishJSTest();
 }
 
-function requestFailed2(error)
-{
-    testFailed('setRemoteDescription request failed.');
-
-    finishJSTest();
-}
-
-function requestSucceeded2()
+function descriptionSet()
 {
     testPassed('setRemoteDescription request succeeded.');
-
-    shouldNotThrow('pc.createAnswer(requestSucceeded3, requestFailed3);');
+    shouldNotThrow('pc.createAnswer(answerCreated, unexpectedCallback);');
 }
 
-function requestFailed1()
+function createOfferWithoutDescriptionFailed()
 {
-    testPassed('createOffer request failed.');
-
+    testPassed('createOffer request without remote description failed.');
     sessionDescription = new RTCSessionDescription({type:"answer", sdp:"remote"});
-    shouldNotThrow('pc.setRemoteDescription(sessionDescription, requestSucceeded2, requestFailed2);');
+    shouldNotThrow('pc.setRemoteDescription(sessionDescription, descriptionSet, unexpectedCallback);');
 }
 
-function requestSucceeded1(sd)
+function testExecutionOrderClosedConnection()
 {
-    testFailed('createOffer request succeeded.');
-    finishJSTest();
+    var localPeerConnection = new webkitRTCPeerConnection(null, null);
+    localPeerConnection.close();
+    var counter = 0;
+    window.events = [];
+    Promise.resolve().then(_ => window.events[counter++] = 1);
+    localPeerConnection.createAnswer(unexpectedCallback, error => {
+        window.error = error;
+        shouldBe('error.name', '"InvalidStateError"');
+        shouldBe('error.toString()', '"InvalidStateError: The RTCPeerConnection\'s signalingState is \'closed\'."');
+        window.events[counter++] = 2;
+    });
+    Promise.resolve().then(_ => {
+        window.events[counter++] = 3;
+        shouldBe('events', '[1,2,3]');
+    });
 }
 
+shouldNotThrow('testExecutionOrderClosedConnection()');
 pc = new webkitRTCPeerConnection(null, null);
-pc.createOffer(requestSucceeded1, requestFailed1);
+pc.createOffer(unexpectedCallback, createOfferWithoutDescriptionFailed);
 
 window.jsTestIsAsync = true;
 window.successfullyParsed = true;
diff --git a/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-createOffer-expected.txt b/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-createOffer-expected.txt
index a62c15b..8016c2a 100644
--- a/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-createOffer-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-createOffer-expected.txt
@@ -3,19 +3,43 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS requestSucceeded was called.
+PASS testExecutionOrderClosedConnection() did not throw exception.
+PASS pc.createOffer(createOfferSucceeded1, unexpectedCallback, {voiceActivityDetection:true, iceRestart:true}); did not throw exception.
+PASS error.name is "InvalidStateError"
+PASS error.toString() is "InvalidStateError: The RTCPeerConnection's signalingState is 'closed'."
+PASS events is [1,2,3]
+PASS createOfferSucceeded1 was called.
 PASS sessionDescription.type is "offer"
-PASS requestFailed was called.
+PASS pc.createOffer(unexpectedCallback, expectedCreateOfferFailed1); did not throw exception.
+PASS expectedCreateOfferFailed1 was called.
 PASS error.name is "OperationError"
 PASS error.toString() is "OperationError: TEST_ERROR"
-PASS pc.createOffer(dummy, dummy); did not throw exception.
-PASS pc.createOffer(dummy, dummy, {}); did not throw exception.
-PASS pc.createOffer(dummy, dummy, {voiceActivityDetection:false}); did not throw exception.
-PASS pc.createOffer(dummy, dummy, {iceRestart:true}); did not throw exception.
-PASS pc.createOffer(dummy, dummy, {voiceActivityDetection:false, iceRestart:true}); did not throw exception.
-PASS pc.createOffer(dummy, dummy, {offerToReceiveVideo:-1, offerToReceiveAudio:0}); threw exception TypeError: Failed to execute 'createOffer' on 'RTCPeerConnection': Invalid offerToReceiveVideo.
-PASS pc.createOffer(dummy, dummy, {offerToReceiveVideo:0, offerToReceiveAudio:-1}); threw exception TypeError: Failed to execute 'createOffer' on 'RTCPeerConnection': Invalid offerToReceiveAudio.
-PASS pc.createOffer(dummy, dummy, {offerToReceiveVideo:1, offerToReceiveAudio:0, voiceActivityDetection:false, iceRestart:true}); did not throw exception.
+PASS pc.createOffer(unexpectedCallback, expectedCreateOfferFailed2); did not throw exception.
+PASS expectedCreateOfferFailed2 was called.
+PASS error.name is "OperationError"
+PASS error.toString() is "OperationError: TEST_ERROR"
+PASS pc.createOffer(unexpectedCallback, expectedCreateOfferFailed3, {}); did not throw exception.
+PASS expectedCreateOfferFailed3 was called.
+PASS error.name is "OperationError"
+PASS error.toString() is "OperationError: TEST_ERROR"
+PASS pc.createOffer(unexpectedCallback, expectedCreateOfferFailed4, {voiceActivityDetection:false}); did not throw exception.
+PASS expectedCreateOfferFailed4 was called.
+PASS error.name is "OperationError"
+PASS error.toString() is "OperationError: TEST_ERROR"
+PASS pc.createOffer(createOfferSucceeded2, unexpectedCallback, {iceRestart:true}); did not throw exception.
+PASS createOfferSucceeded2 was called.
+PASS pc.createOffer(unexpectedCallback, expectedCreateOfferFailed5, {offerToReceiveVideo:1, offerToReceiveAudio:0, voiceActivityDetection:false, iceRestart:true}); did not throw exception.
+PASS expectedCreateOfferFailed5 was called.
+PASS error.name is "OperationError"
+PASS error.toString() is "OperationError: TEST_ERROR"
+PASS pc.createOffer(unexpectedCallback, expectedCreateOfferFailed6, {offerToReceiveVideo:-1, offerToReceiveAudio:0}); did not throw exception.
+PASS expectedCreateOfferFailed6 called.
+PASS error.name is "OperationError"
+PASS error.toString() is "OperationError: TEST_ERROR"
+PASS pc.createOffer(unexpectedCallback, expectedCreateOfferFailed7, {offerToReceiveVideo:0, offerToReceiveAudio:-1}); did not throw exception.
+PASS expectedCreateOfferFailed7 called.
+PASS error.name is "OperationError"
+PASS error.toString() is "OperationError: TEST_ERROR"
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-createOffer.html b/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-createOffer.html
index ae0eb394..5ef08ee 100644
--- a/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-createOffer.html
+++ b/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-createOffer.html
@@ -13,54 +13,106 @@
 
 var pc = null;
 
-function dummy() {}
-
-function requestFailed2(error)
+function unexpectedCallback()
 {
-    testPassed('requestFailed was called.');
+    testFailed('unexpectedCallback was called')
+    finishJSTest();
+}
 
+function expectedCreateOfferFailed7(error)
+{
+    testPassed('expectedCreateOfferFailed7 called.');
     window.error = error;
     shouldBe('error.name', '"OperationError"');
     shouldBe('error.toString()', '"OperationError: TEST_ERROR"');
-
-    shouldNotThrow("pc.createOffer(dummy, dummy);");
-    shouldNotThrow("pc.createOffer(dummy, dummy, {});");
-    shouldNotThrow("pc.createOffer(dummy, dummy, {voiceActivityDetection:false});");
-    shouldNotThrow("pc.createOffer(dummy, dummy, {iceRestart:true});");
-    shouldNotThrow("pc.createOffer(dummy, dummy, {voiceActivityDetection:false, iceRestart:true});");
-
-    // Deprecated.
-    shouldThrow("pc.createOffer(dummy, dummy, {offerToReceiveVideo:-1, offerToReceiveAudio:0});");
-    shouldThrow("pc.createOffer(dummy, dummy, {offerToReceiveVideo:0, offerToReceiveAudio:-1});");
-    shouldNotThrow("pc.createOffer(dummy, dummy, {offerToReceiveVideo:1, offerToReceiveAudio:0, voiceActivityDetection:false, iceRestart:true});");
-
     finishJSTest();
 }
 
-function requestSucceeded2(sd)
+function expectedCreateOfferFailed6(error)
 {
-    testFailed('requestSucceeded was called.');
-    finishJSTest();
+    testPassed('expectedCreateOfferFailed6 called.');
+    window.error = error;
+    shouldBe('error.name', '"OperationError"');
+    shouldBe('error.toString()', '"OperationError: TEST_ERROR"');
+    shouldNotThrow("pc.createOffer(unexpectedCallback, expectedCreateOfferFailed7, {offerToReceiveVideo:0, offerToReceiveAudio:-1});");
 }
 
-function requestFailed1()
-{
-    testFailed('requestFailed was called.');
-    finishJSTest();
+function expectedCreateOfferFailed5(error) {
+    testPassed('expectedCreateOfferFailed5 was called.');
+    window.error = error;
+    shouldBe('error.name', '"OperationError"');
+    shouldBe('error.toString()', '"OperationError: TEST_ERROR"');
+    shouldNotThrow("pc.createOffer(unexpectedCallback, expectedCreateOfferFailed6, {offerToReceiveVideo:-1, offerToReceiveAudio:0});");
 }
 
-function requestSucceeded1(sd)
-{
-    testPassed('requestSucceeded was called.');
+function createOfferSucceeded2() {
+    testPassed('createOfferSucceeded2 was called.');
+    shouldNotThrow("pc.createOffer(unexpectedCallback, expectedCreateOfferFailed5, {offerToReceiveVideo:1, offerToReceiveAudio:0, voiceActivityDetection:false, iceRestart:true});");
+}
 
-    sessionDescription = sd;
+function expectedCreateOfferFailed4(error) {
+    testPassed('expectedCreateOfferFailed4 was called.');
+    window.error = error;
+    shouldBe('error.name', '"OperationError"');
+    shouldBe('error.toString()', '"OperationError: TEST_ERROR"');
+    shouldNotThrow("pc.createOffer(createOfferSucceeded2, unexpectedCallback, {iceRestart:true});");
+}
+
+function expectedCreateOfferFailed3(error) {
+    testPassed('expectedCreateOfferFailed3 was called.');
+    window.error = error;
+    shouldBe('error.name', '"OperationError"');
+    shouldBe('error.toString()', '"OperationError: TEST_ERROR"');
+    shouldNotThrow("pc.createOffer(unexpectedCallback, expectedCreateOfferFailed4, {voiceActivityDetection:false});");
+}
+
+function expectedCreateOfferFailed2(error) {
+    testPassed('expectedCreateOfferFailed2 was called.');
+    window.error = error;
+    shouldBe('error.name', '"OperationError"');
+    shouldBe('error.toString()', '"OperationError: TEST_ERROR"');
+    shouldNotThrow("pc.createOffer(unexpectedCallback, expectedCreateOfferFailed3, {});");
+}
+
+function expectedCreateOfferFailed1(error)
+{
+    testPassed('expectedCreateOfferFailed1 was called.');
+    window.error = error;
+    shouldBe('error.name', '"OperationError"');
+    shouldBe('error.toString()', '"OperationError: TEST_ERROR"');
+    shouldNotThrow("pc.createOffer(unexpectedCallback, expectedCreateOfferFailed2);");
+}
+
+function createOfferSucceeded1(sessionDescription)
+{
+    testPassed('createOfferSucceeded1 was called.');
+    window.sessionDescription = sessionDescription;
     shouldBe('sessionDescription.type', '"offer"');
-
-    pc.createOffer(requestSucceeded2, requestFailed2);
+    shouldNotThrow('pc.createOffer(unexpectedCallback, expectedCreateOfferFailed1);');
 }
 
+function testExecutionOrderClosedConnection()
+{
+    var localPeerConnection = new webkitRTCPeerConnection(null, null);
+    localPeerConnection.close();
+    var counter = 0;
+    window.events = [];
+    Promise.resolve().then(_ => window.events[counter++] = 1);
+    localPeerConnection.createOffer(unexpectedCallback, error => {
+        window.error = error;
+        shouldBe('error.name', '"InvalidStateError"');
+        shouldBe('error.toString()', '"InvalidStateError: The RTCPeerConnection\'s signalingState is \'closed\'."');
+        window.events[counter++] = 2;
+    });
+    Promise.resolve().then(_ => {
+        window.events[counter++] = 3;
+        shouldBe('events', '[1,2,3]');
+    });
+}
+
+shouldNotThrow('testExecutionOrderClosedConnection()');
 pc = new webkitRTCPeerConnection(null);
-pc.createOffer(requestSucceeded1, requestFailed1, {voiceActivityDetection:true, iceRestart:true});
+shouldNotThrow('pc.createOffer(createOfferSucceeded1, unexpectedCallback, {voiceActivityDetection:true, iceRestart:true});');
 
 window.jsTestIsAsync = true;
 window.successfullyParsed = true;
diff --git a/third_party/WebKit/LayoutTests/fragmentation/break-before-empty-child-block-expected.txt b/third_party/WebKit/LayoutTests/fragmentation/break-before-empty-child-block-expected.txt
new file mode 100644
index 0000000..e724bb5b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fragmentation/break-before-empty-child-block-expected.txt
@@ -0,0 +1,4 @@
+There should be two blue squares below.
+
+
+PASS
diff --git a/third_party/WebKit/LayoutTests/fragmentation/break-before-empty-child-block.html b/third_party/WebKit/LayoutTests/fragmentation/break-before-empty-child-block.html
new file mode 100644
index 0000000..8ea8f63
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fragmentation/break-before-empty-child-block.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<script src="../resources/check-layout.js"></script>
+<p>There should be two blue squares below.</p>
+<div id="multicol" style="columns:3; column-fill:auto; column-gap:0; position:relative; width:120px; height:100px; line-height:20px;">
+    <div style="height:60px;"></div>
+    <div data-offset-x="0" data-offset-y="60" data-expected-height="80" style="padding-top:30px; padding-bottom:20px; background:blue;">
+        <div data-offset-x="0" data-offset-y="90"></div>
+        <!-- This is where the soft break should occur, since it's a valid class A break point. -->
+        <div data-offset-x="40" data-offset-y="0">
+            <br>
+        </div>
+    </div>
+</div>
+<script>
+    checkLayout("#multicol");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fragmentation/class-c-break-after-clearance-expected.txt b/third_party/WebKit/LayoutTests/fragmentation/class-c-break-after-clearance-expected.txt
new file mode 100644
index 0000000..353b8240d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fragmentation/class-c-break-after-clearance-expected.txt
@@ -0,0 +1,6 @@
+There should be a blue square below.
+
+
+
+
+PASS
diff --git a/third_party/WebKit/LayoutTests/fragmentation/class-c-break-after-clearance.html b/third_party/WebKit/LayoutTests/fragmentation/class-c-break-after-clearance.html
new file mode 100644
index 0000000..9b9bfdb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fragmentation/class-c-break-after-clearance.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<script src="../resources/check-layout.js"></script>
+<p>There should be a blue square below.</p>
+<div id="multicol" style="position:relative; columns:3; column-fill:auto; column-gap:0; width:180px; height:100px; line-height:20px;">
+    <br>
+    <br>
+    <div style="float:left; width:50px; height:50px;"></div>
+    <div style="background:blue;" data-offset-x="0" data-offset-y="40" data-expected-height="80">
+        <div data-offset-x="60" data-offset-y="0" data-expected-height="20" style="clear:both; background:white;">
+            <br>
+        </div>
+    </div>
+</div>
+<script>
+    checkLayout("#multicol");
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-errors.html b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-errors.html
new file mode 100644
index 0000000..043ae35
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-errors.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="/serviceworker/resources/interfaces.js"></script>
+<script>
+function stubResolverUndefinedChecker(c) {
+    assert_equals(c, undefined);
+    this.done();
+}
+
+function stubRejectionChecker(reason) {
+    assert_unreached("get() should not reject, but did: " + reason.name);
+}
+
+promise_test(function (t) {
+    if (window.testRunner)
+        testRunner.addMockCredentialManagerError("pending");
+    return promise_rejects(t, "InvalidStateError", navigator.credentials.get({ password: true }));
+});
+promise_test(function (t) {
+    if (window.testRunner)
+        testRunner.addMockCredentialManagerError("disabled");
+    return promise_rejects(t, "InvalidStateError", navigator.credentials.get({ password: true }));
+});
+promise_test(function (t) {
+    if (window.testRunner)
+        testRunner.addMockCredentialManagerError("unknown");
+    return promise_rejects(t, "NotReadableError", navigator.credentials.get({ password: true }));
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/linkHeader/link-header-skips-invalid-headers-expected.txt b/third_party/WebKit/LayoutTests/http/tests/linkHeader/link-header-skips-invalid-headers-expected.txt
new file mode 100644
index 0000000..bf5e1594
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/linkHeader/link-header-skips-invalid-headers-expected.txt
@@ -0,0 +1,2 @@
+CONSOLE DEBUG: Preconnect triggered for http://wut.com.test/
+This test check if a Link header triggered a dns prefetch, after an invalid header.
diff --git a/third_party/WebKit/LayoutTests/http/tests/linkHeader/link-header-skips-invalid-headers.php b/third_party/WebKit/LayoutTests/http/tests/linkHeader/link-header-skips-invalid-headers.php
new file mode 100644
index 0000000..0780b860
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/linkHeader/link-header-skips-invalid-headers.php
@@ -0,0 +1,26 @@
+<?php
+header("Link: <http://foo.com/>; rel=preconnect; anchor=\"foo\"");
+header("Link: <   http://wut.com.test/>; rel=preconnect", false);
+?>
+<!DOCTYPE html>
+<script>
+    if (window.testRunner) {
+        testRunner.dumpAsText();
+        testRunner.waitUntilDone();
+    }
+    if (window.internals) {
+        internals.settings.setLogDnsPrefetchAndPreconnect(true);
+        internals.settings.setLinkHeaderEnabled(true);
+    }
+    if (!localStorage.getItem("reloaded")) {
+        localStorage.setItem("reloaded",  true);
+        location.reload();
+    } else {
+        localStorage.removeItem("reloaded");
+    }
+</script>
+This test check if a Link header triggered a dns prefetch, after an invalid header.
+<script>
+    if (window.testRunner)
+        testRunner.notifyDone();
+</script>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.title-09-expected.txt b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.title-09-expected.txt
deleted file mode 100644
index 1bd121d..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/documents/dom-tree-accessors/document.title-09-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-This is a testharness.js-based test.
-FAIL No title element in SVG document assert_equals: expected "title" but got "x-child"
-FAIL Title element in SVG document assert_equals: expected "foobar" but got "foo"
-FAIL Title element not child of SVG root assert_equals: expected "" but got "foo"
-FAIL Title element not in SVG namespace assert_equals: expected "" but got "foo"
-FAIL Root element not named "svg" assert_equals: expected "" but got "foo"
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/svg/dom/set-title-element-on-inner-svg-document.html b/third_party/WebKit/LayoutTests/svg/dom/set-title-element-on-inner-svg-document.html
new file mode 100644
index 0000000..e0ab577
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/svg/dom/set-title-element-on-inner-svg-document.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+test(function() {
+  var doc = document.implementation.createDocument("http://www.w3.org/2000/svg", "SVG", null);
+  var body = doc.createElementNS("http://www.w3.org/1999/xhtml", "body");
+  doc.documentElement.appendChild(body);
+  var svg = doc.createElementNS("http://www.w3.org/2000/svg", "svg");
+  body.appendChild(svg);
+  var g = doc.createElementNS("http://www.w3.org/2000/svg", "g");
+  svg.appendChild(g);
+  var title1 = doc.createElementNS("http://www.w3.org/1999/xhtml", "title");
+  title1.textContent = "title1";
+  g.appendChild(title1);
+  assert_equals(doc.title,'title1');
+  var title2 = doc.createElementNS("http://www.w3.org/1999/xhtml", "title");
+  title2.textContent = "title2";
+  svg.appendChild(title2);
+  assert_equals(doc.title,'title1');
+}, "Test for setting title element of inner svg document.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/svg/dom/set-title-html-namespace-on-SVG.html b/third_party/WebKit/LayoutTests/svg/dom/set-title-html-namespace-on-SVG.html
new file mode 100644
index 0000000..3e8bfbd7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/svg/dom/set-title-html-namespace-on-SVG.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+test(function() {
+  // svg != SVG
+  var doc = document.implementation.createDocument("http://www.w3.org/2000/svg", "SVG", null);
+  doc.documentElement.appendChild(doc.createElementNS("http://www.w3.org/1999/xhtml", "title"));
+  doc.documentElement.lastChild.textContent = "bar";
+  assert_equals(doc.title, "bar");
+
+  doc.documentElement.appendChild(doc.createElementNS("http://www.w3.org/1999/xhtml", "title"));
+  doc.documentElement.lastChild.textContent = "foo";
+  assert_equals(doc.title, "bar");
+}, "Test for setting title element in the html namespace on SVG element that is root.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/svg/dom/svg-document-set-title-mutations.html b/third_party/WebKit/LayoutTests/svg/dom/svg-document-set-title-mutations.html
new file mode 100644
index 0000000..6323c96e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/svg/dom/svg-document-set-title-mutations.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+test(function() {
+  var doc = document.implementation.createDocument("http://www.w3.org/2000/svg", "svg", null);
+  doc.title = 'old';
+  var titleElement = doc.querySelector('title');
+  var observer = new MutationObserver(function(mutations) {
+    assert_equals(mutations.length, 1);
+    assert_equals(mutations[0].type, 'childList');
+    assert_equals(mutations[0].addedNodes[0].data, 'new');
+    assert_equals(mutations[0].addedNodes.length, 1);
+    assert_equals(mutations[0].removedNodes[0].data, 'old');
+    assert_equals(mutations[0].removedNodes.length, 1);
+  });
+
+  observer.observe(titleElement, { childList: true });
+  doc.title = 'new';
+}, "Test for mutations to childList when setting title of svg document.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/canvas-toBlob/canvas-createImageBitmap-blob-in-workers.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/canvas-toBlob/canvas-createImageBitmap-blob-in-workers.html
index 228e9e4..c4156ea 100644
--- a/third_party/WebKit/LayoutTests/virtual/threaded/fast/canvas-toBlob/canvas-createImageBitmap-blob-in-workers.html
+++ b/third_party/WebKit/LayoutTests/virtual/threaded/fast/canvas-toBlob/canvas-createImageBitmap-blob-in-workers.html
@@ -64,13 +64,17 @@
 
 canvas1.toBlob(function(blob) {
     worker.postMessage(blob);
+    var setImgSrc = false;
     for (var i = 0; i < numOfBitmaps; i++) {
         createImageBitmap(blob).then(imageBitmap => {
             bitmapArray.push(imageBitmap);
+            if (i >= numOfBitmaps - 1 && setImgSrc == false) {
+                var url = URL.createObjectURL(blob);
+                newImg.src = url;
+                setImgSrc = true;
+            }
         });
     }
-    url = URL.createObjectURL(blob);
-    newImg.src = url;
 });
 
 </script>
diff --git a/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValueFactory.h b/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValueFactory.h
index 6bc4d233..a64b6e5 100644
--- a/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValueFactory.h
+++ b/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValueFactory.h
@@ -48,7 +48,7 @@
     }
 
     // SerializedScriptValueFactory::initialize() should be invoked when Blink is initialized,
-    // i.e. initializeWithoutV8() in WebKit.cpp.
+    // i.e. initialize() in WebKit.cpp.
     static void initialize(SerializedScriptValueFactory* newFactory)
     {
         ASSERT(!m_instance);
diff --git a/third_party/WebKit/Source/build/scripts/templates/StyleBuilderFunctions.cpp.tmpl b/third_party/WebKit/Source/build/scripts/templates/StyleBuilderFunctions.cpp.tmpl
index 6097cfc..61d5c25 100644
--- a/third_party/WebKit/Source/build/scripts/templates/StyleBuilderFunctions.cpp.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/StyleBuilderFunctions.cpp.tmpl
@@ -461,27 +461,15 @@
 {{declare_value_function(property_id)}}
 {
     Vector<GridTrackSize> trackSizes;
-    Vector<GridTrackSize> autoRepeatTrackSizes;
-    size_t autoRepeatInsertionPoint;
     NamedGridLinesMap namedGridLines;
     OrderedNamedGridLines orderedNamedGridLines;
-    NamedGridLinesMap autoRepeatNamedGridLines;
-    OrderedNamedGridLines autoRepeatOrderedNamedGridLines;
-    AutoRepeatType autoRepeatType;
-    StyleBuilderConverter::convertGridTrackList(*value, trackSizes, namedGridLines, orderedNamedGridLines, autoRepeatTrackSizes, autoRepeatNamedGridLines, autoRepeatOrderedNamedGridLines, autoRepeatInsertionPoint, autoRepeatType, state);
+    StyleBuilderConverter::convertGridTrackList(*value, trackSizes, namedGridLines, orderedNamedGridLines, state);
     const NamedGridAreaMap& namedGridAreas = state.style()->namedGridArea();
     if (!namedGridAreas.isEmpty())
         StyleBuilderConverter::createImplicitNamedGridLinesFromGridArea(namedGridAreas, namedGridLines, For{{type}}s);
     state.style()->setGridTemplate{{type}}s(trackSizes);
     state.style()->setNamedGrid{{type}}Lines(namedGridLines);
     state.style()->setOrderedNamedGrid{{type}}Lines(orderedNamedGridLines);
-    if (autoRepeatTrackSizes.size()) {
-        state.style()->setGridAutoRepeat{{type}}s(autoRepeatTrackSizes);
-        state.style()->setGridAutoRepeat{{type}}sInsertionPoint(autoRepeatInsertionPoint);
-        state.style()->setAutoRepeatNamedGrid{{type}}Lines(autoRepeatNamedGridLines);
-        state.style()->setAutoRepeatOrderedNamedGrid{{type}}Lines(autoRepeatOrderedNamedGridLines);
-        state.style()->setGridAutoRepeatType(autoRepeatType);
-    }
 }
 {% endmacro %}
 {{apply_grid_template('CSSPropertyGridTemplateColumns', 'Column')}}
diff --git a/third_party/WebKit/Source/core/core.gypi b/third_party/WebKit/Source/core/core.gypi
index 87d2d13..dc87173b 100644
--- a/third_party/WebKit/Source/core/core.gypi
+++ b/third_party/WebKit/Source/core/core.gypi
@@ -516,6 +516,7 @@
             'layout/api/LayoutTextControlItem.h',
             'layout/api/LayoutTextFragmentItem.h',
             'layout/api/LayoutTextItem.h',
+            'layout/api/LayoutViewItem.h',
             'layout/api/LineLayoutAPIShim.h',
             'layout/api/LineLayoutBR.h',
             'layout/api/LineLayoutBlockFlow.h',
@@ -1135,8 +1136,6 @@
             'css/CSSFunctionValue.h',
             'css/CSSGradientValue.cpp',
             'css/CSSGradientValue.h',
-            'css/CSSGridAutoRepeatValue.h',
-            'css/CSSGridAutoRepeatValue.cpp',
             'css/CSSGridLineNamesValue.cpp',
             'css/CSSGridLineNamesValue.h',
             'css/CSSGridTemplateAreasValue.cpp',
diff --git a/third_party/WebKit/Source/core/css/CSSGridAutoRepeatValue.cpp b/third_party/WebKit/Source/core/css/CSSGridAutoRepeatValue.cpp
deleted file mode 100644
index 238c6ed..0000000
--- a/third_party/WebKit/Source/core/css/CSSGridAutoRepeatValue.cpp
+++ /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.
-
-#include "core/css/CSSGridAutoRepeatValue.h"
-
-#include "wtf/text/StringBuilder.h"
-
-namespace blink {
-
-String CSSGridAutoRepeatValue::customCSSText() const
-{
-    StringBuilder result;
-    result.append("repeat(");
-    result.append(getValueName(autoRepeatID()));
-    result.append(", ");
-    result.append(CSSValueList::customCSSText());
-    result.append(")");
-    return result.toString();
-}
-
-} // namespace blink
diff --git a/third_party/WebKit/Source/core/css/CSSGridAutoRepeatValue.h b/third_party/WebKit/Source/core/css/CSSGridAutoRepeatValue.h
deleted file mode 100644
index 1b69f935..0000000
--- a/third_party/WebKit/Source/core/css/CSSGridAutoRepeatValue.h
+++ /dev/null
@@ -1,51 +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 CSSGridAutoRepeatValue_h
-#define CSSGridAutoRepeatValue_h
-
-#include "core/CSSValueKeywords.h"
-#include "core/css/CSSValueList.h"
-
-namespace blink {
-
-// CSSGridAutoRepeatValue stores the track sizes and line numbers when the auto-repeat
-// syntax is used
-//
-// Right now the auto-repeat syntax is as follows:
-// <auto-repeat>  = repeat( [ auto-fill | auto-fit ], <line-names>? <fixed-size> <line-names>? )
-//
-// meaning that only one fixed size track is allowed. It could be argued that a different
-// class storing two CSSGridLineNamesValue and one CSSValue (for the track size) fits
-// better but the CSSWG has left the door open to allow more than one track in the
-// future. That's why we're using a list, it's prepared for future changes and it also
-// allows us to keep the parsing algorithm almost intact.
-class CSSGridAutoRepeatValue : public CSSValueList {
-public:
-    static PassRefPtrWillBeRawPtr<CSSGridAutoRepeatValue> create(CSSValueID id)
-    {
-        return adoptRefWillBeNoop(new CSSGridAutoRepeatValue(id));
-    }
-
-    String customCSSText() const;
-    CSSValueID autoRepeatID() const { return m_autoRepeatID; }
-
-    DEFINE_INLINE_TRACE_AFTER_DISPATCH() { CSSValueList::traceAfterDispatch(visitor); }
-
-private:
-    CSSGridAutoRepeatValue(CSSValueID id)
-        : CSSValueList(GridAutoRepeatClass, SpaceSeparator)
-        , m_autoRepeatID(id)
-    {
-        ASSERT(id == CSSValueAutoFill || id == CSSValueAutoFit);
-    }
-
-    const CSSValueID m_autoRepeatID;
-};
-
-DEFINE_CSS_VALUE_TYPE_CASTS(CSSGridAutoRepeatValue, isGridAutoRepeatValue());
-
-} // namespace blink
-
-#endif // CSSGridAutoRepeatValue_h
diff --git a/third_party/WebKit/Source/core/css/CSSValue.cpp b/third_party/WebKit/Source/core/css/CSSValue.cpp
index 7481533..4f3dd601 100644
--- a/third_party/WebKit/Source/core/css/CSSValue.cpp
+++ b/third_party/WebKit/Source/core/css/CSSValue.cpp
@@ -39,7 +39,6 @@
 #include "core/css/CSSFontFeatureValue.h"
 #include "core/css/CSSFunctionValue.h"
 #include "core/css/CSSGradientValue.h"
-#include "core/css/CSSGridAutoRepeatValue.h"
 #include "core/css/CSSGridLineNamesValue.h"
 #include "core/css/CSSGridTemplateAreasValue.h"
 #include "core/css/CSSImageSetValue.h"
@@ -138,8 +137,6 @@
             return compareCSSValues<CSSInitialValue>(*this, other);
         case UnsetClass:
             return compareCSSValues<CSSUnsetValue>(*this, other);
-        case GridAutoRepeatClass:
-            return compareCSSValues<CSSGridAutoRepeatValue>(*this, other);
         case GridLineNamesClass:
             return compareCSSValues<CSSGridLineNamesValue>(*this, other);
         case GridTemplateAreasClass:
@@ -226,8 +223,6 @@
         return toCSSUnsetValue(this)->customCSSText();
     case InitialClass:
         return toCSSInitialValue(this)->customCSSText();
-    case GridAutoRepeatClass:
-        return toCSSGridAutoRepeatValue(this)->customCSSText();
     case GridLineNamesClass:
         return toCSSGridLineNamesValue(this)->customCSSText();
     case GridTemplateAreasClass:
@@ -331,9 +326,6 @@
     case UnsetClass:
         delete toCSSUnsetValue(this);
         return;
-    case GridAutoRepeatClass:
-        delete toCSSGridAutoRepeatValue(this);
-        return;
     case GridLineNamesClass:
         delete toCSSGridLineNamesValue(this);
         return;
@@ -455,9 +447,6 @@
     case UnsetClass:
         toCSSUnsetValue(this)->~CSSUnsetValue();
         return;
-    case GridAutoRepeatClass:
-        toCSSGridAutoRepeatValue(this)->~CSSGridAutoRepeatValue();
-        return;
     case GridLineNamesClass:
         toCSSGridLineNamesValue(this)->~CSSGridLineNamesValue();
         return;
@@ -579,9 +568,6 @@
     case UnsetClass:
         toCSSUnsetValue(this)->traceAfterDispatch(visitor);
         return;
-    case GridAutoRepeatClass:
-        toCSSGridAutoRepeatValue(this)->traceAfterDispatch(visitor);
-        return;
     case GridLineNamesClass:
         toCSSGridLineNamesValue(this)->traceAfterDispatch(visitor);
         return;
diff --git a/third_party/WebKit/Source/core/css/CSSValue.h b/third_party/WebKit/Source/core/css/CSSValue.h
index 33eb456f..8b52da1 100644
--- a/third_party/WebKit/Source/core/css/CSSValue.h
+++ b/third_party/WebKit/Source/core/css/CSSValue.h
@@ -108,7 +108,6 @@
     bool isGridLineNamesValue() const { return m_classType == GridLineNamesClass; }
     bool isCustomPropertyDeclaration() const { return m_classType == CustomPropertyDeclarationClass; }
     bool isVariableReferenceValue() const { return m_classType == VariableReferenceClass; }
-    bool isGridAutoRepeatValue() const { return m_classType == GridAutoRepeatClass; }
 
     bool hasFailedOrCanceledSubresources() const;
 
@@ -183,7 +182,6 @@
         FunctionClass,
         ImageSetClass,
         GridLineNamesClass,
-        GridAutoRepeatClass,
         // Do not append non-list class types here.
     };
 
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
index 82158100f..0ed1d884 100644
--- a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
+++ b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
@@ -566,15 +566,12 @@
 
 static PassRefPtrWillBeRawPtr<CSSValue> valueForGridTrackList(GridTrackSizingDirection direction, const LayoutObject* layoutObject, const ComputedStyle& style)
 {
-    bool isRowAxis = direction == ForColumns;
-    const Vector<GridTrackSize>& trackSizes = isRowAxis ? style.gridTemplateColumns() : style.gridTemplateRows();
-    const Vector<GridTrackSize>& autoRepeatTrackSizes = isRowAxis ? style.gridAutoRepeatColumns() : style.gridAutoRepeatRows();
-    const OrderedNamedGridLines& orderedNamedGridLines = isRowAxis ? style.orderedNamedGridColumnLines() : style.orderedNamedGridRowLines();
-
+    const Vector<GridTrackSize>& trackSizes = direction == ForColumns ? style.gridTemplateColumns() : style.gridTemplateRows();
+    const OrderedNamedGridLines& orderedNamedGridLines = direction == ForColumns ? style.orderedNamedGridColumnLines() : style.orderedNamedGridRowLines();
     bool isLayoutGrid = layoutObject && layoutObject->isLayoutGrid();
 
     // Handle the 'none' case.
-    bool trackListIsEmpty = trackSizes.isEmpty() && autoRepeatTrackSizes.isEmpty();
+    bool trackListIsEmpty = trackSizes.isEmpty();
     if (isLayoutGrid && trackListIsEmpty) {
         // For grids we should consider every listed track, whether implicitly or explicitly created. If we don't have
         // any explicit track and there are no children then there are no implicit tracks. We cannot simply check the
diff --git a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
index cadf7672..4ed490c 100644
--- a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
@@ -29,7 +29,6 @@
 #include "core/StylePropertyShorthand.h"
 #include "core/css/CSSCustomIdentValue.h"
 #include "core/css/CSSFunctionValue.h"
-#include "core/css/CSSGridAutoRepeatValue.h"
 #include "core/css/CSSGridLineNamesValue.h"
 #include "core/css/CSSPrimitiveValueMappings.h"
 #include "core/css/CSSValuePair.h"
@@ -774,28 +773,6 @@
     return true;
 }
 
-static bool allTracksAreFixedSized(CSSValueList& valueList)
-{
-    for (auto value : valueList) {
-        if (value->isGridLineNamesValue())
-            continue;
-        // The auto-repeat value holds a <fixed-size> = <fixed-breadth> | minmax( <fixed-breadth>, <track-breadth> )
-        if (value->isGridAutoRepeatValue()) {
-            if (!allTracksAreFixedSized(toCSSValueList(*value)))
-                return false;
-            continue;
-        }
-        ASSERT(value->isPrimitiveValue() || (value->isFunctionValue() && toCSSFunctionValue(*value).item(0)));
-        const CSSPrimitiveValue& primitiveValue = value->isPrimitiveValue()
-            ? toCSSPrimitiveValue(*value)
-            : toCSSPrimitiveValue(*toCSSFunctionValue(*value).item(0));
-        CSSValueID valueID = primitiveValue.getValueID();
-        if (valueID == CSSValueMinContent || valueID == CSSValueMaxContent || valueID == CSSValueAuto || primitiveValue.isFlex())
-            return false;
-    }
-    return true;
-}
-
 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridTrackList()
 {
     ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
@@ -842,8 +819,19 @@
 
     // <auto-repeat> requires definite minimum track sizes in order to compute the number of repetitions.
     // The above while loop detects those appearances after the <auto-repeat> but not the ones before.
-    if (seenAutoRepeat && !allTracksAreFixedSized(*values))
-        return nullptr;
+    if (seenAutoRepeat) {
+        for (auto value : *values) {
+            if (value->isGridLineNamesValue())
+                continue;
+            ASSERT(value->isPrimitiveValue() || (value->isFunctionValue() && toCSSFunctionValue(*value).item(0)));
+            const CSSPrimitiveValue& primitiveValue = value->isPrimitiveValue()
+                ? toCSSPrimitiveValue(*value)
+                : toCSSPrimitiveValue(*toCSSFunctionValue(*value).item(0));
+            CSSValueID valueID = primitiveValue.getValueID();
+            if (valueID == CSSValueMinContent || valueID == CSSValueMaxContent || valueID == CSSValueAuto || primitiveValue.isFlex())
+                return nullptr;
+        }
+    }
 
     return values;
 }
@@ -863,7 +851,7 @@
     // because it will be computed later, let's set it to 1.
     size_t repetitions = isAutoRepeat ? 1 : clampTo<size_t>(currentValue->fValue, 0, kGridMaxTracks);
 
-    RefPtrWillBeRawPtr<CSSValueList> repeatedValues = isAutoRepeat ? CSSGridAutoRepeatValue::create(currentValue->id) : CSSValueList::createSpaceSeparated();
+    RefPtrWillBeRawPtr<CSSValueList> repeatedValues = CSSValueList::createSpaceSeparated();
     arguments->next(); // Skip the repetition count.
     arguments->next(); // Skip the comma.
 
@@ -893,17 +881,13 @@
     if (!numberOfTracks)
         return false;
 
-    if (isAutoRepeat) {
-        list.append(repeatedValues.release());
-    } else {
-        // We clamp the number of repetitions to a multiple of the repeat() track list's size, while staying below the max
-        // grid size.
-        repetitions = std::min(repetitions, kGridMaxTracks / numberOfTracks);
+    // We clamp the number of repetitions to a multiple of the repeat() track list's size, while staying below the max
+    // grid size.
+    repetitions = std::min(repetitions, kGridMaxTracks / numberOfTracks);
 
-        for (size_t i = 0; i < repetitions; ++i) {
-            for (size_t j = 0; j < repeatedValues->length(); ++j)
-                list.append(repeatedValues->item(j));
-        }
+    for (size_t i = 0; i < repetitions; ++i) {
+        for (size_t j = 0; j < repeatedValues->length(); ++j)
+            list.append(repeatedValues->item(j));
     }
 
     // parseGridTrackSize iterated over the repeat arguments, move to the next value.
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp b/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp
index 8ee0430c..fd34261 100644
--- a/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp
@@ -31,7 +31,6 @@
 #include "core/css/CSSContentDistributionValue.h"
 #include "core/css/CSSFontFeatureValue.h"
 #include "core/css/CSSFunctionValue.h"
-#include "core/css/CSSGridAutoRepeatValue.h"
 #include "core/css/CSSGridLineNamesValue.h"
 #include "core/css/CSSPathValue.h"
 #include "core/css/CSSPrimitiveValueMappings.h"
@@ -452,20 +451,7 @@
     return GridTrackSize(minTrackBreadth, maxTrackBreadth);
 }
 
-static void convertGridLineNamesList(const CSSValue& value, size_t currentNamedGridLine, NamedGridLinesMap& namedGridLines, OrderedNamedGridLines& orderedNamedGridLines)
-{
-    ASSERT(value.isGridLineNamesValue());
-
-    for (auto& namedGridLineValue : toCSSValueList(value)) {
-        String namedGridLine = toCSSCustomIdentValue(*namedGridLineValue).value();
-        NamedGridLinesMap::AddResult result = namedGridLines.add(namedGridLine, Vector<size_t>());
-        result.storedValue->value.append(currentNamedGridLine);
-        OrderedNamedGridLines::AddResult orderedInsertionResult = orderedNamedGridLines.add(currentNamedGridLine, Vector<String>());
-        orderedInsertionResult.storedValue->value.append(namedGridLine);
-    }
-}
-
-void StyleBuilderConverter::convertGridTrackList(const CSSValue& value, Vector<GridTrackSize>& trackSizes, NamedGridLinesMap& namedGridLines, OrderedNamedGridLines& orderedNamedGridLines, Vector<GridTrackSize>& autoRepeatTrackSizes, NamedGridLinesMap& autoRepeatNamedGridLines, OrderedNamedGridLines& autoRepeatOrderedNamedGridLines, size_t& autoRepeatInsertionPoint, AutoRepeatType &autoRepeatType, StyleResolverState& state)
+void StyleBuilderConverter::convertGridTrackList(const CSSValue& value, Vector<GridTrackSize>& trackSizes, NamedGridLinesMap& namedGridLines, OrderedNamedGridLines& orderedNamedGridLines, StyleResolverState& state)
 {
     if (value.isPrimitiveValue()) {
         ASSERT(toCSSPrimitiveValue(value).getValueID() == CSSValueNone);
@@ -473,27 +459,15 @@
     }
 
     size_t currentNamedGridLine = 0;
-    for (auto currValue : toCSSValueList(value)) {
+    for (auto& currValue : toCSSValueList(value)) {
         if (currValue->isGridLineNamesValue()) {
-            convertGridLineNamesList(*currValue, currentNamedGridLine, namedGridLines, orderedNamedGridLines);
-            continue;
-        }
-
-        if (currValue->isGridAutoRepeatValue()) {
-            ASSERT(autoRepeatTrackSizes.isEmpty());
-            size_t autoRepeatIndex = 0;
-            CSSValueID autoRepeatID = toCSSGridAutoRepeatValue(currValue)->autoRepeatID();
-            ASSERT(autoRepeatID == CSSValueAutoFill || autoRepeatID == CSSValueAutoFit);
-            autoRepeatType = autoRepeatID == CSSValueAutoFill ? AutoFill : AutoFit;
-            for (auto autoRepeatValue : toCSSValueList(*currValue)) {
-                if (autoRepeatValue->isGridLineNamesValue()) {
-                    convertGridLineNamesList(*autoRepeatValue, autoRepeatIndex, autoRepeatNamedGridLines, autoRepeatOrderedNamedGridLines);
-                    continue;
-                }
-                ++autoRepeatIndex;
-                autoRepeatTrackSizes.append(convertGridTrackSize(state, *autoRepeatValue));
+            for (auto& namedGridLineValue : toCSSGridLineNamesValue(*currValue)) {
+                String namedGridLine = toCSSCustomIdentValue(*namedGridLineValue).value();
+                NamedGridLinesMap::AddResult result = namedGridLines.add(namedGridLine, Vector<size_t>());
+                result.storedValue->value.append(currentNamedGridLine);
+                OrderedNamedGridLines::AddResult orderedInsertionResult = orderedNamedGridLines.add(currentNamedGridLine, Vector<String>());
+                orderedInsertionResult.storedValue->value.append(namedGridLine);
             }
-            autoRepeatInsertionPoint = currentNamedGridLine++;
             continue;
         }
 
@@ -503,7 +477,7 @@
 
     // The parser should have rejected any <track-list> without any <track-size> as
     // this is not conformant to the syntax.
-    ASSERT(!trackSizes.isEmpty() || !autoRepeatTrackSizes.isEmpty());
+    ASSERT(!trackSizes.isEmpty());
 }
 
 void StyleBuilderConverter::convertOrderedNamedGridLinesMapToNamedGridLinesMap(const OrderedNamedGridLines& orderedNamedGridLines, NamedGridLinesMap& namedGridLines)
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.h b/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.h
index e328c8e..22fd808 100644
--- a/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.h
+++ b/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.h
@@ -96,9 +96,7 @@
     static float convertTextStrokeWidth(StyleResolverState&, const CSSValue&);
     static TransformOrigin convertTransformOrigin(StyleResolverState&, const CSSValue&);
 
-    static void convertGridTrackList(const CSSValue&, Vector<GridTrackSize>&, NamedGridLinesMap&, OrderedNamedGridLines&,
-        Vector<GridTrackSize>& autoRepeatTrackSizes, NamedGridLinesMap&, OrderedNamedGridLines&,
-        size_t& autoRepeatInsertionPoint, AutoRepeatType&, StyleResolverState&);
+    static void convertGridTrackList(const CSSValue&, Vector<GridTrackSize>&, NamedGridLinesMap&, OrderedNamedGridLines&, StyleResolverState&);
     static void createImplicitNamedGridLinesFromGridArea(const NamedGridAreaMap&, NamedGridLinesMap&, GridTrackSizingDirection);
     static void convertOrderedNamedGridLinesMapToNamedGridLinesMap(const OrderedNamedGridLines&, NamedGridLinesMap&);
 
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index 85872f1..f2a70fe 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -1289,33 +1289,51 @@
 void Document::setTitle(const String& title)
 {
     // Title set by JavaScript -- overrides any title elements.
-    if (!isHTMLDocument() && !isXHTMLDocument()) {
-        m_titleElement = nullptr;
-    } else if (!m_titleElement) {
-        HTMLElement* headElement = head();
-        if (!headElement)
-            return;
-        m_titleElement = HTMLTitleElement::create(*this);
-        headElement->appendChild(m_titleElement.get());
+    if (!m_titleElement) {
+        if (isHTMLDocument() || isXHTMLDocument()) {
+            HTMLElement* headElement = head();
+            if (!headElement)
+                return;
+            m_titleElement = HTMLTitleElement::create(*this);
+            headElement->appendChild(m_titleElement.get());
+        } else if (isSVGDocument()) {
+            Element* element = documentElement();
+            if (!isSVGSVGElement(element))
+                return;
+            m_titleElement = SVGTitleElement::create(*this);
+            element->insertBefore(m_titleElement.get(), element->firstChild());
+        }
+    } else {
+        if (!isHTMLDocument() && !isXHTMLDocument() && !isSVGDocument())
+            m_titleElement = nullptr;
     }
 
     if (isHTMLTitleElement(m_titleElement))
         toHTMLTitleElement(m_titleElement)->setText(title);
+    else if (isSVGTitleElement(m_titleElement))
+        toSVGTitleElement(m_titleElement)->setText(title);
     else
         updateTitle(title);
 }
 
 void Document::setTitleElement(Element* titleElement)
 {
-    // Only allow the first title element to change the title -- others have no effect.
-    if (m_titleElement && m_titleElement != titleElement) {
-        if (isHTMLDocument() || isXHTMLDocument()) {
-            m_titleElement = Traversal<HTMLTitleElement>::firstWithin(*this);
-        } else if (isSVGDocument()) {
-            m_titleElement = Traversal<SVGTitleElement>::firstWithin(*this);
-        }
+    // If the root element is an svg element in the SVG namespace, then let value be the child text content
+    // of the first title element in the SVG namespace that is a child of the root element.
+    if (isSVGSVGElement(documentElement())) {
+        m_titleElement = Traversal<SVGTitleElement>::firstChild(*documentElement());
     } else {
-        m_titleElement = titleElement;
+        if (m_titleElement && m_titleElement != titleElement)
+            m_titleElement = Traversal<HTMLTitleElement>::firstWithin(*this);
+        else
+            m_titleElement = titleElement;
+
+        // If the root element isn't an svg element in the SVG namespace and the title element is
+        // in the SVG namespace, it is ignored.
+        if (isSVGTitleElement(m_titleElement)) {
+            m_titleElement = nullptr;
+            return;
+        }
     }
 
     if (isHTMLTitleElement(m_titleElement))
diff --git a/third_party/WebKit/Source/core/frame/Deprecation.cpp b/third_party/WebKit/Source/core/frame/Deprecation.cpp
index 74f4e4d..57920fa 100644
--- a/third_party/WebKit/Source/core/frame/Deprecation.cpp
+++ b/third_party/WebKit/Source/core/frame/Deprecation.cpp
@@ -341,12 +341,6 @@
     case UseCounter::V8TouchEvent_InitTouchEvent_Method:
         return replacedWillBeRemoved("'TouchEvent.initTouchEvent'", "the TouchEvent constructor", 53, "5730982598541312");
 
-    case UseCounter::RTCPeerConnectionCreateAnswerLegacyNoFailureCallback:
-        return "RTCPeerConnection.CreateAnswer without a failure callback is deprecated. The failure callback will be a required parameter in M50. See https://www.chromestatus.com/feature/5663288008376320 for more details";
-
-    case UseCounter::RTCPeerConnectionCreateOfferLegacyNoFailureCallback:
-        return "RTCPeerConnection.CreateOffer without a failure callback is deprecated. The failure callback will be a required parameter in M50. See https://www.chromestatus.com/feature/5663288008376320 for more details";
-
     case UseCounter::ObjectObserve:
         return willBeRemoved("'Object.observe'", 50, "6147094632988672");
 
diff --git a/third_party/WebKit/Source/core/frame/FrameView.cpp b/third_party/WebKit/Source/core/frame/FrameView.cpp
index 901d7b8a..dcf1ef2 100644
--- a/third_party/WebKit/Source/core/frame/FrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/FrameView.cpp
@@ -66,6 +66,7 @@
 #include "core/layout/TracedLayoutObject.h"
 #include "core/layout/api/LayoutBoxModel.h"
 #include "core/layout/api/LayoutItem.h"
+#include "core/layout/api/LayoutViewItem.h"
 #include "core/layout/compositing/CompositedLayerMapping.h"
 #include "core/layout/compositing/CompositedSelection.h"
 #include "core/layout/compositing/PaintLayerCompositor.h"
@@ -521,13 +522,13 @@
 
 void FrameView::adjustViewSize()
 {
-    LayoutView* layoutView = this->layoutView();
-    if (!layoutView)
+    LayoutViewItem layoutViewItem = LayoutViewItem(this->layoutView());
+    if (layoutViewItem.isNull())
         return;
 
     ASSERT(m_frame->view() == this);
 
-    const IntRect rect = layoutView->documentRect();
+    const IntRect rect = layoutViewItem.documentRect();
     const IntSize& size = rect.size();
 
     const IntPoint origin(-rect.x(), -rect.y());
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.h b/third_party/WebKit/Source/core/frame/UseCounter.h
index 5628771..8e599bb6 100644
--- a/third_party/WebKit/Source/core/frame/UseCounter.h
+++ b/third_party/WebKit/Source/core/frame/UseCounter.h
@@ -870,12 +870,10 @@
         SVG1DOMText = 1040,
         RTCPeerConnectionConstructorConstraints = 1041,
         RTCPeerConnectionConstructorCompliant = 1042,
-        RTCPeerConnectionCreateOfferLegacyNoFailureCallback = 1043,
         RTCPeerConnectionCreateOfferLegacyFailureCallback = 1044,
         RTCPeerConnectionCreateOfferLegacyConstraints = 1045,
         RTCPeerConnectionCreateOfferLegacyOfferOptions = 1046,
         RTCPeerConnectionCreateOfferLegacyCompliant = 1047,
-        RTCPeerConnectionCreateAnswerLegacyNoFailureCallback = 1048,
         RTCPeerConnectionCreateAnswerLegacyFailureCallback = 1049,
         RTCPeerConnectionCreateAnswerLegacyConstraints = 1050,
         RTCPeerConnectionCreateAnswerLegacyCompliant = 1051,
diff --git a/third_party/WebKit/Source/core/html/HTMLTableCellElement.cpp b/third_party/WebKit/Source/core/html/HTMLTableCellElement.cpp
index 5eb5032..26553e6f 100644
--- a/third_party/WebKit/Source/core/html/HTMLTableCellElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLTableCellElement.cpp
@@ -177,20 +177,4 @@
     return fastGetAttribute(scopeAttr);
 }
 
-HTMLTableCellElement* HTMLTableCellElement::cellAbove() const
-{
-    LayoutObject* cellLayoutObject = layoutObject();
-    if (!cellLayoutObject)
-        return nullptr;
-    if (!cellLayoutObject->isTableCell())
-        return nullptr;
-
-    LayoutTableCell* tableCellLayoutObject = toLayoutTableCell(cellLayoutObject);
-    LayoutTableCell* cellAboveLayoutObject = tableCellLayoutObject->table()->cellAbove(tableCellLayoutObject);
-    if (!cellAboveLayoutObject)
-        return nullptr;
-
-    return toHTMLTableCellElement(cellAboveLayoutObject->node());
-}
-
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/html/HTMLTableCellElement.h b/third_party/WebKit/Source/core/html/HTMLTableCellElement.h
index 94fbdd9..58c47f0d 100644
--- a/third_party/WebKit/Source/core/html/HTMLTableCellElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLTableCellElement.h
@@ -50,8 +50,6 @@
     void setRowSpan(unsigned);
     const AtomicString& scope() const;
 
-    HTMLTableCellElement* cellAbove() const;
-
 private:
     HTMLTableCellElement(const QualifiedName&, Document&);
 
diff --git a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.cpp b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.cpp
index 65f1577..9c36630 100644
--- a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.cpp
+++ b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.cpp
@@ -223,18 +223,20 @@
     if (m_options.premultiplyAlpha() == "none")
         alphaOp = ImageDecoder::AlphaNotPremultiplied;
     OwnPtr<ImageDecoder> decoder(ImageDecoder::create(*sharedBuffer, alphaOp, ImageDecoder::GammaAndColorProfileApplied));
-    if (decoder)
+    RefPtr<SkImage> frame;
+    if (decoder) {
         decoder->setData(sharedBuffer.get(), true);
-    taskRunner->postTask(BLINK_FROM_HERE, threadSafeBind(&ImageBitmapFactories::ImageBitmapLoader::resolvePromiseOnOriginalThread, AllowCrossThreadAccess(this), decoder.release()));
+        frame = ImageBitmap::getSkImageFromDecoder(decoder.release());
+    }
+    taskRunner->postTask(BLINK_FROM_HERE, threadSafeBind(&ImageBitmapFactories::ImageBitmapLoader::resolvePromiseOnOriginalThread, AllowCrossThreadAccess(this), frame.release()));
 }
 
-void ImageBitmapFactories::ImageBitmapLoader::resolvePromiseOnOriginalThread(PassOwnPtr<ImageDecoder> decoder)
+void ImageBitmapFactories::ImageBitmapLoader::resolvePromiseOnOriginalThread(PassRefPtr<SkImage> frame)
 {
-    if (!decoder) {
+    if (!frame) {
         rejectPromise();
         return;
     }
-    RefPtr<SkImage> frame = ImageBitmap::getSkImageFromDecoder(decoder);
     ASSERT(!frame || (frame->width() && frame->height()));
     if (!frame) {
         rejectPromise();
diff --git a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.h b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.h
index a4922157..239626d 100644
--- a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.h
+++ b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.h
@@ -40,6 +40,7 @@
 #include "core/imagebitmap/ImageBitmapOptions.h"
 #include "platform/Supplementable.h"
 #include "platform/geometry/IntRect.h"
+#include "third_party/skia/include/core/SkImage.h"
 
 namespace blink {
 
@@ -94,7 +95,7 @@
 
         void scheduleAsyncImageBitmapDecoding();
         void decodeImageOnDecoderThread(WebTaskRunner*);
-        void resolvePromiseOnOriginalThread(PassOwnPtr<ImageDecoder>);
+        void resolvePromiseOnOriginalThread(PassRefPtr<SkImage>);
 
         // FileReaderLoaderClient
         void didStartLoading() override { }
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
index 33c18f7..3f8799e 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
@@ -743,16 +743,6 @@
         // box.  We can go ahead and pull the content right back up into our
         // box.
         collapseAnonymousBlockChild(this, toLayoutBlock(child));
-    } else if (((prev && prev->isAnonymousBlock()) || (next && next->isAnonymousBlock())) && canCollapseAnonymousBlockChild()) {
-        // It's possible that the removal has knocked us down to a single anonymous
-        // block with pseudo-style element siblings (e.g. first-letter). If these
-        // are floating, then we need to pull the content up also.
-        LayoutBlock* anonymousBlock = toLayoutBlock((prev && prev->isAnonymousBlock()) ? prev : next);
-        if ((anonymousBlock->previousSibling() || anonymousBlock->nextSibling())
-            && (!anonymousBlock->previousSibling() || (anonymousBlock->previousSibling()->style()->styleType() != PseudoIdNone && anonymousBlock->previousSibling()->isFloating() && !anonymousBlock->previousSibling()->previousSibling()))
-            && (!anonymousBlock->nextSibling() || (anonymousBlock->nextSibling()->style()->styleType() != PseudoIdNone && anonymousBlock->nextSibling()->isFloating() && !anonymousBlock->nextSibling()->nextSibling()))) {
-            collapseAnonymousBlockChild(this, anonymousBlock);
-        }
     }
 
     if (!firstChild()) {
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
index 150aa15..ce2fe9ff 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
@@ -69,6 +69,7 @@
 
 static_assert(sizeof(LayoutBlockFlow::MarginValues) == sizeof(LayoutUnit[4]), "MarginValues should stay small");
 
+// Caches all our current margin collapsing state.
 class MarginInfo {
     // Collapsing flags for whether we can collapse our margins with our children's margins.
     bool m_canCollapseWithChildren : 1;
@@ -154,6 +155,28 @@
     bool lastChildIsSelfCollapsingBlockWithClearance() const { return m_lastChildIsSelfCollapsingBlockWithClearance; }
 };
 
+// Some features, such as floats, margin collapsing and fragmentation, require some knowledge about
+// things that happened when laying out previous block child siblings. Only looking at the object
+// currently being laid out isn't always enough.
+class BlockChildrenLayoutInfo {
+public:
+    BlockChildrenLayoutInfo(LayoutBlockFlow* blockFlow, LayoutUnit beforeEdge, LayoutUnit afterEdge)
+        : m_marginInfo(blockFlow, beforeEdge, afterEdge)
+        , m_isAtFirstInFlowChild(true) { }
+
+    const MarginInfo& marginInfo() const { return m_marginInfo; }
+    MarginInfo& marginInfo() { return m_marginInfo; }
+    LayoutUnit& previousFloatLogicalBottom() { return m_previousFloatLogicalBottom; }
+
+    bool isAtFirstInFlowChild() const { return m_isAtFirstInFlowChild; }
+    void clearIsAtFirstInFlowChild() { m_isAtFirstInFlowChild = false; }
+
+private:
+    MarginInfo m_marginInfo;
+    LayoutUnit m_previousFloatLogicalBottom;
+    bool m_isAtFirstInFlowChild;
+};
+
 LayoutBlockFlow::LayoutBlockFlow(ContainerNode* node)
     : LayoutBlock(node)
 {
@@ -523,9 +546,10 @@
         child.markAllDescendantsWithFloatsForLayout();
 }
 
-bool LayoutBlockFlow::positionAndLayoutOnceIfNeeded(LayoutBox& child, LayoutUnit newLogicalTop, LayoutUnit& previousFloatLogicalBottom)
+bool LayoutBlockFlow::positionAndLayoutOnceIfNeeded(LayoutBox& child, LayoutUnit newLogicalTop, BlockChildrenLayoutInfo& layoutInfo)
 {
     if (child.isLayoutBlockFlow()) {
+        LayoutUnit& previousFloatLogicalBottom = layoutInfo.previousFloatLogicalBottom();
         LayoutBlockFlow& childBlockFlow = toLayoutBlockFlow(child);
         if (childBlockFlow.containsFloats() || containsFloats())
             markDescendantsWithFloatsForLayoutIfNeeded(childBlockFlow, newLogicalTop, previousFloatLogicalBottom);
@@ -556,8 +580,9 @@
     return true;
 }
 
-void LayoutBlockFlow::layoutBlockChild(LayoutBox& child, MarginInfo& marginInfo, LayoutUnit& previousFloatLogicalBottom)
+void LayoutBlockFlow::layoutBlockChild(LayoutBox& child, BlockChildrenLayoutInfo& layoutInfo)
 {
+    MarginInfo& marginInfo = layoutInfo.marginInfo();
     LayoutBlockFlow* childLayoutBlockFlow = child.isLayoutBlockFlow() ? toLayoutBlockFlow(&child) : nullptr;
     LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore();
     LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore();
@@ -577,7 +602,7 @@
     // Use the estimated block position and lay out the child if needed. After child layout, when
     // we have enough information to perform proper margin collapsing, float clearing and
     // pagination, we may have to reposition and lay out again if the estimate was wrong.
-    bool childNeededLayout = positionAndLayoutOnceIfNeeded(child, logicalTopEstimate, previousFloatLogicalBottom);
+    bool childNeededLayout = positionAndLayoutOnceIfNeeded(child, logicalTopEstimate, layoutInfo);
 
     // Cache if we are at the top of the block right now.
     bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock();
@@ -600,10 +625,10 @@
             // We got a new position due to clearance or margin collapsing. Before we attempt to
             // paginate (which may result in the position changing again), let's try again at the
             // new position (since a new position may result in a new logical height).
-            positionAndLayoutOnceIfNeeded(child, newLogicalTop, previousFloatLogicalBottom);
+            positionAndLayoutOnceIfNeeded(child, newLogicalTop, layoutInfo);
         }
 
-        newLogicalTop = adjustBlockChildForPagination(newLogicalTop, child, atBeforeSideOfBlock && logicalTopBeforeClear == newLogicalTop);
+        newLogicalTop = adjustBlockChildForPagination(newLogicalTop, child, layoutInfo, atBeforeSideOfBlock && logicalTopBeforeClear == newLogicalTop);
     }
 
     // Clearance, margin collapsing or pagination may have given us a new logical top, in which
@@ -612,7 +637,7 @@
     if (newLogicalTop != logicalTopEstimate
         || child.needsLayout()
         || (paginated && childLayoutBlockFlow && childLayoutBlockFlow->shouldBreakAtLineToAvoidWidow())) {
-        positionAndLayoutOnceIfNeeded(child, newLogicalTop, previousFloatLogicalBottom);
+        positionAndLayoutOnceIfNeeded(child, newLogicalTop, layoutInfo);
     }
 
     // If we previously encountered a self-collapsing sibling of this child that had clearance then
@@ -662,7 +687,7 @@
     }
 }
 
-LayoutUnit LayoutBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTop, LayoutBox& child, bool atBeforeSideOfBlock)
+LayoutUnit LayoutBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTop, LayoutBox& child, BlockChildrenLayoutInfo& layoutInfo, bool atBeforeSideOfBlock)
 {
     LayoutBlockFlow* childBlockFlow = child.isLayoutBlockFlow() ? toLayoutBlockFlow(&child) : 0;
 
@@ -696,9 +721,11 @@
     LayoutUnit newLogicalTop = logicalTop;
     if (LayoutUnit paginationStrut = logicalTopAfterPagination - logicalTop) {
         ASSERT(paginationStrut > 0);
-        // We are willing to propagate out to our parent block as long as we were at the top of the block prior
-        // to collapsing our margins, and as long as we didn't clear or move as a result of other pagination.
-        if (atBeforeSideOfBlock && logicalTopAfterForcedBreak == logicalTop && allowsPaginationStrut()) {
+        // If we're not at the first in-flow child, there's a class A break point before the child. If we *are* at the
+        // first in-flow child, but the child isn't flush with the content edge of its container, due to e.g. clearance,
+        // there's a class C break point before the child. Otherwise we should propagate the strut to our parent block,
+        // and attempt to break there instead. See https://drafts.csswg.org/css-break/#possible-breaks
+        if (layoutInfo.isAtFirstInFlowChild() && atBeforeSideOfBlock && logicalTopAfterForcedBreak == logicalTop && allowsPaginationStrut()) {
             // FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't
             // have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too
             // and pushes to the next page anyway, so not too concerned about it.
@@ -998,16 +1025,14 @@
 {
     dirtyForLayoutFromPercentageHeightDescendants(layoutScope);
 
-    // The margin struct caches all our current margin collapsing state. The compact struct caches state when we encounter compacts,
-    MarginInfo marginInfo(this, beforeEdge, afterEdge);
+    BlockChildrenLayoutInfo layoutInfo(this, beforeEdge, afterEdge);
+    MarginInfo& marginInfo = layoutInfo.marginInfo();
 
     // Fieldsets need to find their legend and position it inside the border of the object.
     // The legend then gets skipped during normal layout. The same is true for ruby text.
     // It doesn't get included in the normal layout process but is instead skipped.
     LayoutObject* childToExclude = layoutSpecialExcludedChild(relayoutChildren, layoutScope);
 
-    LayoutUnit previousFloatLogicalBottom;
-
     LayoutBox* next = firstChildBox();
     LayoutBox* lastNormalFlowChild = nullptr;
 
@@ -1046,7 +1071,8 @@
         }
 
         // Lay out the child.
-        layoutBlockChild(*child, marginInfo, previousFloatLogicalBottom);
+        layoutBlockChild(*child, layoutInfo);
+        layoutInfo.clearIsAtFirstInFlowChild();
         lastNormalFlowChild = child;
     }
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
index ddd7f7c..5a8780f 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
@@ -44,6 +44,7 @@
 
 namespace blink {
 
+class BlockChildrenLayoutInfo;
 class ClipScope;
 class MarginInfo;
 class LineBreaker;
@@ -319,8 +320,8 @@
     void layoutBlockChildren(bool relayoutChildren, SubtreeLayoutScope&, LayoutUnit beforeEdge, LayoutUnit afterEdge);
 
     void markDescendantsWithFloatsForLayoutIfNeeded(LayoutBlockFlow& child, LayoutUnit newLogicalTop, LayoutUnit previousFloatLogicalBottom);
-    bool positionAndLayoutOnceIfNeeded(LayoutBox& child, LayoutUnit newLogicalTop, LayoutUnit& previousFloatLogicalBottom);
-    void layoutBlockChild(LayoutBox& child, MarginInfo&, LayoutUnit& previousFloatLogicalBottom);
+    bool positionAndLayoutOnceIfNeeded(LayoutBox& child, LayoutUnit newLogicalTop, BlockChildrenLayoutInfo&);
+    void layoutBlockChild(LayoutBox& child, BlockChildrenLayoutInfo&);
     void adjustPositionedBlock(LayoutBox& child, const MarginInfo&);
     void adjustFloatingBlock(const MarginInfo&);
 
@@ -533,7 +534,7 @@
     LayoutUnit applyBeforeBreak(LayoutBox& child, LayoutUnit logicalOffset); // If the child has a before break, then return a new yPos that shifts to the top of the next page/column.
     LayoutUnit applyAfterBreak(LayoutBox& child, LayoutUnit logicalOffset, MarginInfo&); // If the child has an after break, then return a new offset that shifts to the top of the next page/column.
 
-    LayoutUnit adjustBlockChildForPagination(LayoutUnit logicalTop, LayoutBox& child, bool atBeforeSideOfBlock);
+    LayoutUnit adjustBlockChildForPagination(LayoutUnit logicalTop, LayoutBox& child, BlockChildrenLayoutInfo&, bool atBeforeSideOfBlock);
     // Computes a deltaOffset value that put a line at the top of the next page if it doesn't fit on the current page.
     void adjustLinePositionForPagination(RootInlineBox&, LayoutUnit& deltaOffset);
     // If the child is unsplittable and can't fit on the current page, return the top of the next page/column.
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutItem.h b/third_party/WebKit/Source/core/layout/api/LayoutItem.h
index c40a4496..b0fe64e 100644
--- a/third_party/WebKit/Source/core/layout/api/LayoutItem.h
+++ b/third_party/WebKit/Source/core/layout/api/LayoutItem.h
@@ -114,6 +114,11 @@
         return m_layoutObject->isSlider();
     }
 
+    bool isLayoutView() const
+    {
+        return m_layoutObject->isLayoutView();
+    }
+
     bool needsLayout()
     {
         return m_layoutObject->needsLayout();
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutViewItem.h b/third_party/WebKit/Source/core/layout/api/LayoutViewItem.h
new file mode 100644
index 0000000..3aa626a
--- /dev/null
+++ b/third_party/WebKit/Source/core/layout/api/LayoutViewItem.h
@@ -0,0 +1,43 @@
+
+// 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 LayoutViewItem_h
+#define LayoutViewItem_h
+
+#include "core/layout/LayoutView.h"
+#include "core/layout/api/LayoutBlockItem.h"
+
+namespace blink {
+
+class LayoutViewItem : public LayoutBlockItem {
+public:
+    explicit LayoutViewItem(LayoutView* layoutView)
+        : LayoutBlockItem(layoutView)
+    {
+    }
+
+    explicit LayoutViewItem(const LayoutBlockItem& item)
+        : LayoutBlockItem(item)
+    {
+        ASSERT(!item || item.isLayoutView());
+    }
+
+    explicit LayoutViewItem(std::nullptr_t) : LayoutBlockItem(nullptr) { }
+
+    LayoutViewItem() { }
+
+    IntRect documentRect() const
+    {
+        return toView()->documentRect();
+    }
+
+private:
+    LayoutView* toView() { return toLayoutView(layoutObject()); }
+    const LayoutView* toView() const { return toLayoutView(layoutObject()); }
+};
+
+} // namespace blink
+
+#endif // LayoutViewItem_h
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
index 21f219ea..0251cab8 100644
--- a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
@@ -264,7 +264,7 @@
         // When response is received with a provisional docloader, the resource haven't committed yet, and we cannot load resources, only preconnect.
         resourceLoadingPolicy = LinkLoader::DoNotLoadResources;
     }
-    LinkLoader::loadLinkFromHeader(response.httpHeaderField(HTTPNames::Link), response.url(), frame()->document(), NetworkHintsInterfaceImpl(), resourceLoadingPolicy);
+    LinkLoader::loadLinksFromHeader(response.httpHeaderField(HTTPNames::Link), response.url(), frame()->document(), NetworkHintsInterfaceImpl(), resourceLoadingPolicy);
 
     if (response.hasMajorCertificateErrors())
         MixedContentChecker::handleCertificateError(frame(), response, frameType, requestContext);
diff --git a/third_party/WebKit/Source/core/loader/FrameLoader.cpp b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
index aafb689..79fd956 100644
--- a/third_party/WebKit/Source/core/loader/FrameLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
@@ -451,7 +451,7 @@
         m_frame->document()->enforceSuborigin(m_documentLoader->suboriginName());
     if (m_documentLoader) {
         m_frame->document()->clientHintsPreferences().updateFrom(m_documentLoader->clientHintsPreferences());
-        LinkLoader::loadLinkFromHeader(m_documentLoader->response().httpHeaderField(HTTPNames::Link), m_documentLoader->response().url(),
+        LinkLoader::loadLinksFromHeader(m_documentLoader->response().httpHeaderField(HTTPNames::Link), m_documentLoader->response().url(),
             m_frame->document(), NetworkHintsInterfaceImpl(), LinkLoader::OnlyLoadResources);
     }
 
diff --git a/third_party/WebKit/Source/core/loader/LinkLoader.cpp b/third_party/WebKit/Source/core/loader/LinkLoader.cpp
index 4f4e00e..6222b9e 100644
--- a/third_party/WebKit/Source/core/loader/LinkLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/LinkLoader.cpp
@@ -287,14 +287,14 @@
     return document.loader()->startPreload(resourceType, linkRequest);
 }
 
-bool LinkLoader::loadLinkFromHeader(const String& headerValue, const KURL& baseURL, Document* document, const NetworkHintsInterface& networkHintsInterface, CanLoadResources canLoadResources)
+void LinkLoader::loadLinksFromHeader(const String& headerValue, const KURL& baseURL, Document* document, const NetworkHintsInterface& networkHintsInterface, CanLoadResources canLoadResources)
 {
     if (!document)
-        return false;
+        return;
     LinkHeaderSet headerSet(headerValue);
     for (auto& header : headerSet) {
         if (!header.valid() || header.url().isEmpty() || header.rel().isEmpty())
-            return false;
+            continue;
 
         LinkRelAttribute relAttribute(header.rel());
         KURL url(baseURL, header.url());
@@ -312,7 +312,6 @@
         }
         // TODO(yoav): Add more supported headers as needed.
     }
-    return true;
 }
 
 bool LinkLoader::loadLink(const LinkRelAttribute& relAttribute, CrossOriginAttributeValue crossOrigin, const String& type, const String& as, const KURL& href, Document& document, const NetworkHintsInterface& networkHintsInterface)
diff --git a/third_party/WebKit/Source/core/loader/LinkLoader.h b/third_party/WebKit/Source/core/loader/LinkLoader.h
index 7b1d9e3..ffe40b6 100644
--- a/third_party/WebKit/Source/core/loader/LinkLoader.h
+++ b/third_party/WebKit/Source/core/loader/LinkLoader.h
@@ -75,7 +75,7 @@
     void released();
     bool loadLink(const LinkRelAttribute&, CrossOriginAttributeValue, const String& type, const String& as, const KURL&, Document&, const NetworkHintsInterface&);
     enum CanLoadResources { OnlyLoadResources, DoNotLoadResources, LoadResourcesAndPreconnect };
-    static bool loadLinkFromHeader(const String& headerValue, const KURL& baseURL, Document*, const NetworkHintsInterface&, CanLoadResources);
+    static void loadLinksFromHeader(const String& headerValue, const KURL& baseURL, Document*, const NetworkHintsInterface&, CanLoadResources);
     static bool getResourceTypeFromAsAttribute(const String& as, Resource::Type&);
 
     DECLARE_TRACE();
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.h b/third_party/WebKit/Source/core/style/ComputedStyle.h
index 36a0222..75406228 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.h
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.h
@@ -816,19 +816,10 @@
 
     const Vector<GridTrackSize>& gridTemplateColumns() const { return rareNonInheritedData->m_grid->m_gridTemplateColumns; }
     const Vector<GridTrackSize>& gridTemplateRows() const { return rareNonInheritedData->m_grid->m_gridTemplateRows; }
-    const Vector<GridTrackSize>& gridAutoRepeatColumns() const { return rareNonInheritedData->m_grid->m_gridAutoRepeatColumns; }
-    const Vector<GridTrackSize>& gridAutoRepeatRows() const { return rareNonInheritedData->m_grid->m_gridAutoRepeatRows; }
-    size_t gridAutoRepeatColumnsInsertionPoint() const { return rareNonInheritedData->m_grid->m_autoRepeatColumnsInsertionPoint; }
-    size_t gridAutoRepeatRowsInsertionPoint() const { return rareNonInheritedData->m_grid->m_autoRepeatRowsInsertionPoint; }
-    AutoRepeatType gridAutoRepeatType() const  { return rareNonInheritedData->m_grid->m_autoRepeatType; }
     const NamedGridLinesMap& namedGridColumnLines() const { return rareNonInheritedData->m_grid->m_namedGridColumnLines; }
     const NamedGridLinesMap& namedGridRowLines() const { return rareNonInheritedData->m_grid->m_namedGridRowLines; }
     const OrderedNamedGridLines& orderedNamedGridColumnLines() const { return rareNonInheritedData->m_grid->m_orderedNamedGridColumnLines; }
     const OrderedNamedGridLines& orderedNamedGridRowLines() const { return rareNonInheritedData->m_grid->m_orderedNamedGridRowLines; }
-    const NamedGridLinesMap& autoRepeatNamedGridColumnLines() const { return rareNonInheritedData->m_grid->m_autoRepeatNamedGridColumnLines; }
-    const NamedGridLinesMap& autoRepeatNamedGridRowLines() const { return rareNonInheritedData->m_grid->m_autoRepeatNamedGridRowLines; }
-    const OrderedNamedGridLines& autoRepeatOrderedNamedGridColumnLines() const { return rareNonInheritedData->m_grid->m_autoRepeatOrderedNamedGridColumnLines; }
-    const OrderedNamedGridLines& autoRepeatOrderedNamedGridRowLines() const { return rareNonInheritedData->m_grid->m_autoRepeatOrderedNamedGridRowLines; }
     const NamedGridAreaMap& namedGridArea() const { return rareNonInheritedData->m_grid->m_namedGridArea; }
     size_t namedGridAreaRowCount() const { return rareNonInheritedData->m_grid->m_namedGridAreaRowCount; }
     size_t namedGridAreaColumnCount() const { return rareNonInheritedData->m_grid->m_namedGridAreaColumnCount; }
@@ -1377,19 +1368,10 @@
     void setGridAutoRows(const GridTrackSize& length) { SET_NESTED_VAR(rareNonInheritedData, m_grid, m_gridAutoRows, length); }
     void setGridTemplateColumns(const Vector<GridTrackSize>& lengths) { SET_NESTED_VAR(rareNonInheritedData, m_grid, m_gridTemplateColumns, lengths); }
     void setGridTemplateRows(const Vector<GridTrackSize>& lengths) { SET_NESTED_VAR(rareNonInheritedData, m_grid, m_gridTemplateRows, lengths); }
-    void setGridAutoRepeatColumns(const Vector<GridTrackSize>& trackSizes) { SET_NESTED_VAR(rareNonInheritedData, m_grid, m_gridAutoRepeatColumns, trackSizes); }
-    void setGridAutoRepeatRows(const Vector<GridTrackSize>& trackSizes) { SET_NESTED_VAR(rareNonInheritedData, m_grid, m_gridAutoRepeatRows, trackSizes); }
-    void setGridAutoRepeatColumnsInsertionPoint(const size_t insertionPoint) { SET_NESTED_VAR(rareNonInheritedData, m_grid, m_autoRepeatColumnsInsertionPoint, insertionPoint); }
-    void setGridAutoRepeatRowsInsertionPoint(const size_t insertionPoint) { SET_NESTED_VAR(rareNonInheritedData, m_grid, m_autoRepeatRowsInsertionPoint, insertionPoint); }
-    void setGridAutoRepeatType(const AutoRepeatType autoRepeatType) { SET_NESTED_VAR(rareNonInheritedData, m_grid, m_autoRepeatType, autoRepeatType); }
     void setNamedGridColumnLines(const NamedGridLinesMap& namedGridColumnLines) { SET_NESTED_VAR(rareNonInheritedData, m_grid, m_namedGridColumnLines, namedGridColumnLines); }
     void setNamedGridRowLines(const NamedGridLinesMap& namedGridRowLines) { SET_NESTED_VAR(rareNonInheritedData, m_grid, m_namedGridRowLines, namedGridRowLines); }
     void setOrderedNamedGridColumnLines(const OrderedNamedGridLines& orderedNamedGridColumnLines) { SET_NESTED_VAR(rareNonInheritedData, m_grid, m_orderedNamedGridColumnLines, orderedNamedGridColumnLines); }
     void setOrderedNamedGridRowLines(const OrderedNamedGridLines& orderedNamedGridRowLines) { SET_NESTED_VAR(rareNonInheritedData, m_grid, m_orderedNamedGridRowLines, orderedNamedGridRowLines); }
-    void setAutoRepeatNamedGridColumnLines(const NamedGridLinesMap& namedGridColumnLines) { SET_NESTED_VAR(rareNonInheritedData, m_grid, m_autoRepeatNamedGridColumnLines, namedGridColumnLines); }
-    void setAutoRepeatNamedGridRowLines(const NamedGridLinesMap& namedGridRowLines) { SET_NESTED_VAR(rareNonInheritedData, m_grid, m_autoRepeatNamedGridRowLines, namedGridRowLines); }
-    void setAutoRepeatOrderedNamedGridColumnLines(const OrderedNamedGridLines& orderedNamedGridColumnLines) { SET_NESTED_VAR(rareNonInheritedData, m_grid, m_autoRepeatOrderedNamedGridColumnLines, orderedNamedGridColumnLines); }
-    void setAutoRepeatOrderedNamedGridRowLines(const OrderedNamedGridLines& orderedNamedGridRowLines) { SET_NESTED_VAR(rareNonInheritedData, m_grid, m_autoRepeatOrderedNamedGridRowLines, orderedNamedGridRowLines); }
     void setNamedGridArea(const NamedGridAreaMap& namedGridArea) { SET_NESTED_VAR(rareNonInheritedData, m_grid, m_namedGridArea, namedGridArea); }
     void setNamedGridAreaRowCount(size_t rowCount) { SET_NESTED_VAR(rareNonInheritedData, m_grid, m_namedGridAreaRowCount, rowCount); }
     void setNamedGridAreaColumnCount(size_t columnCount) { SET_NESTED_VAR(rareNonInheritedData, m_grid, m_namedGridAreaColumnCount, columnCount); }
@@ -1812,9 +1794,6 @@
     // The initial value is 'none' for grid tracks.
     static Vector<GridTrackSize> initialGridTemplateColumns() { return Vector<GridTrackSize>(); }
     static Vector<GridTrackSize> initialGridTemplateRows() { return Vector<GridTrackSize>(); }
-    static Vector<GridTrackSize> initialGridAutoRepeatTracks() { return Vector<GridTrackSize>(); }
-    static size_t initialGridAutoRepeatInsertionPoint() { return 0; }
-    static AutoRepeatType initialGridAutoRepeatType() { return NoAutoRepeat; }
 
     static GridAutoFlow initialGridAutoFlow() { return AutoFlowRow; }
 
diff --git a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
index 6d9f77b..8e03c3d 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
+++ b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
@@ -605,12 +605,6 @@
     ScrollSnapTypeProximity
 };
 
-enum AutoRepeatType {
-    NoAutoRepeat,
-    AutoFill,
-    AutoFit
-};
-
 } // namespace blink
 
 #endif // ComputedStyleConstants_h
diff --git a/third_party/WebKit/Source/core/style/StyleGridData.cpp b/third_party/WebKit/Source/core/style/StyleGridData.cpp
index 20f1588..f780397 100644
--- a/third_party/WebKit/Source/core/style/StyleGridData.cpp
+++ b/third_party/WebKit/Source/core/style/StyleGridData.cpp
@@ -36,10 +36,6 @@
     , m_namedGridRowLines(ComputedStyle::initialNamedGridRowLines())
     , m_orderedNamedGridColumnLines(ComputedStyle::initialOrderedNamedGridColumnLines())
     , m_orderedNamedGridRowLines(ComputedStyle::initialOrderedNamedGridRowLines())
-    , m_autoRepeatNamedGridColumnLines(ComputedStyle::initialNamedGridColumnLines())
-    , m_autoRepeatNamedGridRowLines(ComputedStyle::initialNamedGridRowLines())
-    , m_autoRepeatOrderedNamedGridColumnLines(ComputedStyle::initialOrderedNamedGridColumnLines())
-    , m_autoRepeatOrderedNamedGridRowLines(ComputedStyle::initialOrderedNamedGridRowLines())
     , m_gridAutoFlow(ComputedStyle::initialGridAutoFlow())
     , m_gridAutoRows(ComputedStyle::initialGridAutoRows())
     , m_gridAutoColumns(ComputedStyle::initialGridAutoColumns())
@@ -48,11 +44,6 @@
     , m_namedGridAreaColumnCount(ComputedStyle::initialNamedGridAreaCount())
     , m_gridColumnGap(ComputedStyle::initialGridColumnGap())
     , m_gridRowGap(ComputedStyle::initialGridRowGap())
-    , m_gridAutoRepeatColumns(ComputedStyle::initialGridAutoRepeatTracks())
-    , m_gridAutoRepeatRows(ComputedStyle::initialGridAutoRepeatTracks())
-    , m_autoRepeatColumnsInsertionPoint(ComputedStyle::initialGridAutoRepeatInsertionPoint())
-    , m_autoRepeatRowsInsertionPoint(ComputedStyle::initialGridAutoRepeatInsertionPoint())
-    , m_autoRepeatType(ComputedStyle::initialGridAutoRepeatType())
 {
 }
 
@@ -64,10 +55,6 @@
     , m_namedGridRowLines(o.m_namedGridRowLines)
     , m_orderedNamedGridColumnLines(o.m_orderedNamedGridColumnLines)
     , m_orderedNamedGridRowLines(o.m_orderedNamedGridRowLines)
-    , m_autoRepeatNamedGridColumnLines(o.m_namedGridColumnLines)
-    , m_autoRepeatNamedGridRowLines(o.m_namedGridRowLines)
-    , m_autoRepeatOrderedNamedGridColumnLines(o.m_orderedNamedGridColumnLines)
-    , m_autoRepeatOrderedNamedGridRowLines(o.m_orderedNamedGridRowLines)
     , m_gridAutoFlow(o.m_gridAutoFlow)
     , m_gridAutoRows(o.m_gridAutoRows)
     , m_gridAutoColumns(o.m_gridAutoColumns)
@@ -76,11 +63,6 @@
     , m_namedGridAreaColumnCount(o.m_namedGridAreaColumnCount)
     , m_gridColumnGap(o.m_gridColumnGap)
     , m_gridRowGap(o.m_gridRowGap)
-    , m_gridAutoRepeatColumns(o.m_gridAutoRepeatColumns)
-    , m_gridAutoRepeatRows(o.m_gridAutoRepeatRows)
-    , m_autoRepeatColumnsInsertionPoint(o.m_autoRepeatColumnsInsertionPoint)
-    , m_autoRepeatRowsInsertionPoint(o.m_autoRepeatRowsInsertionPoint)
-    , m_autoRepeatType(o.m_autoRepeatType)
 {
 }
 
diff --git a/third_party/WebKit/Source/core/style/StyleGridData.h b/third_party/WebKit/Source/core/style/StyleGridData.h
index e47bddc..fa5fae1 100644
--- a/third_party/WebKit/Source/core/style/StyleGridData.h
+++ b/third_party/WebKit/Source/core/style/StyleGridData.h
@@ -50,14 +50,9 @@
         && m_gridAutoFlow == o.m_gridAutoFlow && m_gridAutoRows == o.m_gridAutoRows && m_gridAutoColumns == o.m_gridAutoColumns
         && m_namedGridColumnLines == o.m_namedGridColumnLines && m_namedGridRowLines == o.m_namedGridRowLines
         && m_orderedNamedGridColumnLines == o.m_orderedNamedGridColumnLines && m_orderedNamedGridRowLines == o.m_orderedNamedGridRowLines
-        && m_autoRepeatNamedGridColumnLines == o.m_autoRepeatNamedGridColumnLines && m_autoRepeatNamedGridRowLines == o.m_autoRepeatNamedGridRowLines
-        && m_autoRepeatOrderedNamedGridColumnLines == o.m_autoRepeatOrderedNamedGridColumnLines && m_autoRepeatOrderedNamedGridRowLines == o.m_autoRepeatOrderedNamedGridRowLines
         && m_namedGridArea == o.m_namedGridArea && m_namedGridArea == o.m_namedGridArea
         && m_namedGridAreaRowCount == o.m_namedGridAreaRowCount && m_namedGridAreaColumnCount == o.m_namedGridAreaColumnCount
-        && m_gridColumnGap == o.m_gridColumnGap && m_gridRowGap == o.m_gridRowGap
-        && m_gridAutoRepeatColumns == o.m_gridAutoRepeatColumns && m_gridAutoRepeatRows == o.m_gridAutoRepeatRows
-        && m_autoRepeatColumnsInsertionPoint == o.m_autoRepeatColumnsInsertionPoint && m_autoRepeatRowsInsertionPoint == o.m_autoRepeatRowsInsertionPoint
-        && m_autoRepeatType == o.m_autoRepeatType;
+        && m_gridColumnGap == o.m_gridColumnGap && m_gridRowGap == o.m_gridRowGap;
     }
 
     bool operator!=(const StyleGridData& o) const
@@ -76,11 +71,6 @@
     OrderedNamedGridLines m_orderedNamedGridColumnLines;
     OrderedNamedGridLines m_orderedNamedGridRowLines;
 
-    NamedGridLinesMap m_autoRepeatNamedGridColumnLines;
-    NamedGridLinesMap m_autoRepeatNamedGridRowLines;
-    OrderedNamedGridLines m_autoRepeatOrderedNamedGridColumnLines;
-    OrderedNamedGridLines m_autoRepeatOrderedNamedGridRowLines;
-
     unsigned m_gridAutoFlow : GridAutoFlowBits;
 
     GridTrackSize m_gridAutoRows;
@@ -95,13 +85,6 @@
     Length m_gridColumnGap;
     Length m_gridRowGap;
 
-    Vector<GridTrackSize> m_gridAutoRepeatColumns;
-    Vector<GridTrackSize> m_gridAutoRepeatRows;
-
-    size_t m_autoRepeatColumnsInsertionPoint;
-    size_t m_autoRepeatRowsInsertionPoint;
-
-    AutoRepeatType m_autoRepeatType;
 private:
     StyleGridData();
     StyleGridData(const StyleGridData&);
diff --git a/third_party/WebKit/Source/core/svg/SVGTitleElement.cpp b/third_party/WebKit/Source/core/svg/SVGTitleElement.cpp
index 062cdb53..ebe19d2 100644
--- a/third_party/WebKit/Source/core/svg/SVGTitleElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGTitleElement.cpp
@@ -21,12 +21,15 @@
 #include "core/svg/SVGTitleElement.h"
 
 #include "core/SVGNames.h"
+#include "core/dom/ChildListMutationScope.h"
 #include "core/dom/Document.h"
+#include "core/dom/Text.h"
 
 namespace blink {
 
 inline SVGTitleElement::SVGTitleElement(Document& document)
     : SVGElement(SVGNames::titleTag, document)
+    , m_ignoreTitleUpdatesWhenChildrenChange(false)
 {
 }
 
@@ -52,8 +55,23 @@
 void SVGTitleElement::childrenChanged(const ChildrenChange& change)
 {
     SVGElement::childrenChanged(change);
-    if (inDocument() && document().isSVGDocument())
+    if (inDocument() && document().isSVGDocument() && !m_ignoreTitleUpdatesWhenChildrenChange)
         document().setTitleElement(this);
 }
 
+void SVGTitleElement::setText(const String& value)
+{
+    RefPtrWillBeRawPtr<Node> protectFromMutationEvents(this);
+    ChildListMutationScope mutation(*this);
+
+    {
+        // Avoid calling Document::setTitleElement() during intermediate steps.
+        TemporaryChange<bool> inhibitTitleUpdateScope(m_ignoreTitleUpdatesWhenChildrenChange, !value.isEmpty());
+        removeChildren(OmitSubtreeModifiedEvent);
+    }
+
+    if (!value.isEmpty())
+        appendChild(document().createTextNode(value.impl()), IGNORE_EXCEPTION);
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/svg/SVGTitleElement.h b/third_party/WebKit/Source/core/svg/SVGTitleElement.h
index 31e9753..1adc590 100644
--- a/third_party/WebKit/Source/core/svg/SVGTitleElement.h
+++ b/third_party/WebKit/Source/core/svg/SVGTitleElement.h
@@ -30,6 +30,8 @@
 public:
     DECLARE_NODE_FACTORY(SVGTitleElement);
 
+    void setText(const String&);
+
 private:
     explicit SVGTitleElement(Document&);
 
@@ -38,6 +40,8 @@
     void childrenChanged(const ChildrenChange&) override;
 
     bool layoutObjectIsNeeded(const ComputedStyle&) override { return false; }
+
+    bool m_ignoreTitleUpdatesWhenChildrenChange;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp b/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp
index fb401607..3de1af13 100644
--- a/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp
+++ b/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp
@@ -286,16 +286,15 @@
         SkPaint paint;
         drawForContainer(patternPicture.context().canvas(), paint, containerSize, zoom, tile, srcRect, url);
     }
-    RefPtr<const SkPicture> tilePicture = patternPicture.endRecording();
+    // TODO(fmalita): convert SkPictureBuilder to return sk_sp<SkPicture>
+    sk_sp<SkPicture> tilePicture(const_cast<SkPicture*>(patternPicture.endRecording().leakRef()));
 
     SkMatrix patternTransform;
     patternTransform.setTranslate(phase.x() + spacedTile.x(), phase.y() + spacedTile.y());
-    RefPtr<SkShader> patternShader = adoptRef(SkShader::CreatePictureShader(
-        tilePicture.get(), SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode,
-        &patternTransform, nullptr));
 
     SkPaint paint;
-    paint.setShader(patternShader.get());
+    paint.setShader(SkShader::MakePictureShader(std::move(tilePicture),
+        SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &patternTransform, nullptr));
     paint.setXfermodeMode(compositeOp);
     paint.setColorFilter(context.colorFilter());
     context.drawRect(dstRect, paint);
diff --git a/third_party/WebKit/Source/devtools/front_end/ui_lazy/FlameChart.js b/third_party/WebKit/Source/devtools/front_end/ui_lazy/FlameChart.js
index 20b7e3db..e1adb37 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui_lazy/FlameChart.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui_lazy/FlameChart.js
@@ -1478,9 +1478,11 @@
                 var group = groups[i];
                 if (groupTop - group.style.padding > top + height)
                     break;
-                var firstGroup = group.style.nestingLevel > groupStack.peekLast().nestingLevel
-                if (!firstGroup)
+                var firstGroup = true;
+                while (groupStack.peekLast().nestingLevel >= group.style.nestingLevel) {
                     groupStack.pop();
+                    firstGroup = false;
+                }
                 var parentGroupVisible = groupStack.peekLast().visible;
                 var thisGroupVisible = parentGroupVisible && (!group.style.collapsible || group.expanded);
                 groupStack.push({nestingLevel: group.style.nestingLevel, visible: thisGroupVisible});
@@ -1698,9 +1700,11 @@
             while (groupIndex < groups.length - 1 && level === groups[groupIndex + 1].startLevel) {
                 ++groupIndex;
                 var style = groups[groupIndex].style;
-                var nextLevel = groupStack.peekLast().nestingLevel < style.nestingLevel;
-                if (!nextLevel)
+                var nextLevel = true;
+                while (groupStack.peekLast().nestingLevel >= style.nestingLevel) {
                     groupStack.pop();
+                    nextLevel = false;
+                }
                 var thisGroupIsVisible = style.collapsible ? groups[groupIndex].expanded : true;
                 var parentGroupIsVisible = groupStack.peekLast().visible;
                 visible = thisGroupIsVisible && parentGroupIsVisible;
diff --git a/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp
index 579c3a7..409f370a 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp
@@ -1255,7 +1255,7 @@
             break;
 
         // The descendants of a AXMenuList that are AXLayoutObjects are all
-        // presentational. (The real descendants are a AXMenuListPopup and
+        // presentational. (The real descendants are an AXMenuListPopup and
         // AXMenuListOptions, which are not AXLayoutObjects.)
         if (parent->isMenuList())
             break;
diff --git a/third_party/WebKit/Source/modules/credentialmanager/CredentialsContainer.cpp b/third_party/WebKit/Source/modules/credentialmanager/CredentialsContainer.cpp
index b5f8511..4980c2c2 100644
--- a/third_party/WebKit/Source/modules/credentialmanager/CredentialsContainer.cpp
+++ b/third_party/WebKit/Source/modules/credentialmanager/CredentialsContainer.cpp
@@ -33,9 +33,12 @@
     case WebCredentialManagerDisabledError:
         resolver->reject(DOMException::create(InvalidStateError, "The credential manager is disabled."));
         break;
+    case WebCredentialManagerPendingRequestError:
+        resolver->reject(DOMException::create(InvalidStateError, "A 'get()' request is pending."));
+        break;
     case WebCredentialManagerUnknownError:
     default:
-        resolver->reject(DOMException::create(NotReadableError, "An unknown error occured while talking to the credential manager."));
+        resolver->reject(DOMException::create(NotReadableError, "An unknown error occurred while talking to the credential manager."));
         break;
     }
 }
diff --git a/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.cpp b/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.cpp
index 7091872e..5d168bb 100644
--- a/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.cpp
+++ b/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.cpp
@@ -332,7 +332,7 @@
     return rtcConfiguration;
 }
 
-RTCOfferOptions* RTCPeerConnection::parseOfferOptions(const Dictionary& options, ExceptionState& exceptionState)
+RTCOfferOptions* RTCPeerConnection::parseOfferOptions(const Dictionary& options)
 {
     if (options.isUndefinedOrNull())
         return 0;
@@ -350,16 +350,10 @@
     bool voiceActivityDetection = true;
     bool iceRestart = false;
 
-    if (DictionaryHelper::get(options, "offerToReceiveVideo", offerToReceiveVideo) && offerToReceiveVideo < 0) {
-        exceptionState.throwTypeError("Invalid offerToReceiveVideo");
-        return 0;
-    }
-
-    if (DictionaryHelper::get(options, "offerToReceiveAudio", offerToReceiveAudio) && offerToReceiveAudio < 0) {
-        exceptionState.throwTypeError("Invalid offerToReceiveAudio");
-        return 0;
-    }
-
+    if (DictionaryHelper::get(options, "offerToReceiveVideo", offerToReceiveVideo) && offerToReceiveVideo < 0)
+        offerToReceiveVideo = 0;
+    if (DictionaryHelper::get(options, "offerToReceiveAudio", offerToReceiveAudio) && offerToReceiveAudio < 0)
+        offerToReceiveAudio = 0;
     DictionaryHelper::get(options, "voiceActivityDetection", voiceActivityDetection);
     DictionaryHelper::get(options, "iceRestart", iceRestart);
 
@@ -438,69 +432,64 @@
     ASSERT(m_closed || m_stopped);
 }
 
-void RTCPeerConnection::createOffer(ExecutionContext* context, RTCSessionDescriptionCallback* successCallback, RTCPeerConnectionErrorCallback* errorCallback, const Dictionary& rtcOfferOptions, ExceptionState& exceptionState)
+void RTCPeerConnection::createOffer(ExecutionContext* context, RTCSessionDescriptionCallback* successCallback, RTCPeerConnectionErrorCallback* errorCallback, const Dictionary& rtcOfferOptions)
 {
-    if (errorCallback)
-        UseCounter::count(context, UseCounter::RTCPeerConnectionCreateOfferLegacyFailureCallback);
-    else
-        Deprecation::countDeprecation(context, UseCounter::RTCPeerConnectionCreateOfferLegacyNoFailureCallback);
-
-    if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
-        return;
-
     ASSERT(successCallback);
-
-    RTCOfferOptions* offerOptions = parseOfferOptions(rtcOfferOptions, exceptionState);
-    if (exceptionState.hadException())
+    ASSERT(errorCallback);
+    UseCounter::count(context, UseCounter::RTCPeerConnectionCreateOfferLegacyFailureCallback);
+    if (callErrorCallbackIfSignalingStateClosed(m_signalingState, errorCallback))
         return;
 
+    RTCOfferOptions* offerOptions = parseOfferOptions(rtcOfferOptions);
     RTCSessionDescriptionRequest* request = RTCSessionDescriptionRequestImpl::create(getExecutionContext(), this, successCallback, errorCallback);
 
     if (offerOptions) {
         if (offerOptions->offerToReceiveAudio() != -1 || offerOptions->offerToReceiveVideo() != -1)
             UseCounter::count(context, UseCounter::RTCPeerConnectionCreateOfferLegacyOfferOptions);
-        else if (errorCallback)
+        else
             UseCounter::count(context, UseCounter::RTCPeerConnectionCreateOfferLegacyCompliant);
 
         m_peerHandler->createOffer(request, offerOptions);
     } else {
         MediaErrorState mediaErrorState;
         WebMediaConstraints constraints = MediaConstraintsImpl::create(context, rtcOfferOptions, mediaErrorState);
-        if (mediaErrorState.hadException()) {
-            mediaErrorState.raiseException(exceptionState);
+        // Report constraints parsing errors via the callback, but ignore unknown/unsupported constraints as they
+        // would be silently discarded by WebIDL.
+        if (mediaErrorState.canGenerateException()) {
+            String errorMsg = mediaErrorState.getErrorMessage();
+            asyncCallErrorCallback(errorCallback, DOMException::create(OperationError, errorMsg));
             return;
         }
 
         if (!constraints.isEmpty())
             UseCounter::count(context, UseCounter::RTCPeerConnectionCreateOfferLegacyConstraints);
-        else if (errorCallback)
+        else
             UseCounter::count(context, UseCounter::RTCPeerConnectionCreateOfferLegacyCompliant);
 
         m_peerHandler->createOffer(request, constraints);
     }
 }
 
-void RTCPeerConnection::createAnswer(ExecutionContext* context, RTCSessionDescriptionCallback* successCallback, RTCPeerConnectionErrorCallback* errorCallback, const Dictionary& mediaConstraints, ExceptionState& exceptionState)
+void RTCPeerConnection::createAnswer(ExecutionContext* context, RTCSessionDescriptionCallback* successCallback, RTCPeerConnectionErrorCallback* errorCallback, const Dictionary& mediaConstraints)
 {
-    if (errorCallback)
-        UseCounter::count(context, UseCounter::RTCPeerConnectionCreateAnswerLegacyFailureCallback);
-    else
-        Deprecation::countDeprecation(context, UseCounter::RTCPeerConnectionCreateAnswerLegacyNoFailureCallback);
-
+    ASSERT(successCallback);
+    ASSERT(errorCallback);
+    UseCounter::count(context, UseCounter::RTCPeerConnectionCreateAnswerLegacyFailureCallback);
     if (mediaConstraints.isObject())
         UseCounter::count(context, UseCounter::RTCPeerConnectionCreateAnswerLegacyConstraints);
-    else if (errorCallback)
+    else
         UseCounter::count(context, UseCounter::RTCPeerConnectionCreateAnswerLegacyCompliant);
 
-    if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
+    if (callErrorCallbackIfSignalingStateClosed(m_signalingState, errorCallback))
         return;
 
-    ASSERT(successCallback);
-
     MediaErrorState mediaErrorState;
     WebMediaConstraints constraints = MediaConstraintsImpl::create(context, mediaConstraints, mediaErrorState);
-    if (mediaErrorState.hadException()) {
-        mediaErrorState.raiseException(exceptionState);
+    // Report constraints parsing errors via the callback, but ignore unknown/unsupported constraints as they
+    // would be silently discarded by WebIDL.
+    if (mediaErrorState.canGenerateException()) {
+        String errorMsg = mediaErrorState.getErrorMessage();
+        asyncCallErrorCallback(errorCallback, DOMException::create(OperationError, errorMsg));
         return;
     }
 
diff --git a/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.h b/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.h
index 4e3e164..b76f639 100644
--- a/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.h
+++ b/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.h
@@ -71,8 +71,8 @@
     static RTCPeerConnection* create(ExecutionContext*, const Dictionary&, const Dictionary&, ExceptionState&);
     ~RTCPeerConnection() override;
 
-    void createOffer(ExecutionContext*, RTCSessionDescriptionCallback*, RTCPeerConnectionErrorCallback*, const Dictionary&, ExceptionState&);
-    void createAnswer(ExecutionContext*, RTCSessionDescriptionCallback*, RTCPeerConnectionErrorCallback*, const Dictionary&, ExceptionState&);
+    void createOffer(ExecutionContext*, RTCSessionDescriptionCallback*, RTCPeerConnectionErrorCallback*, const Dictionary&);
+    void createAnswer(ExecutionContext*, RTCSessionDescriptionCallback*, RTCPeerConnectionErrorCallback*, const Dictionary&);
 
     ScriptPromise setLocalDescription(ScriptState*, const RTCSessionDescriptionInit&);
     ScriptPromise setLocalDescription(ScriptState*, RTCSessionDescription*, VoidCallback*, RTCPeerConnectionErrorCallback*);
@@ -177,7 +177,7 @@
     RTCPeerConnection(ExecutionContext*, RTCConfiguration*, WebMediaConstraints, ExceptionState&);
 
     static RTCConfiguration* parseConfiguration(const Dictionary&, ExceptionState&);
-    static RTCOfferOptions* parseOfferOptions(const Dictionary&, ExceptionState&);
+    static RTCOfferOptions* parseOfferOptions(const Dictionary&);
 
     void scheduleDispatchEvent(PassRefPtrWillBeRawPtr<Event>);
     void scheduleDispatchEvent(PassRefPtrWillBeRawPtr<Event>, PassOwnPtr<BoolFunction>);
diff --git a/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.idl b/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.idl
index 8938088..7decebd 100644
--- a/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.idl
+++ b/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.idl
@@ -98,9 +98,9 @@
     // https://w3c.github.io/webrtc-pc/#legacy-interface-extensions
     // These methods return or will be changed to return Promise<void> because
     // having Promise-based versions requires that all overloads return Promises.
-    [CallWith=ExecutionContext, RaisesException] void createOffer(RTCSessionDescriptionCallback successCallback, RTCPeerConnectionErrorCallback failureCallback, optional Dictionary rtcOfferOptions);
+    [CallWith=ExecutionContext] void createOffer(RTCSessionDescriptionCallback successCallback, RTCPeerConnectionErrorCallback failureCallback, optional Dictionary rtcOfferOptions);
     // TODO(guidou): There should be no mediaConstraints argument.
-    [CallWith=ExecutionContext, RaisesException] void createAnswer(RTCSessionDescriptionCallback successCallback, RTCPeerConnectionErrorCallback failureCallback, optional Dictionary mediaConstraints);
+    [CallWith=ExecutionContext] void createAnswer(RTCSessionDescriptionCallback successCallback, RTCPeerConnectionErrorCallback failureCallback, optional Dictionary mediaConstraints);
     [CallWith=ScriptState] Promise<void> setLocalDescription(RTCSessionDescription description, VoidCallback successCallback, [Default=Undefined] optional RTCPeerConnectionErrorCallback failureCallback);
     // TODO(guidou): The failureCallback argument should be non-optional.
     [CallWith=ScriptState] Promise<void> setRemoteDescription(RTCSessionDescription description, VoidCallback successCallback, [Default=Undefined] optional RTCPeerConnectionErrorCallback failureCallback);
diff --git a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp
index f2e7257..976d753 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp
@@ -1524,7 +1524,7 @@
 
 void WebGL2RenderingContextBase::drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount)
 {
-    if (!validateDrawArrays("drawArraysInstanced", mode, first, count))
+    if (!validateDrawArrays("drawArraysInstanced"))
         return;
 
     clearIfComposited();
@@ -1534,7 +1534,7 @@
 
 void WebGL2RenderingContextBase::drawElementsInstanced(GLenum mode, GLsizei count, GLenum type, long long offset, GLsizei instanceCount)
 {
-    if (!validateDrawElements("drawElementsInstanced", mode, count, type, offset))
+    if (!validateDrawElements("drawElementsInstanced", type, offset))
         return;
 
     if (transformFeedbackActive() && !transformFeedbackPaused()) {
@@ -1549,7 +1549,7 @@
 
 void WebGL2RenderingContextBase::drawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, long long offset)
 {
-    if (!validateDrawElements("drawRangeElements", mode, count, type, offset))
+    if (!validateDrawElements("drawRangeElements", type, offset))
         return;
 
     if (transformFeedbackActive() && !transformFeedbackPaused()) {
@@ -2144,6 +2144,10 @@
 
 void WebGL2RenderingContextBase::deleteTransformFeedback(WebGLTransformFeedback* feedback)
 {
+    if (transformFeedbackActive()) {
+        synthesizeGLError(GL_INVALID_OPERATION, "deleteTransformFeedback", "transform feedback is active");
+        return;
+    }
     if (feedback == m_transformFeedbackBinding)
         m_transformFeedbackBinding = nullptr;
 
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
index 2c9e99d..daa0ac8 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
@@ -2109,7 +2109,7 @@
 
 void WebGLRenderingContextBase::drawArrays(GLenum mode, GLint first, GLsizei count)
 {
-    if (!validateDrawArrays("drawArrays", mode, first, count))
+    if (!validateDrawArrays("drawArrays"))
         return;
 
     clearIfComposited();
@@ -2119,7 +2119,7 @@
 
 void WebGLRenderingContextBase::drawElements(GLenum mode, GLsizei count, GLenum type, long long offset)
 {
-    if (!validateDrawElements("drawElements", mode, count, type, offset))
+    if (!validateDrawElements("drawElements", type, offset))
         return;
 
     if (transformFeedbackActive() && !transformFeedbackPaused()) {
@@ -2134,7 +2134,7 @@
 
 void WebGLRenderingContextBase::drawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count, GLsizei primcount)
 {
-    if (!validateDrawArrays("drawArraysInstancedANGLE", mode, first, count))
+    if (!validateDrawArrays("drawArraysInstancedANGLE"))
         return;
 
     clearIfComposited();
@@ -2144,7 +2144,7 @@
 
 void WebGLRenderingContextBase::drawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum type, long long offset, GLsizei primcount)
 {
-    if (!validateDrawElements("drawElementsInstancedANGLE", mode, count, type, offset))
+    if (!validateDrawElements("drawElementsInstancedANGLE", type, offset))
         return;
 
     clearIfComposited();
@@ -5853,7 +5853,7 @@
     return true;
 }
 
-bool WebGLRenderingContextBase::validateDrawArrays(const char* functionName, GLenum mode, GLint first, GLsizei count)
+bool WebGLRenderingContextBase::validateDrawArrays(const char* functionName)
 {
     if (isContextLost())
         return false;
@@ -5874,7 +5874,7 @@
     return true;
 }
 
-bool WebGLRenderingContextBase::validateDrawElements(const char* functionName, GLenum mode, GLsizei count, GLenum type, long long offset)
+bool WebGLRenderingContextBase::validateDrawElements(const char* functionName, GLenum type, long long offset)
 {
     if (isContextLost())
         return false;
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
index 0421b2aa..a240ffc 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
@@ -998,10 +998,10 @@
     bool validateImageBitmap(const char* functionName, ImageBitmap*, ExceptionState&);
 
     // Helper function to validate drawArrays(Instanced) calls
-    bool validateDrawArrays(const char* functionName, GLenum mode, GLint first, GLsizei count);
+    bool validateDrawArrays(const char* functionName);
 
     // Helper function to validate drawElements(Instanced) calls
-    bool validateDrawElements(const char* functionName, GLenum mode, GLsizei count, GLenum type, long long offset);
+    bool validateDrawElements(const char* functionName, GLenum type, long long offset);
 
     // Helper functions to bufferData() and bufferSubData().
     void bufferDataImpl(GLenum target, long long size, const void* data, GLenum usage);
diff --git a/third_party/WebKit/Source/platform/CrossThreadCopier.h b/third_party/WebKit/Source/platform/CrossThreadCopier.h
index 113eebf..acb12a5 100644
--- a/third_party/WebKit/Source/platform/CrossThreadCopier.h
+++ b/third_party/WebKit/Source/platform/CrossThreadCopier.h
@@ -42,6 +42,8 @@
 #include "wtf/ThreadSafeRefCounted.h"
 #include "wtf/TypeTraits.h"
 
+class SkRefCnt;
+
 namespace blink {
 
 class IntRect;
@@ -111,7 +113,10 @@
     std::is_arithmetic<T>::value || std::is_enum<T>::value,
     WTF::IsSubclassOfTemplate<typename WTF::RemoveTemplate<T, RefPtr>::Type, ThreadSafeRefCounted>::value
     || WTF::IsSubclassOfTemplate<typename std::remove_pointer<T>::type, ThreadSafeRefCounted>::value
-    || WTF::IsSubclassOfTemplate<typename WTF::RemoveTemplate<T, PassRefPtr>::Type, ThreadSafeRefCounted>::value,
+    || WTF::IsSubclassOfTemplate<typename WTF::RemoveTemplate<T, PassRefPtr>::Type, ThreadSafeRefCounted>::value
+    || std::is_base_of<SkRefCnt, typename WTF::RemoveTemplate<T, RefPtr>::Type>::value
+    || std::is_base_of<SkRefCnt, typename std::remove_pointer<T>::type>::value
+    || std::is_base_of<SkRefCnt, typename WTF::RemoveTemplate<T, PassRefPtr>::Type>::value,
     WTF::IsSubclassOfTemplate<typename std::remove_pointer<T>::type, GarbageCollected>::value> {
     STATIC_ONLY(CrossThreadCopier);
 };
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
index a91cfa6..52496f3d 100644
--- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
+++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
@@ -29,6 +29,7 @@
 AudioVideoTracks status=experimental
 BackgroundSync status=stable
 CacheIgnoreSearchOption status=experimental
+Canvas2dImageChromium status=experimental
 ClientHints status=stable
 ColumnFill status=stable
 CompositedSelectionUpdate
diff --git a/third_party/WebKit/Source/platform/blink_platform.gypi b/third_party/WebKit/Source/platform/blink_platform.gypi
index 3f0b043..d6b7077 100644
--- a/third_party/WebKit/Source/platform/blink_platform.gypi
+++ b/third_party/WebKit/Source/platform/blink_platform.gypi
@@ -1202,6 +1202,7 @@
       'text/DateTimeFormatTest.cpp',
       'text/LocaleToScriptMappingTest.cpp',
       'text/SegmentedStringTest.cpp',
+      'text/TextBreakIteratorTest.cpp',
       'text/UnicodeUtilitiesTest.cpp',
       'transforms/TransformOperationsTest.cpp',
       'transforms/TransformTestHelper.h',
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
index 06a002e..90ef507 100644
--- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
+++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
@@ -139,6 +139,10 @@
 Canvas2DLayerBridge::~Canvas2DLayerBridge()
 {
     ASSERT(m_destructionInProgress);
+#if USE_IOSURFACE_FOR_2D_CANVAS
+    clearCHROMIUMImageCache();
+#endif // USE_IOSURFACE_FOR_2D_CANVAS
+
     m_layer.clear();
     ASSERT(m_mailboxes.size() == 0);
 #ifndef NDEBUG
@@ -201,24 +205,126 @@
     return m_filterQuality == kNone_SkFilterQuality ? GL_NEAREST : GL_LINEAR;
 }
 
-Canvas2DLayerBridge::MailboxInfo& Canvas2DLayerBridge::createMailboxInfo()
+#if USE_IOSURFACE_FOR_2D_CANVAS
+bool Canvas2DLayerBridge::prepareIOSurfaceMailboxFromImage(SkImage* image, WebExternalTextureMailbox* outMailbox)
+{
+    // Need to flush skia's internal queue because texture is about to be accessed directly
+    GrContext* grContext = m_contextProvider->grContext();
+    grContext->flush();
+
+    ImageInfo imageInfo = createIOSurfaceBackedTexture();
+    if (imageInfo.empty())
+        return false;
+
+    GLuint imageTexture = skia::GrBackendObjectToGrGLTextureInfo(image->getTextureHandle(true))->fID;
+    context()->copySubTextureCHROMIUM(imageTexture, imageInfo.m_textureId, 0, 0, 0, 0, m_size.width(), m_size.height(), GL_FALSE, GL_FALSE, GL_FALSE);
+
+    MailboxInfo& info = m_mailboxes.first();
+    info.m_mailbox.textureTarget = GC3D_TEXTURE_RECTANGLE_ARB;
+    context()->genMailboxCHROMIUM(info.m_mailbox.name);
+    context()->produceTextureDirectCHROMIUM(imageInfo.m_textureId, info.m_mailbox.textureTarget, info.m_mailbox.name);
+    info.m_mailbox.allowOverlay = true;
+
+    const WGC3Duint64 fenceSync = context()->insertFenceSyncCHROMIUM();
+    context()->flush();
+    info.m_mailbox.validSyncToken = context()->genSyncTokenCHROMIUM(fenceSync, info.m_mailbox.syncToken);
+
+    info.m_imageInfo = imageInfo;
+    *outMailbox = info.m_mailbox;
+
+    context()->bindTexture(GC3D_TEXTURE_RECTANGLE_ARB, 0);
+
+    // Because we are changing the texture binding without going through skia,
+    // we must dirty the context.
+    grContext->resetContext(kTextureBinding_GrGLBackendState);
+
+    return true;
+}
+
+Canvas2DLayerBridge::ImageInfo Canvas2DLayerBridge::createIOSurfaceBackedTexture()
+{
+    if (!m_imageInfoCache.isEmpty()) {
+        Canvas2DLayerBridge::ImageInfo info = m_imageInfoCache.last();
+        m_imageInfoCache.removeLast();
+        return info;
+    }
+
+    WebGraphicsContext3D* webContext = context();
+    GLuint imageId = webContext->createGpuMemoryBufferImageCHROMIUM(m_size.width(), m_size.height(), GL_BGRA_EXT, GC3D_SCANOUT_CHROMIUM);
+    if (!imageId)
+        return Canvas2DLayerBridge::ImageInfo();
+
+    GLuint textureId= webContext->createTexture();
+    if (!textureId) {
+        webContext->destroyImageCHROMIUM(imageId);
+        return Canvas2DLayerBridge::ImageInfo();
+    }
+
+    GLenum target = GC3D_TEXTURE_RECTANGLE_ARB;
+    webContext->bindTexture(target, textureId);
+    webContext->texParameteri(target, GL_TEXTURE_MAG_FILTER, getGLFilter());
+    webContext->texParameteri(target, GL_TEXTURE_MIN_FILTER, getGLFilter());
+    webContext->texParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    webContext->texParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    webContext->bindTexImage2DCHROMIUM(target, imageId);
+
+    return Canvas2DLayerBridge::ImageInfo(imageId, textureId);
+}
+
+void Canvas2DLayerBridge::deleteCHROMIUMImage(ImageInfo info)
+{
+    WebGraphicsContext3D* webContext = context();
+    if (webContext->isContextLost())
+        return;
+
+    GLenum target = GC3D_TEXTURE_RECTANGLE_ARB;
+    webContext->bindTexture(target, info.m_textureId);
+    webContext->releaseTexImage2DCHROMIUM(target, info.m_imageId);
+    webContext->destroyImageCHROMIUM(info.m_imageId);
+    webContext->deleteTexture(info.m_textureId);
+    webContext->bindTexture(target, 0);
+
+    resetSkiaTextureBinding();
+}
+
+void Canvas2DLayerBridge::clearCHROMIUMImageCache()
+{
+    for (const auto& it : m_imageInfoCache) {
+        deleteCHROMIUMImage(it);
+    }
+    m_imageInfoCache.clear();
+}
+#endif // USE_IOSURFACE_FOR_2D_CANVAS
+
+void Canvas2DLayerBridge::createMailboxInfo()
 {
     MailboxInfo tmp;
     tmp.m_parentLayerBridge = this;
     m_mailboxes.prepend(tmp);
-    MailboxInfo& mailboxInfo = m_mailboxes.first();
-    return mailboxInfo;
 }
 
 bool Canvas2DLayerBridge::prepareMailboxFromImage(PassRefPtr<SkImage> image, WebExternalTextureMailbox* outMailbox)
 {
-    MailboxInfo& mailboxInfo = createMailboxInfo();
+    createMailboxInfo();
+    MailboxInfo& mailboxInfo = m_mailboxes.first();
     mailboxInfo.m_mailbox.nearestNeighbor = getGLFilter() == GL_NEAREST;
-    mailboxInfo.m_image = image;
 
     GrContext* grContext = m_contextProvider->grContext();
-    if (!grContext)
+    if (!grContext) {
+        mailboxInfo.m_image = image;
         return true; // for testing: skip gl stuff when using a mock graphics context.
+    }
+
+#if USE_IOSURFACE_FOR_2D_CANVAS
+    if (RuntimeEnabledFeatures::canvas2dImageChromiumEnabled()) {
+        if (prepareIOSurfaceMailboxFromImage(image.get(), outMailbox))
+            return true;
+        // Note: if IOSurface backed texture creation failed we fall back to the
+        // non-IOSurface path.
+    }
+#endif // USE_IOSURFACE_FOR_2D_CANVAS
+
+    mailboxInfo.m_image = image;
 
     if (RuntimeEnabledFeatures::forceDisable2dCanvasCopyOnWriteEnabled())
         m_surface->notifyContentWillChange(SkSurface::kRetain_ContentChangeMode);
@@ -271,6 +377,13 @@
     return true;
 }
 
+void Canvas2DLayerBridge::resetSkiaTextureBinding()
+{
+    GrContext* grContext = m_contextProvider->grContext();
+    if (grContext)
+        grContext->resetContext(kTextureBinding_GrGLBackendState);
+}
+
 static void hibernateWrapper(WeakPtr<Canvas2DLayerBridge> bridge, double /*idleDeadline*/)
 {
     if (bridge) {
@@ -334,8 +447,10 @@
     m_hibernationImage = adoptRef(tempHibernationSurface->newImageSnapshot());
     m_surface.clear(); // destroy the GPU-backed buffer
     m_layer->clearTexture();
+#if USE_IOSURFACE_FOR_2D_CANVAS
+    clearCHROMIUMImageCache();
+#endif // USE_IOSURFACE_FOR_2D_CANVAS
     m_logger->didStartHibernating();
-
 }
 
 void Canvas2DLayerBridge::reportSurfaceCreationFailure()
@@ -723,6 +838,9 @@
     if (!contextLost) {
         // Invalidate texture state in case the compositor altered it since the copy-on-write.
         if (releasedMailboxInfo->m_image) {
+#if USE_IOSURFACE_FOR_2D_CANVAS
+            ASSERT(releasedMailboxInfo->m_imageInfo.empty());
+#endif // USE_IOSURFACE_FOR_2D_CANVAS
             if (mailbox.validSyncToken) {
                 context()->waitSyncTokenCHROMIUM(mailbox.syncToken);
             }
@@ -735,6 +853,12 @@
                 }
             }
         }
+
+#if USE_IOSURFACE_FOR_2D_CANVAS
+        if (!releasedMailboxInfo->m_imageInfo.empty() && !lostResource) {
+            m_imageInfoCache.append(releasedMailboxInfo->m_imageInfo);
+        }
+#endif // USE_IOSURFACE_FOR_2D_CANVAS
     }
 
     RefPtr<Canvas2DLayerBridge> selfRef;
@@ -842,11 +966,27 @@
     skipQueuedDrawCommands();
 }
 
+#if USE_IOSURFACE_FOR_2D_CANVAS
+Canvas2DLayerBridge::ImageInfo::ImageInfo(GLuint imageId, GLuint textureId) : m_imageId(imageId), m_textureId(textureId)
+{
+    ASSERT(imageId);
+    ASSERT(textureId);
+}
+
+bool Canvas2DLayerBridge::ImageInfo::empty()
+{
+    return m_imageId == 0;
+}
+#endif // USE_IOSURFACE_FOR_2D_CANVAS
+
 Canvas2DLayerBridge::MailboxInfo::MailboxInfo(const MailboxInfo& other)
 {
     memcpy(&m_mailbox, &other.m_mailbox, sizeof(m_mailbox));
     m_image = other.m_image;
     m_parentLayerBridge = other.m_parentLayerBridge;
+#if USE_IOSURFACE_FOR_2D_CANVAS
+    m_imageInfo = other.m_imageInfo;
+#endif // USE_IOSURFACE_FOR_2D_CANVAS
 }
 
 void Canvas2DLayerBridge::Logger::reportHibernationEvent(HibernationEvent event)
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
index b14738c..df6f231 100644
--- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
+++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
@@ -40,6 +40,7 @@
 #include "wtf/PassOwnPtr.h"
 #include "wtf/RefCounted.h"
 #include "wtf/RefPtr.h"
+#include "wtf/Vector.h"
 #include "wtf/WeakPtr.h"
 
 class SkPictureRecorder;
@@ -57,8 +58,12 @@
 // Canvas hibernation is currently disabled on MacOS X due to a bug that causes content loss
 // TODO: Find a better fix for crbug.com/588434
 #define CANVAS2D_HIBERNATION_ENABLED 0
+
+// IOSurfaces are a primitive only present on OS X.
+#define USE_IOSURFACE_FOR_2D_CANVAS 1
 #else
 #define CANVAS2D_HIBERNATION_ENABLED 1
+#define USE_IOSURFACE_FOR_2D_CANVAS 0
 #endif
 
 class PLATFORM_EXPORT Canvas2DLayerBridge : public WebExternalTextureLayerClient, public WebThread::TaskObserver, public RefCounted<Canvas2DLayerBridge> {
@@ -134,12 +139,35 @@
     void setLoggerForTesting(PassOwnPtr<Logger>);
 
 private:
+#if USE_IOSURFACE_FOR_2D_CANVAS
+    // All information associated with a CHROMIUM image.
+    struct ImageInfo {
+        ImageInfo() {}
+        ImageInfo(GLuint imageId, GLuint textureId);
+
+        // Whether this structure holds references to a CHROMIUM image.
+        bool empty();
+
+        // The id of the CHROMIUM image.
+        GLuint m_imageId = 0;
+
+        // The id of the texture bound to the CHROMIUM image.
+        GLuint m_textureId = 0;
+    };
+#endif // USE_IOSURFACE_FOR_2D_CANVAS
+
     struct MailboxInfo {
         DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
         WebExternalTextureMailbox m_mailbox;
         RefPtr<SkImage> m_image;
         RefPtr<Canvas2DLayerBridge> m_parentLayerBridge;
 
+#if USE_IOSURFACE_FOR_2D_CANVAS
+        // If this mailbox wraps an IOSurface-backed texture, the ids of the
+        // CHROMIUM image and the texture.
+        ImageInfo m_imageInfo;
+#endif // USE_IOSURFACE_FOR_2D_CANVAS
+
         MailboxInfo(const MailboxInfo&);
         MailboxInfo() {}
     };
@@ -162,15 +190,36 @@
     // Returns the GL filter associated with |m_filterQuality|.
     GLenum getGLFilter();
 
-    // Prepends a new MailboxInfo object to |m_mailboxes|, and returns a
-    // reference. The reference is no longer valid after |m_mailboxes| is
-    // mutated.
-    MailboxInfo& createMailboxInfo();
+#if USE_IOSURFACE_FOR_2D_CANVAS
+    // Creates an IOSurface-backed texture. Copies |image| into the texture.
+    // Prepares a mailbox from the texture. The caller must have created a new
+    // MailboxInfo, and prepended it to |m_mailboxs|. Returns whether the
+    // mailbox was successfully prepared. |mailbox| is an out parameter only
+    // populated on success.
+    bool prepareIOSurfaceMailboxFromImage(SkImage*, WebExternalTextureMailbox*);
+
+    // Creates an IOSurface-backed texture. Returns an ImageInfo, which is empty
+    // on failure. The caller takes ownership of both the texture and the image.
+    ImageInfo createIOSurfaceBackedTexture();
+
+    // Releases all resources associated with a CHROMIUM image.
+    void deleteCHROMIUMImage(ImageInfo);
+
+    // Releases all resources in the CHROMIUM image cache.
+    void clearCHROMIUMImageCache();
+#endif // USE_IOSURFACE_FOR_2D_CANVAS
+
+    // Prepends a new MailboxInfo object to |m_mailboxes|.
+    void createMailboxInfo();
 
     // Returns whether the mailbox was successfully prepared from the SkImage.
     // The mailbox is an out parameter only populated on success.
     bool prepareMailboxFromImage(PassRefPtr<SkImage>, WebExternalTextureMailbox*);
 
+    // Resets Skia's texture bindings. This method should be called after
+    // changing texture bindings.
+    void resetSkiaTextureBinding();
+
     OwnPtr<SkPictureRecorder> m_recorder;
     RefPtr<SkSurface> m_surface;
     RefPtr<SkImage> m_hibernationImage;
@@ -208,8 +257,15 @@
     GLenum m_lastFilter;
     AccelerationMode m_accelerationMode;
     OpacityMode m_opacityMode;
-    IntSize m_size;
+    const IntSize m_size;
     int m_recordingPixelCount;
+
+#if USE_IOSURFACE_FOR_2D_CANVAS
+    // Each element in this vector represents an IOSurface backed texture that
+    // is ready to be reused.
+    // Elements in this vector can safely be purged in low memory conditions.
+    Vector<ImageInfo> m_imageInfoCache;
+#endif // USE_IOSURFACE_FOR_2D_CANVAS
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/Gradient.cpp b/third_party/WebKit/Source/platform/graphics/Gradient.cpp
index 9736e023..e59ebf7 100644
--- a/third_party/WebKit/Source/platform/graphics/Gradient.cpp
+++ b/third_party/WebKit/Source/platform/graphics/Gradient.cpp
@@ -84,7 +84,7 @@
     }
 
     m_stops.append(stop);
-    m_gradient.clear();
+    m_gradient.reset();
 }
 
 void Gradient::sortStopsIfNecessary()
@@ -117,7 +117,7 @@
         return;
 
     m_drawInPMColorSpace = drawInPMColorSpace;
-    m_gradient.clear();
+    m_gradient.reset();
 }
 
 void Gradient::setGradientSpaceTransform(const AffineTransform& gradientSpaceTransformation)
@@ -126,7 +126,7 @@
         return;
 
     m_gradientSpaceTransformation = gradientSpaceTransformation;
-    m_gradient.clear();
+    m_gradient.reset();
 }
 
 // Determine the total number of stops needed, including pseudo-stops at the
@@ -189,10 +189,10 @@
     }
 }
 
-SkShader* Gradient::shader()
+sk_sp<SkShader> Gradient::shader()
 {
     if (m_gradient)
-        return m_gradient.get();
+        return m_gradient;
 
     sortStopsIfNecessary();
     ASSERT(m_stopsSorted);
@@ -233,25 +233,25 @@
         // Since the two-point radial gradient is slower than the plain radial,
         // only use it if we have to.
         if (m_p0 == m_p1 && m_r0 <= 0.0f) {
-            m_gradient = adoptRef(SkGradientShader::CreateRadial(m_p1.data(), m_r1, colors.data(), pos.data(), static_cast<int>(countUsed), tile, shouldDrawInPMColorSpace, &localMatrix));
+            m_gradient = SkGradientShader::MakeRadial(m_p1.data(), m_r1, colors.data(), pos.data(), static_cast<int>(countUsed), tile, shouldDrawInPMColorSpace, &localMatrix);
         } else {
             // The radii we give to Skia must be positive. If we're given a
             // negative radius, ask for zero instead.
             SkScalar radius0 = m_r0 >= 0.0f ? WebCoreFloatToSkScalar(m_r0) : 0;
             SkScalar radius1 = m_r1 >= 0.0f ? WebCoreFloatToSkScalar(m_r1) : 0;
-            m_gradient = adoptRef(SkGradientShader::CreateTwoPointConical(m_p0.data(), radius0, m_p1.data(), radius1, colors.data(), pos.data(), static_cast<int>(countUsed), tile, shouldDrawInPMColorSpace, &localMatrix));
+            m_gradient = SkGradientShader::MakeTwoPointConical(m_p0.data(), radius0, m_p1.data(), radius1, colors.data(), pos.data(), static_cast<int>(countUsed), tile, shouldDrawInPMColorSpace, &localMatrix);
         }
     } else {
         SkPoint pts[2] = { m_p0.data(), m_p1.data() };
         SkMatrix localMatrix = affineTransformToSkMatrix(m_gradientSpaceTransformation);
-        m_gradient = adoptRef(SkGradientShader::CreateLinear(pts, colors.data(), pos.data(), static_cast<int>(countUsed), tile, shouldDrawInPMColorSpace, &localMatrix));
+        m_gradient = SkGradientShader::MakeLinear(pts, colors.data(), pos.data(), static_cast<int>(countUsed), tile, shouldDrawInPMColorSpace, &localMatrix);
     }
 
     if (!m_gradient) {
         // use last color, since our "geometry" was degenerate (e.g. radius==0)
-        m_gradient = adoptRef(SkShader::CreateColorShader(colors[countUsed - 1]));
+        m_gradient = SkShader::MakeColorShader(colors[countUsed - 1]);
     }
-    return m_gradient.get();
+    return m_gradient;
 }
 
 void Gradient::applyToPaint(SkPaint& paint)
diff --git a/third_party/WebKit/Source/platform/graphics/Gradient.h b/third_party/WebKit/Source/platform/graphics/Gradient.h
index 49e0f740..0a43ecb 100644
--- a/third_party/WebKit/Source/platform/graphics/Gradient.h
+++ b/third_party/WebKit/Source/platform/graphics/Gradient.h
@@ -34,10 +34,10 @@
 #include "platform/graphics/Color.h"
 #include "platform/graphics/GraphicsTypes.h"
 #include "platform/transforms/AffineTransform.h"
+#include "third_party/skia/include/core/SkRefCnt.h"
 #include "wtf/Noncopyable.h"
 #include "wtf/PassRefPtr.h"
 #include "wtf/RefCounted.h"
-#include "wtf/RefPtr.h"
 #include "wtf/Vector.h"
 
 class SkPaint;
@@ -126,7 +126,7 @@
     Gradient(const FloatPoint& p0, const FloatPoint& p1);
     Gradient(const FloatPoint& p0, float r0, const FloatPoint& p1, float r1, float aspectRatio);
 
-    SkShader* shader();
+    sk_sp<SkShader> shader();
     void destroyShader();
 
     void sortStopsIfNecessary();
@@ -143,7 +143,7 @@
     GradientSpreadMethod m_spreadMethod;
     AffineTransform m_gradientSpaceTransformation;
 
-    RefPtr<SkShader> m_gradient;
+    sk_sp<SkShader> m_gradient;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp
index 55a6b12e..7826b23 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp
@@ -635,11 +635,10 @@
 
     SkMatrix localMatrix;
     localMatrix.setTranslate(originX, originY);
-    RefPtr<SkShader> shader = adoptRef(SkShader::CreateBitmapShader(
-        *misspellBitmap[index], SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix));
 
     SkPaint paint;
-    paint.setShader(shader.get());
+    paint.setShader(SkShader::MakeBitmapShader(*misspellBitmap[index],
+        SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix));
 
     SkRect rect;
     rect.set(originX, originY, originX + WebCoreFloatToSkScalar(width) * deviceScaleFactor, originY + SkIntToScalar(misspellBitmap[index]->height()));
diff --git a/third_party/WebKit/Source/platform/graphics/Image.cpp b/third_party/WebKit/Source/platform/graphics/Image.cpp
index 36e0b9d..7d4ae14 100644
--- a/third_party/WebKit/Source/platform/graphics/Image.cpp
+++ b/third_party/WebKit/Source/platform/graphics/Image.cpp
@@ -185,11 +185,11 @@
 
 namespace {
 
-PassRefPtr<SkShader> createPatternShader(const SkImage* image, const SkMatrix& shaderMatrix,
+sk_sp<SkShader> createPatternShader(const SkImage* image, const SkMatrix& shaderMatrix,
     const SkPaint& paint, const FloatSize& spacing)
 {
     if (spacing.isZero())
-        return adoptRef(image->newShader(SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &shaderMatrix));
+        return image->makeShader(SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &shaderMatrix);
 
     // Arbitrary tiling is currently only supported for SkPictureShader - so we use it instead
     // of a plain bitmap shader to implement spacing.
@@ -200,10 +200,10 @@
     SkPictureRecorder recorder;
     SkCanvas* canvas = recorder.beginRecording(tileRect);
     canvas->drawImage(image, 0, 0, &paint);
-    RefPtr<const SkPicture> picture = adoptRef(recorder.endRecordingAsPicture());
+    sk_sp<SkPicture> picture(recorder.endRecordingAsPicture());
 
-    return adoptRef(SkShader::CreatePictureShader(
-        picture.get(), SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &shaderMatrix, nullptr));
+    return SkShader::MakePictureShader(
+        std::move(picture), SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &shaderMatrix, nullptr);
 }
 
 } // anonymous namespace
@@ -249,9 +249,8 @@
         paint.setXfermodeMode(compositeOp);
         paint.setFilterQuality(context.computeFilterQuality(this, destRect, normSrcRect));
         paint.setAntiAlias(context.shouldAntialias());
-        RefPtr<SkShader> shader = createPatternShader(image.get(), localMatrix, paint,
-            FloatSize(repeatSpacing.width() / scale.width(), repeatSpacing.height() / scale.height()));
-        paint.setShader(shader.get());
+        paint.setShader(createPatternShader(image.get(), localMatrix, paint,
+            FloatSize(repeatSpacing.width() / scale.width(), repeatSpacing.height() / scale.height())));
         context.drawRect(destRect, paint);
     }
 
diff --git a/third_party/WebKit/Source/platform/graphics/ImagePattern.cpp b/third_party/WebKit/Source/platform/graphics/ImagePattern.cpp
index 32f4aa9..a11609e 100644
--- a/third_party/WebKit/Source/platform/graphics/ImagePattern.cpp
+++ b/third_party/WebKit/Source/platform/graphics/ImagePattern.cpp
@@ -30,16 +30,16 @@
     }
 }
 
-PassRefPtr<SkShader> ImagePattern::createShader()
+sk_sp<SkShader> ImagePattern::createShader()
 {
     if (!m_tileImage)
-        return adoptRef(SkShader::CreateColorShader(SK_ColorTRANSPARENT));
+        return SkShader::MakeColorShader(SK_ColorTRANSPARENT);
 
     SkMatrix localMatrix = affineTransformToSkMatrix(m_patternSpaceTransformation);
 
     if (isRepeatXY()) {
         // Fast path: for repeatXY we just return a shader from the original image.
-        return adoptRef(m_tileImage->newShader(SkShader::kRepeat_TileMode,
+        return sk_sp<SkShader>(m_tileImage->newShader(SkShader::kRepeat_TileMode,
             SkShader::kRepeat_TileMode, &localMatrix));
     }
 
@@ -61,7 +61,7 @@
     RefPtr<SkSurface> surface = adoptRef(SkSurface::NewRasterN32Premul(
         m_tileImage->width() + expandW, m_tileImage->height() + expandH));
     if (!surface)
-        return adoptRef(SkShader::CreateColorShader(SK_ColorTRANSPARENT));
+        return SkShader::MakeColorShader(SK_ColorTRANSPARENT);
 
     surface->getCanvas()->clear(SK_ColorTRANSPARENT);
     SkPaint paint;
@@ -69,7 +69,7 @@
     surface->getCanvas()->drawImage(m_tileImage.get(), 0, 0, &paint);
     RefPtr<SkImage> expandedImage = adoptRef(surface->newImageSnapshot());
 
-    return adoptRef(expandedImage->newShader(tileModeX, tileModeY, &localMatrix));
+    return sk_sp<SkShader>(expandedImage->newShader(tileModeX, tileModeY, &localMatrix));
 }
 
 bool ImagePattern::isTextureBacked() const
diff --git a/third_party/WebKit/Source/platform/graphics/ImagePattern.h b/third_party/WebKit/Source/platform/graphics/ImagePattern.h
index d8315c2..2dcee62 100644
--- a/third_party/WebKit/Source/platform/graphics/ImagePattern.h
+++ b/third_party/WebKit/Source/platform/graphics/ImagePattern.h
@@ -20,7 +20,7 @@
     bool isTextureBacked() const override;
 
 protected:
-    PassRefPtr<SkShader> createShader() override;
+    sk_sp<SkShader> createShader() override;
 
 private:
     ImagePattern(PassRefPtr<Image>, RepeatMode);
diff --git a/third_party/WebKit/Source/platform/graphics/Pattern.cpp b/third_party/WebKit/Source/platform/graphics/Pattern.cpp
index ce773d5..ae725b4 100644
--- a/third_party/WebKit/Source/platform/graphics/Pattern.cpp
+++ b/third_party/WebKit/Source/platform/graphics/Pattern.cpp
@@ -65,7 +65,7 @@
         m_pattern = createShader();
     }
 
-    paint.setShader(m_pattern.get());
+    paint.setShader(m_pattern);
 }
 
 void Pattern::setPatternSpaceTransform(const AffineTransform& patternSpaceTransformation)
@@ -74,7 +74,7 @@
         return;
 
     m_patternSpaceTransformation = patternSpaceTransformation;
-    m_pattern.clear();
+    m_pattern.reset();
 }
 
 void Pattern::adjustExternalMemoryAllocated(int64_t delta)
diff --git a/third_party/WebKit/Source/platform/graphics/Pattern.h b/third_party/WebKit/Source/platform/graphics/Pattern.h
index c2068ea..a855cca 100644
--- a/third_party/WebKit/Source/platform/graphics/Pattern.h
+++ b/third_party/WebKit/Source/platform/graphics/Pattern.h
@@ -32,11 +32,11 @@
 #include "platform/PlatformExport.h"
 #include "platform/graphics/Image.h"
 #include "platform/transforms/AffineTransform.h"
+#include "third_party/skia/include/core/SkRefCnt.h"
 
 #include "wtf/Noncopyable.h"
 #include "wtf/PassRefPtr.h"
 #include "wtf/RefCounted.h"
-#include "wtf/RefPtr.h"
 
 class SkPaint;
 class SkPicture;
@@ -71,7 +71,7 @@
     virtual bool isTextureBacked() const { return false; }
 
 protected:
-    virtual PassRefPtr<SkShader> createShader() = 0;
+    virtual sk_sp<SkShader> createShader() = 0;
 
     void adjustExternalMemoryAllocated(int64_t delta);
 
@@ -81,7 +81,7 @@
     Pattern(RepeatMode, int64_t externalMemoryAllocated = 0);
 
 private:
-    RefPtr<SkShader> m_pattern;
+    sk_sp<SkShader> m_pattern;
     int64_t m_externalMemoryAllocated;
 };
 
diff --git a/third_party/WebKit/Source/platform/graphics/PicturePattern.cpp b/third_party/WebKit/Source/platform/graphics/PicturePattern.cpp
index 728a27e..f01e6b3 100644
--- a/third_party/WebKit/Source/platform/graphics/PicturePattern.cpp
+++ b/third_party/WebKit/Source/platform/graphics/PicturePattern.cpp
@@ -18,7 +18,7 @@
 
 PicturePattern::PicturePattern(PassRefPtr<const SkPicture> picture, RepeatMode mode)
     : Pattern(mode)
-    , m_tilePicture(picture)
+    , m_tilePicture(const_cast<SkPicture*>(picture.leakRef()))
 {
     // All current clients use RepeatModeXY, so we only support this mode for now.
     ASSERT(isRepeatXY());
@@ -30,13 +30,13 @@
 {
 }
 
-PassRefPtr<SkShader> PicturePattern::createShader()
+sk_sp<SkShader> PicturePattern::createShader()
 {
     SkMatrix localMatrix = affineTransformToSkMatrix(m_patternSpaceTransformation);
     SkRect tileBounds = m_tilePicture->cullRect();
 
-    return adoptRef(SkShader::CreatePictureShader(m_tilePicture.get(),
-        SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix, &tileBounds));
+    return SkShader::MakePictureShader(m_tilePicture,
+        SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix, &tileBounds);
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/PicturePattern.h b/third_party/WebKit/Source/platform/graphics/PicturePattern.h
index 1ae4d28..d4266fa 100644
--- a/third_party/WebKit/Source/platform/graphics/PicturePattern.h
+++ b/third_party/WebKit/Source/platform/graphics/PicturePattern.h
@@ -16,12 +16,12 @@
     ~PicturePattern() override;
 
 protected:
-    PassRefPtr<SkShader> createShader() override;
+    sk_sp<SkShader> createShader() override;
 
 private:
     PicturePattern(PassRefPtr<const SkPicture>, RepeatMode);
 
-    RefPtr<const SkPicture> m_tilePicture;
+    sk_sp<SkPicture> m_tilePicture;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.cpp b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
index beaaf304..a31d6d47 100644
--- a/third_party/WebKit/Source/platform/heap/ThreadState.cpp
+++ b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
@@ -213,6 +213,18 @@
 {
     ASSERT(isMainThread());
 
+#if defined(LEAK_SANITIZER)
+    // If LSan is about to perform leak detection, release all the registered
+    // static Persistent<> root references to global caches that Blink keeps,
+    // followed by GCs to clear out all they referred to.
+    //
+    // This is not needed for caches over non-Oilpan objects, as they're
+    // not scanned by LSan due to being held in non-global storage
+    // ("static" references inside functions/methods.)
+    releaseStaticPersistentNodes();
+    Heap::collectAllGarbage();
+#endif
+
     // Finish sweeping before shutting down V8. Otherwise, some destructor
     // may access V8 and cause crashes.
     completeSweep();
@@ -622,7 +634,7 @@
         schedulePreciseGC();
         return;
     }
-    if (gcType == BlinkGC::V8MajorGC) {
+    if (gcType == BlinkGC::V8MajorGC && shouldScheduleIdleGC()) {
 #if PRINT_HEAP_STATS
         dataLogF("Scheduled IdleGC\n");
 #endif
diff --git a/third_party/WebKit/Source/platform/text/TextBreakIterator.cpp b/third_party/WebKit/Source/platform/text/TextBreakIterator.cpp
index e1205bf..8c84c54 100644
--- a/third_party/WebKit/Source/platform/text/TextBreakIterator.cpp
+++ b/third_party/WebKit/Source/platform/text/TextBreakIterator.cpp
@@ -22,6 +22,7 @@
 
 #include "platform/text/TextBreakIterator.h"
 
+#include "platform/fonts/Character.h"
 #include "wtf/ASCIICType.h"
 #include "wtf/StdLibExtras.h"
 #include "wtf/text/CharacterNames.h"
@@ -221,6 +222,56 @@
     return ch > asciiLineBreakTableLastChar && ch != noBreakSpaceCharacter;
 }
 
+// Customization for ICU line breaking behavior. This allows us to reject ICU
+// line break suggestions which would split an emoji sequence.
+// FIXME crbug.com/593260: Remove this customization once ICU implements this
+// natively.
+static bool isBreakValid(const UChar* buf, size_t length, size_t breakPos)
+{
+    UChar32 codepoint;
+    size_t prevOffset = breakPos;
+    U16_PREV(buf, 0, prevOffset, codepoint);
+    uint32_t nextCodepoint;
+    size_t nextOffset = breakPos;
+    U16_NEXT(buf, nextOffset, length, nextCodepoint);
+
+    // Possible Emoji ZWJ sequence
+    if (codepoint == zeroWidthJoinerCharacter) {
+        if (nextCodepoint == 0x2764 // HEAVY BLACK HEART
+            || nextCodepoint == 0x1F466 // BOY
+            || nextCodepoint == 0x1F467 // GIRL
+            || nextCodepoint == 0x1F468 // MAN
+            || nextCodepoint == 0x1F469 // WOMAN
+            || nextCodepoint == 0x1F48B // KISS MARK
+            || nextCodepoint == 0x1F5E8) // LEFT SPEECH BUBBLE
+        {
+            return false;
+        }
+    }
+
+    // Possible emoji modifier sequence
+    // Proposed Rule LB30b from http://www.unicode.org/L2/L2016/16011r3-break-prop-emoji.pdf
+    // EB x EM
+    if (Character::isModifier(nextCodepoint)) {
+        if (codepoint == variationSelector16Character && prevOffset > 0) {
+            // Skip over emoji variation selector.
+            U16_PREV(buf, 0, prevOffset, codepoint);
+        }
+        if (Character::isEmojiModifierBase(codepoint)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+// Trivial implementation to match possible template paramters in
+// nextBreakablePosition. There are no emoji sequences in 8bit strings, so we
+// accept all break opportunities.
+static bool isBreakValid(const LChar*, size_t, size_t)
+{
+    return true;
+}
+
 template<typename CharacterType, LineBreakType lineBreakType>
 static inline int nextBreakablePosition(LazyLineBreakIterator& lazyBreakIterator, const CharacterType* str, unsigned length, int pos)
 {
@@ -260,8 +311,9 @@
                     }
                 }
             }
-            if (i == nextBreak && !isBreakableSpace(lastCh))
+            if (i == nextBreak && !isBreakableSpace(lastCh) && isBreakValid(str, length, i)) {
                 return i;
+            }
         }
 
         lastLastCh = lastCh;
@@ -307,7 +359,7 @@
                     }
                 }
             }
-            if (i == nextBreak && !isBreakableSpace(lastCh))
+            if (i == nextBreak && !isBreakableSpace(lastCh) && isBreakValid(str, length, i))
                 return i;
         }
 
diff --git a/third_party/WebKit/Source/platform/text/TextBreakIteratorTest.cpp b/third_party/WebKit/Source/platform/text/TextBreakIteratorTest.cpp
new file mode 100644
index 0000000..b489a4d7
--- /dev/null
+++ b/third_party/WebKit/Source/platform/text/TextBreakIteratorTest.cpp
@@ -0,0 +1,99 @@
+// 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 "platform/text/TextBreakIterator.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "wtf/text/WTFString.h"
+
+namespace blink {
+
+class TextBreakIteratorTest : public testing::Test {
+protected:
+    void SetTestString(const char* testString)
+    {
+        m_testString = String::fromUTF8(testString);
+    }
+
+    // The expected break positions must be specified UTF-16 character boundaries.
+    void MatchLineBreaks(LineBreakType lineBreakType, const Vector<int> expectedBreakPositions)
+    {
+        if (m_testString.is8Bit()) {
+            m_testString = String::make16BitFrom8BitSource(m_testString.characters8(), m_testString.length());
+        }
+        LazyLineBreakIterator lazyBreakIterator(m_testString);
+        int nextBreakable = 0;
+        for (auto breakPosition : expectedBreakPositions) {
+            int triggerPos = std::min(static_cast<unsigned>(nextBreakable + 1), m_testString.length());
+            bool isBreakable = lazyBreakIterator.isBreakable(triggerPos, nextBreakable, lineBreakType);
+            if (isBreakable) {
+                ASSERT_EQ(triggerPos, breakPosition);
+            }
+            ASSERT_EQ(breakPosition, nextBreakable);
+        }
+    }
+
+private:
+    String m_testString;
+};
+
+// Initializing Vector from an initializer list still not possible, C++ feature banned in Blink.
+#define DECLARE_BREAKSVECTOR(...)                   \
+    static const int32_t breaksArray[] = __VA_ARGS__; \
+    Vector<int> breaks;                                         \
+    breaks.append(breaksArray, sizeof(breaksArray) / sizeof(*breaksArray));
+
+#define MATCH_LINE_BREAKS(LINEBREAKTYPE, ...)        \
+    {                                                \
+        DECLARE_BREAKSVECTOR(__VA_ARGS__);           \
+        MatchLineBreaks(LINEBREAKTYPE, breaks); \
+    }
+
+TEST_F(TextBreakIteratorTest, Basic)
+{
+    SetTestString("a b c");
+    MATCH_LINE_BREAKS(LineBreakType::Normal, { 1, 3, 5 });
+}
+
+TEST_F(TextBreakIteratorTest, Chinese)
+{
+    SetTestString("標準萬國碼");
+    MATCH_LINE_BREAKS(LineBreakType::Normal, { 1, 2, 3, 4, 5 });
+    MATCH_LINE_BREAKS(LineBreakType::BreakAll, { 1, 2, 3, 4, 5 });
+    MATCH_LINE_BREAKS(LineBreakType::KeepAll, { 5 });
+}
+
+TEST_F(TextBreakIteratorTest, KeepEmojiZWJFamilyIsolate)
+{
+    SetTestString("\xF0\x9F\x91\xA8\xE2\x80\x8D\xF0\x9F\x91\xA9\xE2\x80\x8D\xF0\x9F\x91\xA7\xE2\x80\x8D\xF0\x9F\x91\xA6");
+    MATCH_LINE_BREAKS(LineBreakType::Normal, { 11 });
+    MATCH_LINE_BREAKS(LineBreakType::BreakAll, { 11 });
+    MATCH_LINE_BREAKS(LineBreakType::KeepAll, { 11 });
+}
+
+TEST_F(TextBreakIteratorTest, KeepEmojiModifierSequenceIsolate)
+{
+    SetTestString("\xE2\x98\x9D\xF0\x9F\x8F\xBB");
+    MATCH_LINE_BREAKS(LineBreakType::Normal, { 3 });
+    MATCH_LINE_BREAKS(LineBreakType::BreakAll, { 3 });
+    MATCH_LINE_BREAKS(LineBreakType::KeepAll, { 3 });
+}
+
+TEST_F(TextBreakIteratorTest, KeepEmojiZWJSequence)
+{
+    SetTestString("abc \xF0\x9F\x91\xA9\xE2\x80\x8D\xF0\x9F\x91\xA9\xE2\x80\x8D\xF0\x9F\x91\xA7\xE2\x80\x8D\xF0\x9F\x91\xA7 def");
+    MATCH_LINE_BREAKS(LineBreakType::Normal, { 3, 15, 19 });
+    MATCH_LINE_BREAKS(LineBreakType::BreakAll, { 1, 2, 3, 15, 17, 18, 19 });
+    MATCH_LINE_BREAKS(LineBreakType::KeepAll, { 3, 15, 19 });
+}
+
+TEST_F(TextBreakIteratorTest, KeepEmojiModifierSequence)
+{
+    SetTestString("abc \xE2\x98\x9D\xF0\x9F\x8F\xBB def");
+    MATCH_LINE_BREAKS(LineBreakType::Normal, { 3, 7, 11 });
+    MATCH_LINE_BREAKS(LineBreakType::BreakAll, { 1, 2, 3, 7, 9, 10, 11 });
+    MATCH_LINE_BREAKS(LineBreakType::KeepAll, { 3, 7, 11 });
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/web/ImageDecodeBench.cpp b/third_party/WebKit/Source/web/ImageDecodeBench.cpp
index 6c8ecc1a..ea632c6f 100644
--- a/third_party/WebKit/Source/web/ImageDecodeBench.cpp
+++ b/third_party/WebKit/Source/web/ImageDecodeBench.cpp
@@ -367,7 +367,7 @@
         }
     };
 
-    blink::initializeWithoutV8(new WebPlatform());
+    Platform::initialize(new WebPlatform());
 
     // Set image decoding Platform options.
 
diff --git a/third_party/WebKit/Source/web/WebKit.cpp b/third_party/WebKit/Source/web/WebKit.cpp
index c5a10a9..29cca01 100644
--- a/third_party/WebKit/Source/web/WebKit.cpp
+++ b/third_party/WebKit/Source/web/WebKit.cpp
@@ -103,29 +103,8 @@
     return V8PerIsolateData::mainThreadIsolate();
 }
 
-// TODO(haraken): Remove this function.
-void initializeWithoutV8(Platform* platform)
-{
-    Platform::initialize(platform);
-}
-
 void shutdown()
 {
-#if defined(LEAK_SANITIZER)
-    // If LSan is about to perform leak detection, release all the registered
-    // static Persistent<> root references to global caches that Blink keeps,
-    // followed by GCs to clear out all they referred to. A full v8 GC cycle
-    // is needed to flush out all garbage.
-    //
-    // This is not needed for caches over non-Oilpan objects, as they're
-    // not scanned by LSan due to being held in non-global storage
-    // ("static" references inside functions/methods.)
-    if (ThreadState* threadState = ThreadState::current()) {
-        threadState->releaseStaticPersistentNodes();
-        Heap::collectAllGarbage();
-    }
-#endif
-
     ThreadState::current()->cleanupMainThread();
 
     // currentThread() is null if we are running on a thread without a message loop.
@@ -144,12 +123,6 @@
     Platform::shutdown();
 }
 
-// TODO(haraken): Remove this function.
-void shutdownWithoutV8()
-{
-    Platform::shutdown();
-}
-
 // TODO(tkent): The following functions to wrap LayoutTestSupport should be
 // moved to public/platform/.
 
diff --git a/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp b/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp
index 46747cb..a98bbca 100644
--- a/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp
+++ b/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp
@@ -65,6 +65,11 @@
     RuntimeEnabledFeatures::setAudioOutputDevicesEnabled(enable);
 }
 
+void WebRuntimeFeatures::enableCanvas2dImageChromium(bool enable)
+{
+    RuntimeEnabledFeatures::setCanvas2dImageChromiumEnabled(enable);
+}
+
 void WebRuntimeFeatures::enableCompositedSelectionUpdate(bool enable)
 {
     RuntimeEnabledFeatures::setCompositedSelectionUpdateEnabled(enable);
diff --git a/third_party/WebKit/public/platform/Platform.h b/third_party/WebKit/public/platform/Platform.h
index 880be7b..623c11f 100644
--- a/third_party/WebKit/public/platform/Platform.h
+++ b/third_party/WebKit/public/platform/Platform.h
@@ -135,6 +135,8 @@
     typedef int FileHandle;
 #endif
 
+    // Initialize platform and wtf. If you need to initialize the entire Blink,
+    // you should use blink::initialize.
     static void initialize(Platform*);
     static void shutdown();
     static Platform* current();
diff --git a/third_party/WebKit/public/platform/WebCredentialManagerError.h b/third_party/WebKit/public/platform/WebCredentialManagerError.h
index 637e219..9ec11e6 100644
--- a/third_party/WebKit/public/platform/WebCredentialManagerError.h
+++ b/third_party/WebKit/public/platform/WebCredentialManagerError.h
@@ -10,7 +10,8 @@
 // FIXME: This is a placeholder list of error conditions. We'll likely expand the
 // list as the API evolves.
 enum WebCredentialManagerError {
-    WebCredentialManagerDisabledError = 0,
+    WebCredentialManagerNoError = 0,
+    WebCredentialManagerDisabledError,
     WebCredentialManagerPendingRequestError,
     WebCredentialManagerPasswordStoreUnavailableError,
     WebCredentialManagerUnknownError,
diff --git a/third_party/WebKit/public/platform/modules/mediasession/WebMediaSession.h b/third_party/WebKit/public/platform/modules/mediasession/WebMediaSession.h
index 439a6c7a..039dd80f 100644
--- a/third_party/WebKit/public/platform/modules/mediasession/WebMediaSession.h
+++ b/third_party/WebKit/public/platform/modules/mediasession/WebMediaSession.h
@@ -18,6 +18,8 @@
 class WebMediaSession {
 public:
     enum {
+        // The media session for media elements that don't have an
+        // explicit user created media session set.
         DefaultID = 0
     };
 
diff --git a/third_party/WebKit/public/web/WebInputEvent.h b/third_party/WebKit/public/web/WebInputEvent.h
index 3be5b18e..d2e24f8 100644
--- a/third_party/WebKit/public/web/WebInputEvent.h
+++ b/third_party/WebKit/public/web/WebInputEvent.h
@@ -513,6 +513,14 @@
             // If true, this event will skip hit testing to find a scroll
             // target and instead just scroll the viewport.
             bool targetViewport;
+            // If true, this event comes after a non-inertial gesture
+            // scroll sequence; OSX has unique phases for normal and
+            // momentum scroll events. Should always be false for touch based
+            // input as it generates GestureFlingStart instead.
+            bool inertial;
+            // True if this event was synthesized in order to force a hit test; avoiding scroll
+            // latching behavior until crbug.com/526463 is fully implemented.
+            bool synthetic;
         } scrollBegin;
 
         struct {
@@ -536,6 +544,16 @@
             // The original delta units the scrollBegin and scrollUpdates
             // were sent as.
             ScrollUnits deltaUnits;
+            // If true, this event comes after an inertial gesture
+            // scroll sequence; OSX has unique phases for normal and
+            // momentum scroll events. Should always be false for touch based
+            // input as it generates GestureFlingStart instead.
+            bool inertial;
+            // True if this event was synthesized in order to generate the proper
+            // GSB/GSU/GSE matching sequences. This is a temporary so that a future
+            // GSB will generate a hit test so latching behavior is avoided
+            // until crbug.com/526463 is fully implemented.
+            bool synthetic;
         } scrollEnd;
 
         struct {
diff --git a/third_party/WebKit/public/web/WebKit.h b/third_party/WebKit/public/web/WebKit.h
index 10830c5..0ee53fd2 100644
--- a/third_party/WebKit/public/web/WebKit.h
+++ b/third_party/WebKit/public/web/WebKit.h
@@ -39,18 +39,14 @@
 
 namespace blink {
 
-// Must be called on the thread that will be the main WebKit thread before
-// using any other WebKit APIs. The provided Platform; must be
+// Initialize the entire Blink (wtf, platform, core, modules and web).
+// If you just need wtf and platform, use Platform::initialize instead.
+//
+// Must be called on the thread that will be the main thread before
+// using any other public APIs. The provided Platform; must be
 // non-null and must remain valid until the current thread calls shutdown.
 BLINK_EXPORT void initialize(Platform*);
 
-// Must be called on the thread that will be the main WebKit thread before
-// using any other WebKit APIs. The provided Platform must be
-// non-null and must remain valid until the current thread calls shutdown.
-//
-// This is a special variant of initialize that does not intitialize V8.
-BLINK_EXPORT void initializeWithoutV8(Platform*);
-
 // Get the V8 Isolate for the main thread.
 // initialize must have been called first.
 BLINK_EXPORT v8::Isolate* mainThreadIsolate();
@@ -61,15 +57,6 @@
 // terminated by the time this function returns.
 BLINK_EXPORT void shutdown();
 
-// Once shutdown, the Platform passed to initializeWithoutV8 will no longer
-// be accessed. No other WebKit objects should be in use when this function is
-// called. Any background threads created by WebKit are promised to be
-// terminated by the time this function returns.
-//
-// If initializeWithoutV8() was used to initialize WebKit, shutdownWithoutV8
-// must be called to shut it down again.
-BLINK_EXPORT void shutdownWithoutV8();
-
 // Alters the rendering of content to conform to a fixed set of rules.
 BLINK_EXPORT void setLayoutTestMode(bool);
 BLINK_EXPORT bool layoutTestMode();
diff --git a/third_party/WebKit/public/web/WebRuntimeFeatures.h b/third_party/WebKit/public/web/WebRuntimeFeatures.h
index b371968c..817d0a23 100644
--- a/third_party/WebKit/public/web/WebRuntimeFeatures.h
+++ b/third_party/WebKit/public/web/WebRuntimeFeatures.h
@@ -59,6 +59,8 @@
 
     BLINK_EXPORT static void enableAudioOutputDevices(bool);
 
+    BLINK_EXPORT static void enableCanvas2dImageChromium(bool);
+
     BLINK_EXPORT static void enableDatabase(bool);
 
     BLINK_EXPORT static void enableCompositedSelectionUpdate(bool);
diff --git a/third_party/polymer/v1_0/chromium.patch b/third_party/polymer/v1_0/chromium.patch
index a38a4d2..d67b3e7 100644
--- a/third_party/polymer/v1_0/chromium.patch
+++ b/third_party/polymer/v1_0/chromium.patch
@@ -74,14 +74,14 @@
 @@ -20,11 +31,11 @@ Polymer({
        state.value = state.value || '';
 
-       // Account for the textarea's new lines.
--      var str = state.value.replace(/(\r\n|\n|\r)/g, '--').length;
-+      var str = state.value.replace(/(\r\n|\n|\r)/g, '--').length.toString();
+-      var counter = state.value.length;
++      var counter = state.value.length.toString();
 
        if (state.inputElement.hasAttribute('maxlength')) {
-         str += '/' + state.inputElement.getAttribute('maxlength');
+         counter += '/' + state.inputElement.getAttribute('maxlength');
        }
-       this._charCounterStr = str;
+
+       this._charCounterStr = counter;
      }
 -  });
 \ No newline at end of file
diff --git a/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/.bower.json b/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/.bower.json
index 81113ef0..e6d37e62 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/.bower.json
+++ b/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/.bower.json
@@ -1,6 +1,6 @@
 {
   "name": "iron-autogrow-textarea",
-  "version": "1.0.10",
+  "version": "1.0.12",
   "description": "A textarea element that automatically grows with input",
   "authors": [
     "The Polymer Authors"
@@ -29,17 +29,18 @@
   },
   "devDependencies": {
     "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+    "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
     "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
     "test-fixture": "PolymerElements/test-fixture#^1.0.0",
-    "web-component-tester": "polymer/web-component-tester#^3.4.0",
+    "web-component-tester": "^4.0.0",
     "paper-styles": "PolymerElements/paper-styles#^1.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
   },
-  "_release": "1.0.10",
+  "_release": "1.0.12",
   "_resolution": {
     "type": "version",
-    "tag": "v1.0.10",
-    "commit": "1ba4f97e250dc14e9638d95be582dd62b9083736"
+    "tag": "v1.0.12",
+    "commit": "86f8fd61b412bcea6bc7b8feaee9b24bc2ad48ea"
   },
   "_source": "git://github.com/PolymerElements/iron-autogrow-textarea.git",
   "_target": "^1.0.0",
diff --git a/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/CONTRIBUTING.md b/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/CONTRIBUTING.md
index 7b101415..f147978a 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/CONTRIBUTING.md
+++ b/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/CONTRIBUTING.md
@@ -5,6 +5,11 @@
 
 If you edit that file, it will get updated everywhere else.
 If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
 -->
 # Polymer Elements
 ## Guide for Contributors
@@ -41,7 +46,7 @@
  3. Click the `paper-foo` element.
  ```
 
- 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [http://jsbin.com/cagaye](http://jsbin.com/cagaye/edit?html,output).
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
 
  3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
 
@@ -51,14 +56,14 @@
 
 When submitting pull requests, please provide:
 
- 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues using the following syntax:
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
 
  ```markdown
  (For a single issue)
  Fixes #20
 
  (For multiple issues)
- Fixes #32, #40
+ Fixes #32, fixes #40
  ```
 
  2. **A succinct description of the design** used to fix any related issues. For example:
diff --git a/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/README.md b/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/README.md
index b0127f89..b207d330 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/README.md
+++ b/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/README.md
@@ -7,23 +7,27 @@
 Edit those files, and our readme bot will duplicate them over here!
 Edit this file, and the bot will squash your changes :)
 
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
 -->
 
-[![Build Status](https://travis-ci.org/PolymerElements/iron-autogrow-textarea.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-autogrow-textarea)
+[![Build status](https://travis-ci.org/PolymerElements/iron-autogrow-textarea.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-autogrow-textarea)
 
-_[Demo and API Docs](https://elements.polymer-project.org/elements/iron-autogrow-textarea)_
+_[Demo and API docs](https://elements.polymer-project.org/elements/iron-autogrow-textarea)_
 
 
 ##&lt;iron-autogrow-textarea&gt;
 
-
 `iron-autogrow-textarea` is an element containing a textarea that grows in height as more
 lines of input are entered. Unless an explicit height or the `maxRows` property is set, it will
 never scroll.
 
 Example:
 
-    <iron-autogrow-textarea></iron-autogrow-textarea>
+```html
+<iron-autogrow-textarea></iron-autogrow-textarea>
+```
 
 Because the `textarea`'s `value` property is not observable, you should use
 this element's `bind-value` instead for imperative updates.
@@ -32,8 +36,9 @@
 
 The following custom properties and mixins are available for styling:
 
-Custom property | Description | Default
-----------------|-------------|----------
-`--iron-autogrow-textarea` | Mixin applied to the textarea | `{}`
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--iron-autogrow-textarea` | Mixin applied to the textarea | `{}` |
+| `--iron-autogrow-textarea-placeholder` | Mixin applied to the textarea placeholder | `{}` |
 
 
diff --git a/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/bower.json b/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/bower.json
index 61a9c49a..67be4a66 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/bower.json
+++ b/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "iron-autogrow-textarea",
-  "version": "1.0.10",
+  "version": "1.0.12",
   "description": "A textarea element that automatically grows with input",
   "authors": [
     "The Polymer Authors"
@@ -29,9 +29,10 @@
   },
   "devDependencies": {
     "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+    "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
     "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
     "test-fixture": "PolymerElements/test-fixture#^1.0.0",
-    "web-component-tester": "polymer/web-component-tester#^3.4.0",
+    "web-component-tester": "^4.0.0",
     "paper-styles": "PolymerElements/paper-styles#^1.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
   }
diff --git a/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/iron-autogrow-textarea-extracted.js b/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/iron-autogrow-textarea-extracted.js
index 6bec3180..464100f9 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/iron-autogrow-textarea-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/iron-autogrow-textarea-extracted.js
@@ -12,8 +12,8 @@
 
       /**
        * Use this property instead of `value` for two-way data binding.
-       *
-       * @type {string|number|undefined|null}
+       * This property will be deprecated in the future. Use `value` instead.
+       * @type {string|number}
        */
       bindValue: {
         observer: '_bindValueChanged',
@@ -71,22 +71,6 @@
       },
 
       /**
-       * Bound to the textarea's `name` attribute.
-       */
-      name: {
-        type: String
-      },
-
-      /**
-       * The value for this input, same as `bindValue`
-       */
-      value: {
-        notify: true,
-        type: String,
-        computed: '_computeValue(bindValue)'
-      },
-
-      /**
        * Bound to the textarea's `placeholder` attribute.
        */
       placeholder: {
@@ -120,6 +104,10 @@
       'input': '_onInput'
     },
 
+    observers: [
+      '_onValueChanged(value)'
+    ],
+
     /**
      * Returns the underlying textarea.
      * @type HTMLTextAreaElement
@@ -196,6 +184,7 @@
         textarea.value = !(this.bindValue || this.bindValue === 0) ? '' : this.bindValue;
       }
 
+      this.value = this.bindValue;
       this.$.mirror.innerHTML = this._valueForMirror();
       // manually notify because we don't want to notify until after setting value
       this.fire('bind-value-changed', {value: this.bindValue});
@@ -234,7 +223,7 @@
       this.$.mirror.innerHTML = this._constrain(this.tokens);
     },
 
-    _computeValue: function() {
-      return this.bindValue;
+    _onValueChanged: function() {
+      this.bindValue = this.value;
     }
   });
\ No newline at end of file
diff --git a/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/iron-autogrow-textarea.html b/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/iron-autogrow-textarea.html
index cdd80b2f..ede93016 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/iron-autogrow-textarea.html
+++ b/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/iron-autogrow-textarea.html
@@ -21,9 +21,6 @@
 
     <iron-autogrow-textarea></iron-autogrow-textarea>
 
-Because the `textarea`'s `value` property is not observable, you should use
-this element's `bind-value` instead for imperative updates.
-
 ### Styling
 
 The following custom properties and mixins are available for styling:
@@ -31,6 +28,7 @@
 Custom property | Description | Default
 ----------------|-------------|----------
 `--iron-autogrow-textarea` | Mixin applied to the textarea | `{}`
+`--iron-autogrow-textarea-placeholder` | Mixin applied to the textarea placeholder | `{}`
 
 @group Iron Elements
 @hero hero.svg
@@ -48,6 +46,7 @@
       padding: 2px;
       -moz-appearance: textarea;
       -webkit-appearance: textarea;
+      overflow: hidden;
     }
 
     .mirror-text {
@@ -80,6 +79,21 @@
       box-shadow: none;
     }
 
+    textarea::-webkit-input-placeholder {
+      @apply(--iron-autogrow-textarea-placeholder);
+    }
+
+    textarea:-moz-placeholder {
+      @apply(--iron-autogrow-textarea-placeholder);
+    }
+
+    textarea::-moz-placeholder {
+      @apply(--iron-autogrow-textarea-placeholder);
+    }
+
+    textarea:-ms-input-placeholder {
+      @apply(--iron-autogrow-textarea-placeholder);
+    }
   </style>
   <template>
     <!-- the mirror sizes the input/textarea so it grows with typing -->
@@ -88,7 +102,7 @@
 
     <!-- size the input/textarea with a div, because the textarea has intrinsic size in ff -->
     <div class="textarea-container fit">
-      <textarea id="textarea" autocomplete$="[[autocomplete]]" autofocus$="[[autofocus]]" inputmode$="[[inputmode]]" placeholder$="[[placeholder]]" readonly$="[[readonly]]" required$="[[required]]" disabled$="[[disabled]]" rows$="[[rows]]" maxlength$="[[maxlength]]"></textarea>
+      <textarea id="textarea" name$="[[name]]" autocomplete$="[[autocomplete]]" autofocus$="[[autofocus]]" inputmode$="[[inputmode]]" placeholder$="[[placeholder]]" readonly$="[[readonly]]" required$="[[required]]" disabled$="[[disabled]]" rows$="[[rows]]" maxlength$="[[maxlength]]"></textarea>
     </div>
   </template>
 </dom-module>
diff --git a/third_party/polymer/v1_0/components-chromium/iron-behaviors/.bower.json b/third_party/polymer/v1_0/components-chromium/iron-behaviors/.bower.json
index db08f21..85e8252b 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-behaviors/.bower.json
+++ b/third_party/polymer/v1_0/components-chromium/iron-behaviors/.bower.json
@@ -1,6 +1,6 @@
 {
   "name": "iron-behaviors",
-  "version": "1.0.12",
+  "version": "1.0.13",
   "description": "Provides a set of behaviors for the iron elements",
   "private": true,
   "authors": [
@@ -25,16 +25,16 @@
     "iron-test-helpers": "polymerelements/iron-test-helpers#^1.0.0",
     "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
     "test-fixture": "polymerelements/test-fixture#^1.0.0",
-    "web-component-tester": "polymer/web-component-tester#^3.4.0",
+    "web-component-tester": "^4.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
   },
   "ignore": [],
   "homepage": "https://github.com/PolymerElements/iron-behaviors",
-  "_release": "1.0.12",
+  "_release": "1.0.13",
   "_resolution": {
     "type": "version",
-    "tag": "v1.0.12",
-    "commit": "657f526a2382a659cdf4e13be87ecc89261588a3"
+    "tag": "v1.0.13",
+    "commit": "a7bc3428a6da2beed21987b3a8028206826a12bc"
   },
   "_source": "git://github.com/PolymerElements/iron-behaviors.git",
   "_target": "^1.0.0",
diff --git a/third_party/polymer/v1_0/components-chromium/iron-behaviors/CONTRIBUTING.md b/third_party/polymer/v1_0/components-chromium/iron-behaviors/CONTRIBUTING.md
index 7b101415..f147978a 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-behaviors/CONTRIBUTING.md
+++ b/third_party/polymer/v1_0/components-chromium/iron-behaviors/CONTRIBUTING.md
@@ -5,6 +5,11 @@
 
 If you edit that file, it will get updated everywhere else.
 If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
 -->
 # Polymer Elements
 ## Guide for Contributors
@@ -41,7 +46,7 @@
  3. Click the `paper-foo` element.
  ```
 
- 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [http://jsbin.com/cagaye](http://jsbin.com/cagaye/edit?html,output).
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
 
  3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
 
@@ -51,14 +56,14 @@
 
 When submitting pull requests, please provide:
 
- 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues using the following syntax:
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
 
  ```markdown
  (For a single issue)
  Fixes #20
 
  (For multiple issues)
- Fixes #32, #40
+ Fixes #32, fixes #40
  ```
 
  2. **A succinct description of the design** used to fix any related issues. For example:
diff --git a/third_party/polymer/v1_0/components-chromium/iron-behaviors/README.md b/third_party/polymer/v1_0/components-chromium/iron-behaviors/README.md
index 6b39f8bb..0a0629ec 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-behaviors/README.md
+++ b/third_party/polymer/v1_0/components-chromium/iron-behaviors/README.md
@@ -7,13 +7,16 @@
 Edit those files, and our readme bot will duplicate them over here!
 Edit this file, and the bot will squash your changes :)
 
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
 -->
 
-[![Build Status](https://travis-ci.org/PolymerElements/iron-behaviors.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-behaviors)
+[![Build status](https://travis-ci.org/PolymerElements/iron-behaviors.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-behaviors)
 
-_[Demo and API Docs](https://elements.polymer-project.org/elements/iron-behaviors)_
+_[Demo and API docs](https://elements.polymer-project.org/elements/iron-behaviors)_
 
 
-<!-- No docs for Polymer.IronControlState found. -->
-
 <!-- No docs for Polymer.IronButtonState found. -->
+
+<!-- No docs for Polymer.IronControlState found. -->
diff --git a/third_party/polymer/v1_0/components-chromium/iron-behaviors/bower.json b/third_party/polymer/v1_0/components-chromium/iron-behaviors/bower.json
index f1f3641..6f3b79d 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-behaviors/bower.json
+++ b/third_party/polymer/v1_0/components-chromium/iron-behaviors/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "iron-behaviors",
-  "version": "1.0.12",
+  "version": "1.0.13",
   "description": "Provides a set of behaviors for the iron elements",
   "private": true,
   "authors": [
@@ -25,7 +25,7 @@
     "iron-test-helpers": "polymerelements/iron-test-helpers#^1.0.0",
     "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
     "test-fixture": "polymerelements/test-fixture#^1.0.0",
-    "web-component-tester": "polymer/web-component-tester#^3.4.0",
+    "web-component-tester": "^4.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
   },
   "ignore": []
diff --git a/third_party/polymer/v1_0/components-chromium/iron-behaviors/iron-control-state-extracted.js b/third_party/polymer/v1_0/components-chromium/iron-behaviors/iron-control-state-extracted.js
index 72f8088..611aaf6e 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-behaviors/iron-control-state-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/iron-behaviors/iron-control-state-extracted.js
@@ -75,6 +75,7 @@
         this._oldTabIndex = this.tabIndex;
         this.focused = false;
         this.tabIndex = -1;
+        this.blur();
       } else if (this._oldTabIndex !== undefined) {
         this.tabIndex = this._oldTabIndex;
       }
diff --git a/third_party/polymer/v1_0/components-chromium/iron-dropdown/compiled_resources2.gyp b/third_party/polymer/v1_0/components-chromium/iron-dropdown/compiled_resources2.gyp
index a242fe5..ab559786 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-dropdown/compiled_resources2.gyp
+++ b/third_party/polymer/v1_0/components-chromium/iron-dropdown/compiled_resources2.gyp
@@ -6,13 +6,6 @@
 {
   'targets': [
     {
-      'target_name': 'iron-dropdown-scroll-manager-extracted',
-      'dependencies': [
-        '../iron-a11y-keys-behavior/compiled_resources2.gyp:iron-a11y-keys-behavior-extracted',
-      ],
-      'includes': ['../../../../closure_compiler/compile_js2.gypi'],
-    },
-    {
       'target_name': 'iron-dropdown-extracted',
       'dependencies': [
         '../iron-a11y-keys-behavior/compiled_resources2.gyp:iron-a11y-keys-behavior-extracted',
@@ -25,5 +18,12 @@
       ],
       'includes': ['../../../../closure_compiler/compile_js2.gypi'],
     },
+    {
+      'target_name': 'iron-dropdown-scroll-manager-extracted',
+      'dependencies': [
+        '../iron-a11y-keys-behavior/compiled_resources2.gyp:iron-a11y-keys-behavior-extracted',
+      ],
+      'includes': ['../../../../closure_compiler/compile_js2.gypi'],
+    },
   ],
 }
diff --git a/third_party/polymer/v1_0/components-chromium/iron-fit-behavior/.bower.json b/third_party/polymer/v1_0/components-chromium/iron-fit-behavior/.bower.json
index b33aab0..1318aaf 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-fit-behavior/.bower.json
+++ b/third_party/polymer/v1_0/components-chromium/iron-fit-behavior/.bower.json
@@ -1,6 +1,6 @@
 {
   "name": "iron-fit-behavior",
-  "version": "1.0.5",
+  "version": "1.0.6",
   "license": "http://polymer.github.io/LICENSE.txt",
   "description": "Fits an element inside another element",
   "private": true,
@@ -24,16 +24,16 @@
     "paper-styles": "polymerelements/paper-styles#^1.0.2",
     "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
     "test-fixture": "PolymerElements/test-fixture#^1.0.0",
-    "web-component-tester": "polymer/web-component-tester#^3.4.0",
+    "web-component-tester": "^4.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
   },
   "ignore": [],
   "homepage": "https://github.com/PolymerElements/iron-fit-behavior",
-  "_release": "1.0.5",
+  "_release": "1.0.6",
   "_resolution": {
     "type": "version",
-    "tag": "v1.0.5",
-    "commit": "18dec1eb5c7217be4d360c0fb9101fe899136f92"
+    "tag": "v1.0.6",
+    "commit": "f2e868af4fad643ffb7fea3501e1429acc4ec0f0"
   },
   "_source": "git://github.com/PolymerElements/iron-fit-behavior.git",
   "_target": "^1.0.0",
diff --git a/third_party/polymer/v1_0/components-chromium/iron-fit-behavior/CONTRIBUTING.md b/third_party/polymer/v1_0/components-chromium/iron-fit-behavior/CONTRIBUTING.md
index 7b101415..f147978a 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-fit-behavior/CONTRIBUTING.md
+++ b/third_party/polymer/v1_0/components-chromium/iron-fit-behavior/CONTRIBUTING.md
@@ -5,6 +5,11 @@
 
 If you edit that file, it will get updated everywhere else.
 If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
 -->
 # Polymer Elements
 ## Guide for Contributors
@@ -41,7 +46,7 @@
  3. Click the `paper-foo` element.
  ```
 
- 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [http://jsbin.com/cagaye](http://jsbin.com/cagaye/edit?html,output).
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
 
  3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
 
@@ -51,14 +56,14 @@
 
 When submitting pull requests, please provide:
 
- 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues using the following syntax:
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
 
  ```markdown
  (For a single issue)
  Fixes #20
 
  (For multiple issues)
- Fixes #32, #40
+ Fixes #32, fixes #40
  ```
 
  2. **A succinct description of the design** used to fix any related issues. For example:
diff --git a/third_party/polymer/v1_0/components-chromium/iron-fit-behavior/README.md b/third_party/polymer/v1_0/components-chromium/iron-fit-behavior/README.md
index d8ac001..ed1b72f 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-fit-behavior/README.md
+++ b/third_party/polymer/v1_0/components-chromium/iron-fit-behavior/README.md
@@ -7,28 +7,30 @@
 Edit those files, and our readme bot will duplicate them over here!
 Edit this file, and the bot will squash your changes :)
 
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
 -->
 
-[![Build Status](https://travis-ci.org/PolymerElements/iron-fit-behavior.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-fit-behavior)
+[![Build status](https://travis-ci.org/PolymerElements/iron-fit-behavior.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-fit-behavior)
 
-_[Demo and API Docs](https://elements.polymer-project.org/elements/iron-fit-behavior)_
+_[Demo and API docs](https://elements.polymer-project.org/elements/iron-fit-behavior)_
 
 
 ##Polymer.IronFitBehavior
 
-
 Polymer.IronFitBehavior fits an element in another element using `max-height` and `max-width`, and
 optionally centers it in the window or another element.
 
 The element will only be sized and/or positioned if it has not already been sized and/or positioned
 by CSS.
 
-CSS properties               | Action
------------------------------|-------------------------------------------
-`position` set               | Element is not centered horizontally or vertically
-`top` or `bottom` set        | Element is not vertically centered
-`left` or `right` set        | Element is not horizontally centered
-`max-height` or `height` set | Element respects `max-height` or `height`
-`max-width` or `width` set   | Element respects `max-width` or `width`
+| CSS properties | Action |
+| --- | --- |
+| `position` set | Element is not centered horizontally or vertically |
+| `top` or `bottom` set | Element is not vertically centered |
+| `left` or `right` set | Element is not horizontally centered |
+| `max-height` or `height` set | Element respects `max-height` or `height` |
+| `max-width` or `width` set | Element respects `max-width` or `width` |
 
 
diff --git a/third_party/polymer/v1_0/components-chromium/iron-fit-behavior/bower.json b/third_party/polymer/v1_0/components-chromium/iron-fit-behavior/bower.json
index 7e0c31d7..86c8582 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-fit-behavior/bower.json
+++ b/third_party/polymer/v1_0/components-chromium/iron-fit-behavior/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "iron-fit-behavior",
-  "version": "1.0.5",
+  "version": "1.0.6",
   "license": "http://polymer.github.io/LICENSE.txt",
   "description": "Fits an element inside another element",
   "private": true,
@@ -24,7 +24,7 @@
     "paper-styles": "polymerelements/paper-styles#^1.0.2",
     "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
     "test-fixture": "PolymerElements/test-fixture#^1.0.0",
-    "web-component-tester": "polymer/web-component-tester#^3.4.0",
+    "web-component-tester": "^4.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
   },
   "ignore": []
diff --git a/third_party/polymer/v1_0/components-chromium/iron-fit-behavior/iron-fit-behavior-extracted.js b/third_party/polymer/v1_0/components-chromium/iron-fit-behavior/iron-fit-behavior-extracted.js
index e6ebe2e..562b67c 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-fit-behavior/iron-fit-behavior-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/iron-fit-behavior/iron-fit-behavior-extracted.js
@@ -157,14 +157,14 @@
      * the memoized data.
      */
     resetFit: function() {
-      if (!this._fitInfo || !this._fitInfo.sizedBy.height) {
-        this.sizingTarget.style.maxHeight = '';
-        this.style.top = this._fitInfo ? this._fitInfo.inlineStyle.top : '';
-      }
       if (!this._fitInfo || !this._fitInfo.sizedBy.width) {
         this.sizingTarget.style.maxWidth = '';
-        this.style.left = this._fitInfo ? this._fitInfo.inlineStyle.left : '';
       }
+      if (!this._fitInfo || !this._fitInfo.sizedBy.height) {
+        this.sizingTarget.style.maxHeight = '';
+      }
+      this.style.top = this._fitInfo ? this._fitInfo.inlineStyle.top : '';
+      this.style.left = this._fitInfo ? this._fitInfo.inlineStyle.left : '';
       if (this._fitInfo) {
         this.style.position = this._fitInfo.positionedBy.css;
       }
@@ -225,18 +225,30 @@
      * `position:fixed`.
      */
     center: function() {
-      if (!this._fitInfo.positionedBy.vertically || !this._fitInfo.positionedBy.horizontally) {
-        // need position:fixed to center
-        this.style.position = 'fixed';
+      var positionedBy = this._fitInfo.positionedBy;
+      if (positionedBy.vertically && positionedBy.horizontally) {
+        // Already positioned.
+        return;
       }
-      if (!this._fitInfo.positionedBy.vertically) {
-        var top = (this._fitHeight - this.offsetHeight) / 2 + this._fitTop;
-        top -= this._fitInfo.margin.top;
+      // Need position:fixed to center
+      this.style.position = 'fixed';
+      // Take into account the offset caused by parents that create stacking
+      // contexts (e.g. with transform: translate3d). Translate to 0,0 and
+      // measure the bounding rect.
+      if (!positionedBy.vertically) {
+        this.style.top = '0px';
+      }
+      if (!positionedBy.horizontally) {
+        this.style.left = '0px';
+      }
+      // It will take in consideration margins and transforms
+      var rect = this.getBoundingClientRect();
+      if (!positionedBy.vertically) {
+        var top = this._fitTop - rect.top + (this._fitHeight - rect.height) / 2;
         this.style.top = top + 'px';
       }
-      if (!this._fitInfo.positionedBy.horizontally) {
-        var left = (this._fitWidth - this.offsetWidth) / 2 + this._fitLeft;
-        left -= this._fitInfo.margin.left;
+      if (!positionedBy.horizontally) {
+        var left = this._fitLeft - rect.left + (this._fitWidth - rect.width) / 2;
         this.style.left = left + 'px';
       }
     }
diff --git a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/.bower.json b/third_party/polymer/v1_0/components-chromium/iron-flex-layout/.bower.json
index 0985b73..3d6c4f44e 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/.bower.json
+++ b/third_party/polymer/v1_0/components-chromium/iron-flex-layout/.bower.json
@@ -1,6 +1,6 @@
 {
   "name": "iron-flex-layout",
-  "version": "1.2.2",
+  "version": "1.3.0",
   "description": "Provide flexbox-based layouts",
   "keywords": [
     "web-components",
@@ -21,19 +21,19 @@
     "polymer": "Polymer/polymer#^1.1.0"
   },
   "devDependencies": {
-    "paper-styles": "polymerelements/paper-styles#^1.0.0",
-    "marked-element": "polymerelements/marked-element#^1.0.0",
-    "prism-element": "PolymerElements/prism-element#^1.0.0",
+    "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
+    "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+    "test-fixture": "PolymerElements/test-fixture#^1.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
-    "iron-component-page": "polymerelements/iron-component-page#^1.0.0"
+    "web-component-tester": "^4.0.0"
   },
   "ignore": [],
   "homepage": "https://github.com/PolymerElements/iron-flex-layout",
-  "_release": "1.2.2",
+  "_release": "1.3.0",
   "_resolution": {
     "type": "version",
-    "tag": "v1.2.2",
-    "commit": "41c4f35be1368afb770312b907a258175565dbdf"
+    "tag": "v1.3.0",
+    "commit": "434224c8cf63cb4bb1b66edb0dc58e4484f7c5b2"
   },
   "_source": "git://github.com/PolymerElements/iron-flex-layout.git",
   "_target": "^1.0.0",
diff --git a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/CONTRIBUTING.md b/third_party/polymer/v1_0/components-chromium/iron-flex-layout/CONTRIBUTING.md
index 7b101415..f147978a 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/CONTRIBUTING.md
+++ b/third_party/polymer/v1_0/components-chromium/iron-flex-layout/CONTRIBUTING.md
@@ -5,6 +5,11 @@
 
 If you edit that file, it will get updated everywhere else.
 If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
 -->
 # Polymer Elements
 ## Guide for Contributors
@@ -41,7 +46,7 @@
  3. Click the `paper-foo` element.
  ```
 
- 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [http://jsbin.com/cagaye](http://jsbin.com/cagaye/edit?html,output).
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
 
  3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
 
@@ -51,14 +56,14 @@
 
 When submitting pull requests, please provide:
 
- 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues using the following syntax:
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
 
  ```markdown
  (For a single issue)
  Fixes #20
 
  (For multiple issues)
- Fixes #32, #40
+ Fixes #32, fixes #40
  ```
 
  2. **A succinct description of the design** used to fix any related issues. For example:
diff --git a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/README.md b/third_party/polymer/v1_0/components-chromium/iron-flex-layout/README.md
index 3651696..804099f 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/README.md
+++ b/third_party/polymer/v1_0/components-chromium/iron-flex-layout/README.md
@@ -7,21 +7,26 @@
 Edit those files, and our readme bot will duplicate them over here!
 Edit this file, and the bot will squash your changes :)
 
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
 -->
 
-[![Build Status](https://travis-ci.org/PolymerElements/iron-flex-layout.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-flex-layout)
+[![Build status](https://travis-ci.org/PolymerElements/iron-flex-layout.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-flex-layout)
 
-_[Demo and API Docs](https://elements.polymer-project.org/elements/iron-flex-layout)_
+_[Demo and API docs](https://elements.polymer-project.org/elements/iron-flex-layout)_
 
 
 ##&lt;iron-flex-layout&gt;
 
-
 The `<iron-flex-layout>` component provides simple ways to use [CSS flexible box layout](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Flexible_boxes), also known as flexbox. This component provides two different ways to use flexbox:
 
 1. [Layout classes](https://github.com/PolymerElements/iron-flex-layout/tree/master/classes). The layout class stylesheet provides a simple set of class-based flexbox rules. Layout classes let you specify layout properties directly in markup.
 
-2. [Custom CSS mixins](https://github.com/PolymerElements/iron-flex-layout/blob/master/iron-flex-layout.html). The mixin stylesheet includes custom CSS mixins that can be applied inside a CSS rule using the `@apply` function.
+
+1. [Custom CSS mixins](https://github.com/PolymerElements/iron-flex-layout/blob/master/iron-flex-layout.html). The mixin stylesheet includes custom CSS mixins that can be applied inside a CSS rule using the `@apply` function.
+
+
 
 A complete [guide](https://elements.polymer-project.org/guides/flex-layout) to `<iron-flex-layout>` is available.
 
diff --git a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/bower.json b/third_party/polymer/v1_0/components-chromium/iron-flex-layout/bower.json
index 3a96d32a..838fd42ed 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/bower.json
+++ b/third_party/polymer/v1_0/components-chromium/iron-flex-layout/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "iron-flex-layout",
-  "version": "1.2.2",
+  "version": "1.3.0",
   "description": "Provide flexbox-based layouts",
   "keywords": [
     "web-components",
@@ -21,11 +21,11 @@
     "polymer": "Polymer/polymer#^1.1.0"
   },
   "devDependencies": {
-    "paper-styles": "polymerelements/paper-styles#^1.0.0",
-    "marked-element": "polymerelements/marked-element#^1.0.0",
-    "prism-element": "PolymerElements/prism-element#^1.0.0",
+    "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
+    "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+    "test-fixture": "PolymerElements/test-fixture#^1.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
-    "iron-component-page": "polymerelements/iron-component-page#^1.0.0"
+    "web-component-tester": "^4.0.0"
   },
   "ignore": []
 }
diff --git a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/compiled_resources2.gyp b/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/compiled_resources2.gyp
index 0ec9182c..daa6f8a 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/compiled_resources2.gyp
+++ b/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/compiled_resources2.gyp
@@ -7,6 +7,9 @@
   'targets': [
     {
       'target_name': 'iron-flex-layout-extracted',
+      'dependencies': [
+        'iron-shadow-flex-layout-extracted',
+      ],
       'includes': ['../../../../../closure_compiler/compile_js2.gypi'],
     },
     {
diff --git a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-flex-layout-extracted.js b/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-flex-layout-extracted.js
new file mode 100644
index 0000000..418f5a5
--- /dev/null
+++ b/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-flex-layout-extracted.js
@@ -0,0 +1 @@
+console.warn('This file is deprecated. Please use `iron-flex-layout/iron-flex-layout-classes.html`, and one of the specific dom-modules instead');
\ No newline at end of file
diff --git a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-flex-layout.html b/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-flex-layout.html
index 283c2a8d..1d0cab5 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-flex-layout.html
+++ b/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-flex-layout.html
@@ -6,9 +6,7 @@
 The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
 Code distributed by Google as part of the polymer project is also
 subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
--->
-
-<link rel="import" href="iron-shadow-flex-layout.html">
+--><html><head><link rel="import" href="iron-shadow-flex-layout.html">
 
 <style>
 
@@ -305,3 +303,4 @@
   }
 
 </style>
+</head><body><script src="iron-flex-layout-extracted.js"></script></body></html>
\ No newline at end of file
diff --git a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-shadow-flex-layout-extracted.js b/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-shadow-flex-layout-extracted.js
new file mode 100644
index 0000000..418f5a5
--- /dev/null
+++ b/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-shadow-flex-layout-extracted.js
@@ -0,0 +1 @@
+console.warn('This file is deprecated. Please use `iron-flex-layout/iron-flex-layout-classes.html`, and one of the specific dom-modules instead');
\ No newline at end of file
diff --git a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-shadow-flex-layout.html b/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-shadow-flex-layout.html
index fe55ec8..ce7bb4e 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-shadow-flex-layout.html
+++ b/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-shadow-flex-layout.html
@@ -6,8 +6,7 @@
 The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
 Code distributed by Google as part of the polymer project is also
 subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
--->
-<style>
+--><html><head><style>
 
   /*******************************
             Flex Layout
@@ -300,3 +299,4 @@
   }
 
 </style>
+</head><body><script src="iron-shadow-flex-layout-extracted.js"></script></body></html>
\ No newline at end of file
diff --git a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/compiled_resources2.gyp b/third_party/polymer/v1_0/components-chromium/iron-flex-layout/compiled_resources2.gyp
index 208618e..bbc8aa6 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/compiled_resources2.gyp
+++ b/third_party/polymer/v1_0/components-chromium/iron-flex-layout/compiled_resources2.gyp
@@ -6,6 +6,10 @@
 {
   'targets': [
     {
+      'target_name': 'iron-flex-layout-classes-extracted',
+      'includes': ['../../../../closure_compiler/compile_js2.gypi'],
+    },
+    {
       'target_name': 'iron-flex-layout-extracted',
       'includes': ['../../../../closure_compiler/compile_js2.gypi'],
     },
diff --git a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/iron-flex-layout-classes.html b/third_party/polymer/v1_0/components-chromium/iron-flex-layout/iron-flex-layout-classes.html
new file mode 100644
index 0000000..2b8cd1a
--- /dev/null
+++ b/third_party/polymer/v1_0/components-chromium/iron-flex-layout/iron-flex-layout-classes.html
@@ -0,0 +1,381 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<!--
+A set of layout classes that let you specify layout properties directly in markup.
+You must include this file in every element that needs to use them.
+
+Sample use:
+
+    <link rel="import" href="../iron-flex-layout/iron-flex-layout-classes.html">
+    <style is="custom-style" include="iron-flex iron-flex-alignment">
+
+    <div class="layout horizontal layout-start">
+      <div>cross axis start alignment</div>
+    </div>
+
+The following imports are available:
+ - iron-flex
+ - iron-flex-reverse
+ - iron-flex-alignment
+ - iron-flex-factors
+ - iron-positioning
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+
+<!-- Most common used flex styles-->
+<dom-module id="iron-flex">
+  <template>
+    <style>
+      .layout.horizontal,
+      .layout.vertical {
+        display: -ms-flexbox;
+        display: -webkit-flex;
+        display: flex;
+      }
+
+      .layout.inline {
+        display: -ms-inline-flexbox;
+        display: -webkit-inline-flex;
+        display: inline-flex;
+      }
+
+      .layout.horizontal {
+        -ms-flex-direction: row;
+        -webkit-flex-direction: row;
+        flex-direction: row;
+      }
+
+      .layout.vertical {
+        -ms-flex-direction: column;
+        -webkit-flex-direction: column;
+        flex-direction: column;
+      }
+
+      .layout.wrap {
+        -ms-flex-wrap: wrap;
+        -webkit-flex-wrap: wrap;
+        flex-wrap: wrap;
+      }
+
+      .layout.center,
+      .layout.center-center {
+        -ms-flex-align: center;
+        -webkit-align-items: center;
+        align-items: center;
+      }
+
+      .layout.center-justified,
+      .layout.center-center {
+        -ms-flex-pack: center;
+        -webkit-justify-content: center;
+        justify-content: center;
+      }
+
+      .flex {
+        -ms-flex: 1 1 0.000000001px;
+        -webkit-flex: 1;
+        flex: 1;
+        -webkit-flex-basis: 0.000000001px;
+        flex-basis: 0.000000001px;
+      }
+
+      .flex-auto {
+        -ms-flex: 1 1 auto;
+        -webkit-flex: 1 1 auto;
+        flex: 1 1 auto;
+      }
+
+      .flex-none {
+        -ms-flex: none;
+        -webkit-flex: none;
+        flex: none;
+      }
+    </style>
+  </template>
+</dom-module>
+
+<!-- Basic flexbox reverse styles -->
+<dom-module id="iron-flex-reverse">
+  <template>
+    <style>
+      .layout.horizontal-reverse,
+      .layout.vertical-reverse {
+        display: -ms-flexbox;
+        display: -webkit-flex;
+        display: flex;
+      }
+
+      .layout.horizontal-reverse {
+        -ms-flex-direction: row-reverse;
+        -webkit-flex-direction: row-reverse;
+        flex-direction: row-reverse;
+      }
+
+      .layout.vertical-reverse {
+        -ms-flex-direction: column-reverse;
+        -webkit-flex-direction: column-reverse;
+        flex-direction: column-reverse;
+      }
+
+      .layout.wrap-reverse {
+        -ms-flex-wrap: wrap-reverse;
+        -webkit-flex-wrap: wrap-reverse;
+        flex-wrap: wrap-reverse;
+      }
+    </style>
+  </template>
+</dom-module>
+
+<!-- Flexbox alignment -->
+<dom-module id="iron-flex-alignment">
+  <template>
+    <style>
+      /**
+       * Alignment in cross axis.
+       */
+      .layout.start {
+        -ms-flex-align: start;
+        -webkit-align-items: flex-start;
+        align-items: flex-start;
+      }
+
+      .layout.center,
+      .layout.center-center {
+        -ms-flex-align: center;
+        -webkit-align-items: center;
+        align-items: center;
+      }
+
+      .layout.end {
+        -ms-flex-align: end;
+        -webkit-align-items: flex-end;
+        align-items: flex-end;
+      }
+
+      /**
+       * Alignment in main axis.
+       */
+      .layout.start-justified {
+        -ms-flex-pack: start;
+        -webkit-justify-content: flex-start;
+        justify-content: flex-start;
+      }
+
+      .layout.center-justified,
+      .layout.center-center {
+        -ms-flex-pack: center;
+        -webkit-justify-content: center;
+        justify-content: center;
+      }
+
+      .layout.end-justified {
+        -ms-flex-pack: end;
+        -webkit-justify-content: flex-end;
+        justify-content: flex-end;
+      }
+
+      .layout.around-justified {
+        -ms-flex-pack: distribute;
+        -webkit-justify-content: space-around;
+        justify-content: space-around;
+      }
+
+      .layout.justified {
+        -ms-flex-pack: justify;
+        -webkit-justify-content: space-between;
+        justify-content: space-between;
+      }
+
+      /**
+       * Self alignment.
+       */
+      .self-start {
+        -ms-align-self: flex-start;
+        -webkit-align-self: flex-start;
+        align-self: flex-start;
+      }
+
+      .self-center {
+        -ms-align-self: center;
+        -webkit-align-self: center;
+        align-self: center;
+      }
+
+      .self-end {
+        -ms-align-self: flex-end;
+        -webkit-align-self: flex-end;
+        align-self: flex-end;
+      }
+
+      .self-stretch {
+        -ms-align-self: stretch;
+        -webkit-align-self: stretch;
+        align-self: stretch;
+      }
+    </style>
+  </template>
+</dom-module>
+
+<dom-module id="iron-flex-factors">
+  <template>
+    <style>
+      .flex,
+      .flex-1 {
+        -ms-flex: 1 1 0.000000001px;
+        -webkit-flex: 1;
+        flex: 1;
+        -webkit-flex-basis: 0.000000001px;
+        flex-basis: 0.000000001px;
+      }
+
+      .flex-2 {
+        -ms-flex: 2;
+        -webkit-flex: 2;
+        flex: 2;
+      }
+
+      .flex-3 {
+        -ms-flex: 3;
+        -webkit-flex: 3;
+        flex: 3;
+      }
+
+      .flex-4 {
+        -ms-flex: 4;
+        -webkit-flex: 4;
+        flex: 4;
+      }
+
+      .flex-5 {
+        -ms-flex: 5;
+        -webkit-flex: 5;
+        flex: 5;
+      }
+
+      .flex-6 {
+        -ms-flex: 6;
+        -webkit-flex: 6;
+        flex: 6;
+      }
+
+      .flex-7 {
+        -ms-flex: 7;
+        -webkit-flex: 7;
+        flex: 7;
+      }
+
+      .flex-8 {
+        -ms-flex: 8;
+        -webkit-flex: 8;
+        flex: 8;
+      }
+
+      .flex-9 {
+        -ms-flex: 9;
+        -webkit-flex: 9;
+        flex: 9;
+      }
+
+      .flex-10 {
+        -ms-flex: 10;
+        -webkit-flex: 10;
+        flex: 10;
+      }
+
+      .flex-11 {
+        -ms-flex: 11;
+        -webkit-flex: 11;
+        flex: 11;
+      }
+
+      .flex-12 {
+        -ms-flex: 12;
+        -webkit-flex: 12;
+        flex: 12;
+      }
+    </style>
+  </template>
+</dom-module>
+
+<!-- Non-flexbox positioning helper styles -->
+<dom-module id="iron-positioning">
+  <template>
+    <style>
+      .block {
+        display: block;
+      }
+
+      /* IE 10 support for HTML5 hidden attr */
+      [hidden] {
+        display: none !important;
+      }
+
+      .invisible {
+        visibility: hidden !important;
+      }
+
+      .relative {
+        position: relative;
+      }
+
+      .fit {
+        position: absolute;
+        top: 0;
+        right: 0;
+        bottom: 0;
+        left: 0;
+      }
+
+      body.fullbleed {
+        margin: 0;
+        height: 100vh;
+      }
+
+      .scroll {
+        -webkit-overflow-scrolling: touch;
+        overflow: auto;
+      }
+
+      /* fixed position */
+      .fixed-bottom,
+      .fixed-left,
+      .fixed-right,
+      .fixed-top {
+        position: fixed;
+      }
+
+      .fixed-top {
+        top: 0;
+        left: 0;
+        right: 0;
+      }
+
+      .fixed-right {
+        top: 0;
+        right: 0;
+        bottom: 0;
+      }
+
+      .fixed-bottom {
+        right: 0;
+        bottom: 0;
+        left: 0;
+      }
+
+      .fixed-left {
+        top: 0;
+        bottom: 0;
+        left: 0;
+      }
+    </style>
+  </template>
+</dom-module>
diff --git a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/iron-flex-layout.html b/third_party/polymer/v1_0/components-chromium/iron-flex-layout/iron-flex-layout.html
index 09b4657a..7315faf 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/iron-flex-layout.html
+++ b/third_party/polymer/v1_0/components-chromium/iron-flex-layout/iron-flex-layout.html
@@ -11,11 +11,33 @@
 <link rel="import" href="../polymer/polymer.html">
 
 <!--
-The `<iron-flex-layout>` component provides simple ways to use [CSS flexible box layout](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Flexible_boxes), also known as flexbox. This component provides two different ways to use flexbox:
+The `<iron-flex-layout>` component provides simple ways to use
+[CSS flexible box layout](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Flexible_boxes),
+also known as flexbox. This component provides two different ways to use flexbox:
 
-1. [Layout classes](https://github.com/PolymerElements/iron-flex-layout/tree/master/classes). The layout class stylesheet provides a simple set of class-based flexbox rules. Layout classes let you specify layout properties directly in markup.
+1. [Layout classes](https://github.com/PolymerElements/iron-flex-layout/tree/master/iron-flex-layout-classes.html).
+The layout class stylesheet provides a simple set of class-based flexbox rules, that
+let you specify layout properties directly in markup. You must include this file
+in every element that needs to use them.
 
-2. [Custom CSS mixins](https://github.com/PolymerElements/iron-flex-layout/blob/master/iron-flex-layout.html). The mixin stylesheet includes custom CSS mixins that can be applied inside a CSS rule using the `@apply` function.
+Sample use:
+
+    <link rel="import" href="../iron-flex-layout/iron-flex-layout-classes.html">
+    <style is="custom-style" include="iron-flex iron-flex-alignment">
+
+    <div class="layout horizontal layout-start">
+      <div>cross axis start alignment</div>
+    </div>
+
+2. [Custom CSS mixins](https://github.com/PolymerElements/iron-flex-layout/blob/master/iron-flex-layout.html).
+The mixin stylesheet includes custom CSS mixins that can be applied inside a CSS rule using the `@apply` function.
+
+Please note that the old [/deep/ layout classes](https://github.com/PolymerElements/iron-flex-layout/tree/master/classes)
+are deprecated, and should not be used. To continue using layout properties
+directly in markup, please switch to using the new `dom-module`-based
+[layout classes](https://github.com/PolymerElements/iron-flex-layout/tree/master/iron-flex-layout-classes.html).
+Please note that the new version does not use `/deep/`, and therefore requires you
+to import the `dom-modules` in every element that needs to use them.
 
 A complete [guide](https://elements.polymer-project.org/guides/flex-layout) to `<iron-flex-layout>` is available.
 
@@ -217,7 +239,7 @@
     };
 
     --layout-around-justified: {
-      -ms-flex-pack: around;
+      -ms-flex-pack: distribute;
       -webkit-justify-content: space-around;
       justify-content: space-around;
     };
diff --git a/third_party/polymer/v1_0/components-chromium/iron-icon/.bower.json b/third_party/polymer/v1_0/components-chromium/iron-icon/.bower.json
index 75ac273..9784e3a3 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-icon/.bower.json
+++ b/third_party/polymer/v1_0/components-chromium/iron-icon/.bower.json
@@ -1,7 +1,7 @@
 {
   "name": "iron-icon",
   "private": true,
-  "version": "1.0.7",
+  "version": "1.0.8",
   "license": "http://polymer.github.io/LICENSE.txt",
   "description": "An element that supports displaying an icon",
   "main": "iron-icon.html",
@@ -17,6 +17,7 @@
     "type": "git",
     "url": "git://github.com/PolymerElements/iron-icon.git"
   },
+  "ignore": [],
   "dependencies": {
     "iron-flex-layout": "polymerelements/iron-flex-layout#^1.0.0",
     "iron-meta": "polymerelements/iron-meta#^1.0.0",
@@ -28,15 +29,15 @@
     "iron-iconset": "polymerelements/iron-iconset#^1.0.0",
     "iron-icons": "polymerelements/iron-icons#^1.0.0",
     "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
-    "web-component-tester": "*",
+    "web-component-tester": "^4.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
   },
   "homepage": "https://github.com/PolymerElements/iron-icon",
-  "_release": "1.0.7",
+  "_release": "1.0.8",
   "_resolution": {
     "type": "version",
-    "tag": "v1.0.7",
-    "commit": "6f4d152dc3998a6cc12a5a585a654f893dc99381"
+    "tag": "v1.0.8",
+    "commit": "f36b38928849ef3853db727faa8c9ef104d611eb"
   },
   "_source": "git://github.com/PolymerElements/iron-icon.git",
   "_target": "^1.0.0",
diff --git a/third_party/polymer/v1_0/components-chromium/iron-icon/CONTRIBUTING.md b/third_party/polymer/v1_0/components-chromium/iron-icon/CONTRIBUTING.md
new file mode 100644
index 0000000..f147978a
--- /dev/null
+++ b/third_party/polymer/v1_0/components-chromium/iron-icon/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/third_party/polymer/v1_0/components-chromium/iron-icon/README.md b/third_party/polymer/v1_0/components-chromium/iron-icon/README.md
index 27b65c0..a08298f 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-icon/README.md
+++ b/third_party/polymer/v1_0/components-chromium/iron-icon/README.md
@@ -1,5 +1,23 @@
-iron-icon
-=========
+
+<!---
+
+This README is automatically generated from the comments in these files:
+iron-icon.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/iron-icon.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-icon)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/iron-icon)_
+
+
+##&lt;iron-icon&gt;
 
 The `iron-icon` element displays an icon. By default an icon renders as a 24px square.
 
@@ -14,29 +32,28 @@
 ```html
 <iron-icon class="big" src="big_star.png"></iron-icon>
 
-<style>
+<style is="custom-style">
   .big {
-    height: 32px;
-    width: 32px;
+    --iron-icon-height: 32px;
+    --iron-icon-width: 32px;
   }
 </style>
 ```
 
 The iron elements include several sets of icons.
-To use the default set of icons, import  `iron-icons.html` and use the `icon` attribute to specify an icon:
+To use the default set of icons, import `iron-icons.html` and use the `icon` attribute to specify an icon:
 
 ```html
-<!-- import default iconset and iron-icon -->
 <link rel="import" href="/components/iron-icons/iron-icons.html">
 
 <iron-icon icon="menu"></iron-icon>
 ```
 
-To use a different built-in set of icons, import  `iron-icons/<iconset>-icons.html`, and
-specify the icon as `<iconset>:<icon>`. For example:
+To use a different built-in set of icons, import the specific `iron-icons/<iconset>-icons.html`, and
+specify the icon as `<iconset>:<icon>`. For example, to use a communication icon, you would
+use:
 
 ```html
-<!-- import communication iconset and iron-icon -->
 <link rel="import" href="/components/iron-icons/communication-icons.html">
 
 <iron-icon icon="communication:email"></iron-icon>
@@ -50,7 +67,26 @@
 <iron-icon icon="fruit:cherry"></iron-icon>
 ```
 
-See [iron-iconset](#iron-iconset) and [iron-iconset-svg](#iron-iconset-svg) for more information about
+See [iron-iconset](iron-iconset) and [iron-iconset-svg](iron-iconset-svg) for more information about
 how to create a custom iconset.
 
-See [iron-icons](http://www.polymer-project.org/components/iron-icons/demo.html) for the default set of icons.
+See the [iron-icons demo](iron-icons?view=demo:demo/index.html) to see the icons available
+in the various iconsets.
+
+To load a subset of icons from one of the default `iron-icons` sets, you can
+use the [poly-icon](https://poly-icon.appspot.com/) tool. It allows you
+to select individual icons, and creates an iconset from them that you can
+use directly in your elements.
+
+### Styling
+
+The following custom properties are available for styling:
+
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--iron-icon-width` | Width of the icon | `24px` |
+| `--iron-icon-height` | Height of the icon | `24px` |
+| `--iron-icon-fill-color` | Fill color of the svg icon | `currentcolor` |
+| `--iron-icon-stroke-color` | Stroke color of the svg icon | none |
+
+
diff --git a/third_party/polymer/v1_0/components-chromium/iron-icon/bower.json b/third_party/polymer/v1_0/components-chromium/iron-icon/bower.json
index 6693f96..38e4ba45 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-icon/bower.json
+++ b/third_party/polymer/v1_0/components-chromium/iron-icon/bower.json
@@ -1,7 +1,7 @@
 {
   "name": "iron-icon",
   "private": true,
-  "version": "1.0.7",
+  "version": "1.0.8",
   "license": "http://polymer.github.io/LICENSE.txt",
   "description": "An element that supports displaying an icon",
   "main": "iron-icon.html",
@@ -17,6 +17,7 @@
     "type": "git",
     "url": "git://github.com/PolymerElements/iron-icon.git"
   },
+  "ignore": [],
   "dependencies": {
     "iron-flex-layout": "polymerelements/iron-flex-layout#^1.0.0",
     "iron-meta": "polymerelements/iron-meta#^1.0.0",
@@ -28,7 +29,7 @@
     "iron-iconset": "polymerelements/iron-iconset#^1.0.0",
     "iron-icons": "polymerelements/iron-icons#^1.0.0",
     "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
-    "web-component-tester": "*",
+    "web-component-tester": "^4.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
   }
 }
diff --git a/third_party/polymer/v1_0/components-chromium/iron-icon/index.html b/third_party/polymer/v1_0/components-chromium/iron-icon/index.html
index e871f17d..487bb5c 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-icon/index.html
+++ b/third_party/polymer/v1_0/components-chromium/iron-icon/index.html
@@ -2,11 +2,11 @@
 <!--
 @license
 Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
-This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE
-The complete set of authors may be found at http://polymer.github.io/AUTHORS
-The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
 Code distributed by Google as part of the polymer project is also
-subject to an additional IP rights grant found at http://polymer.github.io/PATENTS
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 -->
 <html>
 <head>
diff --git a/third_party/polymer/v1_0/components-chromium/iron-icon/iron-icon-extracted.js b/third_party/polymer/v1_0/components-chromium/iron-icon/iron-icon-extracted.js
index cbf6f2a..1f61c65 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-icon/iron-icon-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/iron-icon/iron-icon-extracted.js
@@ -36,7 +36,8 @@
          * @type {!Polymer.IronMeta}
          */
         _meta: {
-          value: Polymer.Base.create('iron-meta', {type: 'iconset'})
+          value: Polymer.Base.create('iron-meta', {type: 'iconset'}),
+          observer: '_updateIcon'
         }
 
       },
@@ -61,7 +62,14 @@
       /** @suppress {visibility} */
       _updateIcon: function() {
         if (this._usesIconset()) {
-          if (this._iconsetName) {
+          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 = /** @type {?Polymer.Iconset} */ (
               this._meta.byKey(this._iconsetName));
             if (this._iconset) {
@@ -72,6 +80,9 @@
             }
           }
         } else {
+          if (this._iconset) {
+            this._iconset.removeIcon(this);
+          }
           if (!this._img) {
             this._img = document.createElement('img');
             this._img.style.width = '100%';
diff --git a/third_party/polymer/v1_0/components-chromium/iron-icon/iron-icon.html b/third_party/polymer/v1_0/components-chromium/iron-icon/iron-icon.html
index 5101f82f..e395853c 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-icon/iron-icon.html
+++ b/third_party/polymer/v1_0/components-chromium/iron-icon/iron-icon.html
@@ -56,6 +56,10 @@
 See the [iron-icons demo](iron-icons?view=demo:demo/index.html) to see the icons available
 in the various iconsets.
 
+To load a subset of icons from one of the default `iron-icons` sets, you can
+use the [poly-icon](https://poly-icon.appspot.com/) tool. It allows you
+to select individual icons, and creates an iconset from them that you can
+use directly in your elements.
 
 ### Styling
 
diff --git a/third_party/polymer/v1_0/components-chromium/iron-list/.bower.json b/third_party/polymer/v1_0/components-chromium/iron-list/.bower.json
index 6340b3c..1217d66 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-list/.bower.json
+++ b/third_party/polymer/v1_0/components-chromium/iron-list/.bower.json
@@ -7,7 +7,7 @@
     "list",
     "virtual-list"
   ],
-  "version": "1.2.3",
+  "version": "1.2.7",
   "homepage": "https://github.com/PolymerElements/iron-list",
   "authors": [
     "The Polymer Authors"
@@ -33,6 +33,7 @@
     "iron-icon": "polymerelements/iron-icon#^1.0.0",
     "iron-icons": "polymerelements/iron-icons#^1.0.0",
     "iron-scroll-threshold": "polymerelements/iron-scroll-threshold#^1.0.0",
+    "iron-image": "polymerelements/iron-image#^1.0.0",
     "paper-menu": "polymerelements/paper-menu#^1.0.0",
     "paper-item": "polymerelements/paper-item#^1.0.0",
     "paper-icon-button": "polymerelements/paper-icon-button#^1.0.0",
@@ -44,11 +45,11 @@
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.2",
     "web-component-tester": "^4.0.0"
   },
-  "_release": "1.2.3",
+  "_release": "1.2.7",
   "_resolution": {
     "type": "version",
-    "tag": "v1.2.3",
-    "commit": "07957dc10616341606ae030d78bb41492fb7c0cc"
+    "tag": "v1.2.7",
+    "commit": "3de2382811553456af4cc8fc9772dac9fbdff41b"
   },
   "_source": "git://github.com/PolymerElements/iron-list.git",
   "_target": "^1.0.0",
diff --git a/third_party/polymer/v1_0/components-chromium/iron-list/CONTRIBUTING.md b/third_party/polymer/v1_0/components-chromium/iron-list/CONTRIBUTING.md
index 7b101415..f147978a 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-list/CONTRIBUTING.md
+++ b/third_party/polymer/v1_0/components-chromium/iron-list/CONTRIBUTING.md
@@ -5,6 +5,11 @@
 
 If you edit that file, it will get updated everywhere else.
 If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
 -->
 # Polymer Elements
 ## Guide for Contributors
@@ -41,7 +46,7 @@
  3. Click the `paper-foo` element.
  ```
 
- 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [http://jsbin.com/cagaye](http://jsbin.com/cagaye/edit?html,output).
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
 
  3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
 
@@ -51,14 +56,14 @@
 
 When submitting pull requests, please provide:
 
- 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues using the following syntax:
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
 
  ```markdown
  (For a single issue)
  Fixes #20
 
  (For multiple issues)
- Fixes #32, #40
+ Fixes #32, fixes #40
  ```
 
  2. **A succinct description of the design** used to fix any related issues. For example:
diff --git a/third_party/polymer/v1_0/components-chromium/iron-list/README.md b/third_party/polymer/v1_0/components-chromium/iron-list/README.md
index 45dba70..a4386c1a 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-list/README.md
+++ b/third_party/polymer/v1_0/components-chromium/iron-list/README.md
@@ -12,9 +12,9 @@
 
 -->
 
-[![Build Status](https://travis-ci.org/PolymerElements/iron-list.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-list)
+[![Build status](https://travis-ci.org/PolymerElements/iron-list.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-list)
 
-_[Demo and API Docs](https://elements.polymer-project.org/elements/iron-list)_
+_[Demo and API docs](https://elements.polymer-project.org/elements/iron-list)_
 
 
 ##&lt;iron-list&gt;
diff --git a/third_party/polymer/v1_0/components-chromium/iron-list/bower.json b/third_party/polymer/v1_0/components-chromium/iron-list/bower.json
index 50bb130a..db9148c 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-list/bower.json
+++ b/third_party/polymer/v1_0/components-chromium/iron-list/bower.json
@@ -7,7 +7,7 @@
     "list",
     "virtual-list"
   ],
-  "version": "1.2.3",
+  "version": "1.2.7",
   "homepage": "https://github.com/PolymerElements/iron-list",
   "authors": [
     "The Polymer Authors"
@@ -33,6 +33,7 @@
     "iron-icon": "polymerelements/iron-icon#^1.0.0",
     "iron-icons": "polymerelements/iron-icons#^1.0.0",
     "iron-scroll-threshold": "polymerelements/iron-scroll-threshold#^1.0.0",
+    "iron-image": "polymerelements/iron-image#^1.0.0",
     "paper-menu": "polymerelements/paper-menu#^1.0.0",
     "paper-item": "polymerelements/paper-item#^1.0.0",
     "paper-icon-button": "polymerelements/paper-icon-button#^1.0.0",
diff --git a/third_party/polymer/v1_0/components-chromium/iron-list/iron-list-extracted.js b/third_party/polymer/v1_0/components-chromium/iron-list/iron-list-extracted.js
index 8a0ee871..6bcafe8f 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-list/iron-list-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/iron-list/iron-list-extracted.js
@@ -118,7 +118,7 @@
     _ratio: 0.5,
 
     /**
-     * The padding-top value of the `scroller` element
+     * The padding-top value for the list.
      */
     _scrollerPaddingTop: 0,
 
@@ -128,21 +128,6 @@
     _scrollPosition: 0,
 
     /**
-     * The number of tiles in the DOM.
-     */
-    _physicalCount: 0,
-
-    /**
-     * The k-th tile that is at the top of the scrolling list.
-     */
-    _physicalStart: 0,
-
-    /**
-     * The k-th tile that is at the bottom of the scrolling list.
-     */
-    _physicalEnd: 0,
-
-    /**
      * The sum of the heights of all the tiles in the DOM.
      */
     _physicalSize: 0,
@@ -169,11 +154,6 @@
     _virtualCount: 0,
 
     /**
-     * The n-th item rendered in the `_physicalStart` tile.
-     */
-    _virtualStartVal: 0,
-
-    /**
      * A map between an item key and its physical item index
      */
     _physicalIndexForKey: null,
@@ -219,7 +199,6 @@
      */
     _lastVisibleIndexVal: null,
 
-
     /**
      * A Polymer collection for the items.
      * @type {?Polymer.Collection}
@@ -243,9 +222,14 @@
     _maxPages: 3,
 
     /**
-     * The currently focused item index.
+     * The currently focused physical item.
      */
-    _focusedIndex: 0,
+    _focusedItem: null,
+
+    /**
+     * The index of the `_focusedItem`.
+     */
+    _focusedIndex: -1,
 
     /**
      * The the item that is focused if it is moved offscreen.
@@ -281,6 +265,20 @@
     },
 
     /**
+     * The height of the physical content that isn't on the screen.
+     */
+    get _hiddenContentSize() {
+      return this._physicalSize - this._viewportSize;
+    },
+
+    /**
+     * The maximum scroll top value.
+     */
+    get _maxScrollTop() {
+      return this._estScrollHeight - this._viewportSize + this._scrollerPaddingTop;
+    },
+
+    /**
      * The lowest n-th value for an item such that it can be rendered in `_physicalStart`.
      */
     _minVirtualStart: 0,
@@ -293,41 +291,54 @@
     },
 
     /**
-     * The height of the physical content that isn't on the screen.
+     * The n-th item rendered in the `_physicalStart` tile.
      */
-    get _hiddenContentSize() {
-      return this._physicalSize - this._viewportSize;
-    },
+    _virtualStartVal: 0,
 
-    /**
-     * The maximum scroll top value.
-     */
-    get _maxScrollTop() {
-      return this._estScrollHeight - this._viewportSize;
-    },
-
-    /**
-     * Sets the n-th item rendered in `_physicalStart`
-     */
     set _virtualStart(val) {
-      // clamp the value so that _minVirtualStart <= val <= _maxVirtualStart
       this._virtualStartVal = Math.min(this._maxVirtualStart, Math.max(this._minVirtualStart, val));
-      if (this._physicalCount === 0)  {
-        this._physicalStart = 0;
-        this._physicalEnd = 0;
-      } else {
-        this._physicalStart = this._virtualStartVal % this._physicalCount;
-        this._physicalEnd = (this._physicalStart + this._physicalCount - 1) % this._physicalCount;
-      }
+    },
+
+    get _virtualStart() {
+      return this._virtualStartVal || 0;
     },
 
     /**
-     * Gets the n-th item rendered in `_physicalStart`
+     * The k-th tile that is at the top of the scrolling list.
      */
-    get _virtualStart() {
-      return this._virtualStartVal;
+    _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;
+    },
+
+    /**
+     * The number of tiles in the DOM.
+     */
+    _physicalCountVal: 0,
+
+    set _physicalCount(val) {
+      this._physicalCountVal = val;
+      this._physicalEnd = (this._physicalStart + this._physicalCount - 1) % this._physicalCount;
+    },
+
+    get _physicalCount() {
+      return this._physicalCountVal;
+    },
+
+    /**
+     * The k-th tile that is at the bottom of the scrolling list.
+     */
+    _physicalEnd: 0,
+
     /**
      * An optimal physical size such that we will have enough physical items
      * to fill up the viewport and recycle when the user scrolls.
@@ -353,12 +364,11 @@
      */
     get firstVisibleIndex() {
       if (this._firstVisibleIndexVal === null) {
-        var physicalOffset = this._physicalTop;
+        var physicalOffset = this._physicalTop + this._scrollerPaddingTop;
 
         this._firstVisibleIndexVal = this._iterateItems(
           function(pidx, vidx) {
             physicalOffset += this._physicalSizes[pidx];
-
             if (physicalOffset > this._scrollPosition) {
               return vidx;
             }
@@ -379,14 +389,18 @@
         this._iterateItems(function(pidx, vidx) {
           physicalOffset += this._physicalSizes[pidx];
 
-          if(physicalOffset <= this._scrollBottom) {
-              this._lastVisibleIndexVal = vidx;
+          if (physicalOffset <= this._scrollBottom) {
+            this._lastVisibleIndexVal = vidx;
           }
         });
       }
       return this._lastVisibleIndexVal;
     },
 
+    get _defaultScrollTarget() {
+      return this;
+    },
+
     ready: function() {
       this.addEventListener('focus', this._didFocus.bind(this), true);
     },
@@ -400,10 +414,6 @@
       this._itemsRendered = false;
     },
 
-    get _defaultScrollTarget() {
-      return this;
-    },
-
     /**
      * Set the overflow property if this element has its own scrolling region
      */
@@ -419,8 +429,9 @@
      * @method updateViewportBoundaries
      */
     updateViewportBoundaries: function() {
-      var scrollerStyle = window.getComputedStyle(this.scrollTarget);
-      this._scrollerPaddingTop = parseInt(scrollerStyle['padding-top'], 10);
+      this._scrollerPaddingTop = this.scrollTarget === this ? 0 :
+          parseInt(window.getComputedStyle(this)['padding-top'], 10);
+
       this._viewportSize = this._scrollTargetHeight;
     },
 
@@ -430,12 +441,10 @@
      */
     _scrollHandler: function() {
       // clamp the `scrollTop` value
-      // IE 10|11 scrollTop may go above `_maxScrollTop`
-      // iOS `scrollTop` may go below 0 and above `_maxScrollTop`
       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 delta = scrollTop - this._scrollPosition;
       var recycledTiles = 0;
       var hiddenContentSize = this._hiddenContentSize;
       var currentRatio = ratio;
@@ -444,7 +453,7 @@
       // track the last `scrollTop`
       this._scrollPosition = scrollTop;
 
-      // clear cached visible index
+      // clear cached visible indexes
       this._firstVisibleIndexVal = null;
       this._lastVisibleIndexVal = null;
 
@@ -531,6 +540,7 @@
         }
       } else {
         this._virtualStart = this._virtualStart + recycledTiles;
+        this._physicalStart = this._physicalStart + recycledTiles;
         this._update(recycledTileSet, movingUp);
       }
     },
@@ -542,11 +552,7 @@
      */
     _update: function(itemSet, movingUp) {
       // manage focus
-      if (this._isIndexRendered(this._focusedIndex)) {
-        this._restoreFocusedItem();
-      } else {
-        this._createFocusBackfillItem();
-      }
+      this._manageFocus();
       // update models
       this._assignModels(itemSet);
       // measure heights
@@ -613,7 +619,6 @@
      * Increases the pool size.
      */
     _increasePool: function(missingItems) {
-      // limit the size
       var nextPhysicalCount = Math.min(
           this._physicalCount + missingItems,
           this._virtualCount - this._virtualStart,
@@ -622,14 +627,24 @@
       var prevPhysicalCount = this._physicalCount;
       var delta = nextPhysicalCount - prevPhysicalCount;
 
-      if (delta > 0) {
-        [].push.apply(this._physicalItems, this._createPool(delta));
-        [].push.apply(this._physicalSizes, new Array(delta));
-
-        this._physicalCount = prevPhysicalCount + delta;
-        // tail call
-        return this._update();
+      if (delta <= 0) {
+        return;
       }
+
+      [].push.apply(this._physicalItems, this._createPool(delta));
+      [].push.apply(this._physicalSizes, new Array(delta));
+
+      this._physicalCount = prevPhysicalCount + delta;
+
+      // update the physical start if we need to preserve the model of the focused item.
+      // In this situation, the focused item is currently rendered and its model would
+      // have changed after increasing the pool if the physical start remained unchanged.
+      if (this._physicalStart > this._physicalEnd &&
+          this._isIndexRendered(this._focusedIndex) &&
+          this._getPhysicalIndex(this._focusedIndex) < this._physicalEnd) {
+        this._physicalStart = this._physicalStart + delta;
+      }
+      this._update();
     },
 
     /**
@@ -718,27 +733,36 @@
 
     /**
      * Called as a side effect of a host items.<key>.<path> path change,
-     * responsible for notifying item.<path> changes to row for key.
+     * responsible for notifying item.<path> changes.
      */
     _forwardItemPath: function(path, value) {
-      if (this._physicalIndexForKey) {
-        var dot = path.indexOf('.');
-        var key = path.substring(0, dot < 0 ? path.length : dot);
-        var idx = this._physicalIndexForKey[key];
-        var row = this._physicalItems[idx];
+      if (!this._physicalIndexForKey) {
+        return;
+      }
+      var inst;
+      var dot = path.indexOf('.');
+      var key = path.substring(0, dot < 0 ? path.length : dot);
+      var idx = this._physicalIndexForKey[key];
+      var el = this._physicalItems[idx];
 
-        if (idx === this._focusedIndex && this._offscreenFocusedItem) {
-          row = this._offscreenFocusedItem;
-        }
-        if (row) {
-          var inst = row._templateInstance;
-          if (dot >= 0) {
-            path = this.as + '.' + path.substring(dot+1);
-            inst.notifyPath(path, value, true);
-          } else {
-            inst[this.as] = value;
-          }
-        }
+
+      if (idx === this._focusedIndex && this._offscreenFocusedItem) {
+        el = this._offscreenFocusedItem;
+      }
+      if (!el) {
+        return;
+      }
+        
+      inst = el._templateInstance;
+
+      if (inst.__key__ !== key) {
+        return;
+      }
+      if (dot >= 0) {
+        path = this.as + '.' + path.substring(dot+1);
+        inst.notifyPath(path, value, true);
+      } else {
+        inst[this.as] = value;
       }
     },
 
@@ -748,19 +772,15 @@
      */
     _itemsChanged: function(change) {
       if (change.path === 'items') {
-
-        this._restoreFocusedItem();
-        // render the new set
-        this._itemsRendered = false;
-        // update the whole set
+        // reset items
         this._virtualStart = 0;
         this._physicalTop = 0;
         this._virtualCount = this.items ? this.items.length : 0;
-        this._focusedIndex = 0;
         this._collection = this.items ? Polymer.Collection.get(this.items) : null;
         this._physicalIndexForKey = {};
 
         this._resetScrollPosition(0);
+        this._removeFocusedItem();
 
         // create the initial physical items
         if (!this._physicalItems) {
@@ -768,47 +788,50 @@
           this._physicalItems = this._createPool(this._physicalCount);
           this._physicalSizes = new Array(this._physicalCount);
         }
-        this._debounceTemplate(this._render);
+
+        this._physicalStart = 0;
 
       } else if (change.path === 'items.splices') {
-        // render the new set
-        this._itemsRendered = false;
         this._adjustVirtualIndex(change.value.indexSplices);
         this._virtualCount = this.items ? this.items.length : 0;
 
-        this._debounceTemplate(this._render);
-
-        if (this._focusedIndex < 0 || this._focusedIndex >= this._virtualCount) {
-          this._focusedIndex = 0;
-        }
-        this._debounceTemplate(this._render);
-
       } else {
         // update a single item
         this._forwardItemPath(change.path.split('.').slice(1).join('.'), change.value);
+        return;
       }
+
+      this._itemsRendered = false;
+      this._debounceTemplate(this._render);
     },
 
     /**
      * @param {!Array<!PolymerSplice>} splices
      */
     _adjustVirtualIndex: function(splices) {
-      var i, splice, idx;
-
-      for (i = 0; i < splices.length; i++) {
-        splice = splices[i];
-
+      splices.forEach(function(splice) {
         // deselect removed items
-        splice.removed.forEach(this.$.selector.deselect, this.$.selector);
-
-        idx = splice.index;
+        splice.removed.forEach(this._removeItem, this);
         // We only need to care about changes happening above the current position
-        if (idx >= this._virtualStart) {
-          break;
-        }
+        if (splice.index < this._virtualStart) {
+          var delta = Math.max(
+              splice.addedCount - splice.removed.length,
+              splice.index - this._virtualStart);
 
-        this._virtualStart = this._virtualStart +
-            Math.max(splice.addedCount - splice.removed.length, idx - this._virtualStart);
+          this._virtualStart = this._virtualStart + delta;
+
+          if (this._focusedIndex >= 0) {
+            this._focusedIndex = this._focusedIndex + delta;
+          }
+        }
+      }, this);
+    },
+
+    _removeItem: function(item) {
+      this.$.selector.deselect(item);
+      // remove the current focused item
+      if (this._focusedItem && this._focusedItem._templateInstance[this.as] === item) {
+        this._removeFocusedItem();
       }
     },
 
@@ -861,19 +884,18 @@
         var inst = el._templateInstance;
         var item = this.items && this.items[vidx];
 
-        if (item !== undefined && item !== null) {
+        if (item != null) {
           inst[this.as] = item;
           inst.__key__ = this._collection.getKey(item);
           inst[this.selectedAs] = /** @type {!ArraySelectorElement} */ (this.$.selector).isSelected(item);
           inst[this.indexAs] = vidx;
-          inst.tabIndex = vidx === this._focusedIndex ? 0 : -1;
-          el.removeAttribute('hidden');
+          inst.tabIndex = this._focusedIndex === vidx ? 0 : -1;
           this._physicalIndexForKey[inst.__key__] = pidx;
+          el.removeAttribute('hidden');
         } else {
           inst.__key__ = null;
           el.setAttribute('hidden', '');
         }
-
       }, itemSet);
     },
 
@@ -921,10 +943,8 @@
       var y = this._physicalTop;
 
       this._iterateItems(function(pidx) {
-
         this.translate3d(0, y + 'px', 0, this._physicalItems[pidx]);
         y += this._physicalSizes[pidx];
-
       });
     },
 
@@ -972,7 +992,6 @@
         this._scrollHeight = this._estScrollHeight;
       }
     },
-
     /**
      * Scroll to a specific item in the virtual list regardless
      * of the physical items in the DOM tree.
@@ -987,12 +1006,13 @@
 
       Polymer.dom.flush();
 
-      var firstVisible = this.firstVisibleIndex;
       idx = Math.min(Math.max(idx, 0), this._virtualCount-1);
-
-      // start at the previous virtual item
-      // so we have a item above the first visible item
-      this._virtualStart = idx - 1;
+      // update the virtual start only when needed
+      if (!this._isIndexRendered(idx) || idx >= this._maxVirtualStart) {
+        this._virtualStart = idx - 1;
+      }
+      // manage focus
+      this._manageFocus();
       // assign new models
       this._assignModels();
       // measure the new sizes
@@ -1055,7 +1075,7 @@
       var key = this._collection.getKey(item);
       var pidx = this._physicalIndexForKey[key];
 
-      if (pidx !== undefined) {
+      if (pidx != null) {
         return this._physicalItems[pidx]._templateInstance;
       }
       return null;
@@ -1193,140 +1213,180 @@
       var key = this._collection.getKey(item);
       var pidx = this._physicalIndexForKey[key];
 
-      if (pidx !== undefined) {
+      if (pidx != null) {
         this._updateMetrics([pidx]);
         this._positionItems();
       }
     },
 
+    /**
+     * Creates a temporary backfill item in the rendered pool of physical items
+     * to replace the main focused item. The focused item has tabIndex = 0
+     * and might be currently focused by the user.
+     *
+     * This dynamic replacement helps to preserve the focus state.
+     */
+    _manageFocus: function() {
+      var fidx = this._focusedIndex;
+
+      if (fidx >= 0 && fidx < this._virtualCount) {
+        // if it's a valid index, check if that index is rendered
+        // in a physical item.
+        if (this._isIndexRendered(fidx)) {
+          this._restoreFocusedItem();
+        } else {
+          this._createFocusBackfillItem();
+        }
+      } else if (this._virtualCount > 0 && this._physicalCount > 0) {
+        // otherwise, assign the initial focused index.
+        this._focusedIndex = this._virtualStart;
+        this._focusedItem = this._physicalItems[this._physicalStart];
+      }
+    },
+
     _isIndexRendered: function(idx) {
       return idx >= this._virtualStart && idx <= this._virtualEnd;
     },
 
-    _getPhysicalItemForIndex: function(idx, force) {
-      if (!this._collection) {
-        return null;
-      }
-      if (!this._isIndexRendered(idx)) {
-        if (force) {
-          this.scrollToIndex(idx);
-          return this._getPhysicalItemForIndex(idx, false);
-        }
-        return null;
-      }
-      var item = this._getNormalizedItem(idx);
-      var physicalItem = this._physicalItems[this._physicalIndexForKey[this._collection.getKey(item)]];
+    _isIndexVisible: function(idx) {
+      return idx >= this.firstVisibleIndex && idx <= this.lastVisibleIndex;
+    },
 
-      return physicalItem || null;
+    _getPhysicalIndex: function(idx) {
+      return this._physicalIndexForKey[this._collection.getKey(this._getNormalizedItem(idx))];
     },
 
     _focusPhysicalItem: function(idx) {
-      this._restoreFocusedItem();
-
-      var physicalItem = this._getPhysicalItemForIndex(idx, true);
-      if (!physicalItem) {
+      if (idx < 0 || idx >= this._virtualCount) {
         return;
       }
+      this._restoreFocusedItem();
+      // scroll to index to make sure it's rendered
+      if (!this._isIndexRendered(idx)) {
+        this.scrollToIndex(idx);
+      }
+
+      var physicalItem = this._physicalItems[this._getPhysicalIndex(idx)];
       var SECRET = ~(Math.random() * 100);
       var model = physicalItem._templateInstance;
       var focusable;
 
+      // set a secret tab index
       model.tabIndex = SECRET;
-      // the focusable element could be the entire physical item
+      // check if focusable element is the physical item
       if (physicalItem.tabIndex === SECRET) {
        focusable = physicalItem;
       }
-      // the focusable element could be somewhere within the physical item
+      // search for the element which tabindex is bound to the secret tab index
       if (!focusable) {
         focusable = Polymer.dom(physicalItem).querySelector('[tabindex="' + SECRET + '"]');
       }
       // restore the tab index
       model.tabIndex = 0;
+      // focus the focusable element
+      this._focusedIndex = idx;
       focusable && focusable.focus();
     },
 
-    _restoreFocusedItem: function() {
-      if (!this._offscreenFocusedItem) {
-        return;
-      }
-      var item = this._getNormalizedItem(this._focusedIndex);
-      var pidx = this._physicalIndexForKey[this._collection.getKey(item)];
-
-      if (pidx !== undefined) {
-        this.translate3d(0, HIDDEN_Y, 0, this._physicalItems[pidx]);
-        this._physicalItems[pidx] = this._offscreenFocusedItem;
-      }
-      this._offscreenFocusedItem = null;
-    },
-
     _removeFocusedItem: function() {
-      if (!this._offscreenFocusedItem) {
-        return;
+      if (this._offscreenFocusedItem) {
+        Polymer.dom(this).removeChild(this._offscreenFocusedItem);
       }
-      Polymer.dom(this).removeChild(this._offscreenFocusedItem);
       this._offscreenFocusedItem = null;
       this._focusBackfillItem = null;
+      this._focusedItem = null;
+      this._focusedIndex = -1;
     },
 
     _createFocusBackfillItem: function() {
-      if (this._offscreenFocusedItem) {
+      var pidx, fidx = this._focusedIndex;
+      if (this._offscreenFocusedItem || fidx < 0) {
         return;
       }
-      var item = this._getNormalizedItem(this._focusedIndex);
-      var pidx = this._physicalIndexForKey[this._collection.getKey(item)];
-
-      this._offscreenFocusedItem = this._physicalItems[pidx];
-      this.translate3d(0, HIDDEN_Y, 0, this._offscreenFocusedItem);
-
       if (!this._focusBackfillItem) {
+        // create a physical item, so that it backfills the focused item.
         var stampedTemplate = this.stamp(null);
         this._focusBackfillItem = stampedTemplate.root.querySelector('*');
         Polymer.dom(this).appendChild(stampedTemplate.root);
       }
-      this._physicalItems[pidx] = this._focusBackfillItem;
+      // get the physical index for the focused index
+      pidx = this._getPhysicalIndex(fidx);
+
+      if (pidx != null) {
+        // set the offcreen focused physical item
+        this._offscreenFocusedItem = this._physicalItems[pidx];
+        // backfill the focused physical item
+        this._physicalItems[pidx] = this._focusBackfillItem;
+        // hide the focused physical
+        this.translate3d(0, HIDDEN_Y, 0, this._offscreenFocusedItem);
+      }
+    },
+
+    _restoreFocusedItem: function() {
+      var pidx, fidx = this._focusedIndex;
+
+      if (!this._offscreenFocusedItem || this._focusedIndex < 0) {
+        return;
+      }
+      // assign models to the focused index
+      this._assignModels();
+      // get the new physical index for the focused index
+      pidx = this._getPhysicalIndex(fidx);
+
+      if (pidx != null) {
+        // flip the focus backfill
+        this._focusBackfillItem = this._physicalItems[pidx];
+        // restore the focused physical item
+        this._physicalItems[pidx] = this._offscreenFocusedItem;
+        // reset the offscreen focused item
+        this._offscreenFocusedItem = null;
+        // hide the physical item that backfills
+        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) {
+      if (!targetModel || !focusedModel) {
         return;
       }
-      this._restoreFocusedItem();
-
-      if (this.modelForElement(this._offscreenFocusedItem) === targetModel) {
-        this.scrollToIndex(fidx);
+      if (focusedModel === targetModel) {
+        // if the user focused the same item, then bring it into view if it's not visible
+        if (!this._isIndexVisible(fidx)) {
+          this.scrollToIndex(fidx);
+        }
       } else {
+        this._restoreFocusedItem();
         // restore tabIndex for the currently focused item
-        this._getModelFromItem(this._getNormalizedItem(fidx)).tabIndex = -1;
+        focusedModel.tabIndex = -1;
         // set the tabIndex for the next focused item
         targetModel.tabIndex = 0;
-        fidx = /** @type {{index: number}} */(targetModel).index;
+        fidx = targetModel[this.indexAs];
         this._focusedIndex = fidx;
-        // bring the item into view
-        if (fidx < this.firstVisibleIndex || fidx > this.lastVisibleIndex) {
-          this.scrollToIndex(fidx);
-        } else {
+        this._focusedItem = this._physicalItems[this._getPhysicalIndex(fidx)];
+
+        if (hasOffscreenFocusedItem && !this._offscreenFocusedItem) {
           this._update();
         }
       }
     },
 
     _didMoveUp: function() {
-      this._focusPhysicalItem(Math.max(0, this._focusedIndex - 1));
+      this._focusPhysicalItem(this._focusedIndex - 1);
     },
 
     _didMoveDown: function() {
-      this._focusPhysicalItem(Math.min(this._virtualCount, this._focusedIndex + 1));
+      this._focusPhysicalItem(this._focusedIndex + 1);
     },
 
     _didEnter: function(e) {
-      // focus the currently focused physical item
       this._focusPhysicalItem(this._focusedIndex);
-      // toggle selection
-      this._selectionHandler(/** @type {{keyboardEvent: Event}} */(e.detail).keyboardEvent);
+      this._selectionHandler(e.detail.keyboardEvent);
     }
   });
 
-})();
+})();
\ No newline at end of file
diff --git a/third_party/polymer/v1_0/components-chromium/iron-list/iron-list.html b/third_party/polymer/v1_0/components-chromium/iron-list/iron-list.html
index 6737eea5..681523e7 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-list/iron-list.html
+++ b/third_party/polymer/v1_0/components-chromium/iron-list/iron-list.html
@@ -132,10 +132,11 @@
 
 @group Iron Element
 @element iron-list
-@demo demo/index.html Simple list
-@demo demo/selection.html Selection of items
+@demo demo/index.html List of cards
+@demo demo/selection.html Items selection
 @demo demo/collapse.html Collapsable items
 @demo demo/scroll-threshold.html Scroll thesholds
+@demo demo/basic.html Basic list
 
 -->
 
diff --git a/third_party/polymer/v1_0/components-chromium/iron-menu-behavior/.bower.json b/third_party/polymer/v1_0/components-chromium/iron-menu-behavior/.bower.json
index 3956d20..751cfcc 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-menu-behavior/.bower.json
+++ b/third_party/polymer/v1_0/components-chromium/iron-menu-behavior/.bower.json
@@ -1,6 +1,6 @@
 {
   "name": "iron-menu-behavior",
-  "version": "1.1.0",
+  "version": "1.1.4",
   "description": "Provides accessible menu behavior",
   "authors": "The Polymer Authors",
   "keywords": [
@@ -34,11 +34,11 @@
     "web-component-tester": "^4.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
   },
-  "_release": "1.1.0",
+  "_release": "1.1.4",
   "_resolution": {
     "type": "version",
-    "tag": "v1.1.0",
-    "commit": "b18d5478f1d4d6befb15533716d60d5772f8e812"
+    "tag": "v1.1.4",
+    "commit": "637c4ae4654b53d4ca29ba97239c1ffba13cfc93"
   },
   "_source": "git://github.com/PolymerElements/iron-menu-behavior.git",
   "_target": "^1.0.0",
diff --git a/third_party/polymer/v1_0/components-chromium/iron-menu-behavior/CONTRIBUTING.md b/third_party/polymer/v1_0/components-chromium/iron-menu-behavior/CONTRIBUTING.md
index 7b101415..f147978a 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-menu-behavior/CONTRIBUTING.md
+++ b/third_party/polymer/v1_0/components-chromium/iron-menu-behavior/CONTRIBUTING.md
@@ -5,6 +5,11 @@
 
 If you edit that file, it will get updated everywhere else.
 If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
 -->
 # Polymer Elements
 ## Guide for Contributors
@@ -41,7 +46,7 @@
  3. Click the `paper-foo` element.
  ```
 
- 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [http://jsbin.com/cagaye](http://jsbin.com/cagaye/edit?html,output).
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
 
  3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
 
@@ -51,14 +56,14 @@
 
 When submitting pull requests, please provide:
 
- 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues using the following syntax:
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
 
  ```markdown
  (For a single issue)
  Fixes #20
 
  (For multiple issues)
- Fixes #32, #40
+ Fixes #32, fixes #40
  ```
 
  2. **A succinct description of the design** used to fix any related issues. For example:
diff --git a/third_party/polymer/v1_0/components-chromium/iron-menu-behavior/README.md b/third_party/polymer/v1_0/components-chromium/iron-menu-behavior/README.md
index 0c35f352..f8d90c65 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-menu-behavior/README.md
+++ b/third_party/polymer/v1_0/components-chromium/iron-menu-behavior/README.md
@@ -12,9 +12,9 @@
 
 -->
 
-[![Build Status](https://travis-ci.org/PolymerElements/iron-menu-behavior.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-menu-behavior)
+[![Build status](https://travis-ci.org/PolymerElements/iron-menu-behavior.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-menu-behavior)
 
-_[Demo and API Docs](https://elements.polymer-project.org/elements/iron-menu-behavior)_
+_[Demo and API docs](https://elements.polymer-project.org/elements/iron-menu-behavior)_
 
 
 ##Polymer.IronMenuBehavior
diff --git a/third_party/polymer/v1_0/components-chromium/iron-menu-behavior/bower.json b/third_party/polymer/v1_0/components-chromium/iron-menu-behavior/bower.json
index 515df81..2e82f89 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-menu-behavior/bower.json
+++ b/third_party/polymer/v1_0/components-chromium/iron-menu-behavior/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "iron-menu-behavior",
-  "version": "1.1.0",
+  "version": "1.1.4",
   "description": "Provides accessible menu behavior",
   "authors": "The Polymer Authors",
   "keywords": [
diff --git a/third_party/polymer/v1_0/components-chromium/iron-menu-behavior/compiled_resources2.gyp b/third_party/polymer/v1_0/components-chromium/iron-menu-behavior/compiled_resources2.gyp
index 3379dbb..1e15827 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-menu-behavior/compiled_resources2.gyp
+++ b/third_party/polymer/v1_0/components-chromium/iron-menu-behavior/compiled_resources2.gyp
@@ -6,17 +6,17 @@
 {
   'targets': [
     {
-      'target_name': 'iron-menu-behavior-extracted',
+      'target_name': 'iron-menubar-behavior-extracted',
       'dependencies': [
-        '../iron-a11y-keys-behavior/compiled_resources2.gyp:iron-a11y-keys-behavior-extracted',
-        '../iron-selector/compiled_resources2.gyp:iron-multi-selectable-extracted',
+        'iron-menu-behavior-extracted',
       ],
       'includes': ['../../../../closure_compiler/compile_js2.gypi'],
     },
     {
-      'target_name': 'iron-menubar-behavior-extracted',
+      'target_name': 'iron-menu-behavior-extracted',
       'dependencies': [
-        'iron-menu-behavior-extracted',
+        '../iron-a11y-keys-behavior/compiled_resources2.gyp:iron-a11y-keys-behavior-extracted',
+        '../iron-selector/compiled_resources2.gyp:iron-multi-selectable-extracted',
       ],
       'includes': ['../../../../closure_compiler/compile_js2.gypi'],
     },
diff --git a/third_party/polymer/v1_0/components-chromium/iron-menu-behavior/iron-menu-behavior-extracted.js b/third_party/polymer/v1_0/components-chromium/iron-menu-behavior/iron-menu-behavior-extracted.js
index fd0cdc5..cfdf031 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-menu-behavior/iron-menu-behavior-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/iron-menu-behavior/iron-menu-behavior-extracted.js
@@ -223,6 +223,14 @@
         return;
       }
 
+      // Do not focus the selected tab if the deepest target is part of the
+      // menu element's local DOM and is focusable.
+      var rootTarget = /** @type {?HTMLElement} */(
+          Polymer.dom(event).rootTarget);
+      if (rootTarget !== this && typeof rootTarget.tabIndex !== "undefined" && !this.isLightDescendant(rootTarget)) {
+        return;
+      }
+
       this.blur();
 
       // clear the cached focus item
@@ -250,6 +258,7 @@
     _onUpKey: function(event) {
       // up and down arrows moves the focus
       this._focusPrevious();
+      event.detail.keyboardEvent.preventDefault();
     },
 
     /**
@@ -259,6 +268,7 @@
      */
     _onDownKey: function(event) {
       this._focusNext();
+      event.detail.keyboardEvent.preventDefault();
     },
 
     /**
diff --git a/third_party/polymer/v1_0/components-chromium/iron-menu-behavior/iron-menubar-behavior-extracted.js b/third_party/polymer/v1_0/components-chromium/iron-menu-behavior/iron-menubar-behavior-extracted.js
index 0599efa..c9012fe 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-menu-behavior/iron-menubar-behavior-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/iron-menu-behavior/iron-menubar-behavior-extracted.js
@@ -28,20 +28,22 @@
       return window.getComputedStyle(this)['direction'] === 'rtl';
     },
 
-    _onLeftKey: function() {
+    _onLeftKey: function(event) {
       if (this._isRTL) {
         this._focusNext();
       } else {
         this._focusPrevious();
       }
+      event.detail.keyboardEvent.preventDefault();
     },
 
-    _onRightKey: function() {
+    _onRightKey: function(event) {
       if (this._isRTL) {
         this._focusPrevious();
       } else {
         this._focusNext();
       }
+      event.detail.keyboardEvent.preventDefault();
     },
 
     _onKeydown: function(event) {
diff --git a/third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/.bower.json b/third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/.bower.json
index 1e1c3d0..b71ee8d 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/.bower.json
+++ b/third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/.bower.json
@@ -1,6 +1,6 @@
 {
   "name": "iron-overlay-behavior",
-  "version": "1.3.0",
+  "version": "1.4.1",
   "license": "http://polymer.github.io/LICENSE.txt",
   "description": "Provides a behavior for making an element an overlay",
   "private": true,
@@ -19,12 +19,14 @@
     "url": "git://github.com/PolymerElements/iron-overlay-behavior.git"
   },
   "dependencies": {
+    "iron-a11y-keys-behavior": "PolymerElements/iron-a11y-keys-behavior#^1.0.0",
     "iron-fit-behavior": "PolymerElements/iron-fit-behavior#^1.0.0",
     "iron-resizable-behavior": "PolymerElements/iron-resizable-behavior#^1.0.0",
     "polymer": "Polymer/polymer#^1.0.0"
   },
   "devDependencies": {
     "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+    "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
     "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
     "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
     "paper-styles": "PolymerElements/paper-styles#^1.0.2",
@@ -33,11 +35,11 @@
   },
   "ignore": [],
   "homepage": "https://github.com/PolymerElements/iron-overlay-behavior",
-  "_release": "1.3.0",
+  "_release": "1.4.1",
   "_resolution": {
     "type": "version",
-    "tag": "v1.3.0",
-    "commit": "b488ce94ec1c17c3a5491af1a2fba2f7382684da"
+    "tag": "v1.4.1",
+    "commit": "4aefb7bc41aecef69022d6435133c430fc52d3ba"
   },
   "_source": "git://github.com/PolymerElements/iron-overlay-behavior.git",
   "_target": "^1.0.0",
diff --git a/third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/bower.json b/third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/bower.json
index 7a5aa4d..805ca3a 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/bower.json
+++ b/third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "iron-overlay-behavior",
-  "version": "1.3.0",
+  "version": "1.4.1", 
   "license": "http://polymer.github.io/LICENSE.txt",
   "description": "Provides a behavior for making an element an overlay",
   "private": true,
@@ -19,12 +19,14 @@
     "url": "git://github.com/PolymerElements/iron-overlay-behavior.git"
   },
   "dependencies": {
+    "iron-a11y-keys-behavior": "PolymerElements/iron-a11y-keys-behavior#^1.0.0",
     "iron-fit-behavior": "PolymerElements/iron-fit-behavior#^1.0.0",
     "iron-resizable-behavior": "PolymerElements/iron-resizable-behavior#^1.0.0",
     "polymer": "Polymer/polymer#^1.0.0"
   },
   "devDependencies": {
     "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+    "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
     "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
     "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
     "paper-styles": "PolymerElements/paper-styles#^1.0.2",
diff --git a/third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/compiled_resources2.gyp b/third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/compiled_resources2.gyp
index 13133722..43084f8 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/compiled_resources2.gyp
+++ b/third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/compiled_resources2.gyp
@@ -15,6 +15,7 @@
     {
       'target_name': 'iron-overlay-behavior-extracted',
       'dependencies': [
+        '../iron-a11y-keys-behavior/compiled_resources2.gyp:iron-a11y-keys-behavior-extracted',
         '../iron-fit-behavior/compiled_resources2.gyp:iron-fit-behavior-extracted',
         '../iron-resizable-behavior/compiled_resources2.gyp:iron-resizable-behavior-extracted',
         'iron-overlay-backdrop-extracted',
diff --git a/third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/iron-overlay-behavior-extracted.js b/third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/iron-overlay-behavior-extracted.js
index ee78f34..d3fddcb 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/iron-overlay-behavior-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/iron-overlay-behavior-extracted.js
@@ -100,6 +100,23 @@
         type: Object
       },
 
+      /**
+       * The HTMLElement that will be firing relevant KeyboardEvents.
+       * Used for capturing esc and tab. Overridden from `IronA11yKeysBehavior`.
+       */
+      keyEventTarget: {
+        type: Object,
+        value: document
+      },
+
+      /**
+       * Set to true to enable restoring of focus when overlay is closed.
+       */
+      restoreFocusOnClose: {
+        type: Boolean,
+        value: false
+      },
+
       _manager: {
         type: Object,
         value: Polymer.IronOverlayManager
@@ -112,13 +129,6 @@
         }
       },
 
-      _boundOnCaptureKeydown: {
-        type: Function,
-        value: function() {
-          return this._onCaptureKeydown.bind(this);
-        }
-      },
-
       _boundOnCaptureFocus: {
         type: Function,
         value: function() {
@@ -126,44 +136,113 @@
         }
       },
 
-      /** @type {?Node} */
+      /**
+       * The node being focused.
+       * @type {?Node}
+       */
       _focusedChild: {
         type: Object
       }
 
     },
 
+    keyBindings: {
+      'esc': '__onEsc',
+      'tab': '__onTab'
+    },
+
     listeners: {
       'iron-resize': '_onIronResize'
     },
 
     /**
      * The backdrop element.
-     * @type Node
+     * @type {Node}
      */
     get backdropElement() {
       return this._manager.backdropElement;
     },
 
+    /**
+     * Returns the node to give focus to.
+     * @type {Node}
+     */
     get _focusNode() {
       return this._focusedChild || Polymer.dom(this).querySelector('[autofocus]') || this;
     },
 
+    /**
+     * Array of nodes that can receive focus (overlay included), ordered by `tabindex`.
+     * This is used to retrieve which is the first and last focusable nodes in order
+     * to wrap the focus for overlays `with-backdrop`.
+     *
+     * If you know what is your content (specifically the first and last focusable children),
+     * you can override this method to return only `[firstFocusable, lastFocusable];`
+     * @type {[Node]}
+     * @protected
+     */
+    get _focusableNodes() {
+      // Elements that can be focused even if they have [disabled] attribute.
+      var FOCUSABLE_WITH_DISABLED = [
+        'a[href]',
+        'area[href]',
+        'iframe',
+        '[tabindex]',
+        '[contentEditable=true]'
+      ];
+
+      // Elements that cannot be focused if they have [disabled] attribute.
+      var FOCUSABLE_WITHOUT_DISABLED = [
+        'input',
+        'select',
+        'textarea',
+        'button'
+      ];
+
+      // Discard elements with tabindex=-1 (makes them not focusable).
+      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) {
+        // Insert at the beginning because we might have all elements with tabIndex = 0,
+        // and the overlay should be the first of the list.
+        focusables.splice(0, 0, this);
+      }
+      // Sort by tabindex.
+      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() {
-      // with-backdrop need tabindex to be set in order to trap the focus.
+      // with-backdrop needs tabindex to be set in order to trap the focus.
       // If it is not set, IronOverlayBehavior will set it, and remove it if with-backdrop = false.
       this.__shouldRemoveTabIndex = false;
+      // Used for wrapping the focus on TAB / Shift+TAB.
+      this.__firstFocusableNode = this.__lastFocusableNode = null;
       this._ensureSetup();
     },
 
     attached: function() {
       // Call _openedChanged here so that position can be computed correctly.
-      if (this._callOpenedWhenReady) {
+      if (this.opened) {
         this._openedChanged();
       }
+      this._observer = Polymer.dom(this).observeNodes(this._onNodesChange);
     },
 
     detached: function() {
+      Polymer.dom(this).unobserveNodes(this._observer);
+      this._observer = null;
       this.opened = false;
       this._manager.trackBackdrop(this);
       this._manager.removeOverlay(this);
@@ -195,9 +274,10 @@
 
     /**
      * Cancels the overlay.
+     * @param {?Event} event The original event
      */
-    cancel: function() {
-      var cancelEvent = this.fire('iron-overlay-canceled', undefined, {cancelable: true});
+    cancel: function(event) {
+      var cancelEvent = this.fire('iron-overlay-canceled', event, {cancelable: true});
       if (cancelEvent.defaultPrevented) {
         return;
       }
@@ -220,12 +300,10 @@
         this.removeAttribute('aria-hidden');
       } else {
         this.setAttribute('aria-hidden', 'true');
-        Polymer.dom(this).unobserveNodes(this._observer);
       }
 
       // wait to call after ready only if we're initially open
       if (!this._overlaySetup) {
-        this._callOpenedWhenReady = this.opened;
         return;
       }
 
@@ -300,16 +378,18 @@
       }
     },
 
-    _toggleListeners: function () {
+    _toggleListeners: function() {
       this._toggleListener(this.opened, document, 'tap', this._boundOnCaptureClick, true);
-      this._toggleListener(this.opened, document, 'keydown', this._boundOnCaptureKeydown, true);
       this._toggleListener(this.opened, document, 'focus', this._boundOnCaptureFocus, true);
     },
 
     // tasks which must occur before opening; e.g. making the element visible
     _prepareRenderOpened: function() {
+
       this._manager.addOverlay(this);
 
+      // Needed to calculate the size of the overlay so that transitions on its size
+      // will have the correct starting points.
       this._preparePositioning();
       this.fit();
       this._finishPositioning();
@@ -317,6 +397,12 @@
       if (this.withBackdrop) {
         this.backdropElement.prepare();
       }
+
+      // Safari will apply the focus to the autofocus element when displayed for the first time,
+      // so we blur it. Later, _applyFocus will set the focus if necessary.
+      if (this.noAutoFocus && document.activeElement === this._focusNode) {
+        this._focusNode.blur();
+      }
     },
 
     // tasks which cause the overlay to actually open; typically play an
@@ -336,23 +422,24 @@
     },
 
     _finishRenderOpened: function() {
-      // focus the child node with [autofocus]
+      // This ensures the overlay is visible before we set the focus
+      // (by calling _onIronResize -> refit).
+      this.notifyResize();
+      // Focus the child node with [autofocus]
       this._applyFocus();
 
-      this._observer = Polymer.dom(this).observeNodes(this.notifyResize);
       this.fire('iron-overlay-opened');
     },
 
     _finishRenderClosed: function() {
-      // hide the overlay and remove the backdrop
+      // Hide the overlay and remove the backdrop.
       this.resetFit();
       this.style.display = 'none';
       this._manager.removeOverlay(this);
 
-      this._focusedChild = null;
       this._applyFocus();
-
       this.notifyResize();
+
       this.fire('iron-overlay-closed', this.closingReason);
     },
 
@@ -365,8 +452,9 @@
     _finishPositioning: function() {
       this.style.display = 'none';
       this.style.transform = this.style.webkitTransform = '';
-      // force layout to avoid application of transform
-      /** @suppress {suspiciousCode} */ this.offsetWidth;
+      // Force layout layout to avoid application of transform.
+      // Set offsetWidth to itself so that compilers won't remove it.
+      this.offsetWidth = this.offsetWidth;
       this.style.transition = this.style.webkitTransition = '';
     },
 
@@ -377,6 +465,7 @@
         }
       } else {
         this._focusNode.blur();
+        this._focusedChild = null;
         this._manager.focusOverlay();
       }
     },
@@ -387,23 +476,13 @@
         if (this.noCancelOnOutsideClick) {
           this._applyFocus();
         } else {
-          this.cancel();
+          this.cancel(event);
         }
       }
     },
 
-    _onCaptureKeydown: function(event) {
-      var ESC = 27;
-      if (this._manager.currentOverlay() === this &&
-          !this.noCancelOnEscKey &&
-          event.keyCode === ESC) {
-        this.cancel();
-      }
-    },
-
     _onCaptureFocus: function (event) {
-      if (this._manager.currentOverlay() === this &&
-          this.withBackdrop) {
+      if (this._manager.currentOverlay() === this && this.withBackdrop) {
         var path = Polymer.dom(event).path;
         if (path.indexOf(this) === -1) {
           event.stopPropagation();
@@ -418,25 +497,70 @@
       if (this.opened) {
         this.refit();
       }
+    },
+
+    /**
+     * @protected
+     * Will call notifyResize if overlay is opened.
+     * Can be overridden in order to avoid multiple observers on the same node.
+     */
+    _onNodesChange: function() {
+      if (this.opened) {
+        this.notifyResize();
+      }
+      // Store it so we don't query too much.
+      var focusableNodes = this._focusableNodes;
+      this.__firstFocusableNode = focusableNodes[0];
+      this.__lastFocusableNode = focusableNodes[focusableNodes.length - 1];
+    },
+
+    __onEsc: function(event) {
+      // Not opened or not on top, so return.
+      if (this._manager.currentOverlay() !== this) {
+        return;
+      }
+      if (!this.noCancelOnEscKey) {
+        this.cancel(event);
+      }
+    },
+
+    __onTab: function(event) {
+      // Not opened or not on top, so return.
+      if (this._manager.currentOverlay() !== this) {
+        return;
+      }
+      // TAB wraps from last to first focusable.
+      // Shift + TAB wraps from first to last focusable.
+      var shift = event.detail.keyboardEvent.shiftKey;
+      var nodeToCheck = shift ? this.__firstFocusableNode : this.__lastFocusableNode;
+      var nodeToSet = shift ? this.__lastFocusableNode : this.__firstFocusableNode;
+      if (this.withBackdrop && this._focusedChild === nodeToCheck) {
+        // We set here the _focusedChild so that _onCaptureFocus will handle the
+        // wrapping of the focus (the next event after tab is focus).
+        this._focusedChild = nodeToSet;
+      }
     }
-
-/**
- * Fired after the `iron-overlay` opens.
- * @event iron-overlay-opened
- */
-
-/**
- * Fired when the `iron-overlay` is canceled, but before it is closed.
- * Cancel the event to prevent the `iron-overlay` from closing.
- * @event iron-overlay-canceled
- */
-
-/**
- * Fired after the `iron-overlay` closes.
- * @event iron-overlay-closed
- * @param {{canceled: (boolean|undefined)}} set to the `closingReason` attribute
- */
   };
 
   /** @polymerBehavior */
-  Polymer.IronOverlayBehavior = [Polymer.IronFitBehavior, Polymer.IronResizableBehavior, Polymer.IronOverlayBehaviorImpl];
\ No newline at end of file
+  Polymer.IronOverlayBehavior = [Polymer.IronA11yKeysBehavior, Polymer.IronFitBehavior, Polymer.IronResizableBehavior, Polymer.IronOverlayBehaviorImpl];
+
+  /**
+  * Fired after the `iron-overlay` opens.
+  * @event iron-overlay-opened
+  */
+
+  /**
+  * Fired when the `iron-overlay` is canceled, but before it is closed.
+  * Cancel the event to prevent the `iron-overlay` from closing.
+  * @event iron-overlay-canceled
+  * @param {Event} event The closing of the `iron-overlay` can be prevented
+  * by calling `event.preventDefault()`. The `event.detail` is the original event that originated
+  * the canceling (e.g. ESC keyboard event or click event outside the `iron-overlay`).
+  */
+
+  /**
+  * Fired after the `iron-overlay` closes.
+  * @event iron-overlay-closed
+  * @param {{canceled: (boolean|undefined)}} closingReason Contains `canceled` (whether the overlay was canceled).
+  */
\ No newline at end of file
diff --git a/third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/iron-overlay-behavior.html b/third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/iron-overlay-behavior.html
index 1a3179e..63db8bf 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/iron-overlay-behavior.html
+++ b/third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/iron-overlay-behavior.html
@@ -7,6 +7,7 @@
 Code distributed by Google as part of the polymer project is also
 subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 --><html><head><link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
 <link rel="import" href="../iron-fit-behavior/iron-fit-behavior.html">
 <link rel="import" href="../iron-resizable-behavior/iron-resizable-behavior.html">
 <link rel="import" href="iron-overlay-backdrop.html">
diff --git a/third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/iron-overlay-manager-extracted.js b/third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/iron-overlay-manager-extracted.js
index 687b02a..b8a165b 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/iron-overlay-manager-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/iron-overlay-manager-extracted.js
@@ -4,6 +4,9 @@
    */
   Polymer.IronOverlayManagerClass = function() {
     this._overlays = [];
+    // Used to keep track of the last focused node before an overlay gets opened.
+    this._lastFocusedNodes = [];
+
     /**
      * iframes have a default z-index of 100, so this default should be at least
      * that.
@@ -12,7 +15,52 @@
     this._minimumZ = 101;
 
     this._backdrops = [];
-  }
+
+    this._backdropElement = null;
+    Object.defineProperty(this, 'backdropElement', {
+      get: function() {
+        if (!this._backdropElement) {
+          this._backdropElement = document.createElement('iron-overlay-backdrop');
+        }
+        return this._backdropElement;
+      }.bind(this)
+    });
+
+    /**
+     * The deepest active element.
+     * returns {?Node} element the active element
+     */
+    this.deepActiveElement = null;
+    Object.defineProperty(this, 'deepActiveElement', {
+      get: function() {
+        var active = document.activeElement;
+        // document.activeElement can be null
+        // https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement
+        while (active && active.root && Polymer.dom(active.root).activeElement) {
+          active = Polymer.dom(active.root).activeElement;
+        }
+        return active;
+      }.bind(this)
+    });
+  };
+
+  /**
+   * If a node is contained in an overlay.
+   * @private
+   * @param {Node} node
+   * @returns {Boolean}
+   */
+  Polymer.IronOverlayManagerClass.prototype._isChildOfOverlay = function(node) {
+    while (node && node !== document.body) {
+      // Use logical parentNode, or native ShadowRoot host.
+      node = Polymer.dom(node).parentNode || node.host;
+      // Check if it is an overlay.
+      if (node && node.behaviors && node.behaviors.indexOf(Polymer.IronOverlayBehaviorImpl) !== -1) {
+        return true;
+      }
+    }
+    return false;
+  };
 
   Polymer.IronOverlayManagerClass.prototype._applyOverlayZ = function(overlay, aboveZ) {
     this._setZ(overlay, aboveZ + 2);
@@ -32,6 +80,12 @@
     if (newZ <= minimumZ) {
       this._applyOverlayZ(overlay, minimumZ);
     }
+    var element = this.deepActiveElement;
+    // If already in other overlay, don't reset focus there.
+    if (this._isChildOfOverlay(element)) {
+      element = null;
+    }
+    this._lastFocusedNodes.push(element);
   };
 
   Polymer.IronOverlayManagerClass.prototype.removeOverlay = function(overlay) {
@@ -39,6 +93,13 @@
     if (i >= 0) {
       this._overlays.splice(i, 1);
       this._setZ(overlay, '');
+
+      var node = this._lastFocusedNodes[i];
+      // Focus only if still contained in document.body
+      if (overlay.restoreFocusOnClose && node && Polymer.dom(document.body).deepContains(node)) {
+        node.focus();
+      }
+      this._lastFocusedNodes.splice(i, 1);
     }
   };
 
@@ -93,15 +154,6 @@
     }
   };
 
-  Object.defineProperty(Polymer.IronOverlayManagerClass.prototype, "backdropElement", {
-    get: function() {
-      if (!this._backdropElement) {
-        this._backdropElement = document.createElement('iron-overlay-backdrop');
-      }
-      return this._backdropElement;
-    }
-  });
-
   Polymer.IronOverlayManagerClass.prototype.getBackdrops = function() {
     return this._backdrops;
   };
diff --git a/third_party/polymer/v1_0/components-chromium/iron-pages/.bower.json b/third_party/polymer/v1_0/components-chromium/iron-pages/.bower.json
index 7e5cb7f..17fa616a 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-pages/.bower.json
+++ b/third_party/polymer/v1_0/components-chromium/iron-pages/.bower.json
@@ -19,13 +19,13 @@
   ],
   "dependencies": {
     "iron-resizable-behavior": "polymerelements/iron-resizable-behavior#^1.0.0",
-    "iron-demo-helpers": "polymerelements/iron-demo-helpers#^1.0.0",
     "iron-selector": "polymerelements/iron-selector#^1.0.0",
     "polymer": "Polymer/polymer#^1.1.0"
   },
   "devDependencies": {
-    "paper-styles": "polymerelements/paper-styles#^1.0.2",
     "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
+    "iron-demo-helpers": "polymerelements/iron-demo-helpers#^1.0.0",
+    "paper-styles": "polymerelements/paper-styles#^1.0.2",
     "test-fixture": "polymerelements/test-fixture#^1.0.0",
     "web-component-tester": "^4.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
@@ -36,7 +36,7 @@
   "_resolution": {
     "type": "version",
     "tag": "v1.0.7",
-    "commit": "395e253134488b1cab13072890ca5a7eb1b0fd54"
+    "commit": "357acb8508da5093b22887a85cb785919c20cfde"
   },
   "_source": "git://github.com/PolymerElements/iron-pages.git",
   "_target": "^1.0.0",
diff --git a/third_party/polymer/v1_0/components-chromium/iron-pages/bower.json b/third_party/polymer/v1_0/components-chromium/iron-pages/bower.json
index a1f740c7..3fa960879 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-pages/bower.json
+++ b/third_party/polymer/v1_0/components-chromium/iron-pages/bower.json
@@ -19,13 +19,13 @@
   ],
   "dependencies": {
     "iron-resizable-behavior": "polymerelements/iron-resizable-behavior#^1.0.0",
-    "iron-demo-helpers": "polymerelements/iron-demo-helpers#^1.0.0",
     "iron-selector": "polymerelements/iron-selector#^1.0.0",
     "polymer": "Polymer/polymer#^1.1.0"
   },
   "devDependencies": {
-    "paper-styles": "polymerelements/paper-styles#^1.0.2",
     "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
+    "iron-demo-helpers": "polymerelements/iron-demo-helpers#^1.0.0",
+    "paper-styles": "polymerelements/paper-styles#^1.0.2",
     "test-fixture": "polymerelements/test-fixture#^1.0.0",
     "web-component-tester": "^4.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
diff --git a/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/.bower.json b/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/.bower.json
index 9ae5e84..2e765b93 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/.bower.json
+++ b/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/.bower.json
@@ -1,6 +1,6 @@
 {
   "name": "iron-resizable-behavior",
-  "version": "1.0.2",
+  "version": "1.0.3",
   "license": "http://polymer.github.io/LICENSE.txt",
   "description": "Coordinates the flow of resizeable elements",
   "private": true,
@@ -24,15 +24,16 @@
   "devDependencies": {
     "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
     "test-fixture": "polymerelements/test-fixture#^1.0.0",
-    "web-component-tester": "*",
+    "web-component-tester": "^4.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
   },
+  "ignore": [],
   "homepage": "https://github.com/PolymerElements/iron-resizable-behavior",
-  "_release": "1.0.2",
+  "_release": "1.0.3",
   "_resolution": {
     "type": "version",
-    "tag": "v1.0.2",
-    "commit": "85de8ba28be2bf17c81d6436ef1119022b003674"
+    "tag": "v1.0.3",
+    "commit": "dda1df6aaf452aedf3e52ff0cf69e72439452216"
   },
   "_source": "git://github.com/PolymerElements/iron-resizable-behavior.git",
   "_target": "^1.0.0",
diff --git a/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/CONTRIBUTING.md b/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/CONTRIBUTING.md
new file mode 100644
index 0000000..f147978a
--- /dev/null
+++ b/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/README.md b/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/README.md
index 72be6def..2f37628 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/README.md
+++ b/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/README.md
@@ -1,11 +1,29 @@
-iron-resizable-behavior
-=======================
+
+<!---
+
+This README is automatically generated from the comments in these files:
+iron-resizable-behavior.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/iron-resizable-behavior.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-resizable-behavior)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/iron-resizable-behavior)_
+
+
+##Polymer.IronResizableBehavior
 
 `IronResizableBehavior` is a behavior that can be used in Polymer elements to
 coordinate the flow of resize events between "resizers" (elements that control the
 size or hidden state of their children) and "resizables" (elements that need to be
 notified when they are resized or un-hidden by their parents in order to take
-action on their new measurements). 
+action on their new measurements).
 
 Elements that perform measurement should add the `IronResizableBehavior` behavior to
 their element definition and listen for the `iron-resize` event on themselves.
@@ -14,3 +32,5 @@
 resized.
 
 Note, the `iron-resize` event is non-bubbling.
+
+
diff --git a/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/bower.json b/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/bower.json
index d0591a3f..053bfd0 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/bower.json
+++ b/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "iron-resizable-behavior",
-  "version": "1.0.2",
+  "version": "1.0.3",
   "license": "http://polymer.github.io/LICENSE.txt",
   "description": "Coordinates the flow of resizeable elements",
   "private": true,
@@ -24,7 +24,8 @@
   "devDependencies": {
     "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
     "test-fixture": "polymerelements/test-fixture#^1.0.0",
-    "web-component-tester": "*",
+    "web-component-tester": "^4.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
-  }
+  },
+  "ignore": []
 }
diff --git a/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/iron-resizable-behavior-extracted.js b/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/iron-resizable-behavior-extracted.js
index ee0b4bf9..a2a912b 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/iron-resizable-behavior-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/iron-resizable-behavior-extracted.js
@@ -4,11 +4,13 @@
    * size or hidden state of their children) and "resizables" (elements that need to be
    * notified when they are resized or un-hidden by their parents in order to take
    * action on their new measurements).
+   * 
    * Elements that perform measurement should add the `IronResizableBehavior` behavior to
    * their element definition and listen for the `iron-resize` event on themselves.
    * This event will be fired when they become showing after having been hidden,
    * when they are resized explicitly by another resizable, or when the window has been
    * resized.
+   * 
    * Note, the `iron-resize` event is non-bubbling.
    *
    * @polymerBehavior Polymer.IronResizableBehavior
diff --git a/third_party/polymer/v1_0/components-chromium/iron-scroll-target-behavior/.bower.json b/third_party/polymer/v1_0/components-chromium/iron-scroll-target-behavior/.bower.json
index be21520..47f79f2 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-scroll-target-behavior/.bower.json
+++ b/third_party/polymer/v1_0/components-chromium/iron-scroll-target-behavior/.bower.json
@@ -1,6 +1,6 @@
 {
   "name": "iron-scroll-target-behavior",
-  "version": "1.0.3",
+  "version": "1.0.4",
   "description": "Allows to define a scroller target",
   "private": true,
   "license": "http://polymer.github.io/LICENSE.txt",
@@ -28,11 +28,11 @@
     "web-component-tester": "^4.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
   },
-  "_release": "1.0.3",
+  "_release": "1.0.4",
   "_resolution": {
     "type": "version",
-    "tag": "v1.0.3",
-    "commit": "7ce943d4bc9daf9704174f58a6c5104fe3097986"
+    "tag": "v1.0.4",
+    "commit": "77870593ace034696a83e0190914861633196e6d"
   },
   "_source": "git://github.com/PolymerElements/iron-scroll-target-behavior.git",
   "_target": "^1.0.0",
diff --git a/third_party/polymer/v1_0/components-chromium/iron-scroll-target-behavior/CONTRIBUTING.md b/third_party/polymer/v1_0/components-chromium/iron-scroll-target-behavior/CONTRIBUTING.md
index 7b101415..f147978a 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-scroll-target-behavior/CONTRIBUTING.md
+++ b/third_party/polymer/v1_0/components-chromium/iron-scroll-target-behavior/CONTRIBUTING.md
@@ -5,6 +5,11 @@
 
 If you edit that file, it will get updated everywhere else.
 If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
 -->
 # Polymer Elements
 ## Guide for Contributors
@@ -41,7 +46,7 @@
  3. Click the `paper-foo` element.
  ```
 
- 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [http://jsbin.com/cagaye](http://jsbin.com/cagaye/edit?html,output).
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
 
  3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
 
@@ -51,14 +56,14 @@
 
 When submitting pull requests, please provide:
 
- 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues using the following syntax:
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
 
  ```markdown
  (For a single issue)
  Fixes #20
 
  (For multiple issues)
- Fixes #32, #40
+ Fixes #32, fixes #40
  ```
 
  2. **A succinct description of the design** used to fix any related issues. For example:
diff --git a/third_party/polymer/v1_0/components-chromium/iron-scroll-target-behavior/README.md b/third_party/polymer/v1_0/components-chromium/iron-scroll-target-behavior/README.md
index 9e54140..d7861f80 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-scroll-target-behavior/README.md
+++ b/third_party/polymer/v1_0/components-chromium/iron-scroll-target-behavior/README.md
@@ -12,7 +12,9 @@
 
 -->
 
-_[Demo and API Docs](https://elements.polymer-project.org/elements/iron-scroll-target-behavior)_
+[![Build status](https://travis-ci.org/PolymerElements/iron-scroll-target-behavior.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-scroll-target-behavior)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/iron-scroll-target-behavior)_
 
 
 ##Polymer.IronScrollTargetBehavior
diff --git a/third_party/polymer/v1_0/components-chromium/iron-scroll-target-behavior/bower.json b/third_party/polymer/v1_0/components-chromium/iron-scroll-target-behavior/bower.json
index 7b074a0..3d5467b 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-scroll-target-behavior/bower.json
+++ b/third_party/polymer/v1_0/components-chromium/iron-scroll-target-behavior/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "iron-scroll-target-behavior",
-  "version": "1.0.3",
+  "version": "1.0.4",
   "description": "Allows to define a scroller target",
   "private": true,
   "license": "http://polymer.github.io/LICENSE.txt",
diff --git a/third_party/polymer/v1_0/components-chromium/iron-scroll-target-behavior/iron-scroll-target-behavior-extracted.js b/third_party/polymer/v1_0/components-chromium/iron-scroll-target-behavior/iron-scroll-target-behavior-extracted.js
index 4619264..6ab3521 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-scroll-target-behavior/iron-scroll-target-behavior-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/iron-scroll-target-behavior/iron-scroll-target-behavior-extracted.js
@@ -62,9 +62,9 @@
         // Support element id references
         if (typeof scrollTarget === 'string') {
 
-          var ownerRoot = Polymer.dom(this).getOwnerRoot();
-          this.scrollTarget = (ownerRoot && ownerRoot.$) ?
-              ownerRoot.$[scrollTarget] : Polymer.dom(this.ownerDocument).querySelector('#' + scrollTarget);
+          var host = this.domHost;
+          this.scrollTarget = host && host.$ ? host.$[scrollTarget] : 
+              Polymer.dom(this.ownerDocument).querySelector('#' + scrollTarget);
 
         } else if (this._scrollHandler) {
 
@@ -163,15 +163,15 @@
      * Scrolls the content to a particular place.
      *
      * @method scroll
-     * @param {number} top The top position
      * @param {number} left The left position
+     * @param {number} top The top position
      */
-    scroll: function(top, left) {
+    scroll: function(left, top) {
        if (this.scrollTarget === this._doc) {
-        window.scrollTo(top, left);
+        window.scrollTo(left, top);
       } else if (this._isValidScrollTarget()) {
-        this.scrollTarget.scrollTop = top;
         this.scrollTarget.scrollLeft = left;
+        this.scrollTarget.scrollTop = top;
       }
     },
 
diff --git a/third_party/polymer/v1_0/components-chromium/iron-selector/.bower.json b/third_party/polymer/v1_0/components-chromium/iron-selector/.bower.json
index 2b3357d..fedc850 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-selector/.bower.json
+++ b/third_party/polymer/v1_0/components-chromium/iron-selector/.bower.json
@@ -1,6 +1,6 @@
 {
   "name": "iron-selector",
-  "version": "1.2.1",
+  "version": "1.2.4",
   "description": "Manages a set of elements that can be selected",
   "private": true,
   "license": "http://polymer.github.io/LICENSE.txt",
@@ -30,11 +30,11 @@
     "web-component-tester": "^4.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
   },
-  "_release": "1.2.1",
+  "_release": "1.2.4",
   "_resolution": {
     "type": "version",
-    "tag": "v1.2.1",
-    "commit": "1e6a7ee05e5ff350472ffc1ee780f145a7606b7b"
+    "tag": "v1.2.4",
+    "commit": "1ee4e2e11a9e5118320987d93fc2c03ae9a489f4"
   },
   "_source": "git://github.com/PolymerElements/iron-selector.git",
   "_target": "^1.0.0",
diff --git a/third_party/polymer/v1_0/components-chromium/iron-selector/bower.json b/third_party/polymer/v1_0/components-chromium/iron-selector/bower.json
index 0b82c5b..a183552 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-selector/bower.json
+++ b/third_party/polymer/v1_0/components-chromium/iron-selector/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "iron-selector",
-  "version": "1.2.1",
+  "version": "1.2.4",
   "description": "Manages a set of elements that can be selected",
   "private": true,
   "license": "http://polymer.github.io/LICENSE.txt",
diff --git a/third_party/polymer/v1_0/components-chromium/iron-selector/iron-multi-selectable-extracted.js b/third_party/polymer/v1_0/components-chromium/iron-selector/iron-multi-selectable-extracted.js
index 7c9c39ea..38b18a86 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-selector/iron-multi-selectable-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/iron-selector/iron-multi-selectable-extracted.js
@@ -32,7 +32,7 @@
     },
 
     observers: [
-      '_updateSelected(attrForSelected, selectedValues)'
+      '_updateSelected(selectedValues)'
     ],
 
     /**
@@ -63,6 +63,18 @@
         (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);
@@ -72,11 +84,16 @@
     },
 
     _selectMulti: function(values) {
-      this._selection.clear();
       if (values) {
-        for (var i = 0; i < values.length; i++) {
-          this._selection.setItemSelected(this._valueToItem(values[i]), true);
+        var selectedItems = this._valuesToItems(values);
+        // clear all but the current selected items
+        this._selection.clear(selectedItems);
+        // select only those not selected yet
+        for (var i = 0; i < selectedItems.length; i++) {
+          this._selection.setItemSelected(selectedItems[i], true);
         }
+      } else {
+        this._selection.clear();
       }
     },
 
@@ -99,6 +116,12 @@
         this.splice('selectedValues',i,1);
       }
       this._selection.setItemSelected(this._valueToItem(value), unselected);
+    },
+
+    _valuesToItems: function(values) {
+      return (values == null) ? null : values.map(function(value) {
+        return this._valueToItem(value);
+      }, this);
     }
   };
 
diff --git a/third_party/polymer/v1_0/components-chromium/iron-selector/iron-selectable-extracted.js b/third_party/polymer/v1_0/components-chromium/iron-selector/iron-selectable-extracted.js
index e33d8768..291e7de4 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-selector/iron-selectable-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/iron-selector/iron-selectable-extracted.js
@@ -122,7 +122,8 @@
     },
 
     observers: [
-      '_updateSelected(attrForSelected, selected)'
+      '_updateAttrForSelected(attrForSelected)',
+      '_updateSelected(selected)'
     ],
 
     created: function() {
@@ -134,7 +135,7 @@
       this._observer = this._observeItems(this);
       this._updateItems();
       if (!this._shouldUpdateSelection) {
-        this._updateSelected(this.attrForSelected,this.selected)
+        this._updateSelected();
       }
       this._addListener(this.activateEvent);
     },
@@ -227,6 +228,12 @@
       this._setItems(nodes);
     },
 
+    _updateAttrForSelected: function() {
+      if (this._shouldUpdateSelection) {
+        this.selected = this._indexToValue(this.indexOf(this.selectedItem));        
+      }
+    },
+
     _updateSelected: function() {
       this._selectSelected(this.selected);
     },
@@ -296,7 +303,7 @@
         }
 
         // Let other interested parties know about the change so that
-        // we don't have to recreate mutation observers everywher.
+        // we don't have to recreate mutation observers everywhere.
         this.fire('iron-items-changed', mutations, {
           bubbles: false,
           cancelable: false
diff --git a/third_party/polymer/v1_0/components-chromium/iron-selector/iron-selection-extracted.js b/third_party/polymer/v1_0/components-chromium/iron-selector/iron-selection-extracted.js
index 9c9d1ec..65083e9 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-selector/iron-selection-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/iron-selector/iron-selection-extracted.js
@@ -55,16 +55,19 @@
      */
     setItemSelected: function(item, isSelected) {
       if (item != null) {
-        if (isSelected) {
-          this.selection.push(item);
-        } else {
-          var i = this.selection.indexOf(item);
-          if (i >= 0) {
-            this.selection.splice(i, 1);
+        if (isSelected !== this.isSelected(item)) {
+          // proceed to update selection only if requested state differs from current
+          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);
+          if (this.selectCallback) {
+            this.selectCallback(item, isSelected);
+          }
         }
       }
     },
diff --git a/third_party/polymer/v1_0/components-chromium/iron-test-helpers/.bower.json b/third_party/polymer/v1_0/components-chromium/iron-test-helpers/.bower.json
index 7135824..c06eb0e 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-test-helpers/.bower.json
+++ b/third_party/polymer/v1_0/components-chromium/iron-test-helpers/.bower.json
@@ -1,6 +1,6 @@
 {
   "name": "iron-test-helpers",
-  "version": "1.1.3",
+  "version": "1.1.5",
   "authors": [
     "The Polymer Authors"
   ],
@@ -23,14 +23,15 @@
     "polymer": "Polymer/polymer#^1.0.0"
   },
   "devDependencies": {
-    "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+    "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
+    "web-component-tester": "^4.0.0"
   },
   "main": "iron-test-helpers.html",
-  "_release": "1.1.3",
+  "_release": "1.1.5",
   "_resolution": {
     "type": "version",
-    "tag": "v1.1.3",
-    "commit": "51e03645e9a5a7884b5fadc567508e1d730e9174"
+    "tag": "v1.1.5",
+    "commit": "76d7e5b4d52587c853e8b2cbdf8d970bcf209ff3"
   },
   "_source": "git://github.com/PolymerElements/iron-test-helpers.git",
   "_target": "^1.0.0",
diff --git a/third_party/polymer/v1_0/components-chromium/iron-test-helpers/CONTRIBUTING.md b/third_party/polymer/v1_0/components-chromium/iron-test-helpers/CONTRIBUTING.md
index 7b101415..f147978a 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-test-helpers/CONTRIBUTING.md
+++ b/third_party/polymer/v1_0/components-chromium/iron-test-helpers/CONTRIBUTING.md
@@ -5,6 +5,11 @@
 
 If you edit that file, it will get updated everywhere else.
 If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
 -->
 # Polymer Elements
 ## Guide for Contributors
@@ -41,7 +46,7 @@
  3. Click the `paper-foo` element.
  ```
 
- 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [http://jsbin.com/cagaye](http://jsbin.com/cagaye/edit?html,output).
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
 
  3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
 
@@ -51,14 +56,14 @@
 
 When submitting pull requests, please provide:
 
- 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues using the following syntax:
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
 
  ```markdown
  (For a single issue)
  Fixes #20
 
  (For multiple issues)
- Fixes #32, #40
+ Fixes #32, fixes #40
  ```
 
  2. **A succinct description of the design** used to fix any related issues. For example:
diff --git a/third_party/polymer/v1_0/components-chromium/iron-test-helpers/README.md b/third_party/polymer/v1_0/components-chromium/iron-test-helpers/README.md
index 6c27bf90..cb2d8a2 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-test-helpers/README.md
+++ b/third_party/polymer/v1_0/components-chromium/iron-test-helpers/README.md
@@ -1,6 +1,10 @@
+[![Build status](https://travis-ci.org/PolymerElements/iron-test-helpers.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-test-helpers)
+
 # iron-test-helpers
 
-Utility classes to make testing easier.
+A set of utility classes to make testing easier. For more details on the methods
+available, please check the documentation of `mock-interactions.js` and
+`test-helpers.js`
 
 ## Mock Interactions
 
diff --git a/third_party/polymer/v1_0/components-chromium/iron-test-helpers/bower.json b/third_party/polymer/v1_0/components-chromium/iron-test-helpers/bower.json
index 7c8147628..677ca3a 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-test-helpers/bower.json
+++ b/third_party/polymer/v1_0/components-chromium/iron-test-helpers/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "iron-test-helpers",
-  "version": "1.1.3",
+  "version": "1.1.5",
   "authors": [
     "The Polymer Authors"
   ],
@@ -23,7 +23,8 @@
     "polymer": "Polymer/polymer#^1.0.0"
   },
   "devDependencies": {
-    "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+    "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
+    "web-component-tester": "^4.0.0"
   },
   "main": "iron-test-helpers.html"
 }
diff --git a/third_party/polymer/v1_0/components-chromium/iron-test-helpers/mock-interactions.js b/third_party/polymer/v1_0/components-chromium/iron-test-helpers/mock-interactions.js
index 10e46a4..d74f518 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-test-helpers/mock-interactions.js
+++ b/third_party/polymer/v1_0/components-chromium/iron-test-helpers/mock-interactions.js
@@ -19,6 +19,11 @@
     return has;
   })();
 
+  /*
+   * Returns the (x,y) coordinates representing the middle of a node.
+   *
+   * @param {HTMLElement} node An element.
+   */
   function middleOfNode(node) {
     var bcr = node.getBoundingClientRect();
     return {
@@ -27,6 +32,11 @@
     };
   }
 
+  /*
+   * Returns the (x,y) coordinates representing the top left corner of a node.
+   *
+   * @param {HTMLElement} node An element.
+   */
   function topLeftOfNode(node) {
     var bcr = node.getBoundingClientRect();
     return {
@@ -35,6 +45,14 @@
     };
   }
 
+  /*
+   * Fires a mouse event on a specific node, at a given set of coordinates.
+   * This event bubbles and is cancellable.
+   *
+   * @param {String} type The type of mouse event (such as 'tap' or 'down').
+   * @param {Object} xy The (x,y) coordinates the mouse event should be fired from.
+   * @param {HTMLElement} node The node to fire the event on.
+   */
   function makeEvent(type, xy, node) {
     var props = {
       bubbles: true,
@@ -67,11 +85,16 @@
     node.dispatchEvent(e);
   }
 
-  function down(node, xy) {
-    xy = xy || middleOfNode(node);
-    makeEvent('down', xy, node);
-  }
-
+  /*
+   * Simulates a mouse move action by firing a `move` mouse event on a
+   * specific node, between a set of coordinates.
+   *
+   * @param {HTMLElement} node The node to fire the event on.
+   * @param {Object} fromXY The (x,y) coordinates the dragging should start from.
+   * @param {Object} toXY The (x,y) coordinates the dragging should end at.
+   * @param {Object} steps Optional. The numbers of steps in the move motion.
+   *    If not specified, the default is 5.
+   */
   function move(node, fromXY, toXY, steps) {
     steps = steps || 5;
     var dx = Math.round((fromXY.x - toXY.x) / steps);
@@ -91,45 +114,15 @@
     }, node);
   }
 
-  function up(node, xy) {
-    xy = xy || middleOfNode(node);
-    makeEvent('up', xy, node);
-  }
-
-  function tap(node) {
-    // Respect nodes that are disabled in the UI.
-    if (window.getComputedStyle(node)['pointer-events'] === 'none')
-      return;
-    var xy = middleOfNode(node);
-    down(node, xy);
-    up(node, xy);
-    makeEvent('tap', xy, node);
-  }
-
-  function focus(target) {
-    Polymer.Base.fire('focus', {}, {
-      bubbles: false,
-      node: target
-    });
-  }
-
-  function blur(target) {
-    Polymer.Base.fire('blur', {}, {
-      bubbles: false,
-      node: target
-    });
-  }
-
-  function downAndUp(target, callback) {
-    down(target);
-    Polymer.Base.async(function() {
-      up(target);
-      tap(target);
-
-      callback && callback();
-    });
-  }
-
+  /*
+   * Simulates a mouse dragging action originating in the middle of a specific node.
+   *
+   * @param {HTMLElement} target The node to fire the event on.
+   * @param {Number} dx The horizontal displacement.
+   * @param {Object} dy The vertical displacement
+   * @param {Object} steps Optional. The numbers of steps in the dragging motion.
+   *    If not specified, the default is 5.
+   */
   function track(target, dx, dy, steps) {
     dx = dx | 0;
     dy = dy | 0;
@@ -144,7 +137,100 @@
     up(target, xy2);
   }
 
-  function keyboardEventFor(type, keyCode) {
+  /*
+   * Fires a `down` mouse event on a specific node, at a given set of coordinates.
+   * This event bubbles and is cancellable. If the (x,y) coordinates are
+   * not specified, the middle of the node will be used instead.
+   *
+   * @param {HTMLElement} node The node to fire the event on.
+   * @param {Object} xy Optional. The (x,y) coordinates the mouse event should be fired from.
+   */
+  function down(node, xy) {
+    xy = xy || middleOfNode(node);
+    makeEvent('down', xy, node);
+  }
+
+  /*
+   * Fires an `up` mouse event on a specific node, at a given set of coordinates.
+   * This event bubbles and is cancellable. If the (x,y) coordinates are
+   * not specified, the middle of the node will be used instead.
+   *
+   * @param {HTMLElement} node The node to fire the event on.
+   * @param {Object} xy Optional. The (x,y) coordinates the mouse event should be fired from.
+   */
+  function up(node, xy) {
+    xy = xy || middleOfNode(node);
+    makeEvent('up', xy, node);
+  }
+
+  /*
+   * Simulates a complete mouse click by firing a `down` mouse event, followed
+   * by an asynchronous `up` and `tap` events on a specific node. Calls the
+   *`callback` after the `tap` event is fired.
+   *
+   * @param {HTMLElement} target The node to fire the event on.
+   * @param {Object} callback Optional. The function to be called after the action ends.
+   */
+  function downAndUp(target, callback) {
+    down(target);
+    Polymer.Base.async(function() {
+      up(target);
+      tap(target);
+
+      callback && callback();
+    });
+  }
+
+  /*
+   * Fires a 'tap' mouse event on a specific node. This respects the pointer-events
+   * set on the node, and will not fire on disabled nodes.
+   *
+   * @param {HTMLElement} node The node to fire the event on.
+   * @param {Object} xy Optional. The (x,y) coordinates the mouse event should be fired from.
+   */
+  function tap(node) {
+    // Respect nodes that are disabled in the UI.
+    if (window.getComputedStyle(node)['pointer-events'] === 'none')
+      return;
+    var xy = middleOfNode(node);
+    down(node, xy);
+    up(node, xy);
+    makeEvent('tap', xy, node);
+  }
+
+  /*
+   * Focuses a node by firing a `focus` event. This event does not bubble.
+   *
+   * @param {HTMLElement} target The node to fire the event on.
+   */
+  function focus(target) {
+    Polymer.Base.fire('focus', {}, {
+      bubbles: false,
+      node: target
+    });
+  }
+
+  /*
+   * Blurs a node by firing a `blur` event. This event does not bubble.
+   *
+   * @param {HTMLElement} target The node to fire the event on.
+   */
+  function blur(target) {
+    Polymer.Base.fire('blur', {}, {
+      bubbles: false,
+      node: target
+    });
+  }
+
+  /*
+   * Returns a keyboard event. This event bubbles and is cancellable.
+   *
+   * @param {String} type The type of keyboard event (such as 'keyup' or 'keydown').
+   * @param {Number} keyCode The keyCode for the event.
+   * @param {?String|[String]} modifiers The key modifiers for the event.
+   * Accepted values are shift, ctrl, alt, meta.
+   */
+  function keyboardEventFor(type, keyCode, modifiers) {
     var event = new CustomEvent(type, {
       bubbles: true,
       cancelable: true
@@ -153,32 +239,87 @@
     event.keyCode = keyCode;
     event.code = keyCode;
 
+    modifiers = modifiers || [];
+    if (typeof modifiers === 'string') {
+      modifiers = [modifiers];
+    }
+    event.shiftKey = modifiers.indexOf('shift') !== -1;
+    event.altKey = modifiers.indexOf('alt') !== -1;
+    event.ctrlKey = modifiers.indexOf('ctrl') !== -1;
+    event.metaKey = modifiers.indexOf('meta') !== -1;
+
     return event;
   }
 
-  function keyEventOn(target, type, keyCode) {
-    target.dispatchEvent(keyboardEventFor(type, keyCode));
+  /*
+   * Fires a keyboard event on a specific node. This event bubbles and is cancellable.
+   *
+   * @param {HTMLElement} target The node to fire the event on.
+   * @param {String} type The type of keyboard event (such as 'keyup' or 'keydown').
+   * @param {Number} keyCode The keyCode for the event.
+   * @param {?String|[String]} modifiers The key modifiers for the event.
+   * Accepted values are shift, ctrl, alt, meta.
+   */
+  function keyEventOn(target, type, keyCode, modifiers) {
+    target.dispatchEvent(keyboardEventFor(type, keyCode, modifiers));
   }
 
-  function keyDownOn(target, keyCode) {
-    keyEventOn(target, 'keydown', keyCode);
+  /*
+   * Fires a 'keydown' event on a specific node. This event bubbles and is cancellable.
+   *
+   * @param {HTMLElement} target The node to fire the event on.
+   * @param {Number} keyCode The keyCode for the event.
+   * @param {?String|[String]} modifiers The key modifiers for the event.
+   * Accepted values are shift, ctrl, alt, meta.
+   */
+  function keyDownOn(target, keyCode, modifiers) {
+    keyEventOn(target, 'keydown', keyCode, modifiers);
   }
 
-  function keyUpOn(target, keyCode) {
-    keyEventOn(target, 'keyup', keyCode);
+  /*
+   * Fires a 'keyup' event on a specific node. This event bubbles and is cancellable.
+   *
+   * @param {HTMLElement} target The node to fire the event on.
+   * @param {Number} keyCode The keyCode for the event.
+   * @param {?String|[String]} modifiers The key modifiers for the event.
+   * Accepted values are shift, ctrl, alt, meta.
+   */
+  function keyUpOn(target, keyCode, modifiers) {
+    keyEventOn(target, 'keyup', keyCode, modifiers);
   }
 
-  function pressAndReleaseKeyOn(target, keyCode) {
-    keyDownOn(target, keyCode);
+  /*
+   * Simulates a complete key press by firing a `keydown` keyboard event, followed
+   * by an asynchronous `keyup` event on a specific node.
+   *
+   * @param {HTMLElement} target The node to fire the event on.
+   * @param {Number} keyCode The keyCode for the event.
+   * @param {?String|[String]} modifiers The key modifiers for the event.
+   * Accepted values are shift, ctrl, alt, meta.
+   */
+  function pressAndReleaseKeyOn(target, keyCode, modifiers) {
+    keyDownOn(target, keyCode, modifiers);
     Polymer.Base.async(function() {
-      keyUpOn(target, keyCode);
+      keyUpOn(target, keyCode, modifiers);
     }, 1);
   }
 
+  /*
+   * Simulates a complete 'enter' key press by firing a `keydown` keyboard event,
+   * followed by an asynchronous `keyup` event on a specific node.
+   *
+   * @param {HTMLElement} target The node to fire the event on.
+   */
   function pressEnter(target) {
     pressAndReleaseKeyOn(target, 13);
   }
 
+  /*
+   * Simulates a complete 'space' key press by firing a `keydown` keyboard event,
+   * followed by an asynchronous `keyup` event on a specific node.
+   *
+   * @param {HTMLElement} target The node to fire the event on.
+   */
   function pressSpace(target) {
     pressAndReleaseKeyOn(target, 32);
   }
@@ -196,6 +337,7 @@
     pressSpace: pressSpace,
     keyDownOn: keyDownOn,
     keyUpOn: keyUpOn,
+    keyEventOn: keyEventOn,
     middleOfNode: middleOfNode,
     topLeftOfNode: topLeftOfNode
   };
diff --git a/third_party/polymer/v1_0/components-chromium/iron-test-helpers/test-helpers.js b/third_party/polymer/v1_0/components-chromium/iron-test-helpers/test-helpers.js
index adaf692..b48bbb9 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-test-helpers/test-helpers.js
+++ b/third_party/polymer/v1_0/components-chromium/iron-test-helpers/test-helpers.js
@@ -10,6 +10,11 @@
 (function(global) {
   'use strict';
 
+  /*
+   * Forces distribution of light children, and lifecycle callbacks on the
+   * Custom Elements polyfill. Used when testing elements that rely on their
+   * distributed children.
+   */
   global.flushAsynchronousOperations = function() {
     // force distribution
     Polymer.dom.flush();
@@ -17,6 +22,11 @@
     window.CustomElements && window.CustomElements.takeRecords();
   };
 
+  /*
+   * Stamps and renders a `dom-if` template.
+   *
+   * @param {HTMLElement} node The node containing the template,
+   */
   global.forceXIfStamp = function(node) {
     var templates = Polymer.dom(node.root).querySelectorAll('template[is=dom-if]');
     for (var tmpl, i = 0; tmpl = templates[i]; i++) {
@@ -26,6 +36,13 @@
     global.flushAsynchronousOperations();
   };
 
+  /*
+   * Fires a custom event on a specific node. This event bubbles and is cancellable.
+   *
+   * @param {String} type The type of event.
+   * @param {Object} props Any custom properties the event contains.
+   * @param {HTMLElement} node The node to fire the event on.
+   */
   global.fireEvent = function(type, props, node) {
     var event = new CustomEvent(type, {
       bubbles: true,
@@ -37,6 +54,19 @@
     node.dispatchEvent(event);
   };
 
+  /*
+   * Skips a test unless a condition is met. Sample use:
+   *    function isNotIE() {
+   *      return !navigator.userAgent.match(/MSIE/i);
+   *    }
+   *    test('runs on non IE browsers', skipUnless(isNotIE, function() {
+   *      ...
+   *    });
+   *
+   * @param {String} condition The name of a Boolean function determining if the test should be run.
+   * @param {Function} test The test to be run.
+   */
+
   global.skipUnless = function(condition, test) {
     var isAsyncTest = !!test.length;
 
diff --git a/third_party/polymer/v1_0/components-chromium/neon-animation/compiled_resources2.gyp b/third_party/polymer/v1_0/components-chromium/neon-animation/compiled_resources2.gyp
index 35e7f55..953c08b 100644
--- a/third_party/polymer/v1_0/components-chromium/neon-animation/compiled_resources2.gyp
+++ b/third_party/polymer/v1_0/components-chromium/neon-animation/compiled_resources2.gyp
@@ -38,14 +38,6 @@
       'includes': ['../../../../closure_compiler/compile_js2.gypi'],
     },
     {
-      'target_name': 'neon-animation-runner-behavior-extracted',
-      'dependencies': [
-        '../iron-meta/compiled_resources2.gyp:iron-meta-extracted',
-        'neon-animatable-behavior-extracted',
-      ],
-      'includes': ['../../../../closure_compiler/compile_js2.gypi'],
-    },
-    {
       'target_name': 'neon-animation-extracted',
       'dependencies': [
         'neon-animatable-behavior-extracted',
@@ -59,6 +51,14 @@
       'includes': ['../../../../closure_compiler/compile_js2.gypi'],
     },
     {
+      'target_name': 'neon-animation-runner-behavior-extracted',
+      'dependencies': [
+        '../iron-meta/compiled_resources2.gyp:iron-meta-extracted',
+        'neon-animatable-behavior-extracted',
+      ],
+      'includes': ['../../../../closure_compiler/compile_js2.gypi'],
+    },
+    {
       'target_name': 'neon-animations-extracted',
       'dependencies': [
         'animations/compiled_resources2.gyp:cascaded-animation-extracted',
diff --git a/third_party/polymer/v1_0/components-chromium/paper-checkbox/.bower.json b/third_party/polymer/v1_0/components-chromium/paper-checkbox/.bower.json
index 0bb2e726..dca95e8 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-checkbox/.bower.json
+++ b/third_party/polymer/v1_0/components-chromium/paper-checkbox/.bower.json
@@ -1,6 +1,6 @@
 {
   "name": "paper-checkbox",
-  "version": "1.1.1",
+  "version": "1.1.3",
   "description": "A material design checkbox",
   "authors": [
     "The Polymer Authors"
@@ -37,11 +37,11 @@
     "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0"
   },
   "main": "paper-checkbox.html",
-  "_release": "1.1.1",
+  "_release": "1.1.3",
   "_resolution": {
     "type": "version",
-    "tag": "v1.1.1",
-    "commit": "ce52f51c537d27f414fec7298b9ebff4248044eb"
+    "tag": "v1.1.3",
+    "commit": "b2698fd0d34153e89369f116f306bc8e8203a460"
   },
   "_source": "git://github.com/PolymerElements/paper-checkbox.git",
   "_target": "^1.0.0",
diff --git a/third_party/polymer/v1_0/components-chromium/paper-checkbox/README.md b/third_party/polymer/v1_0/components-chromium/paper-checkbox/README.md
index 558315d..033675e 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-checkbox/README.md
+++ b/third_party/polymer/v1_0/components-chromium/paper-checkbox/README.md
@@ -49,7 +49,7 @@
 | `--paper-checkbox-checkmark-color` | Checkmark color | `white` |
 | `--paper-checkbox-label-color` | Label color | `--primary-text-color` |
 | `--paper-checkbox-label-spacing` | Spacing between the label and the checkbox | `8px` |
-| `--paper-checkbox-error-color` | Checkbox color when invalid | `--google-red-500` |
+| `--paper-checkbox-error-color` | Checkbox color when invalid | `--error-color` |
 | `--paper-checkbox-size` | Size of the checkbox | `18px` |
 
 This element applies the mixin `--paper-font-common-base` but does not import `paper-styles/typography.html`.
diff --git a/third_party/polymer/v1_0/components-chromium/paper-checkbox/bower.json b/third_party/polymer/v1_0/components-chromium/paper-checkbox/bower.json
index 4947af7..8fb8d63 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-checkbox/bower.json
+++ b/third_party/polymer/v1_0/components-chromium/paper-checkbox/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "paper-checkbox",
-  "version": "1.1.1",
+  "version": "1.1.3",
   "description": "A material design checkbox",
   "authors": [
     "The Polymer Authors"
diff --git a/third_party/polymer/v1_0/components-chromium/paper-checkbox/paper-checkbox.html b/third_party/polymer/v1_0/components-chromium/paper-checkbox/paper-checkbox.html
index 4ef8a47..caba70f 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-checkbox/paper-checkbox.html
+++ b/third_party/polymer/v1_0/components-chromium/paper-checkbox/paper-checkbox.html
@@ -8,7 +8,6 @@
 subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 --><html><head><link rel="import" href="../polymer/polymer.html">
 <link rel="import" href="../paper-styles/default-theme.html">
-<link rel="import" href="../paper-styles/color.html">
 <link rel="import" href="../paper-behaviors/paper-checked-element-behavior.html">
 
 <!--
@@ -40,7 +39,7 @@
 `--paper-checkbox-checkmark-color` | Checkmark color | `white`
 `--paper-checkbox-label-color` | Label color | `--primary-text-color`
 `--paper-checkbox-label-spacing` | Spacing between the label and the checkbox | `8px`
-`--paper-checkbox-error-color` | Checkbox color when invalid | `--google-red-500`
+`--paper-checkbox-error-color` | Checkbox color when invalid | `--error-color`
 `--paper-checkbox-size` | Size of the checkbox | `18px`
 
 This element applies the mixin `--paper-font-common-base` but does not import `paper-styles/typography.html`.
@@ -58,6 +57,7 @@
         cursor: pointer;
         --calculated-paper-checkbox-size: var(--paper-checkbox-size, 18px);
         @apply(--paper-font-common-base);
+        line-height: 0;
       }
 
       :host(:focus) {
@@ -169,7 +169,7 @@
         vertical-align: middle;
         padding-left: var(--paper-checkbox-label-spacing, 8px);
         white-space: normal;
-        pointer-events: none;
+        line-height: normal;
         color: var(--paper-checkbox-label-color, --primary-text-color);
       }
 
@@ -183,9 +183,6 @@
       }
 
       /* disabled state */
-      :host([disabled]) {
-        pointer-events: none;
-      }
 
       :host([disabled]) #checkbox {
         opacity: 0.5;
@@ -203,7 +200,7 @@
 
       /* invalid state */
       #checkbox.invalid:not(.checked) {
-        border-color: var(--paper-checkbox-error-color, --google-red-500);
+        border-color: var(--paper-checkbox-error-color, --error-color);
       }
     </style>
 
diff --git a/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/.bower.json b/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/.bower.json
index 4023c89..6bb6ad4 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/.bower.json
+++ b/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/.bower.json
@@ -1,6 +1,6 @@
 {
   "name": "paper-dialog-behavior",
-  "version": "1.1.1",
+  "version": "1.2.0",
   "description": "Implements a behavior used for material design dialogs",
   "authors": "The Polymer Authors",
   "keywords": [
@@ -26,17 +26,19 @@
   },
   "devDependencies": {
     "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+    "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+    "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
     "paper-button": "PolymerElements/paper-button#^1.0.0",
     "paper-dialog-scrollable": "PolymerElements/paper-dialog-scrollable#^1.0.0",
-    "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+    "paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0",
     "web-component-tester": "^4.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
   },
-  "_release": "1.1.1",
+  "_release": "1.2.0",
   "_resolution": {
     "type": "version",
-    "tag": "v1.1.1",
-    "commit": "5831039e9f878c63478064abed115c98992b5504"
+    "tag": "v1.2.0",
+    "commit": "a3be07d2784073d5e9e5175fb7d13f7b1f2a5558"
   },
   "_source": "git://github.com/PolymerElements/paper-dialog-behavior.git",
   "_target": "^1.0.0",
diff --git a/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/CONTRIBUTING.md b/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/CONTRIBUTING.md
index 7b101415..f147978a 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/CONTRIBUTING.md
+++ b/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/CONTRIBUTING.md
@@ -5,6 +5,11 @@
 
 If you edit that file, it will get updated everywhere else.
 If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
 -->
 # Polymer Elements
 ## Guide for Contributors
@@ -41,7 +46,7 @@
  3. Click the `paper-foo` element.
  ```
 
- 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [http://jsbin.com/cagaye](http://jsbin.com/cagaye/edit?html,output).
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
 
  3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
 
@@ -51,14 +56,14 @@
 
 When submitting pull requests, please provide:
 
- 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues using the following syntax:
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
 
  ```markdown
  (For a single issue)
  Fixes #20
 
  (For multiple issues)
- Fixes #32, #40
+ Fixes #32, fixes #40
  ```
 
  2. **A succinct description of the design** used to fix any related issues. For example:
diff --git a/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/README.md b/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/README.md
index df10124..d67e047 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/README.md
+++ b/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/README.md
@@ -12,9 +12,9 @@
 
 -->
 
-[![Build Status](https://travis-ci.org/PolymerElements/paper-dialog-behavior.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-dialog-behavior)
+[![Build status](https://travis-ci.org/PolymerElements/paper-dialog-behavior.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-dialog-behavior)
 
-_[Demo and API Docs](https://elements.polymer-project.org/elements/paper-dialog-behavior)_
+_[Demo and API docs](https://elements.polymer-project.org/elements/paper-dialog-behavior)_
 
 
 ##Polymer.PaperDialogBehavior
diff --git a/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/bower.json b/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/bower.json
index 7d231ca..f95a6de 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/bower.json
+++ b/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "paper-dialog-behavior",
-  "version": "1.1.1",
+  "version": "1.2.0",
   "description": "Implements a behavior used for material design dialogs",
   "authors": "The Polymer Authors",
   "keywords": [
@@ -26,9 +26,11 @@
   },
   "devDependencies": {
     "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+    "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+    "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
     "paper-button": "PolymerElements/paper-button#^1.0.0",
     "paper-dialog-scrollable": "PolymerElements/paper-dialog-scrollable#^1.0.0",
-    "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+    "paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0",
     "web-component-tester": "^4.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
   }
diff --git a/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/paper-dialog-behavior-extracted.js b/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/paper-dialog-behavior-extracted.js
index a05d175..fadeaec 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/paper-dialog-behavior-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/paper-dialog-behavior-extracted.js
@@ -58,39 +58,28 @@
     properties: {
 
       /**
-       * If `modal` is true, this implies `no-cancel-on-outside-click` and `with-backdrop`.
+       * If `modal` is true, this implies `no-cancel-on-outside-click`, `no-cancel-on-esc-key` and `with-backdrop`.
        */
       modal: {
-        observer: '_modalChanged',
         type: Boolean,
         value: false
-      },
-
-      /** @type {?Node} */
-      _lastFocusedElement: {
-        type: Object
-      },
-
-      _boundOnFocus: {
-        type: Function,
-        value: function() {
-          return this._onFocus.bind(this);
-        }
-      },
-
-      _boundOnBackdropClick: {
-        type: Function,
-        value: function() {
-          return this._onBackdropClick.bind(this);
-        }
       }
 
     },
 
+    observers: [
+      '_modalChanged(modal, _readied)'
+    ],
+
     listeners: {
-      'tap': '_onDialogClick',
-      'iron-overlay-opened': '_onIronOverlayOpened',
-      'iron-overlay-closed': '_onIronOverlayClosed'
+      'tap': '_onDialogClick'
+    },
+
+    ready: function () {
+      // Only now these properties can be read.
+      this.__prevNoCancelOnOutsideClick = this.noCancelOnOutsideClick;
+      this.__prevNoCancelOnEscKey = this.noCancelOnEscKey;
+      this.__prevWithBackdrop = this.withBackdrop;
     },
 
     attached: function() {
@@ -103,17 +92,34 @@
       Polymer.dom(this).unobserveNodes(this._ariaObserver);
     },
 
-    _modalChanged: function() {
-      if (this.modal) {
+    _modalChanged: function(modal, readied) {
+      if (modal) {
         this.setAttribute('aria-modal', 'true');
       } else {
         this.setAttribute('aria-modal', 'false');
       }
-      // modal implies noCancelOnOutsideClick and withBackdrop if true, don't overwrite
-      // those properties otherwise.
-      if (this.modal) {
+
+      // modal implies noCancelOnOutsideClick, noCancelOnEscKey and withBackdrop.
+      // We need to wait for the element to be ready before we can read the
+      // properties values.
+      if (!readied) {
+        return;
+      }
+
+      if (modal) {
+        this.__prevNoCancelOnOutsideClick = this.noCancelOnOutsideClick;
+        this.__prevNoCancelOnEscKey = this.noCancelOnEscKey;
+        this.__prevWithBackdrop = this.withBackdrop;
         this.noCancelOnOutsideClick = true;
+        this.noCancelOnEscKey = true;
         this.withBackdrop = true;
+      } else {
+        // If the value was changed to false, let it false.
+        this.noCancelOnOutsideClick = this.noCancelOnOutsideClick &&
+          this.__prevNoCancelOnOutsideClick;
+        this.noCancelOnEscKey = this.noCancelOnEscKey &&
+          this.__prevNoCancelOnEscKey;
+        this.withBackdrop = this.withBackdrop && this.__prevWithBackdrop;
       }
     },
 
@@ -143,57 +149,21 @@
       this.closingReason.confirmed = confirmed;
     },
 
+    /**
+     * Will dismiss the dialog if user clicked on an element with dialog-dismiss
+     * or dialog-confirm attribute.
+     */
     _onDialogClick: function(event) {
-      var target = Polymer.dom(event).rootTarget;
-      while (target && target !== this) {
-        if (target.hasAttribute) {
-          if (target.hasAttribute('dialog-dismiss')) {
-            this._updateClosingReasonConfirmed(false);
-            this.close();
-            event.stopPropagation();
-            break;
-          } else if (target.hasAttribute('dialog-confirm')) {
-            this._updateClosingReasonConfirmed(true);
-            this.close();
-            event.stopPropagation();
-            break;
-          }
-        }
-        target = Polymer.dom(target).parentNode;
-      }
-    },
-
-    _onIronOverlayOpened: function() {
-      if (this.modal) {
-        document.body.addEventListener('focus', this._boundOnFocus, true);
-        document.body.addEventListener('click', this._boundOnBackdropClick, true);
-      }
-    },
-
-    _onIronOverlayClosed: function() {
-      this._lastFocusedElement = null;
-      document.body.removeEventListener('focus', this._boundOnFocus, true);
-      document.body.removeEventListener('click', this._boundOnBackdropClick, true);
-    },
-
-    _onFocus: function(event) {
-      if (this.modal && this._manager.currentOverlay() === this) {
-        if (Polymer.dom(event).path.indexOf(this) !== -1) {
-          this._lastFocusedElement = event.target;
-        } else if (this._lastFocusedElement) {
-          this._lastFocusedElement.focus();
-        } else {
-          this._focusNode.focus();
-        }
-      }
-    },
-
-    _onBackdropClick: function(event) {
-      if (this.modal && this._manager.currentOverlay() === this && Polymer.dom(event).path.indexOf(this) === -1) {
-        if (this._lastFocusedElement) {
-          this._lastFocusedElement.focus();
-        } else {
-          this._focusNode.focus();
+      // Search for the element with dialog-confirm or dialog-dismiss,
+      // from the root target until this (excluded).
+      var path = Polymer.dom(event).path;
+      for (var i = 0; i < path.indexOf(this); i++) {
+        var target = path[i];
+        if (target.hasAttribute && (target.hasAttribute('dialog-dismiss') || target.hasAttribute('dialog-confirm'))) {
+          this._updateClosingReasonConfirmed(target.hasAttribute('dialog-confirm'));
+          this.close();
+          event.stopPropagation();
+          break;
         }
       }
     }
diff --git a/third_party/polymer/v1_0/components-chromium/paper-drawer-panel/.bower.json b/third_party/polymer/v1_0/components-chromium/paper-drawer-panel/.bower.json
index a0e0d5e..9bb503e 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-drawer-panel/.bower.json
+++ b/third_party/polymer/v1_0/components-chromium/paper-drawer-panel/.bower.json
@@ -1,6 +1,6 @@
 {
   "name": "paper-drawer-panel",
-  "version": "1.0.6",
+  "version": "1.0.7",
   "description": "A responsive drawer panel",
   "authors": [
     "The Polymer Authors"
@@ -28,17 +28,18 @@
     "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
     "paper-button": "PolymerElements/paper-button#^1.0.0",
     "paper-styles": "PolymerElements/paper-styles#^1.0.0",
+    "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
     "test-fixture": "PolymerElements/test-fixture#^1.0.0",
-    "web-component-tester": "polymer/web-component-tester#^3.4.0",
+    "web-component-tester": "^4.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
   },
   "main": "paper-drawer-panel.html",
   "ignore": [],
-  "_release": "1.0.6",
+  "_release": "1.0.7",
   "_resolution": {
     "type": "version",
-    "tag": "v1.0.6",
-    "commit": "9dd19ef9153ed303a5f8b6d573179cde31b2f5e6"
+    "tag": "v1.0.7",
+    "commit": "1d791255c062c0c4c4fd9f6f2b2c1ef16b533721"
   },
   "_source": "git://github.com/PolymerElements/paper-drawer-panel.git",
   "_target": "^1.0.0",
diff --git a/third_party/polymer/v1_0/components-chromium/paper-drawer-panel/CONTRIBUTING.md b/third_party/polymer/v1_0/components-chromium/paper-drawer-panel/CONTRIBUTING.md
index 7b101415..f147978a 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-drawer-panel/CONTRIBUTING.md
+++ b/third_party/polymer/v1_0/components-chromium/paper-drawer-panel/CONTRIBUTING.md
@@ -5,6 +5,11 @@
 
 If you edit that file, it will get updated everywhere else.
 If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
 -->
 # Polymer Elements
 ## Guide for Contributors
@@ -41,7 +46,7 @@
  3. Click the `paper-foo` element.
  ```
 
- 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [http://jsbin.com/cagaye](http://jsbin.com/cagaye/edit?html,output).
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
 
  3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
 
@@ -51,14 +56,14 @@
 
 When submitting pull requests, please provide:
 
- 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues using the following syntax:
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
 
  ```markdown
  (For a single issue)
  Fixes #20
 
  (For multiple issues)
- Fixes #32, #40
+ Fixes #32, fixes #40
  ```
 
  2. **A succinct description of the design** used to fix any related issues. For example:
diff --git a/third_party/polymer/v1_0/components-chromium/paper-drawer-panel/README.md b/third_party/polymer/v1_0/components-chromium/paper-drawer-panel/README.md
index 1fa8c96..78ada9e 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-drawer-panel/README.md
+++ b/third_party/polymer/v1_0/components-chromium/paper-drawer-panel/README.md
@@ -7,16 +7,18 @@
 Edit those files, and our readme bot will duplicate them over here!
 Edit this file, and the bot will squash your changes :)
 
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
 -->
 
-[![Build Status](https://travis-ci.org/PolymerElements/paper-drawer-panel.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-drawer-panel)
+[![Build status](https://travis-ci.org/PolymerElements/paper-drawer-panel.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-drawer-panel)
 
-_[Demo and API Docs](https://elements.polymer-project.org/elements/paper-drawer-panel)_
+_[Demo and API docs](https://elements.polymer-project.org/elements/paper-drawer-panel)_
 
 
 ##&lt;paper-drawer-panel&gt;
 
-
 Material design: [Navigation drawer](https://www.google.com/design/spec/patterns/navigation-drawer.html)
 
 `paper-drawer-panel` contains a drawer panel and a main panel.  The drawer
@@ -31,26 +33,30 @@
 
 Example:
 
-    <paper-drawer-panel>
-      <div drawer> Drawer panel... </div>
-      <div main> Main panel... </div>
-    </paper-drawer-panel>
+```html
+<paper-drawer-panel>
+  <div drawer> Drawer panel... </div>
+  <div main> Main panel... </div>
+</paper-drawer-panel>
+```
 
 The drawer and the main panels are not scrollable.  You can set CSS overflow
 property on the elements to make them scrollable or use `paper-header-panel`.
 
 Example:
 
-    <paper-drawer-panel>
-      <paper-header-panel drawer>
-        <paper-toolbar></paper-toolbar>
-        <div> Drawer content... </div>
-      </paper-header-panel>
-      <paper-header-panel main>
-        <paper-toolbar></paper-toolbar>
-        <div> Main content... </div>
-      </paper-header-panel>
-    </paper-drawer-panel>
+```html
+<paper-drawer-panel>
+  <paper-header-panel drawer>
+    <paper-toolbar></paper-toolbar>
+    <div> Drawer content... </div>
+  </paper-header-panel>
+  <paper-header-panel main>
+    <paper-toolbar></paper-toolbar>
+    <div> Main content... </div>
+  </paper-header-panel>
+</paper-drawer-panel>
+```
 
 An element that should toggle the drawer will automatically do so if it's
 given the `paper-drawer-toggle` attribute.  Also this element will automatically
@@ -58,72 +64,84 @@
 
 Example:
 
-    <paper-drawer-panel>
-      <paper-header-panel drawer>
-        <paper-toolbar>
-          <div>Application</div>
-        </paper-toolbar>
-        <div> Drawer content... </div>
-      </paper-header-panel>
-      <paper-header-panel main>
-        <paper-toolbar>
-          <paper-icon-button icon="menu" paper-drawer-toggle></paper-icon-button>
-          <div>Title</div>
-        </paper-toolbar>
-        <div> Main content... </div>
-      </paper-header-panel>
-    </paper-drawer-panel>
+```html
+<paper-drawer-panel>
+  <paper-header-panel drawer>
+    <paper-toolbar>
+      <div>Application</div>
+    </paper-toolbar>
+    <div> Drawer content... </div>
+  </paper-header-panel>
+  <paper-header-panel main>
+    <paper-toolbar>
+      <paper-icon-button icon="menu" paper-drawer-toggle></paper-icon-button>
+      <div>Title</div>
+    </paper-toolbar>
+    <div> Main content... </div>
+  </paper-header-panel>
+</paper-drawer-panel>
+```
 
 To position the drawer to the right, add `right-drawer` attribute.
 
-    <paper-drawer-panel right-drawer>
-      <div drawer> Drawer panel... </div>
-      <div main> Main panel... </div>
-    </paper-drawer-panel>
+```html
+<paper-drawer-panel right-drawer>
+  <div drawer> Drawer panel... </div>
+  <div main> Main panel... </div>
+</paper-drawer-panel>
+```
 
 ### Styling
 
 To change the main container:
 
-    paper-drawer-panel {
-      --paper-drawer-panel-main-container: {
-        background-color: gray;
-      };
-    }
+```css
+paper-drawer-panel {
+  --paper-drawer-panel-main-container: {
+    background-color: gray;
+  };
+}
+```
 
 To change the drawer container when it's in the left side:
 
-    paper-drawer-panel {
-      --paper-drawer-panel-left-drawer-container: {
-        background-color: white;
-      };
-    }
+```css
+paper-drawer-panel {
+  --paper-drawer-panel-left-drawer-container: {
+    background-color: white;
+  };
+}
+```
 
 To change the drawer container when it's in the right side:
 
-    paper-drawer-panel {
-      --paper-drawer-panel-right-drawer-container: {
-        background-color: white;
-      };
-    }
+```css
+paper-drawer-panel {
+  --paper-drawer-panel-right-drawer-container: {
+    background-color: white;
+  };
+}
+```
 
 To customize the scrim:
 
-    paper-drawer-panel {
-      --paper-drawer-panel-scrim: {
-        background-color: red;
-      };
-    }
+```css
+paper-drawer-panel {
+  --paper-drawer-panel-scrim: {
+    background-color: red;
+  };
+}
+```
 
 The following custom properties and mixins are available for styling:
 
-Custom property | Description | Default
-----------------|-------------|----------
-`--paper-drawer-panel-scrim-opacity` | Scrim opacity | 1
-`--paper-drawer-panel-drawer-container` | Mixin applied to drawer container | {}
-`--paper-drawer-panel-left-drawer-container` | Mixin applied to container when it's in the left side | {}
-`--paper-drawer-panel-main-container` | Mixin applied to main container | {}
-`--paper-drawer-panel-right-drawer-container` | Mixin applied to container when it's in the right side | {}
-`--paper-drawer-panel-scrim` | Mixin applied to scrim | {}
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--paper-drawer-panel-scrim-opacity` | Scrim opacity | 1 |
+| `--paper-drawer-panel-drawer-container` | Mixin applied to drawer container | {} |
+| `--paper-drawer-panel-left-drawer-container` | Mixin applied to container when it's in the left side | {} |
+| `--paper-drawer-panel-main-container` | Mixin applied to main container | {} |
+| `--paper-drawer-panel-right-drawer-container` | Mixin applied to container when it's in the right side | {} |
+| `--paper-drawer-panel-scrim` | Mixin applied to scrim | {} |
 
 
diff --git a/third_party/polymer/v1_0/components-chromium/paper-drawer-panel/bower.json b/third_party/polymer/v1_0/components-chromium/paper-drawer-panel/bower.json
index d5e05e6..9ca9102 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-drawer-panel/bower.json
+++ b/third_party/polymer/v1_0/components-chromium/paper-drawer-panel/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "paper-drawer-panel",
-  "version": "1.0.6",
+  "version": "1.0.7",
   "description": "A responsive drawer panel",
   "authors": [
     "The Polymer Authors"
@@ -28,8 +28,9 @@
     "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
     "paper-button": "PolymerElements/paper-button#^1.0.0",
     "paper-styles": "PolymerElements/paper-styles#^1.0.0",
+    "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
     "test-fixture": "PolymerElements/test-fixture#^1.0.0",
-    "web-component-tester": "polymer/web-component-tester#^3.4.0",
+    "web-component-tester": "^4.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
   },
   "main": "paper-drawer-panel.html",
diff --git a/third_party/polymer/v1_0/components-chromium/paper-drawer-panel/paper-drawer-panel-extracted.js b/third_party/polymer/v1_0/components-chromium/paper-drawer-panel/paper-drawer-panel-extracted.js
index 861e7f7..910830b 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-drawer-panel/paper-drawer-panel-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/paper-drawer-panel/paper-drawer-panel-extracted.js
@@ -189,6 +189,25 @@
           },
 
           /**
+           * The CSS selector for the element that should receive focus when the drawer is open.
+           * By default, when the drawer opens, it focuses the first tabbable element. That is,
+           * the first element that can receive focus.
+           */
+          drawerFocusSelector: {
+            type: String,
+            value:
+                '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"])'
+          },
+
+          /**
            * Whether the transition is enabled.
            */
           _transition: {
@@ -202,13 +221,22 @@
           tap: '_onTap',
           track: '_onTrack',
           down: '_downHandler',
-          up: '_upHandler'
+          up: '_upHandler',
+          transitionend: '_onTransitionEnd'
         },
 
         observers: [
-          '_forceNarrowChanged(forceNarrow, defaultSelected)'
+          '_forceNarrowChanged(forceNarrow, defaultSelected)',
+          '_toggleFocusListener(selected)'
         ],
 
+        ready: function() {
+          // Avoid transition at the beginning e.g. page loads and enable
+          // transitions only after the element is rendered and ready.
+          this._transition = true;
+          this._boundFocusListener = this._didFocus.bind(this);
+        },
+
         /**
          * Toggles the panel open and closed.
          *
@@ -240,16 +268,19 @@
           this.selected = 'main';
         },
 
-        ready: function() {
-          // Avoid transition at the beginning e.g. page loads and enable
-          // transitions only after the element is rendered and ready.
-          this._transition = true;
-        },
-
-        _onMainTransitionEnd: function (e) {
-          if (e.currentTarget === this.$.main && (e.propertyName === 'left' || e.propertyName === 'right')) {
+        _onTransitionEnd: function (e) {
+          var target = Polymer.dom(e).localTarget;
+          if (target !== this) {
+            // ignore events coming from the light dom
+            return;
+          }
+          if (e.propertyName === 'left' || e.propertyName === 'right') {
             this.notifyResize();
           }
+          if (e.propertyName === 'transform' && this.selected === 'drawer') {
+            var focusedChild = this._getAutoFocusedNode();
+            focusedChild && focusedChild.focus();
+          }
         },
 
         _computeIronSelectorClass: function(narrow, transition, dragging, rightDrawer, peeking) {
@@ -302,15 +333,12 @@
               this._trackEnd(event);
               break;
           }
-
         },
 
         _responsiveChange: function(narrow) {
           this._setNarrow(narrow);
 
-          if (this.narrow) {
-            this.selected = this.defaultSelected;
-          }
+          this.selected = this.narrow ? this.defaultSelected : null;
 
           this.setScrollDirection(this._swipeAllowed() ? 'y' : 'all');
           this.fire('paper-responsive-change', {narrow: this.narrow});
@@ -446,14 +474,49 @@
           if (translateX === null) {
             return '';
           }
-
           return this.hasWillChange ? 'translateX(' + translateX + 'px)' :
               'translate3d(' + translateX + 'px, 0, 0)';
         },
 
         _moveDrawer: function(translateX) {
           this.transform(this._transformForTranslateX(translateX), this.$.drawer);
-        }
+        },
 
+        _getDrawerContent: function() {
+          return Polymer.dom(this.$.drawerContent).getDistributedNodes()[0];
+        },
+
+        _getAutoFocusedNode: function() {
+          var drawerContent = this._getDrawerContent();
+          return Polymer.dom(drawerContent).querySelector(this.drawerFocusSelector) || drawerContent;
+        },
+
+        _toggleFocusListener: function(selected) {
+          if (selected === 'drawer') {
+            document.addEventListener('focus', this._boundFocusListener, true);
+          } else {
+            document.removeEventListener('focus', this._boundFocusListener, true);
+          }
+        },
+
+        _didFocus: function(event) {
+          var path = Polymer.dom(event).path;
+          var focusedChild = path[0];
+          var drawerContent = this._getDrawerContent();
+          var focusedChildCameFromDrawer = false;
+          var autoFocusedNode = this._getAutoFocusedNode();
+
+          while (!focusedChildCameFromDrawer && path[0] && path[0].hasAttribute) {
+            focusedChildCameFromDrawer = path.shift() === drawerContent;
+          }
+          if (!focusedChildCameFromDrawer && autoFocusedNode) {
+            autoFocusedNode.focus();
+          }
+        },
+
+        _isDrawerClosed: function(narrow, selected) {
+          return !narrow || selected !== 'drawer';
+        }
       });
+
     }());
\ No newline at end of file
diff --git a/third_party/polymer/v1_0/components-chromium/paper-drawer-panel/paper-drawer-panel.html b/third_party/polymer/v1_0/components-chromium/paper-drawer-panel/paper-drawer-panel.html
index 8423d90a..89fc566 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-drawer-panel/paper-drawer-panel.html
+++ b/third_party/polymer/v1_0/components-chromium/paper-drawer-panel/paper-drawer-panel.html
@@ -228,6 +228,8 @@
       }
 
       .left-drawer.narrow-layout > #drawer:not(.iron-selected) {
+        visibility: hidden;
+
         -webkit-transform: translateX(-100%);
         transform: translateX(-100%);
       }
@@ -240,8 +242,10 @@
         transform: translateX(100%);
       }
 
-      .right-drawer.narrow-layout.dragging > #drawer:not(.iron-selected),
-      .right-drawer.narrow-layout.peeking > #drawer:not(.iron-selected) {
+      .left-drawer.dragging > #drawer:not(.iron-selected),
+      .left-drawer.peeking > #drawer:not(.iron-selected),
+      .right-drawer.dragging > #drawer:not(.iron-selected),
+      .right-drawer.peeking > #drawer:not(.iron-selected) {
         visibility: visible;
       }
 
@@ -270,7 +274,7 @@
         box-sizing: border-box;
       }
 
-      iron-selector:not(.narrow-layout) #main ::content [paper-drawer-toggle] {
+      iron-selector:not(.narrow-layout) ::content [paper-drawer-toggle] {
         display: none;
       }
     </style>
@@ -280,13 +284,13 @@
 
     <iron-selector attr-for-selected="id" class$="[[_computeIronSelectorClass(narrow, _transition, dragging, rightDrawer, peeking)]]" activate-event="" selected="[[selected]]">
 
-      <div id="main" style$="[[_computeMainStyle(narrow, rightDrawer, drawerWidth)]]" on-transitionend="_onMainTransitionEnd">
+      <div id="main" style$="[[_computeMainStyle(narrow, rightDrawer, drawerWidth)]]">
         <content select="[main]"></content>
         <div id="scrim" on-tap="closeDrawer"></div>
       </div>
 
       <div id="drawer" style$="[[_computeDrawerStyle(drawerWidth)]]">
-        <content select="[drawer]"></content>
+        <content id="drawerContent" select="[drawer]"></content>
       </div>
 
     </iron-selector>
diff --git a/third_party/polymer/v1_0/components-chromium/paper-fab/.bower.json b/third_party/polymer/v1_0/components-chromium/paper-fab/.bower.json
index a71b031..80ab078 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-fab/.bower.json
+++ b/third_party/polymer/v1_0/components-chromium/paper-fab/.bower.json
@@ -1,6 +1,6 @@
 {
   "name": "paper-fab",
-  "version": "1.1.2",
+  "version": "1.2.0",
   "description": "A material design floating action button",
   "authors": [
     "The Polymer Authors"
@@ -25,7 +25,6 @@
     "iron-icons": "PolymerElements/iron-icons#^1.0.0",
     "paper-behaviors": "PolymerElements/paper-behaviors#^1.0.0",
     "paper-material": "PolymerElements/paper-material#^1.0.5",
-    "paper-ripple": "PolymerElements/paper-ripple#^1.0.0",
     "paper-styles": "PolymerElements/paper-styles#^1.0.0",
     "polymer": "Polymer/polymer#^1.0.0"
   },
@@ -34,14 +33,14 @@
     "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
     "paper-styles": "PolymerElements/paper-styles#^1.0.0",
     "test-fixture": "PolymerElements/test-fixture#^1.0.0",
-    "web-component-tester": "polymer/web-component-tester#^3.4.0",
+    "web-component-tester": "^4.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
   },
-  "_release": "1.1.2",
+  "_release": "1.2.0",
   "_resolution": {
     "type": "version",
-    "tag": "v1.1.2",
-    "commit": "19bf68f79e4ece424bbaf4cfa1c74c62d481c75d"
+    "tag": "v1.2.0",
+    "commit": "691638ca9b922411926b916a592f01a5f25c1af8"
   },
   "_source": "git://github.com/PolymerElements/paper-fab.git",
   "_target": "^1.0.0",
diff --git a/third_party/polymer/v1_0/components-chromium/paper-fab/CONTRIBUTING.md b/third_party/polymer/v1_0/components-chromium/paper-fab/CONTRIBUTING.md
index 7b101415..f147978a 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-fab/CONTRIBUTING.md
+++ b/third_party/polymer/v1_0/components-chromium/paper-fab/CONTRIBUTING.md
@@ -5,6 +5,11 @@
 
 If you edit that file, it will get updated everywhere else.
 If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
 -->
 # Polymer Elements
 ## Guide for Contributors
@@ -41,7 +46,7 @@
  3. Click the `paper-foo` element.
  ```
 
- 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [http://jsbin.com/cagaye](http://jsbin.com/cagaye/edit?html,output).
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
 
  3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
 
@@ -51,14 +56,14 @@
 
 When submitting pull requests, please provide:
 
- 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues using the following syntax:
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
 
  ```markdown
  (For a single issue)
  Fixes #20
 
  (For multiple issues)
- Fixes #32, #40
+ Fixes #32, fixes #40
  ```
 
  2. **A succinct description of the design** used to fix any related issues. For example:
diff --git a/third_party/polymer/v1_0/components-chromium/paper-fab/README.md b/third_party/polymer/v1_0/components-chromium/paper-fab/README.md
index f2bb1c83..a1fb4bab 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-fab/README.md
+++ b/third_party/polymer/v1_0/components-chromium/paper-fab/README.md
@@ -7,16 +7,18 @@
 Edit those files, and our readme bot will duplicate them over here!
 Edit this file, and the bot will squash your changes :)
 
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
 -->
 
-[![Build Status](https://travis-ci.org/PolymerElements/paper-fab.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-fab)
+[![Build status](https://travis-ci.org/PolymerElements/paper-fab.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-fab)
 
-_[Demo and API Docs](https://elements.polymer-project.org/elements/paper-fab)_
+_[Demo and API docs](https://elements.polymer-project.org/elements/paper-fab)_
 
 
 ##&lt;paper-fab&gt;
 
-
 Material design: [Floating Action Button](https://www.google.com/design/spec/components/buttons-floating-action-button.html)
 
 `paper-fab` is a floating action button. It contains an image placed in the center and
@@ -28,26 +30,27 @@
 
 Example:
 
-    <link href="path/to/iron-icons/iron-icons.html" rel="import">
+```html
+<link href="path/to/iron-icons/iron-icons.html" rel="import">
 
-    <paper-fab icon="add"></paper-fab>
-    <paper-fab mini icon="favorite"></paper-fab>
-    <paper-fab src="star.png"></paper-fab>
-
+<paper-fab icon="add"></paper-fab>
+<paper-fab mini icon="favorite"></paper-fab>
+<paper-fab src="star.png"></paper-fab>
+```
 
 ### Styling
 
 The following custom properties and mixins are available for styling:
 
-Custom property | Description | Default
-----------------|-------------|----------
-`--paper-fab-background` | The background color of the button | `--accent-color`
-`--paper-fab-keyboard-focus-background` | The background color of the button when focused | `--paper-pink-900`
-`--paper-fab-disabled-background` | The background color of the button when it's disabled | `--paper-grey-300`
-`--paper-fab-disabled-text` | The text color of the button when it's disabled | `--paper-grey-500`
-`--paper-fab` | Mixin applied to the button | `{}`
-`--paper-fab-mini` | Mixin applied to a mini button | `{}`
-`--paper-fab-disabled` | Mixin applied to a disabled button | `{}`
-`--paper-fab-iron-icon` | Mixin applied to the iron-icon within the button | `{}`
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--paper-fab-background` | The background color of the button | `--accent-color` |
+| `--paper-fab-keyboard-focus-background` | The background color of the button when focused | `--paper-pink-900` |
+| `--paper-fab-disabled-background` | The background color of the button when it's disabled | `--paper-grey-300` |
+| `--paper-fab-disabled-text` | The text color of the button when it's disabled | `--paper-grey-500` |
+| `--paper-fab` | Mixin applied to the button | `{}` |
+| `--paper-fab-mini` | Mixin applied to a mini button | `{}` |
+| `--paper-fab-disabled` | Mixin applied to a disabled button | `{}` |
+| `--paper-fab-iron-icon` | Mixin applied to the iron-icon within the button | `{}` |
 
 
diff --git a/third_party/polymer/v1_0/components-chromium/paper-fab/bower.json b/third_party/polymer/v1_0/components-chromium/paper-fab/bower.json
index 34966aa..e6a98ba8 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-fab/bower.json
+++ b/third_party/polymer/v1_0/components-chromium/paper-fab/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "paper-fab",
-  "version": "1.1.2",
+  "version": "1.2.0",
   "description": "A material design floating action button",
   "authors": [
     "The Polymer Authors"
@@ -25,7 +25,6 @@
     "iron-icons": "PolymerElements/iron-icons#^1.0.0",
     "paper-behaviors": "PolymerElements/paper-behaviors#^1.0.0",
     "paper-material": "PolymerElements/paper-material#^1.0.5",
-    "paper-ripple": "PolymerElements/paper-ripple#^1.0.0",
     "paper-styles": "PolymerElements/paper-styles#^1.0.0",
     "polymer": "Polymer/polymer#^1.0.0"
   },
@@ -34,7 +33,7 @@
     "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
     "paper-styles": "PolymerElements/paper-styles#^1.0.0",
     "test-fixture": "PolymerElements/test-fixture#^1.0.0",
-    "web-component-tester": "polymer/web-component-tester#^3.4.0",
+    "web-component-tester": "^4.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
   }
 }
diff --git a/third_party/polymer/v1_0/components-chromium/paper-fab/compiled_resources2.gyp b/third_party/polymer/v1_0/components-chromium/paper-fab/compiled_resources2.gyp
index 0c0c131..3a94990a 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-fab/compiled_resources2.gyp
+++ b/third_party/polymer/v1_0/components-chromium/paper-fab/compiled_resources2.gyp
@@ -10,7 +10,6 @@
       'dependencies': [
         '../iron-icon/compiled_resources2.gyp:iron-icon-extracted',
         '../paper-behaviors/compiled_resources2.gyp:paper-button-behavior-extracted',
-        '../paper-ripple/compiled_resources2.gyp:paper-ripple-extracted',
       ],
       'includes': ['../../../../closure_compiler/compile_js2.gypi'],
     },
diff --git a/third_party/polymer/v1_0/components-chromium/paper-fab/index.html b/third_party/polymer/v1_0/components-chromium/paper-fab/index.html
index c98a658d..b0ced26a 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-fab/index.html
+++ b/third_party/polymer/v1_0/components-chromium/paper-fab/index.html
@@ -2,11 +2,11 @@
 <!--
 @license
 Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
-This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE
-The complete set of authors may be found at http://polymer.github.io/AUTHORS
-The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
 Code distributed by Google as part of the polymer project is also
-subject to an additional IP rights grant found at http://polymer.github.io/PATENTS
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 -->
 <html>
 <head>
diff --git a/third_party/polymer/v1_0/components-chromium/paper-fab/paper-fab-extracted.js b/third_party/polymer/v1_0/components-chromium/paper-fab/paper-fab-extracted.js
index e2e94d3..2121d0d 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-fab/paper-fab-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/paper-fab/paper-fab-extracted.js
@@ -1,49 +1,54 @@
 Polymer({
-    is: 'paper-fab',
+      is: 'paper-fab',
 
-    behaviors: [
-      Polymer.PaperButtonBehavior
-    ],
+      behaviors: [
+        Polymer.PaperButtonBehavior
+      ],
 
-    properties: {
-      /**
-       * The URL of an image for the icon. If the src property is specified,
-       * the icon property should not be.
-       *
-       * @attribute src
-       * @type string
-       * @default ''
-       */
-      src: {
-        type: String,
-        value: ''
+      properties: {
+        /**
+         * The URL of an image for the icon. If the src property is specified,
+         * the icon property should not be.
+         */
+        src: {
+          type: String,
+          value: ''
+        },
+
+        /**
+         * Specifies the icon name or index in the set of icons available in
+         * the icon's icon set. If the icon property is specified,
+         * the src property should not be.
+         */
+        icon: {
+          type: String,
+          value: ''
+        },
+
+        /**
+         * Set this to true to style this is a "mini" FAB.
+         */
+        mini: {
+          type: Boolean,
+          value: false,
+          reflectToAttribute: true
+        },
+
+        /**
+         * The label displayed in the badge. The label is centered, and ideally
+         * should have very few characters.
+         */
+        label: {
+          type: String,
+          observer: '_labelChanged'
+        }
       },
 
-      /**
-       * Specifies the icon name or index in the set of icons available in
-       * the icon's icon set. If the icon property is specified,
-       * the src property should not be.
-       *
-       * @attribute icon
-       * @type string
-       * @default ''
-       */
-      icon: {
-        type: String,
-        value: ''
+      _labelChanged: function() {
+        this.setAttribute('aria-label', this.label);
       },
 
-      /**
-       * Set this to true to style this is a "mini" FAB.
-       *
-       * @attribute mini
-       * @type boolean
-       * @default false
-       */
-      mini: {
-        type: Boolean,
-        value: false,
-        reflectToAttribute: true
+      _computeIsIconFab: function(icon, src) {
+        return (icon.length > 0) || (src.length > 0);
       }
-    }
-  });
\ No newline at end of file
+    });
\ No newline at end of file
diff --git a/third_party/polymer/v1_0/components-chromium/paper-fab/paper-fab.html b/third_party/polymer/v1_0/components-chromium/paper-fab/paper-fab.html
index a50a409..546614e 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-fab/paper-fab.html
+++ b/third_party/polymer/v1_0/components-chromium/paper-fab/paper-fab.html
@@ -11,7 +11,6 @@
 <link rel="import" href="../iron-icon/iron-icon.html">
 <link rel="import" href="../paper-behaviors/paper-button-behavior.html">
 <link rel="import" href="../paper-material/paper-material-shared-styles.html">
-<link rel="import" href="../paper-ripple/paper-ripple.html">
 <link rel="import" href="../paper-styles/color.html">
 <link rel="import" href="../paper-styles/default-theme.html">
 
@@ -51,39 +50,43 @@
 
 @group Paper Elements
 @demo demo/index.html
-
 -->
 
 </head><body><dom-module id="paper-fab">
   <template strip-whitespace="">
     <style include="paper-material-shared-styles">
       :host {
-        display: inline-block;
-        position: relative;
+        @apply(--layout-vertical);
+        @apply(--layout-center-center);
+
+        background: var(--paper-fab-background, --accent-color);
+        border-radius: 50%;
+        box-sizing: border-box;
+        color: var(--text-primary-color);
+        cursor: pointer;
+        height: 56px;
+        min-width: 0;
         outline: none;
+        padding: 16px;
+        position: relative;
         -moz-user-select: none;
         -ms-user-select: none;
         -webkit-user-select: none;
-        -webkit-tap-highlight-color: rgba(0,0,0,0);
         user-select: none;
-        cursor: pointer;
-
-        box-sizing: border-box;
-        min-width: 0;
         width: 56px;
-        height: 56px;
-        background: var(--paper-fab-background, --accent-color);
-        color: var(--text-primary-color);
-        border-radius: 50%;
-        padding: 16px;
-
         z-index: 0;
 
-        @apply(--layout-vertical);
-        @apply(--layout-center-center);
+        /* NOTE: Both values are needed, since some phones require the value `transparent`. */
+        -webkit-tap-highlight-color: rgba(0,0,0,0);
+        -webkit-tap-highlight-color: transparent;
+
         @apply(--paper-fab);
       }
 
+      [hidden] {
+        display: none !important;
+      }
+
       :host([mini]) {
         width: 40px;
         height: 40px;
@@ -95,6 +98,7 @@
       :host([disabled]) {
         color: var(--paper-fab-disabled-text, --paper-grey-500);
         background: var(--paper-fab-disabled-background, --paper-grey-300);
+
         @apply(--paper-fab-disabled);
       }
 
@@ -102,13 +106,22 @@
         @apply(--paper-fab-iron-icon);
       }
 
+      span {
+        width: 100%;
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        text-align: center;
+      }
+
       :host(.keyboard-focus) {
         background: var(--paper-fab-keyboard-focus-background, --paper-pink-900);
       }
     </style>
 
-    <iron-icon id="icon" src="[[src]]" icon="[[icon]]"></iron-icon>
+    <iron-icon id="icon" hidden$="{{!_computeIsIconFab(icon, src)}}" src="[[src]]" icon="[[icon]]"></iron-icon>
+    <span hidden$="{{_computeIsIconFab(icon, src)}}">{{label}}</span>
   </template>
-</dom-module>
 
+  </dom-module>
 <script src="paper-fab-extracted.js"></script></body></html>
\ No newline at end of file
diff --git a/third_party/polymer/v1_0/components-chromium/paper-header-panel/.bower.json b/third_party/polymer/v1_0/components-chromium/paper-header-panel/.bower.json
index 006626fa..b21c460 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-header-panel/.bower.json
+++ b/third_party/polymer/v1_0/components-chromium/paper-header-panel/.bower.json
@@ -1,6 +1,6 @@
 {
   "name": "paper-header-panel",
-  "version": "1.1.3",
+  "version": "1.1.4",
   "description": "A header and content wrapper for layout with headers",
   "authors": [
     "The Polymer Authors"
@@ -30,11 +30,11 @@
     "web-component-tester": "^4.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
   },
-  "_release": "1.1.3",
+  "_release": "1.1.4",
   "_resolution": {
     "type": "version",
-    "tag": "v1.1.3",
-    "commit": "a36f782c6687aa08ce811f597a495a4f09137c75"
+    "tag": "v1.1.4",
+    "commit": "46e0a6218b3f984855dde6e52c2177157801718a"
   },
   "_source": "git://github.com/PolymerElements/paper-header-panel.git",
   "_target": "^1.0.0",
diff --git a/third_party/polymer/v1_0/components-chromium/paper-header-panel/bower.json b/third_party/polymer/v1_0/components-chromium/paper-header-panel/bower.json
index c699bb66..8c4a6e8 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-header-panel/bower.json
+++ b/third_party/polymer/v1_0/components-chromium/paper-header-panel/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "paper-header-panel",
-  "version": "1.1.3",
+  "version": "1.1.4",
   "description": "A header and content wrapper for layout with headers",
   "authors": [
     "The Polymer Authors"
diff --git a/third_party/polymer/v1_0/components-chromium/paper-header-panel/paper-header-panel-extracted.js b/third_party/polymer/v1_0/components-chromium/paper-header-panel/paper-header-panel-extracted.js
index 55c09fe8..d7dae41 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-header-panel/paper-header-panel-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/paper-header-panel/paper-header-panel-extracted.js
@@ -103,7 +103,8 @@
             type: Boolean,
             value: true,
             notify: true,
-            readOnly: true
+            readOnly: true,
+            reflectToAttribute: true
           }
         },
 
diff --git a/third_party/polymer/v1_0/components-chromium/paper-input/.bower.json b/third_party/polymer/v1_0/components-chromium/paper-input/.bower.json
index 7e3218aa..2da92b9 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-input/.bower.json
+++ b/third_party/polymer/v1_0/components-chromium/paper-input/.bower.json
@@ -1,6 +1,6 @@
 {
   "name": "paper-input",
-  "version": "1.1.5",
+  "version": "1.1.8",
   "description": "Material design text fields",
   "authors": [
     "The Polymer Authors"
@@ -33,7 +33,7 @@
     "iron-behaviors": "PolymerElements/iron-behaviors#^1.0.0",
     "iron-form-element-behavior": "PolymerElements/iron-form-element-behavior#^1.0.0",
     "iron-input": "PolymerElements/iron-input#^1.0.0",
-    "paper-styles": "PolymerElements/paper-styles#^1.0.0",
+    "paper-styles": "PolymerElements/paper-styles#^1.1.0",
     "iron-a11y-keys-behavior": "PolymerElements/iron-a11y-keys-behavior#^1.0.0"
   },
   "devDependencies": {
@@ -47,11 +47,11 @@
     "web-component-tester": "^4.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
   },
-  "_release": "1.1.5",
+  "_release": "1.1.8",
   "_resolution": {
     "type": "version",
-    "tag": "v1.1.5",
-    "commit": "0aa8318b5e026688f94c78c7673acabf5bad0f17"
+    "tag": "v1.1.8",
+    "commit": "96efaa0f707870d5a5999120467d67b8da806704"
   },
   "_source": "git://github.com/PolymerElements/paper-input.git",
   "_target": "^1.0.0",
diff --git a/third_party/polymer/v1_0/components-chromium/paper-input/CONTRIBUTING.md b/third_party/polymer/v1_0/components-chromium/paper-input/CONTRIBUTING.md
index 7b101415..f147978a 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-input/CONTRIBUTING.md
+++ b/third_party/polymer/v1_0/components-chromium/paper-input/CONTRIBUTING.md
@@ -5,6 +5,11 @@
 
 If you edit that file, it will get updated everywhere else.
 If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
 -->
 # Polymer Elements
 ## Guide for Contributors
@@ -41,7 +46,7 @@
  3. Click the `paper-foo` element.
  ```
 
- 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [http://jsbin.com/cagaye](http://jsbin.com/cagaye/edit?html,output).
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
 
  3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
 
@@ -51,14 +56,14 @@
 
 When submitting pull requests, please provide:
 
- 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues using the following syntax:
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
 
  ```markdown
  (For a single issue)
  Fixes #20
 
  (For multiple issues)
- Fixes #32, #40
+ Fixes #32, fixes #40
  ```
 
  2. **A succinct description of the design** used to fix any related issues. For example:
diff --git a/third_party/polymer/v1_0/components-chromium/paper-input/README.md b/third_party/polymer/v1_0/components-chromium/paper-input/README.md
index de18f2da..099d2a3 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-input/README.md
+++ b/third_party/polymer/v1_0/components-chromium/paper-input/README.md
@@ -12,9 +12,9 @@
 
 -->
 
-[![Build Status](https://travis-ci.org/PolymerElements/paper-input.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-input)
+[![Build status](https://travis-ci.org/PolymerElements/paper-input.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-input)
 
-_[Demo and API Docs](https://elements.polymer-project.org/elements/paper-input)_
+_[Demo and API docs](https://elements.polymer-project.org/elements/paper-input)_
 
 
 ##&lt;paper-input&gt;
@@ -162,8 +162,8 @@
 | Custom property | Description | Default |
 | --- | --- | --- |
 | `--paper-input-container-color` | Label and underline color when the input is not focused | `--secondary-text-color` |
-| `--paper-input-container-focus-color` | Label and underline color when the input is focused | `--default-primary-color` |
-| `--paper-input-container-invalid-color` | Label and underline color when the input is is invalid | `--google-red-500` |
+| `--paper-input-container-focus-color` | Label and underline color when the input is focused | `--primary-color` |
+| `--paper-input-container-invalid-color` | Label and underline color when the input is is invalid | `--error-color` |
 | `--paper-input-container-input-color` | Input foreground color | `--primary-text-color` |
 | `--paper-input-container` | Mixin applied to the container | `{}` |
 | `--paper-input-container-disabled` | Mixin applied to the container when it's disabled | `{}` |
@@ -200,7 +200,7 @@
 
 | Custom property | Description | Default |
 | --- | --- | --- |
-| `--paper-input-container-invalid-color` | The foreground color of the error | `--google-red-500` |
+| `--paper-input-container-invalid-color` | The foreground color of the error | `--error-color` |
 | `--paper-input-error` | Mixin applied to the error | `{}` |
 
 
diff --git a/third_party/polymer/v1_0/components-chromium/paper-input/bower.json b/third_party/polymer/v1_0/components-chromium/paper-input/bower.json
index 99a9b83b..d6d61b8e 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-input/bower.json
+++ b/third_party/polymer/v1_0/components-chromium/paper-input/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "paper-input",
-  "version": "1.1.5",
+  "version": "1.1.8",
   "description": "Material design text fields",
   "authors": [
     "The Polymer Authors"
@@ -33,7 +33,7 @@
     "iron-behaviors": "PolymerElements/iron-behaviors#^1.0.0",
     "iron-form-element-behavior": "PolymerElements/iron-form-element-behavior#^1.0.0",
     "iron-input": "PolymerElements/iron-input#^1.0.0",
-    "paper-styles": "PolymerElements/paper-styles#^1.0.0",
+    "paper-styles": "PolymerElements/paper-styles#^1.1.0",
     "iron-a11y-keys-behavior": "PolymerElements/iron-a11y-keys-behavior#^1.0.0"
   },
   "devDependencies": {
diff --git a/third_party/polymer/v1_0/components-chromium/paper-input/compiled_resources2.gyp b/third_party/polymer/v1_0/components-chromium/paper-input/compiled_resources2.gyp
index 18ff54812..3f40f83d 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-input/compiled_resources2.gyp
+++ b/third_party/polymer/v1_0/components-chromium/paper-input/compiled_resources2.gyp
@@ -59,6 +59,7 @@
       'target_name': 'paper-textarea-extracted',
       'dependencies': [
         '../iron-autogrow-textarea/compiled_resources2.gyp:iron-autogrow-textarea-extracted',
+        '../iron-form-element-behavior/compiled_resources2.gyp:iron-form-element-behavior-extracted',
         'paper-input-behavior-extracted',
         'paper-input-char-counter-extracted',
         'paper-input-container-extracted',
diff --git a/third_party/polymer/v1_0/components-chromium/paper-input/paper-input-behavior-extracted.js b/third_party/polymer/v1_0/components-chromium/paper-input/paper-input-behavior-extracted.js
index 2b10429..2073573 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-input/paper-input-behavior-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/paper-input/paper-input-behavior-extracted.js
@@ -350,13 +350,8 @@
 
     listeners: {
       'addon-attached': '_onAddonAttached',
-      'focus': '_onFocus'
     },
 
-    observers: [
-      '_focusedControlStateChanged(focused)'
-    ],
-
     keyBindings: {
       'shift+tab:keydown': '_onShiftTabDown'
     },
@@ -425,12 +420,17 @@
     },
 
     /**
-     * Forward focus to inputElement
+     * Forward focus to inputElement. Overriden from IronControlState.
      */
-    _onFocus: function() {
-      if (!this._shiftTabPressed) {
+    _focusBlurHandler: function(event) {
+      if (this._shiftTabPressed)
+        return;
+
+      Polymer.IronControlState._focusBlurHandler.call(this, event);
+
+      // Forward the focus to the nested input.
+      if (this.focused)
         this._focusableElement.focus();
-      }
     },
 
     /**
@@ -482,24 +482,6 @@
       return placeholder || alwaysFloatLabel;
     },
 
-    _focusedControlStateChanged: function(focused) {
-      // IronControlState stops the focus and blur events in order to redispatch them on the host
-      // element, but paper-input-container listens to those events. Since there are more
-      // pending work on focus/blur in IronControlState, I'm putting in this hack to get the
-      // input focus state working for now.
-      if (!this.$.container) {
-        this.$.container = Polymer.dom(this.root).querySelector('paper-input-container');
-        if (!this.$.container) {
-          return;
-        }
-      }
-      if (focused) {
-        this.$.container._onFocus();
-      } else {
-        this.$.container._onBlur();
-      }
-    },
-
     _updateAriaLabelledBy: function() {
       var label = Polymer.dom(this.root).querySelector('label');
       if (!label) {
diff --git a/third_party/polymer/v1_0/components-chromium/paper-input/paper-input-char-counter-extracted.js b/third_party/polymer/v1_0/components-chromium/paper-input/paper-input-char-counter-extracted.js
index e5bb409..2d86064e 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-input/paper-input-char-counter-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/paper-input/paper-input-char-counter-extracted.js
@@ -30,12 +30,12 @@
 
       state.value = state.value || '';
 
-      // Account for the textarea's new lines.
-      var str = state.value.replace(/(\r\n|\n|\r)/g, '--').length.toString();
+      var counter = state.value.length.toString();
 
       if (state.inputElement.hasAttribute('maxlength')) {
-        str += '/' + state.inputElement.getAttribute('maxlength');
+        counter += '/' + state.inputElement.getAttribute('maxlength');
       }
-      this._charCounterStr = str;
+
+      this._charCounterStr = counter;
     }
   });
diff --git a/third_party/polymer/v1_0/components-chromium/paper-input/paper-input-container.html b/third_party/polymer/v1_0/components-chromium/paper-input/paper-input-container.html
index a7deb38..3dd7c00 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-input/paper-input-container.html
+++ b/third_party/polymer/v1_0/components-chromium/paper-input/paper-input-container.html
@@ -8,7 +8,6 @@
 subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 --><html><head><link rel="import" href="../polymer/polymer.html">
 <link rel="import" href="../iron-flex-layout/iron-flex-layout.html">
-<link rel="import" href="../paper-styles/color.html">
 <link rel="import" href="../paper-styles/default-theme.html">
 <link rel="import" href="../paper-styles/typography.html">
 
@@ -72,8 +71,8 @@
 Custom property | Description | Default
 ----------------|-------------|----------
 `--paper-input-container-color` | Label and underline color when the input is not focused | `--secondary-text-color`
-`--paper-input-container-focus-color` | Label and underline color when the input is focused | `--default-primary-color`
-`--paper-input-container-invalid-color` | Label and underline color when the input is is invalid | `--google-red-500`
+`--paper-input-container-focus-color` | Label and underline color when the input is focused | `--primary-color`
+`--paper-input-container-invalid-color` | Label and underline color when the input is is invalid | `--error-color`
 `--paper-input-container-input-color` | Input foreground color | `--primary-text-color`
 `--paper-input-container` | Mixin applied to the container | `{}`
 `--paper-input-container-disabled` | Mixin applied to the container when it's disabled | `{}`
@@ -123,8 +122,9 @@
       .focused-line {
         @apply(--layout-fit);
 
-        background: var(--paper-input-container-focus-color, --default-primary-color);
+        background: var(--paper-input-container-focus-color, --primary-color);
         height: 2px;
+
         -webkit-transform-origin: center center;
         transform-origin: center center;
         -webkit-transform: scale3d(0,1,1);
@@ -143,7 +143,7 @@
       }
 
       .underline.is-invalid .focused-line {
-        background: var(--paper-input-container-invalid-color, --google-red-500);
+        background: var(--paper-input-container-invalid-color, --error-color);
         -webkit-transform: none;
         transform: none;
         -webkit-transition: -webkit-transform 0.25s;
@@ -155,8 +155,8 @@
       .unfocused-line {
         @apply(--layout-fit);
 
-        height: 1px;
         background: var(--paper-input-container-color, --secondary-text-color);
+        height: 1px;
 
         @apply(--paper-input-container-underline);
       }
@@ -172,6 +172,7 @@
       .label-and-input-container {
         @apply(--layout-flex-auto);
         @apply(--layout-relative);
+
         width: 100%;
         max-width: 100%;
       }
@@ -192,26 +193,26 @@
         width: 100%;
         font: inherit;
         color: var(--paper-input-container-color, --secondary-text-color);
+        -webkit-transition: -webkit-transform 0.25s, width 0.25s;
+        transition: transform 0.25s, width 0.25s;
+        -webkit-transform-origin: left top;
+        transform-origin: left top;
 
         @apply(--paper-font-common-nowrap);
         @apply(--paper-font-subhead);
         @apply(--paper-input-container-label);
+        @apply(--paper-transition-easing);
       }
 
       .input-content.label-is-floating ::content label,
       .input-content.label-is-floating ::content .paper-input-label {
         -webkit-transform: translateY(-75%) scale(0.75);
         transform: translateY(-75%) scale(0.75);
-        -webkit-transition: -webkit-transform 0.25s, width 0.25s;
-        transition: transform 0.25s, width 0.25s;
-        -webkit-transform-origin: left top;
-        transform-origin: left top;
 
         /* Since we scale to 75/100 of the size, we actually have 100/75 of the
         original space now available */
         width: 133%;
 
-        @apply(--paper-transition-easing);
         @apply(--paper-input-container-label-floating);
       }
 
@@ -227,14 +228,14 @@
 
       .input-content.label-is-highlighted ::content label,
       .input-content.label-is-highlighted ::content .paper-input-label {
-        color: var(--paper-input-container-focus-color, --default-primary-color);
+        color: var(--paper-input-container-focus-color, --primary-color);
 
         @apply(--paper-input-container-label-focus);
       }
 
       .input-content.is-invalid ::content label,
       .input-content.is-invalid ::content .paper-input-label {
-        color: var(--paper-input-container-invalid-color, --google-red-500);
+        color: var(--paper-input-container-invalid-color, --error-color);
       }
 
       .input-content.label-is-hidden ::content label,
@@ -264,12 +265,14 @@
 
       ::content [prefix] {
         @apply(--paper-font-subhead);
+
         @apply(--paper-input-prefix);
         @apply(--layout-flex-none);
       }
 
       ::content [suffix] {
         @apply(--paper-font-subhead);
+
         @apply(--paper-input-suffix);
         @apply(--layout-flex-none);
       }
@@ -288,11 +291,11 @@
       }
 
       .add-on-content.is-invalid ::content * {
-        color: var(--paper-input-container-invalid-color, --google-red-500);
+        color: var(--paper-input-container-invalid-color, --error-color);
       }
 
       .add-on-content.is-highlighted ::content * {
-        color: var(--paper-input-container-focus-color, --default-primary-color);
+        color: var(--paper-input-container-focus-color, --primary-color);
       }
     </style>
 
diff --git a/third_party/polymer/v1_0/components-chromium/paper-input/paper-input-error.html b/third_party/polymer/v1_0/components-chromium/paper-input/paper-input-error.html
index 06928b99..0fb2224e 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-input/paper-input-error.html
+++ b/third_party/polymer/v1_0/components-chromium/paper-input/paper-input-error.html
@@ -7,7 +7,7 @@
 Code distributed by Google as part of the polymer project is also
 subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 --><html><head><link rel="import" href="../polymer/polymer.html">
-<link rel="import" href="../paper-styles/color.html">
+<link rel="import" href="../paper-styles/default-theme.html">
 <link rel="import" href="../paper-styles/typography.html">
 <link rel="import" href="paper-input-addon-behavior.html">
 
@@ -26,7 +26,7 @@
 
 Custom property | Description | Default
 ----------------|-------------|----------
-`--paper-input-container-invalid-color` | The foreground color of the error | `--google-red-500`
+`--paper-input-container-invalid-color` | The foreground color of the error | `--error-color`
 `--paper-input-error`                   | Mixin applied to the error        | `{}`
 -->
 
@@ -37,7 +37,7 @@
         display: inline-block;
         visibility: hidden;
 
-        color: var(--paper-input-container-invalid-color, --google-red-500);
+        color: var(--paper-input-container-invalid-color, --error-color);
 
         @apply(--paper-font-caption);
         @apply(--paper-input-error);
diff --git a/third_party/polymer/v1_0/components-chromium/paper-input/paper-textarea-extracted.js b/third_party/polymer/v1_0/components-chromium/paper-input/paper-textarea-extracted.js
index f0852c3..78a2a9e 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-input/paper-textarea-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/paper-input/paper-textarea-extracted.js
@@ -2,7 +2,8 @@
     is: 'paper-textarea',
 
     behaviors: [
-      Polymer.PaperInputBehavior
+      Polymer.PaperInputBehavior,
+      Polymer.IronFormElementBehavior
     ],
 
     properties: {
diff --git a/third_party/polymer/v1_0/components-chromium/paper-input/paper-textarea.html b/third_party/polymer/v1_0/components-chromium/paper-input/paper-textarea.html
index 4a49cff..c409b941 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-input/paper-textarea.html
+++ b/third_party/polymer/v1_0/components-chromium/paper-input/paper-textarea.html
@@ -8,6 +8,7 @@
 subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 --><html><head><link rel="import" href="../polymer/polymer.html">
 <link rel="import" href="../iron-autogrow-textarea/iron-autogrow-textarea.html">
+<link rel="import" href="../iron-form-element-behavior/iron-form-element-behavior.html">
 <link rel="import" href="paper-input-behavior.html">
 <link rel="import" href="paper-input-char-counter.html">
 <link rel="import" href="paper-input-container.html">
diff --git a/third_party/polymer/v1_0/components-chromium/paper-item/.bower.json b/third_party/polymer/v1_0/components-chromium/paper-item/.bower.json
index e36cad98f..c341588 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-item/.bower.json
+++ b/third_party/polymer/v1_0/components-chromium/paper-item/.bower.json
@@ -1,6 +1,6 @@
 {
   "name": "paper-item",
-  "version": "1.1.3",
+  "version": "1.1.4",
   "description": "A material-design styled list item",
   "authors": [
     "The Polymer Authors"
@@ -31,22 +31,20 @@
   },
   "devDependencies": {
     "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+    "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
     "iron-icon": "PolymerElements/iron-icon#^1.0.0",
     "iron-icons": "PolymerElements/iron-icons#^1.0.0",
-    "paper-checkbox": "PolymerElements/paper-checkbox#^1.0.0",
     "paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0",
-    "paper-input": "PolymerElements/paper-input#^1.0.0",
-    "paper-toggle-button": "PolymerElements/paper-toggle-button#^1.0.0",
     "test-fixture": "PolymerElements/test-fixture#^1.0.0",
-    "web-component-tester": "Polymer/web-component-tester#^3.4.0",
+    "web-component-tester": "^4.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
     "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0"
   },
-  "_release": "1.1.3",
+  "_release": "1.1.4",
   "_resolution": {
     "type": "version",
-    "tag": "v1.1.3",
-    "commit": "280c2e703315a6f1f707bec6fd0b1e0b80fee8f4"
+    "tag": "v1.1.4",
+    "commit": "5dcf21d5f7c13bafa24122c73aac28bd86213191"
   },
   "_source": "git://github.com/PolymerElements/paper-item.git",
   "_target": "^1.0.0",
diff --git a/third_party/polymer/v1_0/components-chromium/paper-item/CONTRIBUTING.md b/third_party/polymer/v1_0/components-chromium/paper-item/CONTRIBUTING.md
index 7b101415..f147978a 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-item/CONTRIBUTING.md
+++ b/third_party/polymer/v1_0/components-chromium/paper-item/CONTRIBUTING.md
@@ -5,6 +5,11 @@
 
 If you edit that file, it will get updated everywhere else.
 If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
 -->
 # Polymer Elements
 ## Guide for Contributors
@@ -41,7 +46,7 @@
  3. Click the `paper-foo` element.
  ```
 
- 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [http://jsbin.com/cagaye](http://jsbin.com/cagaye/edit?html,output).
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
 
  3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
 
@@ -51,14 +56,14 @@
 
 When submitting pull requests, please provide:
 
- 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues using the following syntax:
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
 
  ```markdown
  (For a single issue)
  Fixes #20
 
  (For multiple issues)
- Fixes #32, #40
+ Fixes #32, fixes #40
  ```
 
  2. **A succinct description of the design** used to fix any related issues. For example:
diff --git a/third_party/polymer/v1_0/components-chromium/paper-item/README.md b/third_party/polymer/v1_0/components-chromium/paper-item/README.md
index 8c446dbd..ea5c50a2 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-item/README.md
+++ b/third_party/polymer/v1_0/components-chromium/paper-item/README.md
@@ -7,107 +7,119 @@
 Edit those files, and our readme bot will duplicate them over here!
 Edit this file, and the bot will squash your changes :)
 
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
 -->
 
-[![Build Status](https://travis-ci.org/PolymerElements/paper-item.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-item)
+[![Build status](https://travis-ci.org/PolymerElements/paper-item.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-item)
 
-_[Demo and API Docs](https://elements.polymer-project.org/elements/paper-item)_
+_[Demo and API docs](https://elements.polymer-project.org/elements/paper-item)_
 
 
 ##&lt;paper-item&gt;
 
-
 Material design: [Lists](https://www.google.com/design/spec/components/lists.html)
 
 `<paper-item>` is an interactive list item. By default, it is a horizontal flexbox.
 
-    <paper-item>Item</paper-item>
+```html
+<paper-item>Item</paper-item>
+```
 
 Use this element with `<paper-item-body>` to make Material Design styled two-line and three-line
 items.
 
-    <paper-item>
-      <paper-item-body two-line>
-        <div>Show your status</div>
-        <div secondary>Your status is visible to everyone</div>
-      </paper-item-body>
-      <iron-icon icon="warning"></iron-icon>
-    </paper-item>
+```html
+<paper-item>
+  <paper-item-body two-line>
+    <div>Show your status</div>
+    <div secondary>Your status is visible to everyone</div>
+  </paper-item-body>
+  <iron-icon icon="warning"></iron-icon>
+</paper-item>
+```
 
 ### Styling
 
 The following custom properties and mixins are available for styling:
 
-Custom property               | Description                                  | Default
-------------------------------|----------------------------------------------|----------
-`--paper-item-min-height`     | Minimum height of the item                   | `48px`
-`--paper-item`                | Mixin applied to the item                    | `{}`
-`--paper-item-selected-weight`| The font weight of a selected item           | `bold`
-`--paper-item-selected`       | Mixin applied to selected paper-items        | `{}`
-`--paper-item-disabled-color` | The color for disabled paper-items           | `--disabled-text-color`
-`--paper-item-disabled`       | Mixin applied to disabled paper-items        | `{}`
-`--paper-item-focused`        | Mixin applied to focused paper-items         | `{}`
-`--paper-item-focused-before` | Mixin applied to :before focused paper-items | `{}`
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--paper-item-min-height` | Minimum height of the item | `48px` |
+| `--paper-item` | Mixin applied to the item | `{}` |
+| `--paper-item-selected-weight` | The font weight of a selected item | `bold` |
+| `--paper-item-selected` | Mixin applied to selected paper-items | `{}` |
+| `--paper-item-disabled-color` | The color for disabled paper-items | `--disabled-text-color` |
+| `--paper-item-disabled` | Mixin applied to disabled paper-items | `{}` |
+| `--paper-item-focused` | Mixin applied to focused paper-items | `{}` |
+| `--paper-item-focused-before` | Mixin applied to :before focused paper-items | `{}` |
 
 ### Accessibility
 
 This element has `role="listitem"` by default. Depending on usage, it may be more appropriate to set
 `role="menuitem"`, `role="menuitemcheckbox"` or `role="menuitemradio"`.
 
-    <paper-item role="menuitemcheckbox">
-      <paper-item-body>
-        Show your status
-      </paper-item-body>
-      <paper-checkbox></paper-checkbox>
-    </paper-item>
+```html
+<paper-item role="menuitemcheckbox">
+  <paper-item-body>
+    Show your status
+  </paper-item-body>
+  <paper-checkbox></paper-checkbox>
+</paper-item>
+```
 
 
 
 ##&lt;paper-icon-item&gt;
 
-
 `<paper-icon-item>` is a convenience element to make an item with icon. It is an interactive list
 item with a fixed-width icon area, according to Material Design. This is useful if the icons are of
 varying widths, but you want the item bodies to line up. Use this like a `<paper-item>`. The child
 node with the attribute `item-icon` is placed in the icon area.
 
-    <paper-icon-item>
-      <iron-icon icon="favorite" item-icon></iron-icon>
-      Favorite
-    </paper-icon-item>
-    <paper-icon-item>
-      <div class="avatar" item-icon></div>
-      Avatar
-    </paper-icon-item>
+```html
+<paper-icon-item>
+  <iron-icon icon="favorite" item-icon></iron-icon>
+  Favorite
+</paper-icon-item>
+<paper-icon-item>
+  <div class="avatar" item-icon></div>
+  Avatar
+</paper-icon-item>
+```
 
 ### Styling
 
 The following custom properties and mixins are available for styling:
 
-Custom property               | Description                                    | Default
-------------------------------|------------------------------------------------|----------
-`--paper-item-icon-width`     | Width of the icon area                         | `56px`
-`--paper-icon-item`           | Mixin applied to the item                      | `{}`
-`--paper-item-selected-weight`| The font weight of a selected item             | `bold`
-`--paper-item-selected`       | Mixin applied to selected paper-items                | `{}`
-`--paper-item-disabled-color` | The color for disabled paper-items             | `--disabled-text-color`
-`--paper-item-disabled`       | Mixin applied to disabled paper-items        | `{}`
-`--paper-item-focused`        | Mixin applied to focused paper-items         | `{}`
-`--paper-item-focused-before` | Mixin applied to :before focused paper-items | `{}`
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--paper-item-icon-width` | Width of the icon area | `56px` |
+| `--paper-item-icon` | Mixin applied to the icon area | `{}` |
+| `--paper-icon-item` | Mixin applied to the item | `{}` |
+| `--paper-item-selected-weight` | The font weight of a selected item | `bold` |
+| `--paper-item-selected` | Mixin applied to selected paper-items | `{}` |
+| `--paper-item-disabled-color` | The color for disabled paper-items | `--disabled-text-color` |
+| `--paper-item-disabled` | Mixin applied to disabled paper-items | `{}` |
+| `--paper-item-focused` | Mixin applied to focused paper-items | `{}` |
+| `--paper-item-focused-before` | Mixin applied to :before focused paper-items | `{}` |
+
 
 
 ##&lt;paper-item-body&gt;
 
-
 Use `<paper-item-body>` in a `<paper-item>` or `<paper-icon-item>` to make two- or
 three- line items. It is a flex item that is a vertical flexbox.
 
-    <paper-item>
-      <paper-item-body two-line>
-        <div>Show your status</div>
-        <div secondary>Your status is visible to everyone</div>
-      </paper-item-body>
-    </paper-item>
+```html
+<paper-item>
+  <paper-item-body two-line>
+    <div>Show your status</div>
+    <div secondary>Your status is visible to everyone</div>
+  </paper-item-body>
+</paper-item>
+```
 
 The child elements with the `secondary` attribute is given secondary text styling.
 
@@ -115,12 +127,12 @@
 
 The following custom properties and mixins are available for styling:
 
-Custom property | Description | Default
-----------------|-------------|----------
-`--paper-item-body-two-line-min-height`   | Minimum height of a two-line item          | `72px`
-`--paper-item-body-three-line-min-height` | Minimum height of a three-line item        | `88px`
-`--paper-item-body-secondary-color`       | Foreground color for the `secondary` area  | `--secondary-text-color`
-`--paper-item-body-secondary`             | Mixin applied to the `secondary` area      | `{}`
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--paper-item-body-two-line-min-height` | Minimum height of a two-line item | `72px` |
+| `--paper-item-body-three-line-min-height` | Minimum height of a three-line item | `88px` |
+| `--paper-item-body-secondary-color` | Foreground color for the `secondary` area | `--secondary-text-color` |
+| `--paper-item-body-secondary` | Mixin applied to the `secondary` area | `{}` |
 
 
 
diff --git a/third_party/polymer/v1_0/components-chromium/paper-item/bower.json b/third_party/polymer/v1_0/components-chromium/paper-item/bower.json
index 6b1c37a..dd9b1393 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-item/bower.json
+++ b/third_party/polymer/v1_0/components-chromium/paper-item/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "paper-item",
-  "version": "1.1.3",
+  "version": "1.1.4",
   "description": "A material-design styled list item",
   "authors": [
     "The Polymer Authors"
@@ -31,14 +31,12 @@
   },
   "devDependencies": {
     "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+    "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
     "iron-icon": "PolymerElements/iron-icon#^1.0.0",
     "iron-icons": "PolymerElements/iron-icons#^1.0.0",
-    "paper-checkbox": "PolymerElements/paper-checkbox#^1.0.0",
     "paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0",
-    "paper-input": "PolymerElements/paper-input#^1.0.0",
-    "paper-toggle-button": "PolymerElements/paper-toggle-button#^1.0.0",
     "test-fixture": "PolymerElements/test-fixture#^1.0.0",
-    "web-component-tester": "Polymer/web-component-tester#^3.4.0",
+    "web-component-tester": "^4.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
     "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0"
   }
diff --git a/third_party/polymer/v1_0/components-chromium/paper-item/compiled_resources2.gyp b/third_party/polymer/v1_0/components-chromium/paper-item/compiled_resources2.gyp
index d19d0644..1d0eefc 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-item/compiled_resources2.gyp
+++ b/third_party/polymer/v1_0/components-chromium/paper-item/compiled_resources2.gyp
@@ -34,15 +34,15 @@
       'includes': ['../../../../closure_compiler/compile_js2.gypi'],
     },
     {
-      'target_name': 'paper-item-shared-styles-extracted',
-      'includes': ['../../../../closure_compiler/compile_js2.gypi'],
-    },
-    {
       'target_name': 'paper-item-extracted',
       'dependencies': [
         'paper-item-behavior-extracted',
       ],
       'includes': ['../../../../closure_compiler/compile_js2.gypi'],
     },
+    {
+      'target_name': 'paper-item-shared-styles-extracted',
+      'includes': ['../../../../closure_compiler/compile_js2.gypi'],
+    },
   ],
 }
diff --git a/third_party/polymer/v1_0/components-chromium/paper-item/paper-icon-item.html b/third_party/polymer/v1_0/components-chromium/paper-item/paper-icon-item.html
index 82d1ef7..3d4bc8c 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-item/paper-icon-item.html
+++ b/third_party/polymer/v1_0/components-chromium/paper-item/paper-icon-item.html
@@ -34,6 +34,7 @@
 Custom property               | Description                                    | Default
 ------------------------------|------------------------------------------------|----------
 `--paper-item-icon-width`     | Width of the icon area                         | `56px`
+`--paper-item-icon`           | Mixin applied to the icon area                 | `{}`
 `--paper-icon-item`           | Mixin applied to the item                      | `{}`
 `--paper-item-selected-weight`| The font weight of a selected item             | `bold`
 `--paper-item-selected`       | Mixin applied to selected paper-items                | `{}`
@@ -61,6 +62,7 @@
         @apply(--layout-center);
 
         width: var(--paper-item-icon-width, 56px);
+        @apply(--paper-item-icon);
       }
     </style>
 
diff --git a/third_party/polymer/v1_0/components-chromium/paper-item/paper-item.html b/third_party/polymer/v1_0/components-chromium/paper-item/paper-item.html
index bfafc7c..2f4ceb9 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-item/paper-item.html
+++ b/third_party/polymer/v1_0/components-chromium/paper-item/paper-item.html
@@ -29,6 +29,14 @@
       <iron-icon icon="warning"></iron-icon>
     </paper-item>
 
+To use `paper-item` as a link, wrap it in an anchor tag. Since `paper-item` will
+already receive focus, you may want to prevent the anchor tag from receiving
+focus as well by setting its tabindex to -1.
+
+    <a href="https://www.polymer-project.org/" tabindex="-1">
+      <paper-item raised>Polymer Project</paper-item>
+    </a>
+
 ### Styling
 
 The following custom properties and mixins are available for styling:
diff --git a/third_party/polymer/v1_0/components-chromium/paper-material/compiled_resources2.gyp b/third_party/polymer/v1_0/components-chromium/paper-material/compiled_resources2.gyp
index 3ade9dd..8a45bef 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-material/compiled_resources2.gyp
+++ b/third_party/polymer/v1_0/components-chromium/paper-material/compiled_resources2.gyp
@@ -6,11 +6,11 @@
 {
   'targets': [
     {
-      'target_name': 'paper-material-shared-styles-extracted',
+      'target_name': 'paper-material-extracted',
       'includes': ['../../../../closure_compiler/compile_js2.gypi'],
     },
     {
-      'target_name': 'paper-material-extracted',
+      'target_name': 'paper-material-shared-styles-extracted',
       'includes': ['../../../../closure_compiler/compile_js2.gypi'],
     },
   ],
diff --git a/third_party/polymer/v1_0/components-chromium/paper-menu/compiled_resources2.gyp b/third_party/polymer/v1_0/components-chromium/paper-menu/compiled_resources2.gyp
index 3ccf658..e2ca7eb 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-menu/compiled_resources2.gyp
+++ b/third_party/polymer/v1_0/components-chromium/paper-menu/compiled_resources2.gyp
@@ -6,10 +6,6 @@
 {
   'targets': [
     {
-      'target_name': 'paper-menu-shared-styles-extracted',
-      'includes': ['../../../../closure_compiler/compile_js2.gypi'],
-    },
-    {
       'target_name': 'paper-menu-extracted',
       'dependencies': [
         '../iron-menu-behavior/compiled_resources2.gyp:iron-menu-behavior-extracted',
@@ -17,6 +13,10 @@
       'includes': ['../../../../closure_compiler/compile_js2.gypi'],
     },
     {
+      'target_name': 'paper-menu-shared-styles-extracted',
+      'includes': ['../../../../closure_compiler/compile_js2.gypi'],
+    },
+    {
       'target_name': 'paper-submenu-extracted',
       'dependencies': [
         '../iron-behaviors/compiled_resources2.gyp:iron-control-state-extracted',
diff --git a/third_party/polymer/v1_0/components-chromium/paper-radio-button/.bower.json b/third_party/polymer/v1_0/components-chromium/paper-radio-button/.bower.json
index 1960096..0ec87dd 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-radio-button/.bower.json
+++ b/third_party/polymer/v1_0/components-chromium/paper-radio-button/.bower.json
@@ -1,6 +1,6 @@
 {
   "name": "paper-radio-button",
-  "version": "1.0.12",
+  "version": "1.1.1",
   "description": "A material design radio button",
   "authors": [
     "The Polymer Authors"
@@ -22,8 +22,7 @@
   "dependencies": {
     "iron-checked-element-behavior": "PolymerElements/iron-checked-element-behavior#^1.0.0",
     "paper-behaviors": "PolymerElements/paper-behaviors#^1.0.0",
-    "paper-ripple": "PolymerElements/paper-ripple#^1.0.0",
-    "paper-styles": "PolymerElements/paper-styles#^1.0.0",
+    "paper-styles": "PolymerElements/paper-styles#^1.1.0",
     "polymer": "Polymer/polymer#^1.1.0"
   },
   "devDependencies": {
@@ -31,15 +30,15 @@
     "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
     "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
     "test-fixture": "PolymerElements/test-fixture#^1.0.0",
-    "web-component-tester": "Polymer/web-component-tester#^3.3.0",
+    "web-component-tester": "^4.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
   },
   "main": "paper-radio-button.html",
-  "_release": "1.0.12",
+  "_release": "1.1.1",
   "_resolution": {
     "type": "version",
-    "tag": "v1.0.12",
-    "commit": "d7a5a090968c8448d7568208e05fb626fe74ab64"
+    "tag": "v1.1.1",
+    "commit": "ada62ad3347d304aa72352ea5ef02e2c21907d6c"
   },
   "_source": "git://github.com/PolymerElements/paper-radio-button.git",
   "_target": "^1.0.0",
diff --git a/third_party/polymer/v1_0/components-chromium/paper-radio-button/CONTRIBUTING.md b/third_party/polymer/v1_0/components-chromium/paper-radio-button/CONTRIBUTING.md
index 7b101415..f147978a 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-radio-button/CONTRIBUTING.md
+++ b/third_party/polymer/v1_0/components-chromium/paper-radio-button/CONTRIBUTING.md
@@ -5,6 +5,11 @@
 
 If you edit that file, it will get updated everywhere else.
 If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
 -->
 # Polymer Elements
 ## Guide for Contributors
@@ -41,7 +46,7 @@
  3. Click the `paper-foo` element.
  ```
 
- 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [http://jsbin.com/cagaye](http://jsbin.com/cagaye/edit?html,output).
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
 
  3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
 
@@ -51,14 +56,14 @@
 
 When submitting pull requests, please provide:
 
- 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues using the following syntax:
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
 
  ```markdown
  (For a single issue)
  Fixes #20
 
  (For multiple issues)
- Fixes #32, #40
+ Fixes #32, fixes #40
  ```
 
  2. **A succinct description of the design** used to fix any related issues. For example:
diff --git a/third_party/polymer/v1_0/components-chromium/paper-radio-button/README.md b/third_party/polymer/v1_0/components-chromium/paper-radio-button/README.md
index e3c1a986..d141450 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-radio-button/README.md
+++ b/third_party/polymer/v1_0/components-chromium/paper-radio-button/README.md
@@ -7,16 +7,18 @@
 Edit those files, and our readme bot will duplicate them over here!
 Edit this file, and the bot will squash your changes :)
 
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
 -->
 
-[![Build Status](https://travis-ci.org/PolymerElements/paper-radio-button.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-radio-button)
+[![Build status](https://travis-ci.org/PolymerElements/paper-radio-button.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-radio-button)
 
-_[Demo and API Docs](https://elements.polymer-project.org/elements/paper-radio-button)_
+_[Demo and API docs](https://elements.polymer-project.org/elements/paper-radio-button)_
 
 
 ##&lt;paper-radio-button&gt;
 
-
 Material design: [Radio button](https://www.google.com/design/spec/components/selection-controls.html#selection-controls-radio-button)
 
 `paper-radio-button` is a button that can be either checked or unchecked.
@@ -28,21 +30,26 @@
 
 Example:
 
-    <paper-radio-button></paper-radio-button>
-    <paper-radio-button>Item label</paper-radio-button>
+```html
+<paper-radio-button></paper-radio-button>
+<paper-radio-button>Item label</paper-radio-button>
+```
 
 ### Styling
 
 The following custom properties and mixins are available for styling:
 
-Custom property | Description | Default
-----------------|-------------|----------
-`--paper-radio-button-unchecked-background-color` | Radio button background color when the input is not checked | `transparent`
-`--paper-radio-button-unchecked-color` | Radio button color when the input is not checked | `--primary-text-color`
-`--paper-radio-button-unchecked-ink-color` | Selected/focus ripple color when the input is not checked | `--primary-text-color`
-`--paper-radio-button-checked-color` | Radio button color when the input is checked | `--default-primary-color`
-`--paper-radio-button-checked-ink-color` | Selected/focus ripple color when the input is checked | `--default-primary-color`
-`--paper-radio-button-label-color` | Label color | `--primary-text-color`
-`--paper-radio-button-label-spacing` | Spacing between the label and the button | `10px`
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--paper-radio-button-unchecked-background-color` | Radio button background color when the input is not checked | `transparent` |
+| `--paper-radio-button-unchecked-color` | Radio button color when the input is not checked | `--primary-text-color` |
+| `--paper-radio-button-unchecked-ink-color` | Selected/focus ripple color when the input is not checked | `--primary-text-color` |
+| `--paper-radio-button-checked-color` | Radio button color when the input is checked | `--primary-color` |
+| `--paper-radio-button-checked-ink-color` | Selected/focus ripple color when the input is checked | `--primary-color` |
+| `--paper-radio-button-label-color` | Label color | `--primary-text-color` |
+| `--paper-radio-button-label-spacing` | Spacing between the label and the button | `10px` |
+
+This element applies the mixin `--paper-font-common-base` but does not import `paper-styles/typography.html`.
+In order to apply the `Roboto` font to this element, make sure you've imported `paper-styles/typography.html`.
 
 
diff --git a/third_party/polymer/v1_0/components-chromium/paper-radio-button/bower.json b/third_party/polymer/v1_0/components-chromium/paper-radio-button/bower.json
index f1e8839..70452a7 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-radio-button/bower.json
+++ b/third_party/polymer/v1_0/components-chromium/paper-radio-button/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "paper-radio-button",
-  "version": "1.0.12",
+  "version": "1.1.1",
   "description": "A material design radio button",
   "authors": [
     "The Polymer Authors"
@@ -22,8 +22,7 @@
   "dependencies": {
     "iron-checked-element-behavior": "PolymerElements/iron-checked-element-behavior#^1.0.0",
     "paper-behaviors": "PolymerElements/paper-behaviors#^1.0.0",
-    "paper-ripple": "PolymerElements/paper-ripple#^1.0.0",
-    "paper-styles": "PolymerElements/paper-styles#^1.0.0",
+    "paper-styles": "PolymerElements/paper-styles#^1.1.0",
     "polymer": "Polymer/polymer#^1.1.0"
   },
   "devDependencies": {
@@ -31,7 +30,7 @@
     "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
     "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
     "test-fixture": "PolymerElements/test-fixture#^1.0.0",
-    "web-component-tester": "Polymer/web-component-tester#^3.3.0",
+    "web-component-tester": "^4.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
   },
   "main": "paper-radio-button.html"
diff --git a/third_party/polymer/v1_0/components-chromium/paper-radio-button/compiled_resources2.gyp b/third_party/polymer/v1_0/components-chromium/paper-radio-button/compiled_resources2.gyp
index 7eda577..cd72897e 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-radio-button/compiled_resources2.gyp
+++ b/third_party/polymer/v1_0/components-chromium/paper-radio-button/compiled_resources2.gyp
@@ -9,7 +9,6 @@
       'target_name': 'paper-radio-button-extracted',
       'dependencies': [
         '../paper-behaviors/compiled_resources2.gyp:paper-checked-element-behavior-extracted',
-        '../paper-ripple/compiled_resources2.gyp:paper-ripple-extracted',
       ],
       'includes': ['../../../../closure_compiler/compile_js2.gypi'],
     },
diff --git a/third_party/polymer/v1_0/components-chromium/paper-radio-button/paper-radio-button-extracted.js b/third_party/polymer/v1_0/components-chromium/paper-radio-button/paper-radio-button-extracted.js
index 79806d3..7e5559f 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-radio-button/paper-radio-button-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/paper-radio-button/paper-radio-button-extracted.js
@@ -30,9 +30,7 @@
         }
       },
 
-      // create the element ripple inside the `radioContainer`
-      _createRipple: function() {
+      ready: function() {
         this._rippleContainer = this.$.radioContainer;
-        return Polymer.PaperInkyFocusBehaviorImpl._createRipple.call(this);
       }
     });
\ No newline at end of file
diff --git a/third_party/polymer/v1_0/components-chromium/paper-radio-button/paper-radio-button.html b/third_party/polymer/v1_0/components-chromium/paper-radio-button/paper-radio-button.html
index 60e949d..2b660231 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-radio-button/paper-radio-button.html
+++ b/third_party/polymer/v1_0/components-chromium/paper-radio-button/paper-radio-button.html
@@ -8,7 +8,6 @@
 subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 --><html><head><link rel="import" href="../polymer/polymer.html">
 <link rel="import" href="../paper-behaviors/paper-checked-element-behavior.html">
-<link rel="import" href="../paper-ripple/paper-ripple.html">
 <link rel="import" href="../paper-styles/default-theme.html">
 
 <!--
@@ -35,11 +34,14 @@
 `--paper-radio-button-unchecked-background-color` | Radio button background color when the input is not checked | `transparent`
 `--paper-radio-button-unchecked-color` | Radio button color when the input is not checked | `--primary-text-color`
 `--paper-radio-button-unchecked-ink-color` | Selected/focus ripple color when the input is not checked | `--primary-text-color`
-`--paper-radio-button-checked-color` | Radio button color when the input is checked | `--default-primary-color`
-`--paper-radio-button-checked-ink-color` | Selected/focus ripple color when the input is checked | `--default-primary-color`
+`--paper-radio-button-checked-color` | Radio button color when the input is checked | `--primary-color`
+`--paper-radio-button-checked-ink-color` | Selected/focus ripple color when the input is checked | `--primary-color`
 `--paper-radio-button-label-color` | Label color | `--primary-text-color`
 `--paper-radio-button-label-spacing` | Spacing between the label and the button | `10px`
 
+This element applies the mixin `--paper-font-common-base` but does not import `paper-styles/typography.html`.
+In order to apply the `Roboto` font to this element, make sure you've imported `paper-styles/typography.html`.
+
 @group Paper Elements
 @element paper-radio-button
 @hero hero.svg
@@ -53,6 +55,7 @@
         display: inline-block;
         white-space: nowrap;
         cursor: pointer;
+        @apply(--paper-font-common-base);
       }
 
       :host(:focus) {
@@ -84,7 +87,7 @@
       }
 
       #ink[checked] {
-        color: var(--paper-radio-button-checked-ink-color, --default-primary-color);
+        color: var(--paper-radio-button-checked-ink-color, --primary-color);
       }
 
       #offRadio {
@@ -111,7 +114,7 @@
         width: 8px;
         height: 8px;
         border-radius: 50%;
-        background-color: var(--paper-radio-button-checked-color, --default-primary-color);
+        background-color: var(--paper-radio-button-checked-color, --primary-color);
         -webkit-transform: scale(0);
         transform: scale(0);
         transition: -webkit-transform ease 0.28s;
@@ -119,7 +122,7 @@
       }
 
       :host([checked]) #offRadio {
-        border-color: var(--paper-radio-button-checked-color, --default-primary-color);
+        border-color: var(--paper-radio-button-checked-color, --primary-color);
       }
 
       :host([checked]) #onRadio {
@@ -133,7 +136,6 @@
         vertical-align: middle;
         margin-left: var(--paper-radio-button-label-spacing, 10px);
         white-space: normal;
-        pointer-events: none;
         color: var(--paper-radio-button-label-color, --primary-text-color);
       }
 
@@ -147,9 +149,6 @@
       }
 
       /* disabled state */
-      :host([disabled]) {
-        pointer-events: none;
-      }
 
       :host([disabled]) #offRadio {
         border-color: var(--paper-radio-button-unchecked-color, --primary-text-color);
diff --git a/third_party/polymer/v1_0/components-chromium/paper-spinner/.bower.json b/third_party/polymer/v1_0/components-chromium/paper-spinner/.bower.json
index 4de59c15..211b0d74 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-spinner/.bower.json
+++ b/third_party/polymer/v1_0/components-chromium/paper-spinner/.bower.json
@@ -1,6 +1,6 @@
 {
   "name": "paper-spinner",
-  "version": "1.1.0",
+  "version": "1.1.1",
   "description": "A material design spinner",
   "authors": [
     "The Polymer Authors"
@@ -26,19 +26,20 @@
   },
   "devDependencies": {
     "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+    "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
     "test-fixture": "PolymerElements/test-fixture#^1.0.0",
-    "web-component-tester": "*",
+    "web-component-tester": "^4.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
   },
   "main": [
     "paper-spinner.html",
     "paper-spinner-lite.html"
   ],
-  "_release": "1.1.0",
+  "_release": "1.1.1",
   "_resolution": {
     "type": "version",
-    "tag": "v1.1.0",
-    "commit": "66d77a91969b5f2deff4f2363740ccf4a47d423b"
+    "tag": "v1.1.1",
+    "commit": "fa851c605e1b5b79be592979a4650b3061f6342a"
   },
   "_source": "git://github.com/PolymerElements/paper-spinner.git",
   "_target": "^1.0.0",
diff --git a/third_party/polymer/v1_0/components-chromium/paper-spinner/CONTRIBUTING.md b/third_party/polymer/v1_0/components-chromium/paper-spinner/CONTRIBUTING.md
index 7b101415..f147978a 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-spinner/CONTRIBUTING.md
+++ b/third_party/polymer/v1_0/components-chromium/paper-spinner/CONTRIBUTING.md
@@ -5,6 +5,11 @@
 
 If you edit that file, it will get updated everywhere else.
 If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
 -->
 # Polymer Elements
 ## Guide for Contributors
@@ -41,7 +46,7 @@
  3. Click the `paper-foo` element.
  ```
 
- 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [http://jsbin.com/cagaye](http://jsbin.com/cagaye/edit?html,output).
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
 
  3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
 
@@ -51,14 +56,14 @@
 
 When submitting pull requests, please provide:
 
- 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues using the following syntax:
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
 
  ```markdown
  (For a single issue)
  Fixes #20
 
  (For multiple issues)
- Fixes #32, #40
+ Fixes #32, fixes #40
  ```
 
  2. **A succinct description of the design** used to fix any related issues. For example:
diff --git a/third_party/polymer/v1_0/components-chromium/paper-spinner/README.md b/third_party/polymer/v1_0/components-chromium/paper-spinner/README.md
index 11865ba..ad57a2f 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-spinner/README.md
+++ b/third_party/polymer/v1_0/components-chromium/paper-spinner/README.md
@@ -7,21 +7,25 @@
 Edit those files, and our readme bot will duplicate them over here!
 Edit this file, and the bot will squash your changes :)
 
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
 -->
 
-[![Build Status](https://travis-ci.org/PolymerElements/paper-spinner.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-spinner)
+[![Build status](https://travis-ci.org/PolymerElements/paper-spinner.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-spinner)
 
-_[Demo and API Docs](https://elements.polymer-project.org/elements/paper-spinner)_
+_[Demo and API docs](https://elements.polymer-project.org/elements/paper-spinner)_
 
 
 ##&lt;paper-spinner&gt;
 
-
 Material design: [Progress & activity](https://www.google.com/design/spec/components/progress-activity.html)
 
 Element providing a multiple color material design circular spinner.
 
-    <paper-spinner active></paper-spinner>
+```html
+<paper-spinner active></paper-spinner>
+```
 
 The default spinner cycles between four layers of colors; by default they are
 blue, red, yellow and green. It can be customized to cycle between four different
@@ -34,29 +38,33 @@
 Empty alt can be provided to mark the element as decorative if alternative content is provided
 in another form (e.g. a text block following the spinner).
 
-    <paper-spinner alt="Loading contacts list" active></paper-spinner>
+```html
+<paper-spinner alt="Loading contacts list" active></paper-spinner>
+```
 
 ### Styling
 
 The following custom properties and mixins are available for styling:
 
-Custom property | Description | Default
-----------------|-------------|----------
-`--paper-spinner-layer-1-color` | Color of the first spinner rotation | `--google-blue-500`
-`--paper-spinner-layer-2-color` | Color of the second spinner rotation | `--google-red-500`
-`--paper-spinner-layer-3-color` | Color of the third spinner rotation | `--google-yellow-500`
-`--paper-spinner-layer-4-color` | Color of the fourth spinner rotation | `--google-green-500`
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--paper-spinner-layer-1-color` | Color of the first spinner rotation | `--google-blue-500` |
+| `--paper-spinner-layer-2-color` | Color of the second spinner rotation | `--google-red-500` |
+| `--paper-spinner-layer-3-color` | Color of the third spinner rotation | `--google-yellow-500` |
+| `--paper-spinner-layer-4-color` | Color of the fourth spinner rotation | `--google-green-500` |
+| `--paper-spinner-stroke-width` | The width of the spinner stroke | 3px |
 
 
 
 ##&lt;paper-spinner-lite&gt;
 
-
 Material design: [Progress & activity](https://www.google.com/design/spec/components/progress-activity.html)
 
 Element providing a single color material design circular spinner.
 
-    <paper-spinner-lite active></paper-spinner-lite>
+```html
+<paper-spinner-lite active></paper-spinner-lite>
+```
 
 The default spinner is blue. It can be customized to be a different color.
 
@@ -67,15 +75,18 @@
 Empty alt can be provided to mark the element as decorative if alternative content is provided
 in another form (e.g. a text block following the spinner).
 
-    <paper-spinner-lite alt="Loading contacts list" active></paper-spinner-lite>
+```html
+<paper-spinner-lite alt="Loading contacts list" active></paper-spinner-lite>
+```
 
 ### Styling
 
 The following custom properties and mixins are available for styling:
 
-Custom property | Description | Default
-----------------|-------------|----------
-`--paper-spinner-color` | Color of the spinner | `--google-blue-500`
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--paper-spinner-color` | Color of the spinner | `--google-blue-500` |
+| `--paper-spinner-stroke-width` | The width of the spinner stroke | 3px |
 
 
 
diff --git a/third_party/polymer/v1_0/components-chromium/paper-spinner/bower.json b/third_party/polymer/v1_0/components-chromium/paper-spinner/bower.json
index 24a1b198e..b701ea24 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-spinner/bower.json
+++ b/third_party/polymer/v1_0/components-chromium/paper-spinner/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "paper-spinner",
-  "version": "1.1.0",
+  "version": "1.1.1",
   "description": "A material design spinner",
   "authors": [
     "The Polymer Authors"
@@ -26,8 +26,9 @@
   },
   "devDependencies": {
     "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+    "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
     "test-fixture": "PolymerElements/test-fixture#^1.0.0",
-    "web-component-tester": "*",
+    "web-component-tester": "^4.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
   },
   "main": [
diff --git a/third_party/polymer/v1_0/components-chromium/paper-spinner/compiled_resources2.gyp b/third_party/polymer/v1_0/components-chromium/paper-spinner/compiled_resources2.gyp
index f191dbc..281d664 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-spinner/compiled_resources2.gyp
+++ b/third_party/polymer/v1_0/components-chromium/paper-spinner/compiled_resources2.gyp
@@ -10,6 +10,13 @@
       'includes': ['../../../../closure_compiler/compile_js2.gypi'],
     },
     {
+      'target_name': 'paper-spinner-extracted',
+      'dependencies': [
+        'paper-spinner-behavior-extracted',
+      ],
+      'includes': ['../../../../closure_compiler/compile_js2.gypi'],
+    },
+    {
       'target_name': 'paper-spinner-lite-extracted',
       'dependencies': [
         'paper-spinner-behavior-extracted',
@@ -20,12 +27,5 @@
       'target_name': 'paper-spinner-styles-extracted',
       'includes': ['../../../../closure_compiler/compile_js2.gypi'],
     },
-    {
-      'target_name': 'paper-spinner-extracted',
-      'dependencies': [
-        'paper-spinner-behavior-extracted',
-      ],
-      'includes': ['../../../../closure_compiler/compile_js2.gypi'],
-    },
   ],
 }
diff --git a/third_party/polymer/v1_0/components-chromium/paper-spinner/paper-spinner-lite.html b/third_party/polymer/v1_0/components-chromium/paper-spinner/paper-spinner-lite.html
index 0bba683..8272688 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-spinner/paper-spinner-lite.html
+++ b/third_party/polymer/v1_0/components-chromium/paper-spinner/paper-spinner-lite.html
@@ -37,6 +37,7 @@
 Custom property | Description | Default
 ----------------|-------------|----------
 `--paper-spinner-color` | Color of the spinner | `--google-blue-500`
+`--paper-spinner-stroke-width` | The width of the spinner stroke | 3px
 
 @group Paper Elements
 @element paper-spinner-lite
diff --git a/third_party/polymer/v1_0/components-chromium/paper-spinner/paper-spinner-styles.html b/third_party/polymer/v1_0/components-chromium/paper-spinner/paper-spinner-styles.html
index 1a639cc..e0d2044 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-spinner/paper-spinner-styles.html
+++ b/third_party/polymer/v1_0/components-chromium/paper-spinner/paper-spinner-styles.html
@@ -18,7 +18,6 @@
 
       /*
        * Constants:
-       *      STROKEWIDTH = 3px
        *      ARCSIZE     = 270 degrees (amount of circle the arc takes up)
        *      ARCTIME     = 1333ms (time it takes to expand and contract arc)
        *      ARCSTARTROT = 216 degrees (how much the start location of the arc
@@ -266,7 +265,7 @@
       .circle {
         box-sizing: border-box;
         height: 100%;
-        border-width: 3px; /* STROKEWIDTH */
+        border-width: var(--paper-spinner-stroke-width, 3px); /* STROKEWIDTH */
         border-style: solid;
         border-color: inherit;
         border-bottom-color: transparent !important;
diff --git a/third_party/polymer/v1_0/components-chromium/paper-spinner/paper-spinner.html b/third_party/polymer/v1_0/components-chromium/paper-spinner/paper-spinner.html
index 1cc4626..e15ccc68 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-spinner/paper-spinner.html
+++ b/third_party/polymer/v1_0/components-chromium/paper-spinner/paper-spinner.html
@@ -42,6 +42,7 @@
 `--paper-spinner-layer-2-color` | Color of the second spinner rotation | `--google-red-500`
 `--paper-spinner-layer-3-color` | Color of the third spinner rotation | `--google-yellow-500`
 `--paper-spinner-layer-4-color` | Color of the fourth spinner rotation | `--google-green-500`
+`--paper-spinner-stroke-width` | The width of the spinner stroke | 3px
 
 @group Paper Elements
 @element paper-spinner
diff --git a/third_party/polymer/v1_0/components-chromium/paper-styles/.bower.json b/third_party/polymer/v1_0/components-chromium/paper-styles/.bower.json
index dd4c598..ae677ef 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-styles/.bower.json
+++ b/third_party/polymer/v1_0/components-chromium/paper-styles/.bower.json
@@ -1,6 +1,6 @@
 {
   "name": "paper-styles",
-  "version": "1.1.3",
+  "version": "1.1.4",
   "description": "Common (global) styles for Material Design elements.",
   "authors": [
     "The Polymer Authors"
@@ -30,11 +30,11 @@
     "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
     "web-component-tester": "^4.0.0"
   },
-  "_release": "1.1.3",
+  "_release": "1.1.4",
   "_resolution": {
     "type": "version",
-    "tag": "v1.1.3",
-    "commit": "6239484bc25ca1f56e7263ac952c63edd8298853"
+    "tag": "v1.1.4",
+    "commit": "885bbd74db88dab4fb5dc229cdf994c55fb2b31b"
   },
   "_source": "git://github.com/PolymerElements/paper-styles.git",
   "_target": "^1.0.0",
diff --git a/third_party/polymer/v1_0/components-chromium/paper-styles/CONTRIBUTING.md b/third_party/polymer/v1_0/components-chromium/paper-styles/CONTRIBUTING.md
index 7b101415..f147978a 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-styles/CONTRIBUTING.md
+++ b/third_party/polymer/v1_0/components-chromium/paper-styles/CONTRIBUTING.md
@@ -5,6 +5,11 @@
 
 If you edit that file, it will get updated everywhere else.
 If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
 -->
 # Polymer Elements
 ## Guide for Contributors
@@ -41,7 +46,7 @@
  3. Click the `paper-foo` element.
  ```
 
- 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [http://jsbin.com/cagaye](http://jsbin.com/cagaye/edit?html,output).
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
 
  3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
 
@@ -51,14 +56,14 @@
 
 When submitting pull requests, please provide:
 
- 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues using the following syntax:
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
 
  ```markdown
  (For a single issue)
  Fixes #20
 
  (For multiple issues)
- Fixes #32, #40
+ Fixes #32, fixes #40
  ```
 
  2. **A succinct description of the design** used to fix any related issues. For example:
diff --git a/third_party/polymer/v1_0/components-chromium/paper-styles/README.md b/third_party/polymer/v1_0/components-chromium/paper-styles/README.md
index a43017b4..ca555bd 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-styles/README.md
+++ b/third_party/polymer/v1_0/components-chromium/paper-styles/README.md
@@ -12,9 +12,9 @@
 
 -->
 
-[![Build Status](https://travis-ci.org/PolymerElements/paper-styles.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-styles)
+[![Build status](https://travis-ci.org/PolymerElements/paper-styles.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-styles)
 
-_[Demo and API Docs](https://elements.polymer-project.org/elements/paper-styles)_
+_[Demo and API docs](https://elements.polymer-project.org/elements/paper-styles)_
 
 
 ##&lt;paper-styles&gt;
diff --git a/third_party/polymer/v1_0/components-chromium/paper-styles/bower.json b/third_party/polymer/v1_0/components-chromium/paper-styles/bower.json
index d9deb9c..f3330c3 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-styles/bower.json
+++ b/third_party/polymer/v1_0/components-chromium/paper-styles/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "paper-styles",
-  "version": "1.1.3",
+  "version": "1.1.4",
   "description": "Common (global) styles for Material Design elements.",
   "authors": [
     "The Polymer Authors"
diff --git a/third_party/polymer/v1_0/components-chromium/paper-styles/classes/compiled_resources2.gyp b/third_party/polymer/v1_0/components-chromium/paper-styles/classes/compiled_resources2.gyp
index 53bce6d..f7827d7 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-styles/classes/compiled_resources2.gyp
+++ b/third_party/polymer/v1_0/components-chromium/paper-styles/classes/compiled_resources2.gyp
@@ -10,11 +10,11 @@
       'includes': ['../../../../../closure_compiler/compile_js2.gypi'],
     },
     {
-      'target_name': 'shadow-layout-extracted',
+      'target_name': 'shadow-extracted',
       'includes': ['../../../../../closure_compiler/compile_js2.gypi'],
     },
     {
-      'target_name': 'shadow-extracted',
+      'target_name': 'shadow-layout-extracted',
       'includes': ['../../../../../closure_compiler/compile_js2.gypi'],
     },
     {
diff --git a/third_party/polymer/v1_0/components-chromium/paper-styles/compiled_resources2.gyp b/third_party/polymer/v1_0/components-chromium/paper-styles/compiled_resources2.gyp
index ba088b6..3a4aeaf 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-styles/compiled_resources2.gyp
+++ b/third_party/polymer/v1_0/components-chromium/paper-styles/compiled_resources2.gyp
@@ -19,10 +19,16 @@
     },
     {
       'target_name': 'paper-styles-classes-extracted',
+      'dependencies': [
+        '../iron-flex-layout/classes/compiled_resources2.gyp:iron-flex-layout-extracted',
+      ],
       'includes': ['../../../../closure_compiler/compile_js2.gypi'],
     },
     {
       'target_name': 'paper-styles-extracted',
+      'dependencies': [
+        '../iron-flex-layout/classes/compiled_resources2.gyp:iron-flex-layout-extracted',
+      ],
       'includes': ['../../../../closure_compiler/compile_js2.gypi'],
     },
     {
diff --git a/third_party/polymer/v1_0/components-chromium/paper-styles/default-theme.html b/third_party/polymer/v1_0/components-chromium/paper-styles/default-theme.html
index 478d087f..cc697281 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-styles/default-theme.html
+++ b/third_party/polymer/v1_0/components-chromium/paper-styles/default-theme.html
@@ -9,6 +9,7 @@
 -->
 
 <link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="color.html">
 
 <!-- Taken from https://www.google.com/design/spec/style/color.html#color-ui-color-application -->
 
@@ -26,24 +27,26 @@
     --secondary-text-color: var(--light-theme-secondary-color);
     --disabled-text-color: var(--light-theme-disabled-color);
     --divider-color: var(--light-theme-divider-color);
+    --error-color: var(--paper-deep-orange-a700);
 
     /*
      * Primary and accent colors. Also see color.html for more colors.
      */
-    --primary-color: #3f51b5;  /* --paper-indigo-500 */
-    --light-primary-color: #c5cae9;  /* --paper-indigo-100 */
-    --dark-primary-color: #303f9f;  /* --paper-indigo-700 */
+    --primary-color: var(--paper-indigo-500);
+    --light-primary-color: var(--paper-indigo-100);
+    --dark-primary-color: var(--paper-indigo-700);
 
-    --accent-color: #ff4081;  /* --paper-pink-a200 */
-    --light-accent-color: #ff80ab;  /* --paper-pink-a100 */
-    --dark-accent-color: #f50057;  /* --paper-pink-a400 */
+    --accent-color: var(--paper-pink-a200);
+    --light-accent-color: var(--paper-pink-a100);
+    --dark-accent-color: var(--paper-pink-a400);
+
 
     /*
      * Material Design Light background theme
      */
     --light-theme-background-color: #ffffff;
     --light-theme-base-color: #000000;
-    --light-theme-text-color: #212121;
+    --light-theme-text-color: var(--paper-grey-900);
     --light-theme-secondary-color: #737373;  /* for secondary text and icons */
     --light-theme-disabled-color: #9b9b9b;  /* disabled/hint text */
     --light-theme-divider-color: #dbdbdb;
@@ -51,7 +54,7 @@
     /*
      * Material Design Dark background theme
      */
-    --dark-theme-background-color: #212121;
+    --dark-theme-background-color: var(--paper-grey-900);
     --dark-theme-base-color: #ffffff;
     --dark-theme-text-color: #ffffff;
     --dark-theme-secondary-color: #bcbcbc;  /* for secondary text and icons */
diff --git a/third_party/polymer/v1_0/components-chromium/paper-tabs/.bower.json b/third_party/polymer/v1_0/components-chromium/paper-tabs/.bower.json
index f204eda..4632aa744 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-tabs/.bower.json
+++ b/third_party/polymer/v1_0/components-chromium/paper-tabs/.bower.json
@@ -1,6 +1,6 @@
 {
   "name": "paper-tabs",
-  "version": "1.3.3",
+  "version": "1.3.7",
   "license": "http://polymer.github.io/LICENSE.txt",
   "description": "Material design tabs",
   "private": true,
@@ -23,7 +23,7 @@
     "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
     "iron-icon": "PolymerElements/iron-icon#^1.0.0",
     "iron-iconset-svg": "PolymerElements/iron-iconset-svg#^1.0.0",
-    "iron-menu-behavior": "PolymerElements/iron-menu-behavior#^1.0.0",
+    "iron-menu-behavior": "PolymerElements/iron-menu-behavior#^1.1.0",
     "iron-resizable-behavior": "PolymerElements/iron-resizable-behavior#^1.0.0",
     "paper-behaviors": "PolymerElements/paper-behaviors#^1.0.0",
     "paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0",
@@ -42,11 +42,11 @@
   },
   "ignore": [],
   "homepage": "https://github.com/PolymerElements/paper-tabs",
-  "_release": "1.3.3",
+  "_release": "1.3.7",
   "_resolution": {
     "type": "version",
-    "tag": "v1.3.3",
-    "commit": "4c53ca15663b6f4b13b20a8aab6af8dea5bfc369"
+    "tag": "v1.3.7",
+    "commit": "b8d689c7cdf926a69c91d2421aa6c2536608fad4"
   },
   "_source": "git://github.com/PolymerElements/paper-tabs.git",
   "_target": "^1.0.0",
diff --git a/third_party/polymer/v1_0/components-chromium/paper-tabs/CONTRIBUTING.md b/third_party/polymer/v1_0/components-chromium/paper-tabs/CONTRIBUTING.md
index 7b101415..f147978a 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-tabs/CONTRIBUTING.md
+++ b/third_party/polymer/v1_0/components-chromium/paper-tabs/CONTRIBUTING.md
@@ -5,6 +5,11 @@
 
 If you edit that file, it will get updated everywhere else.
 If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
 -->
 # Polymer Elements
 ## Guide for Contributors
@@ -41,7 +46,7 @@
  3. Click the `paper-foo` element.
  ```
 
- 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [http://jsbin.com/cagaye](http://jsbin.com/cagaye/edit?html,output).
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
 
  3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
 
@@ -51,14 +56,14 @@
 
 When submitting pull requests, please provide:
 
- 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues using the following syntax:
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
 
  ```markdown
  (For a single issue)
  Fixes #20
 
  (For multiple issues)
- Fixes #32, #40
+ Fixes #32, fixes #40
  ```
 
  2. **A succinct description of the design** used to fix any related issues. For example:
diff --git a/third_party/polymer/v1_0/components-chromium/paper-tabs/README.md b/third_party/polymer/v1_0/components-chromium/paper-tabs/README.md
index cc28ca0..68fdc148 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-tabs/README.md
+++ b/third_party/polymer/v1_0/components-chromium/paper-tabs/README.md
@@ -12,9 +12,9 @@
 
 -->
 
-[![Build Status](https://travis-ci.org/PolymerElements/paper-tabs.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-tabs)
+[![Build status](https://travis-ci.org/PolymerElements/paper-tabs.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-tabs)
 
-_[Demo and API Docs](https://elements.polymer-project.org/elements/paper-tabs)_
+_[Demo and API docs](https://elements.polymer-project.org/elements/paper-tabs)_
 
 
 ##&lt;paper-tabs&gt;
@@ -36,7 +36,7 @@
 </paper-tabs>
 ```
 
-See <a href="#paper-tab">paper-tab</a> for more information about
+See <a href="?active=paper-tab">paper-tab</a> for more information about
 `paper-tab`.
 
 A common usage for `paper-tabs` is to use it along with `iron-pages` to switch
@@ -61,10 +61,35 @@
 
 Example:
 
-```html
-<style is="custom-style">
+<pre><code>
+&lt;style is="custom-style">
   .link {
-```
+    &#64;apply(--layout-horizontal);
+    &#64;apply(--layout-center-center);
+  }
+&lt;/style>
+
+&lt;paper-tabs selected="0">
+  &lt;paper-tab link>
+    &lt;a href="#link1" class="link">TAB ONE&lt;/a>
+  &lt;/paper-tab>
+  &lt;paper-tab link>
+    &lt;a href="#link2" class="link">TAB TWO&lt;/a>
+  &lt;/paper-tab>
+  &lt;paper-tab link>
+    &lt;a href="#link3" class="link">TAB THREE&lt;/a>
+  &lt;/paper-tab>
+&lt;/paper-tabs>
+</code></pre>
+
+### Styling
+
+The following custom properties and mixins are available for styling:
+
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--paper-tabs-selection-bar-color` | Color for the selection bar | `--paper-yellow-a100` |
+| `--paper-tabs` | Mixin applied to the tabs | `{}` |
 
 
 
diff --git a/third_party/polymer/v1_0/components-chromium/paper-tabs/bower.json b/third_party/polymer/v1_0/components-chromium/paper-tabs/bower.json
index 8a4c4ac..af6a21c5 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-tabs/bower.json
+++ b/third_party/polymer/v1_0/components-chromium/paper-tabs/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "paper-tabs",
-  "version": "1.3.3",
+  "version": "1.3.7",
   "license": "http://polymer.github.io/LICENSE.txt",
   "description": "Material design tabs",
   "private": true,
@@ -23,7 +23,7 @@
     "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
     "iron-icon": "PolymerElements/iron-icon#^1.0.0",
     "iron-iconset-svg": "PolymerElements/iron-iconset-svg#^1.0.0",
-    "iron-menu-behavior": "PolymerElements/iron-menu-behavior#^1.0.0",
+    "iron-menu-behavior": "PolymerElements/iron-menu-behavior#^1.1.0",
     "iron-resizable-behavior": "PolymerElements/iron-resizable-behavior#^1.0.0",
     "paper-behaviors": "PolymerElements/paper-behaviors#^1.0.0",
     "paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0",
diff --git a/third_party/polymer/v1_0/components-chromium/paper-tabs/compiled_resources2.gyp b/third_party/polymer/v1_0/components-chromium/paper-tabs/compiled_resources2.gyp
index 39997d8..fe704fe 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-tabs/compiled_resources2.gyp
+++ b/third_party/polymer/v1_0/components-chromium/paper-tabs/compiled_resources2.gyp
@@ -15,13 +15,6 @@
       'includes': ['../../../../closure_compiler/compile_js2.gypi'],
     },
     {
-      'target_name': 'paper-tabs-icons-extracted',
-      'dependencies': [
-        '../iron-iconset-svg/compiled_resources2.gyp:iron-iconset-svg-extracted',
-      ],
-      'includes': ['../../../../closure_compiler/compile_js2.gypi'],
-    },
-    {
       'target_name': 'paper-tabs-extracted',
       'dependencies': [
         '../iron-icon/compiled_resources2.gyp:iron-icon-extracted',
@@ -32,5 +25,12 @@
       ],
       'includes': ['../../../../closure_compiler/compile_js2.gypi'],
     },
+    {
+      'target_name': 'paper-tabs-icons-extracted',
+      'dependencies': [
+        '../iron-iconset-svg/compiled_resources2.gyp:iron-iconset-svg-extracted',
+      ],
+      'includes': ['../../../../closure_compiler/compile_js2.gypi'],
+    },
   ],
 }
diff --git a/third_party/polymer/v1_0/components-chromium/paper-tabs/paper-tab.html b/third_party/polymer/v1_0/components-chromium/paper-tabs/paper-tab.html
index e832506..a61f9c4d 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-tabs/paper-tab.html
+++ b/third_party/polymer/v1_0/components-chromium/paper-tabs/paper-tab.html
@@ -93,7 +93,7 @@
       }
 
       .tab-content > ::content > a {
-        @apply(--layout-flex-auto)
+        @apply(--layout-flex-auto);
 
         height: 100%;
       }
diff --git a/third_party/polymer/v1_0/components-chromium/paper-tabs/paper-tabs-extracted.js b/third_party/polymer/v1_0/components-chromium/paper-tabs/paper-tabs-extracted.js
index d0b6e91..9711b0e 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-tabs/paper-tabs-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/paper-tabs/paper-tabs-extracted.js
@@ -66,14 +66,6 @@
           value: false
         },
 
-        /**
-         * Gets or sets the selected element. The default is to use the index of the item.
-         */
-        selected: {
-          type: String,
-          notify: true
-        },
-
         selectable: {
           type: String,
           value: 'paper-tab'
@@ -275,7 +267,13 @@
         // bar animation: expand
         this.$.selectionBar.classList.add('expand');
 
-        if (oldIndex < index) {
+        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 {
diff --git a/third_party/polymer/v1_0/components-chromium/paper-tabs/paper-tabs.html b/third_party/polymer/v1_0/components-chromium/paper-tabs/paper-tabs.html
index d141317..5f5e645 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-tabs/paper-tabs.html
+++ b/third_party/polymer/v1_0/components-chromium/paper-tabs/paper-tabs.html
@@ -56,24 +56,26 @@
 
 Example:
 
-    <style is="custom-style">
-      .link {
-        @apply(--layout-horizontal);
-        @apply(--layout-center-center);
-      }
-    </style>
+<pre><code>
+&lt;style is="custom-style">
+  .link {
+    &#64;apply(--layout-horizontal);
+    &#64;apply(--layout-center-center);
+  }
+&lt;/style>
 
-    <paper-tabs selected="0">
-      <paper-tab link>
-        <a href="#link1" class="link">TAB ONE</a>
-      </paper-tab>
-      <paper-tab link>
-        <a href="#link2" class="link">TAB TWO</a>
-      </paper-tab>
-      <paper-tab link>
-        <a href="#link3" class="link">TAB THREE</a>
-      </paper-tab>
-    </paper-tabs>
+&lt;paper-tabs selected="0">
+  &lt;paper-tab link>
+    &lt;a href="#link1" class="link">TAB ONE&lt;/a>
+  &lt;/paper-tab>
+  &lt;paper-tab link>
+    &lt;a href="#link2" class="link">TAB TWO&lt;/a>
+  &lt;/paper-tab>
+  &lt;paper-tab link>
+    &lt;a href="#link3" class="link">TAB THREE&lt;/a>
+  &lt;/paper-tab>
+&lt;/paper-tabs>
+</code></pre>
 
 ### Styling
 
@@ -82,6 +84,7 @@
 Custom property | Description | Default
 ----------------|-------------|----------
 `--paper-tabs-selection-bar-color` | Color for the selection bar | `--paper-yellow-a100`
+`--paper-tabs-selection-bar` | Mixin applied to the selection bar | {}
 `--paper-tabs` | Mixin applied to the tabs | `{}`
 
 @hero hero.svg
@@ -103,7 +106,10 @@
           -ms-user-select: none;
           -webkit-user-select: none;
         user-select: none;
-        -webkit-tap-highlight-color: rgba(0,0,0,0);
+
+        /* NOTE: Both values are needed, since some phones require the value to be `transparent`. */
+        -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+        -webkit-tap-highlight-color: transparent;
 
         @apply(--paper-tabs);
       }
@@ -193,8 +199,8 @@
 
     <div id="tabsContainer" on-track="_scroll" on-down="_down">
       <div id="tabsContent" class$="[[_computeTabsContentClass(scrollable)]]">
-        <content select="*"></content>
         <div id="selectionBar" class$="[[_computeSelectionBarClass(noBar, alignBottom)]]" on-transitionend="_onBarTransitionEnd"></div>
+        <content select="*"></content>
       </div>
     </div>
 
diff --git a/third_party/polymer/v1_0/components-chromium/paper-toggle-button/.bower.json b/third_party/polymer/v1_0/components-chromium/paper-toggle-button/.bower.json
index 4ce2028..7f52cc6 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-toggle-button/.bower.json
+++ b/third_party/polymer/v1_0/components-chromium/paper-toggle-button/.bower.json
@@ -1,6 +1,6 @@
 {
   "name": "paper-toggle-button",
-  "version": "1.0.14",
+  "version": "1.1.1",
   "description": "A material design toggle button control",
   "authors": [
     "The Polymer Authors"
@@ -23,8 +23,7 @@
     "polymer": "Polymer/polymer#^1.1.0",
     "iron-checked-element-behavior": "PolymerElements/iron-checked-element-behavior#^1.0.0",
     "paper-behaviors": "PolymerElements/paper-behaviors#^1.0.0",
-    "paper-ripple": "PolymerElements/paper-ripple#^1.0.0",
-    "paper-styles": "PolymerElements/paper-styles#^1.0.0"
+    "paper-styles": "PolymerElements/paper-styles#^1.1.0"
   },
   "devDependencies": {
     "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
@@ -32,15 +31,15 @@
     "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
     "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
     "test-fixture": "PolymerElements/test-fixture#^1.0.0",
-    "web-component-tester": "Polymer/web-component-tester#^3.3.0",
+    "web-component-tester": "^4.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
   },
   "main": "paper-toggle-button.html",
-  "_release": "1.0.14",
+  "_release": "1.1.1",
   "_resolution": {
     "type": "version",
-    "tag": "v1.0.14",
-    "commit": "131f32adf5ce831f94be7f80c436865b44d7cd95"
+    "tag": "v1.1.1",
+    "commit": "0cfebed00270466462684718ec73b3195179df48"
   },
   "_source": "git://github.com/PolymerElements/paper-toggle-button.git",
   "_target": "^1.0.0",
diff --git a/third_party/polymer/v1_0/components-chromium/paper-toggle-button/CONTRIBUTING.md b/third_party/polymer/v1_0/components-chromium/paper-toggle-button/CONTRIBUTING.md
index 7b101415..f147978a 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-toggle-button/CONTRIBUTING.md
+++ b/third_party/polymer/v1_0/components-chromium/paper-toggle-button/CONTRIBUTING.md
@@ -5,6 +5,11 @@
 
 If you edit that file, it will get updated everywhere else.
 If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
 -->
 # Polymer Elements
 ## Guide for Contributors
@@ -41,7 +46,7 @@
  3. Click the `paper-foo` element.
  ```
 
- 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [http://jsbin.com/cagaye](http://jsbin.com/cagaye/edit?html,output).
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
 
  3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
 
@@ -51,14 +56,14 @@
 
 When submitting pull requests, please provide:
 
- 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues using the following syntax:
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
 
  ```markdown
  (For a single issue)
  Fixes #20
 
  (For multiple issues)
- Fixes #32, #40
+ Fixes #32, fixes #40
  ```
 
  2. **A succinct description of the design** used to fix any related issues. For example:
diff --git a/third_party/polymer/v1_0/components-chromium/paper-toggle-button/README.md b/third_party/polymer/v1_0/components-chromium/paper-toggle-button/README.md
index 43e6f9c7..8fee54f6 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-toggle-button/README.md
+++ b/third_party/polymer/v1_0/components-chromium/paper-toggle-button/README.md
@@ -7,16 +7,18 @@
 Edit those files, and our readme bot will duplicate them over here!
 Edit this file, and the bot will squash your changes :)
 
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
 -->
 
-[![Build Status](https://travis-ci.org/PolymerElements/paper-toggle-button.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-toggle-button)
+[![Build status](https://travis-ci.org/PolymerElements/paper-toggle-button.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-toggle-button)
 
-_[Demo and API Docs](https://elements.polymer-project.org/elements/paper-toggle-button)_
+_[Demo and API docs](https://elements.polymer-project.org/elements/paper-toggle-button)_
 
 
 ##&lt;paper-toggle-button&gt;
 
-
 Material design: [Switch](https://www.google.com/design/spec/components/selection-controls.html#selection-controls-switch)
 
 `paper-toggle-button` provides a ON/OFF switch that user can toggle the state
@@ -24,25 +26,30 @@
 
 Example:
 
-    <paper-toggle-button></paper-toggle-button>
+```html
+<paper-toggle-button></paper-toggle-button>
+```
 
 ### Styling
 
 The following custom properties and mixins are available for styling:
 
-Custom property | Description | Default
-----------------|-------------|----------
-`--paper-toggle-button-unchecked-bar-color` | Slider color when the input is not checked | `#000000`
-`--paper-toggle-button-unchecked-button-color` | Button color when the input is not checked | `--paper-grey-50`
-`--paper-toggle-button-unchecked-ink-color` | Selected/focus ripple color when the input is not checked | `--dark-primary-color`
-`--paper-toggle-button-checked-bar-color` | Slider button color when the input is checked | `--default-primary-color`
-`--paper-toggle-button-checked-button-color` | Button color when the input is checked | `--default-primary-color`
-`--paper-toggle-button-checked-ink-color` | Selected/focus ripple color when the input is checked | `--default-primary-color`
-`--paper-toggle-button-unchecked-bar` | Mixin applied to the slider when the input is not checked | `{}`
-`--paper-toggle-button-unchecked-button` | Mixin applied to the slider button when the input is not checked | `{}`
-`--paper-toggle-button-checked-bar` | Mixin applied to the slider when the input is checked | `{}`
-`--paper-toggle-button-checked-button` | Mixin applied to the slider button when the input is checked | `{}`
-`--paper-toggle-button-label-color` | Label color | `--primary-text-color`
-`--paper-toggle-button-label-spacing` | Spacing between the label and the button | `8px`
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--paper-toggle-button-unchecked-bar-color` | Slider color when the input is not checked | `#000000` |
+| `--paper-toggle-button-unchecked-button-color` | Button color when the input is not checked | `--paper-grey-50` |
+| `--paper-toggle-button-unchecked-ink-color` | Selected/focus ripple color when the input is not checked | `--dark-primary-color` |
+| `--paper-toggle-button-checked-bar-color` | Slider button color when the input is checked | `--primary-color` |
+| `--paper-toggle-button-checked-button-color` | Button color when the input is checked | `--primary-color` |
+| `--paper-toggle-button-checked-ink-color` | Selected/focus ripple color when the input is checked | `--primary-color` |
+| `--paper-toggle-button-unchecked-bar` | Mixin applied to the slider when the input is not checked | `{}` |
+| `--paper-toggle-button-unchecked-button` | Mixin applied to the slider button when the input is not checked | `{}` |
+| `--paper-toggle-button-checked-bar` | Mixin applied to the slider when the input is checked | `{}` |
+| `--paper-toggle-button-checked-button` | Mixin applied to the slider button when the input is checked | `{}` |
+| `--paper-toggle-button-label-color` | Label color | `--primary-text-color` |
+| `--paper-toggle-button-label-spacing` | Spacing between the label and the button | `8px` |
+
+This element applies the mixin `--paper-font-common-base` but does not import `paper-styles/typography.html`.
+In order to apply the `Roboto` font to this element, make sure you've imported `paper-styles/typography.html`.
 
 
diff --git a/third_party/polymer/v1_0/components-chromium/paper-toggle-button/bower.json b/third_party/polymer/v1_0/components-chromium/paper-toggle-button/bower.json
index c6d1723..9b0b8020 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-toggle-button/bower.json
+++ b/third_party/polymer/v1_0/components-chromium/paper-toggle-button/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "paper-toggle-button",
-  "version": "1.0.14",
+  "version": "1.1.1",
   "description": "A material design toggle button control",
   "authors": [
     "The Polymer Authors"
@@ -23,8 +23,7 @@
     "polymer": "Polymer/polymer#^1.1.0",
     "iron-checked-element-behavior": "PolymerElements/iron-checked-element-behavior#^1.0.0",
     "paper-behaviors": "PolymerElements/paper-behaviors#^1.0.0",
-    "paper-ripple": "PolymerElements/paper-ripple#^1.0.0",
-    "paper-styles": "PolymerElements/paper-styles#^1.0.0"
+    "paper-styles": "PolymerElements/paper-styles#^1.1.0"
   },
   "devDependencies": {
     "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
@@ -32,7 +31,7 @@
     "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
     "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
     "test-fixture": "PolymerElements/test-fixture#^1.0.0",
-    "web-component-tester": "Polymer/web-component-tester#^3.3.0",
+    "web-component-tester": "^4.0.0",
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
   },
   "main": "paper-toggle-button.html"
diff --git a/third_party/polymer/v1_0/components-chromium/paper-toggle-button/compiled_resources2.gyp b/third_party/polymer/v1_0/components-chromium/paper-toggle-button/compiled_resources2.gyp
index 87c8a4cc..9e0785b 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-toggle-button/compiled_resources2.gyp
+++ b/third_party/polymer/v1_0/components-chromium/paper-toggle-button/compiled_resources2.gyp
@@ -9,7 +9,6 @@
       'target_name': 'paper-toggle-button-extracted',
       'dependencies': [
         '../paper-behaviors/compiled_resources2.gyp:paper-checked-element-behavior-extracted',
-        '../paper-ripple/compiled_resources2.gyp:paper-ripple-extracted',
       ],
       'includes': ['../../../../closure_compiler/compile_js2.gypi'],
     },
diff --git a/third_party/polymer/v1_0/components-chromium/paper-toggle-button/paper-toggle-button.html b/third_party/polymer/v1_0/components-chromium/paper-toggle-button/paper-toggle-button.html
index d511e65..cbdd7520 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-toggle-button/paper-toggle-button.html
+++ b/third_party/polymer/v1_0/components-chromium/paper-toggle-button/paper-toggle-button.html
@@ -10,7 +10,6 @@
 <link rel="import" href="../iron-flex-layout/iron-flex-layout.html">
 <link rel="import" href="../paper-styles/color.html">
 <link rel="import" href="../paper-styles/default-theme.html">
-<link rel="import" href="../paper-ripple/paper-ripple.html">
 <link rel="import" href="../paper-behaviors/paper-checked-element-behavior.html">
 
 <!--
@@ -32,9 +31,9 @@
 `--paper-toggle-button-unchecked-bar-color` | Slider color when the input is not checked | `#000000`
 `--paper-toggle-button-unchecked-button-color` | Button color when the input is not checked | `--paper-grey-50`
 `--paper-toggle-button-unchecked-ink-color` | Selected/focus ripple color when the input is not checked | `--dark-primary-color`
-`--paper-toggle-button-checked-bar-color` | Slider button color when the input is checked | `--default-primary-color`
-`--paper-toggle-button-checked-button-color` | Button color when the input is checked | `--default-primary-color`
-`--paper-toggle-button-checked-ink-color` | Selected/focus ripple color when the input is checked | `--default-primary-color`
+`--paper-toggle-button-checked-bar-color` | Slider button color when the input is checked | `--primary-color`
+`--paper-toggle-button-checked-button-color` | Button color when the input is checked | `--primary-color`
+`--paper-toggle-button-checked-ink-color` | Selected/focus ripple color when the input is checked | `--primary-color`
 `--paper-toggle-button-unchecked-bar` | Mixin applied to the slider when the input is not checked | `{}`
 `--paper-toggle-button-unchecked-button` | Mixin applied to the slider button when the input is not checked | `{}`
 `--paper-toggle-button-checked-bar` | Mixin applied to the slider when the input is checked | `{}`
@@ -42,6 +41,9 @@
 `--paper-toggle-button-label-color` | Label color | `--primary-text-color`
 `--paper-toggle-button-label-spacing` | Spacing between the label and the button | `8px`
 
+This element applies the mixin `--paper-font-common-base` but does not import `paper-styles/typography.html`.
+In order to apply the `Roboto` font to this element, make sure you've imported `paper-styles/typography.html`.
+
 @group Paper Elements
 @element paper-toggle-button
 @hero hero.svg
@@ -56,6 +58,7 @@
         display: inline-block;
         @apply(--layout-horizontal);
         @apply(--layout-center);
+        @apply(--paper-font-common-base);
       }
 
       :host([disabled]) {
@@ -75,6 +78,7 @@
         opacity: 0.4;
         transition: background-color linear .08s;
         background-color: var(--paper-toggle-button-unchecked-bar-color, #000000);
+
         @apply(--paper-toggle-button-unchecked-bar);
       }
 
@@ -89,6 +93,7 @@
         transition: transform linear .08s, background-color linear .08s;
         will-change: transform;
         background-color: var(--paper-toggle-button-unchecked-button-color, --paper-grey-50);
+
         @apply(--paper-toggle-button-unchecked-button);
       }
 
@@ -99,7 +104,8 @@
 
       :host([checked]:not([disabled])) .toggle-bar {
         opacity: 0.5;
-        background-color: var(--paper-toggle-button-checked-bar-color, --default-primary-color);
+        background-color: var(--paper-toggle-button-checked-bar-color, --primary-color);
+
         @apply(--paper-toggle-button-checked-bar);
       }
 
@@ -114,7 +120,8 @@
       }
 
       :host([checked]:not([disabled])) .toggle-button {
-        background-color: var(--paper-toggle-button-checked-button-color, --default-primary-color);
+        background-color: var(--paper-toggle-button-checked-button-color, --primary-color);
+
         @apply(--paper-toggle-button-checked-button);
       }
 
@@ -135,7 +142,7 @@
       }
 
       :host([checked]) .toggle-ink {
-        color: var(--paper-toggle-button-checked-ink-color, --default-primary-color);
+        color: var(--paper-toggle-button-checked-ink-color, --primary-color);
       }
 
       .toggle-container {
@@ -153,7 +160,6 @@
         display: inline-block;
         vertical-align: middle;
         padding-left: var(--paper-toggle-button-label-spacing, 8px);
-        white-space: normal;
         pointer-events: none;
         color: var(--paper-toggle-button-label-color, --primary-text-color);
       }
diff --git a/third_party/polymer/v1_0/components-chromium/paper-tooltip/.bower.json b/third_party/polymer/v1_0/components-chromium/paper-tooltip/.bower.json
index 608b876d..3df87bd 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-tooltip/.bower.json
+++ b/third_party/polymer/v1_0/components-chromium/paper-tooltip/.bower.json
@@ -1,6 +1,6 @@
 {
   "name": "paper-tooltip",
-  "version": "1.1.1",
+  "version": "1.1.2",
   "description": "Material design tooltip popup for content",
   "authors": [
     "The Polymer Authors"
@@ -10,9 +10,7 @@
     "polymer",
     "tooltip"
   ],
-  "main": [
-    "paper-tooltip.html"
-  ],
+  "main": "paper-tooltip.html",
   "private": true,
   "repository": {
     "type": "git",
@@ -28,17 +26,18 @@
   },
   "devDependencies": {
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
-    "web-component-tester": "*",
+    "web-component-tester": "^4.0.0",
     "test-fixture": "PolymerElements/test-fixture#^1.0.0",
     "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+    "iron-demo-helpers": "polymerelements/iron-demo-helpers#^1.0.0",
     "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
     "paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0"
   },
-  "_release": "1.1.1",
+  "_release": "1.1.2",
   "_resolution": {
     "type": "version",
-    "tag": "v1.1.1",
-    "commit": "0b274f0ad241877fd316101b43fe48b013a470b6"
+    "tag": "v1.1.2",
+    "commit": "6be894127678900f6e506b56fc9622ab768c03aa"
   },
   "_source": "git://github.com/PolymerElements/paper-tooltip.git",
   "_target": "^1.0.0",
diff --git a/third_party/polymer/v1_0/components-chromium/paper-tooltip/CONTRIBUTING.md b/third_party/polymer/v1_0/components-chromium/paper-tooltip/CONTRIBUTING.md
new file mode 100644
index 0000000..f147978a
--- /dev/null
+++ b/third_party/polymer/v1_0/components-chromium/paper-tooltip/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/third_party/polymer/v1_0/components-chromium/paper-tooltip/README.md b/third_party/polymer/v1_0/components-chromium/paper-tooltip/README.md
index 67a9fa4..b20a34b5 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-tooltip/README.md
+++ b/third_party/polymer/v1_0/components-chromium/paper-tooltip/README.md
@@ -1,28 +1,62 @@
-# paper-tooltip
+
+<!---
+
+This README is automatically generated from the comments in these files:
+paper-tooltip.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/paper-tooltip.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-tooltip)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/paper-tooltip)_
+
+
+##&lt;paper-tooltip&gt;
+
+Material design: [Tooltips](https://www.google.com/design/spec/components/tooltips.html)
 
 `<paper-tooltip>` is a label that appears on hover and focus when the user
 hovers over an element with the cursor or with the keyboard. It will be centered
 to an anchor element specified in the `for` attribute, or, if that doesn't exist,
 centered to the parent node containing it.
+
 Example:
 
 ```html
-    <div style="display:inline-block">
-      <button>Click me!</button>
-      <paper-tooltip>Tooltip text</paper-tooltip>
-    </div>
-    <div>
-      <button id="btn">Click me!</button>
-      <paper-tooltip for="btn">Tooltip text</paper-tooltip>
-    </div>
+<div style="display:inline-block">
+  <button>Click me!</button>
+  <paper-tooltip>Tooltip text</paper-tooltip>
+</div>
+
+<div>
+  <button id="btn">Click me!</button>
+  <paper-tooltip for="btn">Tooltip text</paper-tooltip>
+</div>
+```
+
+The tooltip can be positioned on the top|bottom|left|right of the anchor using
+the `position` attribute. The default position is bottom.
+
+```html
+<paper-tooltip for="btn" position="left">Tooltip text</paper-tooltip>
+<paper-tooltip for="btn" position="top">Tooltip text</paper-tooltip>
 ```
 
 ### Styling
+
 The following custom properties and mixins are available for styling:
 
-Custom property | Description | Default
-----------------|-------------|----------
-`--paper-tooltip-background` | The background color of the tooltip | `#616161`
-`--paper-tooltip-opacity` | The opacity of the tooltip | `0.9`
-`--paper-tooltip-text-color` | The text color of the tooltip | `white`
-`--paper-tooltip` | Mixin applied to the tooltip | `{}`
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--paper-tooltip-background` | The background color of the tooltip | `#616161` |
+| `--paper-tooltip-opacity` | The opacity of the tooltip | `0.9` |
+| `--paper-tooltip-text-color` | The text color of the tooltip | `white` |
+| `--paper-tooltip` | Mixin applied to the tooltip | `{}` |
+
+
diff --git a/third_party/polymer/v1_0/components-chromium/paper-tooltip/bower.json b/third_party/polymer/v1_0/components-chromium/paper-tooltip/bower.json
index 2309926..423c88f 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-tooltip/bower.json
+++ b/third_party/polymer/v1_0/components-chromium/paper-tooltip/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "paper-tooltip",
-  "version": "1.1.1",
+  "version": "1.1.2",
   "description": "Material design tooltip popup for content",
   "authors": [
     "The Polymer Authors"
@@ -10,9 +10,7 @@
     "polymer",
     "tooltip"
   ],
-  "main": [
-    "paper-tooltip.html"
-  ],
+  "main": "paper-tooltip.html",
   "private": true,
   "repository": {
     "type": "git",
@@ -28,9 +26,10 @@
   },
   "devDependencies": {
     "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
-    "web-component-tester": "*",
+    "web-component-tester": "^4.0.0",
     "test-fixture": "PolymerElements/test-fixture#^1.0.0",
     "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+    "iron-demo-helpers": "polymerelements/iron-demo-helpers#^1.0.0",
     "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
     "paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0"
   }
diff --git a/third_party/polymer/v1_0/components-chromium/paper-tooltip/paper-tooltip-extracted.js b/third_party/polymer/v1_0/components-chromium/paper-tooltip/paper-tooltip-extracted.js
index 7946ae48..ed84ac2 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-tooltip/paper-tooltip-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/paper-tooltip/paper-tooltip-extracted.js
@@ -21,6 +21,15 @@
         },
 
         /**
+         * Set this to true if you want to manually control when the tooltip
+         * is shown or hidden.
+         */
+        manualMode: {
+          type: Boolean,
+          value: false
+        },
+
+        /**
          * Positions the tooltip to the top, right, bottom, left of its content.
          */
         position: {
@@ -122,6 +131,9 @@
       attached: function() {
         this._target = this.target;
 
+        if (this.manualMode)
+          return;
+
         this.listen(this._target, 'mouseenter', 'show');
         this.listen(this._target, 'focus', 'show');
         this.listen(this._target, 'mouseleave', 'hide');
@@ -130,7 +142,7 @@
       },
 
       detached: function() {
-        if (this._target) {
+        if (this._target && !this.manualMode) {
           this.unlisten(this._target, 'mouseenter', 'show');
           this.unlisten(this._target, 'focus', 'show');
           this.unlisten(this._target, 'mouseleave', 'hide');
@@ -183,7 +195,7 @@
       },
 
       updatePosition: function() {
-        if (!this._target)
+        if (!this._target || !this.offsetParent)
           return;
 
         var offset = this.offset;
diff --git a/third_party/polymer/v1_0/components-chromium/polymer/.bower.json b/third_party/polymer/v1_0/components-chromium/polymer/.bower.json
index b659cc1..ad5d73c 100644
--- a/third_party/polymer/v1_0/components-chromium/polymer/.bower.json
+++ b/third_party/polymer/v1_0/components-chromium/polymer/.bower.json
@@ -1,6 +1,6 @@
 {
   "name": "polymer",
-  "version": "1.2.4",
+  "version": "1.3.1",
   "main": [
     "polymer.html",
     "polymer-mini.html",
@@ -27,11 +27,11 @@
   },
   "private": true,
   "homepage": "https://github.com/Polymer/polymer",
-  "_release": "1.2.4",
+  "_release": "1.3.1",
   "_resolution": {
     "type": "version",
-    "tag": "v1.2.4",
-    "commit": "284332a905ddd60eab11901a82ac037976175cf8"
+    "tag": "v1.3.1",
+    "commit": "61fac558012d9ef56ea78ed5435de0c418a4afbb"
   },
   "_source": "git://github.com/Polymer/polymer.git",
   "_target": "^v1.0.0",
diff --git a/third_party/polymer/v1_0/components-chromium/polymer/bower.json b/third_party/polymer/v1_0/components-chromium/polymer/bower.json
index bc34c25..ccae83f 100644
--- a/third_party/polymer/v1_0/components-chromium/polymer/bower.json
+++ b/third_party/polymer/v1_0/components-chromium/polymer/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "polymer",
-  "version": "1.2.4",
+  "version": "1.3.1",
   "main": [
     "polymer.html",
     "polymer-mini.html",
diff --git a/third_party/polymer/v1_0/components-chromium/polymer/build.log b/third_party/polymer/v1_0/components-chromium/polymer/build.log
index 012d6fa..34684aa 100644
--- a/third_party/polymer/v1_0/components-chromium/polymer/build.log
+++ b/third_party/polymer/v1_0/components-chromium/polymer/build.log
@@ -1,41 +1,49 @@
 BUILD LOG
 ---------
-Build Time: 2016-01-27T14:09:18-0800
+Build Time: 2016-03-02T10:06:27-0800
 
 NODEJS INFORMATION
 ==================
-nodejs: v5.5.0
-abbrev: 1.0.7
+nodejs: v5.7.0
 accepts: 1.2.13
 accessibility-developer-tools: 2.10.0
+acorn: 2.7.0
+abbrev: 1.0.7
 adm-zip: 0.4.7
 after: 0.8.1
+acorn-jsx: 2.0.1
 align-text: 0.1.3
-amdefine: 1.0.0
 ansi-cyan: 0.1.1
+ansi-escapes: 1.1.1
 ansi-red: 0.1.1
 ansi-regex: 2.0.0
 ansi-styles: 2.1.0
+amdefine: 1.0.0
 ansi-wrap: 0.1.0
+append-field: 0.1.0
 archiver: 0.14.4
-archy: 1.0.0
+argparse: 1.0.6
 arr-diff: 1.1.0
 arr-flatten: 1.0.1
 arr-union: 2.1.0
-array-flatten: 1.1.1
+array-find-index: 1.0.1
 array-differ: 1.0.0
 array-slice: 0.2.3
+array-flatten: 1.1.1
 array-union: 1.0.1
 array-uniq: 1.0.2
+archy: 1.0.0
 arraybuffer.slice: 0.0.6
+arrify: 1.0.1
 asap: 2.0.3
-assert-plus: 0.1.5
-asn1: 0.1.11
-async: 1.5.2
 assertion-error: 1.0.1
+asn1: 0.1.11
+assert-plus: 0.1.5
+async: 1.5.2
 aws-sign2: 0.5.0
-backoff: 2.4.1
+aws4: 1.2.1
 backo2: 1.0.2
+backoff: 2.4.1
 balanced-match: 0.3.0
 base64-arraybuffer: 0.1.2
 base64-js: 0.0.8
@@ -43,132 +51,164 @@
 beeper: 1.1.0
 benchmark: 1.0.0
 better-assert: 1.0.2
-binary: 0.3.0
 binaryextensions: 1.0.0
+binary: 0.3.0
 bl: 0.9.5
 blob: 0.0.4
 bluebird: 2.10.2
 boom: 0.4.2
-brace-expansion: 1.1.2
-browserstack: 1.3.0
-buffer-crc32: 0.2.5
+brace-expansion: 1.1.3
+body-parser: 1.15.0
 buffers: 0.1.1
+buffer-crc32: 0.2.5
+browserstack: 1.3.1
+bufferstreams: 1.1.0
+bunyan: 1.7.1
 builtin-modules: 1.1.1
-bunyan: 1.5.1
-callsite: 1.0.0
+bytes: 2.2.0
+busboy: 0.2.12
 camelcase: 2.1.0
-camelcase-keys: 2.0.0
 capture-stack-trace: 1.0.0
+callsite: 1.0.0
 caseless: 0.8.0
 center-align: 0.1.2
-chai: 3.4.1
+camelcase-keys: 2.0.0
 chainsaw: 0.1.0
+chai: 3.5.0
 chalk: 1.1.1
 cleankill: 1.0.2
+cli-width: 2.1.0
+cli-cursor: 1.0.2
 cliui: 2.1.0
-clone: 1.0.2
+code-point-at: 1.0.0
 clone-stats: 0.0.1
-combined-stream: 0.0.7
+clone: 1.0.2
 commander: 2.3.0
 component-bind: 1.0.0
-component-emitter: 1.1.2
+combined-stream: 0.0.7
 component-inherit: 0.0.3
-compress-commons: 0.2.9
-configstore: 1.4.0
+component-emitter: 1.1.2
 concat-map: 0.0.1
-content-disposition: 0.5.1
+compress-commons: 0.2.9
+concat-stream: 1.5.1
+configstore: 1.4.0
 content-type: 1.0.1
+content-disposition: 0.5.1
 cookie: 0.1.5
-cookie-signature: 1.0.6
 crc: 3.2.1
 core-util-is: 1.0.2
-crc32-stream: 0.3.4
+cookie-signature: 1.0.6
 create-error-class: 2.0.1
-cryptiles: 0.2.2
+crc32-stream: 0.3.4
 csv: 0.4.6
+cryptiles: 0.2.2
 csv-generate: 0.0.6
 csv-stringify: 0.0.8
-dashdash: 1.12.2
-csv-parse: 1.0.1
 ctype: 0.5.3
-debug: 2.2.0
+d: 0.1.1
+csv-parse: 1.0.2
 dateformat: 1.0.12
+debug: 2.2.0
 debuglog: 1.0.1
 decamelize: 1.1.2
+dashdash: 1.13.0
 deep-eql: 0.1.3
 deep-extend: 0.4.1
 deep-is: 0.1.3
-defaults: 1.0.3
 delayed-stream: 0.0.5
-del: 1.2.1
+del: 2.2.0
+defaults: 1.0.3
 depd: 1.1.0
 deprecated: 0.0.1
-destroy: 1.0.4
-diff: 1.4.0
 dezalgo: 1.0.3
-dom5: 1.3.1
-dtrace-provider: 0.6.0
+dicer: 0.2.5
+diff: 1.4.0
 doctrine: 0.7.2
+dom5: 1.3.1
+destroy: 1.0.4
+dom-serializer: 0.1.0
+domelementtype: 1.3.0
+domhandler: 2.3.0
+dtrace-provider: 0.6.0
 duplexer: 0.1.1
 duplexer2: 0.0.2
-each-async: 1.1.1
 ecc-jsbn: 0.1.1
 ee-first: 1.1.1
 end-of-stream: 0.1.5
-engine.io: 1.6.7
-engine.io-client: 1.6.7
+domutils: 1.5.1
+engine.io: 1.6.8
+engine.io-client: 1.6.8
+entities: 1.1.1
 engine.io-parser: 1.2.4
 error-ex: 1.3.0
+es5-ext: 0.10.11
+es6-iterator: 2.0.0
+es6-map: 0.1.3
 es6-promise: 2.3.0
-escape-html: 1.0.3
-escape-regexp-component: 1.0.2
+es6-symbol: 3.0.2
+es6-set: 0.1.4
+es6-weak-map: 2.0.1
 escape-string-regexp: 1.0.4
+escape-regexp-component: 1.0.2
 escodegen: 1.8.0
-esutils: 1.1.6
+escope: 3.4.0
+eslint: 2.1.0
+eslint-plugin-html: 1.4.0
 espree: 2.2.5
+escape-html: 1.0.3
+esrecurse: 3.1.1
+estraverse-fb: 1.3.1
 estraverse: 3.1.0
+esutils: 1.1.6
+event-emitter: 0.3.4
 etag: 1.7.0
 express: 4.13.4
-extend-shallow: 1.1.4
-extend: 2.0.1
+exit-hook: 1.1.1
 extsprintf: 1.2.0
 fancy-log: 1.1.0
+extend-shallow: 1.1.4
+extend: 2.0.1
 fast-levenshtein: 1.1.3
+file-entry-cache: 1.2.4
+figures: 1.4.0
 find-index: 0.1.1
-finalhandler: 0.4.1
 find-up: 1.1.0
-findup-sync: 0.3.0
+finalhandler: 0.4.1
 first-chunk-stream: 1.0.0
+findup-sync: 0.3.0
 flagged-respawn: 0.3.1
 forever-agent: 0.5.2
-form-data: 0.2.0
-formidable: 1.0.17
+flat-cache: 1.0.10
 formatio: 1.1.1
+form-data: 0.2.0
 forwarded: 0.1.0
+formidable: 1.0.17
 freeport: 1.0.5
-fresh: 0.3.0
-fstream: 0.1.31
-gaze: 0.5.2
 generate-function: 2.0.0
+fresh: 0.3.0
+gaze: 0.5.2
 generate-object-property: 1.2.0
-get-stdin: 4.0.1
-github-url-from-username-repo: 1.0.2
 github-url-from-git: 1.4.0
+github-url-from-username-repo: 1.0.2
+get-stdin: 4.0.1
 glob: 5.0.15
-glob-stream: 3.1.18
 glob-watcher: 0.0.6
+glob-stream: 3.1.18
 glob2base: 0.0.12
-globby: 2.1.0
+globby: 4.0.0
+globals: 8.18.0
+fstream: 0.1.31
 glogg: 1.0.0
 globule: 0.1.0
+graceful-fs: 2.0.3
 got: 5.4.1
 graceful-readlink: 1.0.1
-graceful-fs: 4.1.2
 growl: 1.8.1
+gulp: 3.9.1
 gulp-audit: 1.0.0
-gulp: 3.9.0
-gulp-rename: 1.2.2
+gulp-eslint: 2.0.0
 gulp-replace: 0.5.4
+gulp-rename: 1.2.2
 gulp-util: 3.0.7
 gulp-vulcanize: 6.1.0
 gulplog: 1.0.0
@@ -179,211 +219,235 @@
 has-cors: 1.1.0
 has-gulplog: 0.1.0
 hoek: 0.9.1
-hawk: 1.1.1
 hosted-git-info: 2.1.4
-http-errors: 1.3.1
-hydrolysis: 1.21.4
+hawk: 1.1.1
+htmlparser2: 3.9.0
 http-signature: 0.11.0
+hydrolysis: 1.21.4
+http-errors: 1.4.0
+ignore: 2.2.19
 imurmurhash: 0.1.4
 indent-string: 2.1.0
 indexof: 0.0.1
+iconv-lite: 0.4.13
 inflight: 1.0.4
 inherits: 2.0.1
+inquirer: 0.12.0
 ini: 1.3.4
-interpret: 0.6.6
-is-absolute: 0.1.7
+interpret: 1.0.0
 ipaddr.js: 1.0.5
+is-absolute: 0.1.7
 is-arrayish: 0.2.1
 is-buffer: 1.1.1
 is-builtin-module: 1.0.0
 is-finite: 1.0.1
+is-fullwidth-code-point: 1.0.0
 is-my-json-valid: 2.12.4
-is-npm: 1.0.0
 is-path-cwd: 1.0.0
 is-path-in-cwd: 1.0.0
-is-path-inside: 1.0.0
 is-plain-obj: 1.1.0
-is-property: 1.0.2
+is-npm: 1.0.0
+is-path-inside: 1.0.0
 is-redirect: 1.0.0
+is-property: 1.0.2
 is-relative: 0.1.3
+is-resolvable: 1.0.0
 is-retry-allowed: 1.0.0
-is-stream: 1.0.1
 is-typedarray: 1.0.0
-is-utf8: 0.2.1
-isexe: 1.1.1
+is-stream: 1.0.1
 isarray: 0.0.1
+is-utf8: 0.2.1
 isstream: 0.1.2
 istextorbinary: 1.0.2
-jju: 1.2.1
 jade: 0.26.3
 jodid25519: 1.0.2
+jju: 1.2.1
 jsbn: 0.1.0
+isexe: 1.1.2
+js-yaml: 3.5.3
 json-parse-helpfulerror: 1.0.3
-json-schema: 0.2.2
 json-stringify-safe: 5.0.1
-json3: 3.2.6
+json-schema: 0.2.2
+json-stable-stringify: 1.0.1
 jsonpointer: 2.0.0
-jsprim: 1.2.2
-kind-of: 1.1.0
-latest-version: 2.0.0
+jsonify: 0.0.0
+json3: 3.2.6
 keep-alive-agent: 0.0.1
-launchpad: 0.5.0
-lazypipe: 0.2.4
+jsprim: 1.2.2
+latest-version: 2.0.0
+kind-of: 1.1.0
 lazy-cache: 0.2.7
+lazypipe: 1.0.1
+launchpad: 0.5.1
 lazystream: 0.1.0
-levn: 0.3.0
 liftoff: 2.2.0
-lodash: 1.0.2
 load-json-file: 1.1.0
+lodash: 1.0.2
 lodash._basecopy: 3.0.1
 lodash._basetostring: 3.0.1
 lodash._basevalues: 3.0.0
-lodash._isiterateecall: 3.0.9
 lodash._getnative: 3.9.1
+lodash._isiterateecall: 3.0.9
 lodash._reescape: 3.0.0
 lodash._reevaluate: 3.0.0
+lodash._root: 3.0.0
 lodash._reinterpolate: 3.0.0
-lodash.escape: 3.1.1
-lodash.isarguments: 3.0.5
+lodash.escape: 3.2.0
+lodash.isarguments: 3.0.6
 lodash.isarray: 3.0.4
 lodash.keys: 3.1.2
 lodash.template: 3.6.2
 lodash.restparam: 3.6.1
 lodash.templatesettings: 3.1.1
+levn: 0.3.0
 lolex: 1.3.2
 longest: 1.0.1
-loud-rejection: 1.2.0
 lowercase-keys: 1.0.0
+loud-rejection: 1.2.1
 lru-cache: 2.7.3
-map-obj: 1.0.1
 match-stream: 0.0.2
-media-typer: 0.3.0
+map-obj: 1.0.1
 meow: 3.7.0
+media-typer: 0.3.0
 merge-descriptors: 1.0.1
-methods: 1.1.2
-mime-db: 1.21.0
 mime: 1.3.4
-mime-types: 2.1.9
-minimatch: 3.0.0
+methods: 1.1.2
 minimist: 1.2.0
+minimatch: 3.0.0
 mkdirp: 0.5.1
-mocha: 2.4.1
+mime-db: 1.22.0
+mocha: 2.4.5
+mime-types: 2.1.10
 ms: 0.7.1
+moment: 2.11.2
+multer: 1.1.0
 multipipe: 0.1.2
 mv: 2.1.1
+mute-stream: 0.0.5
 nan: 2.2.0
-negotiator: 0.5.3
 ncp: 2.0.0
+negotiator: 0.5.3
 node-int64: 0.3.3
-node-status-codes: 1.0.0
 node-uuid: 1.4.7
-nopt: 3.0.6
+node-status-codes: 1.0.0
 nomnom: 1.8.1
+nopt: 3.0.6
 number-is-nan: 1.0.0
 normalize-package-data: 2.3.5
 oauth-sign: 0.5.0
-object-assign: 3.0.0
 object-component: 0.0.3
+object-assign: 3.0.0
 on-finished: 2.3.0
 once: 1.3.3
-optionator: 0.8.1
 onetime: 1.1.0
-options: 0.0.6
+optionator: 0.8.1
 orchestrator: 0.3.7
 ordered-read-streams: 0.1.0
-os-tmpdir: 1.0.1
+options: 0.0.6
 osenv: 0.1.3
 os-homedir: 1.0.1
-over: 0.0.5
+os-tmpdir: 1.0.1
 package-json: 2.3.0
-parse-json: 2.2.0
+over: 0.0.5
 parse5: 1.5.1
+parse-json: 2.2.0
 parsejson: 0.0.1
-parseuri: 0.0.4
 parseqs: 0.0.2
+parseuri: 0.0.4
 parseurl: 1.3.1
-path-exists: 2.1.0
 path-is-absolute: 1.0.0
 path-is-inside: 1.0.1
-path-posix: 1.0.0
-path-to-regexp: 0.1.7
+path-exists: 2.1.0
 path-type: 1.1.0
+path-to-regexp: 0.1.7
+path-posix: 1.0.0
 pify: 2.3.0
-pinkie: 2.0.1
 pinkie-promise: 2.0.0
 plist: 1.2.0
+pinkie: 2.0.4
 plugin-error: 0.1.2
-polyclean: 1.3.1
 precond: 0.2.3
-prelude-ls: 1.1.2
+pluralize: 1.2.1
+polyclean: 1.3.1
 prepend-http: 1.0.3
-pretty-hrtime: 1.0.1
+prelude-ls: 1.1.2
 process-nextick-args: 1.0.6
 progress: 1.1.8
-pullstream: 0.4.1
 proxy-addr: 1.0.10
+pretty-hrtime: 1.0.1
 q: 1.4.1
-qs: 4.0.0
+qs: 6.1.0
+pullstream: 0.4.1
 range-parser: 1.0.3
-read-all-stream: 3.0.1
-rc: 1.1.6
+raw-body: 2.1.5
+read-all-stream: 3.1.0
 read-installed: 3.1.5
+read-json-sync: 1.1.1
 read-package-json: 1.3.3
 read-pkg: 1.1.0
 read-pkg-up: 1.0.1
-readdir-scoped-modules: 1.0.2
 readable-stream: 1.1.13
+readdir-scoped-modules: 1.0.2
+rc: 1.1.6
 redent: 1.0.0
-rechoir: 0.6.2
+readline2: 1.0.1
 registry-url: 3.0.3
 repeat-string: 1.5.2
-replace-ext: 0.0.1
 repeating: 2.0.0
+replace-ext: 0.0.1
 replacestream: 4.0.0
-request: 2.51.0
 resolve: 1.1.7
+request: 2.51.0
+rechoir: 0.6.2
 right-align: 0.1.3
-restify: 4.0.3
-rimraf: 2.5.1
+rimraf: 2.4.5
+restify: 4.0.4
+run-async: 0.1.0
+rx-lite: 3.1.2
 run-sequence: 1.1.5
+restore-cursor: 1.0.1
 safe-json-stringify: 1.0.3
 samsam: 1.1.2
 sauce-connect-launcher: 0.14.0
-selenium-standalone: 4.8.0
-semver-diff: 2.1.0
+selenium-standalone: 4.9.1
 semver: 4.3.6
 send: 0.11.1
 sequencify: 0.0.7
-serve-static: 1.10.2
+semver-diff: 2.1.0
 serve-waterfall: 1.1.1
-server-destroy: 1.0.1
-set-immediate-shim: 1.0.1
-setimmediate: 1.0.4
+serve-static: 1.10.2
 sigmund: 1.0.1
+shelljs: 0.5.3
+setimmediate: 1.0.4
 signal-exit: 2.1.2
-sinon: 1.17.2
+sinon: 1.17.3
+server-destroy: 1.0.1
 slice-stream: 1.0.0
+slice-ansi: 0.0.4
 sinon-chai: 2.8.0
 slide: 1.1.6
 sntp: 0.2.4
-socket.io: 1.4.4
 socket.io-adapter: 0.4.0
-socket.io-client: 1.4.4
+socket.io: 1.4.5
 socket.io-parser: 2.2.6
+socket.io-client: 1.4.5
+sparkles: 1.0.0
 source-map: 0.2.0
 spdx-correct: 1.0.2
-sparkles: 1.0.0
-spdx-exceptions: 1.0.4
 spdx-expression-parse: 1.0.2
-spdx-license-ids: 1.2.0
+spdx-exceptions: 1.0.4
 spdy: 1.32.5
-statuses: 1.2.1
-sshpk: 1.7.3
+sprintf-js: 1.0.3
+sshpk: 1.7.4
+spdx-license-ids: 1.2.0
 stacky: 1.3.1
 stream-consume: 0.1.0
 stream-combiner: 0.2.2
+statuses: 1.2.1
 stream-transform: 0.1.1
+streamsearch: 0.1.2
 string-length: 1.0.1
+string-width: 1.0.1
 string_decoder: 0.10.31
 stringstream: 0.0.5
 strip-ansi: 3.0.0
@@ -391,76 +455,83 @@
 strip-indent: 1.0.1
 strip-json-comments: 1.0.4
 supports-color: 2.0.0
+table: 3.7.8
 tar-stream: 1.1.5
 temp: 0.8.3
-test-fixture: 1.1.0
+text-table: 0.2.0
 textextensions: 1.0.1
 through: 2.3.8
-through2: 2.0.0
-tildify: 1.1.2
+test-fixture: 1.1.0
+through2: 2.0.1
 timed-out: 2.0.0
-to-array: 0.1.3
+to-array: 0.1.4
+tildify: 1.1.2
 tough-cookie: 2.2.1
+tryit: 1.0.2
 trim-newlines: 1.0.0
-traverse: 0.3.9
 tunnel-agent: 0.4.2
-tweetnacl: 0.13.3
+traverse: 0.3.9
+tv4: 1.2.7
 type-check: 0.3.2
+tweetnacl: 0.14.1
+type-is: 1.6.12
 type-detect: 1.0.0
-type-is: 1.6.10
 uglify-js: 2.6.1
 uglify-to-browserify: 1.0.2
+typedarray: 0.0.6
 ultron: 1.0.2
 underscore: 1.6.0
-underscore.string: 3.0.3
-unpipe: 1.0.0
 unique-stream: 1.0.0
+unpipe: 1.0.0
+underscore.string: 3.0.3
 unzip: 0.1.11
 unzip-response: 1.0.0
-update-notifier: 0.6.0
-urijs: 1.16.1
 url-parse-lax: 1.0.0
+urijs: 1.16.1
 user-home: 1.1.1
+update-notifier: 0.6.0
 utf8: 2.1.0
 util: 0.10.3
 util-deprecate: 1.0.2
 util-extend: 1.0.3
-utils-merge: 1.0.0
 uuid: 2.0.1
 v8flags: 2.0.11
+utils-merge: 1.0.0
 validate-npm-package-license: 3.0.1
-vargs: 0.1.0
-vasync: 1.6.3
 vary: 1.0.1
+vasync: 1.6.3
 vinyl: 0.5.3
-verror: 1.6.0
+verror: 1.6.1
 vinyl-fs: 0.3.14
+vargs: 0.1.0
 vulcanize: 1.14.5
 wct-local: 2.0.1
-wct-sauce: 1.8.3
 wd: 0.3.12
-web-component-tester: 4.1.0
-which: 1.2.2
+wct-sauce: 1.8.3
+web-component-tester: 4.2.1
 window-size: 0.1.0
 wordwrap: 1.0.0
+which: 1.2.4
 wrappy: 1.0.1
 write-file-atomic: 1.1.4
-ws: 1.0.1
+write: 0.2.1
 xdg-basedir: 2.0.0
-xmlbuilder: 4.0.0
-xmldom: 0.1.21
 xmlhttprequest-ssl: 1.5.1
+xmlbuilder: 4.0.0
+xregexp: 3.0.0
 xtend: 4.0.1
-yargs: 3.10.0
+ws: 1.0.1
+xmldom: 0.1.22
 yeast: 0.1.2
 zip-stream: 0.5.2
+yargs: 3.10.0
 
 REPO REVISIONS
 ==============
-polymer: 6c7b2228c7eb5d2df4bd6260828a1f20f7c0fbb0
+polymer: 119361604ad2e733fb1fe0324a2d5ef758ed32fd
 
 BUILD HASHES
 ============
-polymer-mini.html: c25c2e49244d3947604d0e91d8d0d016df71f56d
-polymer-micro.html: e67fbe4d81d5661b4ed16897c3348f2d77325d6a
-polymer.html: bc0e501f8db1c65e2a1c7f665805f5f191fdfc27
\ No newline at end of file
+polymer-mini.html: 1a66f21c130ca9c6d23878820f7d65c8c6914919
+polymer-micro.html: e3398b4fe03068fa83d783123fceb4d17609e3b6
+polymer.html: 23b2be8162d32ac2c4bbeee258dc5c63bf14effc
\ No newline at end of file
diff --git a/third_party/polymer/v1_0/components-chromium/polymer/polymer-extracted.js b/third_party/polymer/v1_0/components-chromium/polymer/polymer-extracted.js
index 5d493761..b40fbcd 100644
--- a/third_party/polymer/v1_0/components-chromium/polymer/polymer-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/polymer/polymer-extracted.js
@@ -10,7 +10,7 @@
 return node.nodeType === Node.TEXT_NODE ? this._parseTextNodeAnnotation(node, list) : this._parseElementAnnotations(node, list, stripWhiteSpace);
 },
 _bindingRegex: function () {
-var IDENT = '(?:' + '[a-zA-Z_$][\\w.:$-*]*' + ')';
+var IDENT = '(?:' + '[a-zA-Z_$][\\w.:$\\-*]*' + ')';
 var NUMBER = '(?:' + '[-+]?[0-9]*\\.?[0-9]+(?:[eE][-+]?[0-9]+)?' + ')';
 var SQUOTE_STRING = '(?:' + '\'(?:[^\'\\\\]|\\\\.)*\'' + ')';
 var DQUOTE_STRING = '(?:' + '"(?:[^"\\\\]|\\\\.)*"' + ')';
@@ -189,12 +189,14 @@
 node.setAttribute(origName, '');
 }
 node.removeAttribute(origName);
+var propertyName = Polymer.CaseMap.dashToCamelCase(name);
 if (kind === 'property') {
-name = Polymer.CaseMap.dashToCamelCase(name);
+name = propertyName;
 }
 return {
 kind: kind,
 name: name,
+propertyName: propertyName,
 parts: parts,
 literal: literal,
 isCompound: parts.length !== 1
@@ -299,8 +301,10 @@
 for (var k = 0; k < b.parts.length; k++) {
 var p = b.parts[k];
 if (!p.literal) {
-p.signature = this._parseMethod(p.value);
-if (!p.signature) {
+var signature = this._parseMethod(p.value);
+if (signature) {
+p.signature = signature;
+} else {
 p.model = this._modelForPath(p.value);
 }
 }
@@ -364,7 +368,7 @@
 this._marshalAnnotatedListeners();
 }
 },
-_configureAnnotationReferences: function (config) {
+_configureAnnotationReferences: function () {
 var notes = this._notes;
 var nodes = this._nodes;
 for (var i = 0; i < notes.length; i++) {
@@ -693,7 +697,7 @@
 Gestures.handleTouchAction(ev);
 }
 }
-if (type === 'touchend') {
+if (type === 'touchend' && !ev.__polymerSimulatedTouch) {
 POINTERSTATE.mouse.target = Polymer.dom(ev).rootTarget;
 ignoreMouse(true);
 }
@@ -707,14 +711,12 @@
 for (var i = 0, r; i < recognizers.length; i++) {
 r = recognizers[i];
 if (gs[r.name] && !handled[r.name]) {
-if (r.flow && r.flow.start.indexOf(ev.type) > -1) {
-if (r.reset) {
+if (r.flow && r.flow.start.indexOf(ev.type) > -1 && r.reset) {
 r.reset();
 }
 }
 }
-}
-for (var i = 0, r; i < recognizers.length; i++) {
+for (i = 0, r; i < recognizers.length; i++) {
 r = recognizers[i];
 if (gs[r.name] && !handled[r.name]) {
 handled[r.name] = true;
@@ -979,6 +981,9 @@
 var x = e.clientX, y = e.clientY;
 if (self.hasMovedEnough(x, y)) {
 self.info.state = self.info.started ? e.type === 'mouseup' ? 'end' : 'track' : 'start';
+if (self.info.state === 'start') {
+Gestures.prevent('tap');
+}
 self.info.addMove({
 x: x,
 y: y
@@ -993,7 +998,6 @@
 };
 var upfn = function upfn(e) {
 if (self.info.started) {
-Gestures.prevent('tap');
 movefn(e);
 }
 untrackDocument(self.info);
@@ -1012,6 +1016,9 @@
 var ct = e.changedTouches[0];
 var x = ct.clientX, y = ct.clientY;
 if (this.hasMovedEnough(x, y)) {
+if (this.info.state === 'start') {
+Gestures.prevent('tap');
+}
 this.info.addMove({
 x: x,
 y: y
@@ -1025,7 +1032,6 @@
 var t = Gestures.findOriginalTarget(e);
 var ct = e.changedTouches[0];
 if (this.info.started) {
-Gestures.prevent('tap');
 this.info.state = 'end';
 this.info.addMove({
 x: ct.clientX,
@@ -1234,7 +1240,7 @@
 fire: function (type, detail, options) {
 options = options || Polymer.nob;
 var node = options.node || this;
-var detail = detail === null || detail === undefined ? {} : detail;
+detail = detail === null || detail === undefined ? {} : detail;
 var bubbles = options.bubbles === undefined ? true : options.bubbles;
 var cancelable = Boolean(options.cancelable);
 var useCache = options._useCache;
@@ -1418,7 +1424,7 @@
 var EFFECT_ORDER = {
 'compute': 0,
 'annotation': 1,
-'computedAnnotation': 2,
+'annotatedComputation': 2,
 'reflect': 3,
 'notify': 4,
 'observer': 5,
@@ -1451,11 +1457,11 @@
 upper: function (name) {
 return name[0].toUpperCase() + name.substring(1);
 },
-_addAnnotatedListener: function (model, index, property, path, event) {
+_addAnnotatedListener: function (model, index, property, path, event, negated) {
 if (!model._bindListeners) {
 model._bindListeners = [];
 }
-var fn = this._notedListenerFactory(property, path, this._isStructured(path));
+var fn = this._notedListenerFactory(property, path, this._isStructured(path), negated);
 var eventName = event || Polymer.CaseMap.camelToDashCase(property) + '-changed';
 model._bindListeners.push({
 index: index,
@@ -1471,12 +1477,15 @@
 _isEventBogus: function (e, target) {
 return e.path && e.path[0] !== target;
 },
-_notedListenerFactory: function (property, path, isStructured) {
+_notedListenerFactory: function (property, path, isStructured, negated) {
 return function (target, value, targetPath) {
 if (targetPath) {
 this._notifyPath(this._fixPath(path, property, targetPath), value);
 } else {
 value = target[property];
+if (negated) {
+value = !value;
+}
 if (!isStructured) {
 this[path] = value;
 } else {
@@ -1496,7 +1505,6 @@
 var node = inst._nodes[info.index];
 this._addNotifyListener(node, inst, info.event, info.changedFn);
 }
-;
 },
 _addNotifyListener: function (element, context, event, changedFn) {
 element.addEventListener(event, function (e) {
@@ -1506,7 +1514,7 @@
 };
 Polymer.Base.extend(Polymer.Bind, {
 _shouldAddListener: function (effect) {
-return effect.name && effect.kind != 'attribute' && effect.kind != 'text' && !effect.isCompound && effect.parts[0].mode === '{' && !effect.parts[0].negate;
+return effect.name && effect.kind != 'attribute' && effect.kind != 'text' && !effect.isCompound && effect.parts[0].mode === '{';
 },
 _annotationEffect: function (source, value, effect) {
 if (source != effect.value) {
@@ -1544,20 +1552,23 @@
 if (args) {
 fn.apply(this, args);
 }
+} else if (effect.dynamicFn) {
 } else {
 this._warn(this._logf('_complexObserverEffect', 'observer method `' + effect.method + '` not defined'));
 }
 },
 _computeEffect: function (source, value, effect) {
-var args = Polymer.Bind._marshalArgs(this.__data__, effect, source, value);
-if (args) {
 var fn = this[effect.method];
 if (fn) {
-this.__setProperty(effect.name, fn.apply(this, args));
+var args = Polymer.Bind._marshalArgs(this.__data__, effect, source, value);
+if (args) {
+var computedvalue = fn.apply(this, args);
+this.__setProperty(effect.name, computedvalue);
+}
+} else if (effect.dynamicFn) {
 } else {
 this._warn(this._logf('_computeEffect', 'compute method `' + effect.method + '` not defined'));
 }
-}
 },
 _annotatedComputationEffect: function (source, value, effect) {
 var computedHost = this._rootDataHost || this;
@@ -1571,6 +1582,7 @@
 }
 this._applyEffectValue(effect, computedvalue);
 }
+} else if (effect.dynamicFn) {
 } else {
 computedHost._warn(computedHost._logf('_annotatedComputationEffect', 'compute method `' + effect.method + '` not defined'));
 }
@@ -1578,6 +1590,7 @@
 _marshalArgs: function (model, effect, path, value) {
 var values = [];
 var args = effect.args;
+var bailoutEarly = args.length > 1 || effect.dynamicFn;
 for (var i = 0, l = args.length; i < l; i++) {
 var arg = args[i];
 var name = arg.name;
@@ -1589,7 +1602,7 @@
 } else {
 v = model[name];
 }
-if (args.length > 1 && v === undefined) {
+if (bailoutEarly && v === undefined) {
 return;
 }
 if (arg.wildcard) {
@@ -1644,12 +1657,23 @@
 },
 _addComputedEffect: function (name, expression) {
 var sig = this._parseMethod(expression);
+var dynamicFn = sig.dynamicFn;
 for (var i = 0, arg; i < sig.args.length && (arg = sig.args[i]); i++) {
 this._addPropertyEffect(arg.model, 'compute', {
 method: sig.method,
 args: sig.args,
 trigger: arg,
-name: name
+name: name,
+dynamicFn: dynamicFn
+});
+}
+if (dynamicFn) {
+this._addPropertyEffect(sig.method, 'compute', {
+method: sig.method,
+args: sig.args,
+trigger: null,
+name: name,
+dynamicFn: dynamicFn
 });
 }
 },
@@ -1671,11 +1695,21 @@
 if (!sig) {
 throw new Error('Malformed observer expression \'' + observer + '\'');
 }
+var dynamicFn = sig.dynamicFn;
 for (var i = 0, arg; i < sig.args.length && (arg = sig.args[i]); i++) {
 this._addPropertyEffect(arg.model, 'complexObserver', {
 method: sig.method,
 args: sig.args,
-trigger: arg
+trigger: arg,
+dynamicFn: dynamicFn
+});
+}
+if (dynamicFn) {
+this._addPropertyEffect(sig.method, 'complexObserver', {
+method: sig.method,
+args: sig.args,
+trigger: null,
+dynamicFn: dynamicFn
 });
 }
 },
@@ -1689,7 +1723,7 @@
 },
 _addAnnotationEffect: function (note, index) {
 if (Polymer.Bind._shouldAddListener(note)) {
-Polymer.Bind._addAnnotatedListener(this, index, note.name, note.parts[0].value, note.parts[0].event);
+Polymer.Bind._addAnnotatedListener(this, index, note.name, note.parts[0].value, note.parts[0].event, note.parts[0].negate);
 }
 for (var i = 0; i < note.parts.length; i++) {
 var part = note.parts[i];
@@ -1700,6 +1734,7 @@
 kind: note.kind,
 index: index,
 name: note.name,
+propertyName: note.propertyName,
 value: part.value,
 isCompound: note.isCompound,
 compoundIndex: part.compoundIndex,
@@ -1720,6 +1755,9 @@
 this.__addAnnotatedComputationEffect(arg.model, index, note, part, arg);
 }
 }
+if (sig.dynamicFn) {
+this.__addAnnotatedComputationEffect(sig.method, index, note, part, null);
+}
 }
 },
 __addAnnotatedComputationEffect: function (property, index, note, part, trigger) {
@@ -1732,16 +1770,21 @@
 negate: part.negate,
 method: part.signature.method,
 args: part.signature.args,
-trigger: trigger
+trigger: trigger,
+dynamicFn: part.signature.dynamicFn
 });
 },
 _parseMethod: function (expression) {
-var m = expression.match(/([^\s]+?)\((.*)\)/);
+var m = expression.match(/([^\s]+?)\(([\s\S]*)\)/);
 if (m) {
 var sig = {
 method: m[1],
 static: true
 };
+if (this.getPropertyInfo(sig.method) !== Polymer.nob) {
+sig.static = false;
+sig.dynamicFn = true;
+}
 if (m[2].trim()) {
 var args = m[2].replace(/\\,/g, '&comma;').split(',');
 return this._parseArgs(args, sig);
@@ -1829,6 +1872,8 @@
 }
 }
 });
+(function () {
+var usePolyfillProto = Polymer.Settings.usePolyfillProto;
 Polymer.Base._addFeature({
 _setupConfigure: function (initialConfig) {
 this._config = {};
@@ -1875,7 +1920,10 @@
 _configureProperties: function (properties, config) {
 for (var i in properties) {
 var c = properties[i];
-if (c.value !== undefined) {
+if (!usePolyfillProto && this.hasOwnProperty(i) && this._propertyEffects && this._propertyEffects[i]) {
+config[i] = this[i];
+delete this[i];
+} else if (c.value !== undefined) {
 var value = c.value;
 if (typeof value == 'function') {
 value = value.call(this, this._config);
@@ -1893,9 +1941,15 @@
 for (var i = 0, l = fx.length, x; i < l && (x = fx[i]); i++) {
 if (x.kind === 'annotation' && !x.isCompound) {
 var node = this._nodes[x.effect.index];
-if (node._configValue) {
+var name = x.effect.propertyName;
+var isAttr = x.effect.kind == 'attribute';
+var hasEffect = node._propertyEffects && node._propertyEffects[name];
+if (node._configValue && (hasEffect || !isAttr)) {
 var value = p === x.effect.value ? config[p] : this._get(x.effect.value, config);
-node._configValue(x.effect.name, value);
+if (isAttr) {
+value = node.deserialize(this.serialize(value), node._propertyInfo[name].type);
+}
+node._configValue(name, value);
 }
 }
 }
@@ -1945,6 +1999,7 @@
 this._handlers = [];
 }
 });
+}());
 (function () {
 'use strict';
 Polymer.Base._addFeature({
@@ -2002,14 +2057,15 @@
 }
 if (array) {
 var coll = Polymer.Collection.get(array);
+var old, key;
 if (last[0] == '#') {
-var key = last;
-var old = coll.getItem(key);
+key = last;
+old = coll.getItem(key);
 last = array.indexOf(old);
 coll.setItem(key, value);
 } else if (parseInt(last, 10) == last) {
-var old = prop[last];
-var key = coll.getKey(old);
+old = prop[last];
+key = coll.getKey(old);
 parts[i] = key;
 coll.setItem(key, value);
 }
@@ -2190,7 +2246,7 @@
 }
 return ret;
 },
-splice: function (path, start, deleteCount) {
+splice: function (path, start) {
 var info = {};
 var array = this._get(path, this, info);
 if (start < 0) {
@@ -2318,6 +2374,7 @@
 node.type = this.types.MEDIA_RULE;
 } else if (s.match(this._rx.keyframesRule)) {
 node.type = this.types.KEYFRAMES_RULE;
+node.keyframesName = node.selector.split(this._rx.multipleSpaces).pop();
 }
 } else {
 if (s.indexOf(this.VAR_START) === 0) {
@@ -2416,14 +2473,14 @@
 rules = this.parser.parse(rules);
 }
 if (callback) {
-this.forEachStyleRule(rules, callback);
+this.forEachRule(rules, callback);
 }
 return this.parser.stringify(rules, preserveProperties);
 },
-forRulesInStyles: function (styles, callback) {
+forRulesInStyles: function (styles, styleRuleCallback, keyframesRuleCallback) {
 if (styles) {
 for (var i = 0, l = styles.length, s; i < l && (s = styles[i]); i++) {
-this.forEachStyleRule(this.rulesForStyle(s), callback);
+this.forEachRule(this.rulesForStyle(s), styleRuleCallback, keyframesRuleCallback);
 }
 }
 },
@@ -2433,20 +2490,25 @@
 }
 return style.__cssRules;
 },
-forEachStyleRule: function (node, callback) {
+isKeyframesSelector: function (rule) {
+return rule.parent && rule.parent.type === this.ruleTypes.KEYFRAMES_RULE;
+},
+forEachRule: function (node, styleRuleCallback, keyframesRuleCallback) {
 if (!node) {
 return;
 }
 var skipRules = false;
 if (node.type === this.ruleTypes.STYLE_RULE) {
-callback(node);
-} else if (node.type === this.ruleTypes.KEYFRAMES_RULE || node.type === this.ruleTypes.MIXIN_RULE) {
+styleRuleCallback(node);
+} else if (keyframesRuleCallback && node.type === this.ruleTypes.KEYFRAMES_RULE) {
+keyframesRuleCallback(node);
+} else if (node.type === this.ruleTypes.MIXIN_RULE) {
 skipRules = true;
 }
 var r$ = node.rules;
 if (r$ && !skipRules) {
 for (var i = 0, l = r$.length, r; i < l && (r = r$[i]); i++) {
-this.forEachStyleRule(r, callback);
+this.forEachRule(r, styleRuleCallback, keyframesRuleCallback);
 }
 }
 },
@@ -2595,15 +2657,18 @@
 },
 _transformRule: function (rule, transformer, scope, hostScope) {
 var p$ = rule.selector.split(COMPLEX_SELECTOR_SEP);
+if (!styleUtil.isKeyframesSelector(rule)) {
 for (var i = 0, l = p$.length, p; i < l && (p = p$[i]); i++) {
 p$[i] = transformer.call(this, p, scope, hostScope);
 }
+}
 rule.selector = rule.transformedSelector = p$.join(COMPLEX_SELECTOR_SEP);
 },
 _transformComplexSelector: function (selector, scope, hostScope) {
 var stop = false;
 var hostContext = false;
 var self = this;
+selector = selector.replace(CONTENT_START, HOST + ' $1');
 selector = selector.replace(SIMPLE_SELECTOR_SEP, function (m, c, s) {
 if (!stop) {
 var info = self._transformCompoundSelector(s, c, scope, hostScope);
@@ -2676,10 +2741,10 @@
 var SCOPE_NAME = api.SCOPE_NAME;
 var SCOPE_DOC_SELECTOR = ':not([' + SCOPE_NAME + '])' + ':not(.' + SCOPE_NAME + ')';
 var COMPLEX_SELECTOR_SEP = ',';
-var SIMPLE_SELECTOR_SEP = /(^|[\s>+~]+)([^\s>+~]+)/g;
+var SIMPLE_SELECTOR_SEP = /(^|[\s>+~]+)((?:\[.+?\]|[^\s>+~=\[])+)/g;
 var HOST = ':host';
 var ROOT = ':root';
-var HOST_PAREN = /(\:host)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))/g;
+var HOST_PAREN = /(:host)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))/g;
 var HOST_CONTEXT = ':host-context';
 var HOST_CONTEXT_PAREN = /(.*)(?::host-context)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))(.*)/;
 var CONTENT = '::content';
@@ -2689,6 +2754,7 @@
 var CSS_ATTR_SUFFIX = ']';
 var PSEUDO_PREFIX = ':';
 var CLASS = 'class';
+var CONTENT_START = new RegExp('^(' + CONTENT + ')');
 return api;
 }();
 Polymer.StyleExtends = function () {
@@ -2700,8 +2766,8 @@
 transform: function (style) {
 var rules = styleUtil.rulesForStyle(style);
 var self = this;
-styleUtil.forEachStyleRule(rules, function (rule) {
-var map = self._mapRule(rule);
+styleUtil.forEachRule(rules, function (rule) {
+self._mapRuleOntoParent(rule);
 if (rule.parent) {
 var m;
 while (m = self.rx.EXTEND.exec(rule.cssText)) {
@@ -2720,7 +2786,7 @@
 }
 }, true);
 },
-_mapRule: function (rule) {
+_mapRuleOntoParent: function (rule) {
 if (rule.parent) {
 var map = rule.parent.map || (rule.parent.map = {});
 var parts = rule.selector.split(',');
@@ -2782,7 +2848,10 @@
 if (this._template) {
 this._styles = this._collectStyles();
 var cssText = styleTransformer.elementStyles(this);
-if (cssText) {
+this._prepStyleProperties();
+var needsStatic = this._styles.length && !this._needsStyleProperties();
+if (needsStatic || !nativeShadow) {
+cssText = needsStatic ? cssText : ' ';
 var style = styleUtil.applyCss(cssText, this.is, nativeShadow ? this._template.content : null);
 if (!nativeShadow) {
 this._scopeStyle = style;
@@ -2873,11 +2942,14 @@
 var styleTransformer = Polymer.StyleTransformer;
 return {
 decorateStyles: function (styles) {
-var self = this, props = {};
+var self = this, props = {}, keyframes = [];
 styleUtil.forRulesInStyles(styles, function (rule) {
 self.decorateRule(rule);
 self.collectPropertiesInCssText(rule.propertyInfo.cssText, props);
+}, function onKeyframesRule(rule) {
+keyframes.push(rule);
 });
+styles._keyframes = keyframes;
 var names = [];
 for (var i in props) {
 names.push(i);
@@ -2917,17 +2989,10 @@
 }
 },
 collectCssText: function (rule) {
-var customCssText = '';
-var cssText = rule.parsedCssText;
-cssText = cssText.replace(this.rx.BRACKETED, '').replace(this.rx.VAR_ASSIGN, '');
-var parts = cssText.split(';');
-for (var i = 0, p; i < parts.length; i++) {
-p = parts[i];
-if (p.match(this.rx.MIXIN_MATCH) || p.match(this.rx.VAR_MATCH)) {
-customCssText += p + ';\n';
-}
-}
-return customCssText;
+return this.collectConsumingCssText(rule.parsedCssText);
+},
+collectConsumingCssText: function (cssText) {
+return cssText.replace(this.rx.BRACKETED, '').replace(this.rx.VAR_ASSIGN, '');
 },
 collectPropertiesInCssText: function (cssText, props) {
 var m;
@@ -2969,12 +3034,13 @@
 if (m) {
 p = this.valueForProperty(props[m[1]], props);
 } else {
-var pp = p.split(':');
-if (pp[1]) {
-pp[1] = pp[1].trim();
-pp[1] = this.valueForProperty(pp[1], props) || pp[1];
+var colon = p.indexOf(':');
+if (colon !== -1) {
+var pp = p.substring(colon);
+pp = pp.trim();
+pp = this.valueForProperty(pp, props) || pp;
+p = p.substring(0, colon) + pp;
 }
-p = pp.join(':');
 }
 parts[i] = p && p.lastIndexOf(';') === p.length - 1 ? p.slice(0, -1) : p || '';
 }
@@ -2991,6 +3057,34 @@
 }
 rule.cssText = output;
 },
+applyKeyframeTransforms: function (rule, keyframeTransforms) {
+var input = rule.cssText;
+var output = rule.cssText;
+if (rule.hasAnimations == null) {
+rule.hasAnimations = this.rx.ANIMATION_MATCH.test(input);
+}
+if (rule.hasAnimations) {
+var transform;
+if (rule.keyframeNamesToTransform == null) {
+rule.keyframeNamesToTransform = [];
+for (var keyframe in keyframeTransforms) {
+transform = keyframeTransforms[keyframe];
+output = transform(input);
+if (input !== output) {
+input = output;
+rule.keyframeNamesToTransform.push(keyframe);
+}
+}
+} else {
+for (var i = 0; i < rule.keyframeNamesToTransform.length; ++i) {
+transform = keyframeTransforms[rule.keyframeNamesToTransform[i]];
+input = transform(input);
+}
+output = input;
+}
+}
+rule.cssText = output;
+},
 propertyDataFromStyles: function (styles, element) {
 var props = {}, self = this;
 var o = [], i = 0;
@@ -3041,20 +3135,44 @@
 var hostSelector = styleTransformer._calcHostScope(element.is, element.extends);
 var rxHostSelector = element.extends ? '\\' + hostSelector.slice(0, -1) + '\\]' : hostSelector;
 var hostRx = new RegExp(this.rx.HOST_PREFIX + rxHostSelector + this.rx.HOST_SUFFIX);
+var keyframeTransforms = this._elementKeyframeTransforms(element, scopeSelector);
 return styleTransformer.elementStyles(element, function (rule) {
 self.applyProperties(rule, properties);
-if (rule.cssText && !nativeShadow) {
+if (!nativeShadow && !Polymer.StyleUtil.isKeyframesSelector(rule) && rule.cssText) {
+self.applyKeyframeTransforms(rule, keyframeTransforms);
 self._scopeSelector(rule, hostRx, hostSelector, element._scopeCssViaAttr, scopeSelector);
 }
 });
 },
+_elementKeyframeTransforms: function (element, scopeSelector) {
+var keyframesRules = element._styles._keyframes;
+var keyframeTransforms = {};
+if (!nativeShadow && keyframesRules) {
+for (var i = 0, keyframesRule = keyframesRules[i]; i < keyframesRules.length; keyframesRule = keyframesRules[++i]) {
+this._scopeKeyframes(keyframesRule, scopeSelector);
+keyframeTransforms[keyframesRule.keyframesName] = this._keyframesRuleTransformer(keyframesRule);
+}
+}
+return keyframeTransforms;
+},
+_keyframesRuleTransformer: function (keyframesRule) {
+return function (cssText) {
+return cssText.replace(keyframesRule.keyframesNameRx, keyframesRule.transformedKeyframesName);
+};
+},
+_scopeKeyframes: function (rule, scopeId) {
+rule.keyframesNameRx = new RegExp(rule.keyframesName, 'g');
+rule.transformedKeyframesName = rule.keyframesName + '-' + scopeId;
+rule.transformedSelector = rule.transformedSelector || rule.selector;
+rule.selector = rule.transformedSelector.replace(rule.keyframesName, rule.transformedKeyframesName);
+},
 _scopeSelector: function (rule, hostRx, hostSelector, viaAttr, scopeId) {
 rule.transformedSelector = rule.transformedSelector || rule.selector;
 var selector = rule.transformedSelector;
 var scope = viaAttr ? '[' + styleTransformer.SCOPE_NAME + '~=' + scopeId + ']' : '.' + scopeId;
 var parts = selector.split(',');
 for (var i = 0, l = parts.length, p; i < l && (p = parts[i]); i++) {
-parts[i] = p.match(hostRx) ? p.replace(hostSelector, hostSelector + scope) : scope + ' ' + p;
+parts[i] = p.match(hostRx) ? p.replace(hostSelector, scope) : scope + ' ' + p;
 }
 rule.selector = parts.join(',');
 },
@@ -3107,8 +3225,9 @@
 rx: {
 VAR_ASSIGN: /(?:^|[;\s{]\s*)(--[\w-]*?)\s*:\s*(?:([^;{]*)|{([^}]*)})(?:(?=[;\s}])|$)/gi,
 MIXIN_MATCH: /(?:^|\W+)@apply[\s]*\(([^)]*)\)/i,
-VAR_MATCH: /(^|\W+)var\([\s]*([^,)]*)[\s]*,?[\s]*((?:[^,)]*)|(?:[^;]*\([^;)]*\)))[\s]*?\)/gi,
+VAR_MATCH: /(^|\W+)var\([\s]*([^,)]*)[\s]*,?[\s]*((?:[^,()]*)|(?:[^;()]*\([^;)]*\)))[\s]*?\)/gi,
 VAR_CAPTURE: /\([\s]*(--[^,\s)]*)(?:,[\s]*(--[^,\s)]*))?(?:\)|,)/gi,
+ANIMATION_MATCH: /(animation\s*:)|(animation-name\s*:)/,
 IS_VAR: /^--/,
 BRACKETED: /\{[^}]*\}/g,
 HOST_PREFIX: '(?:^|[^.#[:])',
@@ -3173,7 +3292,6 @@
 }());
 Polymer.StyleDefaults = function () {
 var styleProperties = Polymer.StyleProperties;
-var styleUtil = Polymer.StyleUtil;
 var StyleCache = Polymer.StyleCache;
 var api = {
 _styles: [],
@@ -3219,12 +3337,11 @@
 var serializeValueToAttribute = Polymer.Base.serializeValueToAttribute;
 var propertyUtils = Polymer.StyleProperties;
 var styleTransformer = Polymer.StyleTransformer;
-var styleUtil = Polymer.StyleUtil;
 var styleDefaults = Polymer.StyleDefaults;
 var nativeShadow = Polymer.Settings.useNativeShadow;
 Polymer.Base._addFeature({
 _prepStyleProperties: function () {
-this._ownStylePropertyNames = this._styles ? propertyUtils.decorateStyles(this._styles) : null;
+this._ownStylePropertyNames = this._styles && this._styles.length ? propertyUtils.decorateStyles(this._styles) : null;
 },
 customStyle: null,
 getComputedStyleValue: function (property) {
@@ -3336,7 +3453,7 @@
 },
 _scopeElementClass: function (element, selector) {
 if (!nativeShadow && !this._scopeCssViaAttr) {
-selector += (selector ? ' ' : '') + SCOPE_NAME + ' ' + this.is + (element._scopeSelector ? ' ' + XSCOPE_NAME + ' ' + element._scopeSelector : '');
+selector = (selector ? selector + ' ' : '') + SCOPE_NAME + ' ' + this.is + (element._scopeSelector ? ' ' + XSCOPE_NAME + ' ' + element._scopeSelector : '');
 }
 return selector;
 },
@@ -3383,7 +3500,6 @@
 this._prepConstructor();
 this._prepTemplate();
 this._prepStyles();
-this._prepStyleProperties();
 this._prepAnnotations();
 this._prepEffects();
 this._prepBehaviors();
@@ -3423,7 +3539,6 @@
 }
 });
 (function () {
-var nativeShadow = Polymer.Settings.useNativeShadow;
 var propertyUtils = Polymer.StyleProperties;
 var styleUtil = Polymer.StyleUtil;
 var cssParse = Polymer.CssParse;
@@ -3465,7 +3580,7 @@
 e.textContent = styleUtil.cssFromModules(this.include, true) + e.textContent;
 }
 if (e.textContent) {
-styleUtil.forEachStyleRule(styleUtil.rulesForStyle(e), function (rule) {
+styleUtil.forEachRule(styleUtil.rulesForStyle(e), function (rule) {
 styleTransformer.documentRule(rule);
 });
 var self = this;
@@ -3570,7 +3685,7 @@
 _debounceTemplate: function (fn) {
 Polymer.dom.addDebouncer(this.debounce('_debounceTemplate', fn));
 },
-_flushTemplates: function (debouncerExpired) {
+_flushTemplates: function () {
 Polymer.dom.flush();
 },
 _customPrepEffects: function (archetype) {
@@ -3578,7 +3693,7 @@
 for (var prop in parentProps) {
 archetype._addPropertyEffect(prop, 'function', this._createHostPropEffector(prop));
 }
-for (var prop in this._instanceProps) {
+for (prop in this._instanceProps) {
 archetype._addPropertyEffect(prop, 'function', this._createInstancePropEffector(prop));
 }
 },
@@ -3663,6 +3778,9 @@
 },
 _extendTemplate: function (template, proto) {
 var n$ = Object.getOwnPropertyNames(proto);
+if (proto._propertySetter) {
+template._propertySetter = proto._propertySetter;
+}
 for (var i = 0, n; i < n$.length && (n = n$[i]); i++) {
 var val = template[n];
 var pd = Object.getOwnPropertyDescriptor(proto, n);
@@ -3743,9 +3861,11 @@
 if (this._parentProps) {
 var templatized = this._templatized;
 for (var prop in this._parentProps) {
+if (model[prop] === undefined) {
 model[prop] = templatized[this._parentPropPrefix + prop];
 }
 }
+}
 return new this.ctor(model, this);
 },
 modelForElement: function (el) {
@@ -3876,7 +3996,7 @@
 key = this.getKey(s.removed[j]);
 keyMap[key] = keyMap[key] ? null : -1;
 }
-for (var j = 0; j < s.addedCount; j++) {
+for (j = 0; j < s.addedCount; j++) {
 var item = this.userArray[s.index + j];
 key = this.getKey(item);
 key = key === undefined ? this.add(item) : key;
@@ -3886,7 +4006,7 @@
 }
 var removed = [];
 var added = [];
-for (var key in keyMap) {
+for (key in keyMap) {
 if (keyMap[key] < 0) {
 this.removeKey(key);
 removed.push(key);
@@ -4083,7 +4203,6 @@
 this._flushTemplates();
 },
 _render: function () {
-var c = this.collection;
 if (this._needFullRefresh) {
 this._applyFullRefresh();
 this._needFullRefresh = false;
@@ -4144,7 +4263,7 @@
 return self._sortFn(c.getItem(a), c.getItem(b));
 });
 }
-for (var i = 0; i < keys.length; i++) {
+for (i = 0; i < keys.length; i++) {
 var key = keys[i];
 var inst = this._instances[i];
 if (inst) {
@@ -4167,21 +4286,21 @@
 },
 _applySplicesUserSort: function (splices) {
 var c = this.collection;
-var instances = this._instances;
 var keyMap = {};
+var key;
 for (var i = 0, s; i < splices.length && (s = splices[i]); i++) {
 for (var j = 0; j < s.removed.length; j++) {
-var key = s.removed[j];
+key = s.removed[j];
 keyMap[key] = keyMap[key] ? null : -1;
 }
-for (var j = 0; j < s.added.length; j++) {
-var key = s.added[j];
+for (j = 0; j < s.added.length; j++) {
+key = s.added[j];
 keyMap[key] = keyMap[key] ? null : 1;
 }
 }
 var removedIdxs = [];
 var addedKeys = [];
-for (var key in keyMap) {
+for (key in keyMap) {
 if (keyMap[key] === -1) {
 removedIdxs.push(this._keyToInstIdx[key]);
 }
@@ -4191,7 +4310,7 @@
 }
 if (removedIdxs.length) {
 removedIdxs.sort(this._numericSort);
-for (var i = removedIdxs.length - 1; i >= 0; i--) {
+for (i = removedIdxs.length - 1; i >= 0; i--) {
 var idx = removedIdxs[i];
 if (idx !== undefined) {
 this._detachAndRemoveInstance(idx);
@@ -4209,7 +4328,7 @@
 return self._sortFn(c.getItem(a), c.getItem(b));
 });
 var start = 0;
-for (var i = 0; i < addedKeys.length; i++) {
+for (i = 0; i < addedKeys.length; i++) {
 start = this._insertRowUserSort(start, addedKeys[i]);
 }
 }
@@ -4239,12 +4358,11 @@
 return idx;
 },
 _applySplicesArrayOrder: function (splices) {
-var c = this.collection;
 for (var i = 0, s; i < splices.length && (s = splices[i]); i++) {
 for (var j = 0; j < s.removed.length; j++) {
 this._detachAndRemoveInstance(s.index);
 }
-for (var j = 0; j < s.addedKeys.length; j++) {
+for (j = 0; j < s.addedKeys.length; j++) {
 this._insertPlaceholder(s.index + j, s.addedKeys[j]);
 }
 }
@@ -4577,8 +4695,14 @@
 created: function () {
 var self = this;
 Polymer.RenderStatus.whenReady(function () {
+if (document.readyState == 'loading') {
+document.addEventListener('DOMContentLoaded', function () {
 self._markImportsReady();
 });
+} else {
+self._markImportsReady();
+}
+});
 },
 _ensureReady: function () {
 if (!this._readied) {
diff --git a/third_party/polymer/v1_0/components-chromium/polymer/polymer-micro-extracted.js b/third_party/polymer/v1_0/components-chromium/polymer/polymer-micro-extracted.js
index 10e3bd0..c47dc58a7 100644
--- a/third_party/polymer/v1_0/components-chromium/polymer/polymer-micro-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/polymer/polymer-micro-extracted.js
@@ -27,6 +27,7 @@
 var hasNativeImports = Boolean('import' in document.createElement('link'));
 var useNativeImports = hasNativeImports;
 var useNativeCustomElements = !window.CustomElements || window.CustomElements.useNative;
+var usePolyfillProto = !useNativeCustomElements && !Object.__proto__;
 return {
 wantShadow: wantShadow,
 hasShadow: hasShadow,
@@ -34,7 +35,8 @@
 useShadow: useShadow,
 useNativeShadow: useShadow && nativeShadow,
 useNativeImports: useNativeImports,
-useNativeCustomElements: useNativeCustomElements
+useNativeCustomElements: useNativeCustomElements,
+usePolyfillProto: usePolyfillProto
 };
 }()
 };
@@ -66,7 +68,6 @@
 prototype.registerCallback();
 return prototype.constructor;
 };
-window.Polymer = Polymer;
 if (userPolymer) {
 for (var i in userPolymer) {
 Polymer[i] = userPolymer[i];
@@ -152,7 +153,6 @@
 h = callbacks[i];
 h[1].apply(h[0], h[2] || Polymer.nar);
 }
-;
 }
 };
 if (window.HTMLImports) {
@@ -275,7 +275,7 @@
 this.register();
 },
 register: function (id) {
-var id = id || this.id || this.getAttribute('name') || this.getAttribute('is');
+id = id || this.id || this.getAttribute('name') || this.getAttribute('is');
 if (id) {
 this.id = id;
 modules[id] = this;
@@ -335,11 +335,16 @@
 }
 },
 _desugarSomeBehaviors: function (behaviors) {
+var behaviorSet = [];
 behaviors = this._flattenBehaviorsList(behaviors);
 for (var i = behaviors.length - 1; i >= 0; i--) {
-this._mixinBehavior(behaviors[i]);
+var b = behaviors[i];
+if (behaviorSet.indexOf(b) === -1) {
+this._mixinBehavior(b);
+behaviorSet.unshift(b);
 }
-return behaviors;
+}
+return behaviorSet;
 },
 _flattenBehaviorsList: function (behaviors) {
 var flat = [];
@@ -461,7 +466,6 @@
 return info;
 }
 }
-;
 }
 return info || Polymer.nob;
 },
@@ -477,7 +481,7 @@
 },
 _prepPropertyInfo: function () {
 this._propertyInfo = {};
-for (var i = 0, p; i < this.behaviors.length; i++) {
+for (var i = 0; i < this.behaviors.length; i++) {
 this._addPropertyInfo(this._propertyInfo, this.behaviors[i].properties);
 }
 this._addPropertyInfo(this._propertyInfo, this.properties);
@@ -512,26 +516,17 @@
 });
 Polymer.CaseMap = {
 _caseMap: {},
+_rx: {
+dashToCamel: /-[a-z]/g,
+camelToDash: /([A-Z])/g
+},
 dashToCamelCase: function (dash) {
-var mapped = Polymer.CaseMap._caseMap[dash];
-if (mapped) {
-return mapped;
-}
-if (dash.indexOf('-') < 0) {
-return Polymer.CaseMap._caseMap[dash] = dash;
-}
-return Polymer.CaseMap._caseMap[dash] = dash.replace(/-([a-z])/g, function (m) {
+return this._caseMap[dash] || (this._caseMap[dash] = dash.indexOf('-') < 0 ? dash : dash.replace(this._rx.dashToCamel, function (m) {
 return m[1].toUpperCase();
-});
+}));
 },
 camelToDashCase: function (camel) {
-var mapped = Polymer.CaseMap._caseMap[camel];
-if (mapped) {
-return mapped;
-}
-return Polymer.CaseMap._caseMap[camel] = camel.replace(/([a-z][A-Z])/g, function (g) {
-return g[0] + '-' + g[1].toLowerCase();
-});
+return this._caseMap[camel] || (this._caseMap[camel] = camel.replace(this._rx.camelToDash, '-$1').toLowerCase());
 }
 };
 Polymer.Base._addFeature({
@@ -571,7 +566,7 @@
 },
 _setAttributeToProperty: function (model, attribute, property, info) {
 if (!this._serializing) {
-var property = property || Polymer.CaseMap.dashToCamelCase(attribute);
+property = property || Polymer.CaseMap.dashToCamelCase(attribute);
 info = info || this._propertyInfo && this._propertyInfo[property];
 if (info && !info.readOnly) {
 var v = this.getAttribute(attribute);
@@ -601,7 +596,7 @@
 value = Number(value);
 break;
 case Boolean:
-value = value !== null;
+value = value != null;
 break;
 case Object:
 try {
@@ -632,7 +627,7 @@
 return value ? '' : undefined;
 case 'object':
 if (value instanceof Date) {
-return value;
+return value.toString();
 } else if (value) {
 try {
 return JSON.stringify(value);
@@ -645,7 +640,7 @@
 }
 }
 });
-Polymer.version = '1.2.4';
+Polymer.version = '1.3.1';
 Polymer.Base._addFeature({
 _registerFeatures: function () {
 this._prepIs();
diff --git a/third_party/polymer/v1_0/components-chromium/polymer/polymer-mini-extracted.js b/third_party/polymer/v1_0/components-chromium/polymer/polymer-mini-extracted.js
index 2ad2385..1bb9c02 100644
--- a/third_party/polymer/v1_0/components-chromium/polymer/polymer-mini-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/polymer/polymer-mini-extracted.js
@@ -122,8 +122,8 @@
 }
 for (var j = 0; j < columnCount; j++)
 distances[0][j] = j;
-for (var i = 1; i < rowCount; i++) {
-for (var j = 1; j < columnCount; j++) {
+for (i = 1; i < rowCount; i++) {
+for (j = 1; j < columnCount; j++) {
 if (this.equals(current[currentStart + j - 1], old[oldStart + i - 1]))
 distances[i][j] = distances[i - 1][j - 1];
 else {
@@ -203,7 +203,7 @@
 } else if (oldStart == oldEnd)
 return [newSplice(currentStart, [], currentEnd - currentStart)];
 var ops = this.spliceOperationsFromEditDistances(this.calcEditDistances(current, currentStart, currentEnd, old, oldStart, oldEnd));
-var splice = undefined;
+splice = undefined;
 var splices = [];
 var index = currentStart;
 var oldIndex = oldStart;
@@ -369,7 +369,7 @@
 var nativeInsertBefore = Element.prototype.insertBefore;
 var nativeAppendChild = Element.prototype.appendChild;
 var nativeRemoveChild = Element.prototype.removeChild;
-var TreeApi = Polymer.TreeApi = {
+Polymer.TreeApi = {
 arrayCopyChildNodes: function (parent) {
 var copy = [], i = 0;
 for (var n = parent.firstChild; n; n = n.nextSibling) {
@@ -1426,7 +1426,6 @@
 'use strict';
 var DomApi = Polymer.DomApi.ctor;
 var Settings = Polymer.Settings;
-var hasDomApi = Polymer.DomApi.hasDomApi;
 DomApi.EffectiveNodesObserver = function (domApi) {
 this.domApi = domApi;
 this.node = this.domApi.node;
@@ -1479,7 +1478,7 @@
 this._scheduleNotify();
 }
 },
-_notify: function (mxns) {
+_notify: function () {
 this._beforeCallListeners();
 this._callListeners();
 },
@@ -1550,8 +1549,8 @@
 info.removedNodes.push(n);
 }
 }
-for (var i = 0, s; i < splices.length && (s = splices[i]); i++) {
-for (var j = s.index; j < s.index + s.addedCount; j++) {
+for (i = 0, s; i < splices.length && (s = splices[i]); i++) {
+for (j = s.index; j < s.index + s.addedCount; j++) {
 info.addedNodes.push(newNodes[j]);
 }
 }
@@ -1569,7 +1568,6 @@
 if (Settings.useShadow) {
 var baseSetup = DomApi.EffectiveNodesObserver.prototype._setup;
 var baseCleanup = DomApi.EffectiveNodesObserver.prototype._cleanup;
-var beforeCallListeners = DomApi.EffectiveNodesObserver.prototype._beforeCallListeners;
 Polymer.Base.extend(DomApi.EffectiveNodesObserver.prototype, {
 _setup: function () {
 if (!this._observer) {
@@ -1884,7 +1882,7 @@
 }
 for (var i = 0, s, next; i < splices.length && (s = splices[i]); i++) {
 next = composed[s.index];
-for (var j = s.index, n; j < s.index + s.addedCount; j++) {
+for (j = s.index, n; j < s.index + s.addedCount; j++) {
 n = children[j];
 TreeApi.Composed.insertBefore(container, n, next);
 composed.splice(j, 0, n);
diff --git a/third_party/polymer/v1_0/components_summary.txt b/third_party/polymer/v1_0/components_summary.txt
index 3560018..bba98eb8 100644
--- a/third_party/polymer/v1_0/components_summary.txt
+++ b/third_party/polymer/v1_0/components_summary.txt
@@ -20,18 +20,18 @@
 Tree link: https://github.com/PolymerElements/iron-a11y-keys-behavior/tree/v1.1.1
 
 Name: iron-autogrow-textarea
-Version: 1.0.10
+Version: 1.0.12
 Repository: git://github.com/PolymerElements/iron-autogrow-textarea.git
-Tag: v1.0.10
-Revision: 1ba4f97e250dc14e9638d95be582dd62b9083736
-Tree link: https://github.com/PolymerElements/iron-autogrow-textarea/tree/v1.0.10
+Tag: v1.0.12
+Revision: 86f8fd61b412bcea6bc7b8feaee9b24bc2ad48ea
+Tree link: https://github.com/PolymerElements/iron-autogrow-textarea/tree/v1.0.12
 
 Name: iron-behaviors
-Version: 1.0.12
+Version: 1.0.13
 Repository: git://github.com/PolymerElements/iron-behaviors.git
-Tag: v1.0.12
-Revision: 657f526a2382a659cdf4e13be87ecc89261588a3
-Tree link: https://github.com/PolymerElements/iron-behaviors/tree/v1.0.12
+Tag: v1.0.13
+Revision: a7bc3428a6da2beed21987b3a8028206826a12bc
+Tree link: https://github.com/PolymerElements/iron-behaviors/tree/v1.0.13
 
 Name: iron-checked-element-behavior
 Version: 1.0.4
@@ -55,18 +55,18 @@
 Tree link: https://github.com/PolymerElements/iron-dropdown/tree/v1.2.0
 
 Name: iron-fit-behavior
-Version: 1.0.5
+Version: 1.0.6
 Repository: git://github.com/PolymerElements/iron-fit-behavior.git
-Tag: v1.0.5
-Revision: 18dec1eb5c7217be4d360c0fb9101fe899136f92
-Tree link: https://github.com/PolymerElements/iron-fit-behavior/tree/v1.0.5
+Tag: v1.0.6
+Revision: f2e868af4fad643ffb7fea3501e1429acc4ec0f0
+Tree link: https://github.com/PolymerElements/iron-fit-behavior/tree/v1.0.6
 
 Name: iron-flex-layout
-Version: 1.2.2
+Version: 1.3.0
 Repository: git://github.com/PolymerElements/iron-flex-layout.git
-Tag: v1.2.2
-Revision: 41c4f35be1368afb770312b907a258175565dbdf
-Tree link: https://github.com/PolymerElements/iron-flex-layout/tree/v1.2.2
+Tag: v1.3.0
+Revision: 434224c8cf63cb4bb1b66edb0dc58e4484f7c5b2
+Tree link: https://github.com/PolymerElements/iron-flex-layout/tree/v1.3.0
 
 Name: iron-form-element-behavior
 Version: 1.0.6
@@ -76,11 +76,11 @@
 Tree link: https://github.com/PolymerElements/iron-form-element-behavior/tree/v1.0.6
 
 Name: iron-icon
-Version: 1.0.7
+Version: 1.0.8
 Repository: git://github.com/PolymerElements/iron-icon.git
-Tag: v1.0.7
-Revision: 6f4d152dc3998a6cc12a5a585a654f893dc99381
-Tree link: https://github.com/PolymerElements/iron-icon/tree/v1.0.7
+Tag: v1.0.8
+Revision: f36b38928849ef3853db727faa8c9ef104d611eb
+Tree link: https://github.com/PolymerElements/iron-icon/tree/v1.0.8
 
 Name: iron-icons
 Version: 1.1.3
@@ -111,11 +111,11 @@
 Tree link: https://github.com/PolymerElements/iron-input/tree/1.0.8
 
 Name: iron-list
-Version: 1.2.3
+Version: 1.2.7
 Repository: git://github.com/PolymerElements/iron-list.git
-Tag: v1.2.3
-Revision: 07957dc10616341606ae030d78bb41492fb7c0cc
-Tree link: https://github.com/PolymerElements/iron-list/tree/v1.2.3
+Tag: v1.2.7
+Revision: 3de2382811553456af4cc8fc9772dac9fbdff41b
+Tree link: https://github.com/PolymerElements/iron-list/tree/v1.2.7
 
 Name: iron-media-query
 Version: 1.0.8
@@ -125,11 +125,11 @@
 Tree link: https://github.com/PolymerElements/iron-media-query/tree/v1.0.8
 
 Name: iron-menu-behavior
-Version: 1.1.0
+Version: 1.1.4
 Repository: git://github.com/PolymerElements/iron-menu-behavior.git
-Tag: v1.1.0
-Revision: b18d5478f1d4d6befb15533716d60d5772f8e812
-Tree link: https://github.com/PolymerElements/iron-menu-behavior/tree/v1.1.0
+Tag: v1.1.4
+Revision: 637c4ae4654b53d4ca29ba97239c1ffba13cfc93
+Tree link: https://github.com/PolymerElements/iron-menu-behavior/tree/v1.1.4
 
 Name: iron-meta
 Version: 1.1.1
@@ -139,17 +139,17 @@
 Tree link: https://github.com/PolymerElements/iron-meta/tree/v1.1.1
 
 Name: iron-overlay-behavior
-Version: 1.3.0
+Version: 1.4.1
 Repository: git://github.com/PolymerElements/iron-overlay-behavior.git
-Tag: v1.3.0
-Revision: b488ce94ec1c17c3a5491af1a2fba2f7382684da
-Tree link: https://github.com/PolymerElements/iron-overlay-behavior/tree/v1.3.0
+Tag: v1.4.1
+Revision: 4aefb7bc41aecef69022d6435133c430fc52d3ba
+Tree link: https://github.com/PolymerElements/iron-overlay-behavior/tree/v1.4.1
 
 Name: iron-pages
 Version: 1.0.7
 Repository: git://github.com/PolymerElements/iron-pages.git
 Tag: v1.0.7
-Revision: 395e253134488b1cab13072890ca5a7eb1b0fd54
+Revision: 357acb8508da5093b22887a85cb785919c20cfde
 Tree link: https://github.com/PolymerElements/iron-pages/tree/v1.0.7
 
 Name: iron-range-behavior
@@ -160,32 +160,32 @@
 Tree link: https://github.com/PolymerElements/iron-range-behavior/tree/v1.0.4
 
 Name: iron-resizable-behavior
-Version: 1.0.2
+Version: 1.0.3
 Repository: git://github.com/PolymerElements/iron-resizable-behavior.git
-Tag: v1.0.2
-Revision: 85de8ba28be2bf17c81d6436ef1119022b003674
-Tree link: https://github.com/PolymerElements/iron-resizable-behavior/tree/v1.0.2
+Tag: v1.0.3
+Revision: dda1df6aaf452aedf3e52ff0cf69e72439452216
+Tree link: https://github.com/PolymerElements/iron-resizable-behavior/tree/v1.0.3
 
 Name: iron-scroll-target-behavior
-Version: 1.0.3
+Version: 1.0.4
 Repository: git://github.com/PolymerElements/iron-scroll-target-behavior.git
-Tag: v1.0.3
-Revision: 7ce943d4bc9daf9704174f58a6c5104fe3097986
-Tree link: https://github.com/PolymerElements/iron-scroll-target-behavior/tree/v1.0.3
+Tag: v1.0.4
+Revision: 77870593ace034696a83e0190914861633196e6d
+Tree link: https://github.com/PolymerElements/iron-scroll-target-behavior/tree/v1.0.4
 
 Name: iron-selector
-Version: 1.2.1
+Version: 1.2.4
 Repository: git://github.com/PolymerElements/iron-selector.git
-Tag: v1.2.1
-Revision: 1e6a7ee05e5ff350472ffc1ee780f145a7606b7b
-Tree link: https://github.com/PolymerElements/iron-selector/tree/v1.2.1
+Tag: v1.2.4
+Revision: 1ee4e2e11a9e5118320987d93fc2c03ae9a489f4
+Tree link: https://github.com/PolymerElements/iron-selector/tree/v1.2.4
 
 Name: iron-test-helpers
-Version: 1.1.3
+Version: 1.1.5
 Repository: git://github.com/PolymerElements/iron-test-helpers.git
-Tag: v1.1.3
-Revision: 51e03645e9a5a7884b5fadc567508e1d730e9174
-Tree link: https://github.com/PolymerElements/iron-test-helpers/tree/v1.1.3
+Tag: v1.1.5
+Revision: 76d7e5b4d52587c853e8b2cbdf8d970bcf209ff3
+Tree link: https://github.com/PolymerElements/iron-test-helpers/tree/v1.1.5
 
 Name: iron-validatable-behavior
 Version: 1.0.5
@@ -223,11 +223,11 @@
 Tree link: https://github.com/PolymerElements/paper-card/tree/v1.1.1
 
 Name: paper-checkbox
-Version: 1.1.1
+Version: 1.1.3
 Repository: git://github.com/PolymerElements/paper-checkbox.git
-Tag: v1.1.1
-Revision: ce52f51c537d27f414fec7298b9ebff4248044eb
-Tree link: https://github.com/PolymerElements/paper-checkbox/tree/v1.1.1
+Tag: v1.1.3
+Revision: b2698fd0d34153e89369f116f306bc8e8203a460
+Tree link: https://github.com/PolymerElements/paper-checkbox/tree/v1.1.3
 
 Name: paper-dialog
 Version: 1.0.4
@@ -237,18 +237,18 @@
 Tree link: https://github.com/PolymerElements/paper-dialog/tree/v1.0.4
 
 Name: paper-dialog-behavior
-Version: 1.1.1
+Version: 1.2.0
 Repository: git://github.com/PolymerElements/paper-dialog-behavior.git
-Tag: v1.1.1
-Revision: 5831039e9f878c63478064abed115c98992b5504
-Tree link: https://github.com/PolymerElements/paper-dialog-behavior/tree/v1.1.1
+Tag: v1.2.0
+Revision: a3be07d2784073d5e9e5175fb7d13f7b1f2a5558
+Tree link: https://github.com/PolymerElements/paper-dialog-behavior/tree/v1.2.0
 
 Name: paper-drawer-panel
-Version: 1.0.6
+Version: 1.0.7
 Repository: git://github.com/PolymerElements/paper-drawer-panel.git
-Tag: v1.0.6
-Revision: 9dd19ef9153ed303a5f8b6d573179cde31b2f5e6
-Tree link: https://github.com/PolymerElements/paper-drawer-panel/tree/v1.0.6
+Tag: v1.0.7
+Revision: 1d791255c062c0c4c4fd9f6f2b2c1ef16b533721
+Tree link: https://github.com/PolymerElements/paper-drawer-panel/tree/v1.0.7
 
 Name: paper-dropdown-menu
 Version: 1.1.3
@@ -258,18 +258,18 @@
 Tree link: https://github.com/PolymerElements/paper-dropdown-menu/tree/v1.1.3
 
 Name: paper-fab
-Version: 1.1.2
+Version: 1.2.0
 Repository: git://github.com/PolymerElements/paper-fab.git
-Tag: v1.1.2
-Revision: 19bf68f79e4ece424bbaf4cfa1c74c62d481c75d
-Tree link: https://github.com/PolymerElements/paper-fab/tree/v1.1.2
+Tag: v1.2.0
+Revision: 691638ca9b922411926b916a592f01a5f25c1af8
+Tree link: https://github.com/PolymerElements/paper-fab/tree/v1.2.0
 
 Name: paper-header-panel
-Version: 1.1.3
+Version: 1.1.4
 Repository: git://github.com/PolymerElements/paper-header-panel.git
-Tag: v1.1.3
-Revision: a36f782c6687aa08ce811f597a495a4f09137c75
-Tree link: https://github.com/PolymerElements/paper-header-panel/tree/v1.1.3
+Tag: v1.1.4
+Revision: 46e0a6218b3f984855dde6e52c2177157801718a
+Tree link: https://github.com/PolymerElements/paper-header-panel/tree/v1.1.4
 
 Name: paper-icon-button
 Version: 1.0.6
@@ -279,18 +279,18 @@
 Tree link: https://github.com/PolymerElements/paper-icon-button/tree/v1.0.6
 
 Name: paper-input
-Version: 1.1.5
+Version: 1.1.8
 Repository: git://github.com/PolymerElements/paper-input.git
-Tag: v1.1.5
-Revision: 0aa8318b5e026688f94c78c7673acabf5bad0f17
-Tree link: https://github.com/PolymerElements/paper-input/tree/v1.1.5
+Tag: v1.1.8
+Revision: 96efaa0f707870d5a5999120467d67b8da806704
+Tree link: https://github.com/PolymerElements/paper-input/tree/v1.1.8
 
 Name: paper-item
-Version: 1.1.3
+Version: 1.1.4
 Repository: git://github.com/PolymerElements/paper-item.git
-Tag: v1.1.3
-Revision: 280c2e703315a6f1f707bec6fd0b1e0b80fee8f4
-Tree link: https://github.com/PolymerElements/paper-item/tree/v1.1.3
+Tag: v1.1.4
+Revision: 5dcf21d5f7c13bafa24122c73aac28bd86213191
+Tree link: https://github.com/PolymerElements/paper-item/tree/v1.1.4
 
 Name: paper-material
 Version: 1.0.6
@@ -321,11 +321,11 @@
 Tree link: https://github.com/PolymerElements/paper-progress/tree/v1.0.8
 
 Name: paper-radio-button
-Version: 1.0.12
+Version: 1.1.1
 Repository: git://github.com/PolymerElements/paper-radio-button.git
-Tag: v1.0.12
-Revision: d7a5a090968c8448d7568208e05fb626fe74ab64
-Tree link: https://github.com/PolymerElements/paper-radio-button/tree/v1.0.12
+Tag: v1.1.1
+Revision: ada62ad3347d304aa72352ea5ef02e2c21907d6c
+Tree link: https://github.com/PolymerElements/paper-radio-button/tree/v1.1.1
 
 Name: paper-radio-group
 Version: 1.0.9
@@ -349,32 +349,32 @@
 Tree link: https://github.com/PolymerElements/paper-slider/tree/v1.0.9
 
 Name: paper-spinner
-Version: 1.1.0
+Version: 1.1.1
 Repository: git://github.com/PolymerElements/paper-spinner.git
-Tag: v1.1.0
-Revision: 66d77a91969b5f2deff4f2363740ccf4a47d423b
-Tree link: https://github.com/PolymerElements/paper-spinner/tree/v1.1.0
+Tag: v1.1.1
+Revision: fa851c605e1b5b79be592979a4650b3061f6342a
+Tree link: https://github.com/PolymerElements/paper-spinner/tree/v1.1.1
 
 Name: paper-styles
-Version: 1.1.3
+Version: 1.1.4
 Repository: git://github.com/PolymerElements/paper-styles.git
-Tag: v1.1.3
-Revision: 6239484bc25ca1f56e7263ac952c63edd8298853
-Tree link: https://github.com/PolymerElements/paper-styles/tree/v1.1.3
+Tag: v1.1.4
+Revision: 885bbd74db88dab4fb5dc229cdf994c55fb2b31b
+Tree link: https://github.com/PolymerElements/paper-styles/tree/v1.1.4
 
 Name: paper-tabs
-Version: 1.3.3
+Version: 1.3.7
 Repository: git://github.com/PolymerElements/paper-tabs.git
-Tag: v1.3.3
-Revision: 4c53ca15663b6f4b13b20a8aab6af8dea5bfc369
-Tree link: https://github.com/PolymerElements/paper-tabs/tree/v1.3.3
+Tag: v1.3.7
+Revision: b8d689c7cdf926a69c91d2421aa6c2536608fad4
+Tree link: https://github.com/PolymerElements/paper-tabs/tree/v1.3.7
 
 Name: paper-toggle-button
-Version: 1.0.14
+Version: 1.1.1
 Repository: git://github.com/PolymerElements/paper-toggle-button.git
-Tag: v1.0.14
-Revision: 131f32adf5ce831f94be7f80c436865b44d7cd95
-Tree link: https://github.com/PolymerElements/paper-toggle-button/tree/v1.0.14
+Tag: v1.1.1
+Revision: 0cfebed00270466462684718ec73b3195179df48
+Tree link: https://github.com/PolymerElements/paper-toggle-button/tree/v1.1.1
 
 Name: paper-toolbar
 Version: 1.1.4
@@ -384,18 +384,18 @@
 Tree link: https://github.com/PolymerElements/paper-toolbar/tree/v1.1.4
 
 Name: paper-tooltip
-Version: 1.1.1
+Version: 1.1.2
 Repository: git://github.com/PolymerElements/paper-tooltip.git
-Tag: v1.1.1
-Revision: 0b274f0ad241877fd316101b43fe48b013a470b6
-Tree link: https://github.com/PolymerElements/paper-tooltip/tree/v1.1.1
+Tag: v1.1.2
+Revision: 6be894127678900f6e506b56fc9622ab768c03aa
+Tree link: https://github.com/PolymerElements/paper-tooltip/tree/v1.1.2
 
 Name: polymer
-Version: 1.2.4
+Version: 1.3.1
 Repository: git://github.com/Polymer/polymer.git
-Tag: v1.2.4
-Revision: 284332a905ddd60eab11901a82ac037976175cf8
-Tree link: https://github.com/Polymer/polymer/tree/v1.2.4
+Tag: v1.3.1
+Revision: 61fac558012d9ef56ea78ed5435de0c418a4afbb
+Tree link: https://github.com/Polymer/polymer/tree/v1.3.1
 
 Name: polymer-externs
 Version: 1.0.16
diff --git a/third_party/sqlite/amalgamation/sqlite3.c b/third_party/sqlite/amalgamation/sqlite3.c
index 1662d81..0d9b5177 100644
--- a/third_party/sqlite/amalgamation/sqlite3.c
+++ b/third_party/sqlite/amalgamation/sqlite3.c
@@ -42289,7 +42289,7 @@
   **   *  Otherwise use separate caches (mode-1)
   */
 #ifdef SQLITE_SEPARATE_CACHE_POOLS
-  const int separateCache = 1;
+  pcache1.separateCache = 1;
 #elif defined(SQLITE_ENABLE_MEMORY_MANAGEMENT)
   pcache1.separateCache = 0;
 #elif SQLITE_THREADSAFE
diff --git a/third_party/sqlite/patches/0002-Use-seperate-page-cache-pools-for-each-sqlite-connec.patch b/third_party/sqlite/patches/0002-Use-seperate-page-cache-pools-for-each-sqlite-connec.patch
index f2e6733..1cb82a6c 100644
--- a/third_party/sqlite/patches/0002-Use-seperate-page-cache-pools-for-each-sqlite-connec.patch
+++ b/third_party/sqlite/patches/0002-Use-seperate-page-cache-pools-for-each-sqlite-connec.patch
@@ -1,7 +1,7 @@
-From d0e21d482f39c92f444957859bc9252dc6bb5239 Mon Sep 17 00:00:00 2001
+From 1a93d36e638db170407cd0cbdaccd30c576ad4c4 Mon Sep 17 00:00:00 2001
 From: rmcilroy <rmcilroy@chromium.org>
 Date: Thu, 20 Jun 2013 22:50:12 +0000
-Subject: [PATCH 02/10] Use seperate page-cache pools for each sqlite
+Subject: [PATCH 02/13] Use seperate page-cache pools for each sqlite
  connection.
 
 Due to multiple different subsystems using sqlite, the shared global page
@@ -16,7 +16,7 @@
  1 file changed, 5 insertions(+), 1 deletion(-)
 
 diff --git a/third_party/sqlite/src/src/pcache1.c b/third_party/sqlite/src/src/pcache1.c
-index 7147f6a..76030f9 100644
+index 7147f6a..940bd62 100644
 --- a/third_party/sqlite/src/src/pcache1.c
 +++ b/third_party/sqlite/src/src/pcache1.c
 @@ -668,6 +668,8 @@ static int pcache1Init(void *NotUsed){
@@ -34,11 +34,11 @@
    */
 -#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT)
 +#ifdef SQLITE_SEPARATE_CACHE_POOLS
-+  const int separateCache = 1;
++  pcache1.separateCache = 1;
 +#elif defined(SQLITE_ENABLE_MEMORY_MANAGEMENT)
    pcache1.separateCache = 0;
  #elif SQLITE_THREADSAFE
    pcache1.separateCache = sqlite3GlobalConfig.pPage==0
 -- 
-2.7.0
+2.7.0.rc3.207.g0ac5344
 
diff --git a/third_party/sqlite/src/src/pcache1.c b/third_party/sqlite/src/src/pcache1.c
index 76030f9d..940bd62 100644
--- a/third_party/sqlite/src/src/pcache1.c
+++ b/third_party/sqlite/src/src/pcache1.c
@@ -680,7 +680,7 @@
   **   *  Otherwise use separate caches (mode-1)
   */
 #ifdef SQLITE_SEPARATE_CACHE_POOLS
-  const int separateCache = 1;
+  pcache1.separateCache = 1;
 #elif defined(SQLITE_ENABLE_MEMORY_MANAGEMENT)
   pcache1.separateCache = 0;
 #elif SQLITE_THREADSAFE
diff --git a/tools/android/BUILD.gn b/tools/android/BUILD.gn
index bcadd0f..99f9a011 100644
--- a/tools/android/BUILD.gn
+++ b/tools/android/BUILD.gn
@@ -79,3 +79,11 @@
     "//tools/android/audio_focus_grabber:audio_focus_grabber_apk",
   ]
 }
+
+# GYP: //tools/android/android_tools.gyp:push_apps_to_background
+group("push_apps_to_background") {
+  testonly = true
+  deps = [
+    "//tools/android/push_apps_to_background:push_apps_to_background_apk",
+  ]
+}
diff --git a/tools/android/android_tools.gyp b/tools/android/android_tools.gyp
index 065c804..3e1589f1 100644
--- a/tools/android/android_tools.gyp
+++ b/tools/android/android_tools.gyp
@@ -85,5 +85,13 @@
         'audio_focus_grabber/audio_focus_grabber.gyp:audio_focus_grabber_apk',
       ],
     },
+    {
+      # GN: //tools/android:push_apps_to_background
+      'target_name': 'push_apps_to_background',
+      'type': 'none',
+      'dependencies': [
+        'push_apps_to_background/push_apps_to_background.gyp:push_apps_to_background_apk',
+      ],
+    },
   ],
 }
diff --git a/tools/android/push_apps_to_background/AndroidManifest.xml b/tools/android/push_apps_to_background/AndroidManifest.xml
new file mode 100644
index 0000000..92753f3
--- /dev/null
+++ b/tools/android/push_apps_to_background/AndroidManifest.xml
@@ -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.
+-->
+
+<manifest
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    package="org.chromium.push_apps_to_background"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" />
+
+    <application
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@android:style/Theme.Light" >
+        <activity
+            android:name="org.chromium.push_apps_to_background.PushAppsToBackgroundActivity"
+            android:label="@string/title_activity_push_apps_to_background"
+            android:exported="true">
+        <intent-filter>
+            <action android:name="android.intent.action.MAIN" />
+            <category android:name="android.intent.category.LAUNCHER" />
+        </intent-filter>
+        </activity>
+    </application>
+</manifest>
\ No newline at end of file
diff --git a/tools/android/push_apps_to_background/BUILD.gn b/tools/android/push_apps_to_background/BUILD.gn
new file mode 100644
index 0000000..cd90aa39
--- /dev/null
+++ b/tools/android/push_apps_to_background/BUILD.gn
@@ -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.
+
+import("//build/config/android/rules.gni")
+import("//testing/test.gni")
+
+# Mark all targets as test only.
+testonly = true
+
+android_apk("push_apps_to_background_apk") {
+  apk_name = "PushAppsToBackground"
+  java_files = [ "src/org/chromium/push_apps_to_background/PushAppsToBackgroundActivity.java" ]
+  android_manifest = "AndroidManifest.xml"
+  deps = [
+    ":push_apps_to_background_apk_resources",
+  ]
+}
+
+android_resources("push_apps_to_background_apk_resources") {
+  resource_dirs = [ "res" ]
+  custom_package = "org.chromium.push_apps_to_background"
+}
diff --git a/tools/android/push_apps_to_background/OWNERS b/tools/android/push_apps_to_background/OWNERS
new file mode 100644
index 0000000..56fcbb89
--- /dev/null
+++ b/tools/android/push_apps_to_background/OWNERS
@@ -0,0 +1,2 @@
+mikecase@chromium.org
+perezju@chromium.org
\ No newline at end of file
diff --git a/tools/android/push_apps_to_background/push_apps_to_background.gyp b/tools/android/push_apps_to_background/push_apps_to_background.gyp
new file mode 100644
index 0000000..25fca1f
--- /dev/null
+++ b/tools/android/push_apps_to_background/push_apps_to_background.gyp
@@ -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.
+{
+  'targets': [
+    # GN: //tools/android/push_apps_to_background:push_apps_to_background_apk
+    {
+      'target_name': 'push_apps_to_background_apk',
+      'type': 'none',
+      'variables': {
+        'apk_name': 'PushAppsToBackground',
+        'java_in_dir': '.',
+        'resource_dir': 'res',
+        'android_manifest_path': 'AndroidManifest.xml',
+      },
+      'includes': [
+        '../../../build/java_apk.gypi',
+      ],
+    },
+  ],
+}
diff --git a/tools/android/push_apps_to_background/res/drawable-mdpi/ic_launcher.png b/tools/android/push_apps_to_background/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..96a442e
--- /dev/null
+++ b/tools/android/push_apps_to_background/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/tools/android/push_apps_to_background/res/layout/activity_push_apps_to_background.xml b/tools/android/push_apps_to_background/res/layout/activity_push_apps_to_background.xml
new file mode 100644
index 0000000..9d292ca
--- /dev/null
+++ b/tools/android/push_apps_to_background/res/layout/activity_push_apps_to_background.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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:gravity="center">
+    <TextView
+        android:id="@+id/text_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:text="@string/push_apps_to_background_message" />
+</LinearLayout>
\ No newline at end of file
diff --git a/tools/android/push_apps_to_background/res/values/strings.xml b/tools/android/push_apps_to_background/res/values/strings.xml
new file mode 100644
index 0000000..99f76a2
--- /dev/null
+++ b/tools/android/push_apps_to_background/res/values/strings.xml
@@ -0,0 +1,15 @@
+<?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.
+-->
+
+<resources>
+    <string name="app_name">Push Apps To Background</string>
+    <string name="push_apps_to_background_message">
+        "<b>What is my purpose?</b>\n
+         <i>You push apps to the background.</i>\n
+         <b>Oh my God</b>."
+    </string>
+    <string name="title_activity_push_apps_to_background">Push Apps To Background</string>
+</resources>
\ No newline at end of file
diff --git a/tools/android/push_apps_to_background/src/org/chromium/push_apps_to_background/PushAppsToBackgroundActivity.java b/tools/android/push_apps_to_background/src/org/chromium/push_apps_to_background/PushAppsToBackgroundActivity.java
new file mode 100644
index 0000000..95e9a99
--- /dev/null
+++ b/tools/android/push_apps_to_background/src/org/chromium/push_apps_to_background/PushAppsToBackgroundActivity.java
@@ -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.
+
+package org.chromium.push_apps_to_background;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * This activity is used in performance tests to push other apps
+ * to the background while running automated user stories.
+ */
+public class PushAppsToBackgroundActivity extends Activity {
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_push_apps_to_background);
+    }
+}
\ No newline at end of file
diff --git a/tools/clang/scripts/package.py b/tools/clang/scripts/package.py
index 944acee..63ab1a98 100755
--- a/tools/clang/scripts/package.py
+++ b/tools/clang/scripts/package.py
@@ -110,13 +110,6 @@
 
 
 def main():
-  if sys.platform == 'win32':
-    try:
-      subprocess.check_output(['grep', '--help'], shell=True)
-    except subprocess.CalledProcessError:
-      print 'Add gnuwin32 to your PATH, then try again.'
-      return 1
-
   parser = argparse.ArgumentParser(description='build and package clang')
   parser.add_argument('--upload', action='store_true',
                       help='Upload the target archive to Google Cloud Storage.')
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index e3fa1b1..b005520 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -136,19 +136,19 @@
       tarfile.open(mode='r:gz', fileobj=f).extractall(path=output_dir)
 
 
-def ReadStampFile():
+def ReadStampFile(path=STAMP_FILE):
   """Return the contents of the stamp file, or '' if it doesn't exist."""
   try:
-    with open(STAMP_FILE, 'r') as f:
+    with open(path, 'r') as f:
       return f.read().rstrip()
   except IOError:
     return ''
 
 
-def WriteStampFile(s):
+def WriteStampFile(s, path=STAMP_FILE):
   """Write s to the stamp file."""
-  EnsureDirExists(os.path.dirname(STAMP_FILE))
-  with open(STAMP_FILE, 'w') as f:
+  EnsureDirExists(os.path.dirname(path))
+  with open(path, 'w') as f:
     f.write(s)
     f.write('\n')
 
@@ -305,6 +305,24 @@
   os.environ['PATH'] = cmake_dir + os.pathsep + os.environ.get('PATH', '')
 
 
+def AddGnuWinToPath():
+  """Download some GNU win tools and add them to PATH."""
+  if sys.platform != 'win32':
+    return
+
+  gnuwin_dir = os.path.join(LLVM_BUILD_TOOLS_DIR, 'gnuwin')
+  GNUWIN_VERSION = '1'
+  GNUWIN_STAMP = os.path.join(gnuwin_dir, 'stamp')
+  if ReadStampFile(GNUWIN_STAMP) == GNUWIN_VERSION:
+    print 'GNU Win tools already up to date.'
+  else:
+    zip_name = 'gnuwin-%s.zip' % GNUWIN_VERSION
+    DownloadAndUnpack(CDS_URL + '/tools/' + zip_name, LLVM_BUILD_TOOLS_DIR)
+    WriteStampFile(GNUWIN_VERSION, GNUWIN_STAMP)
+
+  os.environ['PATH'] = gnuwin_dir + os.pathsep + os.environ.get('PATH', '')
+
+
 vs_version = None
 def GetVSVersion():
   global vs_version
@@ -381,6 +399,7 @@
 
   DownloadHostGcc(args)
   AddCMakeToPath()
+  AddGnuWinToPath()
 
   DeleteChromeToolsShim()
 
diff --git a/tools/cr/cr/base/host.py b/tools/cr/cr/base/host.py
index 5ff7ed8b..a9d5a6f0 100644
--- a/tools/cr/cr/base/host.py
+++ b/tools/cr/cr/base/host.py
@@ -75,6 +75,7 @@
     """
     with cr.context.Trace():
       command = [cr.context.Substitute(arg) for arg in command if arg]
+      command = filter(bool, command)
     trail = cr.context.trail
     if not command:
       print 'Empty command passed to execute'
diff --git a/tools/ipc_fuzzer/message_tools/message_list.cc b/tools/ipc_fuzzer/message_tools/message_list.cc
index 69e4699..8b4d10c 100644
--- a/tools/ipc_fuzzer/message_tools/message_list.cc
+++ b/tools/ipc_fuzzer/message_tools/message_list.cc
@@ -53,9 +53,6 @@
   exemptions.push_back(CCMsgStart);  // Nothing but param traits.
   exemptions.push_back(CldDataProviderMsgStart); // Conditional build.
 
-  // Sent from browser to renderer.
-  exemptions.push_back(WebCacheMsgStart);
-
 #if defined(DISABLE_NACL)
   exemptions.push_back(NaClMsgStart);
 #endif  // defined(DISABLE_NACL)
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 0f3b752..4c4981d9 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -28704,6 +28704,11 @@
   </summary>
 </histogram>
 
+<histogram name="Net.TokenBinding.HeaderCreationTime" units="ms">
+  <owner>nharper@chromium.org</owner>
+  <summary>Time spent creating a Token-Binding header.</summary>
+</histogram>
+
 <histogram name="Net.TokenBinding.KeyMatch" enum="TokenBinding.KeyMatch">
   <owner>nharper@chromium.org</owner>
   <summary>
@@ -84255,6 +84260,7 @@
   <int value="42" label="Open a bookmark"/>
   <int value="43" label="Exit"/>
   <int value="44" label="Upgrade browser"/>
+  <int value="45" label="Cast"/>
 </enum>
 
 <enum name="XMLHttpRequestHeaderValueCategoryInRFC7230" type="int">
@@ -89822,6 +89828,7 @@
       instead.
     </obsolete>
   </suffix>
+  <suffix name="Cast"/>
   <affected-histogram name="WrenchMenu.TimeToAction"/>
 </histogram_suffixes>
 
diff --git a/tools/perf/benchmarks/benchmark_smoke_unittest.py b/tools/perf/benchmarks/benchmark_smoke_unittest.py
index d63629b..f19d1d2 100644
--- a/tools/perf/benchmarks/benchmark_smoke_unittest.py
+++ b/tools/perf/benchmarks/benchmark_smoke_unittest.py
@@ -23,7 +23,6 @@
 from benchmarks import jetstream
 from benchmarks import kraken
 from benchmarks import memory
-from benchmarks import new_tab
 from benchmarks import octane
 from benchmarks import rasterize_and_record_micro
 from benchmarks import repaint
@@ -80,7 +79,6 @@
 _BLACK_LIST_TEST_MODULES = {
     image_decoding,  # Always fails on Mac10.9 Tests builder.
     indexeddb_perf,  # Always fails on Win7 & Android Tests builder.
-    new_tab,  # Fails fairly often on the Linux Tests builder, crbug.com/535664
     octane,  # Often fails & take long time to timeout on cq bot.
     rasterize_and_record_micro,  # Always fails on cq bot.
     repaint,  # Often fails & takes long time to timeout on cq bot.
diff --git a/tools/perf/benchmarks/new_tab.py b/tools/perf/benchmarks/new_tab.py
deleted file mode 100644
index 2071c388..0000000
--- a/tools/perf/benchmarks/new_tab.py
+++ /dev/null
@@ -1,27 +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.
-
-from core import perf_benchmark
-
-from telemetry import benchmark
-from telemetry.web_perf import timeline_based_measurement
-
-import page_sets
-
-
-@benchmark.Disabled('android')
-class NewTabPage(perf_benchmark.PerfBenchmark):
-  """Timeline based measurement benchmark for the New Tab Page."""
-  page_set = page_sets.NewTabPagePageSet
-
-  def CreateTimelineBasedMeasurementOptions(self):
-    return timeline_based_measurement.Options(
-        overhead_level=timeline_based_measurement.MINIMAL_OVERHEAD_LEVEL)
-
-  @classmethod
-  def Name(cls):
-    return 'new_tab.new_tab_page'
-
-  # TODO(beaudoin): Define ValueCanBeAddedPredicate to filter out things we
-  # don't care for.
diff --git a/tools/perf/benchmarks/power.py b/tools/perf/benchmarks/power.py
index d4ebde9d..f7011020 100644
--- a/tools/perf/benchmarks/power.py
+++ b/tools/perf/benchmarks/power.py
@@ -56,6 +56,10 @@
   def Name(cls):
     return 'power.tough_ad_cases'
 
+  @classmethod
+  def ShouldDisable(cls, possible_browser):
+    return cls.IsSvelte(possible_browser) # http://crbug.com/593973
+
 
 @benchmark.Enabled('android')
 @benchmark.Disabled('all')
diff --git a/tools/perf/benchmarks/v8.py b/tools/perf/benchmarks/v8.py
index 57cc73a..92ad47e 100644
--- a/tools/perf/benchmarks/v8.py
+++ b/tools/perf/benchmarks/v8.py
@@ -122,7 +122,9 @@
   page_set = page_sets.TodoMVCPageSet
 
   def CreateTimelineBasedMeasurementOptions(self):
-    category_filter = tracing_category_filter.TracingCategoryFilter('v8')
+    category_filter = tracing_category_filter.CreateMinimalOverheadFilter()
+    category_filter.AddIncludedCategory('v8')
+    category_filter.AddIncludedCategory('blink.console')
     options = timeline_based_measurement.Options(category_filter)
     options.SetLegacyTimelineBasedMetrics([v8_execution.V8ExecutionMetric()])
     return options
diff --git a/tools/perf/core/trybot_command.py b/tools/perf/core/trybot_command.py
index b4073876..79a009b5 100644
--- a/tools/perf/core/trybot_command.py
+++ b/tools/perf/core/trybot_command.py
@@ -5,6 +5,7 @@
 import argparse
 import os
 import logging
+import platform
 import re
 import subprocess
 import urllib2
@@ -125,6 +126,12 @@
   return (returncode, out, err)
 
 
+_GIT_CMD = 'git'
+if platform.system() == 'Windows':
+  # On windows, the git command is installed as 'git.bat'
+  _GIT_CMD = 'git.bat'
+
+
 class Trybot(command_line.ArgParseCommand):
   """ Run telemetry perf benchmark on trybot """
 
@@ -261,13 +268,13 @@
       config_file.write(config_to_write)
     # Commit the config changes locally.
     returncode, out, err = _RunProcess(
-        ['git', 'commit', '-a', '-m', 'bisect config: %s' % bot_platform])
+        [_GIT_CMD, 'commit', '-a', '-m', 'bisect config: %s' % bot_platform])
     if returncode:
       raise TrybotError('Could not commit bisect config change for %s,'
                         ' error %s' % (bot_platform, err))
     # Upload the CL to rietveld and run a try job.
     returncode, out, err = _RunProcess([
-        'git', 'cl', 'upload', '-f', '--bypass-hooks', '-m',
+        _GIT_CMD, 'cl', 'upload', '-f', '--bypass-hooks', '-m',
         'CL for perf tryjob on %s' % bot_platform
     ])
     if returncode:
@@ -280,7 +287,7 @@
                         (bot_platform, out))
     rietveld_url = match.group(0)
     # Generate git try command for available bots.
-    git_try_command = ['git', 'cl', 'try', '-m', 'tryserver.chromium.perf']
+    git_try_command = [_GIT_CMD, 'cl', 'try', '-m', 'tryserver.chromium.perf']
     for bot in self._builder_names[bot_platform]:
       git_try_command.extend(['-b', bot])
     returncode, out, err = _RunProcess(git_try_command)
@@ -356,7 +363,7 @@
     # TODO(prasadv): This method is quite long, we should consider refactor
     # this by extracting to helper methods.
     returncode, original_branchname, err = _RunProcess(
-        ['git', 'rev-parse', '--abbrev-ref', 'HEAD'])
+        [_GIT_CMD, 'rev-parse', '--abbrev-ref', 'HEAD'])
     if returncode:
       msg = 'Must be in a git repository to send changes to trybots.'
       if err:
@@ -368,8 +375,8 @@
 
     # Check if the tree is dirty: make sure the index is up to date and then
     # run diff-index
-    _RunProcess(['git', 'update-index', '--refresh', '-q'])
-    returncode, out, err = _RunProcess(['git', 'diff-index', 'HEAD'])
+    _RunProcess([_GIT_CMD, 'update-index', '--refresh', '-q'])
+    returncode, out, err = _RunProcess([_GIT_CMD, 'diff-index', 'HEAD'])
     if out:
       logging.error(
           'Cannot send a try job with a dirty tree. Commit locally first.')
@@ -377,21 +384,21 @@
 
     # Make sure the tree does have local commits.
     returncode, out, err = _RunProcess(
-        ['git', 'log', 'origin/master..HEAD'])
+        [_GIT_CMD, 'log', 'origin/master..HEAD'])
     if not out:
       return NO_CHANGES
 
     # Create/check out the telemetry-tryjob branch, and edit the configs
     # for the tryjob there.
     returncode, out, err = _RunProcess(
-        ['git', 'checkout', '-b', 'telemetry-tryjob'])
+        [_GIT_CMD, 'checkout', '-b', 'telemetry-tryjob'])
     if returncode:
       logging.error('Error creating branch telemetry-tryjob. '
                     'Please delete it if it exists.\n%s', err)
       return ERROR
     try:
       returncode, out, err = _RunProcess(
-          ['git', 'branch', '--set-upstream-to', 'origin/master'])
+          [_GIT_CMD, 'branch', '--set-upstream-to', 'origin/master'])
       if returncode:
         logging.error('Error in git branch --set-upstream-to: %s', err)
         return ERROR
@@ -419,7 +426,7 @@
       # TODO(prasadv): This finally block could be extracted out to be a
       # separate function called _CleanupBranch.
       returncode, out, err = _RunProcess(
-          ['git', 'checkout', original_branchname])
+          [_GIT_CMD, 'checkout', original_branchname])
       if returncode:
         logging.error('Could not check out %s. Please check it out and '
                       'manually delete the telemetry-tryjob branch. '
@@ -427,7 +434,7 @@
         return ERROR  # pylint: disable=lost-exception
       logging.info('Checked out original branch: %s', original_branchname)
       returncode, out, err = _RunProcess(
-          ['git', 'branch', '-D', 'telemetry-tryjob'])
+          [_GIT_CMD, 'branch', '-D', 'telemetry-tryjob'])
       if returncode:
         logging.error('Could not delete telemetry-tryjob branch. '
                       'Please delete it manually: %s', err)
diff --git a/tools/perf/core/trybot_command_unittest.py b/tools/perf/core/trybot_command_unittest.py
index a953a38..76c7bb72 100644
--- a/tools/perf/core/trybot_command_unittest.py
+++ b/tools/perf/core/trybot_command_unittest.py
@@ -41,6 +41,9 @@
     self._urllib2_mock = self._urllib2_patcher.start()
     self._stubs = system_stub.Override(trybot_command,
                                        ['sys', 'open', 'os'])
+    # Always set git command to 'git' to simplify testing across platforms.
+    self._original_git_cmd = trybot_command._GIT_CMD
+    trybot_command._GIT_CMD = 'git'
 
   def tearDown(self):
     logging.getLogger().removeHandler(self.stream_handler)
@@ -50,6 +53,7 @@
     self._urllib2_patcher.stop()
     # Reset the cached builders in trybot_command
     trybot_command.Trybot._builders = None
+    trybot_command._GIT_CMD = self._original_git_cmd
 
   def _ExpectProcesses(self, expected_args_list):
     counter = [-1]
diff --git a/tools/perf/page_sets/data/new_tab_page_page.json b/tools/perf/page_sets/data/new_tab_page_page.json
deleted file mode 100644
index 17e8818..0000000
--- a/tools/perf/page_sets/data/new_tab_page_page.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-    "description": "Describes the Web Page Replay archives for a user story set. Don't edit by hand! Use record_wpr for updating.", 
-    "archives": {
-        "new_tab_page_page_001.wpr": [
-            "newtabpagepage"
-        ]
-    }
-}
\ No newline at end of file
diff --git a/tools/perf/page_sets/data/new_tab_page_page_001.wpr.sha1 b/tools/perf/page_sets/data/new_tab_page_page_001.wpr.sha1
deleted file mode 100644
index 4924984..0000000
--- a/tools/perf/page_sets/data/new_tab_page_page_001.wpr.sha1
+++ /dev/null
@@ -1 +0,0 @@
-231ebe8bc7738b51193d71a194507d3f9130de08
\ No newline at end of file
diff --git a/tools/perf/page_sets/new_tab_page.py b/tools/perf/page_sets/new_tab_page.py
deleted file mode 100644
index 2fca690..0000000
--- a/tools/perf/page_sets/new_tab_page.py
+++ /dev/null
@@ -1,49 +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.
-import time
-
-from telemetry.page import page as page_module
-from telemetry.page import shared_page_state
-from telemetry import story
-
-INTERACTION_NAME = 'Interaction.PageLoading'
-
-# How long to wait for the page to finish rendering.
-LOADING_DELAY_S = 5
-
-
-class NewTabPagePage(page_module.Page):
-
-  def __init__(self, page_set):
-    super(NewTabPagePage, self).__init__(
-      name='newtabpagepage',
-      url='chrome://newtab',
-      shared_page_state_class=shared_page_state.SharedDesktopPageState,
-      page_set=page_set)
-    self.archive_data_file = 'data/new_tab_page_page.json'
-    self.script_to_evaluate_on_commit = (
-        "console.time('" + INTERACTION_NAME + "');")
-
-  def RunNavigateSteps(self, action_runner):
-    url = self.file_path_url_with_scheme if self.is_file else self.url
-    action_runner.Navigate(
-        url, script_to_evaluate_on_commit=self.script_to_evaluate_on_commit)
-    # We pause for a while so the async JS gets a chance to run.
-    time.sleep(LOADING_DELAY_S)
-    # TODO(beaudoin): We have no guarantee the page has fully rendered and the
-    #   JS has fully executed at that point. The right way to do it would be to
-    #   toggle a Javascript variable in the page code and to wait for it here.
-    #   This should be done when window.performance.mark is supported and we
-    #   migrate to it instead of calling console.timeEnd here. If the test is
-    #   failing flakily, we should use a better heuristic.
-    action_runner.ExecuteJavaScript(
-        "console.timeEnd('" + INTERACTION_NAME + "');")
-
-
-class NewTabPagePageSet(story.StorySet):
-  def __init__(self):
-    super(NewTabPagePageSet, self).__init__(
-        archive_data_file='data/new_tab_page_page.json',
-        cloud_storage_bucket=story.PUBLIC_BUCKET)
-    self.AddStory(NewTabPagePage(page_set=self))
diff --git a/tools/perf/page_sets/todomvc.py b/tools/perf/page_sets/todomvc.py
index 5536c83..4f095ec 100644
--- a/tools/perf/page_sets/todomvc.py
+++ b/tools/perf/page_sets/todomvc.py
@@ -19,6 +19,8 @@
     ('Vanilla JS', 'http://todomvc.com/examples/vanillajs'),
 ]
 
+INTERACTION_NAME = 'Interaction.AppLoad'
+
 
 class TodoMVCPage(page_module.Page):
 
@@ -26,9 +28,27 @@
     super(TodoMVCPage, self).__init__(
         url=url, page_set=page_set, name=name,
         shared_page_state_class=shared_page_state.SharedDesktopPageState)
+    # TODO(jochen): This interaction does not include the
+    # WindowProxy::initialize portion before the commit. To fix this, we'll
+    # have to migrate to TBMv2.
+    self.script_to_evaluate_on_commit = (
+        'console.time("%s");' % INTERACTION_NAME)
 
   def RunPageInteractions(self, action_runner):
-    pass
+    action_runner.ExecuteJavaScript(
+        """
+        this.becameIdle = false;
+        this.idleCallback = function(deadline) {
+            if (deadline.timeRemaining() > 20)
+                this.becameIdle = true;
+            else
+                requestIdleCallback(this.idleCallback);
+        };
+        requestIdleCallback(this.idleCallback);
+        """
+    )
+    action_runner.WaitForJavaScriptCondition('this.becameIdle === true')
+    action_runner.ExecuteJavaScript('console.timeEnd("%s");' % INTERACTION_NAME)
 
 
 class TodoMVCPageSet(story.StorySet):
diff --git a/ui/accessibility/ax_enums.idl b/ui/accessibility/ax_enums.idl
index 4583da7..bad6a7a 100644
--- a/ui/accessibility/ax_enums.idl
+++ b/ui/accessibility/ax_enums.idl
@@ -76,7 +76,7 @@
     // TODO(nektar): Remove busy_indicator because it's used nowhere.
     busy_indicator,
     button,
-    button_drop_down,
+    button_drop_down,  // Not used on Web.
     canvas,
     caption,
     cell,
@@ -132,6 +132,7 @@
     mark,
     marquee,
     math,
+    menu,
     menu_bar,
     menu_button,
     menu_item,
@@ -139,7 +140,6 @@
     menu_item_radio,
     menu_list_option,
     menu_list_popup,
-    menu,
     meter,
     navigation,
     note,
diff --git a/ui/display/chromeos/display_configurator.h b/ui/display/chromeos/display_configurator.h
index 390beaf8..c6c849b 100644
--- a/ui/display/chromeos/display_configurator.h
+++ b/ui/display/chromeos/display_configurator.h
@@ -285,6 +285,10 @@
   // Returns true if there is at least one display on.
   bool IsDisplayOn() const;
 
+  void set_configure_display(bool configure_display) {
+    configure_display_ = configure_display;
+  }
+
  private:
   class DisplayLayoutManagerImpl;
 
diff --git a/ui/events/blink/input_handler_proxy.cc b/ui/events/blink/input_handler_proxy.cc
index 187c9ac8..1889a89 100644
--- a/ui/events/blink/input_handler_proxy.cc
+++ b/ui/events/blink/input_handler_proxy.cc
@@ -208,6 +208,13 @@
   }
 }
 
+cc::InputHandler::ScrollInputType GestureScrollInputType(
+    blink::WebGestureDevice device) {
+  return device == blink::WebGestureDeviceTouchpad
+             ? cc::InputHandler::WHEEL
+             : cc::InputHandler::TOUCHSCREEN;
+}
+
 }  // namespace
 
 namespace ui {
@@ -424,13 +431,12 @@
   }
 }
 
-bool InputHandlerProxy::ShouldAnimate(
-    const blink::WebMouseWheelEvent& event) const {
+bool InputHandlerProxy::ShouldAnimate(bool has_precise_scroll_deltas) const {
 #if defined(OS_MACOSX)
   // Mac does not smooth scroll wheel events (crbug.com/574283).
   return false;
 #else
-  return smooth_scroll_enabled_ && !event.hasPreciseScrollingDeltas;
+  return smooth_scroll_enabled_ && !has_precise_scroll_deltas;
 #endif
 }
 
@@ -487,7 +493,7 @@
     // Wheel events with |canScroll| == false will not trigger scrolling,
     // only event handlers.  Forward to the main thread.
     result = DID_NOT_HANDLE;
-  } else if (ShouldAnimate(wheel_event)) {
+  } else if (ShouldAnimate(wheel_event.hasPreciseScrollingDeltas)) {
     cc::InputHandler::ScrollStatus scroll_status =
         input_handler_->ScrollAnimated(gfx::Point(wheel_event.x, wheel_event.y),
                                        scroll_delta);
@@ -592,26 +598,15 @@
     scroll_status.main_thread_scrolling_reasons =
         cc::MainThreadScrollingReason::kContinuingMainThreadScroll;
   } else if (gesture_event.data.scrollBegin.targetViewport) {
-    scroll_status = input_handler_->RootScrollBegin(&scroll_state,
-                                                    cc::InputHandler::GESTURE);
-  } else if (smooth_scroll_enabled_ &&
-             gesture_event.data.scrollBegin.deltaHintUnits ==
-                 blink::WebGestureEvent::ScrollUnits::Pixels) {
-    // Generate a scroll begin/end combination to determine if
-    // this can actually be handled by the impl thread or not. But
-    // don't generate any scroll yet; GestureScrollUpdate will generate
-    // the scroll animation.
-    scroll_status = input_handler_->ScrollBegin(
-        &scroll_state, cc::InputHandler::ANIMATED_WHEEL);
-    if (scroll_status.thread == cc::InputHandler::SCROLL_ON_IMPL_THREAD) {
-      cc::ScrollStateData scroll_state_end_data;
-      scroll_state_end_data.is_ending = true;
-      cc::ScrollState scroll_state_end(scroll_state_end_data);
-      input_handler_->ScrollEnd(&scroll_state_end);
-    }
+    scroll_status = input_handler_->RootScrollBegin(
+        &scroll_state, GestureScrollInputType(gesture_event.sourceDevice));
+  } else if (ShouldAnimate(gesture_event.data.scrollBegin.deltaHintUnits !=
+                           blink::WebGestureEvent::ScrollUnits::Pixels)) {
+    gfx::Point scroll_point(gesture_event.x, gesture_event.y);
+    scroll_status = input_handler_->ScrollAnimatedBegin(scroll_point);
   } else {
-    scroll_status =
-        input_handler_->ScrollBegin(&scroll_state, cc::InputHandler::GESTURE);
+    scroll_status = input_handler_->ScrollBegin(
+        &scroll_state, GestureScrollInputType(gesture_event.sourceDevice));
   }
   UMA_HISTOGRAM_ENUMERATION("Renderer4.CompositorScrollHitTestResult",
                             scroll_status.thread,
@@ -620,20 +615,28 @@
   RecordMainThreadScrollingReasons(gesture_event.type,
                                    scroll_status.main_thread_scrolling_reasons);
 
+  InputHandlerProxy::EventDisposition result = DID_NOT_HANDLE;
   switch (scroll_status.thread) {
     case cc::InputHandler::SCROLL_ON_IMPL_THREAD:
       TRACE_EVENT_INSTANT0("input",
                            "InputHandlerProxy::handle_input gesture scroll",
                            TRACE_EVENT_SCOPE_THREAD);
       gesture_scroll_on_impl_thread_ = true;
-      return DID_HANDLE;
+      result = DID_HANDLE;
+      break;
     case cc::InputHandler::SCROLL_UNKNOWN:
     case cc::InputHandler::SCROLL_ON_MAIN_THREAD:
-      return DID_NOT_HANDLE;
+      result = DID_NOT_HANDLE;
+      break;
     case cc::InputHandler::SCROLL_IGNORED:
-      return DROP_EVENT;
+      result = DROP_EVENT;
+      break;
   }
-  return DID_NOT_HANDLE;
+  if (scroll_elasticity_controller_ && result != DID_NOT_HANDLE)
+    HandleScrollElasticityOverscroll(gesture_event,
+                                     cc::InputHandlerScrollResult());
+
+  return result;
 }
 
 InputHandlerProxy::EventDisposition
@@ -650,9 +653,8 @@
   gfx::Vector2dF scroll_delta(-gesture_event.data.scrollUpdate.deltaX,
                               -gesture_event.data.scrollUpdate.deltaY);
 
-  if (smooth_scroll_enabled_ &&
-      gesture_event.data.scrollUpdate.deltaUnits ==
-          blink::WebGestureEvent::ScrollUnits::Pixels) {
+  if (ShouldAnimate(gesture_event.data.scrollUpdate.deltaUnits !=
+                    blink::WebGestureEvent::ScrollUnits::Pixels)) {
     switch (input_handler_->ScrollAnimated(scroll_point, scroll_delta).thread) {
       case cc::InputHandler::SCROLL_ON_IMPL_THREAD:
         return DID_HANDLE;
@@ -665,6 +667,10 @@
   cc::InputHandlerScrollResult scroll_result =
       input_handler_->ScrollBy(&scroll_state);
   HandleOverscroll(scroll_point, scroll_result);
+
+  if (scroll_elasticity_controller_)
+    HandleScrollElasticityOverscroll(gesture_event, scroll_result);
+
   return scroll_result.did_scroll ? DID_HANDLE : DROP_EVENT;
 }
 
@@ -674,10 +680,21 @@
   DCHECK(expect_scroll_update_end_);
   expect_scroll_update_end_ = false;
 #endif
-  cc::ScrollState scroll_state = CreateScrollStateForGesture(gesture_event);
-  input_handler_->ScrollEnd(&scroll_state);
+  if (ShouldAnimate(gesture_event.data.scrollEnd.deltaUnits !=
+                    blink::WebGestureEvent::ScrollUnits::Pixels)) {
+    // Do nothing if the scroll is being animated; the scroll animation will
+    // generate the ScrollEnd when it is done.
+  } else {
+    cc::ScrollState scroll_state = CreateScrollStateForGesture(gesture_event);
+    input_handler_->ScrollEnd(&scroll_state);
+  }
   if (!gesture_scroll_on_impl_thread_)
     return DID_NOT_HANDLE;
+
+  if (scroll_elasticity_controller_)
+    HandleScrollElasticityOverscroll(gesture_event,
+                                     cc::InputHandlerScrollResult());
+
   gesture_scroll_on_impl_thread_ = false;
   return DID_HANDLE;
 }
@@ -890,7 +907,7 @@
               gfx::Point(gesture_event.x, gesture_event.y),
               fling_parameters_.sourceDevice == blink::WebGestureDeviceTouchpad
                   ? cc::InputHandler::NON_BUBBLING_GESTURE
-                  : cc::InputHandler::GESTURE)) {
+                  : cc::InputHandler::TOUCHSCREEN)) {
         CancelCurrentFling();
         return false;
       }
@@ -1310,4 +1327,19 @@
   return did_scroll;
 }
 
+void InputHandlerProxy::HandleScrollElasticityOverscroll(
+    const WebGestureEvent& gesture_event,
+    const cc::InputHandlerScrollResult& scroll_result) {
+  DCHECK(scroll_elasticity_controller_);
+  // Send the event and its disposition to the elasticity controller to update
+  // the over-scroll animation. Note that the call to the elasticity controller
+  // is made asynchronously, to minimize divergence between main thread and
+  // impl thread event handling paths.
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::Bind(&InputScrollElasticityController::ObserveGestureEventAndResult,
+                 scroll_elasticity_controller_->GetWeakPtr(), gesture_event,
+                 scroll_result));
+}
+
 }  // namespace ui
diff --git a/ui/events/blink/input_handler_proxy.h b/ui/events/blink/input_handler_proxy.h
index 32c0efc..2da4bc9 100644
--- a/ui/events/blink/input_handler_proxy.h
+++ b/ui/events/blink/input_handler_proxy.h
@@ -138,7 +138,12 @@
       const cc::InputHandlerScrollResult& scroll_result);
 
   // Whether to use a smooth scroll animation for this event.
-  bool ShouldAnimate(const blink::WebMouseWheelEvent& event) const;
+  bool ShouldAnimate(bool has_precise_scroll_deltas) const;
+
+  // Update the elastic overscroll controller with |gesture_event|.
+  void HandleScrollElasticityOverscroll(
+      const blink::WebGestureEvent& gesture_event,
+      const cc::InputHandlerScrollResult& scroll_result);
 
   scoped_ptr<blink::WebGestureCurve> fling_curve_;
   // Parameters for the active fling animation, stored in case we need to
diff --git a/ui/events/blink/input_handler_proxy_unittest.cc b/ui/events/blink/input_handler_proxy_unittest.cc
index 6723a31..b798dc9 100644
--- a/ui/events/blink/input_handler_proxy_unittest.cc
+++ b/ui/events/blink/input_handler_proxy_unittest.cc
@@ -104,6 +104,8 @@
   MOCK_METHOD2(RootScrollBegin,
                ScrollStatus(cc::ScrollState*,
                             cc::InputHandler::ScrollInputType type));
+  MOCK_METHOD1(ScrollAnimatedBegin,
+               ScrollStatus(const gfx::Point& viewport_point));
   MOCK_METHOD2(ScrollAnimated,
                ScrollStatus(const gfx::Point& viewport_point,
                             const gfx::Vector2dF& scroll_delta));
@@ -639,9 +641,8 @@
   gesture_.type = WebInputEvent::GestureScrollBegin;
   gesture_.data.scrollBegin.deltaHintUnits =
       WebGestureEvent::ScrollUnits::Pixels;
-  EXPECT_CALL(mock_input_handler_, ScrollBegin(::testing::_, ::testing::_))
+  EXPECT_CALL(mock_input_handler_, ScrollAnimatedBegin(::testing::_))
       .WillOnce(testing::Return(kImplThreadScrollState));
-  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_));
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
 
   gesture_.type = WebInputEvent::GestureScrollUpdate;
diff --git a/ui/events/blink/input_scroll_elasticity_controller.cc b/ui/events/blink/input_scroll_elasticity_controller.cc
index d063093c..dedf7de 100644
--- a/ui/events/blink/input_scroll_elasticity_controller.cc
+++ b/ui/events/blink/input_scroll_elasticity_controller.cc
@@ -167,6 +167,71 @@
   }
 }
 
+void InputScrollElasticityController::ObserveGestureEventAndResult(
+    const blink::WebGestureEvent& gesture_event,
+    const cc::InputHandlerScrollResult& scroll_result) {
+  base::TimeTicks event_timestamp =
+      base::TimeTicks() +
+      base::TimeDelta::FromSecondsD(gesture_event.timeStampSeconds);
+
+  switch (gesture_event.type) {
+    case blink::WebInputEvent::GestureScrollBegin: {
+      if (gesture_event.data.scrollBegin.synthetic)
+        return;
+      if (gesture_event.data.scrollBegin.inertial) {
+        if (state_ == kStateInactive)
+          state_ = kStateMomentumScroll;
+      } else if (gesture_event.data.scrollBegin.deltaHintUnits ==
+                 blink::WebGestureEvent::PrecisePixels) {
+        scroll_velocity = gfx::Vector2dF();
+        last_scroll_event_timestamp_ = base::TimeTicks();
+        state_ = kStateActiveScroll;
+        pending_overscroll_delta_ = gfx::Vector2dF();
+      }
+      break;
+    }
+    case blink::WebInputEvent::GestureScrollUpdate: {
+      gfx::Vector2dF event_delta(-gesture_event.data.scrollUpdate.deltaX,
+                                 -gesture_event.data.scrollUpdate.deltaY);
+      switch (state_) {
+        case kStateMomentumAnimated:
+        case kStateInactive:
+          break;
+        case kStateActiveScroll:
+        case kStateMomentumScroll:
+          UpdateVelocity(event_delta, event_timestamp);
+          Overscroll(event_delta, scroll_result.unused_scroll_delta);
+          if (gesture_event.data.scrollUpdate.inertial &&
+              !helper_->StretchAmount().IsZero()) {
+            EnterStateMomentumAnimated(event_timestamp);
+          }
+          break;
+      }
+      break;
+    }
+    case blink::WebInputEvent::GestureScrollEnd: {
+      if (gesture_event.data.scrollEnd.synthetic)
+        return;
+      switch (state_) {
+        case kStateMomentumAnimated:
+        case kStateInactive:
+          break;
+        case kStateActiveScroll:
+        case kStateMomentumScroll:
+          if (helper_->StretchAmount().IsZero()) {
+            EnterStateInactive();
+          } else {
+            EnterStateMomentumAnimated(event_timestamp);
+          }
+          break;
+      }
+      break;
+    }
+    default:
+      break;
+  }
+}
+
 void InputScrollElasticityController::UpdateVelocity(
     const gfx::Vector2dF& event_delta,
     const base::TimeTicks& event_timestamp) {
diff --git a/ui/events/blink/input_scroll_elasticity_controller.h b/ui/events/blink/input_scroll_elasticity_controller.h
index 8c64681..915b2e8 100644
--- a/ui/events/blink/input_scroll_elasticity_controller.h
+++ b/ui/events/blink/input_scroll_elasticity_controller.h
@@ -58,6 +58,15 @@
   void ObserveWheelEventAndResult(
       const blink::WebMouseWheelEvent& wheel_event,
       const cc::InputHandlerScrollResult& scroll_result);
+  // Update the overscroll state based a gesture event that has been processed.
+  // Note that this assumes that all events are coming from a single input
+  // device. If the user simultaneously uses multiple input devices, Cocoa may
+  // not correctly pass all the gesture begin and end events. In this case,
+  // this class may disregard some scrolls that come in at unexpected times.
+  void ObserveGestureEventAndResult(
+      const blink::WebGestureEvent& gesture_event,
+      const cc::InputHandlerScrollResult& scroll_result);
+
   void Animate(base::TimeTicks time);
 
   void ReconcileStretchAndScroll();
diff --git a/ui/events/blink/input_scroll_elasticity_controller_unittest.cc b/ui/events/blink/input_scroll_elasticity_controller_unittest.cc
index 82b9434..4ce7b94 100644
--- a/ui/events/blink/input_scroll_elasticity_controller_unittest.cc
+++ b/ui/events/blink/input_scroll_elasticity_controller_unittest.cc
@@ -99,6 +99,53 @@
     input_event_count_ += 1;
   }
 
+  void SendGestureScrollBegin(bool inertial) {
+    blink::WebGestureEvent event;
+    event.sourceDevice = blink::WebGestureDeviceTouchpad;
+    event.type = blink::WebInputEvent::GestureScrollBegin;
+    event.data.scrollBegin.inertial = inertial;
+    TickCurrentTime();
+    event.timeStampSeconds = (current_time_ - base::TimeTicks()).InSecondsF();
+
+    controller_.ObserveGestureEventAndResult(event,
+                                             cc::InputHandlerScrollResult());
+    input_event_count_ += 1;
+  }
+
+  void SendGestureScrollUpdate(
+      bool inertial,
+      const gfx::Vector2dF& event_delta = gfx::Vector2dF(),
+      const gfx::Vector2dF& overscroll_delta = gfx::Vector2dF()) {
+    blink::WebGestureEvent event;
+    event.sourceDevice = blink::WebGestureDeviceTouchpad;
+    event.type = blink::WebInputEvent::GestureScrollUpdate;
+    event.data.scrollUpdate.inertial = inertial;
+    event.data.scrollUpdate.deltaX = -event_delta.x();
+    event.data.scrollUpdate.deltaY = -event_delta.y();
+    TickCurrentTime();
+    event.timeStampSeconds = (current_time_ - base::TimeTicks()).InSecondsF();
+
+    cc::InputHandlerScrollResult scroll_result;
+    scroll_result.did_overscroll_root = !overscroll_delta.IsZero();
+    scroll_result.unused_scroll_delta = overscroll_delta;
+
+    controller_.ObserveGestureEventAndResult(event, scroll_result);
+    input_event_count_ += 1;
+  }
+
+  void SendGestureScrollEnd() {
+    blink::WebGestureEvent event;
+    event.sourceDevice = blink::WebGestureDeviceTouchpad;
+    event.type = blink::WebInputEvent::GestureScrollEnd;
+
+    TickCurrentTime();
+    event.timeStampSeconds = (current_time_ - base::TimeTicks()).InSecondsF();
+
+    controller_.ObserveGestureEventAndResult(event,
+                                             cc::InputHandlerScrollResult());
+    input_event_count_ += 1;
+  }
+
   const base::TimeTicks& TickCurrentTime() {
     current_time_ += base::TimeDelta::FromSecondsD(1 / 60.f);
     return current_time_;
@@ -148,6 +195,40 @@
   EXPECT_EQ(0, helper_.request_begin_frame_count());
 }
 
+// Verify that stretching only occurs in one axis at a time, and that it
+// is biased to the Y axis.
+TEST_F(ScrollElasticityControllerTest, GestureBased_Axis) {
+  helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(0, 0),
+                                            gfx::ScrollOffset(0, 0));
+
+  // If we push equally in the X and Y directions, we should see a stretch only
+  // in the Y direction.
+  SendGestureScrollBegin(false);
+  SendGestureScrollUpdate(false, gfx::Vector2dF(10, 10),
+                          gfx::Vector2dF(10, 10));
+  EXPECT_EQ(1, helper_.set_stretch_amount_count());
+  EXPECT_EQ(0.f, helper_.StretchAmount().x());
+  EXPECT_LT(0.f, helper_.StretchAmount().y());
+  helper_.SetStretchAmount(gfx::Vector2dF());
+  EXPECT_EQ(2, helper_.set_stretch_amount_count());
+  SendGestureScrollEnd();
+  EXPECT_EQ(0, helper_.request_begin_frame_count());
+
+  // If we push more in the X direction than the Y direction, we should see a
+  // stretch only in the X direction. This decision should be based on the
+  // input delta, not the actual overscroll delta.
+  SendGestureScrollBegin(false);
+  SendGestureScrollUpdate(false, gfx::Vector2dF(-25, 10),
+                          gfx::Vector2dF(-25, 40));
+  EXPECT_EQ(3, helper_.set_stretch_amount_count());
+  EXPECT_GT(0.f, helper_.StretchAmount().x());
+  EXPECT_EQ(0.f, helper_.StretchAmount().y());
+  helper_.SetStretchAmount(gfx::Vector2dF());
+  EXPECT_EQ(4, helper_.set_stretch_amount_count());
+  SendGestureScrollEnd();
+  EXPECT_EQ(0, helper_.request_begin_frame_count());
+}
+
 // Verify that we need a total overscroll delta of at least 10 in a pinned
 // direction before we start stretching.
 TEST_F(ScrollElasticityControllerTest, MinimumDeltaBeforeStretch) {
@@ -201,7 +282,54 @@
   EXPECT_EQ(1, helper_.request_begin_frame_count());
 }
 
-// Verify that an stretch caused by a momentum scroll will switch to the
+// Verify that we need a total overscroll delta of at least 10 in a pinned
+// direction before we start stretching.
+TEST_F(ScrollElasticityControllerTest, GestureBased_MinimumDeltaBeforeStretch) {
+  // We should not start stretching while we are not pinned in the direction
+  // of the scroll (even if there is an overscroll delta). We have to wait for
+  // the regular scroll to eat all of the events.
+  helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(5, 5),
+                                            gfx::ScrollOffset(10, 10));
+  SendGestureScrollBegin(false);
+  SendGestureScrollUpdate(false, gfx::Vector2dF(0, 10), gfx::Vector2dF(0, 10));
+  SendGestureScrollUpdate(false, gfx::Vector2dF(0, 10), gfx::Vector2dF(0, 10));
+  EXPECT_EQ(0, helper_.set_stretch_amount_count());
+
+  // Now pin the -X and +Y direction. The first event will not generate a
+  // stretch
+  // because it is below the delta threshold of 10.
+  helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(0, 10),
+                                            gfx::ScrollOffset(10, 10));
+  SendGestureScrollUpdate(false, gfx::Vector2dF(0, 10), gfx::Vector2dF(0, 8));
+  EXPECT_EQ(0, helper_.set_stretch_amount_count());
+
+  // Make the next scroll be in the -X direction more than the +Y direction,
+  // which will erase the memory of the previous unused delta of 8.
+  SendGestureScrollUpdate(false, gfx::Vector2dF(-10, 5),
+                          gfx::Vector2dF(-8, 10));
+  EXPECT_EQ(0, helper_.set_stretch_amount_count());
+
+  // Now push against the pinned +Y direction again by 8. We reset the
+  // previous delta, so this will not generate a stretch.
+  SendGestureScrollUpdate(false, gfx::Vector2dF(0, 10), gfx::Vector2dF(0, 8));
+  EXPECT_EQ(0, helper_.set_stretch_amount_count());
+
+  // Push against +Y by another 8. This gets us above the delta threshold of
+  // 10, so we should now have had the stretch set, and it should be in the
+  // +Y direction. The scroll in the -X direction should have been forgotten.
+  SendGestureScrollUpdate(false, gfx::Vector2dF(0, 10), gfx::Vector2dF(0, 8));
+  EXPECT_EQ(1, helper_.set_stretch_amount_count());
+  EXPECT_EQ(0.f, helper_.StretchAmount().x());
+  EXPECT_LT(0.f, helper_.StretchAmount().y());
+
+  // End the gesture. Because there is a non-zero stretch, we should be in the
+  // animated state, and should have had a frame requested.
+  EXPECT_EQ(0, helper_.request_begin_frame_count());
+  SendGestureScrollEnd();
+  EXPECT_EQ(1, helper_.request_begin_frame_count());
+}
+
+// Verify that a stretch caused by a momentum scroll will switch to the
 // animating mode, where input events are ignored, and the stretch is updated
 // while animating.
 TEST_F(ScrollElasticityControllerTest, MomentumAnimate) {
@@ -297,7 +425,93 @@
   EXPECT_EQ(begin_frame_count, helper_.request_begin_frame_count());
 }
 
-// Verify that an stretch opposing a scroll is correctly resolved.
+// Verify that a stretch caused by a momentum scroll will switch to the
+// animating mode, where input events are ignored, and the stretch is updated
+// while animating.
+TEST_F(ScrollElasticityControllerTest, GestureBased_MomentumAnimate) {
+  // Do an active scroll, then switch to the momentum phase and scroll for a
+  // bit.
+  helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(5, 5),
+                                            gfx::ScrollOffset(10, 10));
+  SendGestureScrollBegin(false);
+  SendGestureScrollUpdate(false, gfx::Vector2dF(0, -80), gfx::Vector2dF(0, 0));
+  SendGestureScrollUpdate(false, gfx::Vector2dF(0, -80), gfx::Vector2dF(0, 0));
+  SendGestureScrollUpdate(false, gfx::Vector2dF(0, -80), gfx::Vector2dF(0, 0));
+  SendGestureScrollEnd();
+  SendGestureScrollBegin(true);
+  SendGestureScrollUpdate(true, gfx::Vector2dF(0, -80), gfx::Vector2dF(0, 0));
+  SendGestureScrollUpdate(true, gfx::Vector2dF(0, -80), gfx::Vector2dF(0, 0));
+  SendGestureScrollUpdate(true, gfx::Vector2dF(0, -80), gfx::Vector2dF(0, 0));
+  EXPECT_EQ(0, helper_.set_stretch_amount_count());
+
+  // Hit the -Y edge and overscroll slightly, but not enough to go over the
+  // threshold to cause a stretch.
+  helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(5, 0),
+                                            gfx::ScrollOffset(10, 10));
+  SendGestureScrollUpdate(true, gfx::Vector2dF(0, -80), gfx::Vector2dF(0, -8));
+  EXPECT_EQ(0, helper_.set_stretch_amount_count());
+  EXPECT_EQ(0, helper_.request_begin_frame_count());
+
+  // Take another step, this time going over the threshold. This should update
+  // the stretch amount, and then switch to the animating mode.
+  SendGestureScrollUpdate(true, gfx::Vector2dF(0, -80), gfx::Vector2dF(0, -80));
+  EXPECT_EQ(1, helper_.set_stretch_amount_count());
+  EXPECT_EQ(1, helper_.request_begin_frame_count());
+  EXPECT_GT(-1.f, helper_.StretchAmount().y());
+
+  // Subsequent momentum events should do nothing.
+  SendGestureScrollUpdate(true, gfx::Vector2dF(0, -80), gfx::Vector2dF(0, -80));
+  SendGestureScrollUpdate(true, gfx::Vector2dF(0, -80), gfx::Vector2dF(0, -80));
+  SendGestureScrollUpdate(true, gfx::Vector2dF(0, -80), gfx::Vector2dF(0, -80));
+  SendGestureScrollEnd();
+  EXPECT_EQ(1, helper_.set_stretch_amount_count());
+  EXPECT_EQ(1, helper_.request_begin_frame_count());
+
+  // Subsequent animate events should update the stretch amount and request
+  // another frame.
+  TickCurrentTimeAndAnimate();
+  EXPECT_EQ(2, helper_.set_stretch_amount_count());
+  EXPECT_EQ(2, helper_.request_begin_frame_count());
+  EXPECT_GT(-1.f, helper_.StretchAmount().y());
+
+  // Touching the trackpad (a PhaseMayBegin event) should disable animation.
+  SendGestureScrollBegin(false);
+  TickCurrentTimeAndAnimate();
+  EXPECT_EQ(2, helper_.set_stretch_amount_count());
+  EXPECT_EQ(2, helper_.request_begin_frame_count());
+
+  // Releasing the trackpad should re-enable animation.
+  SendGestureScrollEnd();
+  EXPECT_EQ(2, helper_.set_stretch_amount_count());
+  EXPECT_EQ(3, helper_.request_begin_frame_count());
+  TickCurrentTimeAndAnimate();
+  EXPECT_EQ(3, helper_.set_stretch_amount_count());
+  EXPECT_EQ(4, helper_.request_begin_frame_count());
+
+  // Keep animating frames until the stretch returns to rest.
+  int stretch_count = 3;
+  int begin_frame_count = 4;
+  while (1) {
+    TickCurrentTimeAndAnimate();
+    if (helper_.StretchAmount().IsZero()) {
+      stretch_count += 1;
+      EXPECT_EQ(stretch_count, helper_.set_stretch_amount_count());
+      EXPECT_EQ(begin_frame_count, helper_.request_begin_frame_count());
+      break;
+    }
+    stretch_count += 1;
+    begin_frame_count += 1;
+    EXPECT_EQ(stretch_count, helper_.set_stretch_amount_count());
+    EXPECT_EQ(begin_frame_count, helper_.request_begin_frame_count());
+  }
+
+  // After coming to rest, no subsequent animate calls change anything.
+  TickCurrentTimeAndAnimate();
+  EXPECT_EQ(stretch_count, helper_.set_stretch_amount_count());
+  EXPECT_EQ(begin_frame_count, helper_.request_begin_frame_count());
+}
+
+// Verify that a stretch opposing a scroll is correctly resolved.
 TEST_F(ScrollElasticityControllerTest, ReconcileStretchAndScroll) {
   SendMouseWheelEvent(PhaseBegan, PhaseNone);
 
@@ -334,14 +548,50 @@
   EXPECT_EQ(helper_.ScrollOffset(), gfx::ScrollOffset(7, 8));
 }
 
+// Verify that a stretch opposing a scroll is correctly resolved.
+TEST_F(ScrollElasticityControllerTest, GestureBased_ReconcileStretchAndScroll) {
+  SendGestureScrollBegin(false);
+
+  // Verify completely knocking out the scroll in the -Y direction.
+  helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(5, 5),
+                                            gfx::ScrollOffset(10, 10));
+  helper_.SetStretchAmount(gfx::Vector2dF(0, -10));
+  controller_.ReconcileStretchAndScroll();
+  EXPECT_EQ(helper_.StretchAmount(), gfx::Vector2dF(0, -5));
+  EXPECT_EQ(helper_.ScrollOffset(), gfx::ScrollOffset(5, 0));
+
+  // Verify partially knocking out the scroll in the -Y direction.
+  helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(5, 8),
+                                            gfx::ScrollOffset(10, 10));
+  helper_.SetStretchAmount(gfx::Vector2dF(0, -5));
+  controller_.ReconcileStretchAndScroll();
+  EXPECT_EQ(helper_.StretchAmount(), gfx::Vector2dF(0, 0));
+  EXPECT_EQ(helper_.ScrollOffset(), gfx::ScrollOffset(5, 3));
+
+  // Verify completely knocking out the scroll in the +X direction.
+  helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(5, 5),
+                                            gfx::ScrollOffset(10, 10));
+  helper_.SetStretchAmount(gfx::Vector2dF(10, 0));
+  controller_.ReconcileStretchAndScroll();
+  EXPECT_EQ(helper_.StretchAmount(), gfx::Vector2dF(5, 0));
+  EXPECT_EQ(helper_.ScrollOffset(), gfx::ScrollOffset(10, 5));
+
+  // Verify partially knocking out the scroll in the +X and +Y directions.
+  helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(2, 3),
+                                            gfx::ScrollOffset(10, 10));
+  helper_.SetStretchAmount(gfx::Vector2dF(5, 5));
+  controller_.ReconcileStretchAndScroll();
+  EXPECT_EQ(helper_.StretchAmount(), gfx::Vector2dF(0, 0));
+  EXPECT_EQ(helper_.ScrollOffset(), gfx::ScrollOffset(7, 8));
+}
+
 // Verify that stretching only happens when the area is user scrollable.
 TEST_F(ScrollElasticityControllerTest, UserScrollableRequiredForStretch) {
   helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(0, 0),
                                             gfx::ScrollOffset(10, 10));
   gfx::Vector2dF delta(0, -15);
 
-  // Do an active scroll, and ensure that the stretch amount doesn't change,
-  // and also that the stretch amount isn't even ever changed.
+  // Do an active scroll, and ensure that the stretch amount doesn't change.
   helper_.SetUserScrollable(false);
   SendMouseWheelEvent(PhaseBegan, PhaseNone);
   SendMouseWheelEvent(PhaseChanged, PhaseNone, delta, delta);
@@ -384,5 +634,55 @@
   EXPECT_GT(ticks_to_zero, 3);
 }
 
+// Verify that stretching only happens when the area is user scrollable.
+TEST_F(ScrollElasticityControllerTest,
+       GestureBased_UserScrollableRequiredForStretch) {
+  helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(0, 0),
+                                            gfx::ScrollOffset(10, 10));
+  gfx::Vector2dF delta(0, -15);
+
+  // Do an active scroll, and ensure that the stretch amount doesn't change.
+  helper_.SetUserScrollable(false);
+  SendGestureScrollBegin(false);
+  SendGestureScrollUpdate(false, delta, delta);
+  SendGestureScrollUpdate(false, delta, delta);
+  SendGestureScrollEnd();
+  EXPECT_EQ(helper_.StretchAmount(), gfx::Vector2dF(0, 0));
+  EXPECT_EQ(0, helper_.set_stretch_amount_count());
+  SendGestureScrollBegin(true);
+  SendGestureScrollUpdate(true, delta, delta);
+  SendGestureScrollUpdate(true, delta, delta);
+  SendGestureScrollEnd();
+  EXPECT_EQ(helper_.StretchAmount(), gfx::Vector2dF(0, 0));
+  EXPECT_EQ(0, helper_.set_stretch_amount_count());
+
+  // Re-enable user scrolling and ensure that stretching is re-enabled.
+  helper_.SetUserScrollable(true);
+  SendGestureScrollBegin(false);
+  SendGestureScrollUpdate(false, delta, delta);
+  SendGestureScrollUpdate(false, delta, delta);
+  SendGestureScrollEnd();
+  EXPECT_NE(helper_.StretchAmount(), gfx::Vector2dF(0, 0));
+  EXPECT_GT(helper_.set_stretch_amount_count(), 0);
+  SendGestureScrollBegin(true);
+  SendGestureScrollUpdate(true, delta, delta);
+  SendGestureScrollUpdate(true, delta, delta);
+  SendGestureScrollEnd();
+  EXPECT_NE(helper_.StretchAmount(), gfx::Vector2dF(0, 0));
+  EXPECT_GT(helper_.set_stretch_amount_count(), 0);
+
+  // Disable user scrolling and tick the timer until the stretch goes back
+  // to zero. Ensure that the return to zero doesn't happen immediately.
+  helper_.SetUserScrollable(false);
+  int ticks_to_zero = 0;
+  while (1) {
+    TickCurrentTimeAndAnimate();
+    if (helper_.StretchAmount().IsZero())
+      break;
+    ticks_to_zero += 1;
+  }
+  EXPECT_GT(ticks_to_zero, 3);
+}
+
 }  // namespace
 }  // namespace ui
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn
index c342cc7..7115ef2 100644
--- a/ui/gfx/BUILD.gn
+++ b/ui/gfx/BUILD.gn
@@ -446,7 +446,6 @@
     "vector_icons/account_box.icon",
     "vector_icons/account_child_invert.icon",
     "vector_icons/apps.icon",
-    "vector_icons/autofill.icon",
     "vector_icons/autologin.icon",
     "vector_icons/bar_close.1x.icon",
     "vector_icons/bar_close.icon",
diff --git a/ui/gfx/canvas.cc b/ui/gfx/canvas.cc
index 80483eb..80b7df3 100644
--- a/ui/gfx/canvas.cc
+++ b/ui/gfx/canvas.cc
@@ -153,16 +153,10 @@
     }
   }
 
-  // Make a shader for the bitmap with an origin of the box we'll draw. This
-  // shader is refcounted and will have an initial refcount of 1.
-  skia::RefPtr<SkShader> shader = skia::AdoptRef(
-      SkShader::CreateBitmapShader(
-          *dots, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode));
-  // Assign the shader to the paint & release our reference. The paint will
-  // now own the shader and the shader will be destroyed when the paint goes
-  // out of scope.
+  // Make a shader for the bitmap with an origin of the box we'll draw.
   SkPaint paint;
-  paint.setShader(shader.get());
+  paint.setShader(SkShader::MakeBitmapShader(*dots, SkShader::kRepeat_TileMode,
+                                             SkShader::kRepeat_TileMode));
 
   DrawRect(Rect(rect.x(), rect.y(), rect.width(), 1), paint);
   DrawRect(Rect(rect.x(), rect.y() + rect.height() - 1, rect.width(), 1),
diff --git a/ui/gfx/native_widget_types.h b/ui/gfx/native_widget_types.h
index 82976302..406c223c 100644
--- a/ui/gfx/native_widget_types.h
+++ b/ui/gfx/native_widget_types.h
@@ -213,29 +213,6 @@
   const PluginWindowHandle kNullPluginWindow = 0;
 #endif
 
-enum SurfaceType {
-  EMPTY,
-  NATIVE_DIRECT,
-  NULL_TRANSPORT,
-  SURFACE_TYPE_LAST = NULL_TRANSPORT
-};
-
-struct GLSurfaceHandle {
-  GLSurfaceHandle() : handle(kNullPluginWindow), transport_type(EMPTY) {}
-  GLSurfaceHandle(PluginWindowHandle handle_, SurfaceType transport_)
-      : handle(handle_), transport_type(transport_) {
-    DCHECK(!is_null() || handle == kNullPluginWindow);
-    DCHECK(transport_type != NULL_TRANSPORT ||
-           handle == kNullPluginWindow);
-  }
-  bool is_null() const { return transport_type == EMPTY; }
-  bool is_transport() const {
-    return transport_type == NULL_TRANSPORT;
-  }
-  PluginWindowHandle handle;
-  SurfaceType transport_type;
-};
-
 // AcceleratedWidget provides a surface to compositors to paint pixels.
 #if defined(OS_WIN)
 typedef HWND AcceleratedWidget;
diff --git a/ui/gfx/screen_mac.mm b/ui/gfx/screen_mac.mm
index 1ee6938e..40077d11 100644
--- a/ui/gfx/screen_mac.mm
+++ b/ui/gfx/screen_mac.mm
@@ -16,6 +16,7 @@
 #include "base/timer/timer.h"
 #include "ui/gfx/display.h"
 #include "ui/gfx/display_change_notifier.h"
+#include "ui/gfx/mac/coordinate_conversion.h"
 
 namespace {
 
@@ -23,16 +24,6 @@
 // See comments in ScreenMac::HandleDisplayReconfiguration.
 const int64_t kConfigureDelayMs = 500;
 
-gfx::Rect ConvertCoordinateSystem(NSRect ns_rect) {
-  // Primary monitor is defined as the monitor with the menubar,
-  // which is always at index 0.
-  NSScreen* primary_screen = [[NSScreen screens] firstObject];
-  float primary_screen_height = [primary_screen frame].size.height;
-  gfx::Rect rect(NSRectToCGRect(ns_rect));
-  rect.set_y(primary_screen_height - rect.y() - rect.height());
-  return rect;
-}
-
 NSScreen* GetMatchingScreen(const gfx::Rect& match_rect) {
   // Default to the monitor with the current keyboard focus, in case
   // |match_rect| is not on any screen at all.
@@ -40,7 +31,7 @@
   int max_area = 0;
 
   for (NSScreen* screen in [NSScreen screens]) {
-    gfx::Rect monitor_area = ConvertCoordinateSystem([screen frame]);
+    gfx::Rect monitor_area = gfx::ScreenRectFromNSRect([screen frame]);
     gfx::Rect intersection = gfx::IntersectRects(monitor_area, match_rect);
     int area = intersection.width() * intersection.height();
     if (area > max_area) {
@@ -69,8 +60,8 @@
                     visible_frame.size.height);
     display.set_work_area(work_area);
   } else {
-    display.set_bounds(ConvertCoordinateSystem(frame));
-    display.set_work_area(ConvertCoordinateSystem(visible_frame));
+    display.set_bounds(gfx::ScreenRectFromNSRect(frame));
+    display.set_work_area(gfx::ScreenRectFromNSRect(visible_frame));
   }
   CGFloat scale = [screen backingScaleFactor];
 
@@ -99,11 +90,8 @@
   }
 
   gfx::Point GetCursorScreenPoint() override {
-    NSPoint mouseLocation  = [NSEvent mouseLocation];
     // Flip coordinates to gfx (0,0 in top-left corner) using primary screen.
-    NSScreen* screen = [[NSScreen screens] firstObject];
-    mouseLocation.y = NSMaxY([screen frame]) - mouseLocation.y;
-    return gfx::Point(mouseLocation.x, mouseLocation.y);
+    return gfx::ScreenPointFromNSPoint([NSEvent mouseLocation]);
   }
 
   gfx::NativeWindow GetWindowUnderCursor() override {
diff --git a/ui/gfx/vector_icons/autofill.icon b/ui/gfx/vector_icons/autofill.icon
deleted file mode 100644
index 8113350..0000000
--- a/ui/gfx/vector_icons/autofill.icon
+++ /dev/null
@@ -1,29 +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.
-
-MOVE_TO, 6, 34.5f,
-LINE_TO, 6, 42,
-LINE_TO, 13.5f, 42,
-LINE_TO, 35.63f, 19.87f,
-LINE_TO, 28.13f, 12.37f,
-LINE_TO, 6, 34.5f,
-LINE_TO, 6, 34.5f,
-CLOSE,
-MOVE_TO, 41.41f, 14.09f,
-CUBIC_TO, 42.2f, 13.3f, 42.2f, 12.04f, 41.41f, 11.26f,
-LINE_TO, 36.74f, 6.59f,
-CUBIC_TO, 35.96f, 5.8f, 34.7f, 5.8f, 33.91f, 6.59f,
-LINE_TO, 30.25f, 10.25f,
-LINE_TO, 37.75f, 17.75f,
-LINE_TO, 41.41f, 14.09f,
-LINE_TO, 41.41f, 14.09f,
-CLOSE,
-MOVE_TO, 24, 38,
-LINE_TO, 20, 42,
-LINE_TO, 42, 42,
-LINE_TO, 42, 38,
-LINE_TO, 24, 38,
-LINE_TO, 24, 38,
-CLOSE,
-END
diff --git a/ui/gl/generate_bindings.py b/ui/gl/generate_bindings.py
index b3158027..1cba0756 100755
--- a/ui/gl/generate_bindings.py
+++ b/ui/gl/generate_bindings.py
@@ -2174,6 +2174,8 @@
     if return_type == 'void':
       file.write('  GL_SERVICE_LOG("%s" << "(" %s << ")");\n' %
           (function_name, log_argument_names))
+      file.write('  DCHECK(g_driver_%s.debug_fn.%sFn != nullptr);\n' %
+          (set_name.lower(), function_name))
       file.write('  g_driver_%s.debug_fn.%sFn(%s);\n' %
           (set_name.lower(), function_name, argument_names))
       if 'logging_code' in func:
@@ -2186,6 +2188,8 @@
     else:
       file.write('  GL_SERVICE_LOG("%s" << "(" %s << ")");\n' %
           (function_name, log_argument_names))
+      file.write('  DCHECK(g_driver_%s.debug_fn.%sFn != nullptr);\n' %
+          (set_name.lower(), function_name))
       file.write('  %s result = g_driver_%s.debug_fn.%sFn(%s);\n' %
           (return_type, set_name.lower(), function_name, argument_names))
       if 'logging_code' in func:
diff --git a/ui/gl/gl_bindings_autogen_egl.cc b/ui/gl/gl_bindings_autogen_egl.cc
index 2bb0bfd8e..c2461d8 100644
--- a/ui/gl/gl_bindings_autogen_egl.cc
+++ b/ui/gl/gl_bindings_autogen_egl.cc
@@ -203,6 +203,7 @@
 static EGLBoolean GL_BINDING_CALL Debug_eglBindAPI(EGLenum api) {
   GL_SERVICE_LOG("eglBindAPI"
                  << "(" << api << ")");
+  DCHECK(g_driver_egl.debug_fn.eglBindAPIFn != nullptr);
   EGLBoolean result = g_driver_egl.debug_fn.eglBindAPIFn(api);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -213,6 +214,7 @@
                                                         EGLint buffer) {
   GL_SERVICE_LOG("eglBindTexImage"
                  << "(" << dpy << ", " << surface << ", " << buffer << ")");
+  DCHECK(g_driver_egl.debug_fn.eglBindTexImageFn != nullptr);
   EGLBoolean result =
       g_driver_egl.debug_fn.eglBindTexImageFn(dpy, surface, buffer);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -230,6 +232,7 @@
                  << ", " << static_cast<const void*>(configs) << ", "
                  << config_size << ", " << static_cast<const void*>(num_config)
                  << ")");
+  DCHECK(g_driver_egl.debug_fn.eglChooseConfigFn != nullptr);
   EGLBoolean result = g_driver_egl.debug_fn.eglChooseConfigFn(
       dpy, attrib_list, configs, config_size, num_config);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -243,6 +246,7 @@
   GL_SERVICE_LOG("eglClientWaitSyncKHR"
                  << "(" << dpy << ", " << sync << ", " << flags << ", "
                  << timeout << ")");
+  DCHECK(g_driver_egl.debug_fn.eglClientWaitSyncKHRFn != nullptr);
   EGLint result =
       g_driver_egl.debug_fn.eglClientWaitSyncKHRFn(dpy, sync, flags, timeout);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -255,6 +259,7 @@
                      EGLNativePixmapType target) {
   GL_SERVICE_LOG("eglCopyBuffers"
                  << "(" << dpy << ", " << surface << ", " << target << ")");
+  DCHECK(g_driver_egl.debug_fn.eglCopyBuffersFn != nullptr);
   EGLBoolean result =
       g_driver_egl.debug_fn.eglCopyBuffersFn(dpy, surface, target);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -269,6 +274,7 @@
   GL_SERVICE_LOG("eglCreateContext"
                  << "(" << dpy << ", " << config << ", " << share_context
                  << ", " << static_cast<const void*>(attrib_list) << ")");
+  DCHECK(g_driver_egl.debug_fn.eglCreateContextFn != nullptr);
   EGLContext result = g_driver_egl.debug_fn.eglCreateContextFn(
       dpy, config, share_context, attrib_list);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -285,6 +291,7 @@
                  << "(" << dpy << ", " << ctx << ", " << target << ", "
                  << buffer << ", " << static_cast<const void*>(attrib_list)
                  << ")");
+  DCHECK(g_driver_egl.debug_fn.eglCreateImageKHRFn != nullptr);
   EGLImageKHR result = g_driver_egl.debug_fn.eglCreateImageKHRFn(
       dpy, ctx, target, buffer, attrib_list);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -301,6 +308,7 @@
                  << "(" << dpy << ", " << buftype << ", "
                  << static_cast<const void*>(buffer) << ", " << config << ", "
                  << static_cast<const void*>(attrib_list) << ")");
+  DCHECK(g_driver_egl.debug_fn.eglCreatePbufferFromClientBufferFn != nullptr);
   EGLSurface result = g_driver_egl.debug_fn.eglCreatePbufferFromClientBufferFn(
       dpy, buftype, buffer, config, attrib_list);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -314,6 +322,7 @@
   GL_SERVICE_LOG("eglCreatePbufferSurface"
                  << "(" << dpy << ", " << config << ", "
                  << static_cast<const void*>(attrib_list) << ")");
+  DCHECK(g_driver_egl.debug_fn.eglCreatePbufferSurfaceFn != nullptr);
   EGLSurface result =
       g_driver_egl.debug_fn.eglCreatePbufferSurfaceFn(dpy, config, attrib_list);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -328,6 +337,7 @@
   GL_SERVICE_LOG("eglCreatePixmapSurface"
                  << "(" << dpy << ", " << config << ", " << pixmap << ", "
                  << static_cast<const void*>(attrib_list) << ")");
+  DCHECK(g_driver_egl.debug_fn.eglCreatePixmapSurfaceFn != nullptr);
   EGLSurface result = g_driver_egl.debug_fn.eglCreatePixmapSurfaceFn(
       dpy, config, pixmap, attrib_list);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -341,6 +351,7 @@
   GL_SERVICE_LOG("eglCreateSyncKHR"
                  << "(" << dpy << ", " << type << ", "
                  << static_cast<const void*>(attrib_list) << ")");
+  DCHECK(g_driver_egl.debug_fn.eglCreateSyncKHRFn != nullptr);
   EGLSyncKHR result =
       g_driver_egl.debug_fn.eglCreateSyncKHRFn(dpy, type, attrib_list);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -355,6 +366,7 @@
   GL_SERVICE_LOG("eglCreateWindowSurface"
                  << "(" << dpy << ", " << config << ", " << win << ", "
                  << static_cast<const void*>(attrib_list) << ")");
+  DCHECK(g_driver_egl.debug_fn.eglCreateWindowSurfaceFn != nullptr);
   EGLSurface result = g_driver_egl.debug_fn.eglCreateWindowSurfaceFn(
       dpy, config, win, attrib_list);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -365,6 +377,7 @@
                                                           EGLContext ctx) {
   GL_SERVICE_LOG("eglDestroyContext"
                  << "(" << dpy << ", " << ctx << ")");
+  DCHECK(g_driver_egl.debug_fn.eglDestroyContextFn != nullptr);
   EGLBoolean result = g_driver_egl.debug_fn.eglDestroyContextFn(dpy, ctx);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -374,6 +387,7 @@
                                                            EGLImageKHR image) {
   GL_SERVICE_LOG("eglDestroyImageKHR"
                  << "(" << dpy << ", " << image << ")");
+  DCHECK(g_driver_egl.debug_fn.eglDestroyImageKHRFn != nullptr);
   EGLBoolean result = g_driver_egl.debug_fn.eglDestroyImageKHRFn(dpy, image);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -383,6 +397,7 @@
                                                           EGLSurface surface) {
   GL_SERVICE_LOG("eglDestroySurface"
                  << "(" << dpy << ", " << surface << ")");
+  DCHECK(g_driver_egl.debug_fn.eglDestroySurfaceFn != nullptr);
   EGLBoolean result = g_driver_egl.debug_fn.eglDestroySurfaceFn(dpy, surface);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -392,6 +407,7 @@
                                                           EGLSyncKHR sync) {
   GL_SERVICE_LOG("eglDestroySyncKHR"
                  << "(" << dpy << ", " << sync << ")");
+  DCHECK(g_driver_egl.debug_fn.eglDestroySyncKHRFn != nullptr);
   EGLBoolean result = g_driver_egl.debug_fn.eglDestroySyncKHRFn(dpy, sync);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -404,6 +420,7 @@
   GL_SERVICE_LOG("eglGetConfigAttrib"
                  << "(" << dpy << ", " << config << ", " << attribute << ", "
                  << static_cast<const void*>(value) << ")");
+  DCHECK(g_driver_egl.debug_fn.eglGetConfigAttribFn != nullptr);
   EGLBoolean result =
       g_driver_egl.debug_fn.eglGetConfigAttribFn(dpy, config, attribute, value);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -418,6 +435,7 @@
                  << "(" << dpy << ", " << static_cast<const void*>(configs)
                  << ", " << config_size << ", "
                  << static_cast<const void*>(num_config) << ")");
+  DCHECK(g_driver_egl.debug_fn.eglGetConfigsFn != nullptr);
   EGLBoolean result = g_driver_egl.debug_fn.eglGetConfigsFn(
       dpy, configs, config_size, num_config);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -428,6 +446,7 @@
   GL_SERVICE_LOG("eglGetCurrentContext"
                  << "("
                  << ")");
+  DCHECK(g_driver_egl.debug_fn.eglGetCurrentContextFn != nullptr);
   EGLContext result = g_driver_egl.debug_fn.eglGetCurrentContextFn();
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -437,6 +456,7 @@
   GL_SERVICE_LOG("eglGetCurrentDisplay"
                  << "("
                  << ")");
+  DCHECK(g_driver_egl.debug_fn.eglGetCurrentDisplayFn != nullptr);
   EGLDisplay result = g_driver_egl.debug_fn.eglGetCurrentDisplayFn();
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -445,6 +465,7 @@
 static EGLSurface GL_BINDING_CALL Debug_eglGetCurrentSurface(EGLint readdraw) {
   GL_SERVICE_LOG("eglGetCurrentSurface"
                  << "(" << readdraw << ")");
+  DCHECK(g_driver_egl.debug_fn.eglGetCurrentSurfaceFn != nullptr);
   EGLSurface result = g_driver_egl.debug_fn.eglGetCurrentSurfaceFn(readdraw);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -454,6 +475,7 @@
 Debug_eglGetDisplay(EGLNativeDisplayType display_id) {
   GL_SERVICE_LOG("eglGetDisplay"
                  << "(" << display_id << ")");
+  DCHECK(g_driver_egl.debug_fn.eglGetDisplayFn != nullptr);
   EGLDisplay result = g_driver_egl.debug_fn.eglGetDisplayFn(display_id);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -463,6 +485,7 @@
   GL_SERVICE_LOG("eglGetError"
                  << "("
                  << ")");
+  DCHECK(g_driver_egl.debug_fn.eglGetErrorFn != nullptr);
   EGLint result = g_driver_egl.debug_fn.eglGetErrorFn();
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -476,6 +499,7 @@
                  << "(" << platform << ", "
                  << static_cast<const void*>(native_display) << ", "
                  << static_cast<const void*>(attrib_list) << ")");
+  DCHECK(g_driver_egl.debug_fn.eglGetPlatformDisplayEXTFn != nullptr);
   EGLDisplay result = g_driver_egl.debug_fn.eglGetPlatformDisplayEXTFn(
       platform, native_display, attrib_list);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -486,6 +510,7 @@
 Debug_eglGetProcAddress(const char* procname) {
   GL_SERVICE_LOG("eglGetProcAddress"
                  << "(" << procname << ")");
+  DCHECK(g_driver_egl.debug_fn.eglGetProcAddressFn != nullptr);
   __eglMustCastToProperFunctionPointerType result =
       g_driver_egl.debug_fn.eglGetProcAddressFn(procname);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -499,6 +524,7 @@
   GL_SERVICE_LOG("eglGetSyncAttribKHR"
                  << "(" << dpy << ", " << sync << ", " << attribute << ", "
                  << static_cast<const void*>(value) << ")");
+  DCHECK(g_driver_egl.debug_fn.eglGetSyncAttribKHRFn != nullptr);
   EGLBoolean result =
       g_driver_egl.debug_fn.eglGetSyncAttribKHRFn(dpy, sync, attribute, value);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -516,6 +542,7 @@
                  << static_cast<const void*>(ust) << ", "
                  << static_cast<const void*>(msc) << ", "
                  << static_cast<const void*>(sbc) << ")");
+  DCHECK(g_driver_egl.debug_fn.eglGetSyncValuesCHROMIUMFn != nullptr);
   EGLBoolean result = g_driver_egl.debug_fn.eglGetSyncValuesCHROMIUMFn(
       dpy, surface, ust, msc, sbc);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -528,6 +555,7 @@
   GL_SERVICE_LOG("eglInitialize"
                  << "(" << dpy << ", " << static_cast<const void*>(major)
                  << ", " << static_cast<const void*>(minor) << ")");
+  DCHECK(g_driver_egl.debug_fn.eglInitializeFn != nullptr);
   EGLBoolean result = g_driver_egl.debug_fn.eglInitializeFn(dpy, major, minor);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -540,6 +568,7 @@
   GL_SERVICE_LOG("eglMakeCurrent"
                  << "(" << dpy << ", " << draw << ", " << read << ", " << ctx
                  << ")");
+  DCHECK(g_driver_egl.debug_fn.eglMakeCurrentFn != nullptr);
   EGLBoolean result =
       g_driver_egl.debug_fn.eglMakeCurrentFn(dpy, draw, read, ctx);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -555,6 +584,7 @@
   GL_SERVICE_LOG("eglPostSubBufferNV"
                  << "(" << dpy << ", " << surface << ", " << x << ", " << y
                  << ", " << width << ", " << height << ")");
+  DCHECK(g_driver_egl.debug_fn.eglPostSubBufferNVFn != nullptr);
   EGLBoolean result = g_driver_egl.debug_fn.eglPostSubBufferNVFn(
       dpy, surface, x, y, width, height);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -565,6 +595,7 @@
   GL_SERVICE_LOG("eglQueryAPI"
                  << "("
                  << ")");
+  DCHECK(g_driver_egl.debug_fn.eglQueryAPIFn != nullptr);
   EGLenum result = g_driver_egl.debug_fn.eglQueryAPIFn();
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -577,6 +608,7 @@
   GL_SERVICE_LOG("eglQueryContext"
                  << "(" << dpy << ", " << ctx << ", " << attribute << ", "
                  << static_cast<const void*>(value) << ")");
+  DCHECK(g_driver_egl.debug_fn.eglQueryContextFn != nullptr);
   EGLBoolean result =
       g_driver_egl.debug_fn.eglQueryContextFn(dpy, ctx, attribute, value);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -587,6 +619,7 @@
                                                         EGLint name) {
   GL_SERVICE_LOG("eglQueryString"
                  << "(" << dpy << ", " << name << ")");
+  DCHECK(g_driver_egl.debug_fn.eglQueryStringFn != nullptr);
   const char* result = g_driver_egl.debug_fn.eglQueryStringFn(dpy, name);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -599,6 +632,7 @@
   GL_SERVICE_LOG("eglQuerySurface"
                  << "(" << dpy << ", " << surface << ", " << attribute << ", "
                  << static_cast<const void*>(value) << ")");
+  DCHECK(g_driver_egl.debug_fn.eglQuerySurfaceFn != nullptr);
   EGLBoolean result =
       g_driver_egl.debug_fn.eglQuerySurfaceFn(dpy, surface, attribute, value);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -613,6 +647,7 @@
   GL_SERVICE_LOG("eglQuerySurfacePointerANGLE"
                  << "(" << dpy << ", " << surface << ", " << attribute << ", "
                  << value << ")");
+  DCHECK(g_driver_egl.debug_fn.eglQuerySurfacePointerANGLEFn != nullptr);
   EGLBoolean result = g_driver_egl.debug_fn.eglQuerySurfacePointerANGLEFn(
       dpy, surface, attribute, value);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -624,6 +659,7 @@
                                                            EGLint buffer) {
   GL_SERVICE_LOG("eglReleaseTexImage"
                  << "(" << dpy << ", " << surface << ", " << buffer << ")");
+  DCHECK(g_driver_egl.debug_fn.eglReleaseTexImageFn != nullptr);
   EGLBoolean result =
       g_driver_egl.debug_fn.eglReleaseTexImageFn(dpy, surface, buffer);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -634,6 +670,7 @@
   GL_SERVICE_LOG("eglReleaseThread"
                  << "("
                  << ")");
+  DCHECK(g_driver_egl.debug_fn.eglReleaseThreadFn != nullptr);
   EGLBoolean result = g_driver_egl.debug_fn.eglReleaseThreadFn();
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -646,6 +683,7 @@
   GL_SERVICE_LOG("eglSurfaceAttrib"
                  << "(" << dpy << ", " << surface << ", " << attribute << ", "
                  << value << ")");
+  DCHECK(g_driver_egl.debug_fn.eglSurfaceAttribFn != nullptr);
   EGLBoolean result =
       g_driver_egl.debug_fn.eglSurfaceAttribFn(dpy, surface, attribute, value);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -656,6 +694,7 @@
                                                        EGLSurface surface) {
   GL_SERVICE_LOG("eglSwapBuffers"
                  << "(" << dpy << ", " << surface << ")");
+  DCHECK(g_driver_egl.debug_fn.eglSwapBuffersFn != nullptr);
   EGLBoolean result = g_driver_egl.debug_fn.eglSwapBuffersFn(dpy, surface);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -665,6 +704,7 @@
                                                         EGLint interval) {
   GL_SERVICE_LOG("eglSwapInterval"
                  << "(" << dpy << ", " << interval << ")");
+  DCHECK(g_driver_egl.debug_fn.eglSwapIntervalFn != nullptr);
   EGLBoolean result = g_driver_egl.debug_fn.eglSwapIntervalFn(dpy, interval);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -673,6 +713,7 @@
 static EGLBoolean GL_BINDING_CALL Debug_eglTerminate(EGLDisplay dpy) {
   GL_SERVICE_LOG("eglTerminate"
                  << "(" << dpy << ")");
+  DCHECK(g_driver_egl.debug_fn.eglTerminateFn != nullptr);
   EGLBoolean result = g_driver_egl.debug_fn.eglTerminateFn(dpy);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -682,6 +723,7 @@
   GL_SERVICE_LOG("eglWaitClient"
                  << "("
                  << ")");
+  DCHECK(g_driver_egl.debug_fn.eglWaitClientFn != nullptr);
   EGLBoolean result = g_driver_egl.debug_fn.eglWaitClientFn();
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -691,6 +733,7 @@
   GL_SERVICE_LOG("eglWaitGL"
                  << "("
                  << ")");
+  DCHECK(g_driver_egl.debug_fn.eglWaitGLFn != nullptr);
   EGLBoolean result = g_driver_egl.debug_fn.eglWaitGLFn();
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -699,6 +742,7 @@
 static EGLBoolean GL_BINDING_CALL Debug_eglWaitNative(EGLint engine) {
   GL_SERVICE_LOG("eglWaitNative"
                  << "(" << engine << ")");
+  DCHECK(g_driver_egl.debug_fn.eglWaitNativeFn != nullptr);
   EGLBoolean result = g_driver_egl.debug_fn.eglWaitNativeFn(engine);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -709,6 +753,7 @@
                                                    EGLint flags) {
   GL_SERVICE_LOG("eglWaitSyncKHR"
                  << "(" << dpy << ", " << sync << ", " << flags << ")");
+  DCHECK(g_driver_egl.debug_fn.eglWaitSyncKHRFn != nullptr);
   EGLint result = g_driver_egl.debug_fn.eglWaitSyncKHRFn(dpy, sync, flags);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
diff --git a/ui/gl/gl_bindings_autogen_gl.cc b/ui/gl/gl_bindings_autogen_gl.cc
index 00cdc811..63c1f23 100644
--- a/ui/gl/gl_bindings_autogen_gl.cc
+++ b/ui/gl/gl_bindings_autogen_gl.cc
@@ -2036,6 +2036,7 @@
 static void GL_BINDING_CALL Debug_glActiveTexture(GLenum texture) {
   GL_SERVICE_LOG("glActiveTexture"
                  << "(" << GLEnums::GetStringEnum(texture) << ")");
+  DCHECK(g_driver_gl.debug_fn.glActiveTextureFn != nullptr);
   g_driver_gl.debug_fn.glActiveTextureFn(texture);
 }
 
@@ -2043,6 +2044,8 @@
   GL_SERVICE_LOG("glApplyFramebufferAttachmentCMAAINTEL"
                  << "("
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glApplyFramebufferAttachmentCMAAINTELFn !=
+         nullptr);
   g_driver_gl.debug_fn.glApplyFramebufferAttachmentCMAAINTELFn();
 }
 
@@ -2050,12 +2053,14 @@
                                                  GLuint shader) {
   GL_SERVICE_LOG("glAttachShader"
                  << "(" << program << ", " << shader << ")");
+  DCHECK(g_driver_gl.debug_fn.glAttachShaderFn != nullptr);
   g_driver_gl.debug_fn.glAttachShaderFn(program, shader);
 }
 
 static void GL_BINDING_CALL Debug_glBeginQuery(GLenum target, GLuint id) {
   GL_SERVICE_LOG("glBeginQuery"
                  << "(" << GLEnums::GetStringEnum(target) << ", " << id << ")");
+  DCHECK(g_driver_gl.debug_fn.glBeginQueryFn != nullptr);
   g_driver_gl.debug_fn.glBeginQueryFn(target, id);
 }
 
@@ -2063,6 +2068,7 @@
 Debug_glBeginTransformFeedback(GLenum primitiveMode) {
   GL_SERVICE_LOG("glBeginTransformFeedback"
                  << "(" << GLEnums::GetStringEnum(primitiveMode) << ")");
+  DCHECK(g_driver_gl.debug_fn.glBeginTransformFeedbackFn != nullptr);
   g_driver_gl.debug_fn.glBeginTransformFeedbackFn(primitiveMode);
 }
 
@@ -2071,6 +2077,7 @@
                                                        const char* name) {
   GL_SERVICE_LOG("glBindAttribLocation"
                  << "(" << program << ", " << index << ", " << name << ")");
+  DCHECK(g_driver_gl.debug_fn.glBindAttribLocationFn != nullptr);
   g_driver_gl.debug_fn.glBindAttribLocationFn(program, index, name);
 }
 
@@ -2078,6 +2085,7 @@
   GL_SERVICE_LOG("glBindBuffer"
                  << "(" << GLEnums::GetStringEnum(target) << ", " << buffer
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glBindBufferFn != nullptr);
   g_driver_gl.debug_fn.glBindBufferFn(target, buffer);
 }
 
@@ -2087,6 +2095,7 @@
   GL_SERVICE_LOG("glBindBufferBase"
                  << "(" << GLEnums::GetStringEnum(target) << ", " << index
                  << ", " << buffer << ")");
+  DCHECK(g_driver_gl.debug_fn.glBindBufferBaseFn != nullptr);
   g_driver_gl.debug_fn.glBindBufferBaseFn(target, index, buffer);
 }
 
@@ -2098,6 +2107,7 @@
   GL_SERVICE_LOG("glBindBufferRange"
                  << "(" << GLEnums::GetStringEnum(target) << ", " << index
                  << ", " << buffer << ", " << offset << ", " << size << ")");
+  DCHECK(g_driver_gl.debug_fn.glBindBufferRangeFn != nullptr);
   g_driver_gl.debug_fn.glBindBufferRangeFn(target, index, buffer, offset, size);
 }
 
@@ -2107,6 +2117,7 @@
   GL_SERVICE_LOG("glBindFragDataLocation"
                  << "(" << program << ", " << colorNumber << ", " << name
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glBindFragDataLocationFn != nullptr);
   g_driver_gl.debug_fn.glBindFragDataLocationFn(program, colorNumber, name);
 }
 
@@ -2118,6 +2129,7 @@
   GL_SERVICE_LOG("glBindFragDataLocationIndexed"
                  << "(" << program << ", " << colorNumber << ", " << index
                  << ", " << name << ")");
+  DCHECK(g_driver_gl.debug_fn.glBindFragDataLocationIndexedFn != nullptr);
   g_driver_gl.debug_fn.glBindFragDataLocationIndexedFn(program, colorNumber,
                                                        index, name);
 }
@@ -2127,6 +2139,7 @@
   GL_SERVICE_LOG("glBindFramebufferEXT"
                  << "(" << GLEnums::GetStringEnum(target) << ", " << framebuffer
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glBindFramebufferEXTFn != nullptr);
   g_driver_gl.debug_fn.glBindFramebufferEXTFn(target, framebuffer);
 }
 
@@ -2141,6 +2154,7 @@
                  << "(" << index << ", " << texture << ", " << level << ", "
                  << GLEnums::GetStringBool(layered) << ", " << layer << ", "
                  << GLEnums::GetStringEnum(access) << ", " << format << ")");
+  DCHECK(g_driver_gl.debug_fn.glBindImageTextureEXTFn != nullptr);
   g_driver_gl.debug_fn.glBindImageTextureEXTFn(index, texture, level, layered,
                                                layer, access, format);
 }
@@ -2150,12 +2164,14 @@
   GL_SERVICE_LOG("glBindRenderbufferEXT"
                  << "(" << GLEnums::GetStringEnum(target) << ", "
                  << renderbuffer << ")");
+  DCHECK(g_driver_gl.debug_fn.glBindRenderbufferEXTFn != nullptr);
   g_driver_gl.debug_fn.glBindRenderbufferEXTFn(target, renderbuffer);
 }
 
 static void GL_BINDING_CALL Debug_glBindSampler(GLuint unit, GLuint sampler) {
   GL_SERVICE_LOG("glBindSampler"
                  << "(" << unit << ", " << sampler << ")");
+  DCHECK(g_driver_gl.debug_fn.glBindSamplerFn != nullptr);
   g_driver_gl.debug_fn.glBindSamplerFn(unit, sampler);
 }
 
@@ -2163,6 +2179,7 @@
   GL_SERVICE_LOG("glBindTexture"
                  << "(" << GLEnums::GetStringEnum(target) << ", " << texture
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glBindTextureFn != nullptr);
   g_driver_gl.debug_fn.glBindTextureFn(target, texture);
 }
 
@@ -2170,12 +2187,14 @@
                                                           GLuint id) {
   GL_SERVICE_LOG("glBindTransformFeedback"
                  << "(" << GLEnums::GetStringEnum(target) << ", " << id << ")");
+  DCHECK(g_driver_gl.debug_fn.glBindTransformFeedbackFn != nullptr);
   g_driver_gl.debug_fn.glBindTransformFeedbackFn(target, id);
 }
 
 static void GL_BINDING_CALL Debug_glBindVertexArrayOES(GLuint array) {
   GL_SERVICE_LOG("glBindVertexArrayOES"
                  << "(" << array << ")");
+  DCHECK(g_driver_gl.debug_fn.glBindVertexArrayOESFn != nullptr);
   g_driver_gl.debug_fn.glBindVertexArrayOESFn(array);
 }
 
@@ -2183,6 +2202,7 @@
   GL_SERVICE_LOG("glBlendBarrierKHR"
                  << "("
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glBlendBarrierKHRFn != nullptr);
   g_driver_gl.debug_fn.glBlendBarrierKHRFn();
 }
 
@@ -2193,12 +2213,14 @@
   GL_SERVICE_LOG("glBlendColor"
                  << "(" << red << ", " << green << ", " << blue << ", " << alpha
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glBlendColorFn != nullptr);
   g_driver_gl.debug_fn.glBlendColorFn(red, green, blue, alpha);
 }
 
 static void GL_BINDING_CALL Debug_glBlendEquation(GLenum mode) {
   GL_SERVICE_LOG("glBlendEquation"
                  << "(" << GLEnums::GetStringEnum(mode) << ")");
+  DCHECK(g_driver_gl.debug_fn.glBlendEquationFn != nullptr);
   g_driver_gl.debug_fn.glBlendEquationFn(mode);
 }
 
@@ -2207,6 +2229,7 @@
   GL_SERVICE_LOG("glBlendEquationSeparate"
                  << "(" << GLEnums::GetStringEnum(modeRGB) << ", "
                  << GLEnums::GetStringEnum(modeAlpha) << ")");
+  DCHECK(g_driver_gl.debug_fn.glBlendEquationSeparateFn != nullptr);
   g_driver_gl.debug_fn.glBlendEquationSeparateFn(modeRGB, modeAlpha);
 }
 
@@ -2214,6 +2237,7 @@
   GL_SERVICE_LOG("glBlendFunc"
                  << "(" << GLEnums::GetStringEnum(sfactor) << ", "
                  << GLEnums::GetStringEnum(dfactor) << ")");
+  DCHECK(g_driver_gl.debug_fn.glBlendFuncFn != nullptr);
   g_driver_gl.debug_fn.glBlendFuncFn(sfactor, dfactor);
 }
 
@@ -2226,6 +2250,7 @@
                  << GLEnums::GetStringEnum(dstRGB) << ", "
                  << GLEnums::GetStringEnum(srcAlpha) << ", "
                  << GLEnums::GetStringEnum(dstAlpha) << ")");
+  DCHECK(g_driver_gl.debug_fn.glBlendFuncSeparateFn != nullptr);
   g_driver_gl.debug_fn.glBlendFuncSeparateFn(srcRGB, dstRGB, srcAlpha,
                                              dstAlpha);
 }
@@ -2245,6 +2270,7 @@
                  << srcY1 << ", " << dstX0 << ", " << dstY0 << ", " << dstX1
                  << ", " << dstY1 << ", " << mask << ", "
                  << GLEnums::GetStringEnum(filter) << ")");
+  DCHECK(g_driver_gl.debug_fn.glBlitFramebufferFn != nullptr);
   g_driver_gl.debug_fn.glBlitFramebufferFn(srcX0, srcY0, srcX1, srcY1, dstX0,
                                            dstY0, dstX1, dstY1, mask, filter);
 }
@@ -2264,6 +2290,7 @@
                  << srcY1 << ", " << dstX0 << ", " << dstY0 << ", " << dstX1
                  << ", " << dstY1 << ", " << mask << ", "
                  << GLEnums::GetStringEnum(filter) << ")");
+  DCHECK(g_driver_gl.debug_fn.glBlitFramebufferANGLEFn != nullptr);
   g_driver_gl.debug_fn.glBlitFramebufferANGLEFn(
       srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
 }
@@ -2283,6 +2310,7 @@
                  << srcY1 << ", " << dstX0 << ", " << dstY0 << ", " << dstX1
                  << ", " << dstY1 << ", " << mask << ", "
                  << GLEnums::GetStringEnum(filter) << ")");
+  DCHECK(g_driver_gl.debug_fn.glBlitFramebufferEXTFn != nullptr);
   g_driver_gl.debug_fn.glBlitFramebufferEXTFn(
       srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
 }
@@ -2295,6 +2323,7 @@
                  << "(" << GLEnums::GetStringEnum(target) << ", " << size
                  << ", " << static_cast<const void*>(data) << ", "
                  << GLEnums::GetStringEnum(usage) << ")");
+  DCHECK(g_driver_gl.debug_fn.glBufferDataFn != nullptr);
   g_driver_gl.debug_fn.glBufferDataFn(target, size, data, usage);
 }
 
@@ -2306,12 +2335,14 @@
                  << "(" << GLEnums::GetStringEnum(target) << ", " << offset
                  << ", " << size << ", " << static_cast<const void*>(data)
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glBufferSubDataFn != nullptr);
   g_driver_gl.debug_fn.glBufferSubDataFn(target, offset, size, data);
 }
 
 static GLenum GL_BINDING_CALL Debug_glCheckFramebufferStatusEXT(GLenum target) {
   GL_SERVICE_LOG("glCheckFramebufferStatusEXT"
                  << "(" << GLEnums::GetStringEnum(target) << ")");
+  DCHECK(g_driver_gl.debug_fn.glCheckFramebufferStatusEXTFn != nullptr);
   GLenum result = g_driver_gl.debug_fn.glCheckFramebufferStatusEXTFn(target);
 
   GL_SERVICE_LOG("GL_RESULT: " << GLEnums::GetStringEnum(result));
@@ -2322,6 +2353,7 @@
 static void GL_BINDING_CALL Debug_glClear(GLbitfield mask) {
   GL_SERVICE_LOG("glClear"
                  << "(" << mask << ")");
+  DCHECK(g_driver_gl.debug_fn.glClearFn != nullptr);
   g_driver_gl.debug_fn.glClearFn(mask);
 }
 
@@ -2332,6 +2364,7 @@
   GL_SERVICE_LOG("glClearBufferfi"
                  << "(" << GLEnums::GetStringEnum(buffer) << ", " << drawbuffer
                  << ", " << depth << ", " << stencil << ")");
+  DCHECK(g_driver_gl.debug_fn.glClearBufferfiFn != nullptr);
   g_driver_gl.debug_fn.glClearBufferfiFn(buffer, drawbuffer, depth, stencil);
 }
 
@@ -2341,6 +2374,7 @@
   GL_SERVICE_LOG("glClearBufferfv"
                  << "(" << GLEnums::GetStringEnum(buffer) << ", " << drawbuffer
                  << ", " << static_cast<const void*>(value) << ")");
+  DCHECK(g_driver_gl.debug_fn.glClearBufferfvFn != nullptr);
   g_driver_gl.debug_fn.glClearBufferfvFn(buffer, drawbuffer, value);
 }
 
@@ -2350,6 +2384,7 @@
   GL_SERVICE_LOG("glClearBufferiv"
                  << "(" << GLEnums::GetStringEnum(buffer) << ", " << drawbuffer
                  << ", " << static_cast<const void*>(value) << ")");
+  DCHECK(g_driver_gl.debug_fn.glClearBufferivFn != nullptr);
   g_driver_gl.debug_fn.glClearBufferivFn(buffer, drawbuffer, value);
 }
 
@@ -2359,6 +2394,7 @@
   GL_SERVICE_LOG("glClearBufferuiv"
                  << "(" << GLEnums::GetStringEnum(buffer) << ", " << drawbuffer
                  << ", " << static_cast<const void*>(value) << ")");
+  DCHECK(g_driver_gl.debug_fn.glClearBufferuivFn != nullptr);
   g_driver_gl.debug_fn.glClearBufferuivFn(buffer, drawbuffer, value);
 }
 
@@ -2369,24 +2405,28 @@
   GL_SERVICE_LOG("glClearColor"
                  << "(" << red << ", " << green << ", " << blue << ", " << alpha
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glClearColorFn != nullptr);
   g_driver_gl.debug_fn.glClearColorFn(red, green, blue, alpha);
 }
 
 static void GL_BINDING_CALL Debug_glClearDepth(GLclampd depth) {
   GL_SERVICE_LOG("glClearDepth"
                  << "(" << depth << ")");
+  DCHECK(g_driver_gl.debug_fn.glClearDepthFn != nullptr);
   g_driver_gl.debug_fn.glClearDepthFn(depth);
 }
 
 static void GL_BINDING_CALL Debug_glClearDepthf(GLclampf depth) {
   GL_SERVICE_LOG("glClearDepthf"
                  << "(" << depth << ")");
+  DCHECK(g_driver_gl.debug_fn.glClearDepthfFn != nullptr);
   g_driver_gl.debug_fn.glClearDepthfFn(depth);
 }
 
 static void GL_BINDING_CALL Debug_glClearStencil(GLint s) {
   GL_SERVICE_LOG("glClearStencil"
                  << "(" << s << ")");
+  DCHECK(g_driver_gl.debug_fn.glClearStencilFn != nullptr);
   g_driver_gl.debug_fn.glClearStencilFn(s);
 }
 
@@ -2395,6 +2435,7 @@
                                                      GLuint64 timeout) {
   GL_SERVICE_LOG("glClientWaitSync"
                  << "(" << sync << ", " << flags << ", " << timeout << ")");
+  DCHECK(g_driver_gl.debug_fn.glClientWaitSyncFn != nullptr);
   GLenum result = g_driver_gl.debug_fn.glClientWaitSyncFn(sync, flags, timeout);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -2409,12 +2450,14 @@
                  << GLEnums::GetStringBool(green) << ", "
                  << GLEnums::GetStringBool(blue) << ", "
                  << GLEnums::GetStringBool(alpha) << ")");
+  DCHECK(g_driver_gl.debug_fn.glColorMaskFn != nullptr);
   g_driver_gl.debug_fn.glColorMaskFn(red, green, blue, alpha);
 }
 
 static void GL_BINDING_CALL Debug_glCompileShader(GLuint shader) {
   GL_SERVICE_LOG("glCompileShader"
                  << "(" << shader << ")");
+  DCHECK(g_driver_gl.debug_fn.glCompileShaderFn != nullptr);
   g_driver_gl.debug_fn.glCompileShaderFn(shader);
 }
 
@@ -2431,6 +2474,7 @@
                  << ", " << GLEnums::GetStringEnum(internalformat) << ", "
                  << width << ", " << height << ", " << border << ", "
                  << imageSize << ", " << static_cast<const void*>(data) << ")");
+  DCHECK(g_driver_gl.debug_fn.glCompressedTexImage2DFn != nullptr);
   g_driver_gl.debug_fn.glCompressedTexImage2DFn(
       target, level, internalformat, width, height, border, imageSize, data);
 }
@@ -2450,6 +2494,7 @@
                  << width << ", " << height << ", " << depth << ", " << border
                  << ", " << imageSize << ", " << static_cast<const void*>(data)
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glCompressedTexImage3DFn != nullptr);
   g_driver_gl.debug_fn.glCompressedTexImage3DFn(target, level, internalformat,
                                                 width, height, depth, border,
                                                 imageSize, data);
@@ -2469,6 +2514,7 @@
                  << ", " << xoffset << ", " << yoffset << ", " << width << ", "
                  << height << ", " << GLEnums::GetStringEnum(format) << ", "
                  << imageSize << ", " << static_cast<const void*>(data) << ")");
+  DCHECK(g_driver_gl.debug_fn.glCompressedTexSubImage2DFn != nullptr);
   g_driver_gl.debug_fn.glCompressedTexSubImage2DFn(
       target, level, xoffset, yoffset, width, height, format, imageSize, data);
 }
@@ -2490,6 +2536,7 @@
                  << ", " << width << ", " << height << ", " << depth << ", "
                  << GLEnums::GetStringEnum(format) << ", " << imageSize << ", "
                  << static_cast<const void*>(data) << ")");
+  DCHECK(g_driver_gl.debug_fn.glCompressedTexSubImage3DFn != nullptr);
   g_driver_gl.debug_fn.glCompressedTexSubImage3DFn(
       target, level, xoffset, yoffset, zoffset, width, height, depth, format,
       imageSize, data);
@@ -2504,6 +2551,7 @@
                  << "(" << GLEnums::GetStringEnum(readTarget) << ", "
                  << GLEnums::GetStringEnum(writeTarget) << ", " << readOffset
                  << ", " << writeOffset << ", " << size << ")");
+  DCHECK(g_driver_gl.debug_fn.glCopyBufferSubDataFn != nullptr);
   g_driver_gl.debug_fn.glCopyBufferSubDataFn(readTarget, writeTarget,
                                              readOffset, writeOffset, size);
 }
@@ -2521,6 +2569,7 @@
                  << ", " << GLEnums::GetStringEnum(internalformat) << ", " << x
                  << ", " << y << ", " << width << ", " << height << ", "
                  << border << ")");
+  DCHECK(g_driver_gl.debug_fn.glCopyTexImage2DFn != nullptr);
   g_driver_gl.debug_fn.glCopyTexImage2DFn(target, level, internalformat, x, y,
                                           width, height, border);
 }
@@ -2537,6 +2586,7 @@
                  << "(" << GLEnums::GetStringEnum(target) << ", " << level
                  << ", " << xoffset << ", " << yoffset << ", " << x << ", " << y
                  << ", " << width << ", " << height << ")");
+  DCHECK(g_driver_gl.debug_fn.glCopyTexSubImage2DFn != nullptr);
   g_driver_gl.debug_fn.glCopyTexSubImage2DFn(target, level, xoffset, yoffset, x,
                                              y, width, height);
 }
@@ -2555,6 +2605,7 @@
                  << ", " << xoffset << ", " << yoffset << ", " << zoffset
                  << ", " << x << ", " << y << ", " << width << ", " << height
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glCopyTexSubImage3DFn != nullptr);
   g_driver_gl.debug_fn.glCopyTexSubImage3DFn(target, level, xoffset, yoffset,
                                              zoffset, x, y, width, height);
 }
@@ -2562,6 +2613,7 @@
 static void GL_BINDING_CALL Debug_glCoverageModulationNV(GLenum components) {
   GL_SERVICE_LOG("glCoverageModulationNV"
                  << "(" << GLEnums::GetStringEnum(components) << ")");
+  DCHECK(g_driver_gl.debug_fn.glCoverageModulationNVFn != nullptr);
   g_driver_gl.debug_fn.glCoverageModulationNVFn(components);
 }
 
@@ -2580,6 +2632,7 @@
                  << GLEnums::GetStringEnum(coverMode) << ", "
                  << GLEnums::GetStringEnum(transformType) << ", "
                  << static_cast<const void*>(transformValues) << ")");
+  DCHECK(g_driver_gl.debug_fn.glCoverFillPathInstancedNVFn != nullptr);
   g_driver_gl.debug_fn.glCoverFillPathInstancedNVFn(
       numPaths, pathNameType, paths, pathBase, coverMode, transformType,
       transformValues);
@@ -2590,6 +2643,7 @@
   GL_SERVICE_LOG("glCoverFillPathNV"
                  << "(" << path << ", " << GLEnums::GetStringEnum(coverMode)
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glCoverFillPathNVFn != nullptr);
   g_driver_gl.debug_fn.glCoverFillPathNVFn(path, coverMode);
 }
 
@@ -2608,6 +2662,7 @@
                  << GLEnums::GetStringEnum(coverMode) << ", "
                  << GLEnums::GetStringEnum(transformType) << ", "
                  << static_cast<const void*>(transformValues) << ")");
+  DCHECK(g_driver_gl.debug_fn.glCoverStrokePathInstancedNVFn != nullptr);
   g_driver_gl.debug_fn.glCoverStrokePathInstancedNVFn(
       numPaths, pathNameType, paths, pathBase, coverMode, transformType,
       transformValues);
@@ -2618,6 +2673,7 @@
   GL_SERVICE_LOG("glCoverStrokePathNV"
                  << "(" << name << ", " << GLEnums::GetStringEnum(coverMode)
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glCoverStrokePathNVFn != nullptr);
   g_driver_gl.debug_fn.glCoverStrokePathNVFn(name, coverMode);
 }
 
@@ -2625,6 +2681,7 @@
   GL_SERVICE_LOG("glCreateProgram"
                  << "("
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glCreateProgramFn != nullptr);
   GLuint result = g_driver_gl.debug_fn.glCreateProgramFn();
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -2633,6 +2690,7 @@
 static GLuint GL_BINDING_CALL Debug_glCreateShader(GLenum type) {
   GL_SERVICE_LOG("glCreateShader"
                  << "(" << GLEnums::GetStringEnum(type) << ")");
+  DCHECK(g_driver_gl.debug_fn.glCreateShaderFn != nullptr);
   GLuint result = g_driver_gl.debug_fn.glCreateShaderFn(type);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -2641,6 +2699,7 @@
 static void GL_BINDING_CALL Debug_glCullFace(GLenum mode) {
   GL_SERVICE_LOG("glCullFace"
                  << "(" << GLEnums::GetStringEnum(mode) << ")");
+  DCHECK(g_driver_gl.debug_fn.glCullFaceFn != nullptr);
   g_driver_gl.debug_fn.glCullFaceFn(mode);
 }
 
@@ -2649,6 +2708,7 @@
   GL_SERVICE_LOG("glDeleteBuffersARB"
                  << "(" << n << ", " << static_cast<const void*>(buffers)
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glDeleteBuffersARBFn != nullptr);
   g_driver_gl.debug_fn.glDeleteBuffersARBFn(n, buffers);
 }
 
@@ -2657,6 +2717,7 @@
   GL_SERVICE_LOG("glDeleteFencesAPPLE"
                  << "(" << n << ", " << static_cast<const void*>(fences)
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glDeleteFencesAPPLEFn != nullptr);
   g_driver_gl.debug_fn.glDeleteFencesAPPLEFn(n, fences);
 }
 
@@ -2665,6 +2726,7 @@
   GL_SERVICE_LOG("glDeleteFencesNV"
                  << "(" << n << ", " << static_cast<const void*>(fences)
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glDeleteFencesNVFn != nullptr);
   g_driver_gl.debug_fn.glDeleteFencesNVFn(n, fences);
 }
 
@@ -2673,18 +2735,21 @@
   GL_SERVICE_LOG("glDeleteFramebuffersEXT"
                  << "(" << n << ", " << static_cast<const void*>(framebuffers)
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glDeleteFramebuffersEXTFn != nullptr);
   g_driver_gl.debug_fn.glDeleteFramebuffersEXTFn(n, framebuffers);
 }
 
 static void GL_BINDING_CALL Debug_glDeletePathsNV(GLuint path, GLsizei range) {
   GL_SERVICE_LOG("glDeletePathsNV"
                  << "(" << path << ", " << range << ")");
+  DCHECK(g_driver_gl.debug_fn.glDeletePathsNVFn != nullptr);
   g_driver_gl.debug_fn.glDeletePathsNVFn(path, range);
 }
 
 static void GL_BINDING_CALL Debug_glDeleteProgram(GLuint program) {
   GL_SERVICE_LOG("glDeleteProgram"
                  << "(" << program << ")");
+  DCHECK(g_driver_gl.debug_fn.glDeleteProgramFn != nullptr);
   g_driver_gl.debug_fn.glDeleteProgramFn(program);
 }
 
@@ -2692,6 +2757,7 @@
                                                   const GLuint* ids) {
   GL_SERVICE_LOG("glDeleteQueries"
                  << "(" << n << ", " << static_cast<const void*>(ids) << ")");
+  DCHECK(g_driver_gl.debug_fn.glDeleteQueriesFn != nullptr);
   g_driver_gl.debug_fn.glDeleteQueriesFn(n, ids);
 }
 
@@ -2700,6 +2766,7 @@
   GL_SERVICE_LOG("glDeleteRenderbuffersEXT"
                  << "(" << n << ", " << static_cast<const void*>(renderbuffers)
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glDeleteRenderbuffersEXTFn != nullptr);
   g_driver_gl.debug_fn.glDeleteRenderbuffersEXTFn(n, renderbuffers);
 }
 
@@ -2708,18 +2775,21 @@
   GL_SERVICE_LOG("glDeleteSamplers"
                  << "(" << n << ", " << static_cast<const void*>(samplers)
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glDeleteSamplersFn != nullptr);
   g_driver_gl.debug_fn.glDeleteSamplersFn(n, samplers);
 }
 
 static void GL_BINDING_CALL Debug_glDeleteShader(GLuint shader) {
   GL_SERVICE_LOG("glDeleteShader"
                  << "(" << shader << ")");
+  DCHECK(g_driver_gl.debug_fn.glDeleteShaderFn != nullptr);
   g_driver_gl.debug_fn.glDeleteShaderFn(shader);
 }
 
 static void GL_BINDING_CALL Debug_glDeleteSync(GLsync sync) {
   GL_SERVICE_LOG("glDeleteSync"
                  << "(" << sync << ")");
+  DCHECK(g_driver_gl.debug_fn.glDeleteSyncFn != nullptr);
   g_driver_gl.debug_fn.glDeleteSyncFn(sync);
 }
 
@@ -2728,6 +2798,7 @@
   GL_SERVICE_LOG("glDeleteTextures"
                  << "(" << n << ", " << static_cast<const void*>(textures)
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glDeleteTexturesFn != nullptr);
   g_driver_gl.debug_fn.glDeleteTexturesFn(n, textures);
 }
 
@@ -2735,6 +2806,7 @@
 Debug_glDeleteTransformFeedbacks(GLsizei n, const GLuint* ids) {
   GL_SERVICE_LOG("glDeleteTransformFeedbacks"
                  << "(" << n << ", " << static_cast<const void*>(ids) << ")");
+  DCHECK(g_driver_gl.debug_fn.glDeleteTransformFeedbacksFn != nullptr);
   g_driver_gl.debug_fn.glDeleteTransformFeedbacksFn(n, ids);
 }
 
@@ -2743,30 +2815,35 @@
   GL_SERVICE_LOG("glDeleteVertexArraysOES"
                  << "(" << n << ", " << static_cast<const void*>(arrays)
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glDeleteVertexArraysOESFn != nullptr);
   g_driver_gl.debug_fn.glDeleteVertexArraysOESFn(n, arrays);
 }
 
 static void GL_BINDING_CALL Debug_glDepthFunc(GLenum func) {
   GL_SERVICE_LOG("glDepthFunc"
                  << "(" << GLEnums::GetStringEnum(func) << ")");
+  DCHECK(g_driver_gl.debug_fn.glDepthFuncFn != nullptr);
   g_driver_gl.debug_fn.glDepthFuncFn(func);
 }
 
 static void GL_BINDING_CALL Debug_glDepthMask(GLboolean flag) {
   GL_SERVICE_LOG("glDepthMask"
                  << "(" << GLEnums::GetStringBool(flag) << ")");
+  DCHECK(g_driver_gl.debug_fn.glDepthMaskFn != nullptr);
   g_driver_gl.debug_fn.glDepthMaskFn(flag);
 }
 
 static void GL_BINDING_CALL Debug_glDepthRange(GLclampd zNear, GLclampd zFar) {
   GL_SERVICE_LOG("glDepthRange"
                  << "(" << zNear << ", " << zFar << ")");
+  DCHECK(g_driver_gl.debug_fn.glDepthRangeFn != nullptr);
   g_driver_gl.debug_fn.glDepthRangeFn(zNear, zFar);
 }
 
 static void GL_BINDING_CALL Debug_glDepthRangef(GLclampf zNear, GLclampf zFar) {
   GL_SERVICE_LOG("glDepthRangef"
                  << "(" << zNear << ", " << zFar << ")");
+  DCHECK(g_driver_gl.debug_fn.glDepthRangefFn != nullptr);
   g_driver_gl.debug_fn.glDepthRangefFn(zNear, zFar);
 }
 
@@ -2774,18 +2851,21 @@
                                                  GLuint shader) {
   GL_SERVICE_LOG("glDetachShader"
                  << "(" << program << ", " << shader << ")");
+  DCHECK(g_driver_gl.debug_fn.glDetachShaderFn != nullptr);
   g_driver_gl.debug_fn.glDetachShaderFn(program, shader);
 }
 
 static void GL_BINDING_CALL Debug_glDisable(GLenum cap) {
   GL_SERVICE_LOG("glDisable"
                  << "(" << GLEnums::GetStringEnum(cap) << ")");
+  DCHECK(g_driver_gl.debug_fn.glDisableFn != nullptr);
   g_driver_gl.debug_fn.glDisableFn(cap);
 }
 
 static void GL_BINDING_CALL Debug_glDisableVertexAttribArray(GLuint index) {
   GL_SERVICE_LOG("glDisableVertexAttribArray"
                  << "(" << index << ")");
+  DCHECK(g_driver_gl.debug_fn.glDisableVertexAttribArrayFn != nullptr);
   g_driver_gl.debug_fn.glDisableVertexAttribArrayFn(index);
 }
 
@@ -2797,6 +2877,7 @@
                  << "(" << GLEnums::GetStringEnum(target) << ", "
                  << numAttachments << ", "
                  << static_cast<const void*>(attachments) << ")");
+  DCHECK(g_driver_gl.debug_fn.glDiscardFramebufferEXTFn != nullptr);
   g_driver_gl.debug_fn.glDiscardFramebufferEXTFn(target, numAttachments,
                                                  attachments);
 }
@@ -2807,6 +2888,7 @@
   GL_SERVICE_LOG("glDrawArrays"
                  << "(" << GLEnums::GetStringEnum(mode) << ", " << first << ", "
                  << count << ")");
+  DCHECK(g_driver_gl.debug_fn.glDrawArraysFn != nullptr);
   g_driver_gl.debug_fn.glDrawArraysFn(mode, first, count);
 }
 
@@ -2818,6 +2900,7 @@
   GL_SERVICE_LOG("glDrawArraysInstancedANGLE"
                  << "(" << GLEnums::GetStringEnum(mode) << ", " << first << ", "
                  << count << ", " << primcount << ")");
+  DCHECK(g_driver_gl.debug_fn.glDrawArraysInstancedANGLEFn != nullptr);
   g_driver_gl.debug_fn.glDrawArraysInstancedANGLEFn(mode, first, count,
                                                     primcount);
 }
@@ -2825,6 +2908,7 @@
 static void GL_BINDING_CALL Debug_glDrawBuffer(GLenum mode) {
   GL_SERVICE_LOG("glDrawBuffer"
                  << "(" << GLEnums::GetStringEnum(mode) << ")");
+  DCHECK(g_driver_gl.debug_fn.glDrawBufferFn != nullptr);
   g_driver_gl.debug_fn.glDrawBufferFn(mode);
 }
 
@@ -2832,6 +2916,7 @@
                                                    const GLenum* bufs) {
   GL_SERVICE_LOG("glDrawBuffersARB"
                  << "(" << n << ", " << static_cast<const void*>(bufs) << ")");
+  DCHECK(g_driver_gl.debug_fn.glDrawBuffersARBFn != nullptr);
   g_driver_gl.debug_fn.glDrawBuffersARBFn(n, bufs);
 }
 
@@ -2843,6 +2928,7 @@
                  << "(" << GLEnums::GetStringEnum(mode) << ", " << count << ", "
                  << GLEnums::GetStringEnum(type) << ", "
                  << static_cast<const void*>(indices) << ")");
+  DCHECK(g_driver_gl.debug_fn.glDrawElementsFn != nullptr);
   g_driver_gl.debug_fn.glDrawElementsFn(mode, count, type, indices);
 }
 
@@ -2857,6 +2943,7 @@
                  << GLEnums::GetStringEnum(type) << ", "
                  << static_cast<const void*>(indices) << ", " << primcount
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glDrawElementsInstancedANGLEFn != nullptr);
   g_driver_gl.debug_fn.glDrawElementsInstancedANGLEFn(mode, count, type,
                                                       indices, primcount);
 }
@@ -2871,6 +2958,7 @@
                  << "(" << GLEnums::GetStringEnum(mode) << ", " << start << ", "
                  << end << ", " << count << ", " << GLEnums::GetStringEnum(type)
                  << ", " << static_cast<const void*>(indices) << ")");
+  DCHECK(g_driver_gl.debug_fn.glDrawRangeElementsFn != nullptr);
   g_driver_gl.debug_fn.glDrawRangeElementsFn(mode, start, end, count, type,
                                              indices);
 }
@@ -2881,6 +2969,8 @@
   GL_SERVICE_LOG("glEGLImageTargetRenderbufferStorageOES"
                  << "(" << GLEnums::GetStringEnum(target) << ", " << image
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glEGLImageTargetRenderbufferStorageOESFn !=
+         nullptr);
   g_driver_gl.debug_fn.glEGLImageTargetRenderbufferStorageOESFn(target, image);
 }
 
@@ -2889,24 +2979,28 @@
   GL_SERVICE_LOG("glEGLImageTargetTexture2DOES"
                  << "(" << GLEnums::GetStringEnum(target) << ", " << image
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glEGLImageTargetTexture2DOESFn != nullptr);
   g_driver_gl.debug_fn.glEGLImageTargetTexture2DOESFn(target, image);
 }
 
 static void GL_BINDING_CALL Debug_glEnable(GLenum cap) {
   GL_SERVICE_LOG("glEnable"
                  << "(" << GLEnums::GetStringEnum(cap) << ")");
+  DCHECK(g_driver_gl.debug_fn.glEnableFn != nullptr);
   g_driver_gl.debug_fn.glEnableFn(cap);
 }
 
 static void GL_BINDING_CALL Debug_glEnableVertexAttribArray(GLuint index) {
   GL_SERVICE_LOG("glEnableVertexAttribArray"
                  << "(" << index << ")");
+  DCHECK(g_driver_gl.debug_fn.glEnableVertexAttribArrayFn != nullptr);
   g_driver_gl.debug_fn.glEnableVertexAttribArrayFn(index);
 }
 
 static void GL_BINDING_CALL Debug_glEndQuery(GLenum target) {
   GL_SERVICE_LOG("glEndQuery"
                  << "(" << GLEnums::GetStringEnum(target) << ")");
+  DCHECK(g_driver_gl.debug_fn.glEndQueryFn != nullptr);
   g_driver_gl.debug_fn.glEndQueryFn(target);
 }
 
@@ -2914,6 +3008,7 @@
   GL_SERVICE_LOG("glEndTransformFeedback"
                  << "("
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glEndTransformFeedbackFn != nullptr);
   g_driver_gl.debug_fn.glEndTransformFeedbackFn();
 }
 
@@ -2922,6 +3017,7 @@
   GL_SERVICE_LOG("glFenceSync"
                  << "(" << GLEnums::GetStringEnum(condition) << ", " << flags
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glFenceSyncFn != nullptr);
   GLsync result = g_driver_gl.debug_fn.glFenceSyncFn(condition, flags);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -2931,18 +3027,21 @@
   GL_SERVICE_LOG("glFinish"
                  << "("
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glFinishFn != nullptr);
   g_driver_gl.debug_fn.glFinishFn();
 }
 
 static void GL_BINDING_CALL Debug_glFinishFenceAPPLE(GLuint fence) {
   GL_SERVICE_LOG("glFinishFenceAPPLE"
                  << "(" << fence << ")");
+  DCHECK(g_driver_gl.debug_fn.glFinishFenceAPPLEFn != nullptr);
   g_driver_gl.debug_fn.glFinishFenceAPPLEFn(fence);
 }
 
 static void GL_BINDING_CALL Debug_glFinishFenceNV(GLuint fence) {
   GL_SERVICE_LOG("glFinishFenceNV"
                  << "(" << fence << ")");
+  DCHECK(g_driver_gl.debug_fn.glFinishFenceNVFn != nullptr);
   g_driver_gl.debug_fn.glFinishFenceNVFn(fence);
 }
 
@@ -2950,6 +3049,7 @@
   GL_SERVICE_LOG("glFlush"
                  << "("
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glFlushFn != nullptr);
   g_driver_gl.debug_fn.glFlushFn();
 }
 
@@ -2959,6 +3059,7 @@
   GL_SERVICE_LOG("glFlushMappedBufferRange"
                  << "(" << GLEnums::GetStringEnum(target) << ", " << offset
                  << ", " << length << ")");
+  DCHECK(g_driver_gl.debug_fn.glFlushMappedBufferRangeFn != nullptr);
   g_driver_gl.debug_fn.glFlushMappedBufferRangeFn(target, offset, length);
 }
 
@@ -2972,6 +3073,7 @@
                  << GLEnums::GetStringEnum(attachment) << ", "
                  << GLEnums::GetStringEnum(renderbuffertarget) << ", "
                  << renderbuffer << ")");
+  DCHECK(g_driver_gl.debug_fn.glFramebufferRenderbufferEXTFn != nullptr);
   g_driver_gl.debug_fn.glFramebufferRenderbufferEXTFn(
       target, attachment, renderbuffertarget, renderbuffer);
 }
@@ -2986,6 +3088,7 @@
                  << GLEnums::GetStringEnum(attachment) << ", "
                  << GLEnums::GetStringEnum(textarget) << ", " << texture << ", "
                  << level << ")");
+  DCHECK(g_driver_gl.debug_fn.glFramebufferTexture2DEXTFn != nullptr);
   g_driver_gl.debug_fn.glFramebufferTexture2DEXTFn(target, attachment,
                                                    textarget, texture, level);
 }
@@ -3002,6 +3105,8 @@
                  << GLEnums::GetStringEnum(attachment) << ", "
                  << GLEnums::GetStringEnum(textarget) << ", " << texture << ", "
                  << level << ", " << samples << ")");
+  DCHECK(g_driver_gl.debug_fn.glFramebufferTexture2DMultisampleEXTFn !=
+         nullptr);
   g_driver_gl.debug_fn.glFramebufferTexture2DMultisampleEXTFn(
       target, attachment, textarget, texture, level, samples);
 }
@@ -3018,6 +3123,8 @@
                  << GLEnums::GetStringEnum(attachment) << ", "
                  << GLEnums::GetStringEnum(textarget) << ", " << texture << ", "
                  << level << ", " << samples << ")");
+  DCHECK(g_driver_gl.debug_fn.glFramebufferTexture2DMultisampleIMGFn !=
+         nullptr);
   g_driver_gl.debug_fn.glFramebufferTexture2DMultisampleIMGFn(
       target, attachment, textarget, texture, level, samples);
 }
@@ -3031,6 +3138,7 @@
                  << "(" << GLEnums::GetStringEnum(target) << ", "
                  << GLEnums::GetStringEnum(attachment) << ", " << texture
                  << ", " << level << ", " << layer << ")");
+  DCHECK(g_driver_gl.debug_fn.glFramebufferTextureLayerFn != nullptr);
   g_driver_gl.debug_fn.glFramebufferTextureLayerFn(target, attachment, texture,
                                                    level, layer);
 }
@@ -3038,6 +3146,7 @@
 static void GL_BINDING_CALL Debug_glFrontFace(GLenum mode) {
   GL_SERVICE_LOG("glFrontFace"
                  << "(" << GLEnums::GetStringEnum(mode) << ")");
+  DCHECK(g_driver_gl.debug_fn.glFrontFaceFn != nullptr);
   g_driver_gl.debug_fn.glFrontFaceFn(mode);
 }
 
@@ -3045,12 +3154,14 @@
   GL_SERVICE_LOG("glGenBuffersARB"
                  << "(" << n << ", " << static_cast<const void*>(buffers)
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glGenBuffersARBFn != nullptr);
   g_driver_gl.debug_fn.glGenBuffersARBFn(n, buffers);
 }
 
 static void GL_BINDING_CALL Debug_glGenerateMipmapEXT(GLenum target) {
   GL_SERVICE_LOG("glGenerateMipmapEXT"
                  << "(" << GLEnums::GetStringEnum(target) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGenerateMipmapEXTFn != nullptr);
   g_driver_gl.debug_fn.glGenerateMipmapEXTFn(target);
 }
 
@@ -3058,6 +3169,7 @@
   GL_SERVICE_LOG("glGenFencesAPPLE"
                  << "(" << n << ", " << static_cast<const void*>(fences)
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glGenFencesAPPLEFn != nullptr);
   g_driver_gl.debug_fn.glGenFencesAPPLEFn(n, fences);
 }
 
@@ -3065,6 +3177,7 @@
   GL_SERVICE_LOG("glGenFencesNV"
                  << "(" << n << ", " << static_cast<const void*>(fences)
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glGenFencesNVFn != nullptr);
   g_driver_gl.debug_fn.glGenFencesNVFn(n, fences);
 }
 
@@ -3073,12 +3186,14 @@
   GL_SERVICE_LOG("glGenFramebuffersEXT"
                  << "(" << n << ", " << static_cast<const void*>(framebuffers)
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glGenFramebuffersEXTFn != nullptr);
   g_driver_gl.debug_fn.glGenFramebuffersEXTFn(n, framebuffers);
 }
 
 static GLuint GL_BINDING_CALL Debug_glGenPathsNV(GLsizei range) {
   GL_SERVICE_LOG("glGenPathsNV"
                  << "(" << range << ")");
+  DCHECK(g_driver_gl.debug_fn.glGenPathsNVFn != nullptr);
   GLuint result = g_driver_gl.debug_fn.glGenPathsNVFn(range);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -3087,6 +3202,7 @@
 static void GL_BINDING_CALL Debug_glGenQueries(GLsizei n, GLuint* ids) {
   GL_SERVICE_LOG("glGenQueries"
                  << "(" << n << ", " << static_cast<const void*>(ids) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGenQueriesFn != nullptr);
   g_driver_gl.debug_fn.glGenQueriesFn(n, ids);
 }
 
@@ -3095,6 +3211,7 @@
   GL_SERVICE_LOG("glGenRenderbuffersEXT"
                  << "(" << n << ", " << static_cast<const void*>(renderbuffers)
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glGenRenderbuffersEXTFn != nullptr);
   g_driver_gl.debug_fn.glGenRenderbuffersEXTFn(n, renderbuffers);
 }
 
@@ -3102,6 +3219,7 @@
   GL_SERVICE_LOG("glGenSamplers"
                  << "(" << n << ", " << static_cast<const void*>(samplers)
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glGenSamplersFn != nullptr);
   g_driver_gl.debug_fn.glGenSamplersFn(n, samplers);
 }
 
@@ -3109,6 +3227,7 @@
   GL_SERVICE_LOG("glGenTextures"
                  << "(" << n << ", " << static_cast<const void*>(textures)
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glGenTexturesFn != nullptr);
   g_driver_gl.debug_fn.glGenTexturesFn(n, textures);
 }
 
@@ -3116,6 +3235,7 @@
                                                           GLuint* ids) {
   GL_SERVICE_LOG("glGenTransformFeedbacks"
                  << "(" << n << ", " << static_cast<const void*>(ids) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGenTransformFeedbacksFn != nullptr);
   g_driver_gl.debug_fn.glGenTransformFeedbacksFn(n, ids);
 }
 
@@ -3124,6 +3244,7 @@
   GL_SERVICE_LOG("glGenVertexArraysOES"
                  << "(" << n << ", " << static_cast<const void*>(arrays)
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glGenVertexArraysOESFn != nullptr);
   g_driver_gl.debug_fn.glGenVertexArraysOESFn(n, arrays);
 }
 
@@ -3140,6 +3261,7 @@
                  << static_cast<const void*>(size) << ", "
                  << static_cast<const void*>(type) << ", "
                  << static_cast<const void*>(name) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetActiveAttribFn != nullptr);
   g_driver_gl.debug_fn.glGetActiveAttribFn(program, index, bufsize, length,
                                            size, type, name);
 }
@@ -3157,6 +3279,7 @@
                  << static_cast<const void*>(size) << ", "
                  << static_cast<const void*>(type) << ", "
                  << static_cast<const void*>(name) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetActiveUniformFn != nullptr);
   g_driver_gl.debug_fn.glGetActiveUniformFn(program, index, bufsize, length,
                                             size, type, name);
 }
@@ -3170,6 +3293,7 @@
                  << "(" << program << ", " << uniformBlockIndex << ", "
                  << GLEnums::GetStringEnum(pname) << ", "
                  << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetActiveUniformBlockivFn != nullptr);
   g_driver_gl.debug_fn.glGetActiveUniformBlockivFn(program, uniformBlockIndex,
                                                    pname, params);
 }
@@ -3184,6 +3308,7 @@
                  << "(" << program << ", " << uniformBlockIndex << ", "
                  << bufSize << ", " << static_cast<const void*>(length) << ", "
                  << static_cast<const void*>(uniformBlockName) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetActiveUniformBlockNameFn != nullptr);
   g_driver_gl.debug_fn.glGetActiveUniformBlockNameFn(
       program, uniformBlockIndex, bufSize, length, uniformBlockName);
 }
@@ -3199,6 +3324,7 @@
                  << static_cast<const void*>(uniformIndices) << ", "
                  << GLEnums::GetStringEnum(pname) << ", "
                  << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetActiveUniformsivFn != nullptr);
   g_driver_gl.debug_fn.glGetActiveUniformsivFn(program, uniformCount,
                                                uniformIndices, pname, params);
 }
@@ -3211,6 +3337,7 @@
                  << "(" << program << ", " << maxcount << ", "
                  << static_cast<const void*>(count) << ", "
                  << static_cast<const void*>(shaders) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetAttachedShadersFn != nullptr);
   g_driver_gl.debug_fn.glGetAttachedShadersFn(program, maxcount, count,
                                               shaders);
 }
@@ -3219,6 +3346,7 @@
                                                        const char* name) {
   GL_SERVICE_LOG("glGetAttribLocation"
                  << "(" << program << ", " << name << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetAttribLocationFn != nullptr);
   GLint result = g_driver_gl.debug_fn.glGetAttribLocationFn(program, name);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -3229,6 +3357,7 @@
   GL_SERVICE_LOG("glGetBooleanv"
                  << "(" << GLEnums::GetStringEnum(pname) << ", "
                  << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetBooleanvFn != nullptr);
   g_driver_gl.debug_fn.glGetBooleanvFn(pname, params);
 }
 
@@ -3239,6 +3368,7 @@
                  << "(" << GLEnums::GetStringEnum(target) << ", "
                  << GLEnums::GetStringEnum(pname) << ", "
                  << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetBufferParameterivFn != nullptr);
   g_driver_gl.debug_fn.glGetBufferParameterivFn(target, pname, params);
 }
 
@@ -3246,6 +3376,7 @@
   GL_SERVICE_LOG("glGetError"
                  << "("
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetErrorFn != nullptr);
   GLenum result = g_driver_gl.debug_fn.glGetErrorFn();
 
   GL_SERVICE_LOG("GL_RESULT: " << GLEnums::GetStringError(result));
@@ -3259,6 +3390,7 @@
   GL_SERVICE_LOG("glGetFenceivNV"
                  << "(" << fence << ", " << GLEnums::GetStringEnum(pname)
                  << ", " << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetFenceivNVFn != nullptr);
   g_driver_gl.debug_fn.glGetFenceivNVFn(fence, pname, params);
 }
 
@@ -3266,6 +3398,7 @@
   GL_SERVICE_LOG("glGetFloatv"
                  << "(" << GLEnums::GetStringEnum(pname) << ", "
                  << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetFloatvFn != nullptr);
   g_driver_gl.debug_fn.glGetFloatvFn(pname, params);
 }
 
@@ -3273,6 +3406,7 @@
                                                       const char* name) {
   GL_SERVICE_LOG("glGetFragDataIndex"
                  << "(" << program << ", " << name << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetFragDataIndexFn != nullptr);
   GLint result = g_driver_gl.debug_fn.glGetFragDataIndexFn(program, name);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -3282,6 +3416,7 @@
                                                          const char* name) {
   GL_SERVICE_LOG("glGetFragDataLocation"
                  << "(" << program << ", " << name << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetFragDataLocationFn != nullptr);
   GLint result = g_driver_gl.debug_fn.glGetFragDataLocationFn(program, name);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -3297,6 +3432,8 @@
                  << GLEnums::GetStringEnum(attachment) << ", "
                  << GLEnums::GetStringEnum(pname) << ", "
                  << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetFramebufferAttachmentParameterivEXTFn !=
+         nullptr);
   g_driver_gl.debug_fn.glGetFramebufferAttachmentParameterivEXTFn(
       target, attachment, pname, params);
 }
@@ -3305,6 +3442,7 @@
   GL_SERVICE_LOG("glGetGraphicsResetStatusARB"
                  << "("
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetGraphicsResetStatusARBFn != nullptr);
   GLenum result = g_driver_gl.debug_fn.glGetGraphicsResetStatusARBFn();
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -3316,6 +3454,7 @@
   GL_SERVICE_LOG("glGetInteger64i_v"
                  << "(" << GLEnums::GetStringEnum(target) << ", " << index
                  << ", " << static_cast<const void*>(data) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetInteger64i_vFn != nullptr);
   g_driver_gl.debug_fn.glGetInteger64i_vFn(target, index, data);
 }
 
@@ -3324,6 +3463,7 @@
   GL_SERVICE_LOG("glGetInteger64v"
                  << "(" << GLEnums::GetStringEnum(pname) << ", "
                  << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetInteger64vFn != nullptr);
   g_driver_gl.debug_fn.glGetInteger64vFn(pname, params);
 }
 
@@ -3333,6 +3473,7 @@
   GL_SERVICE_LOG("glGetIntegeri_v"
                  << "(" << GLEnums::GetStringEnum(target) << ", " << index
                  << ", " << static_cast<const void*>(data) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetIntegeri_vFn != nullptr);
   g_driver_gl.debug_fn.glGetIntegeri_vFn(target, index, data);
 }
 
@@ -3340,6 +3481,7 @@
   GL_SERVICE_LOG("glGetIntegerv"
                  << "(" << GLEnums::GetStringEnum(pname) << ", "
                  << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetIntegervFn != nullptr);
   g_driver_gl.debug_fn.glGetIntegervFn(pname, params);
 }
 
@@ -3353,6 +3495,7 @@
                  << GLEnums::GetStringEnum(internalformat) << ", "
                  << GLEnums::GetStringEnum(pname) << ", " << bufSize << ", "
                  << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetInternalformativFn != nullptr);
   g_driver_gl.debug_fn.glGetInternalformativFn(target, internalformat, pname,
                                                bufSize, params);
 }
@@ -3367,6 +3510,7 @@
                  << static_cast<const void*>(length) << ", "
                  << static_cast<const void*>(binaryFormat) << ", "
                  << static_cast<const void*>(binary) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetProgramBinaryFn != nullptr);
   g_driver_gl.debug_fn.glGetProgramBinaryFn(program, bufSize, length,
                                             binaryFormat, binary);
 }
@@ -3379,6 +3523,7 @@
                  << "(" << program << ", " << bufsize << ", "
                  << static_cast<const void*>(length) << ", "
                  << static_cast<const void*>(infolog) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetProgramInfoLogFn != nullptr);
   g_driver_gl.debug_fn.glGetProgramInfoLogFn(program, bufsize, length, infolog);
 }
 
@@ -3392,6 +3537,7 @@
                  << GLEnums::GetStringEnum(programInterface) << ", "
                  << GLEnums::GetStringEnum(pname) << ", "
                  << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetProgramInterfaceivFn != nullptr);
   g_driver_gl.debug_fn.glGetProgramInterfaceivFn(program, programInterface,
                                                  pname, params);
 }
@@ -3402,6 +3548,7 @@
   GL_SERVICE_LOG("glGetProgramiv"
                  << "(" << program << ", " << GLEnums::GetStringEnum(pname)
                  << ", " << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetProgramivFn != nullptr);
   g_driver_gl.debug_fn.glGetProgramivFn(program, pname, params);
 }
 
@@ -3420,6 +3567,7 @@
                  << ", " << propCount << ", " << static_cast<const void*>(props)
                  << ", " << bufSize << ", " << static_cast<const void*>(length)
                  << ", " << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetProgramResourceivFn != nullptr);
   g_driver_gl.debug_fn.glGetProgramResourceivFn(program, programInterface,
                                                 index, propCount, props,
                                                 bufSize, length, params);
@@ -3433,6 +3581,7 @@
                  << "(" << program << ", "
                  << GLEnums::GetStringEnum(programInterface) << ", " << name
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetProgramResourceLocationFn != nullptr);
   GLint result = g_driver_gl.debug_fn.glGetProgramResourceLocationFn(
       program, programInterface, name);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -3451,6 +3600,7 @@
                  << GLEnums::GetStringEnum(programInterface) << ", " << index
                  << ", " << bufSize << ", " << static_cast<const void*>(length)
                  << ", " << static_cast<const void*>(name) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetProgramResourceNameFn != nullptr);
   g_driver_gl.debug_fn.glGetProgramResourceNameFn(program, programInterface,
                                                   index, bufSize, length, name);
 }
@@ -3462,6 +3612,7 @@
                  << "(" << GLEnums::GetStringEnum(target) << ", "
                  << GLEnums::GetStringEnum(pname) << ", "
                  << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetQueryivFn != nullptr);
   g_driver_gl.debug_fn.glGetQueryivFn(target, pname, params);
 }
 
@@ -3471,6 +3622,7 @@
   GL_SERVICE_LOG("glGetQueryObjecti64v"
                  << "(" << id << ", " << GLEnums::GetStringEnum(pname) << ", "
                  << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetQueryObjecti64vFn != nullptr);
   g_driver_gl.debug_fn.glGetQueryObjecti64vFn(id, pname, params);
 }
 
@@ -3480,6 +3632,7 @@
   GL_SERVICE_LOG("glGetQueryObjectiv"
                  << "(" << id << ", " << GLEnums::GetStringEnum(pname) << ", "
                  << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetQueryObjectivFn != nullptr);
   g_driver_gl.debug_fn.glGetQueryObjectivFn(id, pname, params);
 }
 
@@ -3489,6 +3642,7 @@
   GL_SERVICE_LOG("glGetQueryObjectui64v"
                  << "(" << id << ", " << GLEnums::GetStringEnum(pname) << ", "
                  << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetQueryObjectui64vFn != nullptr);
   g_driver_gl.debug_fn.glGetQueryObjectui64vFn(id, pname, params);
 }
 
@@ -3498,6 +3652,7 @@
   GL_SERVICE_LOG("glGetQueryObjectuiv"
                  << "(" << id << ", " << GLEnums::GetStringEnum(pname) << ", "
                  << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetQueryObjectuivFn != nullptr);
   g_driver_gl.debug_fn.glGetQueryObjectuivFn(id, pname, params);
 }
 
@@ -3509,6 +3664,7 @@
                  << "(" << GLEnums::GetStringEnum(target) << ", "
                  << GLEnums::GetStringEnum(pname) << ", "
                  << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetRenderbufferParameterivEXTFn != nullptr);
   g_driver_gl.debug_fn.glGetRenderbufferParameterivEXTFn(target, pname, params);
 }
 
@@ -3518,6 +3674,7 @@
   GL_SERVICE_LOG("glGetSamplerParameterfv"
                  << "(" << sampler << ", " << GLEnums::GetStringEnum(pname)
                  << ", " << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetSamplerParameterfvFn != nullptr);
   g_driver_gl.debug_fn.glGetSamplerParameterfvFn(sampler, pname, params);
 }
 
@@ -3527,6 +3684,7 @@
   GL_SERVICE_LOG("glGetSamplerParameteriv"
                  << "(" << sampler << ", " << GLEnums::GetStringEnum(pname)
                  << ", " << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetSamplerParameterivFn != nullptr);
   g_driver_gl.debug_fn.glGetSamplerParameterivFn(sampler, pname, params);
 }
 
@@ -3538,6 +3696,7 @@
                  << "(" << shader << ", " << bufsize << ", "
                  << static_cast<const void*>(length) << ", "
                  << static_cast<const void*>(infolog) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetShaderInfoLogFn != nullptr);
   g_driver_gl.debug_fn.glGetShaderInfoLogFn(shader, bufsize, length, infolog);
 }
 
@@ -3547,6 +3706,7 @@
   GL_SERVICE_LOG("glGetShaderiv"
                  << "(" << shader << ", " << GLEnums::GetStringEnum(pname)
                  << ", " << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetShaderivFn != nullptr);
   g_driver_gl.debug_fn.glGetShaderivFn(shader, pname, params);
 }
 
@@ -3560,6 +3720,7 @@
                  << GLEnums::GetStringEnum(precisiontype) << ", "
                  << static_cast<const void*>(range) << ", "
                  << static_cast<const void*>(precision) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetShaderPrecisionFormatFn != nullptr);
   g_driver_gl.debug_fn.glGetShaderPrecisionFormatFn(shadertype, precisiontype,
                                                     range, precision);
 }
@@ -3572,12 +3733,14 @@
                  << "(" << shader << ", " << bufsize << ", "
                  << static_cast<const void*>(length) << ", "
                  << static_cast<const void*>(source) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetShaderSourceFn != nullptr);
   g_driver_gl.debug_fn.glGetShaderSourceFn(shader, bufsize, length, source);
 }
 
 static const GLubyte* GL_BINDING_CALL Debug_glGetString(GLenum name) {
   GL_SERVICE_LOG("glGetString"
                  << "(" << GLEnums::GetStringEnum(name) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetStringFn != nullptr);
   const GLubyte* result = g_driver_gl.debug_fn.glGetStringFn(name);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -3588,6 +3751,7 @@
   GL_SERVICE_LOG("glGetStringi"
                  << "(" << GLEnums::GetStringEnum(name) << ", " << index
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetStringiFn != nullptr);
   const GLubyte* result = g_driver_gl.debug_fn.glGetStringiFn(name, index);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -3602,6 +3766,7 @@
                  << "(" << sync << ", " << GLEnums::GetStringEnum(pname) << ", "
                  << bufSize << ", " << static_cast<const void*>(length) << ", "
                  << static_cast<const void*>(values) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetSyncivFn != nullptr);
   g_driver_gl.debug_fn.glGetSyncivFn(sync, pname, bufSize, length, values);
 }
 
@@ -3613,6 +3778,7 @@
                  << "(" << GLEnums::GetStringEnum(target) << ", " << level
                  << ", " << GLEnums::GetStringEnum(pname) << ", "
                  << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetTexLevelParameterfvFn != nullptr);
   g_driver_gl.debug_fn.glGetTexLevelParameterfvFn(target, level, pname, params);
 }
 
@@ -3624,6 +3790,7 @@
                  << "(" << GLEnums::GetStringEnum(target) << ", " << level
                  << ", " << GLEnums::GetStringEnum(pname) << ", "
                  << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetTexLevelParameterivFn != nullptr);
   g_driver_gl.debug_fn.glGetTexLevelParameterivFn(target, level, pname, params);
 }
 
@@ -3634,6 +3801,7 @@
                  << "(" << GLEnums::GetStringEnum(target) << ", "
                  << GLEnums::GetStringEnum(pname) << ", "
                  << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetTexParameterfvFn != nullptr);
   g_driver_gl.debug_fn.glGetTexParameterfvFn(target, pname, params);
 }
 
@@ -3644,6 +3812,7 @@
                  << "(" << GLEnums::GetStringEnum(target) << ", "
                  << GLEnums::GetStringEnum(pname) << ", "
                  << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetTexParameterivFn != nullptr);
   g_driver_gl.debug_fn.glGetTexParameterivFn(target, pname, params);
 }
 
@@ -3660,6 +3829,7 @@
                  << static_cast<const void*>(size) << ", "
                  << static_cast<const void*>(type) << ", "
                  << static_cast<const void*>(name) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetTransformFeedbackVaryingFn != nullptr);
   g_driver_gl.debug_fn.glGetTransformFeedbackVaryingFn(
       program, index, bufSize, length, size, type, name);
 }
@@ -3673,6 +3843,7 @@
                  << "(" << shader << ", " << bufsize << ", "
                  << static_cast<const void*>(length) << ", "
                  << static_cast<const void*>(source) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetTranslatedShaderSourceANGLEFn != nullptr);
   g_driver_gl.debug_fn.glGetTranslatedShaderSourceANGLEFn(shader, bufsize,
                                                           length, source);
 }
@@ -3681,6 +3852,7 @@
 Debug_glGetUniformBlockIndex(GLuint program, const char* uniformBlockName) {
   GL_SERVICE_LOG("glGetUniformBlockIndex"
                  << "(" << program << ", " << uniformBlockName << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetUniformBlockIndexFn != nullptr);
   GLuint result =
       g_driver_gl.debug_fn.glGetUniformBlockIndexFn(program, uniformBlockName);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -3693,6 +3865,7 @@
   GL_SERVICE_LOG("glGetUniformfv"
                  << "(" << program << ", " << location << ", "
                  << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetUniformfvFn != nullptr);
   g_driver_gl.debug_fn.glGetUniformfvFn(program, location, params);
 }
 
@@ -3705,6 +3878,7 @@
                  << "(" << program << ", " << uniformCount << ", "
                  << static_cast<const void*>(uniformNames) << ", "
                  << static_cast<const void*>(uniformIndices) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetUniformIndicesFn != nullptr);
   g_driver_gl.debug_fn.glGetUniformIndicesFn(program, uniformCount,
                                              uniformNames, uniformIndices);
 }
@@ -3715,6 +3889,7 @@
   GL_SERVICE_LOG("glGetUniformiv"
                  << "(" << program << ", " << location << ", "
                  << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetUniformivFn != nullptr);
   g_driver_gl.debug_fn.glGetUniformivFn(program, location, params);
 }
 
@@ -3722,6 +3897,7 @@
                                                         const char* name) {
   GL_SERVICE_LOG("glGetUniformLocation"
                  << "(" << program << ", " << name << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetUniformLocationFn != nullptr);
   GLint result = g_driver_gl.debug_fn.glGetUniformLocationFn(program, name);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -3733,6 +3909,7 @@
   GL_SERVICE_LOG("glGetUniformuiv"
                  << "(" << program << ", " << location << ", "
                  << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetUniformuivFn != nullptr);
   g_driver_gl.debug_fn.glGetUniformuivFn(program, location, params);
 }
 
@@ -3742,6 +3919,7 @@
   GL_SERVICE_LOG("glGetVertexAttribfv"
                  << "(" << index << ", " << GLEnums::GetStringEnum(pname)
                  << ", " << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetVertexAttribfvFn != nullptr);
   g_driver_gl.debug_fn.glGetVertexAttribfvFn(index, pname, params);
 }
 
@@ -3751,6 +3929,7 @@
   GL_SERVICE_LOG("glGetVertexAttribiv"
                  << "(" << index << ", " << GLEnums::GetStringEnum(pname)
                  << ", " << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetVertexAttribivFn != nullptr);
   g_driver_gl.debug_fn.glGetVertexAttribivFn(index, pname, params);
 }
 
@@ -3760,6 +3939,7 @@
   GL_SERVICE_LOG("glGetVertexAttribPointerv"
                  << "(" << index << ", " << GLEnums::GetStringEnum(pname)
                  << ", " << pointer << ")");
+  DCHECK(g_driver_gl.debug_fn.glGetVertexAttribPointervFn != nullptr);
   g_driver_gl.debug_fn.glGetVertexAttribPointervFn(index, pname, pointer);
 }
 
@@ -3767,6 +3947,7 @@
   GL_SERVICE_LOG("glHint"
                  << "(" << GLEnums::GetStringEnum(target) << ", "
                  << GLEnums::GetStringEnum(mode) << ")");
+  DCHECK(g_driver_gl.debug_fn.glHintFn != nullptr);
   g_driver_gl.debug_fn.glHintFn(target, mode);
 }
 
@@ -3774,6 +3955,7 @@
                                                          const char* marker) {
   GL_SERVICE_LOG("glInsertEventMarkerEXT"
                  << "(" << length << ", " << marker << ")");
+  DCHECK(g_driver_gl.debug_fn.glInsertEventMarkerEXTFn != nullptr);
   g_driver_gl.debug_fn.glInsertEventMarkerEXTFn(length, marker);
 }
 
@@ -3785,6 +3967,7 @@
                  << "(" << GLEnums::GetStringEnum(target) << ", "
                  << numAttachments << ", "
                  << static_cast<const void*>(attachments) << ")");
+  DCHECK(g_driver_gl.debug_fn.glInvalidateFramebufferFn != nullptr);
   g_driver_gl.debug_fn.glInvalidateFramebufferFn(target, numAttachments,
                                                  attachments);
 }
@@ -3802,6 +3985,7 @@
                  << numAttachments << ", "
                  << static_cast<const void*>(attachments) << ", " << x << ", "
                  << y << ", " << width << ", " << height << ")");
+  DCHECK(g_driver_gl.debug_fn.glInvalidateSubFramebufferFn != nullptr);
   g_driver_gl.debug_fn.glInvalidateSubFramebufferFn(
       target, numAttachments, attachments, x, y, width, height);
 }
@@ -3809,6 +3993,7 @@
 static GLboolean GL_BINDING_CALL Debug_glIsBuffer(GLuint buffer) {
   GL_SERVICE_LOG("glIsBuffer"
                  << "(" << buffer << ")");
+  DCHECK(g_driver_gl.debug_fn.glIsBufferFn != nullptr);
   GLboolean result = g_driver_gl.debug_fn.glIsBufferFn(buffer);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -3817,6 +4002,7 @@
 static GLboolean GL_BINDING_CALL Debug_glIsEnabled(GLenum cap) {
   GL_SERVICE_LOG("glIsEnabled"
                  << "(" << GLEnums::GetStringEnum(cap) << ")");
+  DCHECK(g_driver_gl.debug_fn.glIsEnabledFn != nullptr);
   GLboolean result = g_driver_gl.debug_fn.glIsEnabledFn(cap);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -3825,6 +4011,7 @@
 static GLboolean GL_BINDING_CALL Debug_glIsFenceAPPLE(GLuint fence) {
   GL_SERVICE_LOG("glIsFenceAPPLE"
                  << "(" << fence << ")");
+  DCHECK(g_driver_gl.debug_fn.glIsFenceAPPLEFn != nullptr);
   GLboolean result = g_driver_gl.debug_fn.glIsFenceAPPLEFn(fence);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -3833,6 +4020,7 @@
 static GLboolean GL_BINDING_CALL Debug_glIsFenceNV(GLuint fence) {
   GL_SERVICE_LOG("glIsFenceNV"
                  << "(" << fence << ")");
+  DCHECK(g_driver_gl.debug_fn.glIsFenceNVFn != nullptr);
   GLboolean result = g_driver_gl.debug_fn.glIsFenceNVFn(fence);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -3841,6 +4029,7 @@
 static GLboolean GL_BINDING_CALL Debug_glIsFramebufferEXT(GLuint framebuffer) {
   GL_SERVICE_LOG("glIsFramebufferEXT"
                  << "(" << framebuffer << ")");
+  DCHECK(g_driver_gl.debug_fn.glIsFramebufferEXTFn != nullptr);
   GLboolean result = g_driver_gl.debug_fn.glIsFramebufferEXTFn(framebuffer);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -3849,6 +4038,7 @@
 static GLboolean GL_BINDING_CALL Debug_glIsPathNV(GLuint path) {
   GL_SERVICE_LOG("glIsPathNV"
                  << "(" << path << ")");
+  DCHECK(g_driver_gl.debug_fn.glIsPathNVFn != nullptr);
   GLboolean result = g_driver_gl.debug_fn.glIsPathNVFn(path);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -3857,6 +4047,7 @@
 static GLboolean GL_BINDING_CALL Debug_glIsProgram(GLuint program) {
   GL_SERVICE_LOG("glIsProgram"
                  << "(" << program << ")");
+  DCHECK(g_driver_gl.debug_fn.glIsProgramFn != nullptr);
   GLboolean result = g_driver_gl.debug_fn.glIsProgramFn(program);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -3865,6 +4056,7 @@
 static GLboolean GL_BINDING_CALL Debug_glIsQuery(GLuint query) {
   GL_SERVICE_LOG("glIsQuery"
                  << "(" << query << ")");
+  DCHECK(g_driver_gl.debug_fn.glIsQueryFn != nullptr);
   GLboolean result = g_driver_gl.debug_fn.glIsQueryFn(query);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -3874,6 +4066,7 @@
 Debug_glIsRenderbufferEXT(GLuint renderbuffer) {
   GL_SERVICE_LOG("glIsRenderbufferEXT"
                  << "(" << renderbuffer << ")");
+  DCHECK(g_driver_gl.debug_fn.glIsRenderbufferEXTFn != nullptr);
   GLboolean result = g_driver_gl.debug_fn.glIsRenderbufferEXTFn(renderbuffer);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -3882,6 +4075,7 @@
 static GLboolean GL_BINDING_CALL Debug_glIsSampler(GLuint sampler) {
   GL_SERVICE_LOG("glIsSampler"
                  << "(" << sampler << ")");
+  DCHECK(g_driver_gl.debug_fn.glIsSamplerFn != nullptr);
   GLboolean result = g_driver_gl.debug_fn.glIsSamplerFn(sampler);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -3890,6 +4084,7 @@
 static GLboolean GL_BINDING_CALL Debug_glIsShader(GLuint shader) {
   GL_SERVICE_LOG("glIsShader"
                  << "(" << shader << ")");
+  DCHECK(g_driver_gl.debug_fn.glIsShaderFn != nullptr);
   GLboolean result = g_driver_gl.debug_fn.glIsShaderFn(shader);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -3898,6 +4093,7 @@
 static GLboolean GL_BINDING_CALL Debug_glIsSync(GLsync sync) {
   GL_SERVICE_LOG("glIsSync"
                  << "(" << sync << ")");
+  DCHECK(g_driver_gl.debug_fn.glIsSyncFn != nullptr);
   GLboolean result = g_driver_gl.debug_fn.glIsSyncFn(sync);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -3906,6 +4102,7 @@
 static GLboolean GL_BINDING_CALL Debug_glIsTexture(GLuint texture) {
   GL_SERVICE_LOG("glIsTexture"
                  << "(" << texture << ")");
+  DCHECK(g_driver_gl.debug_fn.glIsTextureFn != nullptr);
   GLboolean result = g_driver_gl.debug_fn.glIsTextureFn(texture);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -3914,6 +4111,7 @@
 static GLboolean GL_BINDING_CALL Debug_glIsTransformFeedback(GLuint id) {
   GL_SERVICE_LOG("glIsTransformFeedback"
                  << "(" << id << ")");
+  DCHECK(g_driver_gl.debug_fn.glIsTransformFeedbackFn != nullptr);
   GLboolean result = g_driver_gl.debug_fn.glIsTransformFeedbackFn(id);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -3922,6 +4120,7 @@
 static GLboolean GL_BINDING_CALL Debug_glIsVertexArrayOES(GLuint array) {
   GL_SERVICE_LOG("glIsVertexArrayOES"
                  << "(" << array << ")");
+  DCHECK(g_driver_gl.debug_fn.glIsVertexArrayOESFn != nullptr);
   GLboolean result = g_driver_gl.debug_fn.glIsVertexArrayOESFn(array);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -3930,12 +4129,14 @@
 static void GL_BINDING_CALL Debug_glLineWidth(GLfloat width) {
   GL_SERVICE_LOG("glLineWidth"
                  << "(" << width << ")");
+  DCHECK(g_driver_gl.debug_fn.glLineWidthFn != nullptr);
   g_driver_gl.debug_fn.glLineWidthFn(width);
 }
 
 static void GL_BINDING_CALL Debug_glLinkProgram(GLuint program) {
   GL_SERVICE_LOG("glLinkProgram"
                  << "(" << program << ")");
+  DCHECK(g_driver_gl.debug_fn.glLinkProgramFn != nullptr);
   g_driver_gl.debug_fn.glLinkProgramFn(program);
 }
 
@@ -3943,6 +4144,7 @@
   GL_SERVICE_LOG("glMapBuffer"
                  << "(" << GLEnums::GetStringEnum(target) << ", "
                  << GLEnums::GetStringEnum(access) << ")");
+  DCHECK(g_driver_gl.debug_fn.glMapBufferFn != nullptr);
   void* result = g_driver_gl.debug_fn.glMapBufferFn(target, access);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -3955,6 +4157,7 @@
   GL_SERVICE_LOG("glMapBufferRange"
                  << "(" << GLEnums::GetStringEnum(target) << ", " << offset
                  << ", " << length << ", " << access << ")");
+  DCHECK(g_driver_gl.debug_fn.glMapBufferRangeFn != nullptr);
   void* result =
       g_driver_gl.debug_fn.glMapBufferRangeFn(target, offset, length, access);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -3966,18 +4169,21 @@
   GL_SERVICE_LOG("glMatrixLoadfEXT"
                  << "(" << GLEnums::GetStringEnum(matrixMode) << ", "
                  << static_cast<const void*>(m) << ")");
+  DCHECK(g_driver_gl.debug_fn.glMatrixLoadfEXTFn != nullptr);
   g_driver_gl.debug_fn.glMatrixLoadfEXTFn(matrixMode, m);
 }
 
 static void GL_BINDING_CALL Debug_glMatrixLoadIdentityEXT(GLenum matrixMode) {
   GL_SERVICE_LOG("glMatrixLoadIdentityEXT"
                  << "(" << GLEnums::GetStringEnum(matrixMode) << ")");
+  DCHECK(g_driver_gl.debug_fn.glMatrixLoadIdentityEXTFn != nullptr);
   g_driver_gl.debug_fn.glMatrixLoadIdentityEXTFn(matrixMode);
 }
 
 static void GL_BINDING_CALL Debug_glMemoryBarrierEXT(GLbitfield barriers) {
   GL_SERVICE_LOG("glMemoryBarrierEXT"
                  << "(" << barriers << ")");
+  DCHECK(g_driver_gl.debug_fn.glMemoryBarrierEXTFn != nullptr);
   g_driver_gl.debug_fn.glMemoryBarrierEXTFn(barriers);
 }
 
@@ -3992,6 +4198,7 @@
                  << static_cast<const void*>(commands) << ", " << numCoords
                  << ", " << GLEnums::GetStringEnum(coordType) << ", "
                  << static_cast<const void*>(coords) << ")");
+  DCHECK(g_driver_gl.debug_fn.glPathCommandsNVFn != nullptr);
   g_driver_gl.debug_fn.glPathCommandsNVFn(path, numCommands, commands,
                                           numCoords, coordType, coords);
 }
@@ -4002,6 +4209,7 @@
   GL_SERVICE_LOG("glPathParameterfNV"
                  << "(" << path << ", " << GLEnums::GetStringEnum(pname) << ", "
                  << value << ")");
+  DCHECK(g_driver_gl.debug_fn.glPathParameterfNVFn != nullptr);
   g_driver_gl.debug_fn.glPathParameterfNVFn(path, pname, value);
 }
 
@@ -4011,6 +4219,7 @@
   GL_SERVICE_LOG("glPathParameteriNV"
                  << "(" << path << ", " << GLEnums::GetStringEnum(pname) << ", "
                  << value << ")");
+  DCHECK(g_driver_gl.debug_fn.glPathParameteriNVFn != nullptr);
   g_driver_gl.debug_fn.glPathParameteriNVFn(path, pname, value);
 }
 
@@ -4020,6 +4229,7 @@
   GL_SERVICE_LOG("glPathStencilFuncNV"
                  << "(" << GLEnums::GetStringEnum(func) << ", " << ref << ", "
                  << mask << ")");
+  DCHECK(g_driver_gl.debug_fn.glPathStencilFuncNVFn != nullptr);
   g_driver_gl.debug_fn.glPathStencilFuncNVFn(func, ref, mask);
 }
 
@@ -4027,6 +4237,7 @@
   GL_SERVICE_LOG("glPauseTransformFeedback"
                  << "("
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glPauseTransformFeedbackFn != nullptr);
   g_driver_gl.debug_fn.glPauseTransformFeedbackFn();
 }
 
@@ -4034,6 +4245,7 @@
   GL_SERVICE_LOG("glPixelStorei"
                  << "(" << GLEnums::GetStringEnum(pname) << ", " << param
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glPixelStoreiFn != nullptr);
   g_driver_gl.debug_fn.glPixelStoreiFn(pname, param);
 }
 
@@ -4041,6 +4253,7 @@
   GL_SERVICE_LOG("glPointParameteri"
                  << "(" << GLEnums::GetStringEnum(pname) << ", " << param
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glPointParameteriFn != nullptr);
   g_driver_gl.debug_fn.glPointParameteriFn(pname, param);
 }
 
@@ -4048,6 +4261,7 @@
                                                   GLfloat units) {
   GL_SERVICE_LOG("glPolygonOffset"
                  << "(" << factor << ", " << units << ")");
+  DCHECK(g_driver_gl.debug_fn.glPolygonOffsetFn != nullptr);
   g_driver_gl.debug_fn.glPolygonOffsetFn(factor, units);
 }
 
@@ -4055,6 +4269,7 @@
   GL_SERVICE_LOG("glPopGroupMarkerEXT"
                  << "("
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glPopGroupMarkerEXTFn != nullptr);
   g_driver_gl.debug_fn.glPopGroupMarkerEXTFn();
 }
 
@@ -4066,6 +4281,7 @@
                  << "(" << program << ", "
                  << GLEnums::GetStringEnum(binaryFormat) << ", "
                  << static_cast<const void*>(binary) << ", " << length << ")");
+  DCHECK(g_driver_gl.debug_fn.glProgramBinaryFn != nullptr);
   g_driver_gl.debug_fn.glProgramBinaryFn(program, binaryFormat, binary, length);
 }
 
@@ -4075,6 +4291,7 @@
   GL_SERVICE_LOG("glProgramParameteri"
                  << "(" << program << ", " << GLEnums::GetStringEnum(pname)
                  << ", " << value << ")");
+  DCHECK(g_driver_gl.debug_fn.glProgramParameteriFn != nullptr);
   g_driver_gl.debug_fn.glProgramParameteriFn(program, pname, value);
 }
 
@@ -4088,6 +4305,7 @@
                  << "(" << program << ", " << location << ", "
                  << GLEnums::GetStringEnum(genMode) << ", " << components
                  << ", " << static_cast<const void*>(coeffs) << ")");
+  DCHECK(g_driver_gl.debug_fn.glProgramPathFragmentInputGenNVFn != nullptr);
   g_driver_gl.debug_fn.glProgramPathFragmentInputGenNVFn(
       program, location, genMode, components, coeffs);
 }
@@ -4096,18 +4314,21 @@
                                                        const char* marker) {
   GL_SERVICE_LOG("glPushGroupMarkerEXT"
                  << "(" << length << ", " << marker << ")");
+  DCHECK(g_driver_gl.debug_fn.glPushGroupMarkerEXTFn != nullptr);
   g_driver_gl.debug_fn.glPushGroupMarkerEXTFn(length, marker);
 }
 
 static void GL_BINDING_CALL Debug_glQueryCounter(GLuint id, GLenum target) {
   GL_SERVICE_LOG("glQueryCounter"
                  << "(" << id << ", " << GLEnums::GetStringEnum(target) << ")");
+  DCHECK(g_driver_gl.debug_fn.glQueryCounterFn != nullptr);
   g_driver_gl.debug_fn.glQueryCounterFn(id, target);
 }
 
 static void GL_BINDING_CALL Debug_glReadBuffer(GLenum src) {
   GL_SERVICE_LOG("glReadBuffer"
                  << "(" << GLEnums::GetStringEnum(src) << ")");
+  DCHECK(g_driver_gl.debug_fn.glReadBufferFn != nullptr);
   g_driver_gl.debug_fn.glReadBufferFn(src);
 }
 
@@ -4123,6 +4344,7 @@
                  << ", " << GLEnums::GetStringEnum(format) << ", "
                  << GLEnums::GetStringEnum(type) << ", "
                  << static_cast<const void*>(pixels) << ")");
+  DCHECK(g_driver_gl.debug_fn.glReadPixelsFn != nullptr);
   g_driver_gl.debug_fn.glReadPixelsFn(x, y, width, height, format, type,
                                       pixels);
 }
@@ -4131,6 +4353,7 @@
   GL_SERVICE_LOG("glReleaseShaderCompiler"
                  << "("
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glReleaseShaderCompilerFn != nullptr);
   g_driver_gl.debug_fn.glReleaseShaderCompilerFn();
 }
 
@@ -4143,6 +4366,7 @@
                  << "(" << GLEnums::GetStringEnum(target) << ", "
                  << GLEnums::GetStringEnum(internalformat) << ", " << width
                  << ", " << height << ")");
+  DCHECK(g_driver_gl.debug_fn.glRenderbufferStorageEXTFn != nullptr);
   g_driver_gl.debug_fn.glRenderbufferStorageEXTFn(target, internalformat, width,
                                                   height);
 }
@@ -4157,6 +4381,7 @@
                  << "(" << GLEnums::GetStringEnum(target) << ", " << samples
                  << ", " << GLEnums::GetStringEnum(internalformat) << ", "
                  << width << ", " << height << ")");
+  DCHECK(g_driver_gl.debug_fn.glRenderbufferStorageMultisampleFn != nullptr);
   g_driver_gl.debug_fn.glRenderbufferStorageMultisampleFn(
       target, samples, internalformat, width, height);
 }
@@ -4171,6 +4396,8 @@
                  << "(" << GLEnums::GetStringEnum(target) << ", " << samples
                  << ", " << GLEnums::GetStringEnum(internalformat) << ", "
                  << width << ", " << height << ")");
+  DCHECK(g_driver_gl.debug_fn.glRenderbufferStorageMultisampleANGLEFn !=
+         nullptr);
   g_driver_gl.debug_fn.glRenderbufferStorageMultisampleANGLEFn(
       target, samples, internalformat, width, height);
 }
@@ -4185,6 +4412,7 @@
                  << "(" << GLEnums::GetStringEnum(target) << ", " << samples
                  << ", " << GLEnums::GetStringEnum(internalformat) << ", "
                  << width << ", " << height << ")");
+  DCHECK(g_driver_gl.debug_fn.glRenderbufferStorageMultisampleEXTFn != nullptr);
   g_driver_gl.debug_fn.glRenderbufferStorageMultisampleEXTFn(
       target, samples, internalformat, width, height);
 }
@@ -4199,6 +4427,7 @@
                  << "(" << GLEnums::GetStringEnum(target) << ", " << samples
                  << ", " << GLEnums::GetStringEnum(internalformat) << ", "
                  << width << ", " << height << ")");
+  DCHECK(g_driver_gl.debug_fn.glRenderbufferStorageMultisampleIMGFn != nullptr);
   g_driver_gl.debug_fn.glRenderbufferStorageMultisampleIMGFn(
       target, samples, internalformat, width, height);
 }
@@ -4207,6 +4436,7 @@
   GL_SERVICE_LOG("glResumeTransformFeedback"
                  << "("
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glResumeTransformFeedbackFn != nullptr);
   g_driver_gl.debug_fn.glResumeTransformFeedbackFn();
 }
 
@@ -4215,6 +4445,7 @@
   GL_SERVICE_LOG("glSampleCoverage"
                  << "(" << value << ", " << GLEnums::GetStringBool(invert)
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glSampleCoverageFn != nullptr);
   g_driver_gl.debug_fn.glSampleCoverageFn(value, invert);
 }
 
@@ -4224,6 +4455,7 @@
   GL_SERVICE_LOG("glSamplerParameterf"
                  << "(" << sampler << ", " << GLEnums::GetStringEnum(pname)
                  << ", " << param << ")");
+  DCHECK(g_driver_gl.debug_fn.glSamplerParameterfFn != nullptr);
   g_driver_gl.debug_fn.glSamplerParameterfFn(sampler, pname, param);
 }
 
@@ -4233,6 +4465,7 @@
   GL_SERVICE_LOG("glSamplerParameterfv"
                  << "(" << sampler << ", " << GLEnums::GetStringEnum(pname)
                  << ", " << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glSamplerParameterfvFn != nullptr);
   g_driver_gl.debug_fn.glSamplerParameterfvFn(sampler, pname, params);
 }
 
@@ -4242,6 +4475,7 @@
   GL_SERVICE_LOG("glSamplerParameteri"
                  << "(" << sampler << ", " << GLEnums::GetStringEnum(pname)
                  << ", " << param << ")");
+  DCHECK(g_driver_gl.debug_fn.glSamplerParameteriFn != nullptr);
   g_driver_gl.debug_fn.glSamplerParameteriFn(sampler, pname, param);
 }
 
@@ -4251,6 +4485,7 @@
   GL_SERVICE_LOG("glSamplerParameteriv"
                  << "(" << sampler << ", " << GLEnums::GetStringEnum(pname)
                  << ", " << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glSamplerParameterivFn != nullptr);
   g_driver_gl.debug_fn.glSamplerParameterivFn(sampler, pname, params);
 }
 
@@ -4261,12 +4496,14 @@
   GL_SERVICE_LOG("glScissor"
                  << "(" << x << ", " << y << ", " << width << ", " << height
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glScissorFn != nullptr);
   g_driver_gl.debug_fn.glScissorFn(x, y, width, height);
 }
 
 static void GL_BINDING_CALL Debug_glSetFenceAPPLE(GLuint fence) {
   GL_SERVICE_LOG("glSetFenceAPPLE"
                  << "(" << fence << ")");
+  DCHECK(g_driver_gl.debug_fn.glSetFenceAPPLEFn != nullptr);
   g_driver_gl.debug_fn.glSetFenceAPPLEFn(fence);
 }
 
@@ -4274,6 +4511,7 @@
   GL_SERVICE_LOG("glSetFenceNV"
                  << "(" << fence << ", " << GLEnums::GetStringEnum(condition)
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glSetFenceNVFn != nullptr);
   g_driver_gl.debug_fn.glSetFenceNVFn(fence, condition);
 }
 
@@ -4286,6 +4524,7 @@
                  << "(" << n << ", " << static_cast<const void*>(shaders)
                  << ", " << GLEnums::GetStringEnum(binaryformat) << ", "
                  << static_cast<const void*>(binary) << ", " << length << ")");
+  DCHECK(g_driver_gl.debug_fn.glShaderBinaryFn != nullptr);
   g_driver_gl.debug_fn.glShaderBinaryFn(n, shaders, binaryformat, binary,
                                         length);
 }
@@ -4298,6 +4537,7 @@
                  << "(" << shader << ", " << count << ", "
                  << static_cast<const void*>(str) << ", "
                  << static_cast<const void*>(length) << ")");
+  DCHECK(g_driver_gl.debug_fn.glShaderSourceFn != nullptr);
   g_driver_gl.debug_fn.glShaderSourceFn(shader, count, str, length);
 
   GL_SERVICE_LOG_CODE_BLOCK({
@@ -4332,6 +4572,7 @@
                  << GLEnums::GetStringEnum(fillMode) << ", " << mask << ", "
                  << GLEnums::GetStringEnum(transformType) << ", "
                  << static_cast<const void*>(transformValues) << ")");
+  DCHECK(g_driver_gl.debug_fn.glStencilFillPathInstancedNVFn != nullptr);
   g_driver_gl.debug_fn.glStencilFillPathInstancedNVFn(
       numPaths, pathNameType, paths, pathBase, fillMode, mask, transformType,
       transformValues);
@@ -4343,6 +4584,7 @@
   GL_SERVICE_LOG("glStencilFillPathNV"
                  << "(" << path << ", " << GLEnums::GetStringEnum(fillMode)
                  << ", " << mask << ")");
+  DCHECK(g_driver_gl.debug_fn.glStencilFillPathNVFn != nullptr);
   g_driver_gl.debug_fn.glStencilFillPathNVFn(path, fillMode, mask);
 }
 
@@ -4352,6 +4594,7 @@
   GL_SERVICE_LOG("glStencilFunc"
                  << "(" << GLEnums::GetStringEnum(func) << ", " << ref << ", "
                  << mask << ")");
+  DCHECK(g_driver_gl.debug_fn.glStencilFuncFn != nullptr);
   g_driver_gl.debug_fn.glStencilFuncFn(func, ref, mask);
 }
 
@@ -4363,12 +4606,14 @@
                  << "(" << GLEnums::GetStringEnum(face) << ", "
                  << GLEnums::GetStringEnum(func) << ", " << ref << ", " << mask
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glStencilFuncSeparateFn != nullptr);
   g_driver_gl.debug_fn.glStencilFuncSeparateFn(face, func, ref, mask);
 }
 
 static void GL_BINDING_CALL Debug_glStencilMask(GLuint mask) {
   GL_SERVICE_LOG("glStencilMask"
                  << "(" << mask << ")");
+  DCHECK(g_driver_gl.debug_fn.glStencilMaskFn != nullptr);
   g_driver_gl.debug_fn.glStencilMaskFn(mask);
 }
 
@@ -4376,6 +4621,7 @@
                                                         GLuint mask) {
   GL_SERVICE_LOG("glStencilMaskSeparate"
                  << "(" << GLEnums::GetStringEnum(face) << ", " << mask << ")");
+  DCHECK(g_driver_gl.debug_fn.glStencilMaskSeparateFn != nullptr);
   g_driver_gl.debug_fn.glStencilMaskSeparateFn(face, mask);
 }
 
@@ -4386,6 +4632,7 @@
                  << "(" << GLEnums::GetStringEnum(fail) << ", "
                  << GLEnums::GetStringEnum(zfail) << ", "
                  << GLEnums::GetStringEnum(zpass) << ")");
+  DCHECK(g_driver_gl.debug_fn.glStencilOpFn != nullptr);
   g_driver_gl.debug_fn.glStencilOpFn(fail, zfail, zpass);
 }
 
@@ -4398,6 +4645,7 @@
                  << GLEnums::GetStringEnum(fail) << ", "
                  << GLEnums::GetStringEnum(zfail) << ", "
                  << GLEnums::GetStringEnum(zpass) << ")");
+  DCHECK(g_driver_gl.debug_fn.glStencilOpSeparateFn != nullptr);
   g_driver_gl.debug_fn.glStencilOpSeparateFn(face, fail, zfail, zpass);
 }
 
@@ -4416,6 +4664,7 @@
       << static_cast<const void*>(paths) << ", " << pathBase << ", " << ref
       << ", " << mask << ", " << GLEnums::GetStringEnum(transformType) << ", "
       << static_cast<const void*>(transformValues) << ")");
+  DCHECK(g_driver_gl.debug_fn.glStencilStrokePathInstancedNVFn != nullptr);
   g_driver_gl.debug_fn.glStencilStrokePathInstancedNVFn(
       numPaths, pathNameType, paths, pathBase, ref, mask, transformType,
       transformValues);
@@ -4426,6 +4675,7 @@
                                                         GLuint mask) {
   GL_SERVICE_LOG("glStencilStrokePathNV"
                  << "(" << path << ", " << reference << ", " << mask << ")");
+  DCHECK(g_driver_gl.debug_fn.glStencilStrokePathNVFn != nullptr);
   g_driver_gl.debug_fn.glStencilStrokePathNVFn(path, reference, mask);
 }
 
@@ -4447,6 +4697,8 @@
                  << GLEnums::GetStringEnum(coverMode) << ", "
                  << GLEnums::GetStringEnum(transformType) << ", "
                  << static_cast<const void*>(transformValues) << ")");
+  DCHECK(g_driver_gl.debug_fn.glStencilThenCoverFillPathInstancedNVFn !=
+         nullptr);
   g_driver_gl.debug_fn.glStencilThenCoverFillPathInstancedNVFn(
       numPaths, pathNameType, paths, pathBase, fillMode, mask, coverMode,
       transformType, transformValues);
@@ -4461,6 +4713,7 @@
                  << "(" << path << ", " << GLEnums::GetStringEnum(fillMode)
                  << ", " << mask << ", " << GLEnums::GetStringEnum(coverMode)
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glStencilThenCoverFillPathNVFn != nullptr);
   g_driver_gl.debug_fn.glStencilThenCoverFillPathNVFn(path, fillMode, mask,
                                                       coverMode);
 }
@@ -4482,6 +4735,8 @@
       << ", " << mask << ", " << GLEnums::GetStringEnum(coverMode) << ", "
       << GLEnums::GetStringEnum(transformType) << ", "
       << static_cast<const void*>(transformValues) << ")");
+  DCHECK(g_driver_gl.debug_fn.glStencilThenCoverStrokePathInstancedNVFn !=
+         nullptr);
   g_driver_gl.debug_fn.glStencilThenCoverStrokePathInstancedNVFn(
       numPaths, pathNameType, paths, pathBase, ref, mask, coverMode,
       transformType, transformValues);
@@ -4495,6 +4750,7 @@
   GL_SERVICE_LOG("glStencilThenCoverStrokePathNV"
                  << "(" << path << ", " << reference << ", " << mask << ", "
                  << GLEnums::GetStringEnum(coverMode) << ")");
+  DCHECK(g_driver_gl.debug_fn.glStencilThenCoverStrokePathNVFn != nullptr);
   g_driver_gl.debug_fn.glStencilThenCoverStrokePathNVFn(path, reference, mask,
                                                         coverMode);
 }
@@ -4502,6 +4758,7 @@
 static GLboolean GL_BINDING_CALL Debug_glTestFenceAPPLE(GLuint fence) {
   GL_SERVICE_LOG("glTestFenceAPPLE"
                  << "(" << fence << ")");
+  DCHECK(g_driver_gl.debug_fn.glTestFenceAPPLEFn != nullptr);
   GLboolean result = g_driver_gl.debug_fn.glTestFenceAPPLEFn(fence);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -4510,6 +4767,7 @@
 static GLboolean GL_BINDING_CALL Debug_glTestFenceNV(GLuint fence) {
   GL_SERVICE_LOG("glTestFenceNV"
                  << "(" << fence << ")");
+  DCHECK(g_driver_gl.debug_fn.glTestFenceNVFn != nullptr);
   GLboolean result = g_driver_gl.debug_fn.glTestFenceNVFn(fence);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -4530,6 +4788,7 @@
                  << ", " << border << ", " << GLEnums::GetStringEnum(format)
                  << ", " << GLEnums::GetStringEnum(type) << ", "
                  << static_cast<const void*>(pixels) << ")");
+  DCHECK(g_driver_gl.debug_fn.glTexImage2DFn != nullptr);
   g_driver_gl.debug_fn.glTexImage2DFn(target, level, internalformat, width,
                                       height, border, format, type, pixels);
 }
@@ -4551,6 +4810,7 @@
                  << GLEnums::GetStringEnum(format) << ", "
                  << GLEnums::GetStringEnum(type) << ", "
                  << static_cast<const void*>(pixels) << ")");
+  DCHECK(g_driver_gl.debug_fn.glTexImage3DFn != nullptr);
   g_driver_gl.debug_fn.glTexImage3DFn(target, level, internalformat, width,
                                       height, depth, border, format, type,
                                       pixels);
@@ -4562,6 +4822,7 @@
   GL_SERVICE_LOG("glTexParameterf"
                  << "(" << GLEnums::GetStringEnum(target) << ", "
                  << GLEnums::GetStringEnum(pname) << ", " << param << ")");
+  DCHECK(g_driver_gl.debug_fn.glTexParameterfFn != nullptr);
   g_driver_gl.debug_fn.glTexParameterfFn(target, pname, param);
 }
 
@@ -4572,6 +4833,7 @@
                  << "(" << GLEnums::GetStringEnum(target) << ", "
                  << GLEnums::GetStringEnum(pname) << ", "
                  << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glTexParameterfvFn != nullptr);
   g_driver_gl.debug_fn.glTexParameterfvFn(target, pname, params);
 }
 
@@ -4581,6 +4843,7 @@
   GL_SERVICE_LOG("glTexParameteri"
                  << "(" << GLEnums::GetStringEnum(target) << ", "
                  << GLEnums::GetStringEnum(pname) << ", " << param << ")");
+  DCHECK(g_driver_gl.debug_fn.glTexParameteriFn != nullptr);
   g_driver_gl.debug_fn.glTexParameteriFn(target, pname, param);
 }
 
@@ -4591,6 +4854,7 @@
                  << "(" << GLEnums::GetStringEnum(target) << ", "
                  << GLEnums::GetStringEnum(pname) << ", "
                  << static_cast<const void*>(params) << ")");
+  DCHECK(g_driver_gl.debug_fn.glTexParameterivFn != nullptr);
   g_driver_gl.debug_fn.glTexParameterivFn(target, pname, params);
 }
 
@@ -4603,6 +4867,7 @@
                  << "(" << GLEnums::GetStringEnum(target) << ", " << levels
                  << ", " << GLEnums::GetStringEnum(internalformat) << ", "
                  << width << ", " << height << ")");
+  DCHECK(g_driver_gl.debug_fn.glTexStorage2DEXTFn != nullptr);
   g_driver_gl.debug_fn.glTexStorage2DEXTFn(target, levels, internalformat,
                                            width, height);
 }
@@ -4617,6 +4882,7 @@
                  << "(" << GLEnums::GetStringEnum(target) << ", " << levels
                  << ", " << GLEnums::GetStringEnum(internalformat) << ", "
                  << width << ", " << height << ", " << depth << ")");
+  DCHECK(g_driver_gl.debug_fn.glTexStorage3DFn != nullptr);
   g_driver_gl.debug_fn.glTexStorage3DFn(target, levels, internalformat, width,
                                         height, depth);
 }
@@ -4636,6 +4902,7 @@
                  << height << ", " << GLEnums::GetStringEnum(format) << ", "
                  << GLEnums::GetStringEnum(type) << ", "
                  << static_cast<const void*>(pixels) << ")");
+  DCHECK(g_driver_gl.debug_fn.glTexSubImage2DFn != nullptr);
   g_driver_gl.debug_fn.glTexSubImage2DFn(target, level, xoffset, yoffset, width,
                                          height, format, type, pixels);
 }
@@ -4658,6 +4925,7 @@
                  << GLEnums::GetStringEnum(format) << ", "
                  << GLEnums::GetStringEnum(type) << ", "
                  << static_cast<const void*>(pixels) << ")");
+  DCHECK(g_driver_gl.debug_fn.glTexSubImage3DFn != nullptr);
   g_driver_gl.debug_fn.glTexSubImage3DFn(target, level, xoffset, yoffset,
                                          zoffset, width, height, depth, format,
                                          type, pixels);
@@ -4672,6 +4940,7 @@
                  << "(" << program << ", " << count << ", "
                  << static_cast<const void*>(varyings) << ", "
                  << GLEnums::GetStringEnum(bufferMode) << ")");
+  DCHECK(g_driver_gl.debug_fn.glTransformFeedbackVaryingsFn != nullptr);
   g_driver_gl.debug_fn.glTransformFeedbackVaryingsFn(program, count, varyings,
                                                      bufferMode);
 }
@@ -4679,6 +4948,7 @@
 static void GL_BINDING_CALL Debug_glUniform1f(GLint location, GLfloat x) {
   GL_SERVICE_LOG("glUniform1f"
                  << "(" << location << ", " << x << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniform1fFn != nullptr);
   g_driver_gl.debug_fn.glUniform1fFn(location, x);
 }
 
@@ -4688,12 +4958,14 @@
   GL_SERVICE_LOG("glUniform1fv"
                  << "(" << location << ", " << count << ", "
                  << static_cast<const void*>(v) << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniform1fvFn != nullptr);
   g_driver_gl.debug_fn.glUniform1fvFn(location, count, v);
 }
 
 static void GL_BINDING_CALL Debug_glUniform1i(GLint location, GLint x) {
   GL_SERVICE_LOG("glUniform1i"
                  << "(" << location << ", " << x << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniform1iFn != nullptr);
   g_driver_gl.debug_fn.glUniform1iFn(location, x);
 }
 
@@ -4703,12 +4975,14 @@
   GL_SERVICE_LOG("glUniform1iv"
                  << "(" << location << ", " << count << ", "
                  << static_cast<const void*>(v) << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniform1ivFn != nullptr);
   g_driver_gl.debug_fn.glUniform1ivFn(location, count, v);
 }
 
 static void GL_BINDING_CALL Debug_glUniform1ui(GLint location, GLuint v0) {
   GL_SERVICE_LOG("glUniform1ui"
                  << "(" << location << ", " << v0 << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniform1uiFn != nullptr);
   g_driver_gl.debug_fn.glUniform1uiFn(location, v0);
 }
 
@@ -4718,6 +4992,7 @@
   GL_SERVICE_LOG("glUniform1uiv"
                  << "(" << location << ", " << count << ", "
                  << static_cast<const void*>(v) << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniform1uivFn != nullptr);
   g_driver_gl.debug_fn.glUniform1uivFn(location, count, v);
 }
 
@@ -4726,6 +5001,7 @@
                                               GLfloat y) {
   GL_SERVICE_LOG("glUniform2f"
                  << "(" << location << ", " << x << ", " << y << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniform2fFn != nullptr);
   g_driver_gl.debug_fn.glUniform2fFn(location, x, y);
 }
 
@@ -4735,6 +5011,7 @@
   GL_SERVICE_LOG("glUniform2fv"
                  << "(" << location << ", " << count << ", "
                  << static_cast<const void*>(v) << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniform2fvFn != nullptr);
   g_driver_gl.debug_fn.glUniform2fvFn(location, count, v);
 }
 
@@ -4743,6 +5020,7 @@
                                               GLint y) {
   GL_SERVICE_LOG("glUniform2i"
                  << "(" << location << ", " << x << ", " << y << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniform2iFn != nullptr);
   g_driver_gl.debug_fn.glUniform2iFn(location, x, y);
 }
 
@@ -4752,6 +5030,7 @@
   GL_SERVICE_LOG("glUniform2iv"
                  << "(" << location << ", " << count << ", "
                  << static_cast<const void*>(v) << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniform2ivFn != nullptr);
   g_driver_gl.debug_fn.glUniform2ivFn(location, count, v);
 }
 
@@ -4760,6 +5039,7 @@
                                                GLuint v1) {
   GL_SERVICE_LOG("glUniform2ui"
                  << "(" << location << ", " << v0 << ", " << v1 << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniform2uiFn != nullptr);
   g_driver_gl.debug_fn.glUniform2uiFn(location, v0, v1);
 }
 
@@ -4769,6 +5049,7 @@
   GL_SERVICE_LOG("glUniform2uiv"
                  << "(" << location << ", " << count << ", "
                  << static_cast<const void*>(v) << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniform2uivFn != nullptr);
   g_driver_gl.debug_fn.glUniform2uivFn(location, count, v);
 }
 
@@ -4779,6 +5060,7 @@
   GL_SERVICE_LOG("glUniform3f"
                  << "(" << location << ", " << x << ", " << y << ", " << z
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniform3fFn != nullptr);
   g_driver_gl.debug_fn.glUniform3fFn(location, x, y, z);
 }
 
@@ -4788,6 +5070,7 @@
   GL_SERVICE_LOG("glUniform3fv"
                  << "(" << location << ", " << count << ", "
                  << static_cast<const void*>(v) << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniform3fvFn != nullptr);
   g_driver_gl.debug_fn.glUniform3fvFn(location, count, v);
 }
 
@@ -4798,6 +5081,7 @@
   GL_SERVICE_LOG("glUniform3i"
                  << "(" << location << ", " << x << ", " << y << ", " << z
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniform3iFn != nullptr);
   g_driver_gl.debug_fn.glUniform3iFn(location, x, y, z);
 }
 
@@ -4807,6 +5091,7 @@
   GL_SERVICE_LOG("glUniform3iv"
                  << "(" << location << ", " << count << ", "
                  << static_cast<const void*>(v) << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniform3ivFn != nullptr);
   g_driver_gl.debug_fn.glUniform3ivFn(location, count, v);
 }
 
@@ -4817,6 +5102,7 @@
   GL_SERVICE_LOG("glUniform3ui"
                  << "(" << location << ", " << v0 << ", " << v1 << ", " << v2
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniform3uiFn != nullptr);
   g_driver_gl.debug_fn.glUniform3uiFn(location, v0, v1, v2);
 }
 
@@ -4826,6 +5112,7 @@
   GL_SERVICE_LOG("glUniform3uiv"
                  << "(" << location << ", " << count << ", "
                  << static_cast<const void*>(v) << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniform3uivFn != nullptr);
   g_driver_gl.debug_fn.glUniform3uivFn(location, count, v);
 }
 
@@ -4834,6 +5121,7 @@
   GL_SERVICE_LOG("glUniform4f"
                  << "(" << location << ", " << x << ", " << y << ", " << z
                  << ", " << w << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniform4fFn != nullptr);
   g_driver_gl.debug_fn.glUniform4fFn(location, x, y, z, w);
 }
 
@@ -4843,6 +5131,7 @@
   GL_SERVICE_LOG("glUniform4fv"
                  << "(" << location << ", " << count << ", "
                  << static_cast<const void*>(v) << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniform4fvFn != nullptr);
   g_driver_gl.debug_fn.glUniform4fvFn(location, count, v);
 }
 
@@ -4851,6 +5140,7 @@
   GL_SERVICE_LOG("glUniform4i"
                  << "(" << location << ", " << x << ", " << y << ", " << z
                  << ", " << w << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniform4iFn != nullptr);
   g_driver_gl.debug_fn.glUniform4iFn(location, x, y, z, w);
 }
 
@@ -4860,6 +5150,7 @@
   GL_SERVICE_LOG("glUniform4iv"
                  << "(" << location << ", " << count << ", "
                  << static_cast<const void*>(v) << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniform4ivFn != nullptr);
   g_driver_gl.debug_fn.glUniform4ivFn(location, count, v);
 }
 
@@ -4868,6 +5159,7 @@
   GL_SERVICE_LOG("glUniform4ui"
                  << "(" << location << ", " << v0 << ", " << v1 << ", " << v2
                  << ", " << v3 << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniform4uiFn != nullptr);
   g_driver_gl.debug_fn.glUniform4uiFn(location, v0, v1, v2, v3);
 }
 
@@ -4877,6 +5169,7 @@
   GL_SERVICE_LOG("glUniform4uiv"
                  << "(" << location << ", " << count << ", "
                  << static_cast<const void*>(v) << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniform4uivFn != nullptr);
   g_driver_gl.debug_fn.glUniform4uivFn(location, count, v);
 }
 
@@ -4887,6 +5180,7 @@
   GL_SERVICE_LOG("glUniformBlockBinding"
                  << "(" << program << ", " << uniformBlockIndex << ", "
                  << uniformBlockBinding << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniformBlockBindingFn != nullptr);
   g_driver_gl.debug_fn.glUniformBlockBindingFn(program, uniformBlockIndex,
                                                uniformBlockBinding);
 }
@@ -4899,6 +5193,7 @@
                  << "(" << location << ", " << count << ", "
                  << GLEnums::GetStringBool(transpose) << ", "
                  << static_cast<const void*>(value) << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniformMatrix2fvFn != nullptr);
   g_driver_gl.debug_fn.glUniformMatrix2fvFn(location, count, transpose, value);
 }
 
@@ -4910,6 +5205,7 @@
                  << "(" << location << ", " << count << ", "
                  << GLEnums::GetStringBool(transpose) << ", "
                  << static_cast<const void*>(value) << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniformMatrix2x3fvFn != nullptr);
   g_driver_gl.debug_fn.glUniformMatrix2x3fvFn(location, count, transpose,
                                               value);
 }
@@ -4922,6 +5218,7 @@
                  << "(" << location << ", " << count << ", "
                  << GLEnums::GetStringBool(transpose) << ", "
                  << static_cast<const void*>(value) << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniformMatrix2x4fvFn != nullptr);
   g_driver_gl.debug_fn.glUniformMatrix2x4fvFn(location, count, transpose,
                                               value);
 }
@@ -4934,6 +5231,7 @@
                  << "(" << location << ", " << count << ", "
                  << GLEnums::GetStringBool(transpose) << ", "
                  << static_cast<const void*>(value) << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniformMatrix3fvFn != nullptr);
   g_driver_gl.debug_fn.glUniformMatrix3fvFn(location, count, transpose, value);
 }
 
@@ -4945,6 +5243,7 @@
                  << "(" << location << ", " << count << ", "
                  << GLEnums::GetStringBool(transpose) << ", "
                  << static_cast<const void*>(value) << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniformMatrix3x2fvFn != nullptr);
   g_driver_gl.debug_fn.glUniformMatrix3x2fvFn(location, count, transpose,
                                               value);
 }
@@ -4957,6 +5256,7 @@
                  << "(" << location << ", " << count << ", "
                  << GLEnums::GetStringBool(transpose) << ", "
                  << static_cast<const void*>(value) << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniformMatrix3x4fvFn != nullptr);
   g_driver_gl.debug_fn.glUniformMatrix3x4fvFn(location, count, transpose,
                                               value);
 }
@@ -4969,6 +5269,7 @@
                  << "(" << location << ", " << count << ", "
                  << GLEnums::GetStringBool(transpose) << ", "
                  << static_cast<const void*>(value) << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniformMatrix4fvFn != nullptr);
   g_driver_gl.debug_fn.glUniformMatrix4fvFn(location, count, transpose, value);
 }
 
@@ -4980,6 +5281,7 @@
                  << "(" << location << ", " << count << ", "
                  << GLEnums::GetStringBool(transpose) << ", "
                  << static_cast<const void*>(value) << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniformMatrix4x2fvFn != nullptr);
   g_driver_gl.debug_fn.glUniformMatrix4x2fvFn(location, count, transpose,
                                               value);
 }
@@ -4992,6 +5294,7 @@
                  << "(" << location << ", " << count << ", "
                  << GLEnums::GetStringBool(transpose) << ", "
                  << static_cast<const void*>(value) << ")");
+  DCHECK(g_driver_gl.debug_fn.glUniformMatrix4x3fvFn != nullptr);
   g_driver_gl.debug_fn.glUniformMatrix4x3fvFn(location, count, transpose,
                                               value);
 }
@@ -4999,6 +5302,7 @@
 static GLboolean GL_BINDING_CALL Debug_glUnmapBuffer(GLenum target) {
   GL_SERVICE_LOG("glUnmapBuffer"
                  << "(" << GLEnums::GetStringEnum(target) << ")");
+  DCHECK(g_driver_gl.debug_fn.glUnmapBufferFn != nullptr);
   GLboolean result = g_driver_gl.debug_fn.glUnmapBufferFn(target);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -5007,18 +5311,21 @@
 static void GL_BINDING_CALL Debug_glUseProgram(GLuint program) {
   GL_SERVICE_LOG("glUseProgram"
                  << "(" << program << ")");
+  DCHECK(g_driver_gl.debug_fn.glUseProgramFn != nullptr);
   g_driver_gl.debug_fn.glUseProgramFn(program);
 }
 
 static void GL_BINDING_CALL Debug_glValidateProgram(GLuint program) {
   GL_SERVICE_LOG("glValidateProgram"
                  << "(" << program << ")");
+  DCHECK(g_driver_gl.debug_fn.glValidateProgramFn != nullptr);
   g_driver_gl.debug_fn.glValidateProgramFn(program);
 }
 
 static void GL_BINDING_CALL Debug_glVertexAttrib1f(GLuint indx, GLfloat x) {
   GL_SERVICE_LOG("glVertexAttrib1f"
                  << "(" << indx << ", " << x << ")");
+  DCHECK(g_driver_gl.debug_fn.glVertexAttrib1fFn != nullptr);
   g_driver_gl.debug_fn.glVertexAttrib1fFn(indx, x);
 }
 
@@ -5027,6 +5334,7 @@
   GL_SERVICE_LOG("glVertexAttrib1fv"
                  << "(" << indx << ", " << static_cast<const void*>(values)
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glVertexAttrib1fvFn != nullptr);
   g_driver_gl.debug_fn.glVertexAttrib1fvFn(indx, values);
 }
 
@@ -5035,6 +5343,7 @@
                                                    GLfloat y) {
   GL_SERVICE_LOG("glVertexAttrib2f"
                  << "(" << indx << ", " << x << ", " << y << ")");
+  DCHECK(g_driver_gl.debug_fn.glVertexAttrib2fFn != nullptr);
   g_driver_gl.debug_fn.glVertexAttrib2fFn(indx, x, y);
 }
 
@@ -5043,6 +5352,7 @@
   GL_SERVICE_LOG("glVertexAttrib2fv"
                  << "(" << indx << ", " << static_cast<const void*>(values)
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glVertexAttrib2fvFn != nullptr);
   g_driver_gl.debug_fn.glVertexAttrib2fvFn(indx, values);
 }
 
@@ -5052,6 +5362,7 @@
                                                    GLfloat z) {
   GL_SERVICE_LOG("glVertexAttrib3f"
                  << "(" << indx << ", " << x << ", " << y << ", " << z << ")");
+  DCHECK(g_driver_gl.debug_fn.glVertexAttrib3fFn != nullptr);
   g_driver_gl.debug_fn.glVertexAttrib3fFn(indx, x, y, z);
 }
 
@@ -5060,6 +5371,7 @@
   GL_SERVICE_LOG("glVertexAttrib3fv"
                  << "(" << indx << ", " << static_cast<const void*>(values)
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glVertexAttrib3fvFn != nullptr);
   g_driver_gl.debug_fn.glVertexAttrib3fvFn(indx, values);
 }
 
@@ -5071,6 +5383,7 @@
   GL_SERVICE_LOG("glVertexAttrib4f"
                  << "(" << indx << ", " << x << ", " << y << ", " << z << ", "
                  << w << ")");
+  DCHECK(g_driver_gl.debug_fn.glVertexAttrib4fFn != nullptr);
   g_driver_gl.debug_fn.glVertexAttrib4fFn(indx, x, y, z, w);
 }
 
@@ -5079,6 +5392,7 @@
   GL_SERVICE_LOG("glVertexAttrib4fv"
                  << "(" << indx << ", " << static_cast<const void*>(values)
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glVertexAttrib4fvFn != nullptr);
   g_driver_gl.debug_fn.glVertexAttrib4fvFn(indx, values);
 }
 
@@ -5086,6 +5400,7 @@
                                                              GLuint divisor) {
   GL_SERVICE_LOG("glVertexAttribDivisorANGLE"
                  << "(" << index << ", " << divisor << ")");
+  DCHECK(g_driver_gl.debug_fn.glVertexAttribDivisorANGLEFn != nullptr);
   g_driver_gl.debug_fn.glVertexAttribDivisorANGLEFn(index, divisor);
 }
 
@@ -5094,6 +5409,7 @@
   GL_SERVICE_LOG("glVertexAttribI4i"
                  << "(" << indx << ", " << x << ", " << y << ", " << z << ", "
                  << w << ")");
+  DCHECK(g_driver_gl.debug_fn.glVertexAttribI4iFn != nullptr);
   g_driver_gl.debug_fn.glVertexAttribI4iFn(indx, x, y, z, w);
 }
 
@@ -5102,6 +5418,7 @@
   GL_SERVICE_LOG("glVertexAttribI4iv"
                  << "(" << indx << ", " << static_cast<const void*>(values)
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glVertexAttribI4ivFn != nullptr);
   g_driver_gl.debug_fn.glVertexAttribI4ivFn(indx, values);
 }
 
@@ -5110,6 +5427,7 @@
   GL_SERVICE_LOG("glVertexAttribI4ui"
                  << "(" << indx << ", " << x << ", " << y << ", " << z << ", "
                  << w << ")");
+  DCHECK(g_driver_gl.debug_fn.glVertexAttribI4uiFn != nullptr);
   g_driver_gl.debug_fn.glVertexAttribI4uiFn(indx, x, y, z, w);
 }
 
@@ -5118,6 +5436,7 @@
   GL_SERVICE_LOG("glVertexAttribI4uiv"
                  << "(" << indx << ", " << static_cast<const void*>(values)
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glVertexAttribI4uivFn != nullptr);
   g_driver_gl.debug_fn.glVertexAttribI4uivFn(indx, values);
 }
 
@@ -5130,6 +5449,7 @@
                  << "(" << indx << ", " << size << ", "
                  << GLEnums::GetStringEnum(type) << ", " << stride << ", "
                  << static_cast<const void*>(ptr) << ")");
+  DCHECK(g_driver_gl.debug_fn.glVertexAttribIPointerFn != nullptr);
   g_driver_gl.debug_fn.glVertexAttribIPointerFn(indx, size, type, stride, ptr);
 }
 
@@ -5144,6 +5464,7 @@
                  << GLEnums::GetStringEnum(type) << ", "
                  << GLEnums::GetStringBool(normalized) << ", " << stride << ", "
                  << static_cast<const void*>(ptr) << ")");
+  DCHECK(g_driver_gl.debug_fn.glVertexAttribPointerFn != nullptr);
   g_driver_gl.debug_fn.glVertexAttribPointerFn(indx, size, type, normalized,
                                                stride, ptr);
 }
@@ -5155,6 +5476,7 @@
   GL_SERVICE_LOG("glViewport"
                  << "(" << x << ", " << y << ", " << width << ", " << height
                  << ")");
+  DCHECK(g_driver_gl.debug_fn.glViewportFn != nullptr);
   g_driver_gl.debug_fn.glViewportFn(x, y, width, height);
 }
 
@@ -5163,6 +5485,7 @@
                                                GLuint64 timeout) {
   GL_SERVICE_LOG("glWaitSync"
                  << "(" << sync << ", " << flags << ", " << timeout << ")");
+  DCHECK(g_driver_gl.debug_fn.glWaitSyncFn != nullptr);
   GLenum result = g_driver_gl.debug_fn.glWaitSyncFn(sync, flags, timeout);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
diff --git a/ui/gl/gl_bindings_autogen_glx.cc b/ui/gl/gl_bindings_autogen_glx.cc
index 02aee398..819cd014 100644
--- a/ui/gl/gl_bindings_autogen_glx.cc
+++ b/ui/gl/gl_bindings_autogen_glx.cc
@@ -212,6 +212,7 @@
                  << "(" << static_cast<const void*>(dpy) << ", " << drawable
                  << ", " << buffer << ", "
                  << static_cast<const void*>(attribList) << ")");
+  DCHECK(g_driver_glx.debug_fn.glXBindTexImageEXTFn != nullptr);
   g_driver_glx.debug_fn.glXBindTexImageEXTFn(dpy, drawable, buffer, attribList);
 }
 
@@ -224,6 +225,7 @@
                  << "(" << static_cast<const void*>(dpy) << ", " << screen
                  << ", " << static_cast<const void*>(attribList) << ", "
                  << static_cast<const void*>(nitems) << ")");
+  DCHECK(g_driver_glx.debug_fn.glXChooseFBConfigFn != nullptr);
   GLXFBConfig* result = g_driver_glx.debug_fn.glXChooseFBConfigFn(
       dpy, screen, attribList, nitems);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -236,6 +238,7 @@
   GL_SERVICE_LOG("glXChooseVisual"
                  << "(" << static_cast<const void*>(dpy) << ", " << screen
                  << ", " << static_cast<const void*>(attribList) << ")");
+  DCHECK(g_driver_glx.debug_fn.glXChooseVisualFn != nullptr);
   XVisualInfo* result =
       g_driver_glx.debug_fn.glXChooseVisualFn(dpy, screen, attribList);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -249,6 +252,7 @@
   GL_SERVICE_LOG("glXCopyContext"
                  << "(" << static_cast<const void*>(dpy) << ", " << src << ", "
                  << dst << ", " << mask << ")");
+  DCHECK(g_driver_glx.debug_fn.glXCopyContextFn != nullptr);
   g_driver_glx.debug_fn.glXCopyContextFn(dpy, src, dst, mask);
 }
 
@@ -262,6 +266,7 @@
                  << "(" << static_cast<const void*>(dpy) << ", " << drawable
                  << ", " << x << ", " << y << ", " << width << ", " << height
                  << ")");
+  DCHECK(g_driver_glx.debug_fn.glXCopySubBufferMESAFn != nullptr);
   g_driver_glx.debug_fn.glXCopySubBufferMESAFn(dpy, drawable, x, y, width,
                                                height);
 }
@@ -274,6 +279,7 @@
                  << "(" << static_cast<const void*>(dpy) << ", "
                  << static_cast<const void*>(vis) << ", " << shareList << ", "
                  << direct << ")");
+  DCHECK(g_driver_glx.debug_fn.glXCreateContextFn != nullptr);
   GLXContext result =
       g_driver_glx.debug_fn.glXCreateContextFn(dpy, vis, shareList, direct);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -290,6 +296,7 @@
                  << "(" << static_cast<const void*>(dpy) << ", " << config
                  << ", " << share_context << ", " << direct << ", "
                  << static_cast<const void*>(attrib_list) << ")");
+  DCHECK(g_driver_glx.debug_fn.glXCreateContextAttribsARBFn != nullptr);
   GLXContext result = g_driver_glx.debug_fn.glXCreateContextAttribsARBFn(
       dpy, config, share_context, direct, attrib_list);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -302,6 +309,7 @@
   GL_SERVICE_LOG("glXCreateGLXPixmap"
                  << "(" << static_cast<const void*>(dpy) << ", "
                  << static_cast<const void*>(visual) << ", " << pixmap << ")");
+  DCHECK(g_driver_glx.debug_fn.glXCreateGLXPixmapFn != nullptr);
   GLXPixmap result =
       g_driver_glx.debug_fn.glXCreateGLXPixmapFn(dpy, visual, pixmap);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -318,6 +326,7 @@
                  << "(" << static_cast<const void*>(dpy) << ", " << config
                  << ", " << renderType << ", " << shareList << ", " << direct
                  << ")");
+  DCHECK(g_driver_glx.debug_fn.glXCreateNewContextFn != nullptr);
   GLXContext result = g_driver_glx.debug_fn.glXCreateNewContextFn(
       dpy, config, renderType, shareList, direct);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -331,6 +340,7 @@
   GL_SERVICE_LOG("glXCreatePbuffer"
                  << "(" << static_cast<const void*>(dpy) << ", " << config
                  << ", " << static_cast<const void*>(attribList) << ")");
+  DCHECK(g_driver_glx.debug_fn.glXCreatePbufferFn != nullptr);
   GLXPbuffer result =
       g_driver_glx.debug_fn.glXCreatePbufferFn(dpy, config, attribList);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -345,6 +355,7 @@
                  << "(" << static_cast<const void*>(dpy) << ", " << config
                  << ", " << pixmap << ", "
                  << static_cast<const void*>(attribList) << ")");
+  DCHECK(g_driver_glx.debug_fn.glXCreatePixmapFn != nullptr);
   GLXPixmap result =
       g_driver_glx.debug_fn.glXCreatePixmapFn(dpy, config, pixmap, attribList);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -359,6 +370,7 @@
                  << "(" << static_cast<const void*>(dpy) << ", " << config
                  << ", " << win << ", " << static_cast<const void*>(attribList)
                  << ")");
+  DCHECK(g_driver_glx.debug_fn.glXCreateWindowFn != nullptr);
   GLXWindow result =
       g_driver_glx.debug_fn.glXCreateWindowFn(dpy, config, win, attribList);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -369,6 +381,7 @@
                                                     GLXContext ctx) {
   GL_SERVICE_LOG("glXDestroyContext"
                  << "(" << static_cast<const void*>(dpy) << ", " << ctx << ")");
+  DCHECK(g_driver_glx.debug_fn.glXDestroyContextFn != nullptr);
   g_driver_glx.debug_fn.glXDestroyContextFn(dpy, ctx);
 }
 
@@ -377,6 +390,7 @@
   GL_SERVICE_LOG("glXDestroyGLXPixmap"
                  << "(" << static_cast<const void*>(dpy) << ", " << pixmap
                  << ")");
+  DCHECK(g_driver_glx.debug_fn.glXDestroyGLXPixmapFn != nullptr);
   g_driver_glx.debug_fn.glXDestroyGLXPixmapFn(dpy, pixmap);
 }
 
@@ -385,6 +399,7 @@
   GL_SERVICE_LOG("glXDestroyPbuffer"
                  << "(" << static_cast<const void*>(dpy) << ", " << pbuf
                  << ")");
+  DCHECK(g_driver_glx.debug_fn.glXDestroyPbufferFn != nullptr);
   g_driver_glx.debug_fn.glXDestroyPbufferFn(dpy, pbuf);
 }
 
@@ -393,6 +408,7 @@
   GL_SERVICE_LOG("glXDestroyPixmap"
                  << "(" << static_cast<const void*>(dpy) << ", " << pixmap
                  << ")");
+  DCHECK(g_driver_glx.debug_fn.glXDestroyPixmapFn != nullptr);
   g_driver_glx.debug_fn.glXDestroyPixmapFn(dpy, pixmap);
 }
 
@@ -401,6 +417,7 @@
   GL_SERVICE_LOG("glXDestroyWindow"
                  << "(" << static_cast<const void*>(dpy) << ", " << window
                  << ")");
+  DCHECK(g_driver_glx.debug_fn.glXDestroyWindowFn != nullptr);
   g_driver_glx.debug_fn.glXDestroyWindowFn(dpy, window);
 }
 
@@ -409,6 +426,7 @@
   GL_SERVICE_LOG("glXGetClientString"
                  << "(" << static_cast<const void*>(dpy) << ", " << name
                  << ")");
+  DCHECK(g_driver_glx.debug_fn.glXGetClientStringFn != nullptr);
   const char* result = g_driver_glx.debug_fn.glXGetClientStringFn(dpy, name);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -422,6 +440,7 @@
                  << "(" << static_cast<const void*>(dpy) << ", "
                  << static_cast<const void*>(visual) << ", " << attrib << ", "
                  << static_cast<const void*>(value) << ")");
+  DCHECK(g_driver_glx.debug_fn.glXGetConfigFn != nullptr);
   int result = g_driver_glx.debug_fn.glXGetConfigFn(dpy, visual, attrib, value);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -431,6 +450,7 @@
   GL_SERVICE_LOG("glXGetCurrentContext"
                  << "("
                  << ")");
+  DCHECK(g_driver_glx.debug_fn.glXGetCurrentContextFn != nullptr);
   GLXContext result = g_driver_glx.debug_fn.glXGetCurrentContextFn();
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -440,6 +460,7 @@
   GL_SERVICE_LOG("glXGetCurrentDisplay"
                  << "("
                  << ")");
+  DCHECK(g_driver_glx.debug_fn.glXGetCurrentDisplayFn != nullptr);
   Display* result = g_driver_glx.debug_fn.glXGetCurrentDisplayFn();
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -449,6 +470,7 @@
   GL_SERVICE_LOG("glXGetCurrentDrawable"
                  << "("
                  << ")");
+  DCHECK(g_driver_glx.debug_fn.glXGetCurrentDrawableFn != nullptr);
   GLXDrawable result = g_driver_glx.debug_fn.glXGetCurrentDrawableFn();
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -458,6 +480,7 @@
   GL_SERVICE_LOG("glXGetCurrentReadDrawable"
                  << "("
                  << ")");
+  DCHECK(g_driver_glx.debug_fn.glXGetCurrentReadDrawableFn != nullptr);
   GLXDrawable result = g_driver_glx.debug_fn.glXGetCurrentReadDrawableFn();
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -471,6 +494,7 @@
                  << "(" << static_cast<const void*>(dpy) << ", " << config
                  << ", " << attribute << ", " << static_cast<const void*>(value)
                  << ")");
+  DCHECK(g_driver_glx.debug_fn.glXGetFBConfigAttribFn != nullptr);
   int result = g_driver_glx.debug_fn.glXGetFBConfigAttribFn(dpy, config,
                                                             attribute, value);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -482,6 +506,7 @@
   GL_SERVICE_LOG("glXGetFBConfigFromVisualSGIX"
                  << "(" << static_cast<const void*>(dpy) << ", "
                  << static_cast<const void*>(visualInfo) << ")");
+  DCHECK(g_driver_glx.debug_fn.glXGetFBConfigFromVisualSGIXFn != nullptr);
   GLXFBConfig result =
       g_driver_glx.debug_fn.glXGetFBConfigFromVisualSGIXFn(dpy, visualInfo);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -494,6 +519,7 @@
   GL_SERVICE_LOG("glXGetFBConfigs"
                  << "(" << static_cast<const void*>(dpy) << ", " << screen
                  << ", " << static_cast<const void*>(nelements) << ")");
+  DCHECK(g_driver_glx.debug_fn.glXGetFBConfigsFn != nullptr);
   GLXFBConfig* result =
       g_driver_glx.debug_fn.glXGetFBConfigsFn(dpy, screen, nelements);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -508,6 +534,7 @@
                  << "(" << static_cast<const void*>(dpy) << ", " << drawable
                  << ", " << static_cast<const void*>(numerator) << ", "
                  << static_cast<const void*>(denominator) << ")");
+  DCHECK(g_driver_glx.debug_fn.glXGetMscRateOMLFn != nullptr);
   bool result = g_driver_glx.debug_fn.glXGetMscRateOMLFn(
       dpy, drawable, numerator, denominator);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -520,6 +547,7 @@
   GL_SERVICE_LOG("glXGetSelectedEvent"
                  << "(" << static_cast<const void*>(dpy) << ", " << drawable
                  << ", " << static_cast<const void*>(mask) << ")");
+  DCHECK(g_driver_glx.debug_fn.glXGetSelectedEventFn != nullptr);
   g_driver_glx.debug_fn.glXGetSelectedEventFn(dpy, drawable, mask);
 }
 
@@ -533,6 +561,7 @@
                  << ", " << static_cast<const void*>(ust) << ", "
                  << static_cast<const void*>(msc) << ", "
                  << static_cast<const void*>(sbc) << ")");
+  DCHECK(g_driver_glx.debug_fn.glXGetSyncValuesOMLFn != nullptr);
   bool result =
       g_driver_glx.debug_fn.glXGetSyncValuesOMLFn(dpy, drawable, ust, msc, sbc);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -544,6 +573,7 @@
   GL_SERVICE_LOG("glXGetVisualFromFBConfig"
                  << "(" << static_cast<const void*>(dpy) << ", " << config
                  << ")");
+  DCHECK(g_driver_glx.debug_fn.glXGetVisualFromFBConfigFn != nullptr);
   XVisualInfo* result =
       g_driver_glx.debug_fn.glXGetVisualFromFBConfigFn(dpy, config);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -553,6 +583,7 @@
 static int GL_BINDING_CALL Debug_glXIsDirect(Display* dpy, GLXContext ctx) {
   GL_SERVICE_LOG("glXIsDirect"
                  << "(" << static_cast<const void*>(dpy) << ", " << ctx << ")");
+  DCHECK(g_driver_glx.debug_fn.glXIsDirectFn != nullptr);
   int result = g_driver_glx.debug_fn.glXIsDirectFn(dpy, ctx);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -565,6 +596,7 @@
   GL_SERVICE_LOG("glXMakeContextCurrent"
                  << "(" << static_cast<const void*>(dpy) << ", " << draw << ", "
                  << read << ", " << ctx << ")");
+  DCHECK(g_driver_glx.debug_fn.glXMakeContextCurrentFn != nullptr);
   int result =
       g_driver_glx.debug_fn.glXMakeContextCurrentFn(dpy, draw, read, ctx);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -577,6 +609,7 @@
   GL_SERVICE_LOG("glXMakeCurrent"
                  << "(" << static_cast<const void*>(dpy) << ", " << drawable
                  << ", " << ctx << ")");
+  DCHECK(g_driver_glx.debug_fn.glXMakeCurrentFn != nullptr);
   int result = g_driver_glx.debug_fn.glXMakeCurrentFn(dpy, drawable, ctx);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -590,6 +623,7 @@
                  << "(" << static_cast<const void*>(dpy) << ", " << ctx << ", "
                  << attribute << ", " << static_cast<const void*>(value)
                  << ")");
+  DCHECK(g_driver_glx.debug_fn.glXQueryContextFn != nullptr);
   int result =
       g_driver_glx.debug_fn.glXQueryContextFn(dpy, ctx, attribute, value);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -604,6 +638,7 @@
                  << "(" << static_cast<const void*>(dpy) << ", " << draw << ", "
                  << attribute << ", " << static_cast<const void*>(value)
                  << ")");
+  DCHECK(g_driver_glx.debug_fn.glXQueryDrawableFn != nullptr);
   g_driver_glx.debug_fn.glXQueryDrawableFn(dpy, draw, attribute, value);
 }
 
@@ -614,6 +649,7 @@
                  << "(" << static_cast<const void*>(dpy) << ", "
                  << static_cast<const void*>(errorb) << ", "
                  << static_cast<const void*>(event) << ")");
+  DCHECK(g_driver_glx.debug_fn.glXQueryExtensionFn != nullptr);
   int result = g_driver_glx.debug_fn.glXQueryExtensionFn(dpy, errorb, event);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -624,6 +660,7 @@
   GL_SERVICE_LOG("glXQueryExtensionsString"
                  << "(" << static_cast<const void*>(dpy) << ", " << screen
                  << ")");
+  DCHECK(g_driver_glx.debug_fn.glXQueryExtensionsStringFn != nullptr);
   const char* result =
       g_driver_glx.debug_fn.glXQueryExtensionsStringFn(dpy, screen);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -636,6 +673,7 @@
   GL_SERVICE_LOG("glXQueryServerString"
                  << "(" << static_cast<const void*>(dpy) << ", " << screen
                  << ", " << name << ")");
+  DCHECK(g_driver_glx.debug_fn.glXQueryServerStringFn != nullptr);
   const char* result =
       g_driver_glx.debug_fn.glXQueryServerStringFn(dpy, screen, name);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -649,6 +687,7 @@
                  << "(" << static_cast<const void*>(dpy) << ", "
                  << static_cast<const void*>(maj) << ", "
                  << static_cast<const void*>(min) << ")");
+  DCHECK(g_driver_glx.debug_fn.glXQueryVersionFn != nullptr);
   int result = g_driver_glx.debug_fn.glXQueryVersionFn(dpy, maj, min);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -660,6 +699,7 @@
   GL_SERVICE_LOG("glXReleaseTexImageEXT"
                  << "(" << static_cast<const void*>(dpy) << ", " << drawable
                  << ", " << buffer << ")");
+  DCHECK(g_driver_glx.debug_fn.glXReleaseTexImageEXTFn != nullptr);
   g_driver_glx.debug_fn.glXReleaseTexImageEXTFn(dpy, drawable, buffer);
 }
 
@@ -669,6 +709,7 @@
   GL_SERVICE_LOG("glXSelectEvent"
                  << "(" << static_cast<const void*>(dpy) << ", " << drawable
                  << ", " << mask << ")");
+  DCHECK(g_driver_glx.debug_fn.glXSelectEventFn != nullptr);
   g_driver_glx.debug_fn.glXSelectEventFn(dpy, drawable, mask);
 }
 
@@ -677,6 +718,7 @@
   GL_SERVICE_LOG("glXSwapBuffers"
                  << "(" << static_cast<const void*>(dpy) << ", " << drawable
                  << ")");
+  DCHECK(g_driver_glx.debug_fn.glXSwapBuffersFn != nullptr);
   g_driver_glx.debug_fn.glXSwapBuffersFn(dpy, drawable);
 }
 
@@ -686,12 +728,14 @@
   GL_SERVICE_LOG("glXSwapIntervalEXT"
                  << "(" << static_cast<const void*>(dpy) << ", " << drawable
                  << ", " << interval << ")");
+  DCHECK(g_driver_glx.debug_fn.glXSwapIntervalEXTFn != nullptr);
   g_driver_glx.debug_fn.glXSwapIntervalEXTFn(dpy, drawable, interval);
 }
 
 static void GL_BINDING_CALL Debug_glXSwapIntervalMESA(unsigned int interval) {
   GL_SERVICE_LOG("glXSwapIntervalMESA"
                  << "(" << interval << ")");
+  DCHECK(g_driver_glx.debug_fn.glXSwapIntervalMESAFn != nullptr);
   g_driver_glx.debug_fn.glXSwapIntervalMESAFn(interval);
 }
 
@@ -702,6 +746,7 @@
   GL_SERVICE_LOG("glXUseXFont"
                  << "(" << font << ", " << first << ", " << count << ", "
                  << list << ")");
+  DCHECK(g_driver_glx.debug_fn.glXUseXFontFn != nullptr);
   g_driver_glx.debug_fn.glXUseXFontFn(font, first, count, list);
 }
 
@@ -709,6 +754,7 @@
   GL_SERVICE_LOG("glXWaitGL"
                  << "("
                  << ")");
+  DCHECK(g_driver_glx.debug_fn.glXWaitGLFn != nullptr);
   g_driver_glx.debug_fn.glXWaitGLFn();
 }
 
@@ -718,6 +764,7 @@
   GL_SERVICE_LOG("glXWaitVideoSyncSGI"
                  << "(" << divisor << ", " << remainder << ", "
                  << static_cast<const void*>(count) << ")");
+  DCHECK(g_driver_glx.debug_fn.glXWaitVideoSyncSGIFn != nullptr);
   int result =
       g_driver_glx.debug_fn.glXWaitVideoSyncSGIFn(divisor, remainder, count);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -728,6 +775,7 @@
   GL_SERVICE_LOG("glXWaitX"
                  << "("
                  << ")");
+  DCHECK(g_driver_glx.debug_fn.glXWaitXFn != nullptr);
   g_driver_glx.debug_fn.glXWaitXFn();
 }
 }  // extern "C"
diff --git a/ui/gl/gl_bindings_autogen_osmesa.cc b/ui/gl/gl_bindings_autogen_osmesa.cc
index 27d31e2..1f03fe3 100644
--- a/ui/gl/gl_bindings_autogen_osmesa.cc
+++ b/ui/gl/gl_bindings_autogen_osmesa.cc
@@ -62,6 +62,7 @@
 static void GL_BINDING_CALL Debug_OSMesaColorClamp(GLboolean enable) {
   GL_SERVICE_LOG("OSMesaColorClamp"
                  << "(" << GLEnums::GetStringBool(enable) << ")");
+  DCHECK(g_driver_osmesa.debug_fn.OSMesaColorClampFn != nullptr);
   g_driver_osmesa.debug_fn.OSMesaColorClampFn(enable);
 }
 
@@ -70,6 +71,7 @@
   GL_SERVICE_LOG("OSMesaCreateContext"
                  << "(" << GLEnums::GetStringEnum(format) << ", " << sharelist
                  << ")");
+  DCHECK(g_driver_osmesa.debug_fn.OSMesaCreateContextFn != nullptr);
   OSMesaContext result =
       g_driver_osmesa.debug_fn.OSMesaCreateContextFn(format, sharelist);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -86,6 +88,7 @@
                  << "(" << GLEnums::GetStringEnum(format) << ", " << depthBits
                  << ", " << stencilBits << ", " << accumBits << ", "
                  << sharelist << ")");
+  DCHECK(g_driver_osmesa.debug_fn.OSMesaCreateContextExtFn != nullptr);
   OSMesaContext result = g_driver_osmesa.debug_fn.OSMesaCreateContextExtFn(
       format, depthBits, stencilBits, accumBits, sharelist);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -95,6 +98,7 @@
 static void GL_BINDING_CALL Debug_OSMesaDestroyContext(OSMesaContext ctx) {
   GL_SERVICE_LOG("OSMesaDestroyContext"
                  << "(" << ctx << ")");
+  DCHECK(g_driver_osmesa.debug_fn.OSMesaDestroyContextFn != nullptr);
   g_driver_osmesa.debug_fn.OSMesaDestroyContextFn(ctx);
 }
 
@@ -107,6 +111,7 @@
                  << "(" << c << ", " << static_cast<const void*>(width) << ", "
                  << static_cast<const void*>(height) << ", "
                  << static_cast<const void*>(format) << ", " << buffer << ")");
+  DCHECK(g_driver_osmesa.debug_fn.OSMesaGetColorBufferFn != nullptr);
   GLboolean result = g_driver_osmesa.debug_fn.OSMesaGetColorBufferFn(
       c, width, height, format, buffer);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -117,6 +122,7 @@
   GL_SERVICE_LOG("OSMesaGetCurrentContext"
                  << "("
                  << ")");
+  DCHECK(g_driver_osmesa.debug_fn.OSMesaGetCurrentContextFn != nullptr);
   OSMesaContext result = g_driver_osmesa.debug_fn.OSMesaGetCurrentContextFn();
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -133,6 +139,7 @@
                  << static_cast<const void*>(height) << ", "
                  << static_cast<const void*>(bytesPerValue) << ", " << buffer
                  << ")");
+  DCHECK(g_driver_osmesa.debug_fn.OSMesaGetDepthBufferFn != nullptr);
   GLboolean result = g_driver_osmesa.debug_fn.OSMesaGetDepthBufferFn(
       c, width, height, bytesPerValue, buffer);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -143,6 +150,7 @@
   GL_SERVICE_LOG("OSMesaGetIntegerv"
                  << "(" << pname << ", " << static_cast<const void*>(value)
                  << ")");
+  DCHECK(g_driver_osmesa.debug_fn.OSMesaGetIntegervFn != nullptr);
   g_driver_osmesa.debug_fn.OSMesaGetIntegervFn(pname, value);
 }
 
@@ -150,6 +158,7 @@
 Debug_OSMesaGetProcAddress(const char* funcName) {
   GL_SERVICE_LOG("OSMesaGetProcAddress"
                  << "(" << funcName << ")");
+  DCHECK(g_driver_osmesa.debug_fn.OSMesaGetProcAddressFn != nullptr);
   OSMESAproc result = g_driver_osmesa.debug_fn.OSMesaGetProcAddressFn(funcName);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -164,6 +173,7 @@
                  << "(" << ctx << ", " << static_cast<const void*>(buffer)
                  << ", " << GLEnums::GetStringEnum(type) << ", " << width
                  << ", " << height << ")");
+  DCHECK(g_driver_osmesa.debug_fn.OSMesaMakeCurrentFn != nullptr);
   GLboolean result = g_driver_osmesa.debug_fn.OSMesaMakeCurrentFn(
       ctx, buffer, type, width, height);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -173,6 +183,7 @@
 static void GL_BINDING_CALL Debug_OSMesaPixelStore(GLint pname, GLint value) {
   GL_SERVICE_LOG("OSMesaPixelStore"
                  << "(" << pname << ", " << value << ")");
+  DCHECK(g_driver_osmesa.debug_fn.OSMesaPixelStoreFn != nullptr);
   g_driver_osmesa.debug_fn.OSMesaPixelStoreFn(pname, value);
 }
 }  // extern "C"
diff --git a/ui/gl/gl_bindings_autogen_wgl.cc b/ui/gl/gl_bindings_autogen_wgl.cc
index f1bcb2f..4791424e7 100644
--- a/ui/gl/gl_bindings_autogen_wgl.cc
+++ b/ui/gl/gl_bindings_autogen_wgl.cc
@@ -135,6 +135,7 @@
                  << static_cast<const void*>(float_attrib_list) << ", "
                  << max_formats << ", " << static_cast<const void*>(formats)
                  << ", " << static_cast<const void*>(num_formats) << ")");
+  DCHECK(g_driver_wgl.debug_fn.wglChoosePixelFormatARBFn != nullptr);
   BOOL result = g_driver_wgl.debug_fn.wglChoosePixelFormatARBFn(
       dc, int_attrib_list, float_attrib_list, max_formats, formats,
       num_formats);
@@ -147,6 +148,7 @@
                                                  UINT mask) {
   GL_SERVICE_LOG("wglCopyContext"
                  << "(" << hglrcSrc << ", " << hglrcDst << ", " << mask << ")");
+  DCHECK(g_driver_wgl.debug_fn.wglCopyContextFn != nullptr);
   BOOL result =
       g_driver_wgl.debug_fn.wglCopyContextFn(hglrcSrc, hglrcDst, mask);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -156,6 +158,7 @@
 static HGLRC GL_BINDING_CALL Debug_wglCreateContext(HDC hdc) {
   GL_SERVICE_LOG("wglCreateContext"
                  << "(" << hdc << ")");
+  DCHECK(g_driver_wgl.debug_fn.wglCreateContextFn != nullptr);
   HGLRC result = g_driver_wgl.debug_fn.wglCreateContextFn(hdc);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -165,6 +168,7 @@
                                                          int iLayerPlane) {
   GL_SERVICE_LOG("wglCreateLayerContext"
                  << "(" << hdc << ", " << iLayerPlane << ")");
+  DCHECK(g_driver_wgl.debug_fn.wglCreateLayerContextFn != nullptr);
   HGLRC result =
       g_driver_wgl.debug_fn.wglCreateLayerContextFn(hdc, iLayerPlane);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -181,6 +185,7 @@
                  << "(" << hDC << ", " << iPixelFormat << ", " << iWidth << ", "
                  << iHeight << ", " << static_cast<const void*>(piAttribList)
                  << ")");
+  DCHECK(g_driver_wgl.debug_fn.wglCreatePbufferARBFn != nullptr);
   HPBUFFERARB result = g_driver_wgl.debug_fn.wglCreatePbufferARBFn(
       hDC, iPixelFormat, iWidth, iHeight, piAttribList);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -190,6 +195,7 @@
 static BOOL GL_BINDING_CALL Debug_wglDeleteContext(HGLRC hglrc) {
   GL_SERVICE_LOG("wglDeleteContext"
                  << "(" << hglrc << ")");
+  DCHECK(g_driver_wgl.debug_fn.wglDeleteContextFn != nullptr);
   BOOL result = g_driver_wgl.debug_fn.wglDeleteContextFn(hglrc);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -198,6 +204,7 @@
 static BOOL GL_BINDING_CALL Debug_wglDestroyPbufferARB(HPBUFFERARB hPbuffer) {
   GL_SERVICE_LOG("wglDestroyPbufferARB"
                  << "(" << hPbuffer << ")");
+  DCHECK(g_driver_wgl.debug_fn.wglDestroyPbufferARBFn != nullptr);
   BOOL result = g_driver_wgl.debug_fn.wglDestroyPbufferARBFn(hPbuffer);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -207,6 +214,7 @@
   GL_SERVICE_LOG("wglGetCurrentContext"
                  << "("
                  << ")");
+  DCHECK(g_driver_wgl.debug_fn.wglGetCurrentContextFn != nullptr);
   HGLRC result = g_driver_wgl.debug_fn.wglGetCurrentContextFn();
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -216,6 +224,7 @@
   GL_SERVICE_LOG("wglGetCurrentDC"
                  << "("
                  << ")");
+  DCHECK(g_driver_wgl.debug_fn.wglGetCurrentDCFn != nullptr);
   HDC result = g_driver_wgl.debug_fn.wglGetCurrentDCFn();
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -224,6 +233,7 @@
 static const char* GL_BINDING_CALL Debug_wglGetExtensionsStringARB(HDC hDC) {
   GL_SERVICE_LOG("wglGetExtensionsStringARB"
                  << "(" << hDC << ")");
+  DCHECK(g_driver_wgl.debug_fn.wglGetExtensionsStringARBFn != nullptr);
   const char* result = g_driver_wgl.debug_fn.wglGetExtensionsStringARBFn(hDC);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -233,6 +243,7 @@
   GL_SERVICE_LOG("wglGetExtensionsStringEXT"
                  << "("
                  << ")");
+  DCHECK(g_driver_wgl.debug_fn.wglGetExtensionsStringEXTFn != nullptr);
   const char* result = g_driver_wgl.debug_fn.wglGetExtensionsStringEXTFn();
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -241,6 +252,7 @@
 static HDC GL_BINDING_CALL Debug_wglGetPbufferDCARB(HPBUFFERARB hPbuffer) {
   GL_SERVICE_LOG("wglGetPbufferDCARB"
                  << "(" << hPbuffer << ")");
+  DCHECK(g_driver_wgl.debug_fn.wglGetPbufferDCARBFn != nullptr);
   HDC result = g_driver_wgl.debug_fn.wglGetPbufferDCARBFn(hPbuffer);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -249,6 +261,7 @@
 static BOOL GL_BINDING_CALL Debug_wglMakeCurrent(HDC hdc, HGLRC hglrc) {
   GL_SERVICE_LOG("wglMakeCurrent"
                  << "(" << hdc << ", " << hglrc << ")");
+  DCHECK(g_driver_wgl.debug_fn.wglMakeCurrentFn != nullptr);
   BOOL result = g_driver_wgl.debug_fn.wglMakeCurrentFn(hdc, hglrc);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -260,6 +273,7 @@
   GL_SERVICE_LOG("wglQueryPbufferARB"
                  << "(" << hPbuffer << ", " << iAttribute << ", "
                  << static_cast<const void*>(piValue) << ")");
+  DCHECK(g_driver_wgl.debug_fn.wglQueryPbufferARBFn != nullptr);
   BOOL result =
       g_driver_wgl.debug_fn.wglQueryPbufferARBFn(hPbuffer, iAttribute, piValue);
   GL_SERVICE_LOG("GL_RESULT: " << result);
@@ -270,6 +284,7 @@
                                                         HDC hDC) {
   GL_SERVICE_LOG("wglReleasePbufferDCARB"
                  << "(" << hPbuffer << ", " << hDC << ")");
+  DCHECK(g_driver_wgl.debug_fn.wglReleasePbufferDCARBFn != nullptr);
   int result = g_driver_wgl.debug_fn.wglReleasePbufferDCARBFn(hPbuffer, hDC);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -278,6 +293,7 @@
 static BOOL GL_BINDING_CALL Debug_wglShareLists(HGLRC hglrc1, HGLRC hglrc2) {
   GL_SERVICE_LOG("wglShareLists"
                  << "(" << hglrc1 << ", " << hglrc2 << ")");
+  DCHECK(g_driver_wgl.debug_fn.wglShareListsFn != nullptr);
   BOOL result = g_driver_wgl.debug_fn.wglShareListsFn(hglrc1, hglrc2);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -286,6 +302,7 @@
 static BOOL GL_BINDING_CALL Debug_wglSwapIntervalEXT(int interval) {
   GL_SERVICE_LOG("wglSwapIntervalEXT"
                  << "(" << interval << ")");
+  DCHECK(g_driver_wgl.debug_fn.wglSwapIntervalEXTFn != nullptr);
   BOOL result = g_driver_wgl.debug_fn.wglSwapIntervalEXTFn(interval);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
@@ -294,6 +311,7 @@
 static BOOL GL_BINDING_CALL Debug_wglSwapLayerBuffers(HDC hdc, UINT fuPlanes) {
   GL_SERVICE_LOG("wglSwapLayerBuffers"
                  << "(" << hdc << ", " << fuPlanes << ")");
+  DCHECK(g_driver_wgl.debug_fn.wglSwapLayerBuffersFn != nullptr);
   BOOL result = g_driver_wgl.debug_fn.wglSwapLayerBuffersFn(hdc, fuPlanes);
   GL_SERVICE_LOG("GL_RESULT: " << result);
   return result;
diff --git a/ui/native_theme/native_theme_base.cc b/ui/native_theme/native_theme_base.cc
index 4da1497..9dbecee 100644
--- a/ui/native_theme/native_theme_base.cc
+++ b/ui/native_theme/native_theme_base.cc
@@ -616,12 +616,10 @@
   else /* kNormal */
     startEndColors = kCheckboxGradientColors;
   SkColor colors[3] = {startEndColors[0], startEndColors[0], startEndColors[1]};
-  skia::RefPtr<SkShader> shader = skia::AdoptRef(
-      SkGradientShader::CreateLinear(
-          gradient_bounds, colors, NULL, 3, SkShader::kClamp_TileMode));
   SkPaint paint;
   paint.setAntiAlias(true);
-  paint.setShader(shader.get());
+  paint.setShader(SkGradientShader::MakeLinear(gradient_bounds, colors, NULL, 3,
+                                               SkShader::kClamp_TileMode));
   paint.setStyle(SkPaint::kFill_Style);
   canvas->drawRoundRect(skrect, borderRadius, borderRadius, paint);
   paint.setShader(NULL);
diff --git a/ui/native_theme/native_theme_win.cc b/ui/native_theme/native_theme_win.cc
index 745af69..eef9df02 100644
--- a/ui/native_theme/native_theme_win.cc
+++ b/ui/native_theme/native_theme_win.cc
@@ -76,12 +76,9 @@
   SkMatrix local_matrix;
   local_matrix.setTranslate(SkIntToScalar(align_rect.left),
                             SkIntToScalar(align_rect.top));
-  skia::RefPtr<SkShader> shader =
-      skia::AdoptRef(SkShader::CreateBitmapShader(bitmap,
-                                                  SkShader::kRepeat_TileMode,
-                                                  SkShader::kRepeat_TileMode,
-                                                  &local_matrix));
-  paint->setShader(shader.get());
+  paint->setShader(
+      SkShader::MakeBitmapShader(bitmap, SkShader::kRepeat_TileMode,
+                                 SkShader::kRepeat_TileMode, &local_matrix));
 }
 
 //    <-a->
diff --git a/ui/views/animation/test/test_ink_drop_delegate.cc b/ui/views/animation/test/test_ink_drop_delegate.cc
new file mode 100644
index 0000000..103edf2
--- /dev/null
+++ b/ui/views/animation/test/test_ink_drop_delegate.cc
@@ -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 "ui/views/animation/test/test_ink_drop_delegate.h"
+
+namespace views {
+namespace test {
+
+TestInkDropDelegate::TestInkDropDelegate()
+    : state_(InkDropState::HIDDEN), is_hovered_(false) {}
+
+TestInkDropDelegate::~TestInkDropDelegate() {}
+
+void TestInkDropDelegate::OnAction(InkDropState state) {
+  state_ = state;
+}
+
+void TestInkDropDelegate::SetHovered(bool is_hovered) {
+  is_hovered_ = is_hovered;
+}
+
+}  // namespace test
+}  // namespace views
diff --git a/ui/views/animation/test/test_ink_drop_delegate.h b/ui/views/animation/test/test_ink_drop_delegate.h
new file mode 100644
index 0000000..0fe2cbac
--- /dev/null
+++ b/ui/views/animation/test/test_ink_drop_delegate.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 UI_VIEWS_ANIMATION_TEST_TEST_INK_DROP_DELEGATE_H_
+#define UI_VIEWS_ANIMATION_TEST_TEST_INK_DROP_DELEGATE_H_
+
+#include "base/macros.h"
+#include "ui/views/animation/ink_drop_delegate.h"
+
+namespace views {
+namespace test {
+
+class TestInkDropDelegate : public InkDropDelegate {
+ public:
+  TestInkDropDelegate();
+  ~TestInkDropDelegate() override;
+
+  InkDropState state() const { return state_; }
+
+  bool is_hovered() const { return is_hovered_; }
+
+  // InkDropDelegate:
+  void OnAction(InkDropState state) override;
+  void SetHovered(bool is_hovered) override;
+
+ private:
+  InkDropState state_;
+
+  bool is_hovered_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestInkDropDelegate);
+};
+
+}  // namespace test
+}  // namespace views
+
+#endif  // UI_VIEWS_ANIMATION_TEST_TEST_INK_DROP_DELEGATE_H_
diff --git a/ui/views/color_chooser/color_chooser_view.cc b/ui/views/color_chooser/color_chooser_view.cc
index 2c63883c..e0aea82 100644
--- a/ui/views/color_chooser/color_chooser_view.cc
+++ b/ui/views/color_chooser/color_chooser_view.cc
@@ -103,11 +103,9 @@
     points[1].iset(rect.width() + 1, 0);
   else
     points[1].iset(0, rect.height() + 1);
-  skia::RefPtr<SkShader> shader(skia::AdoptRef(
-      SkGradientShader::CreateLinear(points, colors, NULL, 2,
-                                     SkShader::kClamp_TileMode)));
   SkPaint paint;
-  paint.setShader(shader.get());
+  paint.setShader(SkGradientShader::MakeLinear(points, colors, NULL, 2,
+                                               SkShader::kClamp_TileMode));
   canvas->DrawRect(rect, paint);
 }
 
diff --git a/ui/views/controls/button/menu_button.cc b/ui/views/controls/button/menu_button.cc
index 1922640..599e06a 100644
--- a/ui/views/controls/button/menu_button.cc
+++ b/ui/views/controls/button/menu_button.cc
@@ -72,8 +72,9 @@
       menu_marker_(ui::ResourceBundle::GetSharedInstance()
                        .GetImageNamed(IDR_MENU_DROPARROW)
                        .ToImageSkia()),
-      destroyed_flag_(NULL),
+      destroyed_flag_(nullptr),
       pressed_lock_count_(0),
+      increment_pressed_lock_called_(nullptr),
       should_disable_after_press_(false),
       weak_factory_(this) {
   SetHorizontalAlignment(gfx::ALIGN_LEFT);
@@ -117,17 +118,20 @@
     // matter where the user pressed. To force RootView to recalculate the
     // mouse target during the mouse press we explicitly set the mouse handler
     // to NULL.
-    static_cast<internal::RootView*>(GetWidget()->GetRootView())->
-        SetMouseHandler(NULL);
+    static_cast<internal::RootView*>(GetWidget()->GetRootView())
+        ->SetMouseHandler(nullptr);
 
     bool destroyed = false;
     destroyed_flag_ = &destroyed;
 
+    DCHECK(increment_pressed_lock_called_ == nullptr);
+    // Observe if IncrementPressedLocked() was called so we can trigger the
+    // correct ink drop animations.
+    bool increment_pressed_lock_called = false;
+    increment_pressed_lock_called_ = &increment_pressed_lock_called;
+
     // We don't set our state here. It's handled in the MenuController code or
     // by our click listener.
-
-    if (ink_drop_delegate())
-      ink_drop_delegate()->OnAction(InkDropState::QUICK_ACTION);
     listener_->OnMenuButtonClicked(this, menu_position, event);
 
     if (destroyed) {
@@ -135,15 +139,24 @@
       return false;
     }
 
-    destroyed_flag_ = NULL;
+    increment_pressed_lock_called_ = nullptr;
+    destroyed_flag_ = nullptr;
 
     menu_closed_time_ = TimeTicks::Now();
 
+    if (ink_drop_delegate() && !increment_pressed_lock_called &&
+        pressed_lock_count_ == 0) {
+      ink_drop_delegate()->OnAction(InkDropState::QUICK_ACTION);
+    }
+
     // We must return false here so that the RootView does not get stuck
     // sending all mouse pressed events to us instead of the appropriate
     // target.
     return false;
   }
+
+  if (ink_drop_delegate())
+    ink_drop_delegate()->OnAction(InkDropState::HIDDEN);
   return true;
 }
 
@@ -200,8 +213,6 @@
       IsTriggerableEventType(event)) {
     if (IsTriggerableEvent(event))
       return Activate(&event);
-    if (ink_drop_delegate())
-      ink_drop_delegate()->OnAction(InkDropState::ACTION_PENDING);
   }
   return true;
 }
@@ -359,7 +370,11 @@
 
 void MenuButton::IncrementPressedLocked() {
   ++pressed_lock_count_;
+  if (increment_pressed_lock_called_)
+    *increment_pressed_lock_called_ = true;
   should_disable_after_press_ = state() == STATE_DISABLED;
+  if (state() != STATE_PRESSED && ink_drop_delegate())
+    ink_drop_delegate()->OnAction(InkDropState::ACTIVATED);
   SetState(STATE_PRESSED);
 }
 
@@ -377,6 +392,8 @@
       desired_state = STATE_HOVERED;
     }
     SetState(desired_state);
+    if (ink_drop_delegate() && state() != STATE_PRESSED)
+      ink_drop_delegate()->OnAction(InkDropState::DEACTIVATED);
   }
 }
 
diff --git a/ui/views/controls/button/menu_button.h b/ui/views/controls/button/menu_button.h
index 1d94139..91504d2e 100644
--- a/ui/views/controls/button/menu_button.h
+++ b/ui/views/controls/button/menu_button.h
@@ -137,6 +137,9 @@
   // The current number of "pressed" locks this button has.
   int pressed_lock_count_;
 
+  // Used to let Activate() know if IncrementPressedLocked() was called.
+  bool* increment_pressed_lock_called_;
+
   // True if the button was in a disabled state when a menu was run, and should
   // return to it once the press is complete. This can happen if, e.g., we
   // programmatically show a menu on a disabled button.
diff --git a/ui/views/controls/button/menu_button_unittest.cc b/ui/views/controls/button/menu_button_unittest.cc
index b240f75..54799ae 100644
--- a/ui/views/controls/button/menu_button_unittest.cc
+++ b/ui/views/controls/button/menu_button_unittest.cc
@@ -10,6 +10,7 @@
 #include "build/build_config.h"
 #include "ui/base/dragdrop/drag_drop_types.h"
 #include "ui/events/test/event_generator.h"
+#include "ui/views/animation/test/test_ink_drop_delegate.h"
 #include "ui/views/controls/button/menu_button_listener.h"
 #include "ui/views/drag_controller.h"
 #include "ui/views/test/views_test_base.h"
@@ -23,6 +24,28 @@
 using base::ASCIIToUTF16;
 
 namespace views {
+class InkDropDelegate;
+
+namespace test {
+
+// A MenuButton subclass that provides access to some MenuButton internals.
+class TestMenuButton : public MenuButton {
+ public:
+  explicit TestMenuButton(MenuButtonListener* menu_button_listener)
+      : MenuButton(base::string16(ASCIIToUTF16("button")),
+                   menu_button_listener,
+                   false) {}
+
+  ~TestMenuButton() override {}
+
+  // Accessors to protected MenuButton methods.
+  void set_ink_drop_delegate(InkDropDelegate* ink_drop_delegate) {
+    MenuButton::set_ink_drop_delegate(ink_drop_delegate);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestMenuButton);
+};
 
 class MenuButtonTest : public ViewsTestBase {
  public:
@@ -38,7 +61,7 @@
   }
 
   Widget* widget() { return widget_; }
-  MenuButton* button() { return button_; }
+  TestMenuButton* button() { return button_; }
   ui::test::EventGenerator* generator() { return generator_.get(); }
 
  protected:
@@ -62,8 +85,7 @@
     // are about to create initializes its hover state in a consistent manner.
     generator_->set_current_location(gfx::Point(10, 10));
 
-    const base::string16 label(ASCIIToUTF16("button"));
-    button_ = new MenuButton(label, menu_button_listener, false);
+    button_ = new TestMenuButton(menu_button_listener);
     button_->SetBoundsRect(gfx::Rect(0, 0, 200, 20));
     widget_->SetContentsView(button_);
 
@@ -81,7 +103,7 @@
   }
 
   Widget* widget_;
-  MenuButton* button_;
+  TestMenuButton* button_;
   scoped_ptr<ui::test::EventGenerator> generator_;
 
   DISALLOW_COPY_AND_ASSIGN(MenuButtonTest);
@@ -140,6 +162,36 @@
   DISALLOW_COPY_AND_ASSIGN(TestMenuButtonListener);
 };
 
+// A MenuButtonListener that will acquire a PressedLock in the
+// OnMenuButtonClicked() method and optionally release it as well.
+class PressStateMenuButtonListener : public MenuButtonListener {
+ public:
+  explicit PressStateMenuButtonListener(bool release_lock)
+      : menu_button_(nullptr), release_lock_(release_lock) {}
+
+  ~PressStateMenuButtonListener() override {}
+
+  void set_menu_button(MenuButton* menu_button) { menu_button_ = menu_button; }
+
+  void OnMenuButtonClicked(MenuButton* source,
+                           const gfx::Point& point,
+                           const ui::Event* event) override {
+    pressed_lock_.reset(new MenuButton::PressedLock(menu_button_));
+    if (release_lock_)
+      pressed_lock_.reset();
+  }
+
+ private:
+  MenuButton* menu_button_;
+
+  scoped_ptr<MenuButton::PressedLock> pressed_lock_;
+
+  // The |pressed_lock_| will be released when true.
+  bool release_lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(PressStateMenuButtonListener);
+};
+
 // Basic implementation of a DragController, to test input behaviour for
 // MenuButtons that can be dragged.
 class TestDragController : public DragController {
@@ -289,7 +341,7 @@
 }
 
 // Test that the MenuButton stays pressed while there are any PressedLocks.
-TEST_F(MenuButtonTest, MenuButtonPressedLock) {
+TEST_F(MenuButtonTest, ButtonStateForMenuButtonsWithPressedLocks) {
   CreateMenuButtonWithNoListener();
 
   // Move the mouse over the button; the button should be in a hovered state.
@@ -377,6 +429,111 @@
   EXPECT_EQ(Button::STATE_HOVERED, menu_button_listener.last_source_state());
 }
 
+TEST_F(MenuButtonTest, InkDropStateForMenuButtonActivationsWithoutListener) {
+  CreateMenuButtonWithNoListener();
+  TestInkDropDelegate ink_drop_delegate;
+  ink_drop_delegate.OnAction(InkDropState::ACTION_PENDING);
+  button()->set_ink_drop_delegate(&ink_drop_delegate);
+  button()->Activate(nullptr);
+
+  EXPECT_EQ(InkDropState::HIDDEN, ink_drop_delegate.state());
+}
+
+TEST_F(MenuButtonTest,
+       InkDropStateForMenuButtonActivationsWithListenerThatDoesntAcquireALock) {
+  TestMenuButtonListener menu_button_listener;
+  CreateMenuButtonWithMenuButtonListener(&menu_button_listener);
+  TestInkDropDelegate ink_drop_delegate;
+  button()->set_ink_drop_delegate(&ink_drop_delegate);
+  button()->Activate(nullptr);
+
+  EXPECT_EQ(InkDropState::QUICK_ACTION, ink_drop_delegate.state());
+}
+
+TEST_F(
+    MenuButtonTest,
+    InkDropStateForMenuButtonActivationsWithListenerThatDontReleaseAllLocks) {
+  PressStateMenuButtonListener menu_button_listener(false);
+  CreateMenuButtonWithMenuButtonListener(&menu_button_listener);
+  menu_button_listener.set_menu_button(button());
+  TestInkDropDelegate ink_drop_delegate;
+  button()->set_ink_drop_delegate(&ink_drop_delegate);
+  button()->Activate(nullptr);
+
+  EXPECT_EQ(InkDropState::ACTIVATED, ink_drop_delegate.state());
+
+  // Prevent the button from accessing invalid memory during clean up.
+  button()->set_ink_drop_delegate(nullptr);
+}
+
+TEST_F(MenuButtonTest,
+       InkDropStateForMenuButtonActivationsWithListenerThatReleaseAllLocks) {
+  PressStateMenuButtonListener menu_button_listener(true);
+  CreateMenuButtonWithMenuButtonListener(&menu_button_listener);
+  menu_button_listener.set_menu_button(button());
+  TestInkDropDelegate ink_drop_delegate;
+  button()->set_ink_drop_delegate(&ink_drop_delegate);
+  button()->Activate(nullptr);
+
+  EXPECT_EQ(InkDropState::DEACTIVATED, ink_drop_delegate.state());
+}
+
+TEST_F(MenuButtonTest, InkDropStateForMenuButtonsWithPressedLocks) {
+  CreateMenuButtonWithNoListener();
+  TestInkDropDelegate ink_drop_delegate;
+  button()->set_ink_drop_delegate(&ink_drop_delegate);
+
+  scoped_ptr<MenuButton::PressedLock> pressed_lock1(
+      new MenuButton::PressedLock(button()));
+
+  EXPECT_EQ(InkDropState::ACTIVATED, ink_drop_delegate.state());
+
+  scoped_ptr<MenuButton::PressedLock> pressed_lock2(
+      new MenuButton::PressedLock(button()));
+
+  EXPECT_EQ(InkDropState::ACTIVATED, ink_drop_delegate.state());
+
+  pressed_lock1.reset();
+  EXPECT_EQ(InkDropState::ACTIVATED, ink_drop_delegate.state());
+
+  pressed_lock2.reset();
+  EXPECT_EQ(InkDropState::DEACTIVATED, ink_drop_delegate.state());
+}
+
+// Verifies only one ink drop animation is triggered when multiple PressedLocks
+// are attached to a MenuButton.
+TEST_F(MenuButtonTest, OneInkDropAnimationForReentrantPressedLocks) {
+  CreateMenuButtonWithNoListener();
+  TestInkDropDelegate ink_drop_delegate;
+  button()->set_ink_drop_delegate(&ink_drop_delegate);
+
+  scoped_ptr<MenuButton::PressedLock> pressed_lock1(
+      new MenuButton::PressedLock(button()));
+
+  EXPECT_EQ(InkDropState::ACTIVATED, ink_drop_delegate.state());
+  ink_drop_delegate.OnAction(InkDropState::ACTION_PENDING);
+
+  scoped_ptr<MenuButton::PressedLock> pressed_lock2(
+      new MenuButton::PressedLock(button()));
+
+  EXPECT_EQ(InkDropState::ACTION_PENDING, ink_drop_delegate.state());
+}
+
+// Verifies the InkDropState is left as ACTIVATED if a PressedLock is active
+// before another Activation occurs.
+TEST_F(MenuButtonTest,
+       InkDropStateForMenuButtonWithPressedLockBeforeActivation) {
+  TestMenuButtonListener menu_button_listener;
+  CreateMenuButtonWithMenuButtonListener(&menu_button_listener);
+  TestInkDropDelegate ink_drop_delegate;
+  button()->set_ink_drop_delegate(&ink_drop_delegate);
+  MenuButton::PressedLock lock(button());
+
+  button()->Activate(nullptr);
+
+  EXPECT_EQ(InkDropState::ACTIVATED, ink_drop_delegate.state());
+}
+
 #if defined(USE_AURA)
 
 // Tests that the MenuButton does not become pressed if it can be dragged, and a
@@ -452,3 +609,4 @@
 #endif  // !defined(OS_MACOSX) || defined(USE_AURA)
 
 }  // namespace views
+}  // namespace test
diff --git a/ui/views/controls/progress_bar.cc b/ui/views/controls/progress_bar.cc
index 0a9fd12a..0278e5b 100644
--- a/ui/views/controls/progress_bar.cc
+++ b/ui/views/controls/progress_bar.cc
@@ -82,9 +82,8 @@
   } else {
     p[1].iset(x, y + h);
   }
-  skia::RefPtr<SkShader> s = skia::AdoptRef(SkGradientShader::CreateLinear(
-      p, colors, points, count, SkShader::kClamp_TileMode));
-  paint.setShader(s.get());
+  paint.setShader(SkGradientShader::MakeLinear(p, colors, points, count,
+                                               SkShader::kClamp_TileMode));
 
   canvas->DrawPath(path, paint);
 }
@@ -296,11 +295,9 @@
             std::max(0, progress_width - kHighlightWidth - kBorderWidth);
         p[0].iset(highlight_left, 0);
         p[1].iset(progress_width, 0);
-        skia::RefPtr<SkShader> s =
-            skia::AdoptRef(SkGradientShader::CreateLinear(
-                p, highlight_colors, highlight_points,
-                arraysize(highlight_colors), SkShader::kClamp_TileMode));
-        paint.setShader(s.get());
+        paint.setShader(SkGradientShader::MakeLinear(
+            p, highlight_colors, highlight_points, arraysize(highlight_colors),
+            SkShader::kClamp_TileMode));
         paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
         canvas->DrawRect(gfx::Rect(highlight_left, 0,
                                    kHighlightWidth + kBorderWidth, bar_height),
diff --git a/ui/views/event_monitor_mac.mm b/ui/views/event_monitor_mac.mm
index 45578c9..f21aae7 100644
--- a/ui/views/event_monitor_mac.mm
+++ b/ui/views/event_monitor_mac.mm
@@ -10,6 +10,7 @@
 #include "ui/events/event.h"
 #include "ui/events/event_handler.h"
 #include "ui/events/event_utils.h"
+#include "ui/gfx/screen.h"
 
 namespace views {
 
@@ -28,11 +29,7 @@
 
 // static
 gfx::Point EventMonitor::GetLastMouseLocation() {
-  NSPoint mouseLocation = [NSEvent mouseLocation];
-  // Flip coordinates to gfx (0,0 in top-left corner) using primary screen.
-  NSScreen* screen = [[NSScreen screens] firstObject];
-  mouseLocation.y = NSMaxY([screen frame]) - mouseLocation.y;
-  return gfx::Point(mouseLocation.x, mouseLocation.y);
+  return gfx::Screen::GetScreen()->GetCursorScreenPoint();
 }
 
 EventMonitorMac::EventMonitorMac(ui::EventHandler* event_handler,
diff --git a/ui/views/painter.cc b/ui/views/painter.cc
index 0cc1f0d..8e0d3e6 100644
--- a/ui/views/painter.cc
+++ b/ui/views/painter.cc
@@ -151,10 +151,9 @@
   else
     p[1].iset(0, size.height());
 
-  skia::RefPtr<SkShader> s = skia::AdoptRef(SkGradientShader::CreateLinear(
+  paint.setShader(SkGradientShader::MakeLinear(
       p, colors_.get(), pos_.get(), count_, SkShader::kClamp_TileMode));
   paint.setStyle(SkPaint::kFill_Style);
-  paint.setShader(s.get());
 
   canvas->sk_canvas()->drawRectCoords(SkIntToScalar(0), SkIntToScalar(0),
                                       SkIntToScalar(size.width()),
diff --git a/ui/views/views.gyp b/ui/views/views.gyp
index 68298e5c..8c12de9 100644
--- a/ui/views/views.gyp
+++ b/ui/views/views.gyp
@@ -494,6 +494,8 @@
       'animation/test/test_ink_drop_animation_observer.h',
       'animation/test/test_ink_drop_host.cc',
       'animation/test/test_ink_drop_host.h',
+      'animation/test/test_ink_drop_delegate.cc',
+      'animation/test/test_ink_drop_delegate.h',
       'controls/textfield/textfield_test_api.cc',
       'controls/textfield/textfield_test_api.h',
       'test/capture_tracking_view.cc',
diff --git a/ui/webui/resources/polymer_resources.grdp b/ui/webui/resources/polymer_resources.grdp
index 4f9fb7d0..897f2539 100644
--- a/ui/webui/resources/polymer_resources.grdp
+++ b/ui/webui/resources/polymer_resources.grdp
@@ -80,9 +80,15 @@
   <structure name="IDR_POLYMER_1_0_IRON_FLEX_LAYOUT_CLASSES_IRON_FLEX_LAYOUT_HTML"
              file="../../../third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-flex-layout.html"
              type="chrome_html" />
+  <structure name="IDR_POLYMER_1_0_IRON_FLEX_LAYOUT_CLASSES_IRON_FLEX_LAYOUT_EXTRACTED_JS"
+             file="../../../third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-flex-layout-extracted.js"
+             type="chrome_html" />
   <structure name="IDR_POLYMER_1_0_IRON_FLEX_LAYOUT_CLASSES_IRON_SHADOW_FLEX_LAYOUT_HTML"
              file="../../../third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-shadow-flex-layout.html"
              type="chrome_html" />
+  <structure name="IDR_POLYMER_1_0_IRON_FLEX_LAYOUT_CLASSES_IRON_SHADOW_FLEX_LAYOUT_EXTRACTED_JS"
+             file="../../../third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-shadow-flex-layout-extracted.js"
+             type="chrome_html" />
   <structure name="IDR_POLYMER_1_0_IRON_FLEX_LAYOUT_IRON_FLEX_LAYOUT_HTML"
              file="../../../third_party/polymer/v1_0/components-chromium/iron-flex-layout/iron-flex-layout.html"
              type="chrome_html" />