diff --git a/DEPS b/DEPS
index 4b357e3..75a906d 100644
--- a/DEPS
+++ b/DEPS
@@ -40,11 +40,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '55325b7c59fe5e8fac809adea7bbec4683d26fab',
+  'skia_revision': '7551898f8eba322acb04c74ae12aae1ed3548105',
   # 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': '465309fe61fa42fc6b171649dd7344292ec6d1ce',
+  'v8_revision': '09e2ca1bb70f4735b300f293a8885d3be8fecfe2',
   # 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.
@@ -64,7 +64,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '05f541279ec01dfdc76ad6b8b142fa5f04cd544c',
+  'pdfium_revision': 'db194cf018069b930d0e3d5fc0242e14f70e8620',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -88,7 +88,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling NaCl
   # and whatever else without interference from each other.
-  'nacl_revision': 'cb27d1fd35d71dce84de1458243f19ef23868f75',
+  'nacl_revision': '25f277533941cf6c733ff70ae3e7713423ba60f2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype-android
   # and whatever else without interference from each other.
@@ -96,7 +96,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '9ddf24882ea3083cf0f9d02df57318baf035f75c',
+  'catapult_revision': '71960b03052fb5fe3e75024533923e785a465a26',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -514,7 +514,7 @@
       Var('chromium_git') + '/external/github.com/GoogleChrome/custom-tabs-client.git' + '@' + 'e2b6730dad438de70d88b6ae5d33aa0995ba77d1',
 
     'src/third_party/gvr-android-sdk/src':
-      Var('chromium_git') + '/external/github.com/googlevr/gvr-android-sdk.git' + '@' + '25e7e14413229d4644a66be77e8f8ddeb3f91fe7',
+      Var('chromium_git') + '/external/github.com/googlevr/gvr-android-sdk.git' + '@' + '8d1395957283ee13ebe2bc672ba24e5ca4ec343f',
   },
 }
 
diff --git a/ash/common/system/chromeos/audio/audio_detailed_view.cc b/ash/common/system/chromeos/audio/audio_detailed_view.cc
index d90b662..b65a8e8ce 100644
--- a/ash/common/system/chromeos/audio/audio_detailed_view.cc
+++ b/ash/common/system/chromeos/audio/audio_detailed_view.cc
@@ -73,33 +73,28 @@
 }
 
 void AudioDetailedView::AddInputHeader() {
-  AddScrollListInfoItem(
-      l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_AUDIO_INPUT),
-      gfx::CreateVectorIcon(kSystemMenuAudioInputIcon,
-                            TrayPopupItemStyle::GetIconColor(
-                                TrayPopupItemStyle::ColorStyle::ACTIVE)));
+  AddScrollListInfoItem(IDS_ASH_STATUS_TRAY_AUDIO_INPUT,
+                        kSystemMenuAudioInputIcon);
 }
 
 void AudioDetailedView::AddOutputHeader() {
-  AddScrollListInfoItem(
-      l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_AUDIO_OUTPUT),
-      gfx::CreateVectorIcon(kSystemMenuAudioOutputIcon,
-                            TrayPopupItemStyle::GetIconColor(
-                                TrayPopupItemStyle::ColorStyle::ACTIVE)));
+  AddScrollListInfoItem(IDS_ASH_STATUS_TRAY_AUDIO_OUTPUT,
+                        kSystemMenuAudioOutputIcon);
 }
 
-void AudioDetailedView::AddScrollListInfoItem(const base::string16& text,
-                                              const gfx::ImageSkia& image) {
+void AudioDetailedView::AddScrollListInfoItem(int text_id,
+                                              const gfx::VectorIcon& icon) {
+  const base::string16 text = l10n_util::GetStringUTF16(text_id);
   if (MaterialDesignController::IsSystemTrayMenuMaterial()) {
+    TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::SUB_HEADER);
     TriView* header = TrayPopupUtils::CreateDefaultRowView();
+    TrayPopupUtils::ConfigureAsStickyHeader(header);
     views::ImageView* image_view = TrayPopupUtils::CreateMainImageView();
-    image_view->SetImage(image);
+    image_view->SetImage(gfx::CreateVectorIcon(icon, style.GetIconColor()));
     header->AddView(TriView::Container::START, image_view);
 
     views::Label* label = TrayPopupUtils::CreateDefaultLabel();
     label->SetText(text);
-    TrayPopupItemStyle style(
-        TrayPopupItemStyle::FontStyle::DETAILED_VIEW_LABEL);
     style.SetupLabel(label);
     header->AddView(TriView::Container::CENTER, label);
 
@@ -187,9 +182,6 @@
   const bool has_output_devices = output_devices_.size() > 0;
   if (!use_md || has_output_devices)
     AddOutputHeader();
-  if (use_md && has_output_devices)
-    scroll_content()->AddChildView(
-        TrayPopupUtils::CreateListItemSeparator(true));
 
   for (size_t i = 0; i < output_devices_.size(); ++i) {
     HoverHighlightView* container = AddScrollListItem(
@@ -202,16 +194,13 @@
     AddScrollSeparator();
   } else if (has_output_devices) {
     scroll_content()->AddChildView(
-        TrayPopupUtils::CreateListItemSeparator(false));
+        TrayPopupUtils::CreateListSubHeaderSeparator());
   }
 
   // Add audio input devices.
   const bool has_input_devices = input_devices_.size() > 0;
   if (!use_md || has_input_devices)
     AddInputHeader();
-  if (use_md && has_input_devices)
-    scroll_content()->AddChildView(
-        TrayPopupUtils::CreateListItemSeparator(true));
 
   for (size_t i = 0; i < input_devices_.size(); ++i) {
     HoverHighlightView* container = AddScrollListItem(
diff --git a/ash/common/system/chromeos/audio/audio_detailed_view.h b/ash/common/system/chromeos/audio/audio_detailed_view.h
index c1c855b..e00a61c8 100644
--- a/ash/common/system/chromeos/audio/audio_detailed_view.h
+++ b/ash/common/system/chromeos/audio/audio_detailed_view.h
@@ -12,6 +12,10 @@
 #include "chromeos/audio/audio_device.h"
 #include "ui/gfx/font.h"
 
+namespace gfx {
+struct VectorIcon;
+}
+
 namespace views {
 class View;
 }
@@ -34,8 +38,7 @@
   // list.
   void AddInputHeader();
   void AddOutputHeader();
-  void AddScrollListInfoItem(const base::string16& text,
-                             const gfx::ImageSkia& image);
+  void AddScrollListInfoItem(int text_id, const gfx::VectorIcon& icon);
 
   HoverHighlightView* AddScrollListItem(const base::string16& text,
                                         bool highlight,
diff --git a/base/numerics/safe_conversions_impl.h b/base/numerics/safe_conversions_impl.h
index df7130d..6fd063b1 100644
--- a/base/numerics/safe_conversions_impl.h
+++ b/base/numerics/safe_conversions_impl.h
@@ -67,42 +67,13 @@
       (static_cast<UnsignedT>(x) ^ -SignedT(is_negative)) + is_negative);
 }
 
-// Wrapper for the sign mask used in the absolute value function.
+// This performs a safe, absolute value via unsigned overflow.
 template <typename T>
-constexpr T SignMask(T x) {
-  using SignedT = typename std::make_signed<T>::type;
-  // Right shift on a signed number is implementation defined, but it's often
-  // implemented as arithmetic shift. If the compiler uses an arithmetic shift,
-  // then use that to avoid the extra negation.
-  return static_cast<T>(
-      (static_cast<SignedT>(-1) >> PositionOfSignBit<T>::value) ==
-              static_cast<SignedT>(-1)
-          ? (static_cast<SignedT>(x) >> PositionOfSignBit<T>::value)
-          : -static_cast<SignedT>(static_cast<SignedT>(x) < 0));
-}
-static_assert(SignMask(-2) == -1,
-              "Inconsistent handling of signed right shift.");
-static_assert(SignMask(-3L) == -1L,
-              "Inconsistent handling of signed right shift.");
-static_assert(SignMask(-4LL) == -1LL,
-              "Inconsistent handling of signed right shift.");
-
-// This performs a safe, non-branching absolute value via unsigned overflow.
-template <typename T,
-          typename std::enable_if<std::is_integral<T>::value &&
-                                  std::is_signed<T>::value>::type* = nullptr>
 constexpr typename std::make_unsigned<T>::type SafeUnsignedAbs(T value) {
+  static_assert(std::is_integral<T>::value, "Type must be integral");
   using UnsignedT = typename std::make_unsigned<T>::type;
-  return static_cast<T>(static_cast<UnsignedT>(value ^ SignMask(value)) -
-                        static_cast<UnsignedT>(SignMask(value)));
-}
-
-template <typename T,
-          typename std::enable_if<std::is_integral<T>::value &&
-                                  !std::is_signed<T>::value>::type* = nullptr>
-constexpr T SafeUnsignedAbs(T value) {
-  // T is unsigned, so |value| must already be positive.
-  return static_cast<T>(value);
+  return IsValueNegative(value) ? 0 - static_cast<UnsignedT>(value)
+                                : static_cast<UnsignedT>(value);
 }
 
 enum IntegerRepresentation {
@@ -511,18 +482,46 @@
 // can skip the checked operations if they're not needed. So, for an integer we
 // care if the destination type preserves the sign and is twice the width of
 // the source.
-template <typename T, typename Lhs, typename Rhs>
+template <typename T, typename Lhs, typename Rhs = Lhs>
 struct IsIntegerArithmeticSafe {
   static const bool value =
       !std::is_floating_point<T>::value &&
-      StaticDstRangeRelationToSrcRange<T, Lhs>::value ==
-          NUMERIC_RANGE_CONTAINED &&
+      !std::is_floating_point<Lhs>::value &&
+      !std::is_floating_point<Rhs>::value &&
+      std::is_signed<T>::value >= std::is_signed<Lhs>::value &&
       IntegerBitsPlusSign<T>::value >= (2 * IntegerBitsPlusSign<Lhs>::value) &&
-      StaticDstRangeRelationToSrcRange<T, Rhs>::value !=
-          NUMERIC_RANGE_CONTAINED &&
+      std::is_signed<T>::value >= std::is_signed<Rhs>::value &&
       IntegerBitsPlusSign<T>::value >= (2 * IntegerBitsPlusSign<Rhs>::value);
 };
 
+// Promotes to a type that can represent any possible result of a binary
+// arithmetic operation with the source types.
+template <typename Lhs,
+          typename Rhs,
+          bool is_promotion_possible = IsIntegerArithmeticSafe<
+              typename std::conditional<std::is_signed<Lhs>::value ||
+                                            std::is_signed<Rhs>::value,
+                                        intmax_t,
+                                        uintmax_t>::type,
+              typename MaxExponentPromotion<Lhs, Rhs>::type>::value>
+struct FastIntegerArithmeticPromotion;
+
+template <typename Lhs, typename Rhs>
+struct FastIntegerArithmeticPromotion<Lhs, Rhs, true> {
+  using type =
+      typename TwiceWiderInteger<typename MaxExponentPromotion<Lhs, Rhs>::type,
+                                 std::is_signed<Lhs>::value ||
+                                     std::is_signed<Rhs>::value>::type;
+  static_assert(IsIntegerArithmeticSafe<type, Lhs, Rhs>::value, "");
+  static const bool is_contained = true;
+};
+
+template <typename Lhs, typename Rhs>
+struct FastIntegerArithmeticPromotion<Lhs, Rhs, false> {
+  using type = typename BigEnoughPromotion<Lhs, Rhs>::type;
+  static const bool is_contained = false;
+};
+
 // This hacks around libstdc++ 4.6 missing stuff in type_traits.
 #if defined(__GLIBCXX__)
 #define PRIV_GLIBCXX_4_7_0 20120322
diff --git a/base/numerics/safe_math_impl.h b/base/numerics/safe_math_impl.h
index 9a47a27a..9956115 100644
--- a/base/numerics/safe_math_impl.h
+++ b/base/numerics/safe_math_impl.h
@@ -51,9 +51,9 @@
 #define USE_OVERFLOW_BUILTINS (0)
 #endif
 
-template <typename T,
-          typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+template <typename T>
 bool CheckedAddImpl(T x, T y, T* result) {
+  static_assert(std::is_integral<T>::value, "Type must be integral");
   // Since the value of x+y is undefined if we have a signed type, we compute
   // it using the unsigned type of the same size.
   using UnsignedDst = typename std::make_unsigned<T>::type;
@@ -102,9 +102,9 @@
   }
 };
 
-template <typename T,
-          typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+template <typename T>
 bool CheckedSubImpl(T x, T y, T* result) {
+  static_assert(std::is_integral<T>::value, "Type must be integral");
   // Since the value of x+y is undefined if we have a signed type, we compute
   // it using the unsigned type of the same size.
   using UnsignedDst = typename std::make_unsigned<T>::type;
@@ -153,54 +153,24 @@
   }
 };
 
-// Integer multiplication is a bit complicated. In the fast case we just
-// we just promote to a twice wider type, and range check the result. In the
-// slow case we need to manually check that the result won't be truncated by
-// checking with division against the appropriate bound.
-template <typename T,
-          typename std::enable_if<
-              std::is_integral<T>::value &&
-              ((IntegerBitsPlusSign<T>::value * 2) <=
-               IntegerBitsPlusSign<intmax_t>::value)>::type* = nullptr>
+template <typename T>
 bool CheckedMulImpl(T x, T y, T* result) {
-  using IntermediateType = typename TwiceWiderInteger<T>::type;
-  IntermediateType tmp =
-      static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y);
-  *result = static_cast<T>(tmp);
-  return DstRangeRelationToSrcRange<T>(tmp) == RANGE_VALID;
-}
-
-template <typename T,
-          typename std::enable_if<
-              std::is_integral<T>::value && std::is_signed<T>::value &&
-              ((IntegerBitsPlusSign<T>::value * 2) >
-               IntegerBitsPlusSign<intmax_t>::value)>::type* = nullptr>
-bool CheckedMulImpl(T x, T y, T* result) {
+  static_assert(std::is_integral<T>::value, "Type must be integral");
   // Since the value of x*y is potentially undefined if we have a signed type,
   // we compute it using the unsigned type of the same size.
   using UnsignedDst = typename std::make_unsigned<T>::type;
+  using SignedDst = typename std::make_signed<T>::type;
   const UnsignedDst ux = SafeUnsignedAbs(x);
   const UnsignedDst uy = SafeUnsignedAbs(y);
   UnsignedDst uresult = static_cast<UnsignedDst>(ux * uy);
-  // This is a non-branching conditional negation.
-  const T is_negative = (x ^ y) < 0;
-  *result = static_cast<T>((uresult ^ -is_negative) + is_negative);
-  // This uses the unsigned overflow check on the absolute value, with a +1
-  // bound for a negative result.
-  return (uy == 0 ||
-          ux <= (static_cast<UnsignedDst>(std::numeric_limits<T>::max()) +
-                 is_negative) /
-                    uy);
-}
-
-template <typename T,
-          typename std::enable_if<
-              std::is_integral<T>::value && !std::is_signed<T>::value &&
-              ((IntegerBitsPlusSign<T>::value * 2) >
-               IntegerBitsPlusSign<uintmax_t>::value)>::type* = nullptr>
-bool CheckedMulImpl(T x, T y, T* result) {
-  *result = x * y;
-  return (y == 0 || x <= std::numeric_limits<T>::max() / y);
+  const bool is_negative =
+      std::is_signed<T>::value && static_cast<SignedDst>(x ^ y) < 0;
+  *result = is_negative ? 0 - uresult : uresult;
+  // We have a fast out for unsigned identity or zero on the second operand.
+  // After that it's an unsigned overflow check on the absolute value, with
+  // a +1 bound for a negative result.
+  return uy <= UnsignedDst(!std::is_signed<T>::value || is_negative) ||
+         ux <= (std::numeric_limits<T>::max() + UnsignedDst(is_negative)) / uy;
 }
 
 template <typename T, typename U, class Enable = void>
@@ -233,7 +203,7 @@
     if (kUseMaxInt)
       return !__builtin_mul_overflow(x, y, result);
 #endif
-    using Promotion = typename BigEnoughPromotion<T, U>::type;
+    using Promotion = typename FastIntegerArithmeticPromotion<T, U>::type;
     Promotion presult;
     // Fail if either operand is out of range for the promoted type.
     // TODO(jschuh): This could be made to work for a broader range of values.
@@ -256,9 +226,9 @@
 
 // Division just requires a check for a zero denominator or an invalid negation
 // on signed min/-1.
-template <typename T,
-          typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+template <typename T>
 bool CheckedDivImpl(T x, T y, T* result) {
+  static_assert(std::is_integral<T>::value, "Type must be integral");
   if (y && (!std::is_signed<T>::value ||
             x != std::numeric_limits<T>::lowest() || y != static_cast<T>(-1))) {
     *result = x / y;
@@ -291,9 +261,9 @@
   }
 };
 
-template <typename T,
-          typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+template <typename T>
 bool CheckedModImpl(T x, T y, T* result) {
+  static_assert(std::is_integral<T>::value, "Type must be integral");
   if (y > 0) {
     *result = static_cast<T>(x % y);
     return true;
diff --git a/base/numerics/safe_numerics_unittest.cc b/base/numerics/safe_numerics_unittest.cc
index 5304593..58fac24 100644
--- a/base/numerics/safe_numerics_unittest.cc
+++ b/base/numerics/safe_numerics_unittest.cc
@@ -79,6 +79,57 @@
 
 namespace base {
 namespace internal {
+
+// Test corner case promotions used
+static_assert(IsIntegerArithmeticSafe<int32_t, int8_t, int8_t>::value, "");
+static_assert(IsIntegerArithmeticSafe<int32_t, int16_t, int8_t>::value, "");
+static_assert(IsIntegerArithmeticSafe<int32_t, int8_t, int16_t>::value, "");
+static_assert(!IsIntegerArithmeticSafe<int32_t, int32_t, int8_t>::value, "");
+static_assert(BigEnoughPromotion<int16_t, int8_t>::is_contained, "");
+static_assert(BigEnoughPromotion<int32_t, uint32_t>::is_contained, "");
+static_assert(BigEnoughPromotion<intmax_t, int8_t>::is_contained, "");
+static_assert(!BigEnoughPromotion<uintmax_t, int8_t>::is_contained, "");
+static_assert(
+    std::is_same<BigEnoughPromotion<int16_t, int8_t>::type, int16_t>::value,
+    "");
+static_assert(
+    std::is_same<BigEnoughPromotion<int32_t, uint32_t>::type, int64_t>::value,
+    "");
+static_assert(
+    std::is_same<BigEnoughPromotion<intmax_t, int8_t>::type, intmax_t>::value,
+    "");
+static_assert(
+    std::is_same<BigEnoughPromotion<uintmax_t, int8_t>::type, uintmax_t>::value,
+    "");
+static_assert(BigEnoughPromotion<int16_t, int8_t>::is_contained, "");
+static_assert(BigEnoughPromotion<int32_t, uint32_t>::is_contained, "");
+static_assert(BigEnoughPromotion<intmax_t, int8_t>::is_contained, "");
+static_assert(!BigEnoughPromotion<uintmax_t, int8_t>::is_contained, "");
+static_assert(
+    std::is_same<FastIntegerArithmeticPromotion<int16_t, int8_t>::type,
+                 int32_t>::value,
+    "");
+static_assert(
+    std::is_same<FastIntegerArithmeticPromotion<int32_t, uint32_t>::type,
+                 int64_t>::value,
+    "");
+static_assert(
+    std::is_same<FastIntegerArithmeticPromotion<intmax_t, int8_t>::type,
+                 intmax_t>::value,
+    "");
+static_assert(
+    std::is_same<FastIntegerArithmeticPromotion<uintmax_t, int8_t>::type,
+                 uintmax_t>::value,
+    "");
+static_assert(FastIntegerArithmeticPromotion<int16_t, int8_t>::is_contained,
+              "");
+static_assert(FastIntegerArithmeticPromotion<int32_t, uint32_t>::is_contained,
+              "");
+static_assert(!FastIntegerArithmeticPromotion<intmax_t, int8_t>::is_contained,
+              "");
+static_assert(!FastIntegerArithmeticPromotion<uintmax_t, int8_t>::is_contained,
+              "");
+
 template <typename U>
 U GetNumericValueForTest(const CheckedNumeric<U>& src) {
   return src.state_.value();
@@ -166,6 +217,14 @@
   TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) / -1);
   TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(-1) / 2);
   TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) * -1);
+  TEST_EXPECTED_VALUE(DstLimits::max(),
+                      CheckedNumeric<Dst>(DstLimits::lowest() + 1) * Dst(-1));
+  TEST_EXPECTED_VALUE(DstLimits::max(),
+                      CheckedNumeric<Dst>(-1) * Dst(DstLimits::lowest() + 1));
+  TEST_EXPECTED_VALUE(DstLimits::lowest(),
+                      CheckedNumeric<Dst>(DstLimits::lowest()) * Dst(1));
+  TEST_EXPECTED_VALUE(DstLimits::lowest(),
+                      CheckedNumeric<Dst>(1) * Dst(DstLimits::lowest()));
   TEST_EXPECTED_VALUE(DstLimits::lowest(),
                       MakeCheckedNum(DstLimits::lowest()).UnsignedAbs());
   TEST_EXPECTED_VALUE(DstLimits::max(),
diff --git a/build/android/resource_sizes.py b/build/android/resource_sizes.py
index 6df35fd..242ed83 100755
--- a/build/android/resource_sizes.py
+++ b/build/android/resource_sizes.py
@@ -180,6 +180,9 @@
     self._zip_infos.append(zip_info)
     self._extracted.append(extracted)
 
+  def AllEntries(self):
+    return iter(self._zip_infos)
+
   def GetNumEntries(self):
     return len(self._zip_infos)
 
@@ -227,6 +230,7 @@
   arsc = make_group('Compiled Android resources')
   metadata = make_group('Package metadata')
   unknown = make_group('Unknown files')
+  notices = make_group('licenses.notice file')
 
   apk = zipfile.ZipFile(apk_filename, 'r')
   try:
@@ -262,6 +266,8 @@
       arsc.AddZipInfo(member)
     elif filename.startswith('META-INF') or filename == 'AndroidManifest.xml':
       metadata.AddZipInfo(member)
+    elif filename.endswith('.notice'):
+      notices.AddZipInfo(member)
     else:
       unknown.AddZipInfo(member)
 
@@ -318,6 +324,8 @@
   # updated.
   english_pak = translations.FindByPattern(r'.*/en[-_][Uu][Ss]\.l?pak')
   if english_pak:
+    # TODO(agrieve): This should also analyze .arsc file to remove non-en
+    # configs. http://crbug.com/677966
     normalized_apk_size -= translations.ComputeZippedSize()
     # 1.17 found by looking at Chrome.apk and seeing how much smaller en-US.pak
     # is relative to the average locale .pak.
@@ -330,6 +338,9 @@
   ReportPerfResult(chartjson, apk_basename + '_Specifics',
                    'file count', len(apk_contents), 'zip entries')
 
+  for info in unknown.AllEntries():
+    print 'Unknown entry:', info.filename, info.compress_size
+
 
 def IsPakFileName(file_name):
   """Returns whether the given file name ends with .pak or .lpak."""
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index d084e5b..8d28f5d 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -478,9 +478,6 @@
   was_screen_space_transform_animating_ =
       draw_properties().screen_space_transform_is_animating;
 
-  if (screen_space_transform_is_animating())
-    raster_source_->SetShouldAttemptToUseDistanceFieldText();
-
   double current_frame_time_in_seconds =
       (layer_tree_impl()->CurrentBeginFrameArgs().frame_time -
        base::TimeTicks()).InSecondsF();
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index e13cdd9..be322f6 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -2586,7 +2586,6 @@
                                maximum_animation_scale,
                                starting_animation_scale, animating_transform);
   EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 3.f);
-  EXPECT_BOTH_TRUE(GetRasterSource()->ShouldAttemptToUseDistanceFieldText());
 
   // Further changes to scale during the animation should not cause a new
   // high-res tiling to get created.
diff --git a/cc/playback/raster_source.cc b/cc/playback/raster_source.cc
index 1514383..ab9969a 100644
--- a/cc/playback/raster_source.cc
+++ b/cc/playback/raster_source.cc
@@ -40,7 +40,6 @@
       clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_),
       slow_down_raster_scale_factor_for_debug_(
           other->slow_down_raster_scale_factor_for_debug_),
-      should_attempt_to_use_distance_field_text_(false),
       image_decode_cache_(nullptr) {}
 
 RasterSource::RasterSource(const RasterSource* other, bool can_use_lcd_text)
@@ -56,8 +55,6 @@
       clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_),
       slow_down_raster_scale_factor_for_debug_(
           other->slow_down_raster_scale_factor_for_debug_),
-      should_attempt_to_use_distance_field_text_(
-          other->should_attempt_to_use_distance_field_text_),
       image_decode_cache_(other->image_decode_cache_) {}
 
 RasterSource::~RasterSource() {
@@ -277,14 +274,6 @@
   return recorded_viewport_;
 }
 
-void RasterSource::SetShouldAttemptToUseDistanceFieldText() {
-  should_attempt_to_use_distance_field_text_ = true;
-}
-
-bool RasterSource::ShouldAttemptToUseDistanceFieldText() const {
-  return should_attempt_to_use_distance_field_text_;
-}
-
 void RasterSource::AsValueInto(base::trace_event::TracedValue* array) const {
   if (display_list_.get())
     TracedValue::AppendIDRef(display_list_.get(), array);
diff --git a/cc/playback/raster_source.h b/cc/playback/raster_source.h
index c158094..ad7e5acd 100644
--- a/cc/playback/raster_source.h
+++ b/cc/playback/raster_source.h
@@ -107,14 +107,6 @@
   // Valid rectangle in which everything is recorded and can be rastered from.
   virtual gfx::Rect RecordedViewport() const;
 
-  // Informs the raster source that it should attempt to use distance field text
-  // during rasterization.
-  virtual void SetShouldAttemptToUseDistanceFieldText();
-
-  // Return true iff this raster source would benefit from using distance
-  // field text.
-  virtual bool ShouldAttemptToUseDistanceFieldText() const;
-
   // Tracing functionality.
   virtual void DidBeginTracing();
   virtual void AsValueInto(base::trace_event::TracedValue* array) const;
@@ -153,9 +145,6 @@
   const gfx::Size size_;
   const bool clear_canvas_with_debug_color_;
   const int slow_down_raster_scale_factor_for_debug_;
-  // TODO(enne/vmiura): this has a read/write race between raster and compositor
-  // threads with multi-threaded Ganesh.  Make this const or remove it.
-  bool should_attempt_to_use_distance_field_text_;
 
   // In practice, this is only set once before raster begins, so it's ok with
   // respect to threading.
diff --git a/cc/raster/gpu_raster_buffer_provider.cc b/cc/raster/gpu_raster_buffer_provider.cc
index 9bc475d..e7e4f92 100644
--- a/cc/raster/gpu_raster_buffer_provider.cc
+++ b/cc/raster/gpu_raster_buffer_provider.cc
@@ -213,16 +213,11 @@
     gl->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
   }
 
-  // Turn on distance fields for layers that have ever animated.
-  bool use_distance_field_text =
-      use_distance_field_text_ ||
-      raster_source->ShouldAttemptToUseDistanceFieldText();
-
   RasterizeSource(raster_source, resource_has_previous_content,
                   resource_lock->size(), raster_full_rect, raster_dirty_rect,
                   scales, playback_settings, worker_context_provider_,
                   resource_lock, async_worker_context_enabled_,
-                  use_distance_field_text, msaa_sample_count_);
+                  use_distance_field_text_, msaa_sample_count_);
 
   const uint64_t fence_sync = gl->InsertFenceSyncCHROMIUM();
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadRetry.java b/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadRetry.java
index 8e1befc2..57887cbf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadRetry.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadRetry.java
@@ -9,6 +9,7 @@
 
 import org.chromium.base.NonThreadSafe;
 import org.chromium.base.annotations.SuppressFBWarnings;
+import org.chromium.components.minidump_uploader.util.CrashReportingPermissionManager;
 import org.chromium.net.ConnectionType;
 import org.chromium.net.NetworkChangeNotifier;
 
@@ -18,14 +19,17 @@
  */
 class MinidumpUploadRetry implements NetworkChangeNotifier.ConnectionTypeObserver {
     private final Context mContext;
+    private final CrashReportingPermissionManager mPermissionManager;
     private static MinidumpUploadRetry sSingleton;
 
     private static class Scheduler implements Runnable {
         private static NonThreadSafe sThreadCheck;
         private final Context mContext;
+        private final CrashReportingPermissionManager mPermissionManager;
 
-        private Scheduler(Context context) {
+        private Scheduler(Context context, CrashReportingPermissionManager permissionManager) {
             this.mContext = context;
+            mPermissionManager = permissionManager;
         }
 
         @Override
@@ -39,7 +43,7 @@
                 return;
             }
             if (sSingleton == null) {
-                sSingleton = new MinidumpUploadRetry(mContext);
+                sSingleton = new MinidumpUploadRetry(mContext, mPermissionManager);
             }
         }
     }
@@ -47,26 +51,29 @@
     /**
      * Schedule a retry. If there is already one schedule, this is NO-OP.
      */
-    static void scheduleRetry(Context context) {
+    static void scheduleRetry(Context context, CrashReportingPermissionManager permissionManager) {
         // NetworkChangeNotifier is not thread safe. We will post to UI thread
         // instead since that's where it fires off notification changes.
-        new Handler(context.getMainLooper()).post(new Scheduler(context));
+        new Handler(context.getMainLooper()).post(new Scheduler(context, permissionManager));
     }
 
-    private MinidumpUploadRetry(Context context) {
+    private MinidumpUploadRetry(
+            Context context, CrashReportingPermissionManager permissionManager) {
         this.mContext = context;
+        this.mPermissionManager = permissionManager;
         NetworkChangeNotifier.addConnectionTypeObserver(this);
     }
 
     @SuppressFBWarnings("ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD")
     @Override
     public void onConnectionTypeChanged(int connectionType) {
-        // Look for "favorable" connections. Note that we never
-        // know what the user's crash upload preference is until
-        // the time when we are actually uploading.
+        // Early-out if not connected at all - to avoid checking the current network state.
         if (connectionType == ConnectionType.CONNECTION_NONE) {
             return;
         }
+        if (!mPermissionManager.isNetworkAvailableForCrashUploads()) {
+            return;
+        }
         MinidumpUploadService.tryUploadAllCrashDumps(mContext);
         NetworkChangeNotifier.removeConnectionTypeObserver(this);
         sSingleton = null;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java b/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java
index 613a3a45..628b54f3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java
@@ -18,6 +18,7 @@
 import org.chromium.chrome.browser.preferences.privacy.PrivacyPreferencesManager;
 import org.chromium.components.minidump_uploader.CrashFileManager;
 import org.chromium.components.minidump_uploader.MinidumpUploadCallable;
+import org.chromium.components.minidump_uploader.util.CrashReportingPermissionManager;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -258,7 +259,8 @@
             if (newName != null) {
                 if (++tries < MAX_TRIES_ALLOWED) {
                     // TODO(nyquist): Do this as an exponential backoff.
-                    MinidumpUploadRetry.scheduleRetry(getApplicationContext());
+                    MinidumpUploadRetry.scheduleRetry(
+                            getApplicationContext(), getCrashReportingPermissionManager());
                 } else {
                     // Only record failure to UMA after we have maxed out the allotted tries.
                     incrementCrashFailureUploadCount(newName);
@@ -271,6 +273,13 @@
         }
     }
 
+    /**
+     * Get the permission manager, can be overridden for testing.
+     */
+    CrashReportingPermissionManager getCrashReportingPermissionManager() {
+        return PrivacyPreferencesManager.getInstance();
+    }
+
     private static String getNewNameAfterSuccessfulUpload(String fileName) {
         return fileName.replace("dmp", "up");
     }
@@ -342,7 +351,7 @@
     @VisibleForTesting
     MinidumpUploadCallable createMinidumpUploadCallable(File minidumpFile, File logfile) {
         return new MinidumpUploadCallable(
-                minidumpFile, logfile, PrivacyPreferencesManager.getInstance());
+                minidumpFile, logfile, getCrashReportingPermissionManager());
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
index 4fee2a0..221c47a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
@@ -338,54 +338,18 @@
         // check whether the intent can be resolved. If not, we will see
         // whether we can download it from the Market.
         if (!canResolveActivity) {
-            Pair<String, String> appInfo = null;
             if (hasBrowserFallbackUrl) {
-                // If the fallback URL is a link to Play Store, send the user to Play Store app
-                // instead: crbug.com/638672.
-                appInfo = maybeGetPlayStoreAppIdAndReferrer(browserFallbackUrl);
-                if (appInfo == null) {
-                    return clobberCurrentTabWithFallbackUrl(browserFallbackUrl, params);
-                }
+                return clobberCurrentTabWithFallbackUrl(browserFallbackUrl, params);
             }
 
-            String packagename = appInfo != null ? appInfo.first : intent.getPackage();
-            if (packagename != null) {
-                String marketReferrer = appInfo != null ? appInfo.second :
-                        IntentUtils.safeGetStringExtra(intent, EXTRA_MARKET_REFERRER);
+            if (intent.getPackage() != null) {
+                String marketReferrer = IntentUtils.safeGetStringExtra(
+                        intent, EXTRA_MARKET_REFERRER);
                 if (TextUtils.isEmpty(marketReferrer)) {
                     marketReferrer = mDelegate.getPackageName();
                 }
-                try {
-                    Uri marketUri = new Uri.Builder()
-                            .scheme("market")
-                            .authority("details")
-                            .appendQueryParameter(PLAY_PACKAGE_PARAM, packagename)
-                            .appendQueryParameter(PLAY_REFERRER_PARAM, Uri.decode(marketReferrer))
-                            .build();
-                    intent = new Intent(Intent.ACTION_VIEW, marketUri);
-                    intent.addCategory(Intent.CATEGORY_BROWSABLE);
-                    intent.setPackage("com.android.vending");
-                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                    if (params.getReferrerUrl() != null) {
-                        intent.putExtra(Intent.EXTRA_REFERRER, Uri.parse(params.getReferrerUrl()));
-                    }
-                    if (params.isIncognito()) {
-                        mDelegate.startIncognitoIntent(intent, params.getReferrerUrl(),
-                                hasBrowserFallbackUrl ? browserFallbackUrl : null, params.getTab(),
-                                params.shouldCloseContentsOnOverrideUrlLoadingAndLaunchIntent(),
-                                false);
-                        return OverrideUrlLoadingResult.OVERRIDE_WITH_ASYNC_ACTION;
-                    } else {
-                        mDelegate.startActivity(intent, false);
-                        return OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT;
-                    }
-                } catch (ActivityNotFoundException ex) {
-                    // ignore the error on devices that does not have
-                    // play market installed.
-                    return OverrideUrlLoadingResult.NO_OVERRIDE;
-                }
+                return sendIntentToMarket(intent.getPackage(), marketReferrer, params);
             }
-
             return OverrideUrlLoadingResult.NO_OVERRIDE;
         }
 
@@ -559,6 +523,42 @@
     }
 
     /**
+     * @return OVERRIDE_WITH_EXTERNAL_INTENT when we successfully started market activity,
+     *         NO_OVERRIDE otherwise.
+     */
+    private OverrideUrlLoadingResult sendIntentToMarket(String packageName, String marketReferrer,
+            ExternalNavigationParams params) {
+        try {
+            Uri marketUri = new Uri.Builder()
+                    .scheme("market")
+                    .authority("details")
+                    .appendQueryParameter(PLAY_PACKAGE_PARAM, packageName)
+                    .appendQueryParameter(PLAY_REFERRER_PARAM, Uri.decode(marketReferrer))
+                    .build();
+            Intent intent = new Intent(Intent.ACTION_VIEW, marketUri);
+            intent.addCategory(Intent.CATEGORY_BROWSABLE);
+            intent.setPackage("com.android.vending");
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            if (params.getReferrerUrl() != null) {
+                intent.putExtra(Intent.EXTRA_REFERRER, Uri.parse(params.getReferrerUrl()));
+            }
+            if (params.isIncognito()) {
+                mDelegate.startIncognitoIntent(intent, params.getReferrerUrl(), null,
+                        params.getTab(),
+                        params.shouldCloseContentsOnOverrideUrlLoadingAndLaunchIntent(), false);
+                return OverrideUrlLoadingResult.OVERRIDE_WITH_ASYNC_ACTION;
+            } else {
+                mDelegate.startActivity(intent, false);
+                return OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT;
+            }
+        } catch (ActivityNotFoundException ex) {
+            // ignore the error on devices that does not have
+            // play market installed.
+            return OverrideUrlLoadingResult.NO_OVERRIDE;
+        }
+    }
+
+    /**
      * Checks whether {@param intent} is for an Instant App. Considers both package and actions that
      * would resolve to Supervisor.
      * @return Whether the given intent is going to open an Instant App.
@@ -585,6 +585,15 @@
      */
     private OverrideUrlLoadingResult clobberCurrentTabWithFallbackUrl(
             String browserFallbackUrl, ExternalNavigationParams params) {
+        // If the fallback URL is a link to Play Store, send the user to Play Store app
+        // instead: crbug.com/638672.
+        Pair<String, String> appInfo = maybeGetPlayStoreAppIdAndReferrer(browserFallbackUrl);
+        if (appInfo != null) {
+            String marketReferrer = TextUtils.isEmpty(appInfo.second) ? mDelegate.getPackageName()
+                    : appInfo.second;
+            return sendIntentToMarket(appInfo.first, marketReferrer, params);
+        }
+
         // For subframes, we don't support fallback url for now.
         // http://crbug.com/364522.
         if (!params.isMainFrame()) return OverrideUrlLoadingResult.NO_OVERRIDE;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/evaluation/OfflinePageEvaluationBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/evaluation/OfflinePageEvaluationBridge.java
index dfd5d201..c15c5d4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/evaluation/OfflinePageEvaluationBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/evaluation/OfflinePageEvaluationBridge.java
@@ -207,6 +207,7 @@
         String logString = formatter.format(date) + ": " + sourceTag + " | " + message
                 + System.getProperty("line.separator");
         LogTask logTask = new LogTask();
+        Log.d(TAG, logString);
         logTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, logString);
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/crash/MinidumpUploadServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/crash/MinidumpUploadServiceTest.java
index 87103c9..05f52e9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/crash/MinidumpUploadServiceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/crash/MinidumpUploadServiceTest.java
@@ -22,6 +22,7 @@
 import org.chromium.components.minidump_uploader.CrashFileManager;
 import org.chromium.components.minidump_uploader.CrashTestCase;
 import org.chromium.components.minidump_uploader.MinidumpUploadCallable;
+import org.chromium.components.minidump_uploader.util.CrashReportingPermissionManager;
 import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
 import org.chromium.net.NetworkChangeNotifier;
@@ -79,6 +80,8 @@
     }
 
     private static class TestMinidumpUploadService extends MinidumpUploadService {
+        private final NetworkChangingPermissionManager mPermissionManager =
+                new NetworkChangingPermissionManager();
         private TestMinidumpUploadService() {}
         private TestMinidumpUploadService(Context context) {
             attachBaseContext(context);
@@ -87,6 +90,25 @@
         private void attachBaseContextLate(Context base) {
             super.attachBaseContext(base);
         }
+
+        private static class NetworkChangingPermissionManager
+                extends MockCrashReportingPermissionManager {
+            public boolean isNetworkAvailableForCrashUploads() {
+                return mIsNetworkAvailable;
+            }
+
+            public void setIsNetworkAvailableForCrashUploads(boolean networkAvailable) {
+                mIsNetworkAvailable = networkAvailable;
+            }
+        }
+
+        CrashReportingPermissionManager getCrashReportingPermissionManager() {
+            return mPermissionManager;
+        }
+
+        public void setIsNetworkAvailableForCrashUploads(boolean networkAvailable) {
+            mPermissionManager.setIsNetworkAvailableForCrashUploads(networkAvailable);
+        }
     }
 
     @SmallTest
@@ -270,7 +292,9 @@
                                 NetworkChangeNotifier.setAutoDetectConnectivityState(false);
                                 // Quickly force the state to be connected and back to disconnected.
                                 // An event should be triggered for retry logics.
+                                setIsNetworkAvailableForCrashUploads(false);
                                 NetworkChangeNotifier.forceConnectivityState(false);
+                                setIsNetworkAvailableForCrashUploads(true);
                                 NetworkChangeNotifier.forceConnectivityState(true);
                             }
                         });
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
index 62926c3..2cd72e96 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
@@ -713,6 +713,34 @@
     }
 
     @SmallTest
+    public void testFallbackUrl_RedirectToIntentToMarket() {
+        TestContext context = new TestContext();
+        TabRedirectHandler redirectHandler = new TabRedirectHandler(context);
+
+        redirectHandler.updateNewUrlLoading(PageTransition.TYPED, false, false, 0, 0);
+        checkUrl("http://goo.gl/abcdefg")
+                .withPageTransition(PageTransition.TYPED)
+                .withRedirectHandler(redirectHandler)
+                .expecting(OverrideUrlLoadingResult.NO_OVERRIDE, IGNORE);
+
+        redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, false, 0, 0);
+        String realIntent = "intent:///name/nm0000158#Intent;scheme=imdb;package=com.imdb.mobile;"
+                + "S." + ExternalNavigationHandler.EXTRA_BROWSER_FALLBACK_URL + "="
+                + "https://play.google.com/store/apps/details?id=com.imdb.mobile"
+                + "&referrer=mypage;end";
+
+        checkUrl(realIntent)
+                .withPageTransition(PageTransition.LINK)
+                .withIsRedirect(true)
+                .withRedirectHandler(redirectHandler)
+                .expecting(OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT,
+                        START_OTHER_ACTIVITY);
+
+        assertEquals("market://details?id=com.imdb.mobile&referrer=mypage",
+                mDelegate.startActivityIntent.getDataString());
+    }
+
+    @SmallTest
     public void testFallbackUrl_IntentResolutionFailsWithoutPackageName() {
         // IMDB app isn't installed.
         mDelegate.setCanResolveActivity(false);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageSavePageLaterEvaluationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageSavePageLaterEvaluationTest.java
index 81ae3da..76a7e5d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageSavePageLaterEvaluationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageSavePageLaterEvaluationTest.java
@@ -75,6 +75,7 @@
     }
 
     private static final String TAG = "OPSPLEvaluation";
+    private static final String TAG_PROGRESS = "EvalProgress@@@@@@";
     private static final String NAMESPACE = "async_loading";
     private static final String NEW_LINE = System.getProperty("line.separator");
     private static final String DELIMITER = ";";
@@ -181,15 +182,15 @@
                     for (String file : files) {
                         File currentFile = new File(externalArchiveDir.getPath(), file);
                         if (!currentFile.delete()) {
-                            log(file + " cannot be deleted when clearing previous archives.");
+                            log(TAG, file + " cannot be deleted when clearing previous archives.");
                         }
                     }
                 }
             } else if (!externalArchiveDir.mkdir()) {
-                log("Cannot create directory on external storage to store saved pages.");
+                log(TAG, "Cannot create directory on external storage to store saved pages.");
             }
         } catch (SecurityException e) {
-            log("Failed to delete or create external archive folder!");
+            log(TAG, "Failed to delete or create external archive folder!");
         }
         return externalArchiveDir;
     }
@@ -197,8 +198,8 @@
     /**
      * Print log message in output file through evaluation bridge.
      */
-    private void log(String message) {
-        mBridge.log(TAG, message);
+    private void log(String tag, String format, Object... args) {
+        mBridge.log(tag, String.format(format, args));
     }
 
     /**
@@ -206,7 +207,7 @@
      */
     private void checkTrue(boolean condition, String message) {
         if (!condition) {
-            log(message);
+            log(TAG, message);
             fail();
         }
     }
@@ -274,17 +275,20 @@
                 timeDelta.setStartTime(System.currentTimeMillis());
                 metadata.mTimeDelta = timeDelta;
                 mRequestMetadata.put(request.getRequestId(), metadata);
-                log("SavePageRequest Added for " + metadata.mUrl + "  with id " + metadata.mId);
+                log(TAG,
+                        "SavePageRequest Added for " + metadata.mUrl + "  with id " + metadata.mId);
             }
             public void savePageRequestCompleted(SavePageRequest request, int status) {
                 RequestMetadata metadata = mRequestMetadata.get(request.getRequestId());
                 metadata.mTimeDelta.setEndTime(System.currentTimeMillis());
                 if (metadata.mStatus == -1) {
                     mCount++;
+                    log(TAG_PROGRESS, "%s is saved with result: %s. (%d/%d)", metadata.mUrl,
+                            statusToString(status), mCount, mUrls.size());
                 } else {
-                    log("The request for url: " + metadata.mUrl
-                            + " has more than one completion callbacks!");
-                    log("Previous status: " + metadata.mStatus + ". Current: " + status);
+                    log(TAG, "The request for url: " + metadata.mUrl
+                                    + " has more than one completion callbacks!");
+                    log(TAG, "Previous status: " + metadata.mStatus + ". Current: " + status);
                 }
                 metadata.mStatus = status;
                 if (mCount == mUrls.size() || mCount % mScheduleBatchSize == 0) {
@@ -325,7 +329,7 @@
             return;
         }
         int count = 0;
-        log("# of Urls in file: " + mUrls.size());
+        log(TAG_PROGRESS, "# of Urls in file: " + mUrls.size());
         for (int i = 0; i < mUrls.size(); i++) {
             savePageLater(mUrls.get(i), NAMESPACE);
             count++;
@@ -335,8 +339,8 @@
                 mCompletionLatch.await();
             }
         }
-        log("All urls are processed, going to write results.");
         writeResults();
+        log(TAG_PROGRESS, "Urls processing DONE.");
     }
 
     private void getUrlListFromInputFile(String inputFilePath)
@@ -430,7 +434,7 @@
         try {
             int failedCount = 0;
             if (mCount < mUrls.size()) {
-                log("Test terminated before all requests completed.");
+                log(TAG, "Test terminated before all requests completed.");
             }
             File externalArchiveDir = getExternalArchiveDir();
             for (int i = 0; i < mRequestMetadata.size(); i++) {
@@ -453,7 +457,7 @@
                 File originalPage = new File(page.getFilePath());
                 File externalPage = new File(externalArchiveDir, originalPage.getName());
                 if (!OfflinePageUtils.copyToShareableLocation(originalPage, externalPage)) {
-                    log("Saved page for url " + page.getUrl() + " cannot be moved.");
+                    log(TAG, "Saved page for url " + page.getUrl() + " cannot be moved.");
                 }
             }
             output.write(String.format(
diff --git a/chrome/browser/android/vr_shell/ui_elements.h b/chrome/browser/android/vr_shell/ui_elements.h
index 056896d..a8a2527 100644
--- a/chrome/browser/android/vr_shell/ui_elements.h
+++ b/chrome/browser/android/vr_shell/ui_elements.h
@@ -10,7 +10,7 @@
 
 #include "base/macros.h"
 #include "chrome/browser/android/vr_shell/vr_math.h"
-#include "third_party/gvr-android-sdk/src/ndk/include/vr/gvr/capi/include/gvr_types.h"
+#include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_types.h"
 
 namespace vr_shell {
 
diff --git a/chrome/browser/android/vr_shell/vr_controller.cc b/chrome/browser/android/vr_shell/vr_controller.cc
index 6733d25..0cf8b1660 100644
--- a/chrome/browser/android/vr_shell/vr_controller.cc
+++ b/chrome/browser/android/vr_shell/vr_controller.cc
@@ -8,8 +8,8 @@
 
 #include "base/logging.h"
 #include "base/time/time.h"
-#include "third_party/gvr-android-sdk/src/ndk/include/vr/gvr/capi/include/gvr.h"
-#include "third_party/gvr-android-sdk/src/ndk/include/vr/gvr/capi/include/gvr_controller.h"
+#include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr.h"
+#include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_controller.h"
 
 namespace vr_shell {
 
diff --git a/chrome/browser/android/vr_shell/vr_controller.h b/chrome/browser/android/vr_shell/vr_controller.h
index 7aaebec..7580500 100644
--- a/chrome/browser/android/vr_shell/vr_controller.h
+++ b/chrome/browser/android/vr_shell/vr_controller.h
@@ -11,7 +11,7 @@
 #include "base/macros.h"
 #include "third_party/WebKit/public/platform/WebGestureEvent.h"
 #include "third_party/WebKit/public/platform/WebInputEvent.h"
-#include "third_party/gvr-android-sdk/src/ndk/include/vr/gvr/capi/include/gvr_types.h"
+#include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_types.h"
 
 using blink::WebGestureEvent;
 using blink::WebInputEvent;
diff --git a/chrome/browser/android/vr_shell/vr_gl_util.h b/chrome/browser/android/vr_shell/vr_gl_util.h
index cc577b6..4c21b8d 100644
--- a/chrome/browser/android/vr_shell/vr_gl_util.h
+++ b/chrome/browser/android/vr_shell/vr_gl_util.h
@@ -7,7 +7,7 @@
 
 #include <array>
 
-#include "third_party/gvr-android-sdk/src/ndk/include/vr/gvr/capi/include/gvr_types.h"
+#include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_types.h"
 #include "ui/gl/gl_bindings.h"
 
 namespace vr_shell {
diff --git a/chrome/browser/android/vr_shell/vr_math.h b/chrome/browser/android/vr_shell/vr_math.h
index bc0e3f8..7073d74 100644
--- a/chrome/browser/android/vr_shell/vr_math.h
+++ b/chrome/browser/android/vr_shell/vr_math.h
@@ -7,7 +7,7 @@
 
 #include <array>
 
-#include "third_party/gvr-android-sdk/src/ndk/include/vr/gvr/capi/include/gvr_types.h"
+#include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_types.h"
 
 namespace vr_shell {
 
diff --git a/chrome/browser/android/vr_shell/vr_shell.h b/chrome/browser/android/vr_shell/vr_shell.h
index a8387a5c..212f1fed 100644
--- a/chrome/browser/android/vr_shell/vr_shell.h
+++ b/chrome/browser/android/vr_shell/vr_shell.h
@@ -16,8 +16,8 @@
 #include "base/single_thread_task_runner.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "device/vr/android/gvr/gvr_delegate.h"
-#include "third_party/gvr-android-sdk/src/ndk/include/vr/gvr/capi/include/gvr.h"
-#include "third_party/gvr-android-sdk/src/ndk/include/vr/gvr/capi/include/gvr_types.h"
+#include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr.h"
+#include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_types.h"
 
 namespace base {
 class ListValue;
diff --git a/chrome/browser/android/vr_shell/vr_shell_gl.h b/chrome/browser/android/vr_shell/vr_shell_gl.h
index 1f5d0e3..ae908cb 100644
--- a/chrome/browser/android/vr_shell/vr_shell_gl.h
+++ b/chrome/browser/android/vr_shell/vr_shell_gl.h
@@ -13,8 +13,8 @@
 #include "base/memory/weak_ptr.h"
 #include "base/single_thread_task_runner.h"
 #include "device/vr/android/gvr/gvr_delegate.h"
-#include "third_party/gvr-android-sdk/src/ndk/include/vr/gvr/capi/include/gvr.h"
-#include "third_party/gvr-android-sdk/src/ndk/include/vr/gvr/capi/include/gvr_types.h"
+#include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr.h"
+#include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_types.h"
 #include "ui/gfx/native_widget_types.h"
 
 namespace base {
diff --git a/chrome/browser/android/vr_shell/vr_shell_renderer.h b/chrome/browser/android/vr_shell/vr_shell_renderer.h
index ada54fa3..b5d7f99 100644
--- a/chrome/browser/android/vr_shell/vr_shell_renderer.h
+++ b/chrome/browser/android/vr_shell/vr_shell_renderer.h
@@ -9,7 +9,7 @@
 
 #include "base/macros.h"
 #include "chrome/browser/android/vr_shell/vr_math.h"
-#include "third_party/gvr-android-sdk/src/ndk/include/vr/gvr/capi/include/gvr_types.h"
+#include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_types.h"
 #include "ui/gl/gl_bindings.h"
 
 namespace vr_shell {
diff --git a/chrome/browser/chromeos/login/lock/webui_screen_locker.cc b/chrome/browser/chromeos/login/lock/webui_screen_locker.cc
index df0ef9d..cf9824bd 100644
--- a/chrome/browser/chromeos/login/lock/webui_screen_locker.cc
+++ b/chrome/browser/chromeos/login/lock/webui_screen_locker.cc
@@ -106,7 +106,8 @@
       SharedWebViewFactory::GetForProfile(ProfileHelper::GetSigninProfile());
 
   scoped_refptr<WebViewHandle> web_view_handle;
-  if (!shared_web_view->Get(GURL(kLoginURL), &web_view_handle)) {
+  if (!shared_web_view->has_web_view() &&
+      !shared_web_view->Get(GURL(kLoginURL), &web_view_handle)) {
     web_view_handle->web_view()->LoadInitialURL(GURL(kLoginURL));
     InitializeWebView(
         web_view_handle->web_view(),
diff --git a/chrome/browser/chromeos/login/ui/shared_web_view.cc b/chrome/browser/chromeos/login/ui/shared_web_view.cc
index e2b24f9f..5245d41f 100644
--- a/chrome/browser/chromeos/login/ui/shared_web_view.cc
+++ b/chrome/browser/chromeos/login/ui/shared_web_view.cc
@@ -17,7 +17,7 @@
 namespace chromeos {
 
 SharedWebView::SharedWebView(Profile* profile) : profile_(profile) {
-  registrar_.Add(this, chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST,
+  registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
                  content::NotificationService::AllSources());
   memory_pressure_listener_ = base::MakeUnique<base::MemoryPressureListener>(
       base::Bind(&SharedWebView::OnMemoryPressure, base::Unretained(this)));
@@ -63,7 +63,7 @@
 void SharedWebView::Observe(int type,
                             const content::NotificationSource& source,
                             const content::NotificationDetails& details) {
-  DCHECK_EQ(chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST, type);
+  DCHECK_EQ(chrome::NOTIFICATION_APP_TERMINATING, type);
   web_view_handle_ = nullptr;
 }
 
diff --git a/chrome/browser/chromeos/login/ui/shared_web_view.h b/chrome/browser/chromeos/login/ui/shared_web_view.h
index abe936f8..39300be 100644
--- a/chrome/browser/chromeos/login/ui/shared_web_view.h
+++ b/chrome/browser/chromeos/login/ui/shared_web_view.h
@@ -37,6 +37,9 @@
   // was freshly created.
   bool Get(const GURL& url, scoped_refptr<WebViewHandle>* out_handle);
 
+  // Returns true if there is an attached views::WebView instance.
+  bool has_web_view() const { return !!web_view_handle_; }
+
  private:
   // content::NotificationObserver:
   void Observe(int type,
diff --git a/chrome/browser/chromeos/login/ui/user_adding_screen_browsertest.cc b/chrome/browser/chromeos/login/ui/user_adding_screen_browsertest.cc
index 038a6e9f..2cd6df2 100644
--- a/chrome/browser/chromeos/login/ui/user_adding_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/ui/user_adding_screen_browsertest.cc
@@ -266,15 +266,21 @@
   WaitUntilUserAddingFinishedOrCancelled();
   content::RunAllPendingInMessageLoop();
 
-  ScreenLocker::Show();
-  content::WindowedNotificationObserver(
-      chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED,
-      content::NotificationService::AllSources()).Wait();
+  {
+    content::WindowedNotificationObserver observer(
+        chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED,
+        content::NotificationService::AllSources());
+    ScreenLocker::Show();
+    observer.Wait();
+  }
 
-  ScreenLocker::Hide();
-  content::WindowedNotificationObserver(
-      chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED,
-      content::NotificationService::AllSources()).Wait();
+  {
+    content::WindowedNotificationObserver observer(
+        chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED,
+        content::NotificationService::AllSources());
+    ScreenLocker::Hide();
+    observer.Wait();
+  }
 
   UserAddingScreen::Get()->Start();
   content::RunAllPendingInMessageLoop();
diff --git a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
index 8e1f075..e5fe52b 100644
--- a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
+++ b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
@@ -305,16 +305,10 @@
       if (extension->id() == kWebStoreAppId)
         return true;
 
-      // --isolate-extensions should isolate extensions, except for a) hosted
-      // apps, b) platform apps.
-      // a) Isolating hosted apps is a good idea, but ought to be a separate
-      //    knob.
-      // b) Sandbox pages in platform app can load web content in iframes;
-      //    isolating the app and the iframe leads to StoragePartition mismatch
-      //    in the two processes.
-      //    TODO(lazyboy): We should deprecate this behaviour and not let web
-      //    content load in platform app's process; see http://crbug.com/615585.
-      if (extension->is_hosted_app() || extension->is_platform_app())
+      // --isolate-extensions should isolate extensions, except for hosted
+      // apps. Isolating hosted apps is a good idea, but ought to be a separate
+      // knob.
+      if (extension->is_hosted_app())
         return false;
 
       // Isolate all extensions.
diff --git a/chrome/browser/extensions/sandboxed_pages_apitest.cc b/chrome/browser/extensions/sandboxed_pages_apitest.cc
index 45ae865..4245106 100644
--- a/chrome/browser/extensions/sandboxed_pages_apitest.cc
+++ b/chrome/browser/extensions/sandboxed_pages_apitest.cc
@@ -7,3 +7,14 @@
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, SandboxedPages) {
   EXPECT_TRUE(RunExtensionSubtest("sandboxed_pages", "main.html")) << message_;
 }
+
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, SandboxedPagesCSP) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+
+  // This app attempts to load remote web content inside a sandboxed page.
+  // Loading web content will fail because of CSP. In addition to that we will
+  // show manifest warnings, hence the kFlagIgnoreManifestWarnings.
+  EXPECT_TRUE(RunExtensionSubtest("sandboxed_pages_csp", "main.html",
+                                  kFlagIgnoreManifestWarnings))
+      << message_;
+}
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_drag_controller.h b/chrome/browser/ui/cocoa/tabs/tab_strip_drag_controller.h
index 7af5fc8..6f7f2c8 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_drag_controller.h
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_drag_controller.h
@@ -35,6 +35,7 @@
   // These are released on mouseUp:
   BOOL moveWindowOnDrag_;  // Set if the only tab of a window is dragged.
   BOOL tabWasDragged_;  // Has the tab been dragged?
+  BOOL outOfTabHorizDeadZone_;   // Moved out of its horizontal dead zone?
   BOOL draggingWithinTabStrip_;  // Did drag stay in the current tab strip?
   BOOL chromeIsVisible_;
 
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_drag_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_drag_controller.mm
index 3d16831..f06e1d1a 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_drag_controller.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_drag_controller.mm
@@ -17,7 +17,8 @@
 #include "ui/base/cocoa/cocoa_base_utils.h"
 #include "ui/gfx/mac/scoped_cocoa_disable_screen_updates.h"
 
-const CGFloat kTearDistance = 36.0;
+const CGFloat kHorizTearDistance = 10.0;  // Using the same value as Views.
+const CGFloat kVertTearDistance = 36.0;
 const NSTimeInterval kTearDuration = 0.333;
 
 // Returns whether |screenPoint| is inside the bounds of |view|.
@@ -164,24 +165,34 @@
     return;
   }
 
-  // First, go through the magnetic drag cycle. We break out of this if
-  // "stretchiness" ever exceeds a set amount.
-  tabWasDragged_ = YES;
-
   if (draggingWithinTabStrip_) {
     NSPoint thisPoint = [NSEvent mouseLocation];
-    CGFloat offset = thisPoint.x - dragOrigin_.x;
-    [sourceController_ insertPlaceholderForTab:[draggedTab_ tabView]
-                                         frame:NSOffsetRect(sourceTabFrame_,
-                                                            offset, 0)];
-    // Check that we haven't pulled the tab too far to start a drag. This
-    // can include either pulling it too far down, or off the side of the tab
-    // strip that would cause it to no longer be fully visible.
-    BOOL stillVisible =
-        [sourceController_ isTabFullyVisible:[draggedTab_ tabView]];
-    CGFloat tearForce = fabs(thisPoint.y - dragOrigin_.y);
+    CGFloat horizOffset = thisPoint.x - dragOrigin_.x;
+    CGFloat vertOffset = thisPoint.y - dragOrigin_.y;
+    BOOL stillVisible = YES;
+
+    // If the tab hasn't been torn out of the vertical dead zone, and has never
+    // been torn out of the horizontal dead zone, return. This prevents the tab
+    // from sticking if it's dragged back near its original position.
+    if (fabs(horizOffset) <= kHorizTearDistance && !outOfTabHorizDeadZone_ &&
+        fabs(vertOffset) <= kVertTearDistance)
+      return;
+    if (fabs(horizOffset) > kHorizTearDistance)
+      outOfTabHorizDeadZone_ = YES;
+
+    // If the tab is pulled out of either dead zone, set tabWasDragged_ to YES
+    // and call insertPlaceholderForTab:frame:.
+    if (outOfTabHorizDeadZone_ || fabs(vertOffset) > kVertTearDistance) {
+      tabWasDragged_ = YES;
+      [sourceController_ insertPlaceholderForTab:[draggedTab_ tabView]
+                                           frame:NSOffsetRect(sourceTabFrame_,
+                                                              horizOffset, 0)];
+    }
+
+    // Check if the tab has been pulled out of the tab strip.
+    stillVisible = [sourceController_ isTabFullyVisible:[draggedTab_ tabView]];
     if ([sourceController_ tabTearingAllowed] &&
-        (tearForce > kTearDistance || !stillVisible)) {
+        (fabs(vertOffset) > kVertTearDistance || !stillVisible)) {
       draggingWithinTabStrip_ = NO;
       // When you finally leave the strip, we treat that as the origin.
       dragOrigin_.x = thisPoint.x;
@@ -198,7 +209,7 @@
       // window. To fix, explicitly set the tab's new location so that it's
       // correct at tearoff time. See http://crbug.com/541674 .
       NSRect newTabFrame = [[draggedTab_ tabView] frame];
-      newTabFrame.origin.x = trunc(sourceTabFrame_.origin.x + offset);
+      newTabFrame.origin.x = trunc(sourceTabFrame_.origin.x + horizOffset);
 
       // Ensure that the tab won't extend beyond the right edge of the tab area
       // in the tab strip.
@@ -217,10 +228,11 @@
       }
 
       [[draggedTab_ tabView] setFrameOrigin:newTabFrame.origin];
-  } else {
-      // Still dragging within the tab strip, wait for the next drag event.
-      return;
     }
+
+    // Else, still dragging within the tab strip, wait for the next drag
+    // event.
+    return;
   }
 
   NSPoint thisPoint = [NSEvent mouseLocation];
@@ -403,6 +415,7 @@
 - (void)endDrag:(NSEvent*)event {
   // Cancel any delayed -continueDrag: requests that may still be pending.
   [NSObject cancelPreviousPerformRequestsWithTarget:self];
+  outOfTabHorizDeadZone_ = NO;
 
   // Special-case this to keep the logic below simpler.
   if (moveWindowOnDrag_) {
diff --git a/chrome/browser/ui/webui/settings/profile_info_handler.cc b/chrome/browser/ui/webui/settings/profile_info_handler.cc
index 1dcdfd3b..60f91128 100644
--- a/chrome/browser/ui/webui/settings/profile_info_handler.cc
+++ b/chrome/browser/ui/webui/settings/profile_info_handler.cc
@@ -41,7 +41,13 @@
 
 ProfileInfoHandler::ProfileInfoHandler(Profile* profile)
     : profile_(profile),
-      profile_observer_(this) {}
+      profile_observer_(this) {
+#if defined(OS_CHROMEOS)
+  // Set up the chrome://userimage/ source.
+  content::URLDataSource::Add(profile,
+                              new chromeos::options::UserImageSource());
+#endif
+}
 
 ProfileInfoHandler::~ProfileInfoHandler() {}
 
diff --git a/chrome/common/extensions/docs/templates/articles/manifest/sandbox.html b/chrome/common/extensions/docs/templates/articles/manifest/sandbox.html
index 39ac817..09810bc 100644
--- a/chrome/common/extensions/docs/templates/articles/manifest/sandbox.html
+++ b/chrome/common/extensions/docs/templates/articles/manifest/sandbox.html
@@ -1,6 +1,13 @@
 <h1 id="sandbox">Manifest - Sandbox</h1>
 
 <p>
+<b><em>Warning:</em></b> Starting in version 57, Chrome will no longer allow
+external web content (including embedded frames and scripts) inside sandboxed
+pages.  Please use a
+<a href="https://developer.chrome.com/apps/webview_tag">webview</a> instead.
+</p>
+
+<p>
 Defines an collection of app or extension pages that are to be served
 in a sandboxed unique origin, and optionally a Content Security Policy to use
 with them. Being in a sandbox has two implications:
@@ -30,7 +37,7 @@
     ]
     // content_security_policy is optional.
     "content_security_policy":
-        "sandbox allow-scripts; script-src https://www.google.com"
+        "sandbox allow-scripts; script-src 'self'"
   ],
   ...
 }
@@ -38,11 +45,14 @@
   
   <p>
   If not specified, the default <code>content_security_policy</code> value is
-  <code>sandbox allow-scripts allow-forms</code>. You can specify your CSP
-  value to restrict the sandbox even further, but it must have the <code>sandbox</code>
+  <code>sandbox allow-scripts allow-forms allow-popups allow-modals;
+    script-src 'self' 'unsafe-inline' 'unsafe-eval'; child-src 'self';</code>.
+  You can specify your CSP value to restrict the sandbox even further,
+  but it must have the <code>sandbox</code>
   directive and may not have the <code>allow-same-origin</code> token (see
   <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/the-iframe-element.html#attr-iframe-sandbox">the
-  HTML5 specification</a> for possible sandbox tokens).
+  HTML5 specification</a> for possible sandbox tokens). Also, the CSP you
+  specify may not allow loading external web content inside sandboxed pages.
   </p>
 </li>
 </ol>
diff --git a/chrome/test/data/extensions/api_test/automation/tests/tabs/image_data.js b/chrome/test/data/extensions/api_test/automation/tests/tabs/image_data.js
index 6b1c47f..d98296e 100644
--- a/chrome/test/data/extensions/api_test/automation/tests/tabs/image_data.js
+++ b/chrome/test/data/extensions/api_test/automation/tests/tabs/image_data.js
@@ -13,37 +13,39 @@
       canvas.setAttribute('width', 2);
       canvas.setAttribute('height', 3);
       var context = canvas.getContext('2d');
-      context.drawImage(imgElement, 0, 0);
-      var imageData = context.getImageData(0, 0, 2, 3);
-      // Check image data in RGBA format.
-      // Top row: red
-      assertEq(imageData.data[0], 0xFF);
-      assertEq(imageData.data[1], 0x00);
-      assertEq(imageData.data[2], 0x00);
-      assertEq(imageData.data[3], 0xFF);
-      assertEq(imageData.data[4], 0xFF);
-      assertEq(imageData.data[5], 0x00);
-      assertEq(imageData.data[6], 0x00);
-      assertEq(imageData.data[7], 0xFF);
-      // Middle row: green
-      assertEq(imageData.data[8], 0x00);
-      assertEq(imageData.data[9], 0xFF);
-      assertEq(imageData.data[10], 0x00);
-      assertEq(imageData.data[11], 0xFF);
-      assertEq(imageData.data[12], 0x00);
-      assertEq(imageData.data[13], 0xFF);
-      assertEq(imageData.data[14], 0x00);
-      assertEq(imageData.data[15], 0xFF);
-      // Last row: blue
-      assertEq(imageData.data[16], 0x00);
-      assertEq(imageData.data[17], 0x00);
-      assertEq(imageData.data[18], 0xFF);
-      assertEq(imageData.data[19], 0xFF);
-      assertEq(imageData.data[20], 0x00);
-      assertEq(imageData.data[21], 0x00);
-      assertEq(imageData.data[22], 0xFF);
-      assertEq(imageData.data[23], 0xFF);
-      chrome.test.succeed();
+      imgElement.onload = function() {
+        context.drawImage(imgElement, 0, 0);
+        var imageData = context.getImageData(0, 0, 2, 3);
+        // Check image data in RGBA format.
+        // Top row: red
+        assertEq(imageData.data[0], 0xFF);
+        assertEq(imageData.data[1], 0x00);
+        assertEq(imageData.data[2], 0x00);
+        assertEq(imageData.data[3], 0xFF);
+        assertEq(imageData.data[4], 0xFF);
+        assertEq(imageData.data[5], 0x00);
+        assertEq(imageData.data[6], 0x00);
+        assertEq(imageData.data[7], 0xFF);
+        // Middle row: green
+        assertEq(imageData.data[8], 0x00);
+        assertEq(imageData.data[9], 0xFF);
+        assertEq(imageData.data[10], 0x00);
+        assertEq(imageData.data[11], 0xFF);
+        assertEq(imageData.data[12], 0x00);
+        assertEq(imageData.data[13], 0xFF);
+        assertEq(imageData.data[14], 0x00);
+        assertEq(imageData.data[15], 0xFF);
+        // Last row: blue
+        assertEq(imageData.data[16], 0x00);
+        assertEq(imageData.data[17], 0x00);
+        assertEq(imageData.data[18], 0xFF);
+        assertEq(imageData.data[19], 0xFF);
+        assertEq(imageData.data[20], 0x00);
+        assertEq(imageData.data[21], 0x00);
+        assertEq(imageData.data[22], 0xFF);
+        assertEq(imageData.data[23], 0xFF);
+        chrome.test.succeed();
+      };
     }, true);
     image.getImageData(0, 0);
   }
diff --git a/chrome/test/data/extensions/api_test/sandboxed_pages_csp/local_frame.html b/chrome/test/data/extensions/api_test/sandboxed_pages_csp/local_frame.html
new file mode 100644
index 0000000..eb36bdfc
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/sandboxed_pages_csp/local_frame.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<script src="local_frame.js"></script>
+<div>local_frame.html</div>
diff --git a/chrome/test/data/extensions/api_test/sandboxed_pages_csp/local_frame.js b/chrome/test/data/extensions/api_test/sandboxed_pages_csp/local_frame.js
new file mode 100644
index 0000000..0a320b6
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/sandboxed_pages_csp/local_frame.js
@@ -0,0 +1,11 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+onmessage = function(e) {
+  var data = JSON.parse(e.data);
+  if (data[0] != 'sandboxed frame msg')
+    return;
+  var param = data[1];
+  e.source.postMessage(JSON.stringify(['local frame msg', param]), '*');
+};
diff --git a/chrome/test/data/extensions/api_test/sandboxed_pages_csp/main.html b/chrome/test/data/extensions/api_test/sandboxed_pages_csp/main.html
new file mode 100644
index 0000000..ee7be70
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/sandboxed_pages_csp/main.html
@@ -0,0 +1 @@
+<script src="main.js"></script>
diff --git a/chrome/test/data/extensions/api_test/sandboxed_pages_csp/main.js b/chrome/test/data/extensions/api_test/sandboxed_pages_csp/main.js
new file mode 100644
index 0000000..4b4f45f
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/sandboxed_pages_csp/main.js
@@ -0,0 +1,36 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var LOCAL_FILE_NAME = 'local_frame.html';
+var REMOTE_FILE_NAME = 'remote_frame.html';
+
+onmessage = function(e) {
+  chrome.test.assertEq(e.data, 'succeeded');
+  chrome.test.succeed();
+};
+
+var loadIframeContentInSandboxedPage = function(localUrl, remoteUrl) {
+  var sandboxedFrame = document.createElement('iframe');
+  sandboxedFrame.src = 'sandboxed.html';
+  sandboxedFrame.onload = function() {
+    sandboxedFrame.contentWindow.postMessage(
+        JSON.stringify(['load', localUrl, remoteUrl]), '*');
+    sandboxedFrame.onload = null;
+  };
+  document.body.appendChild(sandboxedFrame);
+};
+
+onload = function() {
+  chrome.test.getConfig(function(config) {
+    chrome.test.runTests([
+      // Local frame will succeed loading, but remote frame will fail.
+      function sandboxedFrameTestLocalAndRemote() {
+        var remoteUrl = 'http://localhost:' + config.testServer.port +
+            '/extensions/api_test/sandboxed_pages_csp/' + REMOTE_FILE_NAME;
+        loadIframeContentInSandboxedPage(
+            LOCAL_FILE_NAME, remoteUrl);
+      }
+    ]);
+  });
+};
diff --git a/chrome/test/data/extensions/api_test/sandboxed_pages_csp/manifest.json b/chrome/test/data/extensions/api_test/sandboxed_pages_csp/manifest.json
new file mode 100644
index 0000000..78fc610
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/sandboxed_pages_csp/manifest.json
@@ -0,0 +1,9 @@
+{
+  "name": "Tests that loading web content fails inside sandboxed pages",
+  "manifest_version": 2,
+  "version": "0.1",
+  "sandbox": {
+    "pages": ["sandboxed.html"],
+    "content_security_policy": "sandbox allow-scripts; child-src *;"
+  }
+}
diff --git a/chrome/test/data/extensions/api_test/sandboxed_pages_csp/remote_frame.html b/chrome/test/data/extensions/api_test/sandboxed_pages_csp/remote_frame.html
new file mode 100644
index 0000000..e969b77
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/sandboxed_pages_csp/remote_frame.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<script src="remote_frame.html"></script>
diff --git a/chrome/test/data/extensions/api_test/sandboxed_pages_csp/remote_frame.js b/chrome/test/data/extensions/api_test/sandboxed_pages_csp/remote_frame.js
new file mode 100644
index 0000000..35f22fc
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/sandboxed_pages_csp/remote_frame.js
@@ -0,0 +1,11 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+onmessage = function(e) {
+  var data = JSON.parse(e.data);
+  if (data[0] != 'sandboxed frame msg')
+    return;
+  var param = data[1];
+  e.source.postMessage(JSON.stringify(['remote frame msg', param]), '*');
+};
diff --git a/chrome/test/data/extensions/api_test/sandboxed_pages_csp/sandboxed.html b/chrome/test/data/extensions/api_test/sandboxed_pages_csp/sandboxed.html
new file mode 100644
index 0000000..ac13d0bb
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/sandboxed_pages_csp/sandboxed.html
@@ -0,0 +1,57 @@
+This page should be sandboxed.
+
+<script>
+// We're not served with the extension default CSP, we can use inline script.
+
+var loadFrameExpectResponse = function(iframe, url) {
+  var identifier = performance.now();
+  return new Promise(function(resolve, reject) {
+    window.addEventListener('message', function(e) {
+      var data = JSON.parse(e.data);
+      if (data[0] == 'local frame msg' && data[1] == identifier) {
+        resolve();
+      } else {
+        reject();
+      }
+    });
+    iframe.onerror = reject;
+    iframe.onload = function() {
+      iframe.contentWindow.postMessage(
+          JSON.stringify(['sandboxed frame msg', identifier]), '*');
+    };
+    iframe.src = url;
+  });
+};
+
+var runTestAndRespond = function(localUrl, remoteUrl) {
+  var iframe = document.createElement('iframe');
+  var sendResponse = function(msg) {
+    var mainWindow = window.opener || window.top;
+    mainWindow.postMessage(msg, '*');
+  };
+
+  // First load local resource in |iframe|, expect the local frame to respond.
+  loadFrameExpectResponse(iframe, localUrl).then(function() {
+    // Then try to load remote resource on the same iframe element. The remote
+    // resource will fail to load but we'd get an iframe.onload event and the
+    // local frame will still be there. Therefore, expect the local frame to
+    // respond again.
+    return loadFrameExpectResponse(iframe, remoteUrl);
+  }).then(function() {
+    sendResponse('succeeded');
+  }).catch(function(err) {
+    sendResponse('failed');
+  });
+  document.body.appendChild(iframe);
+};
+
+onmessage = function(e) {
+  var command = JSON.parse(e.data);
+  if (command[0] == 'load') {
+    var localUrl = command[1];
+    var remoteUrl = command[2];
+    runTestAndRespond(localUrl, remoteUrl);
+  }
+};
+
+</script>
diff --git a/components/cronet/PRESUBMIT.py b/components/cronet/PRESUBMIT.py
index 6ab05a91..e722191e 100644
--- a/components/cronet/PRESUBMIT.py
+++ b/components/cronet/PRESUBMIT.py
@@ -71,15 +71,25 @@
     return []
 
 
+def _RunUnittests(input_api, output_api):
+  return input_api.canned_checks.RunUnitTestsInDirectory(
+      input_api, output_api, '.', [ r'^.+_unittest\.py$'])
+
+
 def CheckChangeOnUpload(input_api, output_api):
   results = []
   results.extend(_PyLintChecks(input_api, output_api))
   results.extend(
       input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
   results.extend(_PackageChecks(input_api, output_api))
+  results.extend(_RunUnittests(input_api, output_api))
   return results
 
 
+def CheckChangeOnCommit(input_api, output_api):
+  return _RunUnittests(input_api, output_api)
+
+
 def _GetTryMasters(project, change):
   return {
     'master.tryserver.chromium.android': {
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn
index 21eabaa..9d50f574 100644
--- a/components/cronet/android/BUILD.gn
+++ b/components/cronet/android/BUILD.gn
@@ -1403,6 +1403,40 @@
   }
 }
 
+# Enforce restrictions for API<->impl boundary.
+action("api_static_checks") {
+  script = "//components/cronet/tools/api_static_checks.py"
+  outputs = [
+    "$target_gen_dir/$target_name.stamp",
+  ]
+  args = [
+    "--api_jar",
+    rebase_path(
+        "$root_out_dir/lib.java/components/cronet/android/cronet_api.jar",
+        root_build_dir),
+    "--impl_jar",
+    rebase_path(
+        "$root_out_dir/lib.java/components/cronet/android/cronet_impl_common_java.jar",
+        root_build_dir),
+    "--impl_jar",
+    rebase_path(
+        "$root_out_dir/lib.java/components/cronet/android/cronet_impl_platform_java.jar",
+        root_build_dir),
+    "--impl_jar",
+    rebase_path(
+        "$root_out_dir/lib.java/components/cronet/android/cronet_impl_native_java.jar",
+        root_build_dir),
+    "--stamp",
+    rebase_path(outputs[0], root_build_dir),
+  ]
+  deps = [
+    ":cronet_api_java",
+    ":cronet_impl_common_java",
+    ":cronet_impl_native_java",
+    ":cronet_impl_platform_java",
+  ]
+}
+
 group("cronet_package") {
   # Marked as testonly as it contains test-only targets too.
   testonly = true
@@ -1413,6 +1447,7 @@
   if (use_platform_icu_alternatives &&
       (!(target_cpu == "arm" && arm_version == 7) || !arm_use_neon)) {
     deps = [
+      ":api_static_checks",
       ":cronet_package_copy",
       ":cronet_package_copy_native_lib",
       ":cronet_package_copy_native_lib_unstripped",
diff --git a/components/cronet/tools/__init__.py b/components/cronet/tools/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/components/cronet/tools/__init__.py
diff --git a/components/cronet/tools/api_static_checks.py b/components/cronet/tools/api_static_checks.py
new file mode 100755
index 0000000..360eaf6
--- /dev/null
+++ b/components/cronet/tools/api_static_checks.py
@@ -0,0 +1,184 @@
+#!/usr/bin/python
+# 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.
+
+"""api_static_checks.py - Check Cronet implementation does not call through
+API classes.
+"""
+
+import argparse
+import os
+import re
+import shutil
+import sys
+import tempfile
+
+REPOSITORY_ROOT = os.path.abspath(os.path.join(
+    os.path.dirname(__file__), '..', '..', '..'))
+
+sys.path.append(os.path.join(REPOSITORY_ROOT, 'build/android/gyp/util'))
+import build_utils
+
+# These regular expressions catch the beginning of lines that declare classes
+# and methods.  The first group returned by a match is the class or method name.
+CLASS_RE = re.compile(r'.*class ([^ ]*) .*\{')
+METHOD_RE = re.compile(r'.* ([^ ]*)\(.*\);')
+
+# Allowed exceptions.  Adding anything to this list is dangerous and should be
+# avoided if possible.  For now these exceptions are for APIs that existed in
+# the first version of Cronet and will be supported forever.
+# TODO(pauljensen): Remove these.
+ALLOWED_EXCEPTIONS = [
+'org.chromium.net.impl.CronetEngineBuilderImpl/build ->'
+    ' org/chromium/net/ExperimentalCronetEngine/getVersionString:'
+    '()Ljava/lang/String;',
+'org.chromium.net.urlconnection.CronetFixedModeOutputStream$UploadDataProviderI'
+    'mpl/read -> org/chromium/net/UploadDataSink/onReadSucceeded:(Z)V',
+'org.chromium.net.urlconnection.CronetFixedModeOutputStream$UploadDataProviderI'
+    'mpl/rewind -> org/chromium/net/UploadDataSink/onRewindError:'
+    '(Ljava/lang/Exception;)V',
+'org.chromium.net.urlconnection.CronetHttpURLConnection/disconnect ->'
+    ' org/chromium/net/UrlRequest/cancel:()V',
+'org.chromium.net.urlconnection.CronetHttpURLConnection/disconnect ->'
+    ' org/chromium/net/UrlResponseInfo/getHttpStatusText:()Ljava/lang/String;',
+'org.chromium.net.urlconnection.CronetHttpURLConnection/disconnect ->'
+    ' org/chromium/net/UrlResponseInfo/getHttpStatusCode:()I',
+'org.chromium.net.urlconnection.CronetHttpURLConnection/getHeaderField ->'
+    ' org/chromium/net/UrlResponseInfo/getHttpStatusCode:()I',
+'org.chromium.net.urlconnection.CronetHttpURLConnection/getErrorStream ->'
+    ' org/chromium/net/UrlResponseInfo/getHttpStatusCode:()I',
+'org.chromium.net.urlconnection.CronetHttpURLConnection/setConnectTimeout ->'
+    ' org/chromium/net/UrlRequest/read:(Ljava/nio/ByteBuffer;)V',
+'org.chromium.net.urlconnection.CronetHttpURLConnection$CronetUrlRequestCallbac'
+    'k/onRedirectReceived -> org/chromium/net/UrlRequest/followRedirect:()V',
+'org.chromium.net.urlconnection.CronetHttpURLConnection$CronetUrlRequestCallbac'
+    'k/onRedirectReceived -> org/chromium/net/UrlRequest/cancel:()V',
+'org.chromium.net.urlconnection.CronetChunkedOutputStream$UploadDataProviderImp'
+    'l/read -> org/chromium/net/UploadDataSink/onReadSucceeded:(Z)V',
+'org.chromium.net.urlconnection.CronetChunkedOutputStream$UploadDataProviderImp'
+    'l/rewind -> org/chromium/net/UploadDataSink/onRewindError:'
+    '(Ljava/lang/Exception;)V',
+'org.chromium.net.urlconnection.CronetBufferedOutputStream$UploadDataProviderIm'
+    'pl/read -> org/chromium/net/UploadDataSink/onReadSucceeded:(Z)V',
+'org.chromium.net.urlconnection.CronetBufferedOutputStream$UploadDataProviderIm'
+    'pl/rewind -> org/chromium/net/UploadDataSink/onRewindSucceeded:()V',
+# getMessage() is an java.lang.Exception member, and so cannot be removed.
+'org.chromium.net.impl.NetworkExceptionImpl/getMessage -> '
+    'org/chromium/net/NetworkException/getMessage:()Ljava/lang/String;',
+]
+
+
+def find_api_calls(dump, api_classes, bad_calls):
+  # Given a dump of an implementation class, find calls through API classes.
+  # |dump| is the output of "javap -c" on the implementation class files.
+  # |api_classes| is the list of classes comprising the API.
+  # |bad_calls| is the list of calls through API classes.  This list is built up
+  #             by this function.
+
+  for line in dump:
+    if CLASS_RE.match(line):
+      caller_class = CLASS_RE.match(line).group(1)
+    if METHOD_RE.match(line):
+      caller_method = METHOD_RE.match(line).group(1)
+    if line[8:16] == ': invoke':
+      callee = line.split(' // ')[1].split('Method ')[1].split('\n')[0]
+      callee_class = callee.split('.')[0]
+      assert callee_class
+      if callee_class in api_classes:
+        callee_method = callee.split('.')[1]
+        assert callee_method
+        # Ignore constructor calls for now as every implementation class
+        # that extends an API class will call them.
+        # TODO(pauljensen): Look into enforcing restricting constructor calls.
+        # https://crbug.com/674975
+        if callee_method.startswith('"<init>"'):
+          continue
+        # Ignore VersionSafe calls
+        if 'VersionSafeCallbacks' in caller_class:
+          continue
+        bad_call = '%s/%s -> %s/%s' % (caller_class, caller_method,
+                                       callee_class, callee_method)
+        if bad_call in ALLOWED_EXCEPTIONS:
+          continue
+        bad_calls += [bad_call]
+
+
+def main(args):
+  # Returns True if no calls through API classes in implementation.
+
+  parser = argparse.ArgumentParser(
+      description='Check modules do not contain ARM Neon instructions.')
+  parser.add_argument('--api_jar',
+                      help='Path to API jar (i.e. cronet_api.jar)',
+                      required=True,
+                      metavar='path/to/cronet_api.jar')
+  parser.add_argument('--impl_jar',
+                      help='Path to implementation jar '
+                          '(i.e. cronet_impl_native_java.jar)',
+                      required=True,
+                      metavar='path/to/cronet_impl_native_java.jar',
+                      action='append')
+  parser.add_argument('--stamp', help='Path to touch on success.')
+  opts = parser.parse_args(args)
+
+  temp_dir = tempfile.mkdtemp()
+
+  # Extract API class files from jar
+  jar_cmd = ['jar', 'xf', os.path.abspath(opts.api_jar)]
+  build_utils.CheckOutput(jar_cmd, cwd=temp_dir)
+  shutil.rmtree(os.path.join(temp_dir, 'META-INF'))
+
+  # Collect names of API classes
+  api_classes = []
+  for dirpath, _, filenames in os.walk(temp_dir):
+    if not filenames:
+      continue
+    package = os.path.relpath(dirpath, temp_dir)
+    for filename in filenames:
+      if filename.endswith('.class'):
+        classname = filename[:-len('.class')]
+        api_classes += [os.path.normpath(os.path.join(package, classname))]
+
+  shutil.rmtree(temp_dir)
+  temp_dir = tempfile.mkdtemp()
+
+  # Extract impl class files from jars
+  for impl_jar in opts.impl_jar:
+    jar_cmd = ['jar', 'xf', os.path.abspath(impl_jar)]
+    build_utils.CheckOutput(jar_cmd, cwd=temp_dir)
+  shutil.rmtree(os.path.join(temp_dir, 'META-INF'))
+
+  # Process classes
+  bad_api_calls = []
+  for dirpath, _, filenames in os.walk(temp_dir):
+    if not filenames:
+      continue
+    # Dump classes
+    dump_file = os.path.join(temp_dir, 'dump.txt')
+    if os.system('javap -c %s > %s' % (
+        ' '.join(os.path.join(dirpath, f) for f in filenames).replace(
+            '$', '\\$'),
+        dump_file)):
+      print 'ERROR: javap failed on ' + ' '.join(filenames)
+      return False
+    # Process class dump
+    with open(dump_file, 'r') as dump:
+      find_api_calls(dump, api_classes, bad_api_calls)
+
+  shutil.rmtree(temp_dir)
+
+  if bad_api_calls:
+    print 'ERROR: Found the following calls from implementation classes through'
+    print '       API classes.  These could fail if older API is used that'
+    print '       does not contain newer methods.  Please call through a'
+    print '       wrapper class from VersionSafeCallbacks.'
+    print '\n'.join(bad_api_calls)
+
+  if not bad_api_calls and opts.stamp:
+    build_utils.Touch(opts.stamp)
+  return not bad_api_calls
+
+
+if __name__ == '__main__':
+  sys.exit(0 if main(sys.argv[1:]) else -1)
diff --git a/components/cronet/tools/api_static_checks_unittest.py b/components/cronet/tools/api_static_checks_unittest.py
new file mode 100755
index 0000000..a6907e6
--- /dev/null
+++ b/components/cronet/tools/api_static_checks_unittest.py
@@ -0,0 +1,95 @@
+#!/usr/bin/python
+# 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.
+
+"""api_static_checks_unittest.py - Unittests for api_static_checks.py"""
+
+
+import contextlib
+from cStringIO import StringIO
+import os
+import shutil
+import sys
+import tempfile
+import unittest
+
+from tools import api_static_checks
+
+
+ERROR_PREFIX = (
+"""ERROR: Found the following calls from implementation classes through
+       API classes.  These could fail if older API is used that
+       does not contain newer methods.  Please call through a
+       wrapper class from VersionSafeCallbacks.
+""")
+
+
+@contextlib.contextmanager
+def capture_output():
+  # A contextmanger that collects the stdout and stderr of wrapped code
+
+  oldout,olderr = sys.stdout, sys.stderr
+  try:
+    out=[StringIO(), StringIO()]
+    sys.stdout,sys.stderr = out
+    yield out
+  finally:
+    sys.stdout,sys.stderr = oldout, olderr
+    out[0] = out[0].getvalue()
+    out[1] = out[1].getvalue()
+
+
+class ApiStaticCheckUnitTest(unittest.TestCase):
+  def setUp(self):
+    self.temp_dir = tempfile.mkdtemp()
+    os.chdir(self.temp_dir)
+
+
+  def tearDown(self):
+    shutil.rmtree(self.temp_dir)
+
+
+  def make_jar(self, java, class_name):
+    # Compile |java| wrapped in a class named |class_name| to a jar file and
+    # return jar filename.
+
+    java_filename = class_name + '.java'
+    class_filename = class_name + '.class'
+    jar_filename = class_name + '.jar'
+
+    with open(java_filename, 'w') as java_file:
+      java_file.write('public class %s {' % class_name)
+      java_file.write(java)
+      java_file.write('}')
+    os.system('javac %s' % java_filename)
+    os.system('jar cf %s %s' % (jar_filename, class_filename))
+    return jar_filename
+
+
+  def run_test(self, api_java, impl_java):
+    api_jar = self.make_jar(api_java, 'Api')
+    impl_jar = self.make_jar(impl_java, 'Impl')
+    with capture_output() as return_output:
+      return_code = api_static_checks.main(
+          ['--api_jar', api_jar, '--impl_jar', impl_jar])
+    return [return_code, return_output[0]]
+
+
+  def test_success(self):
+    # Test simple classes with functions
+    self.assertEqual(self.run_test('void a(){}', 'void b(){}'), [True, ''])
+    # Test simple classes with functions calling themselves
+    self.assertEqual(self.run_test(
+        'void a(){} void b(){a();}', 'void c(){} void d(){c();}'), [True, ''])
+
+
+  def test_failure(self):
+    # Test static call
+    self.assertEqual(self.run_test(
+        'public static void a(){}', 'void b(){Api.a();}'),
+        [False, ERROR_PREFIX + 'Impl/b -> Api/a:()V\n'])
+    # Test virtual call
+    self.assertEqual(self.run_test(
+        'public void a(){}', 'void b(){new Api().a();}'),
+        [False, ERROR_PREFIX + 'Impl/b -> Api/a:()V\n'])
diff --git a/components/cronet/tools_unittest.py b/components/cronet/tools_unittest.py
new file mode 100755
index 0000000..1041406
--- /dev/null
+++ b/components/cronet/tools_unittest.py
@@ -0,0 +1,13 @@
+#!/usr/bin/python
+# 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.
+
+"""Run tools/ unittests."""
+
+import sys
+import unittest
+
+if __name__ == '__main__':
+  suite = unittest.TestLoader().discover('tools', pattern = "*_unittest.py")
+  sys.exit(0 if unittest.TextTestRunner().run(suite).wasSuccessful() else 1)
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
index f8ad88e6..2b58c6b1 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
@@ -154,7 +154,8 @@
       foreground_fetch_pending_(false),
 #endif
       previous_request_failed_authentication_(false),
-      failed_attempts_before_success_(0) {
+      failed_attempts_before_success_(0),
+      fetch_in_progress_(false) {
   DCHECK(request_options);
   DCHECK(config_values);
   DCHECK(config);
@@ -290,6 +291,15 @@
       RecordAuthExpiredHistogram(true);
       previous_request_failed_authentication_ = true;
       InvalidateConfig();
+      DCHECK(!config_->IsDataReductionProxy(proxy_server, nullptr));
+
+      if (fetch_in_progress_) {
+        // If a client config fetch is already in progress, then do not start
+        // another fetch since starting a new fetch will cause extra data
+        // usage, and also cancel the ongoing fetch.
+        return true;
+      }
+
       RetrieveConfig();
 
       if (!load_timing_info.send_start.is_null() &&
@@ -344,6 +354,7 @@
     const net::URLFetcher* source) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(source == fetcher_.get());
+  fetch_in_progress_ = false;
   net::URLRequestStatus status = source->GetStatus();
   std::string response;
   source->GetResponseAsString(&response);
@@ -377,6 +388,7 @@
   }
 
   fetcher_ = std::move(fetcher);
+  fetch_in_progress_ = true;
   fetcher_->Start();
 }
 
@@ -406,8 +418,9 @@
   fetcher->SetRequestContext(url_request_context_getter_);
   // |fetcher| should not retry on 5xx errors since the server may already be
   // overloaded. Spurious 5xx errors are still retried on exponential backoff.
-  static const int kMaxRetries = 5;
-  fetcher->SetAutomaticallyRetryOnNetworkChanges(kMaxRetries);
+  // |fetcher| should not retry on network changes since a new fetch will be
+  // initiated.
+  fetcher->SetAutomaticallyRetryOnNetworkChanges(0);
   return fetcher;
 }
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h
index e9b1332..c14d723f 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h
@@ -276,6 +276,9 @@
   // Time when the IP address last changed.
   base::TimeTicks last_ip_address_change_;
 
+  // True if a client config fetch is in progress.
+  bool fetch_in_progress_;
+
   // Enforce usage on the IO thread.
   base::ThreadChecker thread_checker_;
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc
index b585026..92467e26 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc
@@ -744,8 +744,6 @@
 // headers matches the currrent session key.
 TEST_F(DataReductionProxyConfigServiceClientTest, AuthFailure) {
   Init(true);
-  net::NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
-      net::NetworkChangeNotifier::CONNECTION_WIFI);
   net::HttpRequestHeaders request_headers;
   request_headers.SetHeader(
       "chrome-proxy", "something=something_else, s=" +
@@ -827,6 +825,170 @@
       1 /* AUTH_EXPIRED_SESSION_KEY_MATCH */, 2);
 }
 
+// Verifies that a new config is not fetched due to auth failure while a
+// previous client config fetch triggered due to auth failure is already in
+// progress.
+TEST_F(DataReductionProxyConfigServiceClientTest, MultipleAuthFailures) {
+  Init(true);
+  net::HttpRequestHeaders request_headers;
+  request_headers.SetHeader(
+      "chrome-proxy", "something=something_else, s=" +
+                          std::string(kOldSuccessSessionKey) + ", key=value");
+
+  base::HistogramTester histogram_tester;
+  AddMockPreviousSuccess();
+  AddMockSuccess();
+
+  SetDataReductionProxyEnabled(true, true);
+  EXPECT_FALSE(configurator()->GetProxyConfig().is_valid());
+  histogram_tester.ExpectTotalCount(
+      "DataReductionProxy.ConfigService.AuthExpired", 0);
+  config_client()->RetrieveConfig();
+  RunUntilIdle();
+  // First remote config should be fetched.
+  VerifyRemoteSuccessWithOldConfig();
+  EXPECT_TRUE(configurator()->GetProxyConfig().is_valid());
+  EXPECT_EQ(kOldSuccessSessionKey, request_options()->GetSecureSession());
+  EXPECT_EQ(0, config_client()->GetBackoffErrorCount());
+  histogram_tester.ExpectUniqueSample(
+      "DataReductionProxy.ConfigService.AuthExpired", false, 1);
+
+  // Trigger an auth failure.
+  scoped_refptr<net::HttpResponseHeaders> parsed(new net::HttpResponseHeaders(
+      "HTTP/1.1 407 Proxy Authentication Required\n"));
+  net::ProxyServer origin = net::ProxyServer::FromURI(
+      kOldSuccessOrigin, net::ProxyServer::SCHEME_HTTP);
+  // Calling ShouldRetryDueToAuthFailure should trigger fetching of remote
+  // config.
+  net::LoadTimingInfo load_timing_info;
+  load_timing_info.request_start =
+      base::TimeTicks::Now() - base::TimeDelta::FromSeconds(1);
+  load_timing_info.send_start = load_timing_info.request_start;
+  EXPECT_TRUE(config_client()->ShouldRetryDueToAuthFailure(
+      request_headers, parsed.get(), origin, load_timing_info));
+  EXPECT_EQ(1, config_client()->GetBackoffErrorCount());
+  EXPECT_FALSE(configurator()->GetProxyConfig().is_valid());
+
+  // Persisted config on pref should be cleared.
+  EXPECT_TRUE(persisted_config().empty());
+  histogram_tester.ExpectBucketCount(
+      "DataReductionProxy.ConfigService.AuthExpired", false, 1);
+  histogram_tester.ExpectBucketCount(
+      "DataReductionProxy.ConfigService.AuthExpired", true, 1);
+  histogram_tester.ExpectTotalCount(
+      "DataReductionProxy.ConfigService.AuthFailure.LatencyPenalty", 1);
+
+  // Trigger a second auth failure.
+  EXPECT_EQ(std::string(), request_options()->GetSecureSession());
+  request_headers.SetHeader(
+      "chrome-proxy", "something=something_else, s=" +
+                          std::string(kSuccessSessionKey) + ", key=value");
+  // Calling ShouldRetryDueToAuthFailure should trigger fetching of remote
+  // config.
+  EXPECT_FALSE(config_client()->ShouldRetryDueToAuthFailure(
+      request_headers, parsed.get(), origin, load_timing_info));
+  EXPECT_EQ(1, config_client()->GetBackoffErrorCount());
+  histogram_tester.ExpectBucketCount(
+      "DataReductionProxy.ConfigService.AuthExpired", false, 1);
+  histogram_tester.ExpectBucketCount(
+      "DataReductionProxy.ConfigService.AuthExpired", true, 1);
+  histogram_tester.ExpectTotalCount(
+      "DataReductionProxy.ConfigService.AuthFailure.LatencyPenalty", 1);
+
+  RunUntilIdle();
+  VerifyRemoteSuccess(true);
+
+  // Config should be fetched successfully.
+  EXPECT_FALSE(persisted_config().empty());
+  histogram_tester.ExpectUniqueSample(
+      "DataReductionProxy.ConfigService.AuthExpiredSessionKey",
+      1 /* AUTH_EXPIRED_SESSION_KEY_MATCH */, 1);
+  histogram_tester.ExpectBucketCount(
+      "DataReductionProxy.ConfigService.AuthExpired", false, 2);
+  histogram_tester.ExpectBucketCount(
+      "DataReductionProxy.ConfigService.AuthExpired", true, 1);
+}
+
+// Verifies that a new config is not fetched due to auth failure while a
+// previous client config fetch triggered due to IP address changeis already in
+// progress.
+TEST_F(DataReductionProxyConfigServiceClientTest,
+       IPAddressChangeWithAuthFailure) {
+  Init(true);
+  net::HttpRequestHeaders request_headers;
+  request_headers.SetHeader(
+      "chrome-proxy", "something=something_else, s=" +
+                          std::string(kOldSuccessSessionKey) + ", key=value");
+
+  base::HistogramTester histogram_tester;
+  AddMockPreviousSuccess();
+  AddMockSuccess();
+
+  SetDataReductionProxyEnabled(true, true);
+  EXPECT_FALSE(configurator()->GetProxyConfig().is_valid());
+  histogram_tester.ExpectTotalCount(
+      "DataReductionProxy.ConfigService.AuthExpired", 0);
+  config_client()->RetrieveConfig();
+
+  RunUntilIdle();
+  // First remote config should be fetched.
+  VerifyRemoteSuccessWithOldConfig();
+  EXPECT_TRUE(configurator()->GetProxyConfig().is_valid());
+  EXPECT_EQ(kOldSuccessSessionKey, request_options()->GetSecureSession());
+  EXPECT_EQ(0, config_client()->GetBackoffErrorCount());
+  histogram_tester.ExpectUniqueSample(
+      "DataReductionProxy.ConfigService.AuthExpired", false, 1);
+
+  // Trigger IP address change again.
+  AddMockPreviousSuccess();
+  AddMockPreviousSuccess();
+
+  SetDataReductionProxyEnabled(true, true);
+  EXPECT_TRUE(configurator()->GetProxyConfig().is_valid());
+  config_client()->RetrieveConfig();
+
+  // Trigger an auth failure.
+  scoped_refptr<net::HttpResponseHeaders> parsed(new net::HttpResponseHeaders(
+      "HTTP/1.1 407 Proxy Authentication Required\n"));
+  net::ProxyServer origin = net::ProxyServer::FromURI(
+      kOldSuccessOrigin, net::ProxyServer::SCHEME_HTTP);
+  // Calling ShouldRetryDueToAuthFailure should trigger fetching of remote
+  // config.
+  net::LoadTimingInfo load_timing_info;
+  load_timing_info.request_start =
+      base::TimeTicks::Now() - base::TimeDelta::FromSeconds(1);
+  load_timing_info.send_start = load_timing_info.request_start;
+  EXPECT_TRUE(config_client()->ShouldRetryDueToAuthFailure(
+      request_headers, parsed.get(), origin, load_timing_info));
+  EXPECT_EQ(1, config_client()->GetBackoffErrorCount());
+  EXPECT_FALSE(configurator()->GetProxyConfig().is_valid());
+
+  // Persisted config on pref should be cleared.
+  EXPECT_TRUE(persisted_config().empty());
+  histogram_tester.ExpectBucketCount(
+      "DataReductionProxy.ConfigService.AuthExpired", false, 1);
+  histogram_tester.ExpectBucketCount(
+      "DataReductionProxy.ConfigService.AuthExpired", true, 1);
+
+  EXPECT_FALSE(configurator()->GetProxyConfig().is_valid());
+  // Persisted config on pref should be cleared.
+  EXPECT_TRUE(persisted_config().empty());
+
+  // Config should be fetched now.
+  RunUntilIdle();
+  VerifyRemoteSuccess(true);
+
+  EXPECT_TRUE(configurator()->GetProxyConfig().is_valid());
+  // Persisted config on pref should be cleared.
+  EXPECT_FALSE(persisted_config().empty());
+  EXPECT_EQ(kSuccessSessionKey, request_options()->GetSecureSession());
+  EXPECT_EQ(0, config_client()->GetBackoffErrorCount());
+  histogram_tester.ExpectBucketCount(
+      "DataReductionProxy.ConfigService.AuthExpired", false, 2);
+  histogram_tester.ExpectBucketCount(
+      "DataReductionProxy.ConfigService.AuthExpired", true, 1);
+}
+
 // Verifies the correctness of AuthFailure when the session key in the request
 // headers do not match the currrent session key.
 TEST_F(DataReductionProxyConfigServiceClientTest,
diff --git a/components/ntp_snippets_strings.grdp b/components/ntp_snippets_strings.grdp
index f432f543..c3cfde7 100644
--- a/components/ntp_snippets_strings.grdp
+++ b/components/ntp_snippets_strings.grdp
@@ -30,7 +30,7 @@
   </message>
 
   <message name="IDS_NTP_FOREIGN_SESSIONS_SUGGESTIONS_SECTION_HEADER" desc="Header of the foreign sessions, which is a list of the user's most recently visited tabs on other devices displayed as cards on the New Tab Page.">
-    Recent tabs
+    Tabs from other devices
   </message>
 
   <message name="IDS_NTP_FOREIGN_SESSIONS_SUGGESTIONS_SECTION_EMPTY" desc="On the New Tab Page, text of the card explaining to the user that they can expect to see tabs from other devices in this area in the future.">
diff --git a/components/sync/protocol/search_engine_specifics.proto b/components/sync/protocol/search_engine_specifics.proto
index 03a3e07f..53a6477 100644
--- a/components/sync/protocol/search_engine_specifics.proto
+++ b/components/sync/protocol/search_engine_specifics.proto
@@ -35,7 +35,7 @@
   optional string input_encodings = 8;
   // Obsolete field. This used to represent whether or not this entry is shown
   // in the list of default search engines.
-  // optional bool deprecated_show_in_default_list = 9;
+  optional bool deprecated_show_in_default_list = 9 [deprecated = true];
   // The parameterized URL that provides suggestions as the user types.
   optional string suggestions_url = 10;
   // The ID associated with the prepopulate data this search engine comes from.
diff --git a/content/browser/devtools/protocol/page_handler.cc b/content/browser/devtools/protocol/page_handler.cc
index 03e4af0..f7ec85b 100644
--- a/content/browser/devtools/protocol/page_handler.cc
+++ b/content/browser/devtools/protocol/page_handler.cc
@@ -12,8 +12,8 @@
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/task_scheduler/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "base/threading/worker_pool.h"
 #include "content/browser/devtools/devtools_session.h"
 #include "content/browser/devtools/page_navigation_throttle.h"
 #include "content/browser/devtools/protocol/color_picker.h"
@@ -516,8 +516,9 @@
     --frames_in_flight_;
     return;
   }
-  base::PostTaskAndReplyWithResult(
-      base::WorkerPool::GetTaskRunner(true).get(), FROM_HERE,
+  base::PostTaskWithTraitsAndReplyWithResult(
+      FROM_HERE, base::TaskTraits().WithShutdownBehavior(
+                     base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN),
       base::Bind(&EncodeScreencastFrame, bitmap, screencast_format_,
                  screencast_quality_),
       base::Bind(&PageHandler::ScreencastFrameEncoded,
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 229ef2d..ef14c83 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/frame_host/render_frame_host_impl.h"
 
+#include <algorithm>
 #include <utility>
 
 #include "base/bind.h"
@@ -3229,19 +3230,28 @@
 
 WebBluetoothServiceImpl* RenderFrameHostImpl::CreateWebBluetoothService(
     blink::mojom::WebBluetoothServiceRequest request) {
-  DCHECK(!web_bluetooth_service_);
-  web_bluetooth_service_.reset(
-      new WebBluetoothServiceImpl(this, std::move(request)));
-  // RFHI owns web_bluetooth_service_ and web_bluetooth_service owns the
-  // binding_ which may run the error handler. binding_ can't run the error
+  // RFHI owns |web_bluetooth_services_| and |web_bluetooth_service| owns the
+  // |binding_| which may run the error handler. |binding_| can't run the error
   // handler after it's destroyed so it can't run after the RFHI is destroyed.
-  web_bluetooth_service_->SetClientConnectionErrorHandler(base::Bind(
-      &RenderFrameHostImpl::DeleteWebBluetoothService, base::Unretained(this)));
-  return web_bluetooth_service_.get();
+  auto web_bluetooth_service =
+      base::MakeUnique<WebBluetoothServiceImpl>(this, std::move(request));
+  web_bluetooth_service->SetClientConnectionErrorHandler(
+      base::Bind(&RenderFrameHostImpl::DeleteWebBluetoothService,
+                 base::Unretained(this), web_bluetooth_service.get()));
+  web_bluetooth_services_.push_back(std::move(web_bluetooth_service));
+  return web_bluetooth_services_.back().get();
 }
 
-void RenderFrameHostImpl::DeleteWebBluetoothService() {
-  web_bluetooth_service_.reset();
+void RenderFrameHostImpl::DeleteWebBluetoothService(
+    WebBluetoothServiceImpl* web_bluetooth_service) {
+  auto it = std::find_if(
+      web_bluetooth_services_.begin(), web_bluetooth_services_.end(),
+      [web_bluetooth_service](
+          const std::unique_ptr<WebBluetoothServiceImpl>& service) {
+        return web_bluetooth_service == service.get();
+      });
+  DCHECK(it != web_bluetooth_services_.end());
+  web_bluetooth_services_.erase(it);
 }
 
 void RenderFrameHostImpl::Create(
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 75e7a58..c43170372 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -8,6 +8,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include <list>
 #include <map>
 #include <set>
 #include <string>
@@ -817,7 +818,8 @@
       mojo::InterfaceRequest<blink::mojom::WebBluetoothService> request);
 
   // Deletes the Web Bluetooth Service owned by the frame.
-  void DeleteWebBluetoothService();
+  void DeleteWebBluetoothService(
+      WebBluetoothServiceImpl* web_bluetooth_service);
 
   // service_manager::InterfaceFactory<media::mojom::InterfaceFactory>
   void Create(const service_manager::Identity& remote_identity,
@@ -998,7 +1000,7 @@
       app_web_message_port_message_filter_;
 #endif
 
-  std::unique_ptr<WebBluetoothServiceImpl> web_bluetooth_service_;
+  std::list<std::unique_ptr<WebBluetoothServiceImpl>> web_bluetooth_services_;
 
   // The object managing the accessibility tree for this frame.
   std::unique_ptr<BrowserAccessibilityManager> browser_accessibility_manager_;
diff --git a/content/browser/loader/resource_dispatcher_host_browsertest.cc b/content/browser/loader/resource_dispatcher_host_browsertest.cc
index 4b8b076..44668e0 100644
--- a/content/browser/loader/resource_dispatcher_host_browsertest.cc
+++ b/content/browser/loader/resource_dispatcher_host_browsertest.cc
@@ -4,7 +4,9 @@
 
 #include "content/public/browser/resource_dispatcher_host.h"
 
+#include <memory>
 #include <utility>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
@@ -824,7 +826,9 @@
  public:
   RequestDataResourceDispatcherHostDelegate() {}
 
-  const ScopedVector<RequestDataForDelegate>& data() { return requests_; }
+  const std::vector<std::unique_ptr<RequestDataForDelegate>>& data() {
+    return requests_;
+  }
 
   // ResourceDispatcherHostDelegate implementation:
   void RequestBeginning(
@@ -833,7 +837,7 @@
       AppCacheService* appcache_service,
       ResourceType resource_type,
       std::vector<std::unique_ptr<ResourceThrottle>>* throttles) override {
-    requests_.push_back(new RequestDataForDelegate(
+    requests_.push_back(base::MakeUnique<RequestDataForDelegate>(
         request->url(), request->first_party_for_cookies(),
         request->initiator()));
   }
@@ -841,7 +845,7 @@
   void SetDelegate() { ResourceDispatcherHost::Get()->SetDelegate(this); }
 
  private:
-  ScopedVector<RequestDataForDelegate> requests_;
+  std::vector<std::unique_ptr<RequestDataForDelegate>> requests_;
 
   DISALLOW_COPY_AND_ASSIGN(RequestDataResourceDispatcherHostDelegate);
 };
@@ -885,17 +889,17 @@
   // that match the URL of the top-level document.
   // PlzNavigate: the document itself should have an empty initiator.
   if (IsBrowserSideNavigationEnabled()) {
-    const RequestDataForDelegate* first_request = delegate_->data()[0];
+    const RequestDataForDelegate* first_request = delegate_->data()[0].get();
     EXPECT_EQ(top_url, first_request->first_party);
     EXPECT_FALSE(first_request->initiator.has_value());
     for (size_t i = 1; i < delegate_->data().size(); i++) {
-      const RequestDataForDelegate* request = delegate_->data()[i];
+      const RequestDataForDelegate* request = delegate_->data()[i].get();
       EXPECT_EQ(top_url, request->first_party);
       ASSERT_TRUE(request->initiator.has_value());
       EXPECT_EQ(top_origin, request->initiator);
     }
   } else {
-    for (auto* request : delegate_->data()) {
+    for (const auto& request : delegate_->data()) {
       SCOPED_TRACE(request->url);
       EXPECT_EQ(top_url, request->first_party);
       EXPECT_EQ(top_origin, request->initiator);
diff --git a/content/browser/loader/resource_scheduler_unittest.cc b/content/browser/loader/resource_scheduler_unittest.cc
index 83c2b26..fb88161 100644
--- a/content/browser/loader/resource_scheduler_unittest.cc
+++ b/content/browser/loader/resource_scheduler_unittest.cc
@@ -4,10 +4,11 @@
 
 #include "content/browser/loader/resource_scheduler.h"
 
+#include <memory>
 #include <utility>
+#include <vector>
 
 #include "base/memory/ptr_util.h"
-#include "base/memory/scoped_vector.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/test/scoped_feature_list.h"
@@ -171,57 +172,64 @@
     return NewURLRequestWithChildAndRoute(url, priority, kChildId, kRouteId);
   }
 
-  TestRequest* NewRequestWithRoute(const char* url,
-                                   net::RequestPriority priority,
-                                   int route_id) {
+  std::unique_ptr<TestRequest> NewRequestWithRoute(
+      const char* url,
+      net::RequestPriority priority,
+      int route_id) {
     return NewRequestWithChildAndRoute(url, priority, kChildId, route_id);
   }
 
-  TestRequest* NewRequestWithChildAndRoute(const char* url,
-                                           net::RequestPriority priority,
-                                           int child_id,
-                                           int route_id) {
+  std::unique_ptr<TestRequest> NewRequestWithChildAndRoute(
+      const char* url,
+      net::RequestPriority priority,
+      int child_id,
+      int route_id) {
     return GetNewTestRequest(url, priority, child_id, route_id, true);
   }
 
-  TestRequest* NewRequest(const char* url, net::RequestPriority priority) {
+  std::unique_ptr<TestRequest> NewRequest(const char* url,
+                                          net::RequestPriority priority) {
     return NewRequestWithChildAndRoute(url, priority, kChildId, kRouteId);
   }
 
-  TestRequest* NewBackgroundRequest(const char* url,
-                                    net::RequestPriority priority) {
+  std::unique_ptr<TestRequest> NewBackgroundRequest(
+      const char* url,
+      net::RequestPriority priority) {
     return NewRequestWithChildAndRoute(
         url, priority, kBackgroundChildId, kBackgroundRouteId);
   }
 
-  TestRequest* NewSyncRequest(const char* url, net::RequestPriority priority) {
+  std::unique_ptr<TestRequest> NewSyncRequest(const char* url,
+                                              net::RequestPriority priority) {
     return NewSyncRequestWithChildAndRoute(url, priority, kChildId, kRouteId);
   }
 
-  TestRequest* NewBackgroundSyncRequest(const char* url,
-                                        net::RequestPriority priority) {
+  std::unique_ptr<TestRequest> NewBackgroundSyncRequest(
+      const char* url,
+      net::RequestPriority priority) {
     return NewSyncRequestWithChildAndRoute(
         url, priority, kBackgroundChildId, kBackgroundRouteId);
   }
 
-  TestRequest* NewSyncRequestWithChildAndRoute(const char* url,
-                                               net::RequestPriority priority,
-                                               int child_id,
-                                               int route_id) {
+  std::unique_ptr<TestRequest> NewSyncRequestWithChildAndRoute(
+      const char* url,
+      net::RequestPriority priority,
+      int child_id,
+      int route_id) {
     return GetNewTestRequest(url, priority, child_id, route_id, false);
   }
 
-  TestRequest* GetNewTestRequest(const char* url,
-                                 net::RequestPriority priority,
-                                 int child_id,
-                                 int route_id,
-                                 bool is_async) {
+  std::unique_ptr<TestRequest> GetNewTestRequest(const char* url,
+                                                 net::RequestPriority priority,
+                                                 int child_id,
+                                                 int route_id,
+                                                 bool is_async) {
     std::unique_ptr<net::URLRequest> url_request(
         NewURLRequestWithChildAndRoute(url, priority, child_id, route_id));
     std::unique_ptr<ResourceThrottle> throttle(scheduler_->ScheduleRequest(
         child_id, route_id, is_async, url_request.get()));
-    TestRequest* request = new TestRequest(std::move(url_request),
-                                           std::move(throttle), scheduler());
+    auto request = base::MakeUnique<TestRequest>(
+        std::move(url_request), std::move(throttle), scheduler());
     request->Start();
     return request;
   }
@@ -461,7 +469,7 @@
 
   const int kMaxNumDelayableRequestsPerClient = 10;  // Should match the .cc.
   const int kMaxNumDelayableRequestsPerHost = 6;
-  ScopedVector<TestRequest> lows_singlehost;
+  std::vector<std::unique_ptr<TestRequest>> lows_singlehost;
   // Queue up to the per-host limit (we subtract the current high-pri request).
   for (int i = 0; i < kMaxNumDelayableRequestsPerHost - 1; ++i) {
     string url = "http://host/low" + base::IntToString(i);
@@ -489,7 +497,7 @@
   int expected_slots_left =
       kMaxNumDelayableRequestsPerClient - kMaxNumDelayableRequestsPerHost;
   EXPECT_GT(expected_slots_left, 0);
-  ScopedVector<TestRequest> lows_different_host;
+  std::vector<std::unique_ptr<TestRequest>> lows_different_host;
   base::RunLoop().RunUntilIdle();
   for (int i = 0; i < expected_slots_left; ++i) {
     string url = "http://host" + base::IntToString(i) + "/low";
@@ -535,7 +543,7 @@
   EXPECT_FALSE(idle->started());
 
   const int kMaxNumDelayableRequestsPerClient = 10;  // Should match the .cc.
-  ScopedVector<TestRequest> lows;
+  std::vector<std::unique_ptr<TestRequest>> lows;
   for (int i = 0; i < kMaxNumDelayableRequestsPerClient - 1; ++i) {
     string url = "http://host/low" + base::IntToString(i);
     lows.push_back(NewRequest(url.c_str(), net::LOWEST));
@@ -570,7 +578,7 @@
   // 2 fewer filler requests: 1 for the "low" dummy at the start, and 1 for the
   // one at the end, which will be tested.
   const int kNumFillerRequests = kMaxNumDelayableRequestsPerClient - 2;
-  ScopedVector<TestRequest> lows;
+  std::vector<std::unique_ptr<TestRequest>> lows;
   for (int i = 0; i < kNumFillerRequests; ++i) {
     string url = "http://host" + base::IntToString(i) + "/low";
     lows.push_back(NewRequest(url.c_str(), net::LOWEST));
@@ -597,7 +605,7 @@
   EXPECT_FALSE(idle->started());
 
   const int kMaxNumDelayableRequestsPerClient = 10;  // Should match the .cc.
-  ScopedVector<TestRequest> lows;
+  std::vector<std::unique_ptr<TestRequest>> lows;
   for (int i = 0; i < kMaxNumDelayableRequestsPerClient; ++i) {
     string url = "http://host/low" + base::IntToString(i);
     lows.push_back(NewRequest(url.c_str(), net::LOWEST));
@@ -626,7 +634,7 @@
   std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
 
   const int kMaxNumDelayableRequestsPerClient = 10;  // Should match the .cc.
-  ScopedVector<TestRequest> lows;
+  std::vector<std::unique_ptr<TestRequest>> lows;
   for (int i = 0; i < kMaxNumDelayableRequestsPerClient; ++i) {
     string url = "http://host/low" + base::IntToString(i);
     lows.push_back(NewRequest(url.c_str(), net::IDLE));
@@ -715,7 +723,7 @@
   std::unique_ptr<TestRequest> low1_spdy(
       NewRequest("http://spdyhost1:8080/low", net::LOWEST));
   // Cancel a request after we learn the server supports SPDY.
-  ScopedVector<TestRequest> lows;
+  std::vector<std::unique_ptr<TestRequest>> lows;
   for (int i = 0; i < kMaxNumDelayableRequestsPerClient - 1; ++i) {
     string url = "http://host" + base::IntToString(i) + "/low";
     lows.push_back(NewRequest(url.c_str(), net::LOWEST));
@@ -754,7 +762,7 @@
   std::unique_ptr<TestRequest> low1_spdy(
       NewRequest("http://spdyhost1:8080/low", net::LOWEST));
   // Cancel a request after we learn the server supports SPDY.
-  ScopedVector<TestRequest> lows;
+  std::vector<std::unique_ptr<TestRequest>> lows;
   for (int i = 0; i < kMaxNumDelayableRequestsPerClient - 1; ++i) {
     string url = "http://host" + base::IntToString(i) + "/low";
     lows.push_back(NewRequest(url.c_str(), net::LOWEST));
@@ -810,7 +818,7 @@
   std::unique_ptr<TestRequest> high(NewRequestWithChildAndRoute(
       "http://host/high", net::HIGHEST, kChildId2, kRouteId2));
   const int kMaxNumDelayableRequestsPerClient = 10;
-  ScopedVector<TestRequest> delayable_requests;
+  std::vector<std::unique_ptr<TestRequest>> delayable_requests;
   for (int i = 0; i < kMaxNumDelayableRequestsPerClient + 1; ++i) {
     delayable_requests.push_back(NewRequestWithChildAndRoute(
         "http://host/lowest", net::LOWEST, kChildId2, kRouteId2));
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 2823565..3feab6d 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -51,10 +51,6 @@
     "android/synchronous_compositor_proxy.cc",
     "android/synchronous_compositor_proxy.h",
     "android/synchronous_compositor_registry.h",
-    "bluetooth/bluetooth_type_converters.cc",
-    "bluetooth/bluetooth_type_converters.h",
-    "bluetooth/web_bluetooth_impl.cc",
-    "bluetooth/web_bluetooth_impl.h",
     "browser_plugin/browser_plugin.cc",
     "browser_plugin/browser_plugin.h",
     "browser_plugin/browser_plugin_manager.cc",
@@ -414,7 +410,6 @@
     "//crypto:platform",
     "//device/base/synchronization",
     "//device/battery:mojo_bindings",
-    "//device/bluetooth",
     "//device/gamepad/public/interfaces",
     "//device/screen_orientation/public/interfaces",
     "//device/sensors/public/cpp",
diff --git a/content/renderer/bluetooth/DEPS b/content/renderer/bluetooth/DEPS
deleted file mode 100644
index 2c5a329..0000000
--- a/content/renderer/bluetooth/DEPS
+++ /dev/null
@@ -1,4 +0,0 @@
-include_rules = [
-  "+device/bluetooth",
-]
-
diff --git a/content/renderer/bluetooth/OWNERS b/content/renderer/bluetooth/OWNERS
deleted file mode 100644
index 68a87bd..0000000
--- a/content/renderer/bluetooth/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-per-file *_type_converter*.*=set noparent
-per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS
-
-jyasskin@chromium.org
-ortuno@chromium.org
-scheib@chromium.org
diff --git a/content/renderer/bluetooth/PRESUBMIT.py b/content/renderer/bluetooth/PRESUBMIT.py
deleted file mode 100644
index 3f9babe..0000000
--- a/content/renderer/bluetooth/PRESUBMIT.py
+++ /dev/null
@@ -1,14 +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.
-
-"""Presubmit script.
-
-See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
-for more details about the presubmit API built into depot_tools.
-"""
-
-def CheckChangeOnUpload(input_api, output_api):
-  results = []
-  results += input_api.canned_checks.CheckPatchFormatted(input_api, output_api)
-  return results
diff --git a/content/renderer/bluetooth/bluetooth_type_converters.cc b/content/renderer/bluetooth/bluetooth_type_converters.cc
deleted file mode 100644
index 55a0d8bd..0000000
--- a/content/renderer/bluetooth/bluetooth_type_converters.cc
+++ /dev/null
@@ -1,72 +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 "content/renderer/bluetooth/bluetooth_type_converters.h"
-
-#include "content/child/mojo/type_converters.h"
-#include "third_party/WebKit/public/platform/modules/bluetooth/WebRequestDeviceOptions.h"
-
-namespace mojo {
-
-// static
-blink::mojom::WebBluetoothScanFilterPtr TypeConverter<
-    blink::mojom::WebBluetoothScanFilterPtr,
-    blink::WebBluetoothScanFilter>::Convert(const blink::WebBluetoothScanFilter&
-                                                web_filter) {
-  blink::mojom::WebBluetoothScanFilterPtr filter =
-      blink::mojom::WebBluetoothScanFilter::New();
-
-  if (!web_filter.services.isEmpty()) {
-    filter->services.emplace();
-    for (const auto& service : web_filter.services) {
-      filter->services->push_back(device::BluetoothUUID(service.utf8()));
-    }
-  }
-
-  if (web_filter.hasName)
-    filter->name = web_filter.name.utf8();
-
-  if (!web_filter.namePrefix.isEmpty())
-    filter->name_prefix = web_filter.namePrefix.utf8();
-  return filter;
-}
-
-// static
-blink::mojom::WebBluetoothRequestDeviceOptionsPtr
-TypeConverter<blink::mojom::WebBluetoothRequestDeviceOptionsPtr,
-              blink::WebRequestDeviceOptions>::
-    Convert(const blink::WebRequestDeviceOptions& web_options) {
-  blink::mojom::WebBluetoothRequestDeviceOptionsPtr options =
-      blink::mojom::WebBluetoothRequestDeviceOptions::New();
-
-  options->accept_all_devices = web_options.acceptAllDevices;
-
-  if (web_options.hasFilters) {
-    options->filters.emplace();
-    for (const auto& filter : web_options.filters) {
-      options->filters->push_back(blink::mojom::WebBluetoothScanFilter::From<
-                                  blink::WebBluetoothScanFilter>(filter));
-    }
-  }
-
-  for (const auto& optional_service : web_options.optionalServices) {
-    options->optional_services.push_back(
-        device::BluetoothUUID(optional_service.utf8()));
-  }
-
-  return options;
-}
-
-// static
-device::BluetoothUUID
-TypeConverter<device::BluetoothUUID, blink::WebString>::Convert(
-    const blink::WebString& web_string) {
-  device::BluetoothUUID uuid = device::BluetoothUUID(web_string.utf8());
-
-  DCHECK(uuid.IsValid());
-
-  return uuid;
-}
-
-}  // namespace mojo
diff --git a/content/renderer/bluetooth/bluetooth_type_converters.h b/content/renderer/bluetooth/bluetooth_type_converters.h
deleted file mode 100644
index b747aee..0000000
--- a/content/renderer/bluetooth/bluetooth_type_converters.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_BLUETOOTH_BLUETOOTH_TYPE_CONVERTERS_H_
-#define CONTENT_RENDERER_BLUETOOTH_BLUETOOTH_TYPE_CONVERTERS_H_
-
-#include "base/optional.h"
-#include "device/bluetooth/bluetooth_uuid.h"
-#include "mojo/public/cpp/bindings/type_converter.h"
-#include "third_party/WebKit/public/platform/WebString.h"
-#include "third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom.h"
-
-namespace blink {
-struct WebBluetoothScanFilter;
-struct WebRequestDeviceOptions;
-}
-
-namespace mojo {
-
-template <>
-struct TypeConverter<blink::mojom::WebBluetoothScanFilterPtr,
-                     blink::WebBluetoothScanFilter> {
-  static blink::mojom::WebBluetoothScanFilterPtr Convert(
-      const blink::WebBluetoothScanFilter& web_filter);
-};
-
-template <>
-struct TypeConverter<blink::mojom::WebBluetoothRequestDeviceOptionsPtr,
-                     blink::WebRequestDeviceOptions> {
-  static blink::mojom::WebBluetoothRequestDeviceOptionsPtr Convert(
-      const blink::WebRequestDeviceOptions& web_options);
-};
-
-template <>
-struct TypeConverter<device::BluetoothUUID, blink::WebString> {
-  static device::BluetoothUUID Convert(const blink::WebString& web_string);
-};
-
-}  // namespace mojo
-
-#endif  // CONTENT_RENDERER_BLUETOOTH_BLUETOOTH_TYPE_CONVERTERS_H_
diff --git a/content/renderer/bluetooth/web_bluetooth_impl.cc b/content/renderer/bluetooth/web_bluetooth_impl.cc
deleted file mode 100644
index c518ef6..0000000
--- a/content/renderer/bluetooth/web_bluetooth_impl.cc
+++ /dev/null
@@ -1,330 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/renderer/bluetooth/web_bluetooth_impl.h"
-
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "base/memory/ptr_util.h"
-#include "base/optional.h"
-#include "content/child/mojo/type_converters.h"
-#include "content/child/thread_safe_sender.h"
-#include "content/common/bluetooth/web_bluetooth_device_id.h"
-#include "content/renderer/bluetooth/bluetooth_type_converters.h"
-#include "ipc/ipc_message.h"
-#include "mojo/public/cpp/bindings/array.h"
-#include "services/service_manager/public/cpp/interface_provider.h"
-#include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothDevice.h"
-#include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothDeviceInit.h"
-#include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothRemoteGATTCharacteristic.h"
-#include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothRemoteGATTCharacteristicInit.h"
-#include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothRemoteGATTService.h"
-#include "third_party/WebKit/public/platform/modules/bluetooth/WebRequestDeviceOptions.h"
-
-namespace content {
-
-namespace {
-
-// Blink can't use non-blink mojo enums like blink::mojom::WebBluetoothResult,
-// so we pass it as an int32 across the boundary.
-int32_t ToInt32(blink::mojom::WebBluetoothResult result) {
-  return static_cast<int32_t>(result);
-}
-
-}  // namespace
-
-WebBluetoothImpl::WebBluetoothImpl(
-    service_manager::InterfaceProvider* remote_interfaces)
-    : remote_interfaces_(remote_interfaces), binding_(this) {}
-
-WebBluetoothImpl::~WebBluetoothImpl() {
-}
-
-void WebBluetoothImpl::requestDevice(
-    const blink::WebRequestDeviceOptions& options,
-    blink::WebBluetoothRequestDeviceCallbacks* callbacks) {
-  GetWebBluetoothService().RequestDevice(
-      blink::mojom::WebBluetoothRequestDeviceOptions::From(options),
-      base::Bind(&WebBluetoothImpl::OnRequestDeviceComplete,
-                 base::Unretained(this),
-                 base::Passed(base::WrapUnique(callbacks))));
-}
-
-void WebBluetoothImpl::connect(
-    const blink::WebString& device_id,
-    blink::WebBluetoothDevice* device,
-    blink::WebBluetoothRemoteGATTServerConnectCallbacks* callbacks) {
-  // TODO(crbug.com/495270): After the Bluetooth Tree is implemented, there will
-  // only be one object per device. But for now we replace the previous object.
-  WebBluetoothDeviceId device_id_obj = WebBluetoothDeviceId(device_id.utf8());
-  connected_devices_[device_id_obj] = device;
-
-  GetWebBluetoothService().RemoteServerConnect(
-      std::move(device_id_obj),
-      base::Bind(&WebBluetoothImpl::OnConnectComplete, base::Unretained(this),
-                 base::Passed(base::WrapUnique(callbacks))));
-}
-
-void WebBluetoothImpl::disconnect(const blink::WebString& device_id) {
-  WebBluetoothDeviceId device_id_obj = WebBluetoothDeviceId(device_id.utf8());
-  connected_devices_.erase(device_id_obj);
-
-  GetWebBluetoothService().RemoteServerDisconnect(std::move(device_id_obj));
-}
-
-void WebBluetoothImpl::getPrimaryServices(
-    const blink::WebString& device_id,
-    int32_t quantity,
-    const blink::WebString& services_uuid,
-    blink::WebBluetoothGetPrimaryServicesCallbacks* callbacks) {
-  DCHECK(blink::mojom::IsKnownEnumValue(
-      static_cast<blink::mojom::WebBluetoothGATTQueryQuantity>(quantity)));
-  GetWebBluetoothService().RemoteServerGetPrimaryServices(
-      WebBluetoothDeviceId(device_id.utf8()),
-      static_cast<blink::mojom::WebBluetoothGATTQueryQuantity>(quantity),
-      services_uuid.isEmpty()
-          ? base::nullopt
-          : base::make_optional(device::BluetoothUUID(services_uuid.utf8())),
-      base::Bind(&WebBluetoothImpl::OnGetPrimaryServicesComplete,
-                 base::Unretained(this), device_id,
-                 base::Passed(base::WrapUnique(callbacks))));
-}
-
-void WebBluetoothImpl::getCharacteristics(
-    const blink::WebString& service_instance_id,
-    int32_t quantity,
-    const blink::WebString& characteristics_uuid,
-    blink::WebBluetoothGetCharacteristicsCallbacks* callbacks) {
-  DCHECK(blink::mojom::IsKnownEnumValue(
-      static_cast<blink::mojom::WebBluetoothGATTQueryQuantity>(quantity)));
-  GetWebBluetoothService().RemoteServiceGetCharacteristics(
-      mojo::String::From(service_instance_id),
-      static_cast<blink::mojom::WebBluetoothGATTQueryQuantity>(quantity),
-      characteristics_uuid.isEmpty()
-          ? base::nullopt
-          : base::make_optional(
-                device::BluetoothUUID(characteristics_uuid.utf8())),
-      base::Bind(&WebBluetoothImpl::OnGetCharacteristicsComplete,
-                 base::Unretained(this), service_instance_id,
-                 base::Passed(base::WrapUnique(callbacks))));
-}
-
-void WebBluetoothImpl::readValue(
-    const blink::WebString& characteristic_instance_id,
-    blink::WebBluetoothReadValueCallbacks* callbacks) {
-  GetWebBluetoothService().RemoteCharacteristicReadValue(
-      mojo::String::From(characteristic_instance_id),
-      base::Bind(&WebBluetoothImpl::OnReadValueComplete, base::Unretained(this),
-                 base::Passed(base::WrapUnique(callbacks))));
-}
-
-void WebBluetoothImpl::writeValue(
-    const blink::WebString& characteristic_instance_id,
-    const blink::WebVector<uint8_t>& value,
-    blink::WebBluetoothWriteValueCallbacks* callbacks) {
-  GetWebBluetoothService().RemoteCharacteristicWriteValue(
-      mojo::String::From(characteristic_instance_id),
-      mojo::Array<uint8_t>::From(value),
-      base::Bind(&WebBluetoothImpl::OnWriteValueComplete,
-                 base::Unretained(this), value,
-                 base::Passed(base::WrapUnique(callbacks))));
-}
-
-void WebBluetoothImpl::startNotifications(
-    const blink::WebString& characteristic_instance_id,
-    blink::WebBluetoothNotificationsCallbacks* callbacks) {
-  GetWebBluetoothService().RemoteCharacteristicStartNotifications(
-      mojo::String::From(characteristic_instance_id),
-      base::Bind(&WebBluetoothImpl::OnStartNotificationsComplete,
-                 base::Unretained(this),
-                 base::Passed(base::WrapUnique(callbacks))));
-}
-
-void WebBluetoothImpl::stopNotifications(
-    const blink::WebString& characteristic_instance_id,
-    blink::WebBluetoothNotificationsCallbacks* callbacks) {
-  GetWebBluetoothService().RemoteCharacteristicStopNotifications(
-      mojo::String::From(characteristic_instance_id),
-      base::Bind(&WebBluetoothImpl::OnStopNotificationsComplete,
-                 base::Unretained(this),
-                 base::Passed(base::WrapUnique(callbacks))));
-}
-
-void WebBluetoothImpl::characteristicObjectRemoved(
-    const blink::WebString& characteristic_instance_id,
-    blink::WebBluetoothRemoteGATTCharacteristic* characteristic) {
-  active_characteristics_.erase(characteristic_instance_id.utf8());
-}
-
-void WebBluetoothImpl::registerCharacteristicObject(
-    const blink::WebString& characteristic_instance_id,
-    blink::WebBluetoothRemoteGATTCharacteristic* characteristic) {
-  // TODO(ortuno): After the Bluetooth Tree is implemented, there will
-  // only be one object per characteristic. But for now we replace
-  // the previous object.
-  // https://crbug.com/495270
-  active_characteristics_[characteristic_instance_id.utf8()] = characteristic;
-}
-
-void WebBluetoothImpl::RemoteCharacteristicValueChanged(
-    const std::string& characteristic_instance_id,
-    const std::vector<uint8_t>& value) {
-  // We post a task so that the event is fired after any pending promises have
-  // resolved.
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::Bind(&WebBluetoothImpl::DispatchCharacteristicValueChanged,
-                 base::Unretained(this), characteristic_instance_id, value));
-}
-
-void WebBluetoothImpl::OnRequestDeviceComplete(
-    std::unique_ptr<blink::WebBluetoothRequestDeviceCallbacks> callbacks,
-    const blink::mojom::WebBluetoothResult result,
-    blink::mojom::WebBluetoothDevicePtr device) {
-  if (result == blink::mojom::WebBluetoothResult::SUCCESS) {
-    callbacks->onSuccess(base::MakeUnique<blink::WebBluetoothDeviceInit>(
-        blink::WebString::fromUTF8(device->id.str()),
-        device->name ? blink::WebString::fromUTF8(device->name.value())
-                     : blink::WebString()));
-  } else {
-    callbacks->onError(ToInt32(result));
-  }
-}
-
-void WebBluetoothImpl::GattServerDisconnected(
-    const WebBluetoothDeviceId& device_id) {
-  auto device_iter = connected_devices_.find(device_id);
-  if (device_iter != connected_devices_.end()) {
-    // Remove device from the map before calling dispatchGattServerDisconnected
-    // to avoid removing a device the gattserverdisconnected event handler might
-    // have re-connected.
-    blink::WebBluetoothDevice* device = device_iter->second;
-    connected_devices_.erase(device_iter);
-    device->dispatchGattServerDisconnected();
-  }
-}
-
-void WebBluetoothImpl::OnConnectComplete(
-    std::unique_ptr<blink::WebBluetoothRemoteGATTServerConnectCallbacks>
-        callbacks,
-    blink::mojom::WebBluetoothResult result) {
-  if (result == blink::mojom::WebBluetoothResult::SUCCESS) {
-    callbacks->onSuccess();
-  } else {
-    callbacks->onError(ToInt32(result));
-  }
-}
-
-void WebBluetoothImpl::OnGetPrimaryServicesComplete(
-    const blink::WebString& device_id,
-    std::unique_ptr<blink::WebBluetoothGetPrimaryServicesCallbacks> callbacks,
-    blink::mojom::WebBluetoothResult result,
-    base::Optional<std::vector<blink::mojom::WebBluetoothRemoteGATTServicePtr>>
-        services) {
-  if (result == blink::mojom::WebBluetoothResult::SUCCESS) {
-    DCHECK(services);
-    // TODO(dcheng): This WebVector should use smart pointers.
-    blink::WebVector<blink::WebBluetoothRemoteGATTService*> promise_services(
-        services->size());
-    for (size_t i = 0; i < services->size(); i++) {
-      promise_services[i] = new blink::WebBluetoothRemoteGATTService(
-          blink::WebString::fromUTF8(services.value()[i]->instance_id),
-          blink::WebString::fromUTF8(services.value()[i]->uuid),
-          true /* isPrimary */, device_id);
-    }
-    callbacks->onSuccess(promise_services);
-  } else {
-    callbacks->onError(ToInt32(result));
-  }
-}
-
-void WebBluetoothImpl::OnGetCharacteristicsComplete(
-    const blink::WebString& service_instance_id,
-    std::unique_ptr<blink::WebBluetoothGetCharacteristicsCallbacks> callbacks,
-    blink::mojom::WebBluetoothResult result,
-    base::Optional<
-        std::vector<blink::mojom::WebBluetoothRemoteGATTCharacteristicPtr>>
-        characteristics) {
-  if (result == blink::mojom::WebBluetoothResult::SUCCESS) {
-    DCHECK(characteristics);
-    // TODO(dcheng): This WebVector should use smart pointers.
-    blink::WebVector<blink::WebBluetoothRemoteGATTCharacteristicInit*>
-        promise_characteristics(characteristics->size());
-    for (size_t i = 0; i < characteristics->size(); i++) {
-      promise_characteristics[i] =
-          new blink::WebBluetoothRemoteGATTCharacteristicInit(
-              service_instance_id, blink::WebString::fromUTF8(
-                                       characteristics.value()[i]->instance_id),
-              blink::WebString::fromUTF8(characteristics.value()[i]->uuid),
-              characteristics.value()[i]->properties);
-    }
-    callbacks->onSuccess(promise_characteristics);
-  } else {
-    callbacks->onError(ToInt32(result));
-  }
-}
-
-void WebBluetoothImpl::OnReadValueComplete(
-    std::unique_ptr<blink::WebBluetoothReadValueCallbacks> callbacks,
-    blink::mojom::WebBluetoothResult result,
-    const base::Optional<std::vector<uint8_t>>& value) {
-  if (result == blink::mojom::WebBluetoothResult::SUCCESS) {
-    DCHECK(value);
-    callbacks->onSuccess(value.value());
-  } else {
-    callbacks->onError(ToInt32(result));
-  }
-}
-
-void WebBluetoothImpl::OnWriteValueComplete(
-    const blink::WebVector<uint8_t>& value,
-    std::unique_ptr<blink::WebBluetoothWriteValueCallbacks> callbacks,
-    blink::mojom::WebBluetoothResult result) {
-  if (result == blink::mojom::WebBluetoothResult::SUCCESS) {
-    callbacks->onSuccess(value);
-  } else {
-    callbacks->onError(ToInt32(result));
-  }
-}
-
-void WebBluetoothImpl::OnStartNotificationsComplete(
-    std::unique_ptr<blink::WebBluetoothNotificationsCallbacks> callbacks,
-    blink::mojom::WebBluetoothResult result) {
-  if (result == blink::mojom::WebBluetoothResult::SUCCESS) {
-    callbacks->onSuccess();
-  } else {
-    callbacks->onError(ToInt32(result));
-  }
-}
-
-void WebBluetoothImpl::OnStopNotificationsComplete(
-    std::unique_ptr<blink::WebBluetoothNotificationsCallbacks> callbacks) {
-  callbacks->onSuccess();
-}
-
-void WebBluetoothImpl::DispatchCharacteristicValueChanged(
-    const std::string& characteristic_instance_id,
-    const std::vector<uint8_t>& value) {
-  auto active_iter = active_characteristics_.find(characteristic_instance_id);
-  if (active_iter != active_characteristics_.end()) {
-    active_iter->second->dispatchCharacteristicValueChanged(value);
-  }
-}
-
-blink::mojom::WebBluetoothService& WebBluetoothImpl::GetWebBluetoothService() {
-  if (!web_bluetooth_service_) {
-    remote_interfaces_->GetInterface(
-        mojo::MakeRequest(&web_bluetooth_service_));
-    // Create an associated interface ptr and pass it to the WebBluetoothService
-    // so that it can send us events without us prompting.
-    blink::mojom::WebBluetoothServiceClientAssociatedPtrInfo ptr_info;
-    binding_.Bind(&ptr_info, web_bluetooth_service_.associated_group());
-    web_bluetooth_service_->SetClient(std::move(ptr_info));
-  }
-  return *web_bluetooth_service_;
-}
-
-}  // namespace content
diff --git a/content/renderer/bluetooth/web_bluetooth_impl.h b/content/renderer/bluetooth/web_bluetooth_impl.h
deleted file mode 100644
index 431a4e4a..0000000
--- a/content/renderer/bluetooth/web_bluetooth_impl.h
+++ /dev/null
@@ -1,161 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_BLUETOOTH_WEB_BLUETOOTH_IMPL_H_
-#define CONTENT_RENDERER_BLUETOOTH_WEB_BLUETOOTH_IMPL_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-#include <unordered_map>
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "content/common/bluetooth/web_bluetooth_device_id.h"
-#include "content/common/content_export.h"
-#include "mojo/public/cpp/bindings/associated_binding.h"
-#include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetooth.h"
-#include "third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom.h"
-
-namespace blink {
-class WebBluetoothRemoteGATTCharacteristic;
-}
-
-namespace service_manager {
-class InterfaceProvider;
-}
-
-namespace content {
-
-class BluetoothDispatcher;
-
-// Implementation of blink::WebBluetooth. Passes calls through to the thread
-// specific BluetoothDispatcher.
-class CONTENT_EXPORT WebBluetoothImpl
-    : NON_EXPORTED_BASE(public blink::mojom::WebBluetoothServiceClient),
-      NON_EXPORTED_BASE(public blink::WebBluetooth) {
- public:
-  WebBluetoothImpl(service_manager::InterfaceProvider* remote_interfaces);
-  ~WebBluetoothImpl() override;
-
-  // blink::WebBluetooth interface:
-  void requestDevice(
-      const blink::WebRequestDeviceOptions& options,
-      blink::WebBluetoothRequestDeviceCallbacks* callbacks) override;
-  void connect(
-      const blink::WebString& device_id,
-      blink::WebBluetoothDevice* device,
-      blink::WebBluetoothRemoteGATTServerConnectCallbacks* callbacks) override;
-  void disconnect(const blink::WebString& device_id) override;
-  void getPrimaryServices(
-      const blink::WebString& device_id,
-      int32_t quantity /* Corresponds to WebBluetoothGATTQueryQuantity in
-                        web_bluetooth.mojom */,
-      const blink::WebString& services_uuid,
-      blink::WebBluetoothGetPrimaryServicesCallbacks* callbacks) override;
-  void getCharacteristics(
-      const blink::WebString& service_instance_id,
-      int32_t quantity /* Corresponds to WebBluetoothGATTQueryQuantity in
-                        web_bluetooth.mojom */,
-      const blink::WebString& characteristics_uuid,
-      blink::WebBluetoothGetCharacteristicsCallbacks* callbacks) override;
-  void readValue(const blink::WebString& characteristic_instance_id,
-                 blink::WebBluetoothReadValueCallbacks* callbacks) override;
-  void writeValue(const blink::WebString& characteristic_instance_id,
-                  const blink::WebVector<uint8_t>& value,
-                  blink::WebBluetoothWriteValueCallbacks*) override;
-  void startNotifications(
-      const blink::WebString& characteristic_instance_id,
-      blink::WebBluetoothNotificationsCallbacks*) override;
-  void stopNotifications(
-      const blink::WebString& characteristic_instance_id,
-      blink::WebBluetoothNotificationsCallbacks*) override;
-  void characteristicObjectRemoved(
-      const blink::WebString& characteristic_instance_id,
-      blink::WebBluetoothRemoteGATTCharacteristic* characteristic) override;
-  void registerCharacteristicObject(
-      const blink::WebString& characteristic_instance_id,
-      blink::WebBluetoothRemoteGATTCharacteristic* characteristic) override;
-
- private:
-  struct GetCharacteristicsCallback;
-  // WebBluetoothServiceClient methods:
-  void RemoteCharacteristicValueChanged(
-      const std::string& characteristic_instance_id,
-      const std::vector<uint8_t>& value) override;
-  void GattServerDisconnected(const WebBluetoothDeviceId& device_id) override;
-
-  // Callbacks for WebBluetoothService calls:
-  void OnRequestDeviceComplete(
-      std::unique_ptr<blink::WebBluetoothRequestDeviceCallbacks> callbacks,
-      const blink::mojom::WebBluetoothResult result,
-      blink::mojom::WebBluetoothDevicePtr device);
-  void OnConnectComplete(
-      std::unique_ptr<blink::WebBluetoothRemoteGATTServerConnectCallbacks>
-          callbacks,
-      blink::mojom::WebBluetoothResult result);
-  void OnGetPrimaryServicesComplete(
-      const blink::WebString& device_id,
-      std::unique_ptr<blink::WebBluetoothGetPrimaryServicesCallbacks> callbacks,
-      blink::mojom::WebBluetoothResult result,
-      base::Optional<
-          std::vector<blink::mojom::WebBluetoothRemoteGATTServicePtr>>
-          services);
-  void OnGetCharacteristicsComplete(
-      const blink::WebString& service_instance_id,
-      std::unique_ptr<blink::WebBluetoothGetCharacteristicsCallbacks> callbacks,
-      blink::mojom::WebBluetoothResult result,
-      base::Optional<
-          std::vector<blink::mojom::WebBluetoothRemoteGATTCharacteristicPtr>>
-          characteristics);
-  void OnReadValueComplete(
-      std::unique_ptr<blink::WebBluetoothReadValueCallbacks> callbacks,
-      blink::mojom::WebBluetoothResult result,
-      const base::Optional<std::vector<uint8_t>>& value);
-  void OnWriteValueComplete(
-      const blink::WebVector<uint8_t>& value,
-      std::unique_ptr<blink::WebBluetoothWriteValueCallbacks> callbacks,
-      blink::mojom::WebBluetoothResult result);
-  void OnStartNotificationsComplete(
-      std::unique_ptr<blink::WebBluetoothNotificationsCallbacks> callbacks,
-      blink::mojom::WebBluetoothResult result);
-  void OnStopNotificationsComplete(
-      std::unique_ptr<blink::WebBluetoothNotificationsCallbacks> callbacks);
-
-  void DispatchCharacteristicValueChanged(
-      const std::string& characteristic_instance_id,
-      const std::vector<uint8_t>& value);
-
-  blink::mojom::WebBluetoothService& GetWebBluetoothService();
-  service_manager::InterfaceProvider* const remote_interfaces_;
-  blink::mojom::WebBluetoothServicePtr web_bluetooth_service_;
-
-  // Map of characteristic_instance_ids to
-  // WebBluetoothRemoteGATTCharacteristics. When characteristicObjectRemoved is
-  // called the characteristic should be removed from the map.
-  // Keeps track of what characteristics have listeners.
-  std::unordered_map<std::string, blink::WebBluetoothRemoteGATTCharacteristic*>
-      active_characteristics_;
-
-  // Map of device_ids to WebBluetoothDevices. Added in connect() and removed in
-  // disconnect(). This means a device may not actually be connected while in
-  // this map, but that it will definitely be removed when the page navigates.
-  std::unordered_map<WebBluetoothDeviceId,
-                     blink::WebBluetoothDevice*,
-                     WebBluetoothDeviceIdHash>
-      connected_devices_;
-
-  // Binding associated with |web_bluetooth_service_|.
-  mojo::AssociatedBinding<blink::mojom::WebBluetoothServiceClient> binding_;
-
-  DISALLOW_COPY_AND_ASSIGN(WebBluetoothImpl);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_BLUETOOTH_WEB_BLUETOOTH_IMPL_H_
diff --git a/content/renderer/media/cdm/ppapi_decryptor.cc b/content/renderer/media/cdm/ppapi_decryptor.cc
index c22887a..835907cb 100644
--- a/content/renderer/media/cdm/ppapi_decryptor.cc
+++ b/content/renderer/media/cdm/ppapi_decryptor.cc
@@ -123,7 +123,7 @@
 }
 
 void PpapiDecryptor::CreateSessionAndGenerateRequest(
-    SessionType session_type,
+    media::CdmSessionType session_type,
     media::EmeInitDataType init_data_type,
     const std::vector<uint8_t>& init_data,
     std::unique_ptr<media::NewSessionCdmPromise> promise) {
@@ -141,7 +141,7 @@
 }
 
 void PpapiDecryptor::LoadSession(
-    SessionType session_type,
+    media::CdmSessionType session_type,
     const std::string& session_id,
     std::unique_ptr<media::NewSessionCdmPromise> promise) {
   DVLOG(2) << __func__;
diff --git a/content/renderer/media/cdm/ppapi_decryptor.h b/content/renderer/media/cdm/ppapi_decryptor.h
index d530f5d1..95137fef 100644
--- a/content/renderer/media/cdm/ppapi_decryptor.h
+++ b/content/renderer/media/cdm/ppapi_decryptor.h
@@ -53,12 +53,12 @@
       const std::vector<uint8_t>& certificate,
       std::unique_ptr<media::SimpleCdmPromise> promise) override;
   void CreateSessionAndGenerateRequest(
-      SessionType session_type,
+      media::CdmSessionType session_type,
       media::EmeInitDataType init_data_type,
       const std::vector<uint8_t>& init_data,
       std::unique_ptr<media::NewSessionCdmPromise> promise) override;
   void LoadSession(
-      SessionType session_type,
+      media::CdmSessionType session_type,
       const std::string& session_id,
       std::unique_ptr<media::NewSessionCdmPromise> promise) override;
   void UpdateSession(const std::string& session_id,
diff --git a/content/renderer/pepper/content_decryptor_delegate.cc b/content/renderer/pepper/content_decryptor_delegate.cc
index db8fb6b9..aca96613 100644
--- a/content/renderer/pepper/content_decryptor_delegate.cc
+++ b/content/renderer/pepper/content_decryptor_delegate.cc
@@ -37,8 +37,9 @@
 #include "ui/gfx/geometry/rect.h"
 
 using media::CdmPromise;
-using media::Decryptor;
+using media::CdmSessionType;
 using media::ContentDecryptionModule;
+using media::Decryptor;
 using media::NewSessionCdmPromise;
 using media::SimpleCdmPromise;
 using ppapi::ArrayBufferVar;
@@ -272,14 +273,13 @@
   }
 }
 
-PP_SessionType MediaSessionTypeToPpSessionType(
-    ContentDecryptionModule::SessionType session_type) {
+PP_SessionType MediaSessionTypeToPpSessionType(CdmSessionType session_type) {
   switch (session_type) {
-    case ContentDecryptionModule::TEMPORARY_SESSION:
+    case CdmSessionType::TEMPORARY_SESSION:
       return PP_SESSIONTYPE_TEMPORARY;
-    case ContentDecryptionModule::PERSISTENT_LICENSE_SESSION:
+    case CdmSessionType::PERSISTENT_LICENSE_SESSION:
       return PP_SESSIONTYPE_PERSISTENT_LICENSE;
-    case ContentDecryptionModule::PERSISTENT_RELEASE_MESSAGE_SESSION:
+    case CdmSessionType::PERSISTENT_RELEASE_MESSAGE_SESSION:
       return PP_SESSIONTYPE_PERSISTENT_RELEASE;
     default:
       NOTREACHED();
@@ -444,7 +444,7 @@
 }
 
 void ContentDecryptorDelegate::CreateSessionAndGenerateRequest(
-    ContentDecryptionModule::SessionType session_type,
+    CdmSessionType session_type,
     media::EmeInitDataType init_data_type,
     const std::vector<uint8_t>& init_data,
     std::unique_ptr<NewSessionCdmPromise> promise) {
@@ -458,7 +458,7 @@
 }
 
 void ContentDecryptorDelegate::LoadSession(
-    ContentDecryptionModule::SessionType session_type,
+    CdmSessionType session_type,
     const std::string& session_id,
     std::unique_ptr<NewSessionCdmPromise> promise) {
   uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise));
diff --git a/content/renderer/pepper/content_decryptor_delegate.h b/content/renderer/pepper/content_decryptor_delegate.h
index 0482a940..695aa2e 100644
--- a/content/renderer/pepper/content_decryptor_delegate.h
+++ b/content/renderer/pepper/content_decryptor_delegate.h
@@ -68,11 +68,11 @@
   void SetServerCertificate(const std::vector<uint8_t>& certificate,
                             std::unique_ptr<media::SimpleCdmPromise> promise);
   void CreateSessionAndGenerateRequest(
-      media::ContentDecryptionModule::SessionType session_type,
+      media::CdmSessionType session_type,
       media::EmeInitDataType init_data_type,
       const std::vector<uint8_t>& init_data,
       std::unique_ptr<media::NewSessionCdmPromise> promise);
-  void LoadSession(media::ContentDecryptionModule::SessionType session_type,
+  void LoadSession(media::CdmSessionType session_type,
                    const std::string& session_id,
                    std::unique_ptr<media::NewSessionCdmPromise> promise);
   void UpdateSession(const std::string& session_id,
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 00f49857..b843dd8 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -91,7 +91,6 @@
 #include "content/public/renderer/render_frame_observer.h"
 #include "content/public/renderer/renderer_ppapi_host.h"
 #include "content/renderer/accessibility/render_accessibility_impl.h"
-#include "content/renderer/bluetooth/web_bluetooth_impl.h"
 #include "content/renderer/browser_plugin/browser_plugin.h"
 #include "content/renderer/browser_plugin/browser_plugin_manager.h"
 #include "content/renderer/child_frame_compositing_helper.h"
@@ -4679,12 +4678,6 @@
       user_gesture));
 }
 
-blink::WebBluetooth* RenderFrameImpl::bluetooth() {
-  if (!bluetooth_.get())
-    bluetooth_.reset(new WebBluetoothImpl(GetRemoteInterfaces()));
-  return bluetooth_.get();
-}
-
 void RenderFrameImpl::didSerializeDataForFrame(
     const WebCString& data,
     WebFrameSerializerClient::FrameSerializationStatus status) {
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 6ae3cba3..415f386 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -643,7 +643,6 @@
                                const blink::WebString& title) override;
   void unregisterProtocolHandler(const blink::WebString& scheme,
                                  const blink::WebURL& url) override;
-  blink::WebBluetooth* bluetooth() override;
   void checkIfAudioSinkExistsAndIsAuthorized(
       const blink::WebString& sink_id,
       const blink::WebSecurityOrigin& security_origin,
@@ -1289,8 +1288,6 @@
   // AccessibilityModeOff.
   RenderAccessibilityImpl* render_accessibility_;
 
-  std::unique_ptr<blink::WebBluetooth> bluetooth_;
-
   // Manages play, pause notifications for WebMediaPlayer implementations; its
   // lifetime is tied to the RenderFrame via the RenderFrameObserver interface.
   media::RendererWebMediaPlayerDelegate* media_player_delegate_;
diff --git a/device/usb/usb_ids.h b/device/usb/usb_ids.h
index c69aca4..7f8dbdd 100644
--- a/device/usb/usb_ids.h
+++ b/device/usb/usb_ids.h
@@ -13,14 +13,14 @@
 namespace device {
 
 struct UsbProduct {
-  const uint16_t id;
+  uint16_t id;
   const char* name;
 };
 
 struct UsbVendor {
-  const uint16_t id;
+  uint16_t id;
   const char* name;
-  const size_t product_size;
+  size_t product_size;
   const UsbProduct* products;
 };
 
diff --git a/device/vr/android/gvr/gvr_delegate.h b/device/vr/android/gvr/gvr_delegate.h
index 28470950..c5e22a0 100644
--- a/device/vr/android/gvr/gvr_delegate.h
+++ b/device/vr/android/gvr/gvr_delegate.h
@@ -7,7 +7,7 @@
 
 #include "device/vr/android/gvr/gvr_device_provider.h"
 #include "device/vr/vr_export.h"
-#include "third_party/gvr-android-sdk/src/ndk/include/vr/gvr/capi/include/gvr_types.h"
+#include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_types.h"
 
 namespace gvr {
 class GvrApi;
diff --git a/device/vr/android/gvr/gvr_device.cc b/device/vr/android/gvr/gvr_device.cc
index 426b8cf..9dc6b39 100644
--- a/device/vr/android/gvr/gvr_device.cc
+++ b/device/vr/android/gvr/gvr_device.cc
@@ -12,8 +12,8 @@
 #include "device/vr/android/gvr/gvr_delegate.h"
 #include "device/vr/android/gvr/gvr_device_provider.h"
 #include "device/vr/vr_device_manager.h"
-#include "third_party/gvr-android-sdk/src/ndk/include/vr/gvr/capi/include/gvr.h"
-#include "third_party/gvr-android-sdk/src/ndk/include/vr/gvr/capi/include/gvr_types.h"
+#include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr.h"
+#include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_types.h"
 #include "ui/gfx/transform.h"
 #include "ui/gfx/transform_util.h"
 
diff --git a/device/vr/android/gvr/gvr_device_provider.cc b/device/vr/android/gvr/gvr_device_provider.cc
index 07726ad..26d1c59 100644
--- a/device/vr/android/gvr/gvr_device_provider.cc
+++ b/device/vr/android/gvr/gvr_device_provider.cc
@@ -16,9 +16,9 @@
 #include "device/vr/vr_device.h"
 #include "device/vr/vr_device_manager.h"
 #include "device/vr/vr_service.mojom.h"
-#include "third_party/gvr-android-sdk/src/ndk/include/vr/gvr/capi/include/gvr.h"
-#include "third_party/gvr-android-sdk/src/ndk/include/vr/gvr/capi/include/gvr_controller.h"
-#include "third_party/gvr-android-sdk/src/ndk/include/vr/gvr/capi/include/gvr_types.h"
+#include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr.h"
+#include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_controller.h"
+#include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_types.h"
 
 using base::android::AttachCurrentThread;
 using base::android::GetApplicationContext;
diff --git a/device/vr/android/gvr/gvr_gamepad_data_fetcher.h b/device/vr/android/gvr/gvr_gamepad_data_fetcher.h
index 65e0d1f..5b105c42 100644
--- a/device/vr/android/gvr/gvr_gamepad_data_fetcher.h
+++ b/device/vr/android/gvr/gvr_gamepad_data_fetcher.h
@@ -8,8 +8,8 @@
 #include <string>
 
 #include "device/gamepad/gamepad_data_fetcher.h"
-#include "third_party/gvr-android-sdk/src/ndk/include/vr/gvr/capi/include/gvr_controller.h"
-#include "third_party/gvr-android-sdk/src/ndk/include/vr/gvr/capi/include/gvr_types.h"
+#include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_controller.h"
+#include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_types.h"
 
 namespace device {
 
diff --git a/extensions/common/csp_validator.cc b/extensions/common/csp_validator.cc
index 37d1009..1dc9128 100644
--- a/extensions/common/csp_validator.cc
+++ b/extensions/common/csp_validator.cc
@@ -6,12 +6,16 @@
 
 #include <stddef.h>
 
+#include <initializer_list>
 #include <vector>
 
+#include "base/bind.h"
+#include "base/callback.h"
 #include "base/macros.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_tokenizer.h"
 #include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
 #include "content/public/common/url_constants.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/error_utils.h"
@@ -28,11 +32,20 @@
 const char kDefaultSrc[] = "default-src";
 const char kScriptSrc[] = "script-src";
 const char kObjectSrc[] = "object-src";
+const char kFrameSrc[] = "frame-src";
+const char kChildSrc[] = "child-src";
+
+const char kDirectiveSeparator = ';';
+
 const char kPluginTypes[] = "plugin-types";
 
 const char kObjectSrcDefaultDirective[] = "object-src 'self';";
 const char kScriptSrcDefaultDirective[] = "script-src 'self';";
 
+const char kAppSandboxSubframeSrcDefaultDirective[] = "child-src 'self';";
+const char kAppSandboxScriptSrcDefaultDirective[] =
+    "script-src 'self' 'unsafe-inline' 'unsafe-eval';";
+
 const char kSandboxDirectiveName[] = "sandbox";
 const char kAllowSameOriginToken[] = "allow-same-origin";
 const char kAllowTopNavigation[] = "allow-top-navigation";
@@ -54,12 +67,42 @@
   "'sha512-"
 };
 
-struct DirectiveStatus {
-  explicit DirectiveStatus(const char* name)
-      : directive_name(name), seen_in_policy(false) {}
+// Represents the status of a directive in a CSP string.
+//
+// Examples of directive:
+// script source related: scrict-src
+// subframe source related: child-src/frame-src.
+class DirectiveStatus {
+ public:
+  // Subframe related directives can have multiple directive names: "child-src"
+  // or "frame-src".
+  DirectiveStatus(std::initializer_list<const char*> directives)
+      : directive_names_(directives.begin(), directives.end()) {}
 
-  const char* directive_name;
-  bool seen_in_policy;
+  // Returns true if |directive_name| matches this DirectiveStatus.
+  bool Matches(const std::string& directive_name) const {
+    for (const auto& directive : directive_names_) {
+      if (!base::CompareCaseInsensitiveASCII(directive_name, directive))
+        return true;
+    }
+    return false;
+  }
+
+  bool seen_in_policy() const { return seen_in_policy_; }
+  void set_seen_in_policy() { seen_in_policy_ = true; }
+
+  const std::string& name() const {
+    DCHECK(!directive_names_.empty());
+    return directive_names_[0];
+  }
+
+ private:
+  // The CSP directive names this DirectiveStatus cares about.
+  std::vector<std::string> directive_names_;
+  // Whether or not we've seen any directive name that matches |this|.
+  bool seen_in_policy_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(DirectiveStatus);
 };
 
 // Returns whether |url| starts with |scheme_and_separator| and does not have a
@@ -123,12 +166,11 @@
 }
 
 // Checks whether the source is a syntactically valid hash.
-bool IsHashSource(const std::string& source) {
-  size_t hash_end = source.length() - 1;
-  if (source.empty() || source[hash_end] != '\'') {
+bool IsHashSource(base::StringPiece source) {
+  if (source.empty() || source.back() != '\'')
     return false;
-  }
 
+  size_t hash_end = source.length() - 1;
   for (const char* prefix : kHashSourcePrefixes) {
     if (base::StartsWith(source, prefix,
                          base::CompareCase::INSENSITIVE_ASCII)) {
@@ -150,14 +192,13 @@
   return InstallWarning(csp_warning, manifest_keys::kContentSecurityPolicy);
 }
 
-void GetSecureDirectiveValues(const std::string& directive_name,
-                              base::StringTokenizer* tokenizer,
-                              int options,
-                              std::vector<std::string>* sane_csp_parts,
-                              std::vector<InstallWarning>* warnings) {
-  sane_csp_parts->push_back(directive_name);
-  while (tokenizer->GetNext()) {
-    std::string source_literal = tokenizer->token();
+std::string GetSecureDirectiveValues(
+    int options,
+    const std::string& directive_name,
+    const std::vector<base::StringPiece>& directive_values,
+    std::vector<InstallWarning>* warnings) {
+  std::vector<std::string> sane_csp_parts(1, directive_name);
+  for (base::StringPiece source_literal : directive_values) {
     std::string source_lower = base::ToLowerASCII(source_literal);
     bool is_secure_csp_token = false;
 
@@ -190,40 +231,54 @@
     }
 
     if (is_secure_csp_token) {
-      sane_csp_parts->push_back(source_literal);
+      sane_csp_parts.push_back(source_literal.as_string());
     } else if (warnings) {
       warnings->push_back(CSPInstallWarning(ErrorUtils::FormatErrorMessage(
-          manifest_errors::kInvalidCSPInsecureValue, source_literal,
+          manifest_errors::kInvalidCSPInsecureValue, source_literal.as_string(),
           directive_name)));
     }
   }
   // End of CSP directive that was started at the beginning of this method. If
   // none of the values are secure, the policy will be empty and default to
   // 'none', which is secure.
-  sane_csp_parts->back().push_back(';');
+  sane_csp_parts.back().push_back(kDirectiveSeparator);
+  return base::JoinString(sane_csp_parts, " ");
 }
 
-// Returns true if |directive_name| matches |status.directive_name|.
-bool UpdateStatus(const std::string& directive_name,
-                  base::StringTokenizer* tokenizer,
-                  DirectiveStatus* status,
-                  int options,
-                  std::vector<std::string>* sane_csp_parts,
-                  std::vector<InstallWarning>* warnings) {
-  if (directive_name != status->directive_name)
-    return false;
+// Given a CSP directive-token for app sandbox, returns a secure value of that
+// directive.
+// The directive-token's name is |directive_name| and its values are splitted
+// into |directive_values|.
+std::string GetAppSandboxSecureDirectiveValues(
+    const std::string& directive_name,
+    const std::vector<base::StringPiece>& directive_values,
+    std::vector<InstallWarning>* warnings) {
+  std::vector<std::string> sane_csp_parts(1, directive_name);
+  bool seen_self_or_none = false;
+  for (base::StringPiece source_literal : directive_values) {
+    std::string source_lower = base::ToLowerASCII(source_literal);
 
-  if (!status->seen_in_policy) {
-    status->seen_in_policy = true;
-    GetSecureDirectiveValues(directive_name, tokenizer, options, sane_csp_parts,
-                             warnings);
-  } else {
-    // Don't show any errors for duplicate CSP directives, because it will be
-    // ignored by the CSP parser (http://www.w3.org/TR/CSP2/#policy-parsing).
-    GetSecureDirectiveValues(directive_name, tokenizer, options, sane_csp_parts,
-                             NULL);
+    // Keyword directive sources are surrounded with quotes, e.g. 'self',
+    // 'sha256-...', 'unsafe-eval', 'nonce-...'. These do not specify a remote
+    // host or '*', so keep them and restrict the rest.
+    if (source_lower.size() > 1u && source_lower[0] == '\'' &&
+        source_lower.back() == '\'') {
+      seen_self_or_none |= source_lower == "'none'" || source_lower == "'self'";
+      sane_csp_parts.push_back(source_lower);
+    } else if (warnings) {
+      warnings->push_back(CSPInstallWarning(ErrorUtils::FormatErrorMessage(
+          manifest_errors::kInvalidCSPInsecureValue, source_literal.as_string(),
+          directive_name)));
+    }
   }
-  return true;
+
+  // If we haven't seen any of 'self' or 'none', that means this directive
+  // value isn't secure. Specify 'self' to secure it.
+  if (!seen_self_or_none)
+    sane_csp_parts.push_back("'self'");
+
+  sane_csp_parts.back().push_back(kDirectiveSeparator);
+  return base::JoinString(sane_csp_parts, " ");
 }
 
 // Returns true if the |plugin_type| is one of the fully sandboxed plugin types.
@@ -263,6 +318,212 @@
   return false;
 }
 
+using SecureDirectiveValueFunction = base::Callback<std::string(
+    const std::string& directive_name,
+    const std::vector<base::StringPiece>& directive_values,
+    std::vector<InstallWarning>* warnings)>;
+
+// Represents a token in CSP string.
+// Tokens are delimited by ";" CSP string.
+class CSPDirectiveToken {
+ public:
+  explicit CSPDirectiveToken(base::StringPiece directive_token)
+      : directive_token_(directive_token),
+        parsed_(false),
+        tokenizer_(directive_token.begin(), directive_token.end(), " \t\r\n") {
+    is_empty_ = !tokenizer_.GetNext();
+    if (!is_empty_)
+      directive_name_ = tokenizer_.token();
+  }
+
+  // Returns true if this token affects |status|. In that case, the token's
+  // directive values are secured by |secure_function|.
+  bool MatchAndUpdateStatus(DirectiveStatus* status,
+                            const SecureDirectiveValueFunction& secure_function,
+                            std::vector<InstallWarning>* warnings) {
+    if (is_empty_ || !status->Matches(directive_name_))
+      return false;
+
+    EnsureTokenPartsParsed();
+
+    bool is_duplicate_directive = status->seen_in_policy();
+    status->set_seen_in_policy();
+
+    secure_value_ = secure_function.Run(
+        directive_name_, directive_values_,
+        // Don't show any errors for duplicate CSP directives, because it will
+        // be ignored by the CSP parser
+        // (http://www.w3.org/TR/CSP2/#policy-parsing). Therefore, set warnings
+        // param to nullptr.
+        is_duplicate_directive ? nullptr : warnings);
+    return true;
+  }
+
+  std::string ToString() {
+    if (secure_value_)
+      return secure_value_.value();
+    // This token didn't require modification.
+    return base::StringPrintf("%s%c", directive_token_.as_string().c_str(),
+                              kDirectiveSeparator);
+  }
+
+ private:
+  void EnsureTokenPartsParsed() {
+    if (!parsed_) {
+      while (tokenizer_.GetNext())
+        directive_values_.push_back(tokenizer_.token_piece());
+      parsed_ = true;
+    }
+  }
+
+  base::StringPiece directive_token_;
+  std::string directive_name_;
+  std::vector<base::StringPiece> directive_values_;
+
+  base::Optional<std::string> secure_value_;
+
+  bool is_empty_;
+  bool parsed_;
+  base::CStringTokenizer tokenizer_;
+
+  DISALLOW_COPY_AND_ASSIGN(CSPDirectiveToken);
+};
+
+// Class responsible for parsing a given CSP string |policy|, and enforcing
+// secure directive-tokens within the policy.
+//
+// If a CSP directive's value is not secure, this class will use secure
+// values (via |secure_function|). If a CSP directive-token is not present and
+// as a result will fallback to default (possibly non-secure), this class
+// will use default secure values (via GetDefaultCSPValue).
+class CSPEnforcer {
+ public:
+  CSPEnforcer(bool show_missing_csp_warnings,
+              const SecureDirectiveValueFunction& secure_function)
+      : show_missing_csp_warnings_(show_missing_csp_warnings),
+        secure_function_(secure_function) {}
+  virtual ~CSPEnforcer() {}
+
+  // Returns the enforced CSP.
+  // Emits warnings in |warnings| for insecure directive values. If
+  // |show_missing_csp_warnings_| is true, these will also include missing CSP
+  // directive warnings.
+  std::string Enforce(const std::string& policy,
+                      std::vector<InstallWarning>* warnings);
+
+ protected:
+  virtual std::string GetDefaultCSPValue(const DirectiveStatus& status) = 0;
+
+  // List of directives we care about.
+  std::vector<std::unique_ptr<DirectiveStatus>> directives_;
+
+ private:
+  const bool show_missing_csp_warnings_;
+  const SecureDirectiveValueFunction secure_function_;
+
+  DISALLOW_COPY_AND_ASSIGN(CSPEnforcer);
+};
+
+std::string CSPEnforcer::Enforce(const std::string& policy,
+                                 std::vector<InstallWarning>* warnings) {
+  DCHECK(!directives_.empty());
+  std::vector<std::string> enforced_csp_parts;
+
+  // If any directive that we care about isn't explicitly listed in |policy|,
+  // "default-src" fallback is used.
+  DirectiveStatus default_src_status({kDefaultSrc});
+  std::vector<InstallWarning> default_src_csp_warnings;
+
+  for (const base::StringPiece& directive_token : base::SplitStringPiece(
+           policy, ";", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
+    CSPDirectiveToken csp_directive_token(directive_token);
+    bool matches_enforcing_directive = false;
+    for (const std::unique_ptr<DirectiveStatus>& status : directives_) {
+      if (csp_directive_token.MatchAndUpdateStatus(
+              status.get(), secure_function_, warnings)) {
+        matches_enforcing_directive = true;
+        break;
+      }
+    }
+    if (!matches_enforcing_directive) {
+      csp_directive_token.MatchAndUpdateStatus(
+          &default_src_status, secure_function_, &default_src_csp_warnings);
+    }
+
+    enforced_csp_parts.push_back(csp_directive_token.ToString());
+  }
+
+  if (default_src_status.seen_in_policy()) {
+    for (const std::unique_ptr<DirectiveStatus>& status : directives_) {
+      if (!status->seen_in_policy()) {
+        // This |status| falls back to "default-src". So warnings from
+        // "default-src" will apply.
+        if (warnings) {
+          warnings->insert(warnings->end(), default_src_csp_warnings.begin(),
+                           default_src_csp_warnings.end());
+        }
+        break;
+      }
+    }
+  } else {
+    // Did not see "default-src".
+    // Make sure we cover all sources from |directives_|.
+    for (const std::unique_ptr<DirectiveStatus>& status : directives_) {
+      if (status->seen_in_policy())  // Already covered.
+        continue;
+      enforced_csp_parts.push_back(GetDefaultCSPValue(*status));
+
+      if (warnings && show_missing_csp_warnings_) {
+        warnings->push_back(CSPInstallWarning(ErrorUtils::FormatErrorMessage(
+            manifest_errors::kInvalidCSPMissingSecureSrc, status->name())));
+      }
+    }
+  }
+
+  return base::JoinString(enforced_csp_parts, " ");
+}
+
+class ExtensionCSPEnforcer : public CSPEnforcer {
+ public:
+  ExtensionCSPEnforcer(bool allow_insecure_object_src, int options)
+      : CSPEnforcer(true, base::Bind(&GetSecureDirectiveValues, options)) {
+    directives_.emplace_back(new DirectiveStatus({kScriptSrc}));
+    if (!allow_insecure_object_src)
+      directives_.emplace_back(new DirectiveStatus({kObjectSrc}));
+  }
+
+ protected:
+  std::string GetDefaultCSPValue(const DirectiveStatus& status) override {
+    if (status.Matches(kObjectSrc))
+      return kObjectSrcDefaultDirective;
+    DCHECK(status.Matches(kScriptSrc));
+    return kScriptSrcDefaultDirective;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ExtensionCSPEnforcer);
+};
+
+class AppSandboxPageCSPEnforcer : public CSPEnforcer {
+ public:
+  AppSandboxPageCSPEnforcer()
+      : CSPEnforcer(false, base::Bind(&GetAppSandboxSecureDirectiveValues)) {
+    directives_.emplace_back(new DirectiveStatus({kChildSrc, kFrameSrc}));
+    directives_.emplace_back(new DirectiveStatus({kScriptSrc}));
+  }
+
+ protected:
+  std::string GetDefaultCSPValue(const DirectiveStatus& status) override {
+    if (status.Matches(kChildSrc))
+      return kAppSandboxSubframeSrcDefaultDirective;
+    DCHECK(status.Matches(kScriptSrc));
+    return kAppSandboxScriptSrcDefaultDirective;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AppSandboxPageCSPEnforcer);
+};
+
 }  //  namespace
 
 bool ContentSecurityPolicyIsLegal(const std::string& policy) {
@@ -271,7 +532,7 @@
   const char kBadChars[] = {',', '\r', '\n', '\0'};
 
   return policy.find_first_of(kBadChars, 0, arraysize(kBadChars)) ==
-      std::string::npos;
+         std::string::npos;
 }
 
 std::string SanitizeContentSecurityPolicy(
@@ -282,63 +543,17 @@
   std::vector<std::string> directives = base::SplitString(
       policy, ";", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
 
-  DirectiveStatus default_src_status(kDefaultSrc);
-  DirectiveStatus script_src_status(kScriptSrc);
-  DirectiveStatus object_src_status(kObjectSrc);
-
   bool allow_insecure_object_src =
       AllowedToHaveInsecureObjectSrc(options, directives);
 
-  std::vector<std::string> sane_csp_parts;
-  std::vector<InstallWarning> default_src_csp_warnings;
-  for (size_t i = 0; i < directives.size(); ++i) {
-    std::string& input = directives[i];
-    base::StringTokenizer tokenizer(input, " \t\r\n");
-    if (!tokenizer.GetNext())
-      continue;
+  ExtensionCSPEnforcer csp_enforcer(allow_insecure_object_src, options);
+  return csp_enforcer.Enforce(policy, warnings);
+}
 
-    std::string directive_name = base::ToLowerASCII(tokenizer.token_piece());
-    if (UpdateStatus(directive_name, &tokenizer, &default_src_status, options,
-                     &sane_csp_parts, &default_src_csp_warnings))
-      continue;
-    if (UpdateStatus(directive_name, &tokenizer, &script_src_status, options,
-                     &sane_csp_parts, warnings))
-      continue;
-    if (!allow_insecure_object_src &&
-        UpdateStatus(directive_name, &tokenizer, &object_src_status, options,
-                     &sane_csp_parts, warnings))
-      continue;
-
-    // Pass the other CSP directives as-is without further validation.
-    sane_csp_parts.push_back(input + ";");
-  }
-
-  if (default_src_status.seen_in_policy) {
-    if (!script_src_status.seen_in_policy ||
-        !object_src_status.seen_in_policy) {
-      // Insecure values in default-src are only relevant if either script-src
-      // or object-src is omitted.
-      if (warnings)
-        warnings->insert(warnings->end(),
-                         default_src_csp_warnings.begin(),
-                         default_src_csp_warnings.end());
-    }
-  } else {
-    if (!script_src_status.seen_in_policy) {
-      sane_csp_parts.push_back(kScriptSrcDefaultDirective);
-      if (warnings)
-        warnings->push_back(CSPInstallWarning(ErrorUtils::FormatErrorMessage(
-            manifest_errors::kInvalidCSPMissingSecureSrc, kScriptSrc)));
-    }
-    if (!object_src_status.seen_in_policy && !allow_insecure_object_src) {
-      sane_csp_parts.push_back(kObjectSrcDefaultDirective);
-      if (warnings)
-        warnings->push_back(CSPInstallWarning(ErrorUtils::FormatErrorMessage(
-            manifest_errors::kInvalidCSPMissingSecureSrc, kObjectSrc)));
-    }
-  }
-
-  return base::JoinString(sane_csp_parts, " ");
+std::string GetEffectiveSandoxedPageCSP(const std::string& policy,
+                                        std::vector<InstallWarning>* warnings) {
+  AppSandboxPageCSPEnforcer csp_enforcer;
+  return csp_enforcer.Enforce(policy, warnings);
 }
 
 bool ContentSecurityPolicyIsSandboxed(
diff --git a/extensions/common/csp_validator.h b/extensions/common/csp_validator.h
index 93676b0..e4d1cb9 100644
--- a/extensions/common/csp_validator.h
+++ b/extensions/common/csp_validator.h
@@ -51,6 +51,18 @@
     int options,
     std::vector<InstallWarning>* warnings);
 
+// Given the Content Security Policy of an app sandbox page, returns the
+// effective CSP for that sandbox page.
+//
+// The effective policy restricts the page from loading external web content
+// (frames and scripts) within the page. This is done through adding 'self'
+// directive source to relevant CSP directive names.
+//
+// If |warnings| is not nullptr, any validation errors are appended to
+// |warnings|.
+std::string GetEffectiveSandoxedPageCSP(const std::string& policy,
+                                        std::vector<InstallWarning>* warnings);
+
 // Checks whether the given |policy| enforces a unique origin sandbox as
 // defined by http://www.whatwg.org/specs/web-apps/current-work/multipage/
 // the-iframe-element.html#attr-iframe-sandbox. The policy must have the
diff --git a/extensions/common/csp_validator_unittest.cc b/extensions/common/csp_validator_unittest.cc
index bb85ea5f4..da16e6b 100644
--- a/extensions/common/csp_validator_unittest.cc
+++ b/extensions/common/csp_validator_unittest.cc
@@ -4,6 +4,7 @@
 
 #include <stddef.h>
 
+#include "base/strings/string_split.h"
 #include "extensions/common/csp_validator.h"
 #include "extensions/common/error_utils.h"
 #include "extensions/common/install_warning.h"
@@ -11,6 +12,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 using extensions::csp_validator::ContentSecurityPolicyIsLegal;
+using extensions::csp_validator::GetEffectiveSandoxedPageCSP;
 using extensions::csp_validator::SanitizeContentSecurityPolicy;
 using extensions::csp_validator::ContentSecurityPolicyIsSandboxed;
 using extensions::csp_validator::OPTIONS_NONE;
@@ -33,80 +35,98 @@
       extensions::manifest_errors::kInvalidCSPMissingSecureSrc, directive);
 }
 
-testing::AssertionResult CheckSanitizeCSP(
-    const std::string& policy,
-    int options,
+bool CSPEquals(const std::string& csp1, const std::string& csp2) {
+  std::vector<std::string> csp1_parts = base::SplitString(
+      csp1, ";", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+  std::sort(csp1_parts.begin(), csp1_parts.end());
+  std::vector<std::string> csp2_parts = base::SplitString(
+      csp2, ";", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+  std::sort(csp2_parts.begin(), csp2_parts.end());
+  return csp1_parts == csp2_parts;
+}
+
+struct SanitizedCSPResult {
+  std::string csp;
+  std::vector<InstallWarning> warnings;
+};
+
+SanitizedCSPResult SanitizeCSP(const std::string& policy, int options) {
+  SanitizedCSPResult result;
+  result.csp = SanitizeContentSecurityPolicy(policy, options, &result.warnings);
+  return result;
+}
+
+SanitizedCSPResult SanitizeSandboxPageCSP(const std::string& policy) {
+  SanitizedCSPResult result;
+  result.csp = GetEffectiveSandoxedPageCSP(policy, &result.warnings);
+  return result;
+}
+
+testing::AssertionResult CheckCSP(
+    const SanitizedCSPResult& actual,
     const std::string& expected_csp,
     const std::vector<std::string>& expected_warnings) {
-  std::vector<InstallWarning> actual_warnings;
-  std::string actual_csp = SanitizeContentSecurityPolicy(policy,
-                                                         options,
-                                                         &actual_warnings);
-  if (actual_csp != expected_csp)
+  if (!CSPEquals(expected_csp, actual.csp)) {
     return testing::AssertionFailure()
-        << "SanitizeContentSecurityPolicy returned an unexpected CSP.\n"
-        << "Expected CSP: " << expected_csp << "\n"
-        << "  Actual CSP: " << actual_csp;
+           << "SanitizeContentSecurityPolicy returned an unexpected CSP.\n"
+           << "Expected CSP: " << expected_csp << "\n"
+           << "  Actual CSP: " << actual.csp;
+  }
 
-  if (expected_warnings.size() != actual_warnings.size()) {
+  if (expected_warnings.size() != actual.warnings.size()) {
     testing::Message msg;
-    msg << "Expected " << expected_warnings.size()
-        << " warnings, but got " << actual_warnings.size();
-    for (size_t i = 0; i < actual_warnings.size(); ++i)
-      msg << "\nWarning " << i << " " << actual_warnings[i].message;
+    msg << "Expected " << expected_warnings.size() << " warnings, but got "
+        << actual.warnings.size();
+    for (size_t i = 0; i < actual.warnings.size(); ++i)
+      msg << "\nWarning " << i << " " << actual.warnings[i].message;
     return testing::AssertionFailure() << msg;
   }
 
   for (size_t i = 0; i < expected_warnings.size(); ++i) {
-    if (expected_warnings[i] != actual_warnings[i].message)
+    if (expected_warnings[i] != actual.warnings[i].message)
       return testing::AssertionFailure()
-          << "Unexpected warning from SanitizeContentSecurityPolicy.\n"
-          << "Expected warning[" << i << "]: " << expected_warnings[i]
-          << "  Actual warning[" << i << "]: " << actual_warnings[i].message;
+             << "Unexpected warning from SanitizeContentSecurityPolicy.\n"
+             << "Expected warning[" << i << "]: " << expected_warnings[i]
+             << "  Actual warning[" << i << "]: " << actual.warnings[i].message;
   }
   return testing::AssertionSuccess();
 }
 
-testing::AssertionResult CheckSanitizeCSP(const std::string& policy,
-                                          int options) {
-  return CheckSanitizeCSP(policy, options, policy, std::vector<std::string>());
+testing::AssertionResult CheckCSP(const SanitizedCSPResult& actual) {
+  return CheckCSP(actual, actual.csp, std::vector<std::string>());
 }
 
-testing::AssertionResult CheckSanitizeCSP(const std::string& policy,
-                                          int options,
-                                          const std::string& expected_csp) {
+testing::AssertionResult CheckCSP(const SanitizedCSPResult& actual,
+                                  const std::string& expected_csp) {
   std::vector<std::string> expected_warnings;
-  return CheckSanitizeCSP(policy, options, expected_csp, expected_warnings);
+  return CheckCSP(actual, expected_csp, expected_warnings);
 }
 
-testing::AssertionResult CheckSanitizeCSP(const std::string& policy,
-                                          int options,
-                                          const std::string& expected_csp,
-                                          const std::string& warning1) {
+testing::AssertionResult CheckCSP(const SanitizedCSPResult& actual,
+                                  const std::string& expected_csp,
+                                  const std::string& warning1) {
   std::vector<std::string> expected_warnings(1, warning1);
-  return CheckSanitizeCSP(policy, options, expected_csp, expected_warnings);
+  return CheckCSP(actual, expected_csp, expected_warnings);
 }
 
-testing::AssertionResult CheckSanitizeCSP(const std::string& policy,
-                                          int options,
-                                          const std::string& expected_csp,
-                                          const std::string& warning1,
-                                          const std::string& warning2) {
+testing::AssertionResult CheckCSP(const SanitizedCSPResult& actual,
+                                  const std::string& expected_csp,
+                                  const std::string& warning1,
+                                  const std::string& warning2) {
   std::vector<std::string> expected_warnings(1, warning1);
   expected_warnings.push_back(warning2);
-  return CheckSanitizeCSP(policy, options, expected_csp, expected_warnings);
+  return CheckCSP(actual, expected_csp, expected_warnings);
 }
 
-testing::AssertionResult CheckSanitizeCSP(const std::string& policy,
-                                          int options,
-                                          const std::string& expected_csp,
-                                          const std::string& warning1,
-                                          const std::string& warning2,
-                                          const std::string& warning3) {
+testing::AssertionResult CheckCSP(const SanitizedCSPResult& actual,
+                                  const std::string& expected_csp,
+                                  const std::string& warning1,
+                                  const std::string& warning2,
+                                  const std::string& warning3) {
   std::vector<std::string> expected_warnings(1, warning1);
   expected_warnings.push_back(warning2);
   expected_warnings.push_back(warning3);
-  return CheckSanitizeCSP(policy, options, expected_csp, expected_warnings);
+  return CheckCSP(actual, expected_csp, expected_warnings);
 }
 
 };  // namespace
@@ -124,294 +144,296 @@
 }
 
 TEST(ExtensionCSPValidator, IsSecure) {
-  EXPECT_TRUE(CheckSanitizeCSP(std::string(), OPTIONS_ALLOW_UNSAFE_EVAL,
-                               "script-src 'self'; object-src 'self';",
-                               MissingSecureSrcWarning("script-src"),
-                               MissingSecureSrcWarning("object-src")));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "img-src https://google.com", OPTIONS_ALLOW_UNSAFE_EVAL,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(std::string(), OPTIONS_ALLOW_UNSAFE_EVAL),
+      "script-src 'self'; object-src 'self';",
+      MissingSecureSrcWarning("script-src"),
+      MissingSecureSrcWarning("object-src")));
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "img-src https://google.com", OPTIONS_ALLOW_UNSAFE_EVAL),
       "img-src https://google.com; script-src 'self'; object-src 'self';",
       MissingSecureSrcWarning("script-src"),
       MissingSecureSrcWarning("object-src")));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "script-src a b", OPTIONS_ALLOW_UNSAFE_EVAL,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "script-src a b", OPTIONS_ALLOW_UNSAFE_EVAL),
       "script-src; object-src 'self';",
       InsecureValueWarning("script-src", "a"),
       InsecureValueWarning("script-src", "b"),
       MissingSecureSrcWarning("object-src")));
 
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src *", OPTIONS_ALLOW_UNSAFE_EVAL,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src *", OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src;",
       InsecureValueWarning("default-src", "*")));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self';", OPTIONS_ALLOW_UNSAFE_EVAL));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'none';", OPTIONS_ALLOW_UNSAFE_EVAL));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' ftp://google.com", OPTIONS_ALLOW_UNSAFE_EVAL,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self';", OPTIONS_ALLOW_UNSAFE_EVAL)));
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'none';", OPTIONS_ALLOW_UNSAFE_EVAL)));
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' ftp://google.com", OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src 'self';",
       InsecureValueWarning("default-src", "ftp://google.com")));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' https://google.com;", OPTIONS_ALLOW_UNSAFE_EVAL));
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' https://google.com;", OPTIONS_ALLOW_UNSAFE_EVAL)));
 
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src *; default-src 'self'", OPTIONS_ALLOW_UNSAFE_EVAL,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src *; default-src 'self'", OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src; default-src 'self';",
       InsecureValueWarning("default-src", "*")));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self'; default-src *;", OPTIONS_ALLOW_UNSAFE_EVAL,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self'; default-src *;", OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src 'self'; default-src;"));
-  EXPECT_TRUE(CheckSanitizeCSP(
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
       "default-src 'self'; default-src *; script-src *; script-src 'self'",
-      OPTIONS_ALLOW_UNSAFE_EVAL,
+      OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src 'self'; default-src; script-src; script-src 'self';",
       InsecureValueWarning("script-src", "*")));
-  EXPECT_TRUE(CheckSanitizeCSP(
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
       "default-src 'self'; default-src *; script-src 'self'; script-src *;",
-      OPTIONS_ALLOW_UNSAFE_EVAL,
+      OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src 'self'; default-src; script-src 'self'; script-src;"));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src *; script-src 'self'", OPTIONS_ALLOW_UNSAFE_EVAL,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src *; script-src 'self'", OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src; script-src 'self';",
       InsecureValueWarning("default-src", "*")));
-  EXPECT_TRUE(CheckSanitizeCSP(
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
       "default-src *; script-src 'self'; img-src 'self'",
-      OPTIONS_ALLOW_UNSAFE_EVAL,
+      OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src; script-src 'self'; img-src 'self';",
       InsecureValueWarning("default-src", "*")));
-  EXPECT_TRUE(CheckSanitizeCSP(
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
       "default-src *; script-src 'self'; object-src 'self';",
-      OPTIONS_ALLOW_UNSAFE_EVAL,
+      OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src; script-src 'self'; object-src 'self';"));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "script-src 'self'; object-src 'self';", OPTIONS_ALLOW_UNSAFE_EVAL));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'unsafe-eval';", OPTIONS_ALLOW_UNSAFE_EVAL));
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "script-src 'self'; object-src 'self';", OPTIONS_ALLOW_UNSAFE_EVAL)));
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'unsafe-eval';", OPTIONS_ALLOW_UNSAFE_EVAL)));
 
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'unsafe-eval'", OPTIONS_NONE,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'unsafe-eval'", OPTIONS_NONE),
       "default-src;",
       InsecureValueWarning("default-src", "'unsafe-eval'")));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'unsafe-inline'", OPTIONS_ALLOW_UNSAFE_EVAL,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'unsafe-inline'", OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src;",
       InsecureValueWarning("default-src", "'unsafe-inline'")));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'unsafe-inline' 'none'", OPTIONS_ALLOW_UNSAFE_EVAL,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'unsafe-inline' 'none'", OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src 'none';",
       InsecureValueWarning("default-src", "'unsafe-inline'")));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' http://google.com", OPTIONS_ALLOW_UNSAFE_EVAL,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' http://google.com", OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src 'self';",
       InsecureValueWarning("default-src", "http://google.com")));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' https://google.com;", OPTIONS_ALLOW_UNSAFE_EVAL));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' chrome://resources;", OPTIONS_ALLOW_UNSAFE_EVAL));
-  EXPECT_TRUE(CheckSanitizeCSP(
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' https://google.com;", OPTIONS_ALLOW_UNSAFE_EVAL)));
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' chrome://resources;", OPTIONS_ALLOW_UNSAFE_EVAL)));
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
       "default-src 'self' chrome-extension://aabbcc;",
-      OPTIONS_ALLOW_UNSAFE_EVAL));
-  EXPECT_TRUE(CheckSanitizeCSP(
+      OPTIONS_ALLOW_UNSAFE_EVAL)));
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
       "default-src 'self' chrome-extension-resource://aabbcc;",
-      OPTIONS_ALLOW_UNSAFE_EVAL));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' https:", OPTIONS_ALLOW_UNSAFE_EVAL,
+      OPTIONS_ALLOW_UNSAFE_EVAL)));
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' https:", OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src 'self';",
       InsecureValueWarning("default-src", "https:")));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' http:", OPTIONS_ALLOW_UNSAFE_EVAL,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' http:", OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src 'self';",
       InsecureValueWarning("default-src", "http:")));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' google.com", OPTIONS_ALLOW_UNSAFE_EVAL,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' google.com", OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src 'self';",
       InsecureValueWarning("default-src", "google.com")));
 
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' *", OPTIONS_ALLOW_UNSAFE_EVAL,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' *", OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src 'self';",
       InsecureValueWarning("default-src", "*")));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' *:*", OPTIONS_ALLOW_UNSAFE_EVAL,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' *:*", OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src 'self';",
       InsecureValueWarning("default-src", "*:*")));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' *:*/", OPTIONS_ALLOW_UNSAFE_EVAL,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' *:*/", OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src 'self';",
       InsecureValueWarning("default-src", "*:*/")));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' *:*/path", OPTIONS_ALLOW_UNSAFE_EVAL,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' *:*/path", OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src 'self';",
       InsecureValueWarning("default-src", "*:*/path")));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' https://", OPTIONS_ALLOW_UNSAFE_EVAL,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' https://", OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src 'self';",
       InsecureValueWarning("default-src", "https://")));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' https://*:*", OPTIONS_ALLOW_UNSAFE_EVAL,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' https://*:*", OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src 'self';",
       InsecureValueWarning("default-src", "https://*:*")));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' https://*:*/", OPTIONS_ALLOW_UNSAFE_EVAL,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' https://*:*/", OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src 'self';",
       InsecureValueWarning("default-src", "https://*:*/")));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' https://*:*/path", OPTIONS_ALLOW_UNSAFE_EVAL,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' https://*:*/path", OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src 'self';",
       InsecureValueWarning("default-src", "https://*:*/path")));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' https://*.com", OPTIONS_ALLOW_UNSAFE_EVAL,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' https://*.com", OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src 'self';",
       InsecureValueWarning("default-src", "https://*.com")));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' https://*.*.google.com/", OPTIONS_ALLOW_UNSAFE_EVAL,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' https://*.*.google.com/", OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src 'self';",
       InsecureValueWarning("default-src", "https://*.*.google.com/")));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' https://*.*.google.com:*/", OPTIONS_ALLOW_UNSAFE_EVAL,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' https://*.*.google.com:*/", OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src 'self';",
       InsecureValueWarning("default-src", "https://*.*.google.com:*/")));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' https://www.*.google.com/", OPTIONS_ALLOW_UNSAFE_EVAL,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' https://www.*.google.com/", OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src 'self';",
       InsecureValueWarning("default-src", "https://www.*.google.com/")));
-  EXPECT_TRUE(CheckSanitizeCSP(
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
       "default-src 'self' https://www.*.google.com:*/",
-      OPTIONS_ALLOW_UNSAFE_EVAL,
+      OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src 'self';",
       InsecureValueWarning("default-src", "https://www.*.google.com:*/")));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' chrome://*", OPTIONS_ALLOW_UNSAFE_EVAL,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' chrome://*", OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src 'self';",
       InsecureValueWarning("default-src", "chrome://*")));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' chrome-extension://*", OPTIONS_ALLOW_UNSAFE_EVAL,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' chrome-extension://*", OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src 'self';",
       InsecureValueWarning("default-src", "chrome-extension://*")));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' chrome-extension://", OPTIONS_ALLOW_UNSAFE_EVAL,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' chrome-extension://", OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src 'self';",
       InsecureValueWarning("default-src", "chrome-extension://")));
 
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' https://*.google.com;", OPTIONS_ALLOW_UNSAFE_EVAL));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' https://*.google.com:1;", OPTIONS_ALLOW_UNSAFE_EVAL));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' https://*.google.com:*;", OPTIONS_ALLOW_UNSAFE_EVAL));
-  EXPECT_TRUE(CheckSanitizeCSP(
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' https://*.google.com;", OPTIONS_ALLOW_UNSAFE_EVAL)));
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' https://*.google.com:1;",
+      OPTIONS_ALLOW_UNSAFE_EVAL)));
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' https://*.google.com:*;",
+      OPTIONS_ALLOW_UNSAFE_EVAL)));
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
       "default-src 'self' https://*.google.com:1/;",
-      OPTIONS_ALLOW_UNSAFE_EVAL));
-  EXPECT_TRUE(CheckSanitizeCSP(
+      OPTIONS_ALLOW_UNSAFE_EVAL)));
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
       "default-src 'self' https://*.google.com:*/;",
-      OPTIONS_ALLOW_UNSAFE_EVAL));
+      OPTIONS_ALLOW_UNSAFE_EVAL)));
 
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' http://127.0.0.1;", OPTIONS_ALLOW_UNSAFE_EVAL));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' http://localhost;", OPTIONS_ALLOW_UNSAFE_EVAL));
-  EXPECT_TRUE(CheckSanitizeCSP("default-src 'self' http://lOcAlHoSt;",
-                               OPTIONS_ALLOW_UNSAFE_EVAL,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' http://127.0.0.1;", OPTIONS_ALLOW_UNSAFE_EVAL)));
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' http://localhost;", OPTIONS_ALLOW_UNSAFE_EVAL)));
+  EXPECT_TRUE(CheckCSP(SanitizeCSP("default-src 'self' http://lOcAlHoSt;",
+                               OPTIONS_ALLOW_UNSAFE_EVAL),
                                "default-src 'self' http://lOcAlHoSt;"));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' http://127.0.0.1:9999;", OPTIONS_ALLOW_UNSAFE_EVAL));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' http://localhost:8888;", OPTIONS_ALLOW_UNSAFE_EVAL));
-  EXPECT_TRUE(CheckSanitizeCSP(
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' http://127.0.0.1:9999;", OPTIONS_ALLOW_UNSAFE_EVAL)));
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' http://localhost:8888;", OPTIONS_ALLOW_UNSAFE_EVAL)));
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
       "default-src 'self' http://127.0.0.1.example.com",
-      OPTIONS_ALLOW_UNSAFE_EVAL,
+      OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src 'self';",
       InsecureValueWarning("default-src", "http://127.0.0.1.example.com")));
-  EXPECT_TRUE(CheckSanitizeCSP(
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
       "default-src 'self' http://localhost.example.com",
-      OPTIONS_ALLOW_UNSAFE_EVAL,
+      OPTIONS_ALLOW_UNSAFE_EVAL),
       "default-src 'self';",
       InsecureValueWarning("default-src", "http://localhost.example.com")));
 
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' blob:;", OPTIONS_ALLOW_UNSAFE_EVAL));
-  EXPECT_TRUE(CheckSanitizeCSP(
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' blob:;", OPTIONS_ALLOW_UNSAFE_EVAL)));
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
       "default-src 'self' blob:http://example.com/XXX",
-      OPTIONS_ALLOW_UNSAFE_EVAL, "default-src 'self';",
+      OPTIONS_ALLOW_UNSAFE_EVAL), "default-src 'self';",
       InsecureValueWarning("default-src", "blob:http://example.com/XXX")));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "default-src 'self' filesystem:;", OPTIONS_ALLOW_UNSAFE_EVAL));
-  EXPECT_TRUE(CheckSanitizeCSP(
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "default-src 'self' filesystem:;", OPTIONS_ALLOW_UNSAFE_EVAL)));
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
       "default-src 'self' filesystem:http://example.com/XX",
-      OPTIONS_ALLOW_UNSAFE_EVAL, "default-src 'self';",
+      OPTIONS_ALLOW_UNSAFE_EVAL), "default-src 'self';",
       InsecureValueWarning("default-src", "filesystem:http://example.com/XX")));
 
-  EXPECT_TRUE(CheckSanitizeCSP(
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
       "default-src 'self' https://*.googleapis.com;",
-      OPTIONS_ALLOW_UNSAFE_EVAL));
-  EXPECT_TRUE(CheckSanitizeCSP(
+      OPTIONS_ALLOW_UNSAFE_EVAL)));
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
       "default-src 'self' https://x.googleapis.com;",
-      OPTIONS_ALLOW_UNSAFE_EVAL));
+      OPTIONS_ALLOW_UNSAFE_EVAL)));
 
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "script-src 'self'; object-src *", OPTIONS_NONE,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "script-src 'self'; object-src *", OPTIONS_NONE),
       "script-src 'self'; object-src;",
       InsecureValueWarning("object-src", "*")));
-  EXPECT_TRUE(CheckSanitizeCSP(
-      "script-src 'self'; object-src *", OPTIONS_ALLOW_INSECURE_OBJECT_SRC,
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
+      "script-src 'self'; object-src *", OPTIONS_ALLOW_INSECURE_OBJECT_SRC),
       "script-src 'self'; object-src;",
       InsecureValueWarning("object-src", "*")));
-  EXPECT_TRUE(CheckSanitizeCSP(
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
       "script-src 'self'; object-src *; plugin-types application/pdf;",
-      OPTIONS_ALLOW_INSECURE_OBJECT_SRC));
-  EXPECT_TRUE(CheckSanitizeCSP(
+      OPTIONS_ALLOW_INSECURE_OBJECT_SRC)));
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
       "script-src 'self'; object-src *; "
       "plugin-types application/x-shockwave-flash",
-      OPTIONS_ALLOW_INSECURE_OBJECT_SRC,
+      OPTIONS_ALLOW_INSECURE_OBJECT_SRC),
       "script-src 'self'; object-src; "
       "plugin-types application/x-shockwave-flash;",
       InsecureValueWarning("object-src", "*")));
-  EXPECT_TRUE(CheckSanitizeCSP(
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
       "script-src 'self'; object-src *; "
       "plugin-types application/x-shockwave-flash application/pdf;",
-      OPTIONS_ALLOW_INSECURE_OBJECT_SRC,
+      OPTIONS_ALLOW_INSECURE_OBJECT_SRC),
       "script-src 'self'; object-src; "
       "plugin-types application/x-shockwave-flash application/pdf;",
       InsecureValueWarning("object-src", "*")));
-  EXPECT_TRUE(CheckSanitizeCSP(
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
       "script-src 'self'; object-src http://www.example.com; "
       "plugin-types application/pdf;",
-      OPTIONS_ALLOW_INSECURE_OBJECT_SRC));
-  EXPECT_TRUE(CheckSanitizeCSP(
+      OPTIONS_ALLOW_INSECURE_OBJECT_SRC)));
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
       "object-src http://www.example.com blob:; script-src 'self'; "
       "plugin-types application/pdf;",
-      OPTIONS_ALLOW_INSECURE_OBJECT_SRC));
-  EXPECT_TRUE(CheckSanitizeCSP(
+      OPTIONS_ALLOW_INSECURE_OBJECT_SRC)));
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
       "script-src 'self'; object-src http://*.example.com; "
       "plugin-types application/pdf;",
-      OPTIONS_ALLOW_INSECURE_OBJECT_SRC));
-  EXPECT_TRUE(CheckSanitizeCSP(
+      OPTIONS_ALLOW_INSECURE_OBJECT_SRC)));
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
       "script-src *; object-src *; plugin-types application/pdf;",
-      OPTIONS_ALLOW_INSECURE_OBJECT_SRC,
+      OPTIONS_ALLOW_INSECURE_OBJECT_SRC),
       "script-src; object-src *; plugin-types application/pdf;",
       InsecureValueWarning("script-src", "*")));
 
-  EXPECT_TRUE(CheckSanitizeCSP(
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
       "default-src; script-src"
       " 'sha256-hndjYvzUzy2Ykuad81Cwsl1FOXX/qYs/aDVyUyNZwBw='"
       " 'sha384-bSVm1i3sjPBRM4TwZtYTDjk9JxZMExYHWbFmP1SxDhJH4ue0Wu9OPOkY5hcqRcS"
       "t'"
       " 'sha512-440MmBLtj9Kp5Bqloogn9BqGDylY8vFsv5/zXL1zH2fJVssCoskRig4gyM+9Kqw"
       "vCSapSz5CVoUGHQcxv43UQg==';",
-      OPTIONS_NONE));
+      OPTIONS_NONE)));
 
   // Reject non-standard algorithms, even if they are still supported by Blink.
-  EXPECT_TRUE(CheckSanitizeCSP(
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
       "default-src; script-src 'sha1-eYyYGmKWdhpUewohaXk9o8IaLSw=';",
-      OPTIONS_NONE, "default-src; script-src;",
+      OPTIONS_NONE), "default-src; script-src;",
       InsecureValueWarning("script-src",
                            "'sha1-eYyYGmKWdhpUewohaXk9o8IaLSw='")));
 
-  EXPECT_TRUE(CheckSanitizeCSP(
+  EXPECT_TRUE(CheckCSP(SanitizeCSP(
       "default-src; script-src 'sha256-hndjYvzUzy2Ykuad81Cwsl1FOXX/qYs/aDVyUyNZ"
       "wBw= sha256-qznLcsROx4GACP2dm0UCKCzCG+HiZ1guq6ZZDob/Tng=';",
-      OPTIONS_NONE, "default-src; script-src;",
+      OPTIONS_NONE), "default-src; script-src;",
       InsecureValueWarning(
           "script-src", "'sha256-hndjYvzUzy2Ykuad81Cwsl1FOXX/qYs/aDVyUyNZwBw="),
       InsecureValueWarning(
@@ -452,3 +474,63 @@
   EXPECT_TRUE(ContentSecurityPolicyIsSandboxed(
       "sandbox allow-popups", Manifest::TYPE_PLATFORM_APP));
 }
+
+TEST(ExtensionCSPValidator, EffectiveSandboxedPageCSP) {
+  EXPECT_TRUE(CheckCSP(
+      SanitizeSandboxPageCSP(""),
+      "child-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval';"));
+  EXPECT_TRUE(CheckCSP(
+      SanitizeSandboxPageCSP("child-src http://www.google.com"),
+      "child-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval';",
+      InsecureValueWarning("child-src", "http://www.google.com")));
+  EXPECT_TRUE(CheckCSP(
+      SanitizeSandboxPageCSP("child-src *"),
+      "child-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval';",
+      InsecureValueWarning("child-src", "*")));
+  EXPECT_TRUE(CheckCSP(
+      SanitizeSandboxPageCSP("child-src 'none'"),
+      "child-src 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval';"));
+
+  // Directive values of 'none' and 'self' are preserved.
+  EXPECT_TRUE(
+      CheckCSP(SanitizeSandboxPageCSP("script-src 'none'; frame-src 'self';"),
+               "frame-src 'self'; script-src 'none';"));
+  EXPECT_TRUE(CheckCSP(
+      SanitizeSandboxPageCSP(
+          "script-src 'none'; frame-src 'self' http://www.google.com;"),
+      "frame-src 'self'; script-src 'none';",
+      InsecureValueWarning("frame-src", "http://www.google.com")));
+
+  // script-src will add 'unsafe-inline' and 'unsafe-eval' only if script-src is
+  // not specified.
+  EXPECT_TRUE(CheckCSP(SanitizeSandboxPageCSP("script-src 'self'"),
+                       "script-src 'self'; child-src 'self'"));
+  EXPECT_TRUE(
+      CheckCSP(SanitizeSandboxPageCSP(
+                   "script-src 'self' 'unsafe-inline'; child-src 'self';"),
+               "child-src 'self'; script-src 'self' 'unsafe-inline';"));
+  EXPECT_TRUE(
+      CheckCSP(SanitizeSandboxPageCSP(
+                   "script-src 'self' 'unsafe-eval'; child-src 'self';"),
+               "child-src 'self'; script-src 'self' 'unsafe-eval';"));
+
+  // child-src and frame-src are handled correctly.
+  EXPECT_TRUE(CheckCSP(
+      SanitizeSandboxPageCSP(
+          "script-src 'none'; frame-src 'self' http://www.google.com;"),
+      "frame-src 'self'; script-src 'none';",
+      InsecureValueWarning("frame-src", "http://www.google.com")));
+  EXPECT_TRUE(CheckCSP(
+      SanitizeSandboxPageCSP(
+          "script-src 'none'; child-src 'self' http://www.google.com;"),
+      "child-src 'self'; script-src 'none';",
+      InsecureValueWarning("child-src", "http://www.google.com")));
+
+  // Multiple insecure values.
+  EXPECT_TRUE(CheckCSP(
+      SanitizeSandboxPageCSP(
+          "script-src 'none'; child-src http://bar.com 'self' http://foo.com;"),
+      "child-src 'self'; script-src 'none';",
+      InsecureValueWarning("child-src", "http://bar.com"),
+      InsecureValueWarning("child-src", "http://foo.com")));
+}
diff --git a/extensions/common/manifest_handlers/csp_info_unittest.cc b/extensions/common/manifest_handlers/csp_info_unittest.cc
index e6698fa..d2621ff 100644
--- a/extensions/common/manifest_handlers/csp_info_unittest.cc
+++ b/extensions/common/manifest_handlers/csp_info_unittest.cc
@@ -34,12 +34,13 @@
       LoadAndExpectSuccess("sandboxed_pages_valid_5.json"));
 
   const char kSandboxedCSP[] =
-      "sandbox allow-scripts allow-forms allow-popups allow-modals";
+      "sandbox allow-scripts allow-forms allow-popups allow-modals; "
+      "script-src 'self' 'unsafe-inline' 'unsafe-eval'; child-src 'self';";
   const char kDefaultCSP[] =
       "script-src 'self' blob: filesystem: chrome-extension-resource:; "
       "object-src 'self' blob: filesystem:;";
   const char kCustomSandboxedCSP[] =
-      "sandbox; script-src: https://www.google.com";
+      "sandbox; script-src 'self'; child-src 'self';";
 
   EXPECT_EQ(kSandboxedCSP, CSPInfo::GetResourceContentSecurityPolicy(
                                extension1.get(), "/test"));
diff --git a/extensions/common/manifest_handlers/sandboxed_page_info.cc b/extensions/common/manifest_handlers/sandboxed_page_info.cc
index d3c82d5f..c8ad586 100644
--- a/extensions/common/manifest_handlers/sandboxed_page_info.cc
+++ b/extensions/common/manifest_handlers/sandboxed_page_info.cc
@@ -25,7 +25,8 @@
 namespace errors = manifest_errors;
 
 const char kDefaultSandboxedPageContentSecurityPolicy[] =
-    "sandbox allow-scripts allow-forms allow-popups allow-modals";
+    "sandbox allow-scripts allow-forms allow-popups allow-modals; "
+    "script-src 'self' 'unsafe-inline' 'unsafe-eval'; child-src 'self';";
 
 static base::LazyInstance<SandboxedPageInfo> g_empty_sandboxed_info =
     LAZY_INSTANCE_INITIALIZER;
@@ -93,26 +94,31 @@
   }
 
   if (extension->manifest()->HasPath(keys::kSandboxedPagesCSP)) {
-    if (!extension->manifest()->GetString(
-            keys::kSandboxedPagesCSP,
-            &sandboxed_info->content_security_policy)) {
+    std::string content_security_policy;
+    if (!extension->manifest()->GetString(keys::kSandboxedPagesCSP,
+                                          &content_security_policy)) {
       *error = base::ASCIIToUTF16(errors::kInvalidSandboxedPagesCSP);
       return false;
     }
 
-    if (!csp_validator::ContentSecurityPolicyIsLegal(
-            sandboxed_info->content_security_policy) ||
+    if (!csp_validator::ContentSecurityPolicyIsLegal(content_security_policy) ||
         !csp_validator::ContentSecurityPolicyIsSandboxed(
-            sandboxed_info->content_security_policy, extension->GetType())) {
+            content_security_policy, extension->GetType())) {
       *error = base::ASCIIToUTF16(errors::kInvalidSandboxedPagesCSP);
       return false;
     }
+
+    std::vector<InstallWarning> warnings;
+    sandboxed_info->content_security_policy =
+        csp_validator::GetEffectiveSandoxedPageCSP(content_security_policy,
+                                                   &warnings);
+    extension->AddInstallWarnings(warnings);
   } else {
     sandboxed_info->content_security_policy =
         kDefaultSandboxedPageContentSecurityPolicy;
-    CHECK(csp_validator::ContentSecurityPolicyIsSandboxed(
-        sandboxed_info->content_security_policy, extension->GetType()));
   }
+  CHECK(csp_validator::ContentSecurityPolicyIsSandboxed(
+      sandboxed_info->content_security_policy, extension->GetType()));
 
   extension->SetManifestData(keys::kSandboxedPages, sandboxed_info.release());
   return true;
diff --git a/extensions/test/data/manifest_tests/sandboxed_pages_valid_3.json b/extensions/test/data/manifest_tests/sandboxed_pages_valid_3.json
index 0b97f20..24da1ee 100644
--- a/extensions/test/data/manifest_tests/sandboxed_pages_valid_3.json
+++ b/extensions/test/data/manifest_tests/sandboxed_pages_valid_3.json
@@ -4,6 +4,6 @@
   "manifest_version": 2,
   "sandbox": {
     "pages": ["test"],
-    "content_security_policy": "sandbox; script-src: https://www.google.com"
+    "content_security_policy": "sandbox; script-src https://www.google.com"
   }
 }
diff --git a/media/base/android/media_drm_bridge.cc b/media/base/android/media_drm_bridge.cc
index bb7b251..477186c 100644
--- a/media/base/android/media_drm_bridge.cc
+++ b/media/base/android/media_drm_bridge.cc
@@ -360,14 +360,14 @@
 }
 
 void MediaDrmBridge::CreateSessionAndGenerateRequest(
-    SessionType session_type,
+    CdmSessionType session_type,
     media::EmeInitDataType init_data_type,
     const std::vector<uint8_t>& init_data,
     std::unique_ptr<media::NewSessionCdmPromise> promise) {
   DCHECK(task_runner_->BelongsToCurrentThread());
   DVLOG(2) << __func__;
 
-  if (session_type != ContentDecryptionModule::TEMPORARY_SESSION) {
+  if (session_type != CdmSessionType::TEMPORARY_SESSION) {
     NOTIMPLEMENTED() << "EME persistent sessions not yet supported on Android.";
     promise->reject(CdmPromise::NOT_SUPPORTED_ERROR, 0,
                     "Only the temporary session type is supported.");
@@ -418,7 +418,7 @@
 }
 
 void MediaDrmBridge::LoadSession(
-    SessionType session_type,
+    CdmSessionType session_type,
     const std::string& session_id,
     std::unique_ptr<media::NewSessionCdmPromise> promise) {
   DCHECK(task_runner_->BelongsToCurrentThread());
diff --git a/media/base/android/media_drm_bridge.h b/media/base/android/media_drm_bridge.h
index 1171baa..d5577cc7 100644
--- a/media/base/android/media_drm_bridge.h
+++ b/media/base/android/media_drm_bridge.h
@@ -107,12 +107,12 @@
       const std::vector<uint8_t>& certificate,
       std::unique_ptr<media::SimpleCdmPromise> promise) override;
   void CreateSessionAndGenerateRequest(
-      SessionType session_type,
+      CdmSessionType session_type,
       media::EmeInitDataType init_data_type,
       const std::vector<uint8_t>& init_data,
       std::unique_ptr<media::NewSessionCdmPromise> promise) override;
   void LoadSession(
-      SessionType session_type,
+      CdmSessionType session_type,
       const std::string& session_id,
       std::unique_ptr<media::NewSessionCdmPromise> promise) override;
   void UpdateSession(const std::string& session_id,
diff --git a/media/base/content_decryption_module.h b/media/base/content_decryption_module.h
index 3fe3eb6f..e8b3665 100644
--- a/media/base/content_decryption_module.h
+++ b/media/base/content_decryption_module.h
@@ -36,6 +36,16 @@
 typedef CdmPromiseTemplate<> SimpleCdmPromise;
 typedef ScopedVector<CdmKeyInformation> CdmKeysInfo;
 
+// Type of license required when creating/loading a session.
+// Must be consistent with the values specified in the spec:
+// https://w3c.github.io/encrypted-media/#idl-def-MediaKeySessionType
+enum class CdmSessionType {
+  TEMPORARY_SESSION,
+  PERSISTENT_LICENSE_SESSION,
+  PERSISTENT_RELEASE_MESSAGE_SESSION,
+  SESSION_TYPE_MAX = PERSISTENT_RELEASE_MESSAGE_SESSION
+};
+
 // An interface that represents the Content Decryption Module (CDM) in the
 // Encrypted Media Extensions (EME) spec in Chromium.
 // See http://w3c.github.io/encrypted-media/#cdm
@@ -59,21 +69,10 @@
 // that thread. For example, if the CDM supports a Decryptor interface, the
 // Decryptor methods could be called on a different thread. The CDM
 // implementation should make sure it's thread safe for these situations.
-
 class MEDIA_EXPORT ContentDecryptionModule
     : public base::RefCountedThreadSafe<ContentDecryptionModule,
                                         ContentDecryptionModuleTraits> {
  public:
-  // Type of license required when creating/loading a session.
-  // Must be consistent with the values specified in the spec:
-  // https://w3c.github.io/encrypted-media/#idl-def-MediaKeySessionType
-  enum SessionType {
-    TEMPORARY_SESSION,
-    PERSISTENT_LICENSE_SESSION,
-    PERSISTENT_RELEASE_MESSAGE_SESSION,
-    SESSION_TYPE_MAX = PERSISTENT_RELEASE_MESSAGE_SESSION
-  };
-
   // Type of message being sent to the application.
   // Must be consistent with the values specified in the spec:
   // https://w3c.github.io/encrypted-media/#idl-def-MediaKeyMessageType
@@ -100,7 +99,7 @@
   // 3. UpdateSession(), CloseSession() and RemoveSession() should only be
   //    called after the |promise| is resolved.
   virtual void CreateSessionAndGenerateRequest(
-      SessionType session_type,
+      CdmSessionType session_type,
       EmeInitDataType init_data_type,
       const std::vector<uint8_t>& init_data,
       std::unique_ptr<NewSessionCdmPromise> promise) = 0;
@@ -112,7 +111,7 @@
   // happened.
   // Note: UpdateSession(), CloseSession() and RemoveSession() should only be
   //       called after the |promise| is resolved.
-  virtual void LoadSession(SessionType session_type,
+  virtual void LoadSession(CdmSessionType session_type,
                            const std::string& session_id,
                            std::unique_ptr<NewSessionCdmPromise> promise) = 0;
 
diff --git a/media/base/ipc/media_param_traits_macros.h b/media/base/ipc/media_param_traits_macros.h
index 8fe5e2c..fff70465 100644
--- a/media/base/ipc/media_param_traits_macros.h
+++ b/media/base/ipc/media_param_traits_macros.h
@@ -69,8 +69,8 @@
 IPC_ENUM_TRAITS_MAX_VALUE(media::ContentDecryptionModule::MessageType,
                           media::ContentDecryptionModule::MESSAGE_TYPE_MAX)
 
-IPC_ENUM_TRAITS_MAX_VALUE(media::ContentDecryptionModule::SessionType,
-                          media::ContentDecryptionModule::SESSION_TYPE_MAX)
+IPC_ENUM_TRAITS_MAX_VALUE(media::CdmSessionType,
+                          media::CdmSessionType::SESSION_TYPE_MAX)
 
 IPC_ENUM_TRAITS_MAX_VALUE(media::SampleFormat, media::kSampleFormatMax)
 
diff --git a/media/blink/cdm_session_adapter.cc b/media/blink/cdm_session_adapter.cc
index d42a628..5b98d03 100644
--- a/media/blink/cdm_session_adapter.cc
+++ b/media/blink/cdm_session_adapter.cc
@@ -91,14 +91,14 @@
 void CdmSessionAdapter::InitializeNewSession(
     EmeInitDataType init_data_type,
     const std::vector<uint8_t>& init_data,
-    ContentDecryptionModule::SessionType session_type,
+    CdmSessionType session_type,
     std::unique_ptr<NewSessionCdmPromise> promise) {
   cdm_->CreateSessionAndGenerateRequest(session_type, init_data_type, init_data,
                                         std::move(promise));
 }
 
 void CdmSessionAdapter::LoadSession(
-    ContentDecryptionModule::SessionType session_type,
+    CdmSessionType session_type,
     const std::string& session_id,
     std::unique_ptr<NewSessionCdmPromise> promise) {
   cdm_->LoadSession(session_type, session_id, std::move(promise));
diff --git a/media/blink/cdm_session_adapter.h b/media/blink/cdm_session_adapter.h
index b72060d..d2692971 100644
--- a/media/blink/cdm_session_adapter.h
+++ b/media/blink/cdm_session_adapter.h
@@ -68,11 +68,11 @@
   // |session_type| provided.
   void InitializeNewSession(EmeInitDataType init_data_type,
                             const std::vector<uint8_t>& init_data,
-                            ContentDecryptionModule::SessionType session_type,
+                            CdmSessionType session_type,
                             std::unique_ptr<NewSessionCdmPromise> promise);
 
   // Loads the session specified by |session_id|.
-  void LoadSession(ContentDecryptionModule::SessionType session_type,
+  void LoadSession(CdmSessionType session_type,
                    const std::string& session_id,
                    std::unique_ptr<NewSessionCdmPromise> promise);
 
diff --git a/media/blink/webcontentdecryptionmodulesession_impl.cc b/media/blink/webcontentdecryptionmodulesession_impl.cc
index 707fe5a0..5ef54ee 100644
--- a/media/blink/webcontentdecryptionmodulesession_impl.cc
+++ b/media/blink/webcontentdecryptionmodulesession_impl.cc
@@ -85,21 +85,21 @@
   return blink::WebEncryptedMediaKeyInformation::KeyStatus::InternalError;
 }
 
-ContentDecryptionModule::SessionType convertSessionType(
+CdmSessionType convertSessionType(
     blink::WebEncryptedMediaSessionType session_type) {
   switch (session_type) {
     case blink::WebEncryptedMediaSessionType::Temporary:
-      return ContentDecryptionModule::TEMPORARY_SESSION;
+      return CdmSessionType::TEMPORARY_SESSION;
     case blink::WebEncryptedMediaSessionType::PersistentLicense:
-      return ContentDecryptionModule::PERSISTENT_LICENSE_SESSION;
+      return CdmSessionType::PERSISTENT_LICENSE_SESSION;
     case blink::WebEncryptedMediaSessionType::PersistentReleaseMessage:
-      return ContentDecryptionModule::PERSISTENT_RELEASE_MESSAGE_SESSION;
+      return CdmSessionType::PERSISTENT_RELEASE_MESSAGE_SESSION;
     case blink::WebEncryptedMediaSessionType::Unknown:
       break;
   }
 
   NOTREACHED();
-  return ContentDecryptionModule::TEMPORARY_SESSION;
+  return CdmSessionType::TEMPORARY_SESSION;
 }
 
 bool SanitizeInitData(EmeInitDataType init_data_type,
@@ -202,8 +202,7 @@
   if (IsClearKey(key_system) || IsExternalClearKey(key_system)) {
     std::string key_string(response, response + response_length);
     KeyIdAndKeyPairs keys;
-    ContentDecryptionModule::SessionType session_type =
-        ContentDecryptionModule::TEMPORARY_SESSION;
+    CdmSessionType session_type = CdmSessionType::TEMPORARY_SESSION;
     if (!ExtractKeysFromJWKSet(key_string, &keys, &session_type))
       return false;
 
@@ -392,7 +391,7 @@
   // session type should be passed from blink. Type should also be passed in the
   // constructor (and removed from initializeNewSession()).
   adapter_->LoadSession(
-      ContentDecryptionModule::PERSISTENT_LICENSE_SESSION, sanitized_session_id,
+      CdmSessionType::PERSISTENT_LICENSE_SESSION, sanitized_session_id,
       std::unique_ptr<NewSessionCdmPromise>(new NewSessionCdmResultPromise(
           result, adapter_->GetKeySystemUMAPrefix() + kLoadSessionUMAName,
           base::Bind(
diff --git a/media/cdm/aes_decryptor.cc b/media/cdm/aes_decryptor.cc
index 919a54e..43f81d8 100644
--- a/media/cdm/aes_decryptor.cc
+++ b/media/cdm/aes_decryptor.cc
@@ -256,7 +256,7 @@
 }
 
 void AesDecryptor::CreateSessionAndGenerateRequest(
-    SessionType session_type,
+    CdmSessionType session_type,
     EmeInitDataType init_data_type,
     const std::vector<uint8_t>& init_data,
     std::unique_ptr<NewSessionCdmPromise> promise) {
@@ -315,7 +315,7 @@
   session_message_cb_.Run(session_id, LICENSE_REQUEST, message);
 }
 
-void AesDecryptor::LoadSession(SessionType session_type,
+void AesDecryptor::LoadSession(CdmSessionType session_type,
                                const std::string& session_id,
                                std::unique_ptr<NewSessionCdmPromise> promise) {
   // TODO(xhwang): Change this to NOTREACHED() when blink checks for key systems
@@ -342,7 +342,7 @@
   std::string key_string(response.begin(), response.end());
 
   KeyIdAndKeyPairs keys;
-  SessionType session_type = ContentDecryptionModule::TEMPORARY_SESSION;
+  CdmSessionType session_type = CdmSessionType::TEMPORARY_SESSION;
   if (!ExtractKeysFromJWKSet(key_string, &keys, &session_type)) {
     promise->reject(CdmPromise::INVALID_ACCESS_ERROR, 0,
                     "Response is not a valid JSON Web Key Set.");
diff --git a/media/cdm/aes_decryptor.h b/media/cdm/aes_decryptor.h
index bc9d990..f82b943 100644
--- a/media/cdm/aes_decryptor.h
+++ b/media/cdm/aes_decryptor.h
@@ -44,11 +44,11 @@
   void SetServerCertificate(const std::vector<uint8_t>& certificate,
                             std::unique_ptr<SimpleCdmPromise> promise) override;
   void CreateSessionAndGenerateRequest(
-      SessionType session_type,
+      CdmSessionType session_type,
       EmeInitDataType init_data_type,
       const std::vector<uint8_t>& init_data,
       std::unique_ptr<NewSessionCdmPromise> promise) override;
-  void LoadSession(SessionType session_type,
+  void LoadSession(CdmSessionType session_type,
                    const std::string& session_id,
                    std::unique_ptr<NewSessionCdmPromise> promise) override;
   void UpdateSession(const std::string& session_id,
diff --git a/media/cdm/aes_decryptor_unittest.cc b/media/cdm/aes_decryptor_unittest.cc
index fa87262..042de6a 100644
--- a/media/cdm/aes_decryptor_unittest.cc
+++ b/media/cdm/aes_decryptor_unittest.cc
@@ -328,9 +328,9 @@
     DCHECK(!key_id.empty());
     EXPECT_CALL(cdm_client_,
                 OnSessionMessage(NotEmpty(), _, IsJSONDictionary()));
-    cdm_->CreateSessionAndGenerateRequest(
-        ContentDecryptionModule::TEMPORARY_SESSION, EmeInitDataType::WEBM,
-        key_id, CreateSessionPromise(RESOLVED));
+    cdm_->CreateSessionAndGenerateRequest(CdmSessionType::TEMPORARY_SESSION,
+                                          EmeInitDataType::WEBM, key_id,
+                                          CreateSessionPromise(RESOLVED));
     // This expects the promise to be called synchronously, which is the case
     // for AesDecryptor.
     return session_id_;
@@ -468,13 +468,13 @@
 
 TEST_P(AesDecryptorTest, CreateSessionWithEmptyInitData) {
   cdm_->CreateSessionAndGenerateRequest(
-      ContentDecryptionModule::TEMPORARY_SESSION, EmeInitDataType::WEBM,
+      CdmSessionType::TEMPORARY_SESSION, EmeInitDataType::WEBM,
       std::vector<uint8_t>(), CreateSessionPromise(REJECTED));
   cdm_->CreateSessionAndGenerateRequest(
-      ContentDecryptionModule::TEMPORARY_SESSION, EmeInitDataType::CENC,
+      CdmSessionType::TEMPORARY_SESSION, EmeInitDataType::CENC,
       std::vector<uint8_t>(), CreateSessionPromise(REJECTED));
   cdm_->CreateSessionAndGenerateRequest(
-      ContentDecryptionModule::TEMPORARY_SESSION, EmeInitDataType::KEYIDS,
+      CdmSessionType::TEMPORARY_SESSION, EmeInitDataType::KEYIDS,
       std::vector<uint8_t>(), CreateSessionPromise(REJECTED));
 }
 
@@ -483,41 +483,41 @@
   init_data.resize(1);
   EXPECT_CALL(cdm_client_, OnSessionMessage(NotEmpty(), _, IsJSONDictionary()));
   cdm_->CreateSessionAndGenerateRequest(
-      ContentDecryptionModule::TEMPORARY_SESSION, EmeInitDataType::WEBM,
+      CdmSessionType::TEMPORARY_SESSION, EmeInitDataType::WEBM,
       std::vector<uint8_t>(init_data), CreateSessionPromise(RESOLVED));
 
   init_data.resize(16);  // The expected size.
   EXPECT_CALL(cdm_client_, OnSessionMessage(NotEmpty(), _, IsJSONDictionary()));
   cdm_->CreateSessionAndGenerateRequest(
-      ContentDecryptionModule::TEMPORARY_SESSION, EmeInitDataType::WEBM,
+      CdmSessionType::TEMPORARY_SESSION, EmeInitDataType::WEBM,
       std::vector<uint8_t>(init_data), CreateSessionPromise(RESOLVED));
 
   init_data.resize(512);
   EXPECT_CALL(cdm_client_, OnSessionMessage(NotEmpty(), _, IsJSONDictionary()));
   cdm_->CreateSessionAndGenerateRequest(
-      ContentDecryptionModule::TEMPORARY_SESSION, EmeInitDataType::WEBM,
+      CdmSessionType::TEMPORARY_SESSION, EmeInitDataType::WEBM,
       std::vector<uint8_t>(init_data), CreateSessionPromise(RESOLVED));
 
   init_data.resize(513);
   cdm_->CreateSessionAndGenerateRequest(
-      ContentDecryptionModule::TEMPORARY_SESSION, EmeInitDataType::WEBM,
+      CdmSessionType::TEMPORARY_SESSION, EmeInitDataType::WEBM,
       std::vector<uint8_t>(init_data), CreateSessionPromise(REJECTED));
 }
 
 TEST_P(AesDecryptorTest, MultipleCreateSession) {
   EXPECT_CALL(cdm_client_, OnSessionMessage(NotEmpty(), _, IsJSONDictionary()));
   cdm_->CreateSessionAndGenerateRequest(
-      ContentDecryptionModule::TEMPORARY_SESSION, EmeInitDataType::WEBM,
+      CdmSessionType::TEMPORARY_SESSION, EmeInitDataType::WEBM,
       std::vector<uint8_t>(1), CreateSessionPromise(RESOLVED));
 
   EXPECT_CALL(cdm_client_, OnSessionMessage(NotEmpty(), _, IsJSONDictionary()));
   cdm_->CreateSessionAndGenerateRequest(
-      ContentDecryptionModule::TEMPORARY_SESSION, EmeInitDataType::WEBM,
+      CdmSessionType::TEMPORARY_SESSION, EmeInitDataType::WEBM,
       std::vector<uint8_t>(1), CreateSessionPromise(RESOLVED));
 
   EXPECT_CALL(cdm_client_, OnSessionMessage(NotEmpty(), _, IsJSONDictionary()));
   cdm_->CreateSessionAndGenerateRequest(
-      ContentDecryptionModule::TEMPORARY_SESSION, EmeInitDataType::WEBM,
+      CdmSessionType::TEMPORARY_SESSION, EmeInitDataType::WEBM,
       std::vector<uint8_t>(1), CreateSessionPromise(RESOLVED));
 }
 
@@ -540,12 +540,12 @@
 #if defined(USE_PROPRIETARY_CODECS)
   EXPECT_CALL(cdm_client_, OnSessionMessage(NotEmpty(), _, IsJSONDictionary()));
   cdm_->CreateSessionAndGenerateRequest(
-      ContentDecryptionModule::TEMPORARY_SESSION, EmeInitDataType::CENC,
+      CdmSessionType::TEMPORARY_SESSION, EmeInitDataType::CENC,
       std::vector<uint8_t>(init_data, init_data + arraysize(init_data)),
       CreateSessionPromise(RESOLVED));
 #else
   cdm_->CreateSessionAndGenerateRequest(
-      ContentDecryptionModule::TEMPORARY_SESSION, EmeInitDataType::CENC,
+      CdmSessionType::TEMPORARY_SESSION, EmeInitDataType::CENC,
       std::vector<uint8_t>(init_data, init_data + arraysize(init_data)),
       CreateSessionPromise(REJECTED));
 #endif
@@ -557,7 +557,7 @@
 
   EXPECT_CALL(cdm_client_, OnSessionMessage(NotEmpty(), _, IsJSONDictionary()));
   cdm_->CreateSessionAndGenerateRequest(
-      ContentDecryptionModule::TEMPORARY_SESSION, EmeInitDataType::KEYIDS,
+      CdmSessionType::TEMPORARY_SESSION, EmeInitDataType::KEYIDS,
       std::vector<uint8_t>(init_data, init_data + arraysize(init_data) - 1),
       CreateSessionPromise(RESOLVED));
 }
diff --git a/media/cdm/cdm_adapter.cc b/media/cdm/cdm_adapter.cc
index d2a977f..2d0bd6c 100644
--- a/media/cdm/cdm_adapter.cc
+++ b/media/cdm/cdm_adapter.cc
@@ -35,18 +35,17 @@
 
 namespace {
 
-cdm::SessionType ToCdmSessionType(
-    ContentDecryptionModule::SessionType session_type) {
+cdm::SessionType ToCdmSessionType(CdmSessionType session_type) {
   switch (session_type) {
-    case ContentDecryptionModule::TEMPORARY_SESSION:
+    case CdmSessionType::TEMPORARY_SESSION:
       return cdm::kTemporary;
-    case ContentDecryptionModule::PERSISTENT_LICENSE_SESSION:
+    case CdmSessionType::PERSISTENT_LICENSE_SESSION:
       return cdm::kPersistentLicense;
-    case ContentDecryptionModule::PERSISTENT_RELEASE_MESSAGE_SESSION:
+    case CdmSessionType::PERSISTENT_RELEASE_MESSAGE_SESSION:
       return cdm::kPersistentKeyRelease;
   }
 
-  NOTREACHED() << "Unexpected SessionType " << session_type;
+  NOTREACHED() << "Unexpected session type: " << static_cast<int>(session_type);
   return cdm::kTemporary;
 }
 
@@ -450,7 +449,7 @@
 }
 
 void CdmAdapter::CreateSessionAndGenerateRequest(
-    SessionType session_type,
+    CdmSessionType session_type,
     EmeInitDataType init_data_type,
     const std::vector<uint8_t>& init_data,
     std::unique_ptr<NewSessionCdmPromise> promise) {
@@ -462,7 +461,7 @@
       ToCdmInitDataType(init_data_type), init_data.data(), init_data.size());
 }
 
-void CdmAdapter::LoadSession(SessionType session_type,
+void CdmAdapter::LoadSession(CdmSessionType session_type,
                              const std::string& session_id,
                              std::unique_ptr<NewSessionCdmPromise> promise) {
   DCHECK(task_runner_->BelongsToCurrentThread());
diff --git a/media/cdm/cdm_adapter.h b/media/cdm/cdm_adapter.h
index 511bf36..837a8f3 100644
--- a/media/cdm/cdm_adapter.h
+++ b/media/cdm/cdm_adapter.h
@@ -71,11 +71,11 @@
   void SetServerCertificate(const std::vector<uint8_t>& certificate,
                             std::unique_ptr<SimpleCdmPromise> promise) final;
   void CreateSessionAndGenerateRequest(
-      SessionType session_type,
+      CdmSessionType session_type,
       EmeInitDataType init_data_type,
       const std::vector<uint8_t>& init_data,
       std::unique_ptr<NewSessionCdmPromise> promise) final;
-  void LoadSession(SessionType session_type,
+  void LoadSession(CdmSessionType session_type,
                    const std::string& session_id,
                    std::unique_ptr<NewSessionCdmPromise> promise) final;
   void UpdateSession(const std::string& session_id,
diff --git a/media/cdm/cdm_adapter_unittest.cc b/media/cdm/cdm_adapter_unittest.cc
index 2b1d309..ad5194a 100644
--- a/media/cdm/cdm_adapter_unittest.cc
+++ b/media/cdm/cdm_adapter_unittest.cc
@@ -117,7 +117,7 @@
     }
 
     adapter_->CreateSessionAndGenerateRequest(
-        ContentDecryptionModule::TEMPORARY_SESSION, data_type, key_id,
+        CdmSessionType::TEMPORARY_SESSION, data_type, key_id,
         CreateSessionPromise(expected_result));
     RunUntilIdle();
   }
@@ -129,8 +129,8 @@
     DCHECK(!session_id.empty());
     ASSERT_EQ(expected_result, FAILURE) << "LoadSession not supported.";
 
-    adapter_->LoadSession(ContentDecryptionModule::TEMPORARY_SESSION,
-                          session_id, CreateSessionPromise(expected_result));
+    adapter_->LoadSession(CdmSessionType::TEMPORARY_SESSION, session_id,
+                          CreateSessionPromise(expected_result));
     RunUntilIdle();
   }
 
diff --git a/media/cdm/json_web_key.cc b/media/cdm/json_web_key.cc
index 3a6b9ad..fb70224 100644
--- a/media/cdm/json_web_key.cc
+++ b/media/cdm/json_web_key.cc
@@ -18,6 +18,7 @@
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "base/values.h"
+#include "media/base/content_decryption_module.h"
 
 namespace media {
 
@@ -85,7 +86,7 @@
 }
 
 std::string GenerateJWKSet(const KeyIdAndKeyPairs& keys,
-                           ContentDecryptionModule::SessionType session_type) {
+                           CdmSessionType session_type) {
   std::unique_ptr<base::ListValue> list(new base::ListValue());
   for (const auto& key_pair : keys) {
     list->Append(CreateJSONDictionary(
@@ -98,13 +99,13 @@
   base::DictionaryValue jwk_set;
   jwk_set.Set(kKeysTag, list.release());
   switch (session_type) {
-    case ContentDecryptionModule::TEMPORARY_SESSION:
+    case CdmSessionType::TEMPORARY_SESSION:
       jwk_set.SetString(kTypeTag, kTemporarySession);
       break;
-    case ContentDecryptionModule::PERSISTENT_LICENSE_SESSION:
+    case CdmSessionType::PERSISTENT_LICENSE_SESSION:
       jwk_set.SetString(kTypeTag, kPersistentLicenseSession);
       break;
-    case ContentDecryptionModule::PERSISTENT_RELEASE_MESSAGE_SESSION:
+    case CdmSessionType::PERSISTENT_RELEASE_MESSAGE_SESSION:
       jwk_set.SetString(kTypeTag, kPersistentReleaseMessageSession);
       break;
   }
@@ -164,7 +165,7 @@
 
 bool ExtractKeysFromJWKSet(const std::string& jwk_set,
                            KeyIdAndKeyPairs* keys,
-                           ContentDecryptionModule::SessionType* session_type) {
+                           CdmSessionType* session_type) {
   if (!base::IsStringASCII(jwk_set)) {
     DVLOG(1) << "Non ASCII JWK Set: " << jwk_set;
     return false;
@@ -210,16 +211,16 @@
   std::string session_type_id;
   if (!dictionary->Get(kTypeTag, &value)) {
     // Not specified, so use the default type.
-    *session_type = ContentDecryptionModule::TEMPORARY_SESSION;
+    *session_type = CdmSessionType::TEMPORARY_SESSION;
   } else if (!value->GetAsString(&session_type_id)) {
     DVLOG(1) << "Invalid '" << kTypeTag << "' value";
     return false;
   } else if (session_type_id == kTemporarySession) {
-    *session_type = ContentDecryptionModule::TEMPORARY_SESSION;
+    *session_type = CdmSessionType::TEMPORARY_SESSION;
   } else if (session_type_id == kPersistentLicenseSession) {
-    *session_type = ContentDecryptionModule::PERSISTENT_LICENSE_SESSION;
+    *session_type = CdmSessionType::PERSISTENT_LICENSE_SESSION;
   } else if (session_type_id == kPersistentReleaseMessageSession) {
-    *session_type = ContentDecryptionModule::PERSISTENT_RELEASE_MESSAGE_SESSION;
+    *session_type = CdmSessionType::PERSISTENT_RELEASE_MESSAGE_SESSION;
   } else {
     DVLOG(1) << "Invalid '" << kTypeTag << "' value: " << session_type_id;
     return false;
@@ -298,7 +299,7 @@
 }
 
 void CreateLicenseRequest(const KeyIdList& key_ids,
-                          ContentDecryptionModule::SessionType session_type,
+                          CdmSessionType session_type,
                           std::vector<uint8_t>* license) {
   // Create the license request.
   std::unique_ptr<base::DictionaryValue> request(new base::DictionaryValue());
@@ -315,13 +316,13 @@
   request->Set(kKeyIdsTag, list.release());
 
   switch (session_type) {
-    case ContentDecryptionModule::TEMPORARY_SESSION:
+    case CdmSessionType::TEMPORARY_SESSION:
       request->SetString(kTypeTag, kTemporarySession);
       break;
-    case ContentDecryptionModule::PERSISTENT_LICENSE_SESSION:
+    case CdmSessionType::PERSISTENT_LICENSE_SESSION:
       request->SetString(kTypeTag, kPersistentLicenseSession);
       break;
-    case ContentDecryptionModule::PERSISTENT_RELEASE_MESSAGE_SESSION:
+    case CdmSessionType::PERSISTENT_RELEASE_MESSAGE_SESSION:
       request->SetString(kTypeTag, kPersistentReleaseMessageSession);
       break;
   }
diff --git a/media/cdm/json_web_key.h b/media/cdm/json_web_key.h
index be48828c..143b5a0 100644
--- a/media/cdm/json_web_key.h
+++ b/media/cdm/json_web_key.h
@@ -11,7 +11,6 @@
 #include <utility>
 #include <vector>
 
-#include "media/base/content_decryption_module.h"
 #include "media/base/media_export.h"
 
 namespace media {
@@ -49,6 +48,8 @@
 // Ref: http://tools.ietf.org/html/draft-ietf-jose-json-web-key and:
 // http://tools.ietf.org/html/draft-jones-jose-json-private-and-symmetric-key
 
+enum class CdmSessionType;
+
 // Vector of key IDs.
 typedef std::vector<std::vector<uint8_t>> KeyIdList;
 
@@ -64,17 +65,15 @@
                                         int key_id_length);
 
 // Converts a set of |key|, |key_id| pairs to a JSON Web Key Set.
-MEDIA_EXPORT std::string GenerateJWKSet(
-    const KeyIdAndKeyPairs& keys,
-    ContentDecryptionModule::SessionType session_type);
+MEDIA_EXPORT std::string GenerateJWKSet(const KeyIdAndKeyPairs& keys,
+                                        CdmSessionType session_type);
 
 // Extracts the JSON Web Keys from a JSON Web Key Set. If |input| looks like
 // a valid JWK Set, then true is returned and |keys| and |session_type| are
 // updated to contain the values found. Otherwise return false.
-MEDIA_EXPORT bool ExtractKeysFromJWKSet(
-    const std::string& jwk_set,
-    KeyIdAndKeyPairs* keys,
-    ContentDecryptionModule::SessionType* session_type);
+MEDIA_EXPORT bool ExtractKeysFromJWKSet(const std::string& jwk_set,
+                                        KeyIdAndKeyPairs* keys,
+                                        CdmSessionType* session_type);
 
 // Extracts the Key Ids from a Key IDs Initialization Data
 // (https://w3c.github.io/encrypted-media/keyids-format.html). If |input| looks
@@ -86,10 +85,9 @@
 
 // Creates a license request message for the |key_ids| and |session_type|
 // specified. |license| is updated to contain the resulting JSON string.
-MEDIA_EXPORT void CreateLicenseRequest(
-    const KeyIdList& key_ids,
-    ContentDecryptionModule::SessionType session_type,
-    std::vector<uint8_t>* license);
+MEDIA_EXPORT void CreateLicenseRequest(const KeyIdList& key_ids,
+                                       CdmSessionType session_type,
+                                       std::vector<uint8_t>* license);
 
 // Creates a keyIDs init_data message for the |key_ids| specified.
 // |key_ids_init_data| is updated to contain the resulting JSON string.
diff --git a/media/cdm/json_web_key_unittest.cc b/media/cdm/json_web_key_unittest.cc
index 074265a66..d0ba9711 100644
--- a/media/cdm/json_web_key_unittest.cc
+++ b/media/cdm/json_web_key_unittest.cc
@@ -25,19 +25,18 @@
                                size_t expected_number_of_keys) {
     DCHECK(!jwk.empty());
     KeyIdAndKeyPairs keys;
-    ContentDecryptionModule::SessionType session_type;
+    CdmSessionType session_type;
     EXPECT_EQ(expected_result,
               ExtractKeysFromJWKSet(jwk, &keys, &session_type));
     EXPECT_EQ(expected_number_of_keys, keys.size());
   }
 
-  void ExtractSessionTypeAndExpect(
-      const std::string& jwk,
-      bool expected_result,
-      ContentDecryptionModule::SessionType expected_type) {
+  void ExtractSessionTypeAndExpect(const std::string& jwk,
+                                   bool expected_result,
+                                   CdmSessionType expected_type) {
     DCHECK(!jwk.empty());
     KeyIdAndKeyPairs keys;
-    ContentDecryptionModule::SessionType session_type;
+    CdmSessionType session_type;
     EXPECT_EQ(expected_result,
               ExtractKeysFromJWKSet(jwk, &keys, &session_type));
     if (expected_result) {
@@ -48,7 +47,7 @@
 
   void CreateLicenseAndExpect(const uint8_t* key_id,
                               int key_id_length,
-                              ContentDecryptionModule::SessionType session_type,
+                              CdmSessionType session_type,
                               const std::string& expected_result) {
     std::vector<uint8_t> result;
     KeyIdList key_ids;
@@ -113,15 +112,14 @@
   EXPECT_EQ(
       "{\"keys\":[{\"k\":\"AQI\",\"kid\":\"AQI\",\"kty\":\"oct\"}],\"type\":"
       "\"temporary\"}",
-      GenerateJWKSet(keys, ContentDecryptionModule::TEMPORARY_SESSION));
+      GenerateJWKSet(keys, CdmSessionType::TEMPORARY_SESSION));
   keys.push_back(
       MakeKeyIdAndKeyPair(data2, arraysize(data2), data2, arraysize(data2)));
   EXPECT_EQ(
       "{\"keys\":[{\"k\":\"AQI\",\"kid\":\"AQI\",\"kty\":\"oct\"},{\"k\":"
       "\"AQIDBA\",\"kid\":\"AQIDBA\",\"kty\":\"oct\"}],\"type\":\"persistent-"
       "license\"}",
-      GenerateJWKSet(keys,
-                     ContentDecryptionModule::PERSISTENT_LICENSE_SESSION));
+      GenerateJWKSet(keys, CdmSessionType::PERSISTENT_LICENSE_SESSION));
   keys.push_back(
       MakeKeyIdAndKeyPair(data3, arraysize(data3), data3, arraysize(data3)));
   EXPECT_EQ(
@@ -129,8 +127,7 @@
       "\"AQIDBA\",\"kid\":\"AQIDBA\",\"kty\":\"oct\"},{\"k\":"
       "\"AQIDBAUGBwgJCgsMDQ4PEA\",\"kid\":\"AQIDBAUGBwgJCgsMDQ4PEA\",\"kty\":"
       "\"oct\"}],\"type\":\"persistent-release-message\"}",
-      GenerateJWKSet(
-          keys, ContentDecryptionModule::PERSISTENT_RELEASE_MESSAGE_SESSION));
+      GenerateJWKSet(keys, CdmSessionType::PERSISTENT_RELEASE_MESSAGE_SESSION));
 }
 
 TEST_F(JSONWebKeyTest, ExtractValidJWKKeys) {
@@ -398,29 +395,29 @@
   ExtractJWKKeysAndExpect(kJwksWithWrongAlg, true, 1);
 }
 
-TEST_F(JSONWebKeyTest, SessionType) {
+TEST_F(JSONWebKeyTest, CdmSessionType) {
   ExtractSessionTypeAndExpect(
       "{\"keys\":[{\"k\":\"AQI\",\"kid\":\"AQI\",\"kty\":\"oct\"}]}", true,
-      ContentDecryptionModule::TEMPORARY_SESSION);
+      CdmSessionType::TEMPORARY_SESSION);
   ExtractSessionTypeAndExpect(
       "{\"keys\":[{\"k\":\"AQI\",\"kid\":\"AQI\",\"kty\":\"oct\"}],\"type\":"
       "\"temporary\"}",
-      true, ContentDecryptionModule::TEMPORARY_SESSION);
+      true, CdmSessionType::TEMPORARY_SESSION);
   ExtractSessionTypeAndExpect(
       "{\"keys\":[{\"k\":\"AQI\",\"kid\":\"AQI\",\"kty\":\"oct\"}],\"type\":"
       "\"persistent-license\"}",
-      true, ContentDecryptionModule::PERSISTENT_LICENSE_SESSION);
+      true, CdmSessionType::PERSISTENT_LICENSE_SESSION);
   ExtractSessionTypeAndExpect(
       "{\"keys\":[{\"k\":\"AQI\",\"kid\":\"AQI\",\"kty\":\"oct\"}],\"type\":"
       "\"persistent-release-message\"}",
-      true, ContentDecryptionModule::PERSISTENT_RELEASE_MESSAGE_SESSION);
+      true, CdmSessionType::PERSISTENT_RELEASE_MESSAGE_SESSION);
   ExtractSessionTypeAndExpect(
       "{\"keys\":[{\"k\":\"AQI\",\"kid\":\"AQI\",\"kty\":\"oct\"}],\"type\":"
       "\"unknown\"}",
-      false, ContentDecryptionModule::TEMPORARY_SESSION);
+      false, CdmSessionType::TEMPORARY_SESSION);
   ExtractSessionTypeAndExpect(
       "{\"keys\":[{\"k\":\"AQI\",\"kid\":\"AQI\",\"kty\":\"oct\"}],\"type\":3}",
-      false, ContentDecryptionModule::TEMPORARY_SESSION);
+      false, CdmSessionType::TEMPORARY_SESSION);
 }
 
 TEST_F(JSONWebKeyTest, CreateLicense) {
@@ -430,21 +427,20 @@
                            0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10};
 
   CreateLicenseAndExpect(data1, arraysize(data1),
-                         ContentDecryptionModule::TEMPORARY_SESSION,
+                         CdmSessionType::TEMPORARY_SESSION,
                          "{\"kids\":[\"AQI\"],\"type\":\"temporary\"}");
   CreateLicenseAndExpect(
-      data1, arraysize(data1),
-      ContentDecryptionModule::PERSISTENT_LICENSE_SESSION,
+      data1, arraysize(data1), CdmSessionType::PERSISTENT_LICENSE_SESSION,
       "{\"kids\":[\"AQI\"],\"type\":\"persistent-license\"}");
   CreateLicenseAndExpect(
       data1, arraysize(data1),
-      ContentDecryptionModule::PERSISTENT_RELEASE_MESSAGE_SESSION,
+      CdmSessionType::PERSISTENT_RELEASE_MESSAGE_SESSION,
       "{\"kids\":[\"AQI\"],\"type\":\"persistent-release-message\"}");
   CreateLicenseAndExpect(data2, arraysize(data2),
-                         ContentDecryptionModule::TEMPORARY_SESSION,
+                         CdmSessionType::TEMPORARY_SESSION,
                          "{\"kids\":[\"AQIDBA\"],\"type\":\"temporary\"}");
   CreateLicenseAndExpect(data3, arraysize(data3),
-                         ContentDecryptionModule::PERSISTENT_LICENSE_SESSION,
+                         CdmSessionType::PERSISTENT_LICENSE_SESSION,
                          "{\"kids\":[\"AQIDBAUGBwgJCgsMDQ4PEA\"],\"type\":"
                          "\"persistent-license\"}");
 }
@@ -511,7 +507,7 @@
   EXPECT_EQ(encoded_text.find('_'), std::string::npos);
 
   CreateLicenseAndExpect(data1, arraysize(data1),
-                         ContentDecryptionModule::TEMPORARY_SESSION,
+                         CdmSessionType::TEMPORARY_SESSION,
                          "{\"kids\":[\"-_37_fv9-w\"],\"type\":\"temporary\"}");
 
   ExtractKeyFromLicenseAndExpect(
@@ -530,8 +526,7 @@
   key_ids.push_back(std::vector<uint8_t>(data1, data1 + arraysize(data1)));
   key_ids.push_back(std::vector<uint8_t>(data2, data2 + arraysize(data2)));
   key_ids.push_back(std::vector<uint8_t>(data3, data3 + arraysize(data3)));
-  CreateLicenseRequest(key_ids, ContentDecryptionModule::TEMPORARY_SESSION,
-                       &result);
+  CreateLicenseRequest(key_ids, CdmSessionType::TEMPORARY_SESSION, &result);
   std::string s(result.begin(), result.end());
   EXPECT_EQ(
       "{\"kids\":[\"AQI\",\"AQIDBA\",\"AQIDBAUGBwgJCgsMDQ4PEA\"],\"type\":"
diff --git a/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc b/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
index 3946ab6..4820555 100644
--- a/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
+++ b/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
@@ -145,18 +145,17 @@
   return cdm::kUnknownError;
 }
 
-static media::ContentDecryptionModule::SessionType ConvertSessionType(
-    cdm::SessionType session_type) {
+static media::CdmSessionType ConvertSessionType(cdm::SessionType session_type) {
   switch (session_type) {
     case cdm::kTemporary:
-      return media::ContentDecryptionModule::TEMPORARY_SESSION;
+      return media::CdmSessionType::TEMPORARY_SESSION;
     case cdm::kPersistentLicense:
-      return media::ContentDecryptionModule::PERSISTENT_LICENSE_SESSION;
+      return media::CdmSessionType::PERSISTENT_LICENSE_SESSION;
     case cdm::kPersistentKeyRelease:
-      return media::ContentDecryptionModule::PERSISTENT_RELEASE_MESSAGE_SESSION;
+      return media::CdmSessionType::PERSISTENT_RELEASE_MESSAGE_SESSION;
   }
   NOTREACHED();
-  return media::ContentDecryptionModule::TEMPORARY_SESSION;
+  return media::CdmSessionType::TEMPORARY_SESSION;
 }
 
 static media::EmeInitDataType ConvertInitDataType(
@@ -351,9 +350,9 @@
   std::vector<uint8_t> key_id(
       kLoadableSessionKeyId,
       kLoadableSessionKeyId + arraysize(kLoadableSessionKeyId) - 1);
-  decryptor_->CreateSessionAndGenerateRequest(
-      ContentDecryptionModule::TEMPORARY_SESSION, EmeInitDataType::WEBM, key_id,
-      std::move(promise));
+  decryptor_->CreateSessionAndGenerateRequest(CdmSessionType::TEMPORARY_SESSION,
+                                              EmeInitDataType::WEBM, key_id,
+                                              std::move(promise));
 }
 
 void ClearKeyCdm::UpdateSession(uint32_t promise_id,
diff --git a/media/mojo/clients/mojo_cdm.cc b/media/mojo/clients/mojo_cdm.cc
index 494149e9..471647b 100644
--- a/media/mojo/clients/mojo_cdm.cc
+++ b/media/mojo/clients/mojo_cdm.cc
@@ -160,7 +160,7 @@
 }
 
 void MojoCdm::CreateSessionAndGenerateRequest(
-    SessionType session_type,
+    CdmSessionType session_type,
     EmeInitDataType init_data_type,
     const std::vector<uint8_t>& init_data,
     std::unique_ptr<NewSessionCdmPromise> promise) {
@@ -179,7 +179,7 @@
                  base::Passed(&promise)));
 }
 
-void MojoCdm::LoadSession(SessionType session_type,
+void MojoCdm::LoadSession(CdmSessionType session_type,
                           const std::string& session_id,
                           std::unique_ptr<NewSessionCdmPromise> promise) {
   DVLOG(2) << __func__;
diff --git a/media/mojo/clients/mojo_cdm.h b/media/mojo/clients/mojo_cdm.h
index 33f4c774..e72b5352 100644
--- a/media/mojo/clients/mojo_cdm.h
+++ b/media/mojo/clients/mojo_cdm.h
@@ -54,11 +54,11 @@
   void SetServerCertificate(const std::vector<uint8_t>& certificate,
                             std::unique_ptr<SimpleCdmPromise> promise) final;
   void CreateSessionAndGenerateRequest(
-      SessionType session_type,
+      CdmSessionType session_type,
       EmeInitDataType init_data_type,
       const std::vector<uint8_t>& init_data,
       std::unique_ptr<NewSessionCdmPromise> promise) final;
-  void LoadSession(SessionType session_type,
+  void LoadSession(CdmSessionType session_type,
                    const std::string& session_id,
                    std::unique_ptr<NewSessionCdmPromise> promise) final;
   void UpdateSession(const std::string& session_id,
diff --git a/media/mojo/clients/mojo_cdm_unittest.cc b/media/mojo/clients/mojo_cdm_unittest.cc
index 2a8afa8..43c7da4 100644
--- a/media/mojo/clients/mojo_cdm_unittest.cc
+++ b/media/mojo/clients/mojo_cdm_unittest.cc
@@ -128,9 +128,9 @@
     }
 
     mojo_cdm_->CreateSessionAndGenerateRequest(
-        ContentDecryptionModule::SessionType::TEMPORARY_SESSION, data_type,
-        key_id, base::MakeUnique<MockCdmSessionPromise>(
-                    expected_result == SUCCESS, &session_id_));
+        CdmSessionType::TEMPORARY_SESSION, data_type, key_id,
+        base::MakeUnique<MockCdmSessionPromise>(expected_result == SUCCESS,
+                                                &session_id_));
 
     base::RunLoop().RunUntilIdle();
   }
diff --git a/media/mojo/interfaces/content_decryption_module.mojom b/media/mojo/interfaces/content_decryption_module.mojom
index 0eab133..5c02bd3 100644
--- a/media/mojo/interfaces/content_decryption_module.mojom
+++ b/media/mojo/interfaces/content_decryption_module.mojom
@@ -50,7 +50,7 @@
 // spec (https://w3c.github.io/encrypted-media/).
 // See media/base/content_decryption_module.h
 interface ContentDecryptionModule {
-  // See media::ContentDecryptionModule::SessionType
+  // See media::CdmSessionType
   [Native]
   enum SessionType;
 
diff --git a/media/mojo/interfaces/content_decryption_module.typemap b/media/mojo/interfaces/content_decryption_module.typemap
index ad8ad18..7aadbc9c 100644
--- a/media/mojo/interfaces/content_decryption_module.typemap
+++ b/media/mojo/interfaces/content_decryption_module.typemap
@@ -21,7 +21,7 @@
 type_mappings = [
   "media.mojom.CdmKeyInformation.KeyStatus=media::CdmKeyInformation::KeyStatus",
   "media.mojom.CdmPromiseResult.Exception=media::CdmPromise::Exception",
-  "media.mojom.ContentDecryptionModule.SessionType=media::ContentDecryptionModule::SessionType",
+  "media.mojom.ContentDecryptionModule.SessionType=media::CdmSessionType",
   "media.mojom.ContentDecryptionModuleClient.MessageType=media::ContentDecryptionModule::MessageType",
   "media.mojom.EmeInitDataType=media::EmeInitDataType",
 ]
diff --git a/media/mojo/services/mojo_cdm_service.cc b/media/mojo/services/mojo_cdm_service.cc
index ab3ce9a..a5bed7c0 100644
--- a/media/mojo/services/mojo_cdm_service.cc
+++ b/media/mojo/services/mojo_cdm_service.cc
@@ -129,7 +129,7 @@
 }
 
 void MojoCdmService::CreateSessionAndGenerateRequest(
-    SessionType session_type,
+    CdmSessionType session_type,
     EmeInitDataType init_data_type,
     const std::vector<uint8_t>& init_data,
     const CreateSessionAndGenerateRequestCallback& callback) {
@@ -139,7 +139,7 @@
       base::MakeUnique<NewSessionMojoCdmPromise>(callback));
 }
 
-void MojoCdmService::LoadSession(SessionType session_type,
+void MojoCdmService::LoadSession(CdmSessionType session_type,
                                  const std::string& session_id,
                                  const LoadSessionCallback& callback) {
   DVLOG(2) << __func__;
diff --git a/media/mojo/services/mojo_cdm_service.h b/media/mojo/services/mojo_cdm_service.h
index 233b9ad3..892001f 100644
--- a/media/mojo/services/mojo_cdm_service.h
+++ b/media/mojo/services/mojo_cdm_service.h
@@ -31,8 +31,6 @@
 class MEDIA_MOJO_EXPORT MojoCdmService
     : NON_EXPORTED_BASE(public mojom::ContentDecryptionModule) {
  public:
-  using SessionType = ::media::ContentDecryptionModule::SessionType;
-
   // Get the CDM associated with |cdm_id|, which is unique per process.
   // Can be called on any thread. The returned CDM is not guaranteed to be
   // thread safe.
@@ -59,11 +57,11 @@
   void SetServerCertificate(const std::vector<uint8_t>& certificate_data,
                             const SetServerCertificateCallback& callback) final;
   void CreateSessionAndGenerateRequest(
-      SessionType session_type,
+      CdmSessionType session_type,
       EmeInitDataType init_data_type,
       const std::vector<uint8_t>& init_data,
       const CreateSessionAndGenerateRequestCallback& callback) final;
-  void LoadSession(SessionType session_type,
+  void LoadSession(CdmSessionType session_type,
                    const std::string& session_id,
                    const LoadSessionCallback& callback) final;
   void UpdateSession(const std::string& session_id,
diff --git a/media/remoting/proto/remoting_rpc_message.proto b/media/remoting/proto/remoting_rpc_message.proto
index eb50b0b8..0a351db0c 100644
--- a/media/remoting/proto/remoting_rpc_message.proto
+++ b/media/remoting/proto/remoting_rpc_message.proto
@@ -278,7 +278,7 @@
   LICENSE_RELEASE = 2;
 }
 
-// Should align with ::media::ContentDecryptionModule::SessionType
+// Should align with ::media::CdmSessionType
 enum CdmSessionType {
   TEMPORARY_SESSION = 0;
   PERSISTENT_LICENSE_SESSION = 1;
diff --git a/media/remoting/remoting_cdm.cc b/media/remoting/remoting_cdm.cc
index 8e2aa05..b34eeed 100644
--- a/media/remoting/remoting_cdm.cc
+++ b/media/remoting/remoting_cdm.cc
@@ -36,7 +36,7 @@
 }
 
 void RemotingCdm::CreateSessionAndGenerateRequest(
-    SessionType session_type,
+    CdmSessionType session_type,
     EmeInitDataType init_data_type,
     const std::vector<uint8_t>& init_data,
     std::unique_ptr<NewSessionCdmPromise> promise) {
@@ -44,7 +44,7 @@
   NOTIMPLEMENTED();
 }
 
-void RemotingCdm::LoadSession(SessionType session_type,
+void RemotingCdm::LoadSession(CdmSessionType session_type,
                               const std::string& session_id,
                               std::unique_ptr<NewSessionCdmPromise> promise) {
   // TODO(xjz): Merge with erickung's implementation.
diff --git a/media/remoting/remoting_cdm.h b/media/remoting/remoting_cdm.h
index 78f61d7..466dfdf25b 100644
--- a/media/remoting/remoting_cdm.h
+++ b/media/remoting/remoting_cdm.h
@@ -29,11 +29,11 @@
   void SetServerCertificate(const std::vector<uint8_t>& certificate,
                             std::unique_ptr<SimpleCdmPromise> promise) override;
   void CreateSessionAndGenerateRequest(
-      SessionType session_type,
+      CdmSessionType session_type,
       EmeInitDataType init_data_type,
       const std::vector<uint8_t>& init_data,
       std::unique_ptr<NewSessionCdmPromise> promise) override;
-  void LoadSession(SessionType session_type,
+  void LoadSession(CdmSessionType session_type,
                    const std::string& session_id,
                    std::unique_ptr<NewSessionCdmPromise> promise) override;
   void UpdateSession(const std::string& session_id,
diff --git a/media/remoting/rpc/proto_enum_utils.cc b/media/remoting/rpc/proto_enum_utils.cc
index 3ed41dd..93a1c2e 100644
--- a/media/remoting/rpc/proto_enum_utils.cc
+++ b/media/remoting/rpc/proto_enum_utils.cc
@@ -513,10 +513,10 @@
   return base::nullopt;  // Not a 'default' to ensure compile-time checks.
 }
 
-base::Optional<::media::ContentDecryptionModule::SessionType> ToCdmSessionType(
+base::Optional<::media::CdmSessionType> ToCdmSessionType(
     pb::CdmSessionType value) {
   using OriginType = pb::CdmSessionType;
-  using OtherType = ::media::ContentDecryptionModule;
+  using OtherType = ::media::CdmSessionType;
   switch (value) {
     CASE_RETURN_OTHER(TEMPORARY_SESSION);
     CASE_RETURN_OTHER(PERSISTENT_LICENSE_SESSION);
@@ -526,8 +526,8 @@
 }
 
 base::Optional<pb::CdmSessionType> ToProtoCdmSessionType(
-    ::media::ContentDecryptionModule::SessionType value) {
-  using OriginType = ::media::ContentDecryptionModule;
+    ::media::CdmSessionType value) {
+  using OriginType = ::media::CdmSessionType;
   using OtherType = pb::CdmSessionType;
   switch (value) {
     CASE_RETURN_OTHER(TEMPORARY_SESSION);
diff --git a/media/remoting/rpc/proto_enum_utils.h b/media/remoting/rpc/proto_enum_utils.h
index b5384bb..19dee91 100644
--- a/media/remoting/rpc/proto_enum_utils.h
+++ b/media/remoting/rpc/proto_enum_utils.h
@@ -91,10 +91,10 @@
 base::Optional<pb::CdmMessageType> ToProtoCdmMessageType(
     ::media::ContentDecryptionModule::MessageType value);
 
-base::Optional<::media::ContentDecryptionModule::SessionType> ToCdmSessionType(
+base::Optional<::media::CdmSessionType> ToCdmSessionType(
     pb::CdmSessionType value);
 base::Optional<pb::CdmSessionType> ToProtoCdmSessionType(
-    ::media::ContentDecryptionModule::SessionType value);
+    ::media::CdmSessionType value);
 
 base::Optional<::media::EmeInitDataType> ToMediaEmeInitDataType(
     pb::CdmCreateSessionAndGenerateRequest::EmeInitDataType value);
diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc
index 57b6d96..652398f 100644
--- a/media/test/pipeline_integration_test.cc
+++ b/media/test/pipeline_integration_test.cc
@@ -365,7 +365,7 @@
 
     if (current_session_id_.empty()) {
       decryptor->CreateSessionAndGenerateRequest(
-          ContentDecryptionModule::TEMPORARY_SESSION, init_data_type, init_data,
+          CdmSessionType::TEMPORARY_SESSION, init_data_type, init_data,
           CreateSessionPromise(RESOLVED));
       EXPECT_FALSE(current_session_id_.empty());
     }
@@ -400,7 +400,7 @@
     ++num_distinct_need_key_calls_;
 
     decryptor->CreateSessionAndGenerateRequest(
-        ContentDecryptionModule::TEMPORARY_SESSION, init_data_type, init_data,
+        CdmSessionType::TEMPORARY_SESSION, init_data_type, init_data,
         CreateSessionPromise(RESOLVED));
   }
 
diff --git a/net/base/test_completion_callback_unittest.cc b/net/base/test_completion_callback_unittest.cc
index a2bc4909..db62f7e 100644
--- a/net/base/test_completion_callback_unittest.cc
+++ b/net/base/test_completion_callback_unittest.cc
@@ -2,15 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Illustrates how to use worker threads that issue completion callbacks
+// Illustrates how to use net::TestCompletionCallback.
 
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
 #include "base/single_thread_task_runner.h"
-#include "base/threading/worker_pool.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "net/base/completion_callback.h"
 #include "net/base/test_completion_callback.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -38,9 +37,8 @@
   ExampleEmployer();
   ~ExampleEmployer();
 
-  // Do some imaginary work on a worker thread;
-  // when done, worker posts callback on the original thread.
-  // Returns true on success
+  // Posts to the current thread a task which itself posts |callback| to the
+  // current thread. Returns true on success
   bool DoSomething(const CompletionCallback& callback);
 
  private:
@@ -50,14 +48,12 @@
   DISALLOW_COPY_AND_ASSIGN(ExampleEmployer);
 };
 
-// Helper class; this is how ExampleEmployer puts work on a different thread
+// Helper class; this is how ExampleEmployer schedules work.
 class ExampleEmployer::ExampleWorker
     : public base::RefCountedThreadSafe<ExampleWorker> {
  public:
   ExampleWorker(ExampleEmployer* employer, const CompletionCallback& callback)
-      : employer_(employer),
-        callback_(callback),
-        origin_loop_(base::MessageLoop::current()) {}
+      : employer_(employer), callback_(callback) {}
   void DoWork();
   void DoCallback();
  private:
@@ -69,23 +65,15 @@
   ExampleEmployer* employer_;
   CompletionCallback callback_;
   // Used to post ourselves onto the origin thread.
-  base::Lock origin_loop_lock_;
-  base::MessageLoop* origin_loop_;
+  const scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_ =
+      base::ThreadTaskRunnerHandle::Get();
 };
 
 void ExampleEmployer::ExampleWorker::DoWork() {
-  // Running on the worker thread
   // In a real worker thread, some work would be done here.
   // Pretend it is, and send the completion callback.
-
-  // The origin loop could go away while we are trying to post to it, so we
-  // need to call its PostTask method inside a lock.  See ~ExampleEmployer.
-  {
-    base::AutoLock locked(origin_loop_lock_);
-    if (origin_loop_)
-      origin_loop_->task_runner()->PostTask(
-          FROM_HERE, base::Bind(&ExampleWorker::DoCallback, this));
-  }
+  origin_task_runner_->PostTask(FROM_HERE,
+                                base::Bind(&ExampleWorker::DoCallback, this));
 }
 
 void ExampleEmployer::ExampleWorker::DoCallback() {
@@ -110,9 +98,8 @@
 
   request_ = new ExampleWorker(this, callback);
 
-  // Dispatch to worker thread...
-  if (!base::WorkerPool::PostTask(
-          FROM_HERE, base::Bind(&ExampleWorker::DoWork, request_), true)) {
+  if (!base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::Bind(&ExampleWorker::DoWork, request_))) {
     NOTREACHED();
     request_ = NULL;
     return false;
diff --git a/net/filter/gzip_source_stream.cc b/net/filter/gzip_source_stream.cc
index de1a2de..aff449f 100644
--- a/net/filter/gzip_source_stream.cc
+++ b/net/filter/gzip_source_stream.cc
@@ -10,6 +10,7 @@
 #include "base/bind.h"
 #include "base/bit_cast.h"
 #include "base/logging.h"
+#include "base/memory/ref_counted.h"
 #include "net/base/io_buffer.h"
 #include "third_party/zlib/zlib.h"
 
@@ -21,6 +22,14 @@
 const char kGzip[] = "GZIP";
 const char kGzipFallback[] = "GZIP_FALLBACK";
 
+// For deflate streams, if more than this many bytes have been received without
+// an error and without adding a Zlib header, assume the original stream had a
+// Zlib header. In practice, don't need nearly this much data, but since the
+// detection logic is a heuristic, best to be safe. Data is freed once it's been
+// determined whether the stream has a zlib header or not, so larger values
+// shouldn't affect memory usage, in practice.
+const int kMaxZlibHeaderSniffBytes = 1000;
+
 }  // namespace
 
 GzipSourceStream::~GzipSourceStream() {
@@ -42,9 +51,9 @@
 GzipSourceStream::GzipSourceStream(std::unique_ptr<SourceStream> upstream,
                                    SourceStream::SourceType type)
     : FilterSourceStream(type, std::move(upstream)),
-      zlib_header_added_(false),
       gzip_footer_bytes_left_(0),
-      input_state_(STATE_START) {}
+      input_state_(STATE_START),
+      replay_state_(STATE_COMPRESSED_BODY) {}
 
 bool GzipSourceStream::Init() {
   zlib_stream_.reset(new z_stream);
@@ -81,7 +90,7 @@
                                  IOBuffer* input_buffer,
                                  int input_buffer_size,
                                  int* consumed_bytes,
-                                 bool /*upstream_end_reached*/) {
+                                 bool upstream_end_reached) {
   *consumed_bytes = 0;
   char* input_data = input_buffer->data();
   int input_data_size = input_buffer_size;
@@ -92,7 +101,7 @@
     switch (state) {
       case STATE_START: {
         if (type() == TYPE_DEFLATE) {
-          input_state_ = STATE_COMPRESSED_BODY;
+          input_state_ = STATE_SNIFFING_DEFLATE_HEADER;
           break;
         }
         // If this stream is not really gzipped as detected by
@@ -106,6 +115,8 @@
         break;
       }
       case STATE_GZIP_HEADER: {
+        DCHECK_NE(TYPE_DEFLATE, type());
+
         const size_t kGzipFooterBytes = 8;
         const char* end = nullptr;
         GZipHeader::Status status =
@@ -125,6 +136,83 @@
         }
         break;
       }
+      case STATE_SNIFFING_DEFLATE_HEADER: {
+        DCHECK_EQ(TYPE_DEFLATE, type());
+
+        zlib_stream_.get()->next_in = bit_cast<Bytef*>(input_data);
+        zlib_stream_.get()->avail_in = input_data_size;
+        zlib_stream_.get()->next_out = bit_cast<Bytef*>(output_buffer->data());
+        zlib_stream_.get()->avail_out = output_buffer_size;
+
+        int ret = inflate(zlib_stream_.get(), Z_NO_FLUSH);
+
+        // On error, try adding a zlib header and replaying the response. Note
+        // that data just received doesn't have to be replayed, since it hasn't
+        // been removed from input_data yet, only data from previous FilterData
+        // calls needs to be replayed.
+        if (ret != Z_STREAM_END && ret != Z_OK) {
+          if (!InsertZlibHeader())
+            return ERR_CONTENT_DECODING_FAILED;
+
+          input_state_ = STATE_REPLAY_DATA;
+          // |replay_state_| should still have its initial value.
+          DCHECK_EQ(STATE_COMPRESSED_BODY, replay_state_);
+          break;
+        }
+
+        int bytes_used = input_data_size - zlib_stream_.get()->avail_in;
+        bytes_out = output_buffer_size - zlib_stream_.get()->avail_out;
+        // If any bytes are output, enough total bytes have been received, or at
+        // the end of the stream, assume the response had a valid Zlib header.
+        if (bytes_out > 0 ||
+            bytes_used + replay_data_.size() >= kMaxZlibHeaderSniffBytes ||
+            ret == Z_STREAM_END) {
+          std::move(replay_data_);
+          if (ret == Z_STREAM_END) {
+            input_state_ = STATE_GZIP_FOOTER;
+          } else {
+            input_state_ = STATE_COMPRESSED_BODY;
+          }
+        } else {
+          replay_data_.append(input_data, bytes_used);
+        }
+
+        input_data_size -= bytes_used;
+        input_data += bytes_used;
+        break;
+      }
+      case STATE_REPLAY_DATA: {
+        DCHECK_EQ(TYPE_DEFLATE, type());
+
+        if (replay_data_.empty()) {
+          std::move(replay_data_);
+          input_state_ = replay_state_;
+          break;
+        }
+
+        // Call FilterData recursively, after updating |input_state_|, with
+        // |replay_data_|. This recursive call makes handling data from
+        // |replay_data_| and |input_buffer| much simpler than the alternative
+        // operations, though it's not pretty.
+        input_state_ = replay_state_;
+        int bytes_used;
+        scoped_refptr<IOBuffer> replay_buffer(
+            new WrappedIOBuffer(replay_data_.data()));
+        int result =
+            FilterData(output_buffer, output_buffer_size, replay_buffer.get(),
+                       replay_data_.size(), &bytes_used, upstream_end_reached);
+        replay_data_.erase(0, bytes_used);
+        // Back up resulting state, and return state to STATE_REPLAY_DATA.
+        replay_state_ = input_state_;
+        input_state_ = STATE_REPLAY_DATA;
+
+        // On error, or if bytes were read, just return result immediately.
+        // Could continue consuming data in the success case, but simplest not
+        // to.
+        if (result != 0)
+          return result;
+        break;
+      }
       case STATE_COMPRESSED_BODY: {
         DCHECK(!state_compressed_entered);
         DCHECK_LE(0, input_data_size);
@@ -136,25 +224,6 @@
         zlib_stream_.get()->avail_out = output_buffer_size;
 
         int ret = inflate(zlib_stream_.get(), Z_NO_FLUSH);
-
-        // Sometimes misconfigured servers omit the zlib header, relying on
-        // clients to splice it back in.
-        if (ret < 0 && !zlib_header_added_) {
-          zlib_header_added_ = true;
-          if (!InsertZlibHeader())
-            return ERR_CONTENT_DECODING_FAILED;
-
-          zlib_stream_.get()->next_in = bit_cast<Bytef*>(input_data);
-          zlib_stream_.get()->avail_in = input_data_size;
-          zlib_stream_.get()->next_out =
-              bit_cast<Bytef*>(output_buffer->data());
-          zlib_stream_.get()->avail_out = output_buffer_size;
-
-          ret = inflate(zlib_stream_.get(), Z_NO_FLUSH);
-          // TODO(xunjieli): add a histogram to see how often this happens. The
-          // original bug for this behavior was ancient and maybe it doesn't
-          // happen in the wild any more? crbug.com/649339
-        }
         if (ret != Z_STREAM_END && ret != Z_OK)
           return ERR_CONTENT_DECODING_FAILED;
 
diff --git a/net/filter/gzip_source_stream.h b/net/filter/gzip_source_stream.h
index 46f296af..1a03804 100644
--- a/net/filter/gzip_source_stream.h
+++ b/net/filter/gzip_source_stream.h
@@ -9,8 +9,6 @@
 #include <string>
 
 #include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "net/base/io_buffer.h"
 #include "net/base/net_export.h"
 #include "net/filter/filter_source_stream.h"
 #include "net/filter/gzip_header.h"
@@ -44,6 +42,16 @@
     STATE_START,
     // Gzip header of the input stream is being processed.
     STATE_GZIP_HEADER,
+    // Deflate responses may or may not have a zlib header. In this state until
+    // enough has been inflated that this stream most likely has a zlib header,
+    // or until a zlib header has been added. Data is appended to |replay_data_|
+    // in case it needs to be replayed after adding a header.
+    STATE_SNIFFING_DEFLATE_HEADER,
+    // If a zlib header has to be added to the response, this state will replay
+    // data passed to inflate before it was determined that no zlib header was
+    // present.
+    // See https://crbug.com/677001
+    STATE_REPLAY_DATA,
     // The input stream is being decoded.
     STATE_COMPRESSED_BODY,
     // Gzip footer of the input stream is being processed.
@@ -84,9 +92,10 @@
   // FilterData(), with InsertZlibHeader() being the exception as a workaround.
   std::unique_ptr<z_stream> zlib_stream_;
 
-  // A flag used by FilterData() to record whether we've successfully added
-  // a zlib header to this stream.
-  bool zlib_header_added_;
+  // While in STATE_SNIFFING_DEFLATE_HEADER, it may be determined that a zlib
+  // header needs to be added, and all received data needs to be replayed. In
+  // that case, this buffer holds the data to be replayed.
+  std::string replay_data_;
 
   // Used to parse the gzip header in gzip stream.
   // It is used when the decoding mode is GZIP_SOURCE_STREAM_GZIP.
@@ -98,6 +107,9 @@
   // Tracks the state of the input stream.
   InputState input_state_;
 
+  // Used when replaying data.
+  InputState replay_state_;
+
   DISALLOW_COPY_AND_ASSIGN(GzipSourceStream);
 };
 
diff --git a/net/filter/gzip_source_stream_unittest.cc b/net/filter/gzip_source_stream_unittest.cc
index f0cb180..ed4daaf 100644
--- a/net/filter/gzip_source_stream_unittest.cc
+++ b/net/filter/gzip_source_stream_unittest.cc
@@ -26,17 +26,31 @@
 const int kBigBufferSize = 4096;
 const int kSmallBufferSize = 1;
 
+enum class ReadResultType {
+  // Each call to AddReadResult is a separate read from the lower layer
+  // SourceStream.
+  EVERYTHING_AT_ONCE,
+  // Whenever AddReadResult is called, each byte is actually a separate read
+  // result.
+  ONE_BYTE_AT_A_TIME,
+};
+
 // How many bytes to leave unused at the end of |source_data_|. This margin is
 // present so that tests that need to append data after the zlib EOF do not run
 // out of room in the output buffer.
 const size_t kEOFMargin = 64;
 
 struct GzipTestParam {
-  GzipTestParam(int buf_size, MockSourceStream::Mode read_mode)
-      : buffer_size(buf_size), mode(read_mode) {}
+  GzipTestParam(int buf_size,
+                MockSourceStream::Mode read_mode,
+                ReadResultType read_result_type)
+      : buffer_size(buf_size),
+        mode(read_mode),
+        read_result_type(read_result_type) {}
 
   const int buffer_size;
   const MockSourceStream::Mode mode;
+  const ReadResultType read_result_type;
 };
 
 }  // namespace
@@ -63,19 +77,23 @@
 
     output_buffer_ = new IOBuffer(output_buffer_size_);
     std::unique_ptr<MockSourceStream> source(new MockSourceStream());
+    if (GetParam().read_result_type == ReadResultType::ONE_BYTE_AT_A_TIME)
+      source->set_read_one_byte_at_a_time(true);
     source_ = source.get();
     stream_ = GzipSourceStream::Create(std::move(source), type);
   }
 
-  // If MockSourceStream::Mode is ASYNC, completes 1 read from |mock_stream| and
-  // wait for |callback| to complete. If Mode is not ASYNC, does nothing and
-  // returns |previous_result|.
-  int CompleteReadIfAsync(int previous_result,
-                          TestCompletionCallback* callback,
-                          MockSourceStream* mock_stream) {
+  // If MockSourceStream::Mode is ASYNC, completes reads from |mock_stream|
+  // until there's no pending read, and then returns |callback|'s result, once
+  // it's invoked. If Mode is not ASYNC, does nothing and returns
+  // |previous_result|.
+  int CompleteReadsIfAsync(int previous_result,
+                           TestCompletionCallback* callback,
+                           MockSourceStream* mock_stream) {
     if (GetParam().mode == MockSourceStream::ASYNC) {
       EXPECT_EQ(ERR_IO_PENDING, previous_result);
-      mock_stream->CompleteNextRead();
+      while (mock_stream->awaiting_completion())
+        mock_stream->CompleteNextRead();
       return callback->WaitForResult();
     }
     return previous_result;
@@ -104,7 +122,7 @@
       int rv = stream_->Read(output_buffer(), output_buffer_size(),
                              callback.callback());
       if (rv == ERR_IO_PENDING)
-        rv = CompleteReadIfAsync(rv, &callback, source());
+        rv = CompleteReadsIfAsync(rv, &callback, source());
       if (rv == OK)
         break;
       if (rv < OK)
@@ -133,15 +151,34 @@
 INSTANTIATE_TEST_CASE_P(
     GzipSourceStreamTests,
     GzipSourceStreamTest,
-    ::testing::Values(GzipTestParam(kBigBufferSize, MockSourceStream::SYNC),
-                      GzipTestParam(kSmallBufferSize, MockSourceStream::SYNC),
-                      GzipTestParam(kBigBufferSize, MockSourceStream::ASYNC),
+    ::testing::Values(GzipTestParam(kBigBufferSize,
+                                    MockSourceStream::SYNC,
+                                    ReadResultType::EVERYTHING_AT_ONCE),
                       GzipTestParam(kSmallBufferSize,
-                                    MockSourceStream::ASYNC)));
+                                    MockSourceStream::SYNC,
+                                    ReadResultType::EVERYTHING_AT_ONCE),
+                      GzipTestParam(kBigBufferSize,
+                                    MockSourceStream::ASYNC,
+                                    ReadResultType::EVERYTHING_AT_ONCE),
+                      GzipTestParam(kSmallBufferSize,
+                                    MockSourceStream::ASYNC,
+                                    ReadResultType::EVERYTHING_AT_ONCE),
+                      GzipTestParam(kBigBufferSize,
+                                    MockSourceStream::SYNC,
+                                    ReadResultType::ONE_BYTE_AT_A_TIME),
+                      GzipTestParam(kSmallBufferSize,
+                                    MockSourceStream::SYNC,
+                                    ReadResultType::ONE_BYTE_AT_A_TIME),
+                      GzipTestParam(kBigBufferSize,
+                                    MockSourceStream::ASYNC,
+                                    ReadResultType::ONE_BYTE_AT_A_TIME),
+                      GzipTestParam(kSmallBufferSize,
+                                    MockSourceStream::ASYNC,
+                                    ReadResultType::ONE_BYTE_AT_A_TIME)));
 
 TEST_P(GzipSourceStreamTest, EmptyStream) {
   Init(SourceStream::TYPE_DEFLATE);
-  source()->AddReadResult("", 0, OK, GetParam().mode);
+  source()->AddReadResult(nullptr, 0, OK, GetParam().mode);
   TestCompletionCallback callback;
   std::string actual_output;
   int result = ReadStream(&actual_output);
@@ -153,7 +190,7 @@
   Init(SourceStream::TYPE_DEFLATE);
   source()->AddReadResult(encoded_data(), encoded_data_len(), OK,
                           GetParam().mode);
-  source()->AddReadResult(encoded_data(), 0, OK, GetParam().mode);
+  source()->AddReadResult(nullptr, 0, OK, GetParam().mode);
   std::string actual_output;
   int rv = ReadStream(&actual_output);
   EXPECT_EQ(static_cast<int>(source_data_len()), rv);
@@ -165,7 +202,7 @@
   Init(SourceStream::TYPE_GZIP);
   source()->AddReadResult(encoded_data(), encoded_data_len(), OK,
                           GetParam().mode);
-  source()->AddReadResult(encoded_data(), 0, OK, GetParam().mode);
+  source()->AddReadResult(nullptr, 0, OK, GetParam().mode);
   std::string actual_output;
   int rv = ReadStream(&actual_output);
   EXPECT_EQ(static_cast<int>(source_data_len()), rv);
@@ -178,8 +215,7 @@
   source()->AddReadResult(encoded_data(), 10, OK, GetParam().mode);
   source()->AddReadResult(encoded_data() + 10, encoded_data_len() - 10, OK,
                           GetParam().mode);
-  source()->AddReadResult(encoded_data() + encoded_data_len(), 0, OK,
-                          GetParam().mode);
+  source()->AddReadResult(nullptr, 0, OK, GetParam().mode);
   std::string actual_output;
   int rv = ReadStream(&actual_output);
   EXPECT_EQ(static_cast<int>(source_data_len()), rv);
@@ -196,7 +232,7 @@
   source()->AddReadResult(encoded_data_with_trailing_data.c_str(),
                           encoded_data_len() + sizeof(test_data), OK,
                           GetParam().mode);
-  source()->AddReadResult(encoded_data(), 0, OK, GetParam().mode);
+  source()->AddReadResult(nullptr, 0, OK, GetParam().mode);
   // Compressed and uncompressed data get returned as separate Read() results,
   // so this test has to call Read twice.
   std::string actual_output;
@@ -214,7 +250,7 @@
   source()->AddReadResult(encoded_data() + kZlibHeaderLen,
                           encoded_data_len() - kZlibHeaderLen, OK,
                           GetParam().mode);
-  source()->AddReadResult(encoded_data(), 0, OK, GetParam().mode);
+  source()->AddReadResult(nullptr, 0, OK, GetParam().mode);
   std::string actual_output;
   int rv = ReadStream(&actual_output);
   EXPECT_EQ(static_cast<int>(source_data_len()), rv);
@@ -224,9 +260,12 @@
 
 TEST_P(GzipSourceStreamTest, CorruptGzipHeader) {
   Init(SourceStream::TYPE_GZIP);
-  encoded_data()[0] = 0;
-  source()->AddReadResult(encoded_data(), encoded_data_len(), OK,
-                          GetParam().mode);
+  encoded_data()[1] = 0;
+  int read_len = encoded_data_len();
+  // Needed to a avoid a DCHECK that all reads were consumed.
+  if (GetParam().read_result_type == ReadResultType::ONE_BYTE_AT_A_TIME)
+    read_len = 2;
+  source()->AddReadResult(encoded_data(), read_len, OK, GetParam().mode);
   std::string actual_output;
   int rv = ReadStream(&actual_output);
   EXPECT_EQ(ERR_CONTENT_DECODING_FAILED, rv);
@@ -237,7 +276,7 @@
   Init(SourceStream::TYPE_GZIP_FALLBACK);
   source()->AddReadResult(source_data(), source_data_len(), OK,
                           GetParam().mode);
-  source()->AddReadResult(source_data(), 0, OK, GetParam().mode);
+  source()->AddReadResult(nullptr, 0, OK, GetParam().mode);
 
   std::string actual_output;
   int rv = ReadStream(&actual_output);
@@ -250,50 +289,21 @@
 // as produced by gzip(1).
 TEST_P(GzipSourceStreamTest, GzipCorrectness) {
   Init(SourceStream::TYPE_GZIP);
-  char plain_data[] = "Hello, World!";
-  unsigned char gzip_data[] = {
+  const char kDecompressedData[] = "Hello, World!";
+  const unsigned char kGzipData[] = {
       // From:
       //   echo -n 'Hello, World!' | gzip | xxd -i | sed -e 's/^/  /'
       // The footer is the last 8 bytes.
       0x1f, 0x8b, 0x08, 0x00, 0x2b, 0x02, 0x84, 0x55, 0x00, 0x03, 0xf3,
       0x48, 0xcd, 0xc9, 0xc9, 0xd7, 0x51, 0x08, 0xcf, 0x2f, 0xca, 0x49,
       0x51, 0x04, 0x00, 0xd0, 0xc3, 0x4a, 0xec, 0x0d, 0x00, 0x00, 0x00};
-  source()->AddReadResult(reinterpret_cast<char*>(gzip_data), sizeof(gzip_data),
-                          OK, GetParam().mode);
-  source()->AddReadResult(
-      reinterpret_cast<char*>(gzip_data) + sizeof(gzip_data), 0, OK,
-      GetParam().mode);
+  source()->AddReadResult(reinterpret_cast<const char*>(kGzipData),
+                          sizeof(kGzipData), OK, GetParam().mode);
+  source()->AddReadResult(nullptr, 0, OK, GetParam().mode);
   std::string actual_output;
   int rv = ReadStream(&actual_output);
-  EXPECT_EQ(static_cast<int>(strlen(plain_data)), rv);
-  EXPECT_EQ(plain_data, actual_output);
-  EXPECT_EQ("GZIP", stream()->Description());
-}
-
-// Only test synchronous read because it's not straightforward to know how many
-// MockSourceStream reads to complete in order for GzipSourceStream to return.
-TEST_P(GzipSourceStreamTest, GzipCorrectnessWithSmallInputBuffer) {
-  Init(SourceStream::TYPE_GZIP);
-  char plain_data[] = "Hello, World!";
-  unsigned char gzip_data[] = {
-      // From:
-      //   echo -n 'Hello, World!' | gzip | xxd -i | sed -e 's/^/  /'
-      // The footer is the last 8 bytes.
-      0x1f, 0x8b, 0x08, 0x00, 0x2b, 0x02, 0x84, 0x55, 0x00, 0x03, 0xf3,
-      0x48, 0xcd, 0xc9, 0xc9, 0xd7, 0x51, 0x08, 0xcf, 0x2f, 0xca, 0x49,
-      0x51, 0x04, 0x00, 0xd0, 0xc3, 0x4a, 0xec, 0x0d, 0x00, 0x00, 0x00};
-  size_t gzip_data_len = sizeof(gzip_data);
-  // Add a sequence of small reads.
-  for (size_t i = 0; i < gzip_data_len; i++) {
-    source()->AddReadResult(reinterpret_cast<char*>(gzip_data) + i, 1, OK,
-                            MockSourceStream::SYNC);
-  }
-  source()->AddReadResult(reinterpret_cast<char*>(gzip_data) + gzip_data_len, 0,
-                          OK, MockSourceStream::SYNC);
-  std::string actual_output;
-  int rv = ReadStream(&actual_output);
-  EXPECT_EQ(static_cast<int>(strlen(plain_data)), rv);
-  EXPECT_EQ(plain_data, actual_output);
+  EXPECT_EQ(static_cast<int>(strlen(kDecompressedData)), rv);
+  EXPECT_EQ(kDecompressedData, actual_output);
   EXPECT_EQ("GZIP", stream()->Description());
 }
 
@@ -301,23 +311,83 @@
 // implementation can handle missing footer.
 TEST_P(GzipSourceStreamTest, GzipCorrectnessWithoutFooter) {
   Init(SourceStream::TYPE_GZIP);
-  char plain_data[] = "Hello, World!";
-  unsigned char gzip_data[] = {
+  const char kDecompressedData[] = "Hello, World!";
+  const unsigned char kGzipData[] = {
       // From:
       //   echo -n 'Hello, World!' | gzip | xxd -i | sed -e 's/^/  /'
       // with the 8 footer bytes removed.
       0x1f, 0x8b, 0x08, 0x00, 0x2b, 0x02, 0x84, 0x55, 0x00,
       0x03, 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0xd7, 0x51, 0x08,
       0xcf, 0x2f, 0xca, 0x49, 0x51, 0x04, 0x00};
-  source()->AddReadResult(reinterpret_cast<char*>(gzip_data), sizeof(gzip_data),
-                          OK, GetParam().mode);
-  source()->AddReadResult(reinterpret_cast<char*>(gzip_data), 0, OK,
-                          GetParam().mode);
+  source()->AddReadResult(reinterpret_cast<const char*>(kGzipData),
+                          sizeof(kGzipData), OK, GetParam().mode);
+  source()->AddReadResult(nullptr, 0, OK, GetParam().mode);
   std::string actual_output;
   int rv = ReadStream(&actual_output);
-  EXPECT_EQ(static_cast<int>(strlen(plain_data)), rv);
-  EXPECT_EQ(plain_data, actual_output);
+  EXPECT_EQ(static_cast<int>(strlen(kDecompressedData)), rv);
+  EXPECT_EQ(kDecompressedData, actual_output);
   EXPECT_EQ("GZIP", stream()->Description());
 }
 
+// Test with the same compressed data as the above tests, but uses deflate with
+// header and checksum. Tests the Z_STREAM_END case in
+// STATE_SNIFFING_DEFLATE_HEADER.
+TEST_P(GzipSourceStreamTest, DeflateWithAdler32) {
+  Init(SourceStream::TYPE_DEFLATE);
+  const char kDecompressedData[] = "Hello, World!";
+  const unsigned char kGzipData[] = {0x78, 0x01, 0xf3, 0x48, 0xcd, 0xc9, 0xc9,
+                                     0xd7, 0x51, 0x08, 0xcf, 0x2f, 0xca, 0x49,
+                                     0x51, 0x04, 0x00, 0x1f, 0x9e, 0x04, 0x6a};
+  source()->AddReadResult(reinterpret_cast<const char*>(kGzipData),
+                          sizeof(kGzipData), OK, GetParam().mode);
+  source()->AddReadResult(nullptr, 0, OK, GetParam().mode);
+  std::string actual_output;
+  int rv = ReadStream(&actual_output);
+  EXPECT_EQ(static_cast<int>(strlen(kDecompressedData)), rv);
+  EXPECT_EQ(kDecompressedData, actual_output);
+  EXPECT_EQ("DEFLATE", stream()->Description());
+}
+
+TEST_P(GzipSourceStreamTest, DeflateWithBadAdler32) {
+  Init(SourceStream::TYPE_DEFLATE);
+  const unsigned char kGzipData[] = {0x78, 0x01, 0xf3, 0x48, 0xcd, 0xc9, 0xc9,
+                                     0xd7, 0x51, 0x08, 0xcf, 0x2f, 0xca, 0x49,
+                                     0x51, 0x04, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
+  source()->AddReadResult(reinterpret_cast<const char*>(kGzipData),
+                          sizeof(kGzipData), OK, GetParam().mode);
+  std::string actual_output;
+  int rv = ReadStream(&actual_output);
+  EXPECT_EQ(ERR_CONTENT_DECODING_FAILED, rv);
+  EXPECT_EQ("DEFLATE", stream()->Description());
+}
+
+TEST_P(GzipSourceStreamTest, DeflateWithoutHeaderWithAdler32) {
+  Init(SourceStream::TYPE_DEFLATE);
+  const char kDecompressedData[] = "Hello, World!";
+  const unsigned char kGzipData[] = {0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0xd7, 0x51,
+                                     0x08, 0xcf, 0x2f, 0xca, 0x49, 0x51, 0x04,
+                                     0x00, 0x1f, 0x9e, 0x04, 0x6a};
+  source()->AddReadResult(reinterpret_cast<const char*>(kGzipData),
+                          sizeof(kGzipData), OK, GetParam().mode);
+  source()->AddReadResult(nullptr, 0, OK, GetParam().mode);
+  std::string actual_output;
+  int rv = ReadStream(&actual_output);
+  EXPECT_EQ(static_cast<int>(strlen(kDecompressedData)), rv);
+  EXPECT_EQ(kDecompressedData, actual_output);
+  EXPECT_EQ("DEFLATE", stream()->Description());
+}
+
+TEST_P(GzipSourceStreamTest, DeflateWithoutHeaderWithBadAdler32) {
+  Init(SourceStream::TYPE_DEFLATE);
+  const unsigned char kGzipData[] = {0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0xd7, 0x51,
+                                     0x08, 0xcf, 0x2f, 0xca, 0x49, 0x51, 0x04,
+                                     0x00, 0xFF, 0xFF, 0xFF, 0xFF};
+  source()->AddReadResult(reinterpret_cast<const char*>(kGzipData),
+                          sizeof(kGzipData), OK, GetParam().mode);
+  std::string actual_output;
+  int rv = ReadStream(&actual_output);
+  EXPECT_EQ(ERR_CONTENT_DECODING_FAILED, rv);
+  EXPECT_EQ("DEFLATE", stream()->Description());
+}
+
 }  // namespace net
diff --git a/net/filter/mock_source_stream.cc b/net/filter/mock_source_stream.cc
index bdf56c6..7dceef2 100644
--- a/net/filter/mock_source_stream.cc
+++ b/net/filter/mock_source_stream.cc
@@ -6,18 +6,21 @@
 
 #include "base/logging.h"
 #include "net/base/io_buffer.h"
+#include "testing/gtest/include/gtest/gtest.h"
 
 namespace net {
 
 MockSourceStream::MockSourceStream()
     : SourceStream(SourceStream::TYPE_NONE),
+      read_one_byte_at_a_time_(false),
       awaiting_completion_(false),
       dest_buffer_(nullptr),
       dest_buffer_size_(0) {}
 
 MockSourceStream::~MockSourceStream() {
   DCHECK(!awaiting_completion_);
-  DCHECK(results_.empty());
+  // All data should have been consumed.
+  EXPECT_TRUE(results_.empty());
 }
 
 int MockSourceStream::Read(IOBuffer* dest_buffer,
@@ -58,10 +61,24 @@
                                      int len,
                                      Error error,
                                      Mode mode) {
-  // The read result must be between 0 and 32k (inclusive) because the read
-  // buffer used in FilterSourceStream is 32k.
-  DCHECK_GE(32 * 1024, len);
-  DCHECK_LE(0, len);
+  if (error != OK) {
+    // Doesn't make any sense to have both an error and data.
+    DCHECK_EQ(len, 0);
+  } else {
+    // The read result must be between 0 and 32k (inclusive) because the read
+    // buffer used in FilterSourceStream is 32k.
+    DCHECK_GE(32 * 1024, len);
+    DCHECK_LE(0, len);
+  }
+
+  if (len > 0 && read_one_byte_at_a_time_) {
+    for (int i = 0; i < len; ++i) {
+      QueuedResult result(data + i, 1, OK, mode);
+      results_.push(result);
+    }
+    return;
+  }
+
   QueuedResult result(data, len, error, mode);
   results_.push(result);
 }
diff --git a/net/filter/mock_source_stream.h b/net/filter/mock_source_stream.h
index 9c88bef..4d85444 100644
--- a/net/filter/mock_source_stream.h
+++ b/net/filter/mock_source_stream.h
@@ -46,6 +46,18 @@
   // pending read.
   void CompleteNextRead();
 
+  // Affects behavior or AddReadResult.  When set to true, each character in
+  // |data| passed to AddReadResult will be read as an individual byte, instead
+  // of all at once. Default to false.
+  // Note that setting it only affects future calls to AddReadResult, not
+  // previous ones.
+  void set_read_one_byte_at_a_time(bool read_one_byte_at_a_time) {
+    read_one_byte_at_a_time_ = read_one_byte_at_a_time;
+  }
+
+  // Returns true if a read is waiting to be completed.
+  bool awaiting_completion() const { return awaiting_completion_; }
+
  private:
   struct QueuedResult {
     QueuedResult(const char* data, int len, Error error, Mode mode);
@@ -56,6 +68,7 @@
     const Mode mode;
   };
 
+  bool read_one_byte_at_a_time_;
   std::queue<QueuedResult> results_;
   bool awaiting_completion_;
   scoped_refptr<IOBuffer> dest_buffer_;
diff --git a/remoting/protocol/channel_socket_adapter.cc b/remoting/protocol/channel_socket_adapter.cc
index 4a5946da..4d727f5 100644
--- a/remoting/protocol/channel_socket_adapter.cc
+++ b/remoting/protocol/channel_socket_adapter.cc
@@ -10,15 +10,13 @@
 #include "base/logging.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
-#include "third_party/webrtc/p2p/base/transportchannel.h"
 
 namespace remoting {
 namespace protocol {
 
 TransportChannelSocketAdapter::TransportChannelSocketAdapter(
-    cricket::TransportChannel* channel)
-    : channel_(channel),
-      closed_error_code_(net::OK) {
+    cricket::IceTransportInternal* ice_transport)
+    : channel_(ice_transport), closed_error_code_(net::OK) {
   DCHECK(channel_);
 
   channel_->SignalReadPacket.connect(
@@ -176,7 +174,7 @@
 }
 
 void TransportChannelSocketAdapter::OnChannelDestroyed(
-    cricket::TransportChannel* channel) {
+    cricket::IceTransportInternal* channel) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK_EQ(channel, channel_);
   Close(net::ERR_CONNECTION_ABORTED);
diff --git a/remoting/protocol/channel_socket_adapter.h b/remoting/protocol/channel_socket_adapter.h
index 0d2bdf59..7e664c4 100644
--- a/remoting/protocol/channel_socket_adapter.h
+++ b/remoting/protocol/channel_socket_adapter.h
@@ -15,27 +15,28 @@
 #include "third_party/webrtc/base/asyncpacketsocket.h"
 #include "third_party/webrtc/base/sigslot.h"
 #include "third_party/webrtc/base/socketaddress.h"
+// TODO(zhihuang):Replace #include by forward declaration once proper
+// inheritance is defined for cricket::IceTransportInternal and
+// cricket::P2PTransportChannel.
+#include "third_party/webrtc/p2p/base/icetransportinternal.h"
 // TODO(johan): Replace #include by forward declaration once proper
 // inheritance is defined for rtc::PacketTransportInterface and
 // cricket::TransportChannel.
 #include "third_party/webrtc/p2p/base/packettransportinterface.h"
 
-namespace cricket {
-class TransportChannel;
-}  // namespace cricket
-
 namespace remoting {
 namespace protocol {
 
 // TransportChannelSocketAdapter implements P2PDatagramSocket interface on
-// top of libjingle's TransportChannel. It is used by IceTransport to provide
+// top of cricket::IceTransportInternal. It is used by IceTransport to provide
 // P2PDatagramSocket interface for channels.
 class TransportChannelSocketAdapter : public P2PDatagramSocket,
                                       public sigslot::has_slots<> {
  public:
   // Doesn't take ownership of the |channel|. The |channel| must outlive
   // this adapter.
-  explicit TransportChannelSocketAdapter(cricket::TransportChannel* channel);
+  explicit TransportChannelSocketAdapter(
+      cricket::IceTransportInternal* ice_transport);
   ~TransportChannelSocketAdapter() override;
 
   // Sets callback that should be called when the adapter is being
@@ -61,11 +62,11 @@
                    const rtc::PacketTime& packet_time,
                    int flags);
   void OnWritableState(rtc::PacketTransportInterface* transport);
-  void OnChannelDestroyed(cricket::TransportChannel* channel);
+  void OnChannelDestroyed(cricket::IceTransportInternal* ice_transport);
 
   base::ThreadChecker thread_checker_;
 
-  cricket::TransportChannel* channel_;
+  cricket::IceTransportInternal* channel_;
 
   base::Closure destruction_callback_;
 
diff --git a/remoting/protocol/ice_transport_channel.cc b/remoting/protocol/ice_transport_channel.cc
index 9c3658ae..e57aa10 100644
--- a/remoting/protocol/ice_transport_channel.cc
+++ b/remoting/protocol/ice_transport_channel.cc
@@ -183,14 +183,14 @@
 }
 
 void IceTransportChannel::OnCandidateGathered(
-    cricket::TransportChannelImpl* channel,
+    cricket::IceTransportInternal2* ice_transport,
     const cricket::Candidate& candidate) {
   DCHECK(thread_checker_.CalledOnValidThread());
   delegate_->OnChannelCandidate(this, candidate);
 }
 
 void IceTransportChannel::OnRouteChange(
-    cricket::TransportChannel* channel,
+    cricket::IceTransportInternal* ice_transport,
     const cricket::Candidate& candidate) {
   // Ignore notifications if the channel is not writable.
   if (channel_->writable())
diff --git a/remoting/protocol/ice_transport_channel.h b/remoting/protocol/ice_transport_channel.h
index c709f0f..f28ff82 100644
--- a/remoting/protocol/ice_transport_channel.h
+++ b/remoting/protocol/ice_transport_channel.h
@@ -15,6 +15,10 @@
 #include "remoting/protocol/transport.h"
 #include "third_party/webrtc/base/sigslot.h"
 
+// TODO(zhihuang):Replace #include by forward declaration once proper
+// inheritance is defined for cricket::IceTransportInternal and
+// cricket::P2PTransportChannel.
+#include "third_party/webrtc/p2p/base/icetransportinternal.h"
 // TODO(johan): Replace #include by forward declaration once proper inheritance
 // is defined for rtc::PacketTransportInterface and cricket::TransportChannel.
 #include "third_party/webrtc/p2p/base/packettransportinterface.h"
@@ -23,8 +27,6 @@
 class Candidate;
 class P2PTransportChannel;
 class PortAllocator;
-class TransportChannel;
-class TransportChannelImpl;
 }  // namespace cricket
 
 namespace remoting {
@@ -96,10 +98,10 @@
 
   void NotifyConnected();
 
-  // Signal handlers for cricket::TransportChannel.
-  void OnCandidateGathered(cricket::TransportChannelImpl* channel,
+  // Signal handlers for cricket::IceTransportInternal.
+  void OnCandidateGathered(cricket::IceTransportInternal2* ice_transport,
                            const cricket::Candidate& candidate);
-  void OnRouteChange(cricket::TransportChannel* channel,
+  void OnRouteChange(cricket::IceTransportInternal* ice_transport,
                      const cricket::Candidate& candidate);
   void OnWritableState(rtc::PacketTransportInterface* transport);
 
diff --git a/third_party/WebKit/LayoutTests/bluetooth/characteristic/notifications/add-multiple-event-listeners.html b/third_party/WebKit/LayoutTests/bluetooth/characteristic/notifications/add-multiple-event-listeners.html
index 44b5c19..6b2d2bc 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/characteristic/notifications/add-multiple-event-listeners.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/characteristic/notifications/add-multiple-event-listeners.html
@@ -17,7 +17,8 @@
       return assert_event_fires_after_promise(characteristic,
                                               'startNotifications',
                                               'characteristicvaluechanged',
-                                              3 /* add 3 listeners */);
+                                              3 /* add 3 listeners */,
+                                              false /* ignore_event_promise_order */);
     })
     .then(() => char.stopNotifications())
     .then(() => assert_no_events(char, 'characteristicvaluechanged'));
diff --git a/third_party/WebKit/LayoutTests/bluetooth/characteristic/notifications/event-after-starting.html b/third_party/WebKit/LayoutTests/bluetooth/characteristic/notifications/event-after-starting.html
index 246784c..eaae9fd 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/characteristic/notifications/event-after-starting.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/characteristic/notifications/event-after-starting.html
@@ -13,7 +13,8 @@
     .then(service => service.getCharacteristic('heart_rate_measurement'))
     .then(characteristic => {
       return assert_event_fires_after_promise(
-        characteristic, 'startNotifications', 'characteristicvaluechanged')
+        characteristic, 'startNotifications', 'characteristicvaluechanged',
+        1 /* attach 1 listener */, false /* ignore_event_promise_order */)
         .then(() => characteristic.stopNotifications())
         .then(() => assert_no_events(characteristic,
                                      'characteristicvaluechanged'));
diff --git a/third_party/WebKit/LayoutTests/bluetooth/characteristic/readValue/add-multiple-event-listeners.html b/third_party/WebKit/LayoutTests/bluetooth/characteristic/readValue/add-multiple-event-listeners.html
index 116440969..206060c4 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/characteristic/readValue/add-multiple-event-listeners.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/characteristic/readValue/add-multiple-event-listeners.html
@@ -15,7 +15,8 @@
       return assert_event_fires_after_promise(characteristic,
                                               'readValue',
                                               'characteristicvaluechanged',
-                                              3 /* attach 3 listeners */);
+                                              3 /* attach 3 listeners */,
+                                              true /* ignore_event_promise_order */);
     }).then(results => {
       let read_value = results[0].buffer;
       let event_values = results.slice(1).map(v => v.buffer);
diff --git a/third_party/WebKit/LayoutTests/bluetooth/characteristic/readValue/event-is-fired.html b/third_party/WebKit/LayoutTests/bluetooth/characteristic/readValue/event-is-fired.html
index d43f27d6..3f1a9a6 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/characteristic/readValue/event-is-fired.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/characteristic/readValue/event-is-fired.html
@@ -14,7 +14,9 @@
     .then(characteristic => {
       return assert_event_fires_after_promise(characteristic,
                                               'readValue',
-                                              'characteristicvaluechanged');
+                                              'characteristicvaluechanged',
+                                              1 /* attach 1 listener */,
+                                              true /* ignore_event_promise_order */);
     }).then(results => {
       let read_value = results[0].buffer;
       let event_value = results[1].buffer;
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-drawImage-out-of-bounds-src.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-drawImage-out-of-bounds-src.html
index 85173363..e2afad9 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-drawImage-out-of-bounds-src.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-drawImage-out-of-bounds-src.html
@@ -36,15 +36,17 @@
 ctx1.drawImage(bgcanvas, 0,    0,    100, 200, 75,  175, 100, 100);
 ctx1.drawImage(bgcanvas, 0,    0,    200, 200, 175, 175, 100, 100);
 
-ctx2.drawImage(img, -100, -100, 300, 300, -25, -25, 300, 300);
-ctx2.drawImage(img, -100, -100, 200, 200, -25, -25, 100, 100);
-ctx2.drawImage(img, 0,    -100, 100, 200, 75,  -25, 100, 100);
-ctx2.drawImage(img, 0,    -100, 200, 200, 175, -25, 100, 100);
-ctx2.drawImage(img, -100, 0,    200, 100, -25, 75,  100, 100);
-ctx2.drawImage(img, 0,  0,      200, 100, 175, 75,  100, 100);
-ctx2.drawImage(img, -100, 0,    200, 200, -25, 175, 100, 100);
-ctx2.drawImage(img, 0,    0,    100, 200, 75,  175, 100, 100);
-ctx2.drawImage(img, 0,    0,    200, 200, 175, 175, 100, 100);
+img.onload = function() {
+    ctx2.drawImage(img, -100, -100, 300, 300, -25, -25, 300, 300);
+    ctx2.drawImage(img, -100, -100, 200, 200, -25, -25, 100, 100);
+    ctx2.drawImage(img, 0,    -100, 100, 200, 75,  -25, 100, 100);
+    ctx2.drawImage(img, 0,    -100, 200, 200, 175, -25, 100, 100);
+    ctx2.drawImage(img, -100, 0,    200, 100, -25, 75,  100, 100);
+    ctx2.drawImage(img, 0,  0,      200, 100, 175, 75,  100, 100);
+    ctx2.drawImage(img, -100, 0,    200, 200, -25, 175, 100, 100);
+    ctx2.drawImage(img, 0,    0,    100, 200, 75,  175, 100, 100);
+    ctx2.drawImage(img, 0,    0,    200, 200, 175, 175, 100, 100);
+}
 
 if (window.testRunner) {
     testRunner.waitUntilDone();
@@ -96,4 +98,4 @@
 }
 
 </script>
-</body></html>
\ No newline at end of file
+</body></html>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/HTMLImageElement/image-async-loading-data-uris.html b/third_party/WebKit/LayoutTests/fast/dom/HTMLImageElement/image-async-loading-data-uris.html
new file mode 100644
index 0000000..458b84930b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/dom/HTMLImageElement/image-async-loading-data-uris.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script>
+    test(function() {
+        var img = new Image();
+        img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=";
+        assert_equals(img.width, 0);
+    }, "Test that a data URI resource doesn't get loaded synchronously");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/geometry-interfaces-dom-point-readonly.html b/third_party/WebKit/LayoutTests/fast/dom/geometry-interfaces-dom-point-readonly.html
index 1c0ef51a..3729453 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/geometry-interfaces-dom-point-readonly.html
+++ b/third_party/WebKit/LayoutTests/fast/dom/geometry-interfaces-dom-point-readonly.html
@@ -9,6 +9,26 @@
 'use strict';
 
 test(() => {
+  var point = new DOMPointReadOnly();
+  assert_dom_point_equals(point, [0, 0, 0, 1]);
+}, 'DOMPointReadOnly constructor without parameter');
+
+test(() => {
+  var point = new DOMPointReadOnly(10);
+  assert_dom_point_equals(point, [10, 0, 0, 1]);
+}, 'DOMPointReadOnly constructor with x parameter');
+
+test(() => {
+  var point = new DOMPointReadOnly(10, 20);
+  assert_dom_point_equals(point, [10, 20, 0, 1]);
+}, 'DOMPointReadOnly constructor with x, y parameters');
+
+test(() => {
+  var point = new DOMPointReadOnly(10, 20, 30);
+  assert_dom_point_equals(point, [10, 20, 30, 1]);
+}, 'DOMPointReadOnly constructor with x, y, z parameters');
+
+test(() => {
   var point = new DOMPointReadOnly(10, 20, 30, 40);
   assert_dom_point_equals(point, [10, 20, 30, 40]);
 }, 'DOMPointReadOnly constructor with x, y, z, w parameters');
@@ -40,10 +60,19 @@
   var point1 = DOMPointReadOnly.fromPoint();
   var point2 = DOMPointReadOnly.fromPoint();
   assert_false(point1 == point2);
-  assert_true(point1.x == point2.x);
-  assert_true(point1.y == point2.y);
-  assert_true(point1.z == point2.z);
-  assert_true(point1.w == point2.w);
+  assert_dom_point_equals(point1, point2);
 }, 'DOMPointReadOnly.fromPoint() should create a new DOMPointReadOnly');
 
+test(() => {
+  var point = new DOMPointReadOnly(5, 4);
+  var transformed_point = point.matrixTransform(new DOMMatrixReadOnly([2, 0, 0, 2, 10, 10]));
+  assert_dom_point_equals(transformed_point, new DOMPoint(20, 18));
+}, 'DOMMatrixReadOnly.matrixTransform() - 2d matrixTransform');
+
+test(() => {
+  var point = new DOMPointReadOnly(5, 4);
+  var transformed_point = point.matrixTransform(new DOMMatrixReadOnly([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]));
+  assert_dom_point_equals(transformed_point, new DOMPoint(38, 48, 58, 68));
+}, 'DOMMatrixReadOnly.matrixTransform() - 3d matrixTransform');
+
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/basic-buttons.html b/third_party/WebKit/LayoutTests/fast/forms/basic-buttons.html
index 1ff9824..47fbe97 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/basic-buttons.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/basic-buttons.html
@@ -48,8 +48,10 @@
     }
 }
 
-printSize('button');
-printSize('input');
+window.onload = function() {
+    printSize('button');
+    printSize('input');
+};
 </script>
 
 </body> 
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/network/waterfall-images.html b/third_party/WebKit/LayoutTests/http/tests/inspector/network/waterfall-images.html
index 8eb0f94..eb029afc 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/network/waterfall-images.html
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/network/waterfall-images.html
@@ -5,19 +5,20 @@
 <script>
 // TODO(allada) Move much of this canvas code to a canvas-test.js file.
 var images = [];
-var sumWidth = 0;
-var maxHeight = 0;
 
 function receiveImage(imageUrl) {
   var image = new Image();
   image.src = imageUrl;
   images.push(image);
-
-  sumWidth += image.width;
-  maxHeight = Math.max(image.height, maxHeight);
 }
 
 function done() {
+  var sumWidth = 0;
+  var maxHeight = 0;
+  for (var image of images) {
+    sumWidth += image.width;
+    maxHeight = Math.max(image.height, maxHeight);
+  }
   var canvas = document.getElementById("outputCanvas");
   canvas.height = maxHeight;
   canvas.width = sumWidth;
@@ -268,15 +269,15 @@
     if (numDraws > 2)
       return;
     if (numDraws === 2) {
-      sendData(waterfall._canvas, true);
+      sendData(true);
       return;
     }
-    sendData(waterfall._canvas, false);
+    sendData(false);
     // This makes sure we test both old bars and new bars with same data.
     Common.moduleSetting('networkColorCodeResourceTypes').set(true);
   }
 
-  function sendData(canvas, done) {
+  function sendData(done) {
     var imageData = waterfall._canvas.toDataURL();
     var height = waterfall._canvas.height;
     var width = waterfall._canvas.width;
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/report-blocked-data-uri-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/report-blocked-data-uri-expected.txt
index 063acdb..fac75f1 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/report-blocked-data-uri-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/report-blocked-data-uri-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: line 7: Refused to load the image 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' because it violates the following Content Security Policy directive: "img-src 'none'".
+CONSOLE ERROR: line 8: Refused to load the image 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' because it violates the following Content Security Policy directive: "img-src 'none'".
 
 PingLoader dispatched to 'http://127.0.0.1:8000/security/contentSecurityPolicy/resources/save-report.php?test=report-blocked-data-uri.php'.
 CSP report received:
@@ -6,4 +6,4 @@
 HTTP_REFERER: http://127.0.0.1:8000/security/contentSecurityPolicy/report-blocked-data-uri.php
 REQUEST_METHOD: POST
 === POST DATA ===
-{"csp-report":{"document-uri":"http://127.0.0.1:8000/security/contentSecurityPolicy/report-blocked-data-uri.php","referrer":"","violated-directive":"img-src","effective-directive":"img-src","original-policy":"img-src 'none'; report-uri resources/save-report.php?test=report-blocked-data-uri.php","disposition":"enforce","blocked-uri":"data","line-number":7,"source-file":"http://127.0.0.1:8000/security/contentSecurityPolicy/report-blocked-data-uri.php","status-code":200}}
+{"csp-report":{"document-uri":"http://127.0.0.1:8000/security/contentSecurityPolicy/report-blocked-data-uri.php","referrer":"","violated-directive":"img-src","effective-directive":"img-src","original-policy":"img-src 'none'; report-uri resources/save-report.php?test=report-blocked-data-uri.php","disposition":"enforce","blocked-uri":"data","line-number":8,"source-file":"http://127.0.0.1:8000/security/contentSecurityPolicy/report-blocked-data-uri.php","status-code":200}}
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-format-array-prototype-expected.txt b/third_party/WebKit/LayoutTests/inspector/console/console-format-array-prototype-expected.txt
index e3a5df0..17947fe 100644
--- a/third_party/WebKit/LayoutTests/inspector/console/console-format-array-prototype-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/console/console-format-array-prototype-expected.txt
@@ -16,31 +16,31 @@
 console-format-array-prototype.html:4 []
 a1
 [undefined × 1]
-console-format-array-prototype.html:4 []
+console-format-array-prototype.html:4 [undefined × 1]
 a2
 [undefined × 5]
-console-format-array-prototype.html:4 []
+console-format-array-prototype.html:4 [undefined × 5]
 a3
 [undefined × 1, 2, 3]
-console-format-array-prototype.html:4 [1: 2, 2: 3]
+console-format-array-prototype.html:4 [undefined × 1, 2, 3]
 a4
 [undefined × 15]
-console-format-array-prototype.html:4 []
+console-format-array-prototype.html:4 [undefined × 15]
 a5
 [undefined × 8, 8, undefined × 6]
-console-format-array-prototype.html:4 [8: 8]
+console-format-array-prototype.html:4 [undefined × 8, 8, undefined × 6]
 a6
 [0, undefined × 9, 10, undefined × 4]
-console-format-array-prototype.html:4 [0, 10: 10]
+console-format-array-prototype.html:4 [0, undefined × 9, 10, undefined × 4]
 a7
-[undefined × 3, 4, undefined × 11]
+[3: 4, index0: 0, index1: 1, index2: 2, index3: 3, index4: 4…]
 console-format-array-prototype.html:4 [3: 4, index0: 0, index1: 1, index2: 2, index3: 3, index4: 4…]
 a8
 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
 console-format-array-prototype.html:4 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
 a9
-[undefined × 1, 1, 2, 3, 4, undefined × 1, 6, 7, 8, 9, undefined × 1]
-console-format-array-prototype.html:4 [1: 1, 2: 2, 3: 3, 4: 4, 6: 6, 7: 7, 8: 8, 9: 9, foo: "bar"]
+[undefined × 1, 1, 2, 3, 4, undefined × 1, 6, 7, 8, 9, undefined × 1, foo: "bar"]
+console-format-array-prototype.html:4 [undefined × 1, 1, 2, 3, 4, undefined × 1, 6, 7, 8, 9, undefined × 1, foo: "bar"]
 a10
 Array {}
 console-format-array-prototype.html:4 Array {}
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-format-collections-expected.txt b/third_party/WebKit/LayoutTests/inspector/console/console-format-collections-expected.txt
index 990df25..0051e91 100644
--- a/third_party/WebKit/LayoutTests/inspector/console/console-format-collections-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/console/console-format-collections-expected.txt
@@ -64,8 +64,8 @@
 console-format-collections.html:44 NonArrayWithLength {keys: Array(0)}
 console-format-collections.html:51 [1, "2", callee: function, Symbol(Symbol.iterator): function]
 console-format-collections.html:55 ["c1", "c2", "c3", value: "c1 c2 c3"]
-console-format-collections.html:58 []
-console-format-collections.html:59 []
+console-format-collections.html:58 [undefined × 5]
+console-format-collections.html:59 [undefined × 4294967295]
 console-format-collections.html:61 ArrayLike {length: -5}
 console-format-collections.html:62 ArrayLike {length: 5.6}
 console-format-collections.html:63 ArrayLike {length: NaN}
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-format-expected.txt b/third_party/WebKit/LayoutTests/inspector/console/console-format-expected.txt
index 9f0ff1c..52ae781 100644
--- a/third_party/WebKit/LayoutTests/inspector/console/console-format-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/console/console-format-expected.txt
@@ -96,6 +96,8 @@
 CONSOLE MESSAGE: line 13: [object Uint8Array]
 CONSOLE MESSAGE: line 12: [object Object]
 CONSOLE MESSAGE: line 13: [object Object]
+CONSOLE MESSAGE: line 12: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
+CONSOLE MESSAGE: line 13: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
 Tests that console logging dumps proper messages.
 
  console-format.html:21 Array(10)
@@ -206,10 +208,10 @@
 console-format.html:8 [-Infinity]
 globals[20]
 -Infinity
-console-format.html:7 ["test", "test2", 4: "test4", foo: Object]
+console-format.html:7 ["test", "test2", undefined × 2, "test4", undefined × 5, foo: Object]
 console-format.html:8 [Array(10)]
 globals[21]
-["test", "test2", undefined × 2, "test4", undefined × 5]
+["test", "test2", undefined × 2, "test4", undefined × 5, foo: Object]
 console-format.html:7 Object {}
 console-format.html:8 [Object]
 globals[22]
@@ -276,15 +278,19 @@
 console-format.html:7 Uint8Array(400) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…]
 console-format.html:8 [Uint8Array(400)]
 globals[37]
-Uint8Array(400)
+Uint8Array(400) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…]
 console-format.html:7 Uint8Array(400000000) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…]
 console-format.html:8 [Uint8Array(400000000)]
 globals[38]
-Uint8Array(400000000)
+Uint8Array(400000000) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…]
 console-format.html:7 namespace.longSubNamespace.x.className {}
 console-format.html:8 [n…e.l…e.x.className]
 globals[39]
 namespace.longSubNamespace.x.className {}
+console-format.html:7 [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…]
+console-format.html:8 [Array(200)]
+globals[40]
+[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…]
 Expanded all messages
 console-format.html:21 Array(10)
     0: "test"
@@ -742,4 +748,19 @@
 globals[39]
 namespace.longSubNamespace.x.className
     __proto__: Object
+console-format.html:7 Array(200)
+    [0 … 99]
+    [100 … 199]
+    length: 200
+    __proto__: Array(0)
+console-format.html:8 Array(1)
+    0: Array(200)
+    length: 1
+    __proto__: Array(0)
+globals[40]
+Array(200)
+    [0 … 99]
+    [100 … 199]
+    length: 200
+    __proto__: Array(0)
 
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-format.html b/third_party/WebKit/LayoutTests/inspector/console/console-format.html
index 513278b..e29edf2e 100644
--- a/third_party/WebKit/LayoutTests/inspector/console/console-format.html
+++ b/third_party/WebKit/LayoutTests/inspector/console/console-format.html
@@ -76,13 +76,16 @@
     namespace.longSubNamespace.x = {};
     namespace.longSubNamespace.x.className = function(){};
     var instanceWithLongClassName = new namespace.longSubNamespace.x.className();
+    var bigArray = [];
+    bigArray.length = 200;
+    bigArray.fill(1);
     globals = [
         regex1, regex2, str, str2, error, errorWithMessage, errorWithMultilineMessage, node, func, multilinefunc, 
         num, linkify, null, undefined, valuelessAttribute, valuedAttribute, existingAttribute, throwingLengthGetter,
         NaN, Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY, array, {}, [function() {}], bar, svg,
         objectWithNonEnumerables, negZero, Object.create(null), Object, Object.prototype, arrayLikeFunction,
         new Number(42), new String("abc"), new Uint16Array([1, 2, 3]), textNode, domException(),
-        smallTypedArray, bigTypedArray, instanceWithLongClassName
+        smallTypedArray, bigTypedArray, instanceWithLongClassName, bigArray
     ];
 
     runTest();
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-log-object-with-getter-expected.txt b/third_party/WebKit/LayoutTests/inspector/console/console-log-object-with-getter-expected.txt
index a8996db..6cd6bfd6 100644
--- a/third_party/WebKit/LayoutTests/inspector/console/console-log-object-with-getter-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/console/console-log-object-with-getter-expected.txt
@@ -3,7 +3,7 @@
 Tests that console logging dumps object values defined by getters and allows to expand it.
 
 console-log-object-with-getter.html:15 Object {}
-console-log-object-with-getter.html:16 [(...)]
+console-log-object-with-getter.html:16 [(...), undefined × 1]
 console-log-object-with-getter.html:15 Objectfoo: Objecta: 1b: 2__proto__: Objectget foo: function ()set bar: function (x)__proto__: Object
 console-log-object-with-getter.html:16 Array(2)0: 1length: 2get 0: function ()set 1: function (x)__proto__: Array(0)
 
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-object-preview-expected.txt b/third_party/WebKit/LayoutTests/inspector/console/console-object-preview-expected.txt
index e69679b..1936479 100644
--- a/third_party/WebKit/LayoutTests/inspector/console/console-object-preview-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/console/console-object-preview-expected.txt
@@ -10,21 +10,25 @@
 CONSOLE MESSAGE: line 28: [object Object]
 CONSOLE MESSAGE: line 30: Array with many properties
 CONSOLE MESSAGE: line 35: 0,1
-CONSOLE MESSAGE: line 37: Object with proto
-CONSOLE MESSAGE: line 40: [object Object]
-CONSOLE MESSAGE: line 42: Sparse array
-CONSOLE MESSAGE: line 45: ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,50,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
-CONSOLE MESSAGE: line 47: Dense array with indexes and propeties
-CONSOLE MESSAGE: line 53: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149
-CONSOLE MESSAGE: line 55: Object with properties containing whitespaces
-CONSOLE MESSAGE: line 62: [object Object]
-CONSOLE MESSAGE: line 64: Object with a document.all property
-CONSOLE MESSAGE: line 65: [object Object]
-CONSOLE MESSAGE: line 67: Object with special numbers
-CONSOLE MESSAGE: line 69: [object Object]
-CONSOLE MESSAGE: line 71: Object with exactly 5 properties: expected to be lossless
-CONSOLE MESSAGE: line 72: [object Object]
-CONSOLE MESSAGE: line 74: [object Object]
+CONSOLE MESSAGE: line 37: Array with gaps and overflow
+CONSOLE MESSAGE: line 42: ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,8,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,11,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,12,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,14,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,15,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,16,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,18,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,19,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,20,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,21,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,22,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,23,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,24,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,25,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,26,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,27,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,28,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,29,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,30,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,31,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,32,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,33,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,34,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,35,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,36,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,37,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,38,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,39,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,40,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,41,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,42,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,43,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,44,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,45,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,46,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,47,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,48,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,49,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,50,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,51,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,52,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,53,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,54,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,55,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,56,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,57,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,58,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,59,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,60,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,61,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,62,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,63,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,64,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,65,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,66,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,67,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,68,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,69,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,70,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,71,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,72,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,73,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,74,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,75,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,76,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,77,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,78,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,79,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,80,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,81,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,82,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,83,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,84,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,85,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,86,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,87,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,88,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,89,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,90,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,91,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,92,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,93,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,94,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,95,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,96,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,97,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,98,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,99,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,100
+CONSOLE MESSAGE: line 44: Array with gaps without overflow
+CONSOLE MESSAGE: line 49: ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,8,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,11,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,12,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,14,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,15,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,16,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,18,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,19,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,20,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,21,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,22,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,23,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,24,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,25,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,26,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,27,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,28,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,29,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,30,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,31,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,32,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,33,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,34,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,35,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,36,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,37,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,38,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,39,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,40,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,41,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,42,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,43,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,44,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,45,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,46,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,47,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,48,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,49,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,50,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,51,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,52,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,53,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,54,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,55,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,56,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,57,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,58,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,59,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,60,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,61,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,62,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,63,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,64,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,65,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,66,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,67,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,68,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,69,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,70,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,71,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,72,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,73,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,74,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,75,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,76,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,77,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,78,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,79,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,80,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,81,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,82,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,83,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,84,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,85,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,86,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,87,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,88,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,89,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,90,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,91,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,92,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,93,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,94,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,95,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,96,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,97,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,98
+CONSOLE MESSAGE: line 51: Object with proto
+CONSOLE MESSAGE: line 54: [object Object]
+CONSOLE MESSAGE: line 56: Sparse array
+CONSOLE MESSAGE: line 59: ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,50,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+CONSOLE MESSAGE: line 61: Dense array with indexes and propeties
+CONSOLE MESSAGE: line 67: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149
+CONSOLE MESSAGE: line 69: Object with properties containing whitespaces
+CONSOLE MESSAGE: line 76: [object Object]
+CONSOLE MESSAGE: line 78: Object with a document.all property
+CONSOLE MESSAGE: line 79: [object Object]
+CONSOLE MESSAGE: line 81: Object with special numbers
+CONSOLE MESSAGE: line 83: [object Object]
+CONSOLE MESSAGE: line 85: Object with exactly 5 properties: expected to be lossless
+CONSOLE MESSAGE: line 86: [object Object]
+CONSOLE MESSAGE: line 88: [object Object]
 Tests that console produces instant previews for arrays and objects.
 
 console-object-preview.html:9 Mutating object in a loop console-message > source-code > console-message-url devtools-link > console-message-text
@@ -39,21 +43,25 @@
 console-object-preview.html:28 Object {property_0: 0, property_1: 1, property_2: 2, property_3: 3, property_4: 4…} console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-object source-code > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element > selection fill > console-object-preview > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > children
 console-object-preview.html:30 Array with many properties console-message > source-code > console-message-url devtools-link > console-message-text
 console-object-preview.html:35 [0, 1, property_0: 0, property_1: 1, property_2: 2, property_3: 3, property_4: 4…] console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-array source-code > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element > selection fill > console-object-preview > object-value-number > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > children
-console-object-preview.html:37 Object with proto console-message > source-code > console-message-url devtools-link > console-message-text
-console-object-preview.html:40 Object {d: 1} console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-object source-code > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element > selection fill > console-object-preview > name > object-value-number > children
-console-object-preview.html:42 Sparse array console-message > source-code > console-message-url devtools-link > console-message-text
-console-object-preview.html:45 [50: 50] console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-array source-code > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element > selection fill > console-object-preview > name > object-value-number > children
-console-object-preview.html:47 Dense array with indexes and propeties console-message > source-code > console-message-url devtools-link > console-message-text
-console-object-preview.html:53 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99…] console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-array source-code > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element > selection fill > console-object-preview > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > children
-console-object-preview.html:55 Object with properties containing whitespaces console-message > source-code > console-message-url devtools-link > console-message-text
-console-object-preview.html:62 Object {" a b ": " a b ", c d: "c d", "": "", "  ": "  ", "a↵↵b↵c": "a↵↵b↵c"} console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-object source-code > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element > selection fill > console-object-preview > name > object-value-string > name > object-value-string > name > object-value-string > name > object-value-string > name > object-value-string > children
-console-object-preview.html:64 Object with a document.all property console-message > source-code > console-message-url devtools-link > console-message-text
-console-object-preview.html:65 Object {all: HTMLAllCollection(7)} console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-object source-code > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element > selection fill > console-object-preview > name > object-value-array > children
-console-object-preview.html:67 Object with special numbers console-message > source-code > console-message-url devtools-link > console-message-text
-console-object-preview.html:69 Object {nan: NaN, posInf: Infinity, negInf: -Infinity, negZero: -0} console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-object source-code > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element > selection fill > console-object-preview > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > children
-console-object-preview.html:71 Object with exactly 5 properties: expected to be lossless console-message > source-code > console-message-url devtools-link > console-message-text
-console-object-preview.html:72 Object {a: 1, b: 2, c: 3, d: 4, e: 5} console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-object source-code > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element > selection fill > console-object-preview > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > children
-console-object-preview.html:74 Object {null: null, undef: undefined, regexp: /^[regexp]$/g, bool: false} console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-object source-code > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element > selection fill > console-object-preview > name > object-value-null > name > object-value-undefined > name > object-value-regexp > name > object-value-boolean > children
+console-object-preview.html:37 Array with gaps and overflow console-message > source-code > console-message-url devtools-link > console-message-text
+console-object-preview.html:42 [32: 0, 89: 1, 146: 2, 203: 3, 260: 4, 317: 5, 374: 6, 431: 7, 488: 8, 545: 9, 602: 10, 659: 11, 716: 12, 773: 13, 830: 14, 887: 15, 944: 16, 1001: 17, 1058: 18, 1115: 19, 1172: 20, 1229: 21, 1286: 22, 1343: 23, 1400: 24, 1457: 25, 1514: 26, 1571: 27, 1628: 28, 1685: 29, 1742: 30, 1799: 31, 1856: 32, 1913: 33, 1970: 34, 2027: 35, 2084: 36, 2141: 37, 2198: 38, 2255: 39, 2312: 40, 2369: 41, 2426: 42, 2483: 43, 2540: 44, 2597: 45, 2654: 46, 2711: 47, 2768: 48, 2825: 49, 2882: 50, 2939: 51, 2996: 52, 3053: 53, 3110: 54, 3167: 55, 3224: 56, 3281: 57, 3338: 58, 3395: 59, 3452: 60, 3509: 61, 3566: 62, 3623: 63, 3680: 64, 3737: 65, 3794: 66, 3851: 67, 3908: 68, 3965: 69, 4022: 70, 4079: 71, 4136: 72, 4193: 73, 4250: 74, 4307: 75, 4364: 76, 4421: 77, 4478: 78, 4535: 79, 4592: 80, 4649: 81, 4706: 82, 4763: 83, 4820: 84, 4877: 85, 4934: 86, 4991: 87, 5048: 88, 5105: 89, 5162: 90, 5219: 91, 5276: 92, 5333: 93, 5390: 94, 5447: 95, 5504: 96, 5561: 97, 5618: 98, 5675: 99…] console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-array source-code > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element > selection fill > console-object-preview > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > children
+console-object-preview.html:44 Array with gaps without overflow console-message > source-code > console-message-url devtools-link > console-message-text
+console-object-preview.html:49 [undefined × 32, 0, undefined × 56, 1, undefined × 56, 2, undefined × 56, 3, undefined × 56, 4, undefined × 56, 5, undefined × 56, 6, undefined × 56, 7, undefined × 56, 8, undefined × 56, 9, undefined × 56, 10, undefined × 56, 11, undefined × 56, 12, undefined × 56, 13, undefined × 56, 14, undefined × 56, 15, undefined × 56, 16, undefined × 56, 17, undefined × 56, 18, undefined × 56, 19, undefined × 56, 20, undefined × 56, 21, undefined × 56, 22, undefined × 56, 23, undefined × 56, 24, undefined × 56, 25, undefined × 56, 26, undefined × 56, 27, undefined × 56, 28, undefined × 56, 29, undefined × 56, 30, undefined × 56, 31, undefined × 56, 32, undefined × 56, 33, undefined × 56, 34, undefined × 56, 35, undefined × 56, 36, undefined × 56, 37, undefined × 56, 38, undefined × 56, 39, undefined × 56, 40, undefined × 56, 41, undefined × 56, 42, undefined × 56, 43, undefined × 56, 44, undefined × 56, 45, undefined × 56, 46, undefined × 56, 47, undefined × 56, 48, undefined × 56, 49, un console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-array source-code > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element > selection fill > console-object-preview > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > object-value-undefined > object-value-number > children
+console-object-preview.html:51 Object with proto console-message > source-code > console-message-url devtools-link > console-message-text
+console-object-preview.html:54 Object {d: 1} console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-object source-code > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element > selection fill > console-object-preview > name > object-value-number > children
+console-object-preview.html:56 Sparse array console-message > source-code > console-message-url devtools-link > console-message-text
+console-object-preview.html:59 [undefined × 50, 50, undefined × 99] console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-array source-code > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element > selection fill > console-object-preview > object-value-undefined > object-value-number > object-value-undefined > children
+console-object-preview.html:61 Dense array with indexes and propeties console-message > source-code > console-message-url devtools-link > console-message-text
+console-object-preview.html:67 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99…] console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-array source-code > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element > selection fill > console-object-preview > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > children
+console-object-preview.html:69 Object with properties containing whitespaces console-message > source-code > console-message-url devtools-link > console-message-text
+console-object-preview.html:76 Object {" a b ": " a b ", c d: "c d", "": "", "  ": "  ", "a↵↵b↵c": "a↵↵b↵c"} console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-object source-code > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element > selection fill > console-object-preview > name > object-value-string > name > object-value-string > name > object-value-string > name > object-value-string > name > object-value-string > children
+console-object-preview.html:78 Object with a document.all property console-message > source-code > console-message-url devtools-link > console-message-text
+console-object-preview.html:79 Object {all: HTMLAllCollection(7)} console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-object source-code > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element > selection fill > console-object-preview > name > object-value-array > children
+console-object-preview.html:81 Object with special numbers console-message > source-code > console-message-url devtools-link > console-message-text
+console-object-preview.html:83 Object {nan: NaN, posInf: Infinity, negInf: -Infinity, negZero: -0} console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-object source-code > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element > selection fill > console-object-preview > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > children
+console-object-preview.html:85 Object with exactly 5 properties: expected to be lossless console-message > source-code > console-message-url devtools-link > console-message-text
+console-object-preview.html:86 Object {a: 1, b: 2, c: 3, d: 4, e: 5} console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-object source-code > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element > selection fill > console-object-preview > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > children
+console-object-preview.html:88 Object {null: null, undef: undefined, regexp: /^[regexp]$/g, bool: false} console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-object source-code > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element > selection fill > console-object-preview > name > object-value-null > name > object-value-undefined > name > object-value-regexp > name > object-value-boolean > children
 Expanded all messages
 console-object-preview.html:9 Mutating object in a loop console-message > source-code > console-message-url devtools-link > console-message-text
 console-object-preview.html:13 Objecta: 0b: 0c: 2__proto__: Object console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-object source-code expanded > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element expanded > selection fill > object-state-note info-note > children expanded > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > parent > selection fill > name object-properties-section-dimmed > object-properties-section-separator > value object-value-object > children
@@ -67,19 +75,23 @@
 console-object-preview.html:28 Objectproperty_0: 0property_1: 1property_2: 2property_3: 3property_4: 4property_5: 5property_6: 6property_7: 7property_8: 8property_9: 9__proto__: Object console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-object source-code expanded > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element expanded > selection fill > object-state-note info-note > children expanded > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > parent > selection fill > name object-properties-section-dimmed > object-properties-section-separator > value object-value-object > children
 console-object-preview.html:30 Array with many properties console-message > source-code > console-message-url devtools-link > console-message-text
 console-object-preview.html:35 Array(2)0: 01: 1property_0: 0property_1: 1property_2: 2property_3: 3property_4: 4property_5: 5property_6: 6property_7: 7property_8: 8property_9: 9length: 2__proto__: Array(0) console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-array source-code expanded > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element expanded > selection fill > object-state-note info-note > children expanded > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name object-properties-section-dimmed > object-properties-section-separator > value object-value-number > children > parent > selection fill > name object-properties-section-dimmed > object-properties-section-separator > value object-value-array > children
-console-object-preview.html:37 Object with proto console-message > source-code > console-message-url devtools-link > console-message-text
-console-object-preview.html:40 Objectd: 1__proto__: Object console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-object source-code expanded > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element expanded > selection fill > object-state-note info-note > children expanded > selection fill > name > object-properties-section-separator > value object-value-number > children > parent > selection fill > name object-properties-section-dimmed > object-properties-section-separator > value object-value-object > children
-console-object-preview.html:42 Sparse array console-message > source-code > console-message-url devtools-link > console-message-text
-console-object-preview.html:45 Array(150)50: 50length: 150__proto__: Array(0) console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-array source-code expanded > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element expanded > selection fill > object-state-note info-note > children expanded > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name object-properties-section-dimmed > object-properties-section-separator > value object-value-number > children > parent > selection fill > name object-properties-section-dimmed > object-properties-section-separator > value object-value-array > children
-console-object-preview.html:47 Dense array with indexes and propeties console-message > source-code > console-message-url devtools-link > console-message-text
-console-object-preview.html:53 Array(150)[0 … 99][100 … 149]property_0: 0property_1: 1property_2: 2property_3: 3property_4: 4property_5: 5property_6: 6property_7: 7property_8: 8property_9: 9property_10: 10property_11: 11property_12: 12property_13: 13property_14: 14property_15: 15property_16: 16property_17: 17property_18: 18property_19: 19property_20: 20property_21: 21property_22: 22property_23: 23property_24: 24property_25: 25property_26: 26property_27: 27property_28: 28property_29: 29property_30: 30property_31: 31property_32: 32property_33: 33property_34: 34property_35: 35property_36: 36property_37: 37property_38: 38property_39: 39property_40: 40property_41: 41property_42: 42property_43: 43property_44: 44property_45: 45property_46: 46property_47: 47property_48: 48property_49: 49property_50: 50property_51: 51property_52: 52property_53: 53property_54: 54property_55: 55property_56: 56property_57: 57property_58: 58property_59: 59property_60: 60property_61: 61property_62: 62property_63: 63property_64: 64property_ console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-array source-code expanded > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element expanded > selection fill > object-state-note info-note > children expanded > parent object-properties-section-name > selection fill > tree-element-title > children > parent object-properties-section-name > selection fill > tree-element-title > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name object-properties-section-dimmed > object-properties-section-separator > value object-value-number > children > parent > selection fill > name object-properties-section-dimmed > object-properties-section-separator > value object-value-array > children
-console-object-preview.html:55 Object with properties containing whitespaces console-message > source-code > console-message-url devtools-link > console-message-text
-console-object-preview.html:62 Object"": """  ": "  "" a b ": " a b ""a↵↵b↵c": "a↵↵b↵c"c d: "c d"__proto__: Object console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-object source-code expanded > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element expanded > selection fill > object-state-note info-note > children expanded > selection fill > name > object-properties-section-separator > value object-value-string > children > selection fill > name > object-properties-section-separator > value object-value-string > children > selection fill > name > object-properties-section-separator > value object-value-string > children > selection fill > name > object-properties-section-separator > value object-value-string > children > selection fill > name > object-properties-section-separator > value object-value-string > children > parent > selection fill > name object-properties-section-dimmed > object-properties-section-separator > value object-value-object > children
-console-object-preview.html:64 Object with a document.all property console-message > source-code > console-message-url devtools-link > console-message-text
-console-object-preview.html:65 Objectall: HTMLAllCollection(7)__proto__: Object console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-object source-code expanded > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element expanded > selection fill > object-state-note info-note > children expanded > parent > selection fill > name > object-properties-section-separator > value object-value-array > children > parent > selection fill > name object-properties-section-dimmed > object-properties-section-separator > value object-value-object > children
-console-object-preview.html:67 Object with special numbers console-message > source-code > console-message-url devtools-link > console-message-text
-console-object-preview.html:69 Objectnan: NaNnegInf: -InfinitynegZero: -0posInf: Infinity__proto__: Object console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-object source-code expanded > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element expanded > selection fill > object-state-note info-note > children expanded > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > parent > selection fill > name object-properties-section-dimmed > object-properties-section-separator > value object-value-object > children
-console-object-preview.html:71 Object with exactly 5 properties: expected to be lossless console-message > source-code > console-message-url devtools-link > console-message-text
-console-object-preview.html:72 Objecta: 1b: 2c: 3d: 4e: 5__proto__: Object console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-object source-code expanded > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element expanded > selection fill > object-state-note info-note > children expanded > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > parent > selection fill > name object-properties-section-dimmed > object-properties-section-separator > value object-value-object > children
-console-object-preview.html:74 Objectbool: falsenull: nullregexp: /^[regexp]$/gundef: undefined__proto__: Object console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-object source-code expanded > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element expanded > selection fill > object-state-note info-note > children expanded > selection fill > name > object-properties-section-separator > value object-value-boolean > children > selection fill > name > object-properties-section-separator > value object-value-null > children > parent > selection fill > name > object-properties-section-separator > value object-value-regexp > children > selection fill > name > object-properties-section-separator > value object-value-undefined > children > parent > selection fill > name object-properties-section-dimmed > object-properties-section-separator > value object-value-object > children
+console-object-preview.html:37 Array with gaps and overflow console-message > source-code > console-message-url devtools-link > console-message-text
+console-object-preview.html:42 Array(5733)[32 … 5675]5732: 100length: 5733__proto__: Array(0) console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-array source-code expanded > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element expanded > selection fill > object-state-note info-note > children expanded > parent object-properties-section-name > selection fill > tree-element-title > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name object-properties-section-dimmed > object-properties-section-separator > value object-value-number > children > parent > selection fill > name object-properties-section-dimmed > object-properties-section-separator > value object-value-array > children
+console-object-preview.html:44 Array with gaps without overflow console-message > source-code > console-message-url devtools-link > console-message-text
+console-object-preview.html:49 Array(5619)32: 089: 1146: 2203: 3260: 4317: 5374: 6431: 7488: 8545: 9602: 10659: 11716: 12773: 13830: 14887: 15944: 161001: 171058: 181115: 191172: 201229: 211286: 221343: 231400: 241457: 251514: 261571: 271628: 281685: 291742: 301799: 311856: 321913: 331970: 342027: 352084: 362141: 372198: 382255: 392312: 402369: 412426: 422483: 432540: 442597: 452654: 462711: 472768: 482825: 492882: 502939: 512996: 523053: 533110: 543167: 553224: 563281: 573338: 583395: 593452: 603509: 613566: 623623: 633680: 643737: 653794: 663851: 673908: 683965: 694022: 704079: 714136: 724193: 734250: 744307: 754364: 764421: 774478: 784535: 794592: 804649: 814706: 824763: 834820: 844877: 854934: 864991: 875048: 885105: 895162: 905219: 915276: 925333: 935390: 945447: 955504: 965561: 975618: 98length: 5619__proto__: Array(0) console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-array source-code expanded > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element expanded > selection fill > object-state-note info-note > children expanded > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name object-properties-section-dimmed > object-properties-section-separator > value object-value-number > children > parent > selection fill > name object-properties-section-dimmed > object-properties-section-separator > value object-value-array > children
+console-object-preview.html:51 Object with proto console-message > source-code > console-message-url devtools-link > console-message-text
+console-object-preview.html:54 Objectd: 1__proto__: Object console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-object source-code expanded > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element expanded > selection fill > object-state-note info-note > children expanded > selection fill > name > object-properties-section-separator > value object-value-number > children > parent > selection fill > name object-properties-section-dimmed > object-properties-section-separator > value object-value-object > children
+console-object-preview.html:56 Sparse array console-message > source-code > console-message-url devtools-link > console-message-text
+console-object-preview.html:59 Array(150)50: 50length: 150__proto__: Array(0) console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-array source-code expanded > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element expanded > selection fill > object-state-note info-note > children expanded > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name object-properties-section-dimmed > object-properties-section-separator > value object-value-number > children > parent > selection fill > name object-properties-section-dimmed > object-properties-section-separator > value object-value-array > children
+console-object-preview.html:61 Dense array with indexes and propeties console-message > source-code > console-message-url devtools-link > console-message-text
+console-object-preview.html:67 Array(150)[0 … 99][100 … 149]property_0: 0property_1: 1property_2: 2property_3: 3property_4: 4property_5: 5property_6: 6property_7: 7property_8: 8property_9: 9property_10: 10property_11: 11property_12: 12property_13: 13property_14: 14property_15: 15property_16: 16property_17: 17property_18: 18property_19: 19property_20: 20property_21: 21property_22: 22property_23: 23property_24: 24property_25: 25property_26: 26property_27: 27property_28: 28property_29: 29property_30: 30property_31: 31property_32: 32property_33: 33property_34: 34property_35: 35property_36: 36property_37: 37property_38: 38property_39: 39property_40: 40property_41: 41property_42: 42property_43: 43property_44: 44property_45: 45property_46: 46property_47: 47property_48: 48property_49: 49property_50: 50property_51: 51property_52: 52property_53: 53property_54: 54property_55: 55property_56: 56property_57: 57property_58: 58property_59: 59property_60: 60property_61: 61property_62: 62property_63: 63property_64: 64property_ console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-array source-code expanded > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element expanded > selection fill > object-state-note info-note > children expanded > parent object-properties-section-name > selection fill > tree-element-title > children > parent object-properties-section-name > selection fill > tree-element-title > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name object-properties-section-dimmed > object-properties-section-separator > value object-value-number > children > parent > selection fill > name object-properties-section-dimmed > object-properties-section-separator > value object-value-array > children
+console-object-preview.html:69 Object with properties containing whitespaces console-message > source-code > console-message-url devtools-link > console-message-text
+console-object-preview.html:76 Object"": """  ": "  "" a b ": " a b ""a↵↵b↵c": "a↵↵b↵c"c d: "c d"__proto__: Object console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-object source-code expanded > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element expanded > selection fill > object-state-note info-note > children expanded > selection fill > name > object-properties-section-separator > value object-value-string > children > selection fill > name > object-properties-section-separator > value object-value-string > children > selection fill > name > object-properties-section-separator > value object-value-string > children > selection fill > name > object-properties-section-separator > value object-value-string > children > selection fill > name > object-properties-section-separator > value object-value-string > children > parent > selection fill > name object-properties-section-dimmed > object-properties-section-separator > value object-value-object > children
+console-object-preview.html:78 Object with a document.all property console-message > source-code > console-message-url devtools-link > console-message-text
+console-object-preview.html:79 Objectall: HTMLAllCollection(7)__proto__: Object console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-object source-code expanded > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element expanded > selection fill > object-state-note info-note > children expanded > parent > selection fill > name > object-properties-section-separator > value object-value-array > children > parent > selection fill > name object-properties-section-dimmed > object-properties-section-separator > value object-value-object > children
+console-object-preview.html:81 Object with special numbers console-message > source-code > console-message-url devtools-link > console-message-text
+console-object-preview.html:83 Objectnan: NaNnegInf: -InfinitynegZero: -0posInf: Infinity__proto__: Object console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-object source-code expanded > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element expanded > selection fill > object-state-note info-note > children expanded > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > parent > selection fill > name object-properties-section-dimmed > object-properties-section-separator > value object-value-object > children
+console-object-preview.html:85 Object with exactly 5 properties: expected to be lossless console-message > source-code > console-message-url devtools-link > console-message-text
+console-object-preview.html:86 Objecta: 1b: 2c: 3d: 4e: 5__proto__: Object console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-object source-code expanded > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element expanded > selection fill > object-state-note info-note > children expanded > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > selection fill > name > object-properties-section-separator > value object-value-number > children > parent > selection fill > name object-properties-section-dimmed > object-properties-section-separator > value object-value-object > children
+console-object-preview.html:88 Objectbool: falsenull: nullregexp: /^[regexp]$/gundef: undefined__proto__: Object console-message > source-code > console-message-url devtools-link > console-message-text > console-view-object-properties-section object-value-object source-code expanded > tree-outline-disclosure tree-outline-disclosure-hide-overflow > tree-outline source-code object-properties-section > parent object-properties-section-root-element expanded > selection fill > object-state-note info-note > children expanded > selection fill > name > object-properties-section-separator > value object-value-boolean > children > selection fill > name > object-properties-section-separator > value object-value-null > children > parent > selection fill > name > object-properties-section-separator > value object-value-regexp > children > selection fill > name > object-properties-section-separator > value object-value-undefined > children > parent > selection fill > name object-properties-section-dimmed > object-properties-section-separator > value object-value-object > children
 
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-object-preview.html b/third_party/WebKit/LayoutTests/inspector/console/console-object-preview.html
index eea7136..6ed10e6 100644
--- a/third_party/WebKit/LayoutTests/inspector/console/console-object-preview.html
+++ b/third_party/WebKit/LayoutTests/inspector/console/console-object-preview.html
@@ -34,6 +34,20 @@
     }
     console.log(arrayWithManyProperties);
 
+    console.log("Array with gaps and overflow");
+    var arrayWithGapsAndOverflow = [];
+    for (var i = 0; i < 101; i++) {
+        arrayWithGapsAndOverflow[57 * i + 32] = i;
+    }
+    console.log(arrayWithGapsAndOverflow);
+
+    console.log("Array with gaps without overflow");
+    var arrayWithGapsWithoutOverflow = [];
+    for (var i = 0; i < 99; i++) {
+        arrayWithGapsWithoutOverflow[57 * i + 32] = i;
+    }
+    console.log(arrayWithGapsWithoutOverflow);
+
     console.log("Object with proto");
     var objectWithProto = { d: 1 };
     objectWithProto.__proto__ = object;
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-save-to-temp-var-expected.txt b/third_party/WebKit/LayoutTests/inspector/console/console-save-to-temp-var-expected.txt
index db6a0d2e..c080021 100644
--- a/third_party/WebKit/LayoutTests/inspector/console/console-save-to-temp-var-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/console/console-save-to-temp-var-expected.txt
@@ -20,7 +20,7 @@
 temp13
 Object {foo: "bar"}
 temp14
-[1, 2, 3, 4]
+[1, 2, 3, 4, callee: function, Symbol(Symbol.iterator): function]
 temp15
 function func() {}
 temp16
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-tainted-globals-expected.txt b/third_party/WebKit/LayoutTests/inspector/console/console-tainted-globals-expected.txt
index bf9abcc3..d37be47 100644
--- a/third_party/WebKit/LayoutTests/inspector/console/console-tainted-globals-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/console/console-tainted-globals-expected.txt
@@ -13,7 +13,7 @@
 testThrowConstructorName()
 Object {}
 testOverriddenIsFinite()
-["arg1", "arg2"]
+["arg1", "arg2", callee: function, Symbol(Symbol.iterator): function]
 testOverriddenError()
 Object {result: "PASS"}
 restoreError()
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/debugger-inline-values-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/debugger-inline-values-expected.txt
index 4b36bb9..b0503d7c 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/debugger-inline-values-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/debugger-inline-values-expected.txt
@@ -59,7 +59,7 @@
 [ 8]       debugger; 	
 [ 9]       var a = { k: 1 }; 	 a = Object {k: 1}
 [10]       var b = [1, 2, 3, 4, 5]; 	 b = [1, 2, 3, 4, 5]
-[11]       var c = new Array(100); c[10] = 1; 	 c = [10: 1]
+[11]       var c = new Array(100); c[10] = 1; 	 c = [undefined × 10, 1, undefined × 89]
 [12] >     a.k = 2; 	
 [13]       a.l = window; 	
 [14]       b[1]++; 	
@@ -70,7 +70,7 @@
 [ 8]       debugger; 	
 [ 9]       var a = { k: 1 }; 	 a = Object {k: 2}
 [10]       var b = [1, 2, 3, 4, 5]; 	 b = [1, 2, 3, 4, 5]
-[11]       var c = new Array(100); c[10] = 1; 	 c = [10: 1]
+[11]       var c = new Array(100); c[10] = 1; 	 c = [undefined × 10, 1, undefined × 89]
 [12]       a.k = 2; 	 a = Object {k: 2}
 [13] >     a.l = window; 	
 [14]       b[1]++; 	
@@ -81,7 +81,7 @@
 [ 8]       debugger; 	
 [ 9]       var a = { k: 1 }; 	 a = Object {k: 2, l: Window}
 [10]       var b = [1, 2, 3, 4, 5]; 	 b = [1, 2, 3, 4, 5]
-[11]       var c = new Array(100); c[10] = 1; 	 c = [10: 1]
+[11]       var c = new Array(100); c[10] = 1; 	 c = [undefined × 10, 1, undefined × 89]
 [12]       a.k = 2; 	 a = Object {k: 2, l: Window}
 [13]       a.l = window; 	 
 [14] >     b[1]++; 	
@@ -92,7 +92,7 @@
 [ 8]       debugger; 	
 [ 9]       var a = { k: 1 }; 	 a = Object {k: 2, l: Window}
 [10]       var b = [1, 2, 3, 4, 5]; 	 b = [1, 3, 3, 4, 5]
-[11]       var c = new Array(100); c[10] = 1; 	 c = [10: 1]
+[11]       var c = new Array(100); c[10] = 1; 	 c = [undefined × 10, 1, undefined × 89]
 [12]       a.k = 2; 	 a = Object {k: 2, l: Window}
 [13]       a.l = window; 	 
 [14]       b[1]++; 	 b = [1, 3, 3, 4, 5]
@@ -103,7 +103,7 @@
 [ 8]       debugger; 	
 [ 9]       var a = { k: 1 }; 	 a = Object {k: 2, l: Window}
 [10]       var b = [1, 2, 3, 4, 5]; 	 b = [1, 3, body, 4, 5]
-[11]       var c = new Array(100); c[10] = 1; 	 c = [10: 1]
+[11]       var c = new Array(100); c[10] = 1; 	 c = [undefined × 10, 1, undefined × 89]
 [12]       a.k = 2; 	 a = Object {k: 2, l: Window}
 [13]       a.l = window; 	 
 [14]       b[1]++; 	 b = [1, 3, body, 4, 5]
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/debugger-save-to-temp-var-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/debugger-save-to-temp-var-expected.txt
index b642947..8b9f8151 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/debugger-save-to-temp-var-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/debugger-save-to-temp-var-expected.txt
@@ -21,7 +21,7 @@
 temp13
 Object {foo: "bar"}
 temp14
-[1, 2, 3, 4]
+[1, 2, 3, 4, callee: function, Symbol(Symbol.iterator): function]
 temp15
 function func() {}
 temp16
diff --git a/third_party/WebKit/LayoutTests/loader/data-uri-images-load-asynchronously-expected.txt b/third_party/WebKit/LayoutTests/loader/data-uri-images-load-asynchronously-expected.txt
new file mode 100644
index 0000000..21927c9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/loader/data-uri-images-load-asynchronously-expected.txt
@@ -0,0 +1,2 @@
+Test for crbug.com/224317: data:uri images should load asynchronously.
+PASS
diff --git a/third_party/WebKit/LayoutTests/loader/data-uri-images-load-synchronously.html b/third_party/WebKit/LayoutTests/loader/data-uri-images-load-asynchronously.html
similarity index 89%
rename from third_party/WebKit/LayoutTests/loader/data-uri-images-load-synchronously.html
rename to third_party/WebKit/LayoutTests/loader/data-uri-images-load-asynchronously.html
index 7746f5b5..370eff19 100644
--- a/third_party/WebKit/LayoutTests/loader/data-uri-images-load-synchronously.html
+++ b/third_party/WebKit/LayoutTests/loader/data-uri-images-load-asynchronously.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html>
 <body>
-Test for crbug.com/224317: data:uri images should load synchronously.<br/>
+Test for crbug.com/224317: data:uri images should load asynchronously.<br/>
 <script>
     if (window.testRunner)
         testRunner.dumpAsText();
@@ -10,9 +10,9 @@
     image.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAnklEQVR42u3QMQEAAAgDoGlyo1vBzwciUJlw1ApkyZIlS5YsBbJkyZIlS5YCWbJkyZIlS4EsWbJkyZKlQJYsWbJkyVIgS5YsWbJkKZAlS5YsWbIUyJIlS5YsWQpkyZIlS5YsBbJkyZIlS5YCWbJkyZIlS4EsWbJkyZKlQJYsWbJkyVIgS5YsWbJkKZAlS5YsWbIUyJIlS5YsWQpkyfq2MosBSIeKONMAAAAASUVORK5CYII=";
 
     if (image.width == 100 && image.height == 100)
-        document.write("PASS");
-    else
         document.write("FAIL");
+    else
+        document.write("PASS");
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/loader/data-uri-images-load-synchronously-expected.txt b/third_party/WebKit/LayoutTests/loader/data-uri-images-load-synchronously-expected.txt
deleted file mode 100644
index 1dddd7e..0000000
--- a/third_party/WebKit/LayoutTests/loader/data-uri-images-load-synchronously-expected.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Test for crbug.com/224317: data:uri images should load synchronously.
-PASS
diff --git a/third_party/WebKit/LayoutTests/loader/data-uri-images-reload-asynchronously-expected.txt b/third_party/WebKit/LayoutTests/loader/data-uri-images-reload-asynchronously-expected.txt
new file mode 100644
index 0000000..8289b387
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/loader/data-uri-images-reload-asynchronously-expected.txt
@@ -0,0 +1,2 @@
+Test for crbug.com/224317: data:uri images should load asynchronously and reload synchronously.
+PASS
diff --git a/third_party/WebKit/LayoutTests/loader/data-uri-images-reload-synchronously.html b/third_party/WebKit/LayoutTests/loader/data-uri-images-reload-asynchronously.html
similarity index 65%
rename from third_party/WebKit/LayoutTests/loader/data-uri-images-reload-synchronously.html
rename to third_party/WebKit/LayoutTests/loader/data-uri-images-reload-asynchronously.html
index 9b583e07..cc83ee51 100644
--- a/third_party/WebKit/LayoutTests/loader/data-uri-images-reload-synchronously.html
+++ b/third_party/WebKit/LayoutTests/loader/data-uri-images-reload-asynchronously.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html>
 <body>
-Test for crbug.com/224317: data:uri images should reload synchronously.<br/>
+Test for crbug.com/224317: data:uri images should load asynchronously and reload synchronously.<br/>
 <script>
     if (window.testRunner) {
         testRunner.waitUntilDone();
@@ -11,17 +11,23 @@
     var image = new Image();
     image.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAnklEQVR42u3QMQEAAAgDoGlyo1vBzwciUJlw1ApkyZIlS5YsBbJkyZIlS5YCWbJkyZIlS4EsWbJkyZKlQJYsWbJkyVIgS5YsWbJkKZAlS5YsWbIUyJIlS5YsWQpkyZIlS5YsBbJkyZIlS5YCWbJkyZIlS4EsWbJkyZKlQJYsWbJkyVIgS5YsWbJkKZAlS5YsWbIUyJIlS5YsWQpkyfq2MosBSIeKONMAAAAASUVORK5CYII=";
 
-    if (image.width != 100 || image.height != 100) {
-        document.write("FAIL");
-    } else {
-        if (location.hash == "#reloaded") {
-            document.write("PASS");
+    if (location.hash != "#reloaded") {
+        if (image.width == 100 || image.height == 100) {
+            document.write("FAIL");
             if (window.testRunner)
                 testRunner.notifyDone();
         } else {
             location.hash = "#reloaded";
             location.reload();
         }
+    } else {
+        if (image.width == 100 || image.height == 100) {
+            document.write("PASS");
+        } else {
+            document.write("FAIL");
+        }
+        if (window.testRunner)
+            testRunner.notifyDone();
     }
 </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/loader/data-uri-images-reload-synchronously-expected.txt b/third_party/WebKit/LayoutTests/loader/data-uri-images-reload-synchronously-expected.txt
deleted file mode 100644
index c0ed5e95..0000000
--- a/third_party/WebKit/LayoutTests/loader/data-uri-images-reload-synchronously-expected.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Test for crbug.com/224317: data:uri images should reload synchronously.
-PASS
diff --git a/third_party/WebKit/LayoutTests/resources/bluetooth/bluetooth-helpers.js b/third_party/WebKit/LayoutTests/resources/bluetooth/bluetooth-helpers.js
index 3a9f8ee5..fdde3c6 100644
--- a/third_party/WebKit/LayoutTests/resources/bluetooth/bluetooth-helpers.js
+++ b/third_party/WebKit/LayoutTests/resources/bluetooth/bluetooth-helpers.js
@@ -234,7 +234,10 @@
 // reject if the event is fired before |object|.|func|() resolves.
 // Returns a promise that fulfills with the result of |object|.|func()|
 // and |event.target.value| of each of the other promises.
-function assert_event_fires_after_promise(object, func, event, num_listeners) {
+// If |ignore_event_promise_order| is set true, this function will ignore
+// the relative order of the event and the promise; otherwise it will assert
+// the event is triggered after the promise is resolved.
+function assert_event_fires_after_promise(object, func, event, num_listeners, ignore_event_promise_order) {
   num_listeners = num_listeners !== undefined ? num_listeners : 1;
 
   if (object[func] === undefined) {
@@ -246,7 +249,7 @@
     event_promises.push(new Promise((resolve, reject) => {
       let event_listener = (e) => {
         object.removeEventListener(event, event_listener);
-        if (should_resolve) {
+        if (should_resolve || ignore_event_promise_order) {
           resolve(e.target.value);
         } else {
           reject(event + ' was triggered before the promise resolved.');
diff --git a/third_party/WebKit/LayoutTests/svg/canvas/canvas-draw-image-globalalpha.html b/third_party/WebKit/LayoutTests/svg/canvas/canvas-draw-image-globalalpha.html
index dec1382..24ba5cd 100644
--- a/third_party/WebKit/LayoutTests/svg/canvas/canvas-draw-image-globalalpha.html
+++ b/third_party/WebKit/LayoutTests/svg/canvas/canvas-draw-image-globalalpha.html
@@ -3,7 +3,9 @@
 <script>
 var img = new Image();
 img.src = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg"><rect width="100" height="100" fill="#008000"/></svg>';
-var c = document.querySelector('canvas').getContext('2d');
-c.globalAlpha = 0.5;
-c.drawImage(img, 0, 0);
+img.onload = function() {
+    var c = document.querySelector('canvas').getContext('2d');
+    c.globalAlpha = 0.5;
+    c.drawImage(img, 0, 0);
+}
 </script>
diff --git a/third_party/WebKit/LayoutTests/svg/canvas/image-svg-intrinsic-size.html b/third_party/WebKit/LayoutTests/svg/canvas/image-svg-intrinsic-size.html
index 917e029e8..bb94b5b 100644
--- a/third_party/WebKit/LayoutTests/svg/canvas/image-svg-intrinsic-size.html
+++ b/third_party/WebKit/LayoutTests/svg/canvas/image-svg-intrinsic-size.html
@@ -8,12 +8,15 @@
       image.src = "data:image/svg+xml," +
                   "<svg xmlns='http://www.w3.org/2000/svg' width='200' viewBox='0 0 1 1'>" +
                   "<rect width='1' height='1' fill='green'/></svg>";
+      image.onload = function() {
+          var canvas = document.querySelector('canvas');
+          var ctx = canvas.getContext("2d");
+          ctx.drawImage(document.querySelector('img'), 0, 0);
+          document.body.removeChild(document.querySelector('img'));
+      };
       return image;
   }
   document.body.appendChild(createSVGImage());
   document.body.offsetTop; // Force layout
-  var canvas = document.querySelector('canvas');
-  var ctx = canvas.getContext("2d");
-  ctx.drawImage(document.querySelector('img'), 0, 0);
-  document.body.removeChild(document.querySelector('img'));
+
 </script>
diff --git a/third_party/WebKit/LayoutTests/vr/getVRDisplays_one_display.html b/third_party/WebKit/LayoutTests/vr/getVRDisplays_one_display.html
new file mode 100644
index 0000000..e2e5d3d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/vr/getVRDisplays_one_display.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="../resources/mojo-helpers.js"></script>
+<script src="resources/fake-vr-displays.js"></script>
+<script src="resources/mock-vr-service.js"></script>
+<script>
+let fakeDisplays = fakeVRDisplays();
+
+vr_test((service) => {
+  return navigator.getVRDisplays().then(devices => {
+      assert_true(devices != null);
+      assert_equals(1, devices.length);
+      assert_equals(devices[0].displayName, 'Google, Inc. Daydream View');
+      assert_true(devices[0].capabilities.hasOrientation);
+      assert_true(devices != null);
+    });
+}, [fakeDisplays['Pixel']], 'test 1 VRDisplay');
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/vr/getVRDisplays_two_display.html b/third_party/WebKit/LayoutTests/vr/getVRDisplays_two_display.html
new file mode 100644
index 0000000..c886111
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/vr/getVRDisplays_two_display.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="../resources/mojo-helpers.js"></script>
+<script src="resources/fake-vr-displays.js"></script>
+<script src="resources/mock-vr-service.js"></script>
+<script>
+let fakeDisplays = fakeVRDisplays();
+
+vr_test((service) => {
+  return navigator.getVRDisplays().then(devices => {
+      assert_true(devices != null);
+      assert_equals(2, devices.length);
+      assert_equals(devices[0].displayName, 'Google, Inc. Daydream View');
+      assert_equals(devices[1].displayName, 'FakeVRDisplay');
+      assert_true(devices[0].capabilities.hasOrientation);
+      assert_true(devices[1].capabilities.hasOrientation);
+      assert_true(devices[0].capabilities.canPresent);
+      assert_false(devices[1].capabilities.canPresent);
+    });
+}, [fakeDisplays['Pixel'], fakeDisplays['FakeMagicWindowOnly']],
+'Test 2 VRDisplays');
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/vr/no_vrdisplays_test.html b/third_party/WebKit/LayoutTests/vr/getVRDisplays_zero_display.html
similarity index 87%
rename from third_party/WebKit/LayoutTests/vr/no_vrdisplays_test.html
rename to third_party/WebKit/LayoutTests/vr/getVRDisplays_zero_display.html
index a104189b..41bcafb 100644
--- a/third_party/WebKit/LayoutTests/vr/no_vrdisplays_test.html
+++ b/third_party/WebKit/LayoutTests/vr/getVRDisplays_zero_display.html
@@ -5,11 +5,11 @@
 <script src="resources/mock-vr-service.js"></script>
 <script>
 
-vr_test(() => {
+vr_test((service) => {
   return  navigator.getVRDisplays().then(devices => {
       assert_true(devices != null);
       assert_equals(0, devices.length);
     });
-}, null, 'test no VRDisplay');
+}, [], 'test no VRDisplay');
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/vr/requestPresent_reject_nogesture.html b/third_party/WebKit/LayoutTests/vr/requestPresent_reject_nogesture.html
new file mode 100644
index 0000000..6758b24
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/vr/requestPresent_reject_nogesture.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="../resources/mojo-helpers.js"></script>
+<script src="resources/fake-vr-displays.js"></script>
+<script src="resources/mock-vr-service.js"></script>
+<canvas id="webgl-canvas"></canvas>
+<script src="resources/presentation-setup.js"></script>
+<script>
+let fakeDisplays = fakeVRDisplays();
+
+vr_test((service) => {
+  return navigator.getVRDisplays().then(displays => {
+      assert_true(displays != null);
+      assert_equals(1, displays.length);
+      promise_test( function() {
+        return promise_rejects(this, 'InvalidStateError',
+            displays[0].requestPresent([{ source : webglCanvas }]));
+      }, 'requestPresent rejected');
+    });
+}, [fakeDisplays['Pixel']],
+'Test requestPresent rejects without user gesture');
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/vr/requestPresent_reject_notsupported.html b/third_party/WebKit/LayoutTests/vr/requestPresent_reject_notsupported.html
new file mode 100644
index 0000000..4f0f69e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/vr/requestPresent_reject_notsupported.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="../resources/mojo-helpers.js"></script>
+<script src="resources/fake-vr-displays.js"></script>
+<script src="resources/mock-vr-service.js"></script>
+<canvas id="webgl-canvas"></canvas>
+<script src="resources/presentation-setup.js"></script>
+<script>
+let fakeDisplays = fakeVRDisplays();
+
+vr_test((service) => {
+  return navigator.getVRDisplays().then(displays => {
+      assert_true(displays != null);
+      assert_equals(1, displays.length);
+      var asyncTest = async_test(
+          "requestPresent rejects and does not present");
+      runWithUserGesture( () => {
+        displays[0].requestPresent([{ source : webglCanvas }]).then( () => {
+          asyncTest.step( () => {
+            assert_unreached();
+          }, "Display should be presenting");
+        }, (err) => {
+          asyncTest.step( () => {
+            assert_false(displays[0].isPresenting);
+          }, "requestPresent rejected and not presenting");
+        }).then( () => {
+          asyncTest.done();
+        });
+      });
+    });
+}, [fakeDisplays['FakeMagicWindowOnly']],
+'Test requestPresent rejects if display does not support it');
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/vr/requestPresent_resolve.html b/third_party/WebKit/LayoutTests/vr/requestPresent_resolve.html
new file mode 100644
index 0000000..47a5a55
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/vr/requestPresent_resolve.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="../resources/mojo-helpers.js"></script>
+<script src="resources/fake-vr-displays.js"></script>
+<script src="resources/mock-vr-service.js"></script>
+<canvas id="webgl-canvas"></canvas>
+<script src="resources/presentation-setup.js"></script>
+<script>
+let fakeDisplays = fakeVRDisplays();
+
+vr_test((service) => {
+  return navigator.getVRDisplays().then(displays => {
+      assert_true(displays != null);
+      assert_equals(1, displays.length);
+      var asyncTest = async_test(
+          "requestPresent resolves and actually presents");
+      runWithUserGesture( () => {
+        displays[0].requestPresent([{ source : webglCanvas }]).then( () => {
+          asyncTest.step( () => {
+            assert_true(displays[0].isPresenting);
+          }, "Display should be presenting");
+        }, (err) => {
+          asyncTest.step( () => {
+            assert_unreached(err);
+          }, "Should never reach here");
+        }).then( () => {
+          asyncTest.done();
+        });
+      });
+    });
+}, [fakeDisplays['Pixel']],
+'Test requestPresent resolves');
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/vr/resources/fake-vr-displays.js b/third_party/WebKit/LayoutTests/vr/resources/fake-vr-displays.js
index 2e50caa..f469e9c 100644
--- a/third_party/WebKit/LayoutTests/vr/resources/fake-vr-displays.js
+++ b/third_party/WebKit/LayoutTests/vr/resources/fake-vr-displays.js
@@ -1,41 +1,68 @@
 'use strict';
 
 function fakeVRDisplays(){
-  return [{
-  index : 0,
-  displayName : "FakeVRDevice",
-  capabilities : {
-    hasOrientation : true,
-    hasPosition : false,
-    hasExternalDisplay : false,
-    canPresent : false,
-  },
-  stageParameters : null,
-  leftEye : {
-    fieldOfView : {
-      upDegrees : 45,
-      downDegrees : 45,
-      leftDegrees : 45,
-      rightDegrees : 45,
+  let generic_fov = {
+    upDegrees : 45,
+    downDegrees : 45,
+    leftDegrees : 45,
+    rightDegrees : 45,
+  };
+
+  return {
+    FakeMagicWindowOnly: {
+      displayName : "FakeVRDisplay",
+      capabilities : {
+        hasOrientation : true,
+        hasPosition : false,
+        hasExternalDisplay : true,
+        canPresent : false
+      },
+      stageParameters : null,
+      leftEye : {
+        fieldOfView: generic_fov,
+        offset : [-0.03, 0, 0],
+        renderWidth: 1024,
+        renderHeight: 1024
+      },
+      rightEye : {
+        fieldOfView : generic_fov,
+        offset : [0.03, 0, 0],
+        renderWidth: 1024,
+        renderHeight: 1024
+      }
     },
-    offset : [
-      -0.03, 0, 0
-    ],
-    renderWidth : 1024,
-    renderHeight : 1024,
-  },
-  rightEye : {
-    fieldOfView : {
-      upDegrees : 45,
-      downDegrees : 45,
-      leftDegrees : 45,
-      rightDegrees : 45,
-    },
-    offset : [
-      0.03, 0, 0
-    ],
-    renderWidth : 1024,
-    renderHeigth : 1024,
-  }
-}];
+    Pixel: { // Pixel info as of Dec. 22 2016
+      displayName : "Google, Inc. Daydream View",
+      capabilities : {
+        hasOrientation : true,
+        hasPosition : false,
+        hasExternalDisplay : false,
+        canPresent : true,
+      },
+      stageParameters : null,
+      leftEye : {
+        fieldOfView : {
+          upDegrees : 48.316,
+          downDegrees : 50.099,
+          leftDegrees : 35.197,
+          rightDegrees : 50.899,
+        },
+        offset : [-0.032, 0, 0],
+        renderWidth : 0,
+        renderHeight : 0
+      },
+      rightEye : {
+        fieldOfView : {
+          upDegrees : 48.316,
+          downDegrees : 50.099,
+          leftDegrees: 50.899,
+          rightDegrees: 35.197
+        },
+        offset : [0.032, 0, 0],
+        renderWidth : 0,
+        renderHeight : 0
+      }
+    }
+    // TODO(bsheedy) add more displays like Rift/Vive
+  };
 }
diff --git a/third_party/WebKit/LayoutTests/vr/resources/mock-vr-service.js b/third_party/WebKit/LayoutTests/vr/resources/mock-vr-service.js
index 1d76e6b..7946790 100644
--- a/third_party/WebKit/LayoutTests/vr/resources/mock-vr-service.js
+++ b/third_party/WebKit/LayoutTests/vr/resources/mock-vr-service.js
@@ -21,6 +21,10 @@
       this.router_ = new router.Router(handle);
       this.router_.setIncomingReceiver(this);
     }
+
+    requestPresent(secureOrigin) {
+      return Promise.resolve({success: true});
+    }
   }
 
   class MockVRService extends vr_service.VRService.stubClass {
@@ -29,7 +33,7 @@
       interfaceProvider.addInterfaceOverrideForTesting(
           vr_service.VRService.name,
           handle => this.connect_(handle));
-      this.vrDisplays_ = null;
+      this.vr_displays_ = null;
     }
 
     connect_(handle) {
@@ -38,25 +42,36 @@
     }
 
     setVRDisplays(displays) {
-      this.vrDisplays_ = displays;
+      for (let i = 0; i < displays.length; i++) {
+        displays[i].index = i;
+      }
+      this.vr_displays_ = displays;
+    }
+
+    notifyClientOfDisplays() {
+      if (this.vr_displays_ == null) {
+        return;
+      }
+      for (let i = 0; i < this.vr_displays_.length; i++) {
+        let displayPtr = new vr_service.VRDisplayPtr();
+        let request = bindings.makeRequest(displayPtr);
+        let binding = new bindings.Binding(
+            vr_service.VRDisplay,
+            new MockVRDisplay(mojo.frameInterfaces), request);
+        let client_handle = new bindings.InterfaceRequest(
+          connection.bindProxy(proxy => {
+            this.displayClient_ = proxy;
+        }, vr_service.VRDisplayClient));
+        this.client_.onDisplayConnected(displayPtr, client_handle, this.vr_displays_[i]);
+      }
     }
 
     setClient(client) {
-      if (this.vrDisplays_ != null) {
-        this.vrDisplays_.forEach(display => {
-          var displayPtr = new vr_service.VRDisplayPtr();
-          var request = bindings.makeRequest(displayPtr);
-          var binding = new bindings.Binding(
-              vr_service.VRDisplay,
-              new MockVRDisplay(mojo.frameInterfaces), request);
-          var client_handle = new bindings.InterfaceRequest(
-            connection.bindProxy(proxy => {}, vr_service.VRDisplayClient));
-          client.onDisplayConnected(displayPtr, client_handle, display);
-        });
-        return Promise.resolve(
-            {numberOfConnectedDevices: this.vrDisplays_.length});
-      }
-      return Promise.resolve({numberOfConnectedDevices: 0});
+      this.client_ = client;
+      this.notifyClientOfDisplays();
+
+      var device_number = (this.vr_displays_== null ? 0 : this.vr_displays_.length);
+      return Promise.resolve({numberOfConnectedDevices: device_number});
     }
   }
 
@@ -69,5 +84,3 @@
     return func();
   }), name, properties);
 }
-
-
diff --git a/third_party/WebKit/LayoutTests/vr/resources/presentation-setup.js b/third_party/WebKit/LayoutTests/vr/resources/presentation-setup.js
new file mode 100644
index 0000000..33c8269e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/vr/resources/presentation-setup.js
@@ -0,0 +1,15 @@
+var webglCanvas = document.getElementById("webgl-canvas");
+var glAttributes = {
+  alpha : false,
+  antialias : false,
+};
+var gl = webglCanvas.getContext("webgl", glAttributes);
+
+function runWithUserGesture(fn) {
+  function thunk() {
+    document.removeEventListener("keypress", thunk, false);
+    fn()
+  }
+  document.addEventListener("keypress", thunk, false);
+  eventSender.keyDown(" ", []);
+}
diff --git a/third_party/WebKit/LayoutTests/vr/vrdisplays_test.html b/third_party/WebKit/LayoutTests/vr/vrdisplays_test.html
deleted file mode 100644
index 47709b84..0000000
--- a/third_party/WebKit/LayoutTests/vr/vrdisplays_test.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="../resources/mojo-helpers.js"></script>
-<script src="resources/fake-vr-displays.js"></script>
-<script src="resources/mock-vr-service.js"></script>
-<script>
-
-vr_test(() => {
-  return navigator.getVRDisplays().then(displays => {
-      assert_true(displays != null);
-      assert_equals(1, displays.length);
-      assert_equals(displays[0].displayName, 'FakeVRDevice');
-      assert_true(displays[0].capabilities.hasOrientation);
-      assert_true(displays != null);
-  });
-}, fakeVRDisplays(), 'test 1 VRDisplay');
-
-</script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-basic.html b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-basic.html
index bb2fca3..b790bb2 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-basic.html
@@ -4,7 +4,6 @@
 <script src="../../resources/js-test.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
-<script src="../resources/compatibility.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-byte-data.html b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-byte-data.html
index a8d1e1b..45778cc 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-byte-data.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-byte-data.html
@@ -3,7 +3,6 @@
   <head>
     <script src="../../resources/testharness.js"></script>
     <script src="../../resources/testharnessreport.js"></script> 
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <title>Test Analyser.getByteTimeDomainData()</title>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-downmix.html b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-downmix.html
index 6f919b0..6354f3c6 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-downmix.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-downmix.html
@@ -3,7 +3,6 @@
   <head>
     <script src="../../resources/testharness.js"></script>
     <script src="../../resources/testharnessreport.js"></script> 
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="../resources/fft.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-fft-scaling-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-fft-scaling-expected.txt
deleted file mode 100644
index fb72e77f..0000000
--- a/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-fft-scaling-expected.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-Test scaling of FFT data for AnalyserNode
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-PASS Actual FFT peak in the expected position (1).
-PASS Peak value is near -14.43 dBFS as expected.
-PASS Analyser correctly scaled FFT data of size 32
-PASS Actual FFT peak in the expected position (2).
-PASS Peak value is near -13.56 dBFS as expected.
-PASS Analyser correctly scaled FFT data of size 64
-PASS Actual FFT peak in the expected position (4).
-PASS Peak value is near -13.56 dBFS as expected.
-PASS Analyser correctly scaled FFT data of size 128
-PASS Actual FFT peak in the expected position (8).
-PASS Peak value is near -13.56 dBFS as expected.
-PASS Analyser correctly scaled FFT data of size 256
-PASS Actual FFT peak in the expected position (16).
-PASS Peak value is near -13.56 dBFS as expected.
-PASS Analyser correctly scaled FFT data of size 512
-PASS Actual FFT peak in the expected position (32).
-PASS Peak value is near -13.56 dBFS as expected.
-PASS Analyser correctly scaled FFT data of size 1024
-PASS Actual FFT peak in the expected position (64).
-PASS Peak value is near -13.56 dBFS as expected.
-PASS Analyser correctly scaled FFT data of size 2048
-PASS All Analyser tests passed.
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-fft-scaling.html b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-fft-scaling.html
index 25b6c88..2ee683ca 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-fft-scaling.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-fft-scaling.html
@@ -1,10 +1,10 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
-    <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
+    <script src="../../resources/testharness.js"></script>
+    <script src="../../resources/testharnessreport.js"></script>
     <script src="../resources/audit-util.js"></script>
-    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/audit.js"></script>
   </head>
 
   <body>
@@ -12,21 +12,21 @@
     <div id="console"></div>
 
     <script>
-      description("Test scaling of FFT data for AnalyserNode");
+      let audit = Audit.createTaskRunner();
 
       // The number of analysers. We have analysers from size for each of the possible sizes of 32,
       // 64, 128, 256, 512, 1024 and 2048 for a total of 7.
-      var numberOfAnalysers = 7;
-      var sampleRate = 44100;
-      var nyquistFrequency = sampleRate / 2;
+      let numberOfAnalysers = 7;
+      let sampleRate = 44100;
+      let nyquistFrequency = sampleRate / 2;
 
       // Frequency of the sine wave test signal.  Should be high enough so that we get at least one
       // full cycle for the 32-point FFT.  This should also be such that the frequency should be
       // exactly in one of the FFT bins for each of the possible FFT sizes.
-      var oscFrequency = nyquistFrequency/16;
+      let oscFrequency = nyquistFrequency/16;
 
       // The actual peak values from each analyser.  Useful for examining the results in Chrome.
-      var peakValue = new Array(numberOfAnalysers);
+      let peakValue = new Array(numberOfAnalysers);
       
       // For a 0dBFS sine wave, we would expect the FFT magnitude to be 0dB as well, but the
       // analyzer node applies a Blackman window (to smooth the estimate).  This reduces the energy
@@ -34,22 +34,20 @@
       // determined experimentally.
       //
       // See https://code.google.com/p/chromium/issues/detail?id=341596.
-      var peakThreshold = [-14.43, -13.56, -13.56, -13.56, -13.56, -13.56, -13.56];
+      let peakThreshold = [-14.43, -13.56, -13.56, -13.56, -13.56, -13.56, -13.56];
 
-      var allTestsPassed = true;
-
-      function checkResult(order, analyser) {
+      function checkResult(order, analyser, should) {
           return function () {
-              var index = order - 5;
-              var fftSize = 1 << order;
-              var fftData = new Float32Array(fftSize);
+              let index = order - 5;
+              let fftSize = 1 << order;
+              let fftData = new Float32Array(fftSize);
               analyser.getFloatFrequencyData(fftData);
 
               // Compute the frequency bin that should contain the peak.
-              var expectedBin = analyser.frequencyBinCount * (oscFrequency / nyquistFrequency);
+              let expectedBin = analyser.frequencyBinCount * (oscFrequency / nyquistFrequency);
 
               // Find the actual bin by finding the bin containing the peak.
-              var actualBin = 0;
+              let actualBin = 0;
               peakValue[index] = -1000;
               for (k = 0; k < analyser.frequencyBinCount; ++k) {
                   if (fftData[k] > peakValue[index]) {
@@ -58,77 +56,48 @@
                   }
               }
 
-              var success = true;
+              should(actualBin, (1 << order) + "-point FFT peak position")
+                .beEqualTo(expectedBin);
 
-              if (actualBin == expectedBin) {
-                  testPassed("Actual FFT peak in the expected position (" + expectedBin + ").");
-              } else {
-                  success = false;
-                  testFailed("Actual FFT peak (" + actualBin + ") differs from expected (" + expectedBin + ").");
-              }
-
-              if (peakValue[index] >= peakThreshold[index]) {
-                  testPassed("Peak value is near " + peakThreshold[index] + " dBFS as expected.");
-              } else {
-                  success = false;
-                  testFailed("Peak value of " + peakValue[index]
-                             + " is incorrect.  (Expected approximately "
-                             + peakThreshold[index] + ").");
-              }
-
-              if (success) {
-                  testPassed("Analyser correctly scaled FFT data of size " + fftSize);
-              } else {
-                  testFailed("Analyser incorrectly scaled FFT data of size " + fftSize);
-              }
-              allTestsPassed = allTestsPassed && success;
-
-              if (fftSize == 2048) {
-                  if (allTestsPassed) {
-                      testPassed("All Analyser tests passed.");
-                  } else {
-                      testFailed("At least one Analyser test failed.");
-                  }
-
-                  finishJSTest();
-              }
+              should(peakValue[index], (1 << order) +
+                  "-point FFT peak value in dBFS")
+                .beGreaterThanOrEqualTo(peakThreshold[index]);
           }
       }
 
-      function runTests() {
-          if (window.testRunner) {
-              testRunner.dumpAsText();
-              testRunner.waitUntilDone();
-          }
+      audit.define("FFT scaling tests", function (task, should) {
+        task.describe("Test Scaling of FFT in AnalyserNode");
+        let tests = [];
+        for (let k = 5; k < 12; ++k)
+          tests.push(runTest(k, should));
 
-          window.jsTestIsAsync = true;
+        Promise.all(tests)
+          .then(task.done.bind(task));
+      });
 
-          // Test each analyser size from order 5 (size 32) to 11 (size 2048).
-          for (order = 5; order < 12; ++order) {
-              // Create a new offline context for each analyser test with the number of samples
-              // exactly equal to the fft size.  This ensures that the analyser node gets the
-              // expected data from the oscillator.
-              var context = new OfflineAudioContext(1, 1 << order, sampleRate);
-              // Use a sine wave oscillator as the reference source signal.
-              var osc = context.createOscillator();
-              osc.type = "sine";
-              osc.frequency.value = oscFrequency;
-              osc.connect(context.destination);
+      function runTest(order, should) {
+        let context = new OfflineAudioContext(1, 1 << order, sampleRate);
+        // Use a sine wave oscillator as the reference source signal.
+        let osc = context.createOscillator();
+        osc.type = "sine";
+        osc.frequency.value = oscFrequency;
+        osc.connect(context.destination);
 
-              var analyser = context.createAnalyser();
-              // No smoothing to simplify the analysis of the result.
-              analyser.smoothingTimeConstant = 0;
-              analyser.fftSize = 1 << order;
-              osc.connect(analyser);
+        let analyser = context.createAnalyser();
+        // No smoothing to simplify the analysis of the result.
+        analyser.smoothingTimeConstant = 0;
+        analyser.fftSize = 1 << order;
+        osc.connect(analyser);
 
-              osc.start();
-              context.oncomplete = checkResult(order, analyser);
-              context.startRendering();
-          }
+        osc.start();
+        context.oncomplete = checkResult(order, analyser, should);
+        return context.startRendering()
+          .then(function (audioBuffer) {
+            checkResult(audioBuffer, order, analyser);
+          });
       }
 
-      runTests();
-      successfullyParsed = true;
+      audit.run();
     </script>
   </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-fft-sizing.html b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-fft-sizing.html
index 2d591e5..d3da160 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-fft-sizing.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-fft-sizing.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-float-data.html b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-float-data.html
index 19fbd104..738b5a50 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-float-data.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-float-data.html
@@ -3,7 +3,6 @@
   <head>
     <script src="../../resources/testharness.js"></script>
     <script src="../../resources/testharnessreport.js"></script> 
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <title>Test AnalyserNode getFloatTimeDomainData</title>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-freq-data-smoothing.html b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-freq-data-smoothing.html
index ef2e4dd4..603bf19 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-freq-data-smoothing.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-freq-data-smoothing.html
@@ -3,7 +3,6 @@
   <head>
     <script src="../../resources/testharness.js"></script>
     <script src="../../resources/testharnessreport.js"></script> 
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="../resources/realtimeanalyser-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-freq-data.html b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-freq-data.html
index cb9e3bea..03836c454 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-freq-data.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-freq-data.html
@@ -3,7 +3,6 @@
   <head>
     <script src="../../resources/testharness.js"></script>
     <script src="../../resources/testharnessreport.js"></script> 
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="../resources/realtimeanalyser-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-multiple-calls.html b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-multiple-calls.html
index 40dee1d..9f97886e 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-multiple-calls.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-multiple-calls.html
@@ -3,7 +3,6 @@
   <head>
     <script src="../../resources/testharness.js"></script>
     <script src="../../resources/testharnessreport.js"></script> 
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <title>Test Multiple Calls to getFloatFrequencyData</title>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-zero.html b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-zero.html
index c5776e7..c13a11e 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-zero.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-zero.html
@@ -3,7 +3,6 @@
   <head>
     <script src="../../resources/testharness.js"></script>
     <script src="../../resources/testharnessreport.js"></script> 
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <title>Test getFloatFrequencyData With Zero Inputs</title>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer-copy-channel.html b/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer-copy-channel.html
index 799f9ad13..dc6b00c 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer-copy-channel.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer-copy-channel.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <title>Test Basic Functionality of AudioBuffer.copyFromChannel and AudioBuffer.copyToChannel</title>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer-getChannelData.html b/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer-getChannelData.html
index 969236a..1c9ba36a 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer-getChannelData.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer-getChannelData.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="../resources/audioparam-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer-resample.html b/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer-resample.html
index 94a6ef61..d45aa6cd 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer-resample.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer-resample.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
   </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer.html b/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer.html
index a437eeb5..65abaa1 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer.html
@@ -4,7 +4,6 @@
 <script src="../../resources/js-test.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
-<script src="../resources/compatibility.js"></script>
 </head>
 <body>
 <script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-channels.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-channels.html
index f1d11122..f123103 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-channels.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-channels.html
@@ -5,7 +5,6 @@
 <script src="../../resources/js-test.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
-<script src="../resources/compatibility.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-detune-modulated-impulse.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-detune-modulated-impulse.html
index 290e9c9..8a8a49e 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-detune-modulated-impulse.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-detune-modulated-impulse.html
@@ -3,7 +3,6 @@
 
 <head>
   <script src="../../resources/js-test.js"></script>
-  <script src="../resources/compatibility.js"></script>
   <script src="../resources/audit-util.js"></script>
   <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-detune-modulation.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-detune-modulation.html
index c392847..9f76ea9 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-detune-modulation.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-detune-modulation.html
@@ -3,7 +3,6 @@
 
 <head>
   <script src="../../resources/js-test.js"></script>
-  <script src="../resources/compatibility.js"></script>
   <script src="../resources/audit-util.js"></script>
   <script src="../resources/audio-testing.js"></script>
   <script src="../resources/audiobuffersource-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-ended.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-ended.html
index 39b3fd94..3e72fa3 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-ended.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-ended.html
@@ -3,7 +3,6 @@
     <script src="../../resources/js-test.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audiobuffersource-testing.js"></script>
     <script>
         var context;
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-grain.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-grain.html
index 14ba0618..a50b108 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-grain.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-grain.html
@@ -3,7 +3,6 @@
   <head>
     <title>Test Start Grain with Delayed Buffer Setting </title>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
   </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-late-start.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-late-start.html
index 785b327c..c3cba0f 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-late-start.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-late-start.html
@@ -3,7 +3,6 @@
 
 <head>
   <script src="../../resources/js-test.js"></script>
-  <script src="../resources/compatibility.js"></script>
   <script src="../resources/audit-util.js"></script>
   <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-comprehensive.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-comprehensive.html
index 7e2f951..72590c1 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-comprehensive.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-comprehensive.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script src="../resources/audiobuffersource-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-grain-no-duration.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-grain-no-duration.html
index e6f4fe2..1859a77 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-grain-no-duration.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-grain-no-duration.html
@@ -4,7 +4,6 @@
 <head>
   <title>Test AudioBufferSourceNode looping without explicit duration</title>
   <script src="../../resources/js-test.js"></script>
-  <script src="../resources/compatibility.js"></script>
   <script src="../resources/audit-util.js"></script>
   <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-one-sample-loop.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-one-sample-loop.html
index cd20529..0e824a3 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-one-sample-loop.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-one-sample-loop.html
@@ -3,7 +3,6 @@
   <head>
     <title>Test AudioBufferSourceNode With Looping a Single-Sample Buffer</title>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
   </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-modulated-impulse.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-modulated-impulse.html
index df50599..9f940975 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-modulated-impulse.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-modulated-impulse.html
@@ -3,7 +3,6 @@
 
 <head>
   <script src="../../resources/js-test.js"></script>
-  <script src="../resources/compatibility.js"></script>
   <script src="../resources/audit-util.js"></script>
   <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-modulation.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-modulation.html
index 5803fab..a93250a 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-modulation.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-modulation.html
@@ -3,7 +3,6 @@
 
 <head>
   <script src="../../resources/js-test.js"></script>
-  <script src="../resources/compatibility.js"></script>
   <script src="../resources/audit-util.js"></script>
   <script src="../resources/audio-testing.js"></script>
   <script src="../resources/audiobuffersource-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-zero.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-zero.html
index f205937d..31fd3b0b 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-zero.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-zero.html
@@ -3,7 +3,6 @@
 
 <head>
   <script src="../../resources/js-test.js"></script>
-  <script src="../resources/compatibility.js"></script>
   <script src="../resources/audit-util.js"></script>
   <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate.html
index f1afb9b6..9e8740b6 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate.html
@@ -3,7 +3,6 @@
 <head>
   <title>AudioBufferSourceNode - playbackRate test</title>
   <script src="../../resources/js-test.js"></script>
-  <script src="../resources/compatibility.js"></script>
   <script src="../resources/audit-util.js"></script>
   <script src="../resources/audio-testing.js"></script>
 </head>
@@ -115,4 +114,4 @@
   successfullyParsed = true;
   </script>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-premature-loop-stop.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-premature-loop-stop.html
index 2155a3ad..241c003 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-premature-loop-stop.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-premature-loop-stop.html
@@ -4,7 +4,6 @@
 <head>
   <title>Test AudioBufferSourceNode premature loop stop</title>
   <script src="../../resources/js-test.js"></script>
-  <script src="../resources/compatibility.js"></script>
   <script src="../resources/audit-util.js"></script>
   <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-start.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-start.html
index 77fa91f5..f30c9a20 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-start.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-start.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script src="../resources/audiobuffersource-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiosource-onended.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiosource-onended.html
index 13bb9ec..a81133b 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiosource-onended.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiosource-onended.html
@@ -3,7 +3,6 @@
   <head>
     <title>Test Onended Event Listener</title>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
   </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiosource-time-limits.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiosource-time-limits.html
index 5893bdb..9b2b551 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiosource-time-limits.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiosource-time-limits.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="../resources/audioparam-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/note-grain-on-play.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/note-grain-on-play.html
index dc8640d7..fe0ca70 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/note-grain-on-play.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/note-grain-on-play.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="../resources/note-grain-on-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/note-grain-on-timing.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/note-grain-on-timing.html
index 40c1cae..cc49d1a 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/note-grain-on-timing.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/note-grain-on-timing.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="../resources/note-grain-on-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/sample-accurate-scheduling.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/sample-accurate-scheduling.html
index 3c73ba69..4dc1a7d 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/sample-accurate-scheduling.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/sample-accurate-scheduling.html
@@ -8,7 +8,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script type="text/javascript" src="../resources/buffer-loader.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-close-basic.html b/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-close-basic.html
index b0dcd02..8f34deb 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-close-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-close-basic.html
@@ -3,7 +3,6 @@
   <head>
     <title>Test AudioContext.close() closes many contexts</title>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
   </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-close.html b/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-close.html
index 7a42ad6..c97ef2c9 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-close.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-close.html
@@ -3,7 +3,6 @@
 <head>
   <title>Test AudioContext.close()</title>
   <script src="../../resources/js-test.js"></script>
-  <script src="../resources/compatibility.js"></script>
   <script src="../resources/audit-util.js"></script>
   <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-max-contexts.html b/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-max-contexts.html
index afbedef..12af774b 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-max-contexts.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-max-contexts.html
@@ -2,7 +2,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 </head>
 <body>
 <script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-suspend-resume.html b/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-suspend-resume.html
index e7115aa..037d2b8 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-suspend-resume.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-suspend-resume.html
@@ -3,7 +3,6 @@
 <head>
   <title>Test AudioContext.suspend() and AudioContext.resume()</title>
   <script src="../../resources/js-test.js"></script>
-  <script src="../resources/compatibility.js"></script>
   <script src="../resources/audit-util.js"></script>
   <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioListener/audiolistener-automation-position.html b/third_party/WebKit/LayoutTests/webaudio/AudioListener/audiolistener-automation-position.html
index 4fe126c..00e8be89 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioListener/audiolistener-automation-position.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioListener/audiolistener-automation-position.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <title>Test Automation of AudioListener</title>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-channel-rules.html b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-channel-rules.html
index 9abd5f1..487394e3 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-channel-rules.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-channel-rules.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script src="../resources/mixing-rules.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-connect-method-chaining.html b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-connect-method-chaining.html
index 86ce4921..5b27e30 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-connect-method-chaining.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-connect-method-chaining.html
@@ -3,7 +3,6 @@
 
 <head>
   <script src="../../resources/js-test.js"></script>
-  <script src="../resources/compatibility.js"></script>
   <script src="../resources/audit-util.js"></script>
   <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-connect-order.html b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-connect-order.html
index 8065033..80329fef 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-connect-order.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-connect-order.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-disconnect-audioparam.html b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-disconnect-audioparam.html
index a3cbbf55..c290b6f 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-disconnect-audioparam.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-disconnect-audioparam.html
@@ -3,7 +3,6 @@
 
 <head>
   <script src="../../resources/js-test.js"></script>
-  <script src="../resources/compatibility.js"></script>
   <script src="../resources/audit-util.js"></script>
   <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-disconnect.html b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-disconnect.html
index 1ffa3d8b..37187a6 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-disconnect.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-disconnect.html
@@ -3,7 +3,6 @@
 
 <head>
   <script src="../../resources/js-test.js"></script>
-  <script src="../resources/compatibility.js"></script>
   <script src="../resources/audit-util.js"></script>
   <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode.html b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode.html
index c4dd1dc1..ff458518 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-automation-clamping-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-automation-clamping-expected.txt
index 5cf06d2..a39e6a8 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-automation-clamping-expected.txt
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-automation-clamping-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE WARNING: line 50: BiquadFilter.frequency.linearRampToValueAtTime value -1000 outside nominal range [0, 24000]; value will be clamped.
+CONSOLE WARNING: line 49: BiquadFilter.frequency.linearRampToValueAtTime value -1000 outside nominal range [0, 24000]; value will be clamped.
 Test Clamping of Automations.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-automation-clamping.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-automation-clamping.html
index 80ad4c9..d7caa05 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-automation-clamping.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-automation-clamping.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <title>Test Clamping of Automations</title>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-connect-audioratesignal.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-connect-audioratesignal.html
index cacced01..fbd034a7 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-connect-audioratesignal.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-connect-audioratesignal.html
@@ -12,7 +12,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-exceptional-values.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-exceptional-values.html
index c8342a3..a0aedef 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-exceptional-values.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-exceptional-values.html
@@ -1,7 +1,6 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
-    <script src="../resources/compatibility.js"></script>
     <script src="../../resources/js-test.js"></script>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-exponentialRampToValueAtTime.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-exponentialRampToValueAtTime.html
index 920e90e..f3ff722 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-exponentialRampToValueAtTime.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-exponentialRampToValueAtTime.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="../resources/audioparam-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-initial-event.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-initial-event.html
index dbada25..db6c382 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-initial-event.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-initial-event.html
@@ -3,7 +3,6 @@
 
 <head>
   <script src="../../resources/js-test.js"></script>
-  <script src="../resources/compatibility.js"></script>
   <script src="../resources/audit-util.js"></script>
   <script src="../resources/audio-testing.js"></script>
   <script src="../resources/audioparam-testing.js"></script>
@@ -173,4 +172,4 @@
   </script>
 </body>
 
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-large-endtime.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-large-endtime.html
index 70c56ab..f97527aa5 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-large-endtime.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-large-endtime.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <title>AudioParam with Huge End Time</title>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-linearRamp-value-attribute.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-linearRamp-value-attribute.html
index cf1b4cd..fd27bbc 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-linearRamp-value-attribute.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-linearRamp-value-attribute.html
@@ -3,7 +3,6 @@
   <head>
     <title>Test linearRampToValue Updates the Param Value</title>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
   </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-linearRampToValueAtTime.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-linearRampToValueAtTime.html
index 2d8601a..ce9bb217 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-linearRampToValueAtTime.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-linearRampToValueAtTime.html
@@ -2,7 +2,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script src="../resources/audioparam-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-method-chaining.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-method-chaining.html
index ebdea00..0fac244 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-method-chaining.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-method-chaining.html
@@ -3,7 +3,6 @@
 
 <head>
   <script src="../../resources/js-test.js"></script>
-  <script src="../resources/compatibility.js"></script>
   <script src="../resources/audit-util.js"></script>
   <script src="../resources/audio-testing.js"></script>
   <script src="../resources/audioparam-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-negative-exponentialRamp.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-negative-exponentialRamp.html
index 7f9788c..d74819b 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-negative-exponentialRamp.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-negative-exponentialRamp.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <title>Test Negative AudioParam.exponentialRampToValueAtTime</title>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-nominal-range-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-nominal-range-expected.txt
index 0d9c91db..a971d24 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-nominal-range-expected.txt
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-nominal-range-expected.txt
@@ -1,25 +1,25 @@
-CONSOLE WARNING: line 397: Delay.delayTime.value -1 outside nominal range [0, 1.5]; value will be clamped.
-CONSOLE WARNING: line 406: Delay.delayTime.value 4 outside nominal range [0, 1.5]; value will be clamped.
-CONSOLE WARNING: line 397: StereoPanner.pan.value -3 outside nominal range [-1, 1]; value will be clamped.
-CONSOLE WARNING: line 406: StereoPanner.pan.value 3 outside nominal range [-1, 1]; value will be clamped.
-CONSOLE WARNING: line 397: DynamicsCompressor.threshold.value -201 outside nominal range [-100, 0]; value will be clamped.
-CONSOLE WARNING: line 406: DynamicsCompressor.threshold.value 1 outside nominal range [-100, 0]; value will be clamped.
-CONSOLE WARNING: line 397: DynamicsCompressor.knee.value -1 outside nominal range [0, 40]; value will be clamped.
-CONSOLE WARNING: line 406: DynamicsCompressor.knee.value 81 outside nominal range [0, 40]; value will be clamped.
-CONSOLE WARNING: line 406: DynamicsCompressor.ratio.value 41 outside nominal range [1, 20]; value will be clamped.
-CONSOLE WARNING: line 397: DynamicsCompressor.attack.value -1 outside nominal range [0, 1]; value will be clamped.
-CONSOLE WARNING: line 406: DynamicsCompressor.attack.value 3 outside nominal range [0, 1]; value will be clamped.
-CONSOLE WARNING: line 397: DynamicsCompressor.release.value -1 outside nominal range [0, 1]; value will be clamped.
-CONSOLE WARNING: line 406: DynamicsCompressor.release.value 3 outside nominal range [0, 1]; value will be clamped.
-CONSOLE WARNING: line 397: BiquadFilter.frequency.value -1 outside nominal range [0, 24000]; value will be clamped.
-CONSOLE WARNING: line 406: BiquadFilter.frequency.value 48001 outside nominal range [0, 24000]; value will be clamped.
-CONSOLE WARNING: line 397: Oscillator.frequency.value -48001 outside nominal range [-24000, 24000]; value will be clamped.
-CONSOLE WARNING: line 406: Oscillator.frequency.value 48001 outside nominal range [-24000, 24000]; value will be clamped.
-CONSOLE WARNING: line 326: Delay.delayTime.setValueAtTime value -1 outside nominal range [0, 1]; value will be clamped.
-CONSOLE WARNING: line 327: Delay.delayTime.linearRampToValueAtTime value 2 outside nominal range [0, 1]; value will be clamped.
-CONSOLE WARNING: line 328: Delay.delayTime.exponentialRampToValue value 3 outside nominal range [0, 1]; value will be clamped.
-CONSOLE WARNING: line 329: Delay.delayTime.setTargetAtTime value -1 outside nominal range [0, 1]; value will be clamped.
-CONSOLE WARNING: line 330: Delay.delayTime.setValueCurveAtTime value 1.5 outside nominal range [0, 1]; value will be clamped.
+CONSOLE WARNING: line 396: Delay.delayTime.value -1 outside nominal range [0, 1.5]; value will be clamped.
+CONSOLE WARNING: line 405: Delay.delayTime.value 4 outside nominal range [0, 1.5]; value will be clamped.
+CONSOLE WARNING: line 396: StereoPanner.pan.value -3 outside nominal range [-1, 1]; value will be clamped.
+CONSOLE WARNING: line 405: StereoPanner.pan.value 3 outside nominal range [-1, 1]; value will be clamped.
+CONSOLE WARNING: line 396: DynamicsCompressor.threshold.value -201 outside nominal range [-100, 0]; value will be clamped.
+CONSOLE WARNING: line 405: DynamicsCompressor.threshold.value 1 outside nominal range [-100, 0]; value will be clamped.
+CONSOLE WARNING: line 396: DynamicsCompressor.knee.value -1 outside nominal range [0, 40]; value will be clamped.
+CONSOLE WARNING: line 405: DynamicsCompressor.knee.value 81 outside nominal range [0, 40]; value will be clamped.
+CONSOLE WARNING: line 405: DynamicsCompressor.ratio.value 41 outside nominal range [1, 20]; value will be clamped.
+CONSOLE WARNING: line 396: DynamicsCompressor.attack.value -1 outside nominal range [0, 1]; value will be clamped.
+CONSOLE WARNING: line 405: DynamicsCompressor.attack.value 3 outside nominal range [0, 1]; value will be clamped.
+CONSOLE WARNING: line 396: DynamicsCompressor.release.value -1 outside nominal range [0, 1]; value will be clamped.
+CONSOLE WARNING: line 405: DynamicsCompressor.release.value 3 outside nominal range [0, 1]; value will be clamped.
+CONSOLE WARNING: line 396: BiquadFilter.frequency.value -1 outside nominal range [0, 24000]; value will be clamped.
+CONSOLE WARNING: line 405: BiquadFilter.frequency.value 48001 outside nominal range [0, 24000]; value will be clamped.
+CONSOLE WARNING: line 396: Oscillator.frequency.value -48001 outside nominal range [-24000, 24000]; value will be clamped.
+CONSOLE WARNING: line 405: Oscillator.frequency.value 48001 outside nominal range [-24000, 24000]; value will be clamped.
+CONSOLE WARNING: line 325: Delay.delayTime.setValueAtTime value -1 outside nominal range [0, 1]; value will be clamped.
+CONSOLE WARNING: line 326: Delay.delayTime.linearRampToValueAtTime value 2 outside nominal range [0, 1]; value will be clamped.
+CONSOLE WARNING: line 327: Delay.delayTime.exponentialRampToValue value 3 outside nominal range [0, 1]; value will be clamped.
+CONSOLE WARNING: line 328: Delay.delayTime.setTargetAtTime value -1 outside nominal range [0, 1]; value will be clamped.
+CONSOLE WARNING: line 329: Delay.delayTime.setValueCurveAtTime value 1.5 outside nominal range [0, 1]; value will be clamped.
 Test AudioParam Nominal Range Values.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-nominal-range.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-nominal-range.html
index 2d4fb750..ff1d0b2 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-nominal-range.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-nominal-range.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <title>Test AudioParam Nominal Range Values</title>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-sampling.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-sampling.html
index 807bad8..4555fa7 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-sampling.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-sampling.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="../resources/audioparam-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-continuous.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-continuous.html
index 2ca542b2..17e86a9d1 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-continuous.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-continuous.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="../resources/audioparam-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-limit.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-limit.html
index 261ffd4d..a21c38d7 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-limit.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-limit.html
@@ -3,7 +3,6 @@
   <head>
     <title>Test setTargetAtTime Approach to Limit</title>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="../resources/audioparam-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-sampling.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-sampling.html
index b1f357b..b2d201f 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-sampling.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-sampling.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="../resources/audioparam-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime.html
index 8dc95136..0fd4d74 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime.html
@@ -2,7 +2,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script src="../resources/audioparam-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueAtTime.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueAtTime.html
index b190086..e718e35 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueAtTime.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueAtTime.html
@@ -2,7 +2,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script src="../resources/audioparam-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-copy.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-copy.html
index e4626495..749d06a 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-copy.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-copy.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="../resources/panner-formulas.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-duration-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-duration-expected.txt
index b7377fd..4acfadc 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-duration-expected.txt
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-duration-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 45: [object AudioBuffer]
+CONSOLE MESSAGE: line 44: [object AudioBuffer]
 Test AudioParam setValueCurveAtTime() with Huge Duration.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-duration.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-duration.html
index be8bed96..00f04b3 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-duration.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-duration.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="../resources/audioparam-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-end.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-end.html
index 8726afe..482f2be 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-end.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-end.html
@@ -3,7 +3,6 @@
   <head>
     <title>Test Automation Following setValueCurveAtTime Automations</title>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="../resources/audio-param.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-exceptions-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-exceptions-expected.txt
index 0659c20..b2edc132 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-exceptions-expected.txt
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-exceptions-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE WARNING: line 122: Delay.delayTime.setValueCurveAtTime value 5 outside nominal range [0, 1]; value will be clamped.
+CONSOLE WARNING: line 121: Delay.delayTime.setValueCurveAtTime value 5 outside nominal range [0, 1]; value will be clamped.
 Test Exceptions from setValueCurveAtTime
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-exceptions.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-exceptions.html
index c899520..ddcbee1 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-exceptions.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-exceptions.html
@@ -3,7 +3,6 @@
   <head>
     <title>Test Exceptions from setValueCurveAtTime</title>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
   </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurveAtTime-interpolation.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurveAtTime-interpolation.html
index 677af894..0214144 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurveAtTime-interpolation.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurveAtTime-interpolation.html
@@ -3,7 +3,6 @@
   <head>
     <title>Test Interpolation for AudioParam.setValueCurveAtTime</title>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <title>Test Interpolation for AudioParam.setValueCurveAtTime</title>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurveAtTime.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurveAtTime.html
index 4af17d8..2cb0775 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurveAtTime.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurveAtTime.html
@@ -2,7 +2,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script src="../resources/audioparam-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-summingjunction.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-summingjunction.html
index 432536a..2781ce317 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-summingjunction.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-summingjunction.html
@@ -8,7 +8,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script src="../resources/mix-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-update-value-attribute.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-update-value-attribute.html
index 4a3fefb..5d59542 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-update-value-attribute.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-update-value-attribute.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="../resources/audio-param.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-allpass.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-allpass.html
index 6d8c9fa3..9305e2d 100644
--- a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-allpass.html
+++ b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-allpass.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script src="../resources/biquad-filters.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-automation.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-automation.html
index d664018..15a0a93 100644
--- a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-automation.html
+++ b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-automation.html
@@ -3,7 +3,6 @@
   <head>
     <title>Biquad Automation Test</title>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="../resources/biquad-filters.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-bandpass.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-bandpass.html
index 5dafe2a..8eeb209e 100644
--- a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-bandpass.html
+++ b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-bandpass.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script src="../resources/biquad-filters.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-getFrequencyResponse.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-getFrequencyResponse.html
index bbc1847..432174f2 100644
--- a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-getFrequencyResponse.html
+++ b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-getFrequencyResponse.html
@@ -2,7 +2,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script src="../resources/biquad-filters.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-highpass.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-highpass.html
index b0822ea..2c1ad0eaa 100644
--- a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-highpass.html
+++ b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-highpass.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script src="../resources/biquad-filters.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-highshelf.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-highshelf.html
index 3f7b806..10002c7 100644
--- a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-highshelf.html
+++ b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-highshelf.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script src="../resources/biquad-filters.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-lowpass.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-lowpass.html
index 79f0824..2e17982 100644
--- a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-lowpass.html
+++ b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-lowpass.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script src="../resources/biquad-filters.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-lowshelf.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-lowshelf.html
index b2a110a..a72b005 100644
--- a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-lowshelf.html
+++ b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-lowshelf.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script src="../resources/biquad-filters.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-notch.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-notch.html
index 427f71c..21dfe0f 100644
--- a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-notch.html
+++ b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-notch.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script src="../resources/biquad-filters.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-peaking.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-peaking.html
index 5db5dc1..4abacdc 100644
--- a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-peaking.html
+++ b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-peaking.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script src="../resources/biquad-filters.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-tail.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-tail.html
index afa82f1..387958b8 100644
--- a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-tail.html
+++ b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-tail.html
@@ -3,7 +3,6 @@
   <head>
     <title>Test Biquad Tail Output</title>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
   </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquadfilternode-basic-expected.txt b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquadfilternode-basic-expected.txt
index 9a9d2ae6..2c3b3d5 100644
--- a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquadfilternode-basic-expected.txt
+++ b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquadfilternode-basic-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE WARNING: line 88: The provided value '99' is not a valid enum value of type BiquadFilterType.
+CONSOLE WARNING: line 87: The provided value '99' is not a valid enum value of type BiquadFilterType.
 Basic tests for BiquadFilterNode.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquadfilternode-basic.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquadfilternode-basic.html
index 4788e92..deb3685 100644
--- a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquadfilternode-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquadfilternode-basic.html
@@ -2,7 +2,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-basic.html b/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-basic.html
index 61c36fbc..2da39a3 100644
--- a/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-basic.html
@@ -3,7 +3,6 @@
 
 <head>
   <script src="../../resources/js-test.js"></script>
-  <script src="../resources/compatibility.js"></script>
   <script src="../resources/audit-util.js"></script>
   <script src="../resources/audio-testing.js"></script>
 </head>
@@ -77,4 +76,4 @@
   </script>
 </body>
 
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-cycle.html b/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-cycle.html
index d533645ac..913d7e6 100644
--- a/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-cycle.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-cycle.html
@@ -3,7 +3,6 @@
 
 <head>
   <script src="../../resources/js-test.js"></script>
-  <script src="../resources/compatibility.js"></script>
   <script src="../resources/audit-util.js"></script>
   <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-disconnect.html b/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-disconnect.html
index ec4da60..d6e9d600 100644
--- a/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-disconnect.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-disconnect.html
@@ -3,7 +3,6 @@
 
 <head>
   <script src="../../resources/js-test.js"></script>
-  <script src="../resources/compatibility.js"></script>
   <script src="../resources/audit-util.js"></script>
   <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-input-non-default.html b/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-input-non-default.html
index 4a7ced76..abc0959 100644
--- a/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-input-non-default.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-input-non-default.html
@@ -3,7 +3,6 @@
 
 <head>
   <script src="../../resources/js-test.js"></script>
-  <script src="../resources/compatibility.js"></script>
   <script src="../resources/audit-util.js"></script>
   <script src="../resources/audio-testing.js"></script>
   <script src="../resources/merger-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-input.html b/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-input.html
index 706d7e9..ceef300 100644
--- a/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-input.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-input.html
@@ -3,7 +3,6 @@
 
 <head>
   <script src="../../resources/js-test.js"></script>
-  <script src="../resources/compatibility.js"></script>
   <script src="../resources/audit-util.js"></script>
   <script src="../resources/audio-testing.js"></script>
   <script src="../resources/merger-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/ChannelSplitter/audiochannelsplitter.html b/third_party/WebKit/LayoutTests/webaudio/ChannelSplitter/audiochannelsplitter.html
index c97d1ca..f3cab43 100644
--- a/third_party/WebKit/LayoutTests/webaudio/ChannelSplitter/audiochannelsplitter.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ChannelSplitter/audiochannelsplitter.html
@@ -7,7 +7,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Convolver/convolution-mono-mono.html b/third_party/WebKit/LayoutTests/webaudio/Convolver/convolution-mono-mono.html
index bebfc00a..337769a 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Convolver/convolution-mono-mono.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Convolver/convolution-mono-mono.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script src="../resources/convolution-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Convolver/convolver-channels.html b/third_party/WebKit/LayoutTests/webaudio/Convolver/convolver-channels.html
index 5c0a7bb..0153a53f7 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Convolver/convolver-channels.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Convolver/convolver-channels.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <title>Test Supported Number of Channels for ConvolverNode</title>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Convolver/convolver-setBuffer-null.html b/third_party/WebKit/LayoutTests/webaudio/Convolver/convolver-setBuffer-null.html
index 45b47a0..b8f4db6 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Convolver/convolver-setBuffer-null.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Convolver/convolver-setBuffer-null.html
@@ -2,7 +2,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-default-delay.html b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-default-delay.html
index 9895f2d..c0589ee 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-default-delay.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-default-delay.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script src="../resources/delay-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-nondefault-delay.html b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-nondefault-delay.html
index d0c54ea..13f9b97 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-nondefault-delay.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-nondefault-delay.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script src="../resources/delay-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelay.html b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelay.html
index 5366aea..f9c17fb5 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelay.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelay.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script src="../resources/delay-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelaylimit.html b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelaylimit.html
index 58647b61..278bd43 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelaylimit.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelaylimit.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script src="../resources/delay-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-scheduling.html b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-scheduling.html
index 3b1500b..255d329 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-scheduling.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-scheduling.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script src="../resources/delay-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode.html b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode.html
index c527071..df29c186 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script src="../resources/delay-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-basic.html b/third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-basic.html
index 7c2b8ab..d8298d1 100644
--- a/third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-basic.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-clear-internal-state.html b/third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-clear-internal-state.html
index c3725835..b90034c 100644
--- a/third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-clear-internal-state.html
+++ b/third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-clear-internal-state.html
@@ -3,7 +3,6 @@
   <head>
     <title>Validate Reduction Value of DynamicsComporessor after Disabling</title>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
   </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-simple.html b/third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-simple.html
index c844dca..999f45b 100644
--- a/third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-simple.html
+++ b/third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-simple.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
   </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Gain/gain-basic.html b/third_party/WebKit/LayoutTests/webaudio/Gain/gain-basic.html
index 4f74f97..14b4275f 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Gain/gain-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Gain/gain-basic.html
@@ -7,7 +7,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter-basic.html b/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter-basic.html
index 9639b2a..7d725f44 100644
--- a/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter-basic.html
@@ -3,7 +3,6 @@
   <head>
     <title>Test Basic IIRFilterNode Properties</title>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
   </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter-getFrequencyResponse.html b/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter-getFrequencyResponse.html
index 27c292c..44a0644 100644
--- a/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter-getFrequencyResponse.html
+++ b/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter-getFrequencyResponse.html
@@ -3,7 +3,6 @@
   <head>
     <title>Test IIRFilter getFrequencyResponse() functionality</title>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="../resources/biquad-filters.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter.html b/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter.html
index b027f63..c6c9c91f 100644
--- a/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter.html
+++ b/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter.html
@@ -3,7 +3,6 @@
   <head>
     <title>Test Basic IIRFilterNode Operation</title>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="../resources/biquad-filters.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/MediaElementAudioSource/mediaelementaudiosourcenode-gc.html b/third_party/WebKit/LayoutTests/webaudio/MediaElementAudioSource/mediaelementaudiosourcenode-gc.html
index c5ab59f..d5da196 100644
--- a/third_party/WebKit/LayoutTests/webaudio/MediaElementAudioSource/mediaelementaudiosourcenode-gc.html
+++ b/third_party/WebKit/LayoutTests/webaudio/MediaElementAudioSource/mediaelementaudiosourcenode-gc.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/MediaElementAudioSource/mediaelementaudiosourcenode-wrapper.html b/third_party/WebKit/LayoutTests/webaudio/MediaElementAudioSource/mediaelementaudiosourcenode-wrapper.html
index 3fc50ac..359fbbb5 100644
--- a/third_party/WebKit/LayoutTests/webaudio/MediaElementAudioSource/mediaelementaudiosourcenode-wrapper.html
+++ b/third_party/WebKit/LayoutTests/webaudio/MediaElementAudioSource/mediaelementaudiosourcenode-wrapper.html
@@ -2,7 +2,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/MediaElementAudioSource/mediaelementaudiosourcenode.html b/third_party/WebKit/LayoutTests/webaudio/MediaElementAudioSource/mediaelementaudiosourcenode.html
index 8fa105f1..1628bc65 100644
--- a/third_party/WebKit/LayoutTests/webaudio/MediaElementAudioSource/mediaelementaudiosourcenode.html
+++ b/third_party/WebKit/LayoutTests/webaudio/MediaElementAudioSource/mediaelementaudiosourcenode.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/MediaStreamAudioDestination/mediastreamaudiodestinationnode.html b/third_party/WebKit/LayoutTests/webaudio/MediaStreamAudioDestination/mediastreamaudiodestinationnode.html
index 38e177a7..d3264ce 100644
--- a/third_party/WebKit/LayoutTests/webaudio/MediaStreamAudioDestination/mediastreamaudiodestinationnode.html
+++ b/third_party/WebKit/LayoutTests/webaudio/MediaStreamAudioDestination/mediastreamaudiodestinationnode.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/MediaStreamAudioSource/mediastreamaudiosourcenode.html b/third_party/WebKit/LayoutTests/webaudio/MediaStreamAudioSource/mediastreamaudiosourcenode.html
index 9686de3..588ba86 100644
--- a/third_party/WebKit/LayoutTests/webaudio/MediaStreamAudioSource/mediastreamaudiosourcenode.html
+++ b/third_party/WebKit/LayoutTests/webaudio/MediaStreamAudioSource/mediastreamaudiosourcenode.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-constructor.html b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-constructor.html
index df657ca..783a212b 100644
--- a/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-constructor.html
+++ b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-constructor.html
@@ -2,7 +2,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 </head>
 <body>
 <script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-detached-no-crash.html b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-detached-no-crash.html
index f893a72..e947919 100644
--- a/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-detached-no-crash.html
+++ b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-detached-no-crash.html
@@ -2,7 +2,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-promise-basic.html b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-promise-basic.html
index 23b987818..d3aa1625b 100644
--- a/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-promise-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-promise-basic.html
@@ -2,8 +2,7 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/audio-testing.js"/>
-    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audio-testing.js"></script>
     <title>OfflineAudioContext.startRendering Promise</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-promise.html b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-promise.html
index cfc5aea..704deb14 100644
--- a/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-promise.html
+++ b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-promise.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <title>OfflineAudioContext.startRendering Promise with oncomplete</title>
diff --git a/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-basic.html b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-basic.html
index 4acaf7a..eb1ab235 100644
--- a/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-basic.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
   </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-eventhandler.html b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-eventhandler.html
index 0ef81eba..03d191b6 100644
--- a/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-eventhandler.html
+++ b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-eventhandler.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
   </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-graph-manipulation.html b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-graph-manipulation.html
index ece7d86..f9d34f8 100644
--- a/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-graph-manipulation.html
+++ b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-graph-manipulation.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
   </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-promise.html b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-promise.html
index 8516b428..b02df2e 100644
--- a/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-promise.html
+++ b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-promise.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
   </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-sequence.html b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-sequence.html
index 6bcb3721..bfeaa19 100644
--- a/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-sequence.html
+++ b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-sequence.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
   </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/onstatechange.html b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/onstatechange.html
index 23c024c..4e20b77 100644
--- a/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/onstatechange.html
+++ b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/onstatechange.html
@@ -5,7 +5,6 @@
     <script src="../../resources/js-test.js"></script>
     <script src="../resources/audit-util.js"/></script>
     <script src="../resources/audio-testing.js"/></script>
-    <script src="../resources/compatibility.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-custom-sweep-snr.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-custom-sweep-snr.html
index d386a49e..076beee 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-custom-sweep-snr.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-custom-sweep-snr.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <title>Test Oscillator Node: custom</title>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/buffer-loader.js"></script>
     <script src="../../resources/js-test.js"></script>
     <script src="../resources/oscillator-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-low-freq.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-low-freq.html
index 84f0dc65..7a94372 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-low-freq.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-low-freq.html
@@ -3,7 +3,6 @@
   <head>
     <title>Test Custom Oscillator at Very Low Frequency</title>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
   </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-negative-freq.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-negative-freq.html
index 2b3aa76..90648a7 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-negative-freq.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-negative-freq.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <title>Test OscillatorNode with Negative Frequency</title>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sawtooth-sweep-snr.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sawtooth-sweep-snr.html
index 7965e82..5015fd7 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sawtooth-sweep-snr.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sawtooth-sweep-snr.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <title>Test Oscillator Node: sawtooth</title>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/buffer-loader.js"></script>
     <script src="../../resources/js-test.js"></script>
     <script src="../resources/oscillator-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sine-sweep-snr.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sine-sweep-snr.html
index 89977c8..26bda2a 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sine-sweep-snr.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sine-sweep-snr.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <title>Test Oscillator Node: sine</title>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/buffer-loader.js"></script>
     <script src="../../resources/js-test.js"></script>
     <script src="../resources/oscillator-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-square-sweep-snr.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-square-sweep-snr.html
index 46508531..baa4eca 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-square-sweep-snr.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-square-sweep-snr.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <title>Test Oscillator Node: square</title>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/buffer-loader.js"></script>
     <script src="../../resources/js-test.js"></script>
     <script src="../resources/oscillator-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-triangle-sweep-snr.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-triangle-sweep-snr.html
index e52d03b3..544e859 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-triangle-sweep-snr.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-triangle-sweep-snr.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <title>Test Oscillator Node: triangle</title>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/buffer-loader.js"></script>
     <script src="../../resources/js-test.js"></script>
     <script src="../resources/oscillator-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-basic-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-basic-expected.txt
index 1a6f232..5cda5b9 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-basic-expected.txt
+++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-basic-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE WARNING: line 65: The provided value '0' is not a valid enum value of type OscillatorType.
+CONSOLE WARNING: line 64: The provided value '0' is not a valid enum value of type OscillatorType.
 Basic test of setting Oscillator node types.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-basic.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-basic.html
index dee6c686..c98186e 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-basic.html
@@ -6,7 +6,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-ended.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-ended.html
index 5d6c17b0..ba51ccb 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-ended.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-ended.html
@@ -1,7 +1,6 @@
 <!DOCTYPE html>
 <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="../resources/audiobuffersource-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-late-start.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-late-start.html
index 7796f9b..959475fa 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-late-start.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-late-start.html
@@ -3,7 +3,6 @@
 
 <head>
   <script src="../../resources/js-test.js"></script>
-  <script src="../resources/compatibility.js"></script>
   <script src="../resources/audit-util.js"></script>
   <script src="../resources/audio-testing.js"></script>
   <script src="../resources/late-start-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Panner/distance-exponential.html b/third_party/WebKit/LayoutTests/webaudio/Panner/distance-exponential.html
index 38b5aa46..b1a07da2 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Panner/distance-exponential.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Panner/distance-exponential.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="../resources/distance-model-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Panner/distance-inverse.html b/third_party/WebKit/LayoutTests/webaudio/Panner/distance-inverse.html
index 56f75cd..49b7c3fe 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Panner/distance-inverse.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Panner/distance-inverse.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="../resources/distance-model-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Panner/distance-linear.html b/third_party/WebKit/LayoutTests/webaudio/Panner/distance-linear.html
index 26777c8..335bf11 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Panner/distance-linear.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Panner/distance-linear.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="../resources/distance-model-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Panner/panner-automation-basic.html b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-automation-basic.html
index 27ed4a59..0caa4ea 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Panner/panner-automation-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-automation-basic.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="../resources/panner-formulas.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Panner/panner-automation-equalpower-stereo.html b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-automation-equalpower-stereo.html
index f46c968..f885a05 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Panner/panner-automation-equalpower-stereo.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-automation-equalpower-stereo.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="../resources/panner-model-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Panner/panner-automation-position.html b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-automation-position.html
index bcd9098..f8b063b 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Panner/panner-automation-position.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-automation-position.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="../resources/panner-formulas.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Panner/panner-equalpower-stereo.html b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-equalpower-stereo.html
index a296efe3..033f3e7 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Panner/panner-equalpower-stereo.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-equalpower-stereo.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="../resources/panner-model-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Panner/panner-equalpower.html b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-equalpower.html
index f9616f8a..8ab2bbd 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Panner/panner-equalpower.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-equalpower.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="../resources/panner-model-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Panner/panner-loop.html b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-loop.html
index 552c22a2..83fe6e5 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Panner/panner-loop.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-loop.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="../resources/panner-model-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Panner/pannernode-basic-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Panner/pannernode-basic-expected.txt
index 5aa7856..34e622bb 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Panner/pannernode-basic-expected.txt
+++ b/third_party/WebKit/LayoutTests/webaudio/Panner/pannernode-basic-expected.txt
@@ -1,6 +1,6 @@
-CONSOLE WARNING: line 133: The provided value 'invalid' is not a valid enum value of type PanningModelType.
-CONSOLE WARNING: line 143: The provided value '1' is not a valid enum value of type PanningModelType.
-CONSOLE WARNING: line 173: The provided value 'invalid' is not a valid enum value of type DistanceModelType.
+CONSOLE WARNING: line 132: The provided value 'invalid' is not a valid enum value of type PanningModelType.
+CONSOLE WARNING: line 142: The provided value '1' is not a valid enum value of type PanningModelType.
+CONSOLE WARNING: line 172: The provided value 'invalid' is not a valid enum value of type DistanceModelType.
 Basic tests for PannerNode.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/webaudio/Panner/pannernode-basic.html b/third_party/WebKit/LayoutTests/webaudio/Panner/pannernode-basic.html
index ffa2415..cfc4179 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Panner/pannernode-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Panner/pannernode-basic.html
@@ -3,7 +3,6 @@
 
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
   </head>
@@ -194,4 +193,4 @@
 
   </body>
 
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-contexts.html b/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-contexts.html
index ff8d492..5ae37760 100644
--- a/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-contexts.html
+++ b/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-contexts.html
@@ -3,7 +3,6 @@
   <head>
     <title>Test Oscillator Node: sawtooth</title>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/buffer-loader.js"></script>
     <script src="../resources/oscillator-testing.js"></script>
   </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-lengths.html b/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-lengths.html
index 2bc1783..443504b 100644
--- a/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-lengths.html
+++ b/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-lengths.html
@@ -3,7 +3,6 @@
   <head>
     <title>Test Different PeriodicWave Lengths at Different Sample Rates</title>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
   </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-normalization.html b/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-normalization.html
index 4474b67..0db672d 100644
--- a/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-normalization.html
+++ b/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-normalization.html
@@ -3,7 +3,6 @@
   <head>
     <title>Test PeriodicWave Normalization</title>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
   </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-0-output-channels.html b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-0-output-channels.html
index c188163..c233b09 100644
--- a/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-0-output-channels.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-0-output-channels.html
@@ -3,7 +3,6 @@
   <head>
     <title>Test Connecting 0-output channel ScriptProcessor to Another Node </title>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
   </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-detached-no-crash.html b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-detached-no-crash.html
index 1fb6bc9..2f8df79 100644
--- a/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-detached-no-crash.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-detached-no-crash.html
@@ -2,7 +2,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-downmix8-2channel-input.html b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-downmix8-2channel-input.html
index 0d6f5c69..cdf1127 100644
--- a/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-downmix8-2channel-input.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-downmix8-2channel-input.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script type="text/javascript" src="../resources/scriptprocessornode-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-premature-death.html b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-premature-death.html
index a8c00e6..4ddfd3f 100644
--- a/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-premature-death.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-premature-death.html
@@ -1,6 +1,5 @@
 <!DOCTYPE html>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <body>
 <script>
 description('Tests that a script processor node is not prematurely GCed');
diff --git a/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-rewrap.html b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-rewrap.html
index 931c6338..399037d5 100644
--- a/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-rewrap.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-rewrap.html
@@ -2,7 +2,6 @@
 <html>
 <body>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script>
 var jsTestIsAsync = true;
 description("Tests re-wrapping an AudioNode sublass after its JS wrapper is deleted wraps the node as the correct subclass. A binding integrity assert will fire otherwise.");
diff --git a/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-upmix2-8channel-input.html b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-upmix2-8channel-input.html
index c6c45f1..e390c67a 100644
--- a/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-upmix2-8channel-input.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-upmix2-8channel-input.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script type="text/javascript" src="../resources/scriptprocessornode-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-zero-input-channels.html b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-zero-input-channels.html
index 59efd789..4a05ed93 100644
--- a/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-zero-input-channels.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-zero-input-channels.html
@@ -2,7 +2,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode.html b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode.html
index d837625..5bc37cea 100644
--- a/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode.html
@@ -2,7 +2,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-basic.html b/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-basic.html
index 8b33293..2457555 100644
--- a/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-basic.html
@@ -3,7 +3,6 @@
 
 <head>
   <script src="../../resources/js-test.js"></script>
-  <script src="../resources/compatibility.js"></script>
   <script src="../resources/audit-util.js"></script>
   <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-no-glitch.html b/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-no-glitch.html
index ae9b4cd3..65947be0 100644
--- a/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-no-glitch.html
+++ b/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-no-glitch.html
@@ -3,7 +3,6 @@
 
 <head>
   <script src="../../resources/js-test.js"></script>
-  <script src="../resources/compatibility.js"></script>
   <script src="../resources/audit-util.js"></script>
   <script src="../resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-panning.html b/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-panning.html
index b833d01..a2711440 100644
--- a/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-panning.html
+++ b/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-panning.html
@@ -3,7 +3,6 @@
 
 <head>
   <script src="../../resources/js-test.js"></script>
-  <script src="../resources/compatibility.js"></script>
   <script src="../resources/audit-util.js"></script>
   <script src="../resources/audio-testing.js"></script>
   <script src="../resources/stereopanner-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-364379.html b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-364379.html
index bdbdce81..7e7dad6 100644
--- a/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-364379.html
+++ b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-364379.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-limits.html b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-limits.html
index 320ed50..eb9d4ff3 100644
--- a/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-limits.html
+++ b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-limits.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     <script src="../../resources/js-test.js"></script>
-    <script src="../resources/compatibility.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-2x.html b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-2x.html
index 1564fe0..b023d1f 100644
--- a/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-2x.html
+++ b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-2x.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script type="text/javascript" src="../resources/mix-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-4x.html b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-4x.html
index 7273878..ac9b299 100644
--- a/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-4x.html
+++ b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-4x.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script type="text/javascript" src="../resources/mix-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper.html b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper.html
index 45a575f..1330a23 100644
--- a/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper.html
+++ b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../../resources/js-test.js"></script>
-<script src="../resources/compatibility.js"></script>
 <script src="../resources/audit-util.js"></script>
 <script src="../resources/audio-testing.js"></script>
 <script type="text/javascript" src="../resources/buffer-loader.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/constructor/waveshaper.html b/third_party/WebKit/LayoutTests/webaudio/constructor/waveshaper.html
index 0975f7d..8332741 100644
--- a/third_party/WebKit/LayoutTests/webaudio/constructor/waveshaper.html
+++ b/third_party/WebKit/LayoutTests/webaudio/constructor/waveshaper.html
@@ -4,7 +4,6 @@
     <title>Test Constructor: WaveShaper</title>
     <script src="../../resources/testharness.js"></script>
     <script src="../../resources/testharnessreport.js"></script>
-    <script src="../resources/compatibility.js"></script>
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audio-testing.js"></script>
     <script src="audionodeoptions.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/decodeAudioData/decode-audio-data-basic.html b/third_party/WebKit/LayoutTests/webaudio/decodeAudioData/decode-audio-data-basic.html
index 83c7a5e..6ea7b42 100644
--- a/third_party/WebKit/LayoutTests/webaudio/decodeAudioData/decode-audio-data-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/decodeAudioData/decode-audio-data-basic.html
@@ -2,7 +2,6 @@
 <html>
 <head>
   <script src="../../resources/js-test.js"></script>
-  <script src="../resources/compatibility.js"></script>
   <script src="../resources/audit-util.js"></script>
   <script src="../resources/audio-testing.js"></script>
   <title>Test decodeAudioData promises</title>
diff --git a/third_party/WebKit/LayoutTests/webaudio/dom-exceptions.html b/third_party/WebKit/LayoutTests/webaudio/dom-exceptions.html
index 6fcfb39..b1c8667 100644
--- a/third_party/WebKit/LayoutTests/webaudio/dom-exceptions.html
+++ b/third_party/WebKit/LayoutTests/webaudio/dom-exceptions.html
@@ -2,7 +2,6 @@
 <html>
 <head>
 <script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
 <script src="resources/audit-util.js"></script>
 <script src="resources/audio-testing.js"></script>
 <script src="resources/biquad-testing.js"></script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/resources/compatibility.js b/third_party/WebKit/LayoutTests/webaudio/resources/compatibility.js
deleted file mode 100644
index 7b400a1..0000000
--- a/third_party/WebKit/LayoutTests/webaudio/resources/compatibility.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// We want to be able to run these tests with chrome that only supports the prefixed
-// AudioContext. This is useful in case a regression has occurred.
-
-if (window.hasOwnProperty('webkitAudioContext') &&
-    !window.hasOwnProperty('AudioContext')) {
-    window.AudioContext = webkitAudioContext;
-    window.OfflineAudioContext = webkitOfflineAudioContext;
-    console.log("Using deprecated prefixed AudioContext or OfflineAudioContext");
-}
diff --git a/third_party/WebKit/LayoutTests/webaudio/stereo2mono-down-mixing.html b/third_party/WebKit/LayoutTests/webaudio/stereo2mono-down-mixing.html
index 149ca66..b4a1b3b4 100644
--- a/third_party/WebKit/LayoutTests/webaudio/stereo2mono-down-mixing.html
+++ b/third_party/WebKit/LayoutTests/webaudio/stereo2mono-down-mixing.html
@@ -3,7 +3,6 @@
 <html>
 <head>
 <script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
 <script src="resources/audit-util.js"></script>
 <script src="resources/audio-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index fb8634b..2ee1e54 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -1127,6 +1127,7 @@
     getter y
     getter z
     method constructor
+    method matrixTransform
     method toJSON
 interface DOMRect : DOMRectReadOnly
     attribute @@toStringTag
diff --git a/third_party/WebKit/Source/core/dom/DOMPointReadOnly.cpp b/third_party/WebKit/Source/core/dom/DOMPointReadOnly.cpp
index 6857417..538249e9 100644
--- a/third_party/WebKit/Source/core/dom/DOMPointReadOnly.cpp
+++ b/third_party/WebKit/Source/core/dom/DOMPointReadOnly.cpp
@@ -4,8 +4,12 @@
 
 #include "core/dom/DOMPointReadOnly.h"
 
+#include "bindings/core/v8/ExceptionState.h"
 #include "bindings/core/v8/ScriptValue.h"
 #include "bindings/core/v8/V8ObjectBuilder.h"
+#include "core/dom/DOMMatrixInit.h"
+#include "core/dom/DOMMatrixReadOnly.h"
+#include "core/dom/DOMPoint.h"
 #include "core/dom/DOMPointInit.h"
 
 namespace blink {
@@ -31,6 +35,31 @@
   return new DOMPointReadOnly(other.x(), other.y(), other.z(), other.w());
 }
 
+DOMPoint* DOMPointReadOnly::matrixTransform(DOMMatrixInit& other,
+                                            ExceptionState& exceptionState) {
+  DOMMatrixReadOnly* matrix =
+      DOMMatrixReadOnly::fromMatrix(other, exceptionState);
+
+  if (matrix->is2D() && z() == 0 && w() == 1) {
+    double transformedX =
+        x() * matrix->m11() + y() * matrix->m12() + matrix->m41();
+    double transformedY =
+        x() * matrix->m12() + y() * matrix->m22() + matrix->m42();
+    return DOMPoint::create(transformedX, transformedY, 0, 1);
+  }
+
+  double transformedX = x() * matrix->m11() + y() * matrix->m21() +
+                        z() * matrix->m31() + w() * matrix->m41();
+  double transformedY = x() * matrix->m12() + y() * matrix->m22() +
+                        z() * matrix->m32() + w() * matrix->m42();
+  double transformedZ = x() * matrix->m13() + y() * matrix->m23() +
+                        z() * matrix->m33() + w() * matrix->m43();
+  double transformedW = x() * matrix->m14() + y() * matrix->m24() +
+                        z() * matrix->m34() + w() * matrix->m44();
+  return DOMPoint::create(transformedX, transformedY, transformedZ,
+                          transformedW);
+}
+
 DOMPointReadOnly::DOMPointReadOnly(double x, double y, double z, double w)
     : m_x(x), m_y(y), m_z(z), m_w(w) {}
 
diff --git a/third_party/WebKit/Source/core/dom/DOMPointReadOnly.h b/third_party/WebKit/Source/core/dom/DOMPointReadOnly.h
index d5ebc36..61d6176 100644
--- a/third_party/WebKit/Source/core/dom/DOMPointReadOnly.h
+++ b/third_party/WebKit/Source/core/dom/DOMPointReadOnly.h
@@ -11,9 +11,12 @@
 
 namespace blink {
 
-class ScriptValue;
-class ScriptState;
+class DOMMatrixInit;
+class DOMPoint;
 class DOMPointInit;
+class ExceptionState;
+class ScriptState;
+class ScriptValue;
 
 class CORE_EXPORT DOMPointReadOnly : public GarbageCollected<DOMPointReadOnly>,
                                      public ScriptWrappable {
@@ -31,7 +34,8 @@
   DEFINE_INLINE_TRACE() {}
   
   ScriptValue toJSONForBinding(ScriptState*) const;
- 
+  DOMPoint* matrixTransform(DOMMatrixInit&, ExceptionState&);
+
  protected:
   DOMPointReadOnly(double x, double y, double z, double w);
 
diff --git a/third_party/WebKit/Source/core/dom/DOMPointReadOnly.idl b/third_party/WebKit/Source/core/dom/DOMPointReadOnly.idl
index 15a44d4..7c381bd 100644
--- a/third_party/WebKit/Source/core/dom/DOMPointReadOnly.idl
+++ b/third_party/WebKit/Source/core/dom/DOMPointReadOnly.idl
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://dev.w3.org/fxtf/geometry/#DOMPoint
+// https://drafts.fxtf.org/geometry/#dompointreadonly
 
 [
-    Constructor(unrestricted double x, unrestricted double y,
-                unrestricted double z, unrestricted double w),
+    Constructor(optional unrestricted double x = 0, optional unrestricted double y = 0,
+                optional unrestricted double z = 0, optional unrestricted double w = 1),
     // FIXME: Exposed=(Window,Worker)
     RuntimeEnabled=GeometryInterfaces,
 ] interface DOMPointReadOnly {
@@ -17,7 +17,7 @@
     readonly attribute unrestricted double z;
     readonly attribute unrestricted double w;
 
-    // FIXME: Implement matrixTransform.
-    // DOMPoint matrixTransform(DOMMatrixReadOnly matrix);
+    [RaisesException] DOMPoint matrixTransform(optional DOMMatrixInit matrix);
+
     serializer = { attribute };
 };
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.h b/third_party/WebKit/Source/core/frame/UseCounter.h
index 18a85df3..272bd29c 100644
--- a/third_party/WebKit/Source/core/frame/UseCounter.h
+++ b/third_party/WebKit/Source/core/frame/UseCounter.h
@@ -616,10 +616,6 @@
     ClientHintsResourceWidth = 836,
     ClientHintsViewportWidth = 837,
     SRIElementIntegrityAttributeButIneligible = 838,
-    FormDataAppendFile = 839,
-    FormDataAppendFileWithFilename = 840,
-    FormDataAppendBlob = 841,
-    FormDataAppendBlobWithFilename = 842,
     FormDataAppendNull = 843,
     NonHTMLElementSetAttributeNodeFromHTMLDocumentNameNotLowercase = 845,
     DOMStringList_Item_AttributeGetter_IndexedDB = 846,
diff --git a/third_party/WebKit/Source/core/html/FormData.cpp b/third_party/WebKit/Source/core/html/FormData.cpp
index 2051fed9..d20d2984 100644
--- a/third_party/WebKit/Source/core/html/FormData.cpp
+++ b/third_party/WebKit/Source/core/html/FormData.cpp
@@ -104,21 +104,8 @@
                       const String& name,
                       Blob* blob,
                       const String& filename) {
-  if (blob) {
-    if (blob->isFile()) {
-      if (filename.isNull())
-        UseCounter::count(context, UseCounter::FormDataAppendFile);
-      else
-        UseCounter::count(context, UseCounter::FormDataAppendFileWithFilename);
-    } else {
-      if (filename.isNull())
-        UseCounter::count(context, UseCounter::FormDataAppendBlob);
-      else
-        UseCounter::count(context, UseCounter::FormDataAppendBlobWithFilename);
-    }
-  } else {
+  if (!blob)
     UseCounter::count(context, UseCounter::FormDataAppendNull);
-  }
   append(name, blob, filename);
 }
 
diff --git a/third_party/WebKit/Source/core/html/FormData.idl b/third_party/WebKit/Source/core/html/FormData.idl
index 9dd68b7c..46c26fea 100644
--- a/third_party/WebKit/Source/core/html/FormData.idl
+++ b/third_party/WebKit/Source/core/html/FormData.idl
@@ -30,26 +30,23 @@
 
 // https://xhr.spec.whatwg.org/#interface-formdata
 
-// TODO(foolip): The FormDataEntryValue typedef should use Blob, not File.
 typedef (File or USVString) FormDataEntryValue;
 
+// TODO(foolip): Remove LegacyInterfaceTypeChecking, which allows for
+// `append('name', null, 'filename')` and `set('name', null, 'filename')` to
+// append/set null values instead of throwing. https://crbug.com/561338
 [
     Constructor(optional HTMLFormElement form),
     Exposed=(Window,Worker),
     LegacyInterfaceTypeChecking,
 ] interface FormData {
-    // TODO(foolip): The value argument should be FormDataEntryValue and there
-    // should be no optional filename argument. crbug.com/498790
-    [CallWith=ExecutionContext] void append(USVString name, Blob value, optional USVString filename);
     void append(USVString name, USVString value);
-
+    [CallWith=ExecutionContext] void append(USVString name, Blob value, optional USVString filename);
     [ImplementedAs=deleteEntry] void delete(USVString name);
     FormDataEntryValue? get(USVString name);
     sequence<FormDataEntryValue> getAll(USVString name);
     boolean has(USVString name);
-    // TODO(foolip): The value argument should be FormDataEntryValue and there
-    // should be no optional filename argument.
-    void set(USVString name, Blob value, optional USVString filename);
     void set(USVString name, USVString value);
+    void set(USVString name, Blob value, optional USVString filename);
     iterable<USVString, FormDataEntryValue>;
 };
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLSrcsetParser.cpp b/third_party/WebKit/Source/core/html/parser/HTMLSrcsetParser.cpp
index 900b93d..298834ac 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLSrcsetParser.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLSrcsetParser.cpp
@@ -395,7 +395,8 @@
     KURL url = document->completeURL(
         stripLeadingAndTrailingHTMLSpaces(imageCandidates[i]->url()));
     if (memoryCache()->resourceForURL(
-            url, document->fetcher()->getCacheIdentifier()))
+            url, document->fetcher()->getCacheIdentifier()) ||
+        url.protocolIsData())
       return i;
   }
   return winner;
diff --git a/third_party/WebKit/Source/core/loader/ImageLoader.cpp b/third_party/WebKit/Source/core/loader/ImageLoader.cpp
index dc36dc0..faf0df8 100644
--- a/third_party/WebKit/Source/core/loader/ImageLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/ImageLoader.cpp
@@ -466,8 +466,7 @@
     if (resource && !resource->errorOccurred())
       return true;
   }
-  return (isHTMLObjectElement(m_element) || isHTMLEmbedElement(m_element) ||
-          url.protocolIsData());
+  return (isHTMLObjectElement(m_element) || isHTMLEmbedElement(m_element));
 }
 
 void ImageLoader::imageNotifyFinished(ImageResourceContent* resource) {
diff --git a/third_party/WebKit/Source/devtools/front_end/components/RemoteObjectPreviewFormatter.js b/third_party/WebKit/Source/devtools/front_end/components/RemoteObjectPreviewFormatter.js
index 82d1adc..30cb1a7 100644
--- a/third_party/WebKit/Source/devtools/front_end/components/RemoteObjectPreviewFormatter.js
+++ b/third_party/WebKit/Source/devtools/front_end/components/RemoteObjectPreviewFormatter.js
@@ -6,6 +6,19 @@
  */
 Components.RemoteObjectPreviewFormatter = class {
   /**
+   * @param {!Protocol.Runtime.PropertyPreview} a
+   * @param {!Protocol.Runtime.PropertyPreview} b
+   * @return {number}
+   */
+  static _objectPropertyComparator(a, b) {
+    if (a.type !== 'function' && b.type === 'function')
+      return -1;
+    if (a.type === 'function' && b.type !== 'function')
+      return 1;
+    return 0;
+  }
+
+  /**
    * @param {!Element} parentElement
    * @param {!Protocol.Runtime.ObjectPreview} preview
    */
@@ -47,20 +60,8 @@
    * @param {!Protocol.Runtime.ObjectPreview} preview
    */
   _appendObjectPropertiesPreview(parentElement, preview) {
-    var properties = preview.properties.filter(p => p.type !== 'accessor').stableSort(compareFunctionsLast);
-
-    /**
-     * @param {!Protocol.Runtime.PropertyPreview} a
-     * @param {!Protocol.Runtime.PropertyPreview} b
-     */
-    function compareFunctionsLast(a, b) {
-      if (a.type !== 'function' && b.type === 'function')
-        return -1;
-      if (a.type === 'function' && b.type !== 'function')
-        return 1;
-      return 0;
-    }
-
+    var properties = preview.properties.filter(p => p.type !== 'accessor')
+                         .stableSort(Components.RemoteObjectPreviewFormatter._objectPropertyComparator);
     for (var i = 0; i < properties.length; ++i) {
       if (i > 0)
         parentElement.createTextChild(', ');
@@ -78,19 +79,17 @@
    */
   _appendArrayPropertiesPreview(parentElement, preview) {
     var arrayLength = SDK.RemoteObject.arrayLength(preview);
-    var properties = preview.properties;
-    properties = properties.slice().stableSort(compareIndexesFirst);
+    var indexProperties = preview.properties.filter(p => toArrayIndex(p.name) !== -1).stableSort(arrayEntryComparator);
+    var otherProperties = preview.properties.filter(p => toArrayIndex(p.name) === -1)
+                              .stableSort(Components.RemoteObjectPreviewFormatter._objectPropertyComparator);
 
     /**
      * @param {!Protocol.Runtime.PropertyPreview} a
      * @param {!Protocol.Runtime.PropertyPreview} b
+     * @return {number}
      */
-    function compareIndexesFirst(a, b) {
-      var index1 = toArrayIndex(a.name);
-      var index2 = toArrayIndex(b.name);
-      if (index1 < 0)
-        return index2 < 0 ? 0 : 1;
-      return index2 < 0 ? -1 : index1 - index2;
+    function arrayEntryComparator(a, b) {
+      return toArrayIndex(a.name) - toArrayIndex(b.name);
     }
 
     /**
@@ -104,16 +103,53 @@
       return -1;
     }
 
-    for (var i = 0; i < properties.length; ++i) {
-      if (i > 0)
+    // Gaps can be shown when all properties are guaranteed to be in the preview.
+    var canShowGaps = !preview.overflow;
+    var lastNonEmptyArrayIndex = -1;
+    var elementsAdded = false;
+    for (var i = 0; i < indexProperties.length; ++i) {
+      if (elementsAdded)
         parentElement.createTextChild(', ');
 
-      var property = properties[i];
-      if (property.name !== String(i) || i >= arrayLength) {
+      var property = indexProperties[i];
+      var index = toArrayIndex(property.name);
+      if (canShowGaps && index - lastNonEmptyArrayIndex > 1) {
+        appendUndefined(index);
+        parentElement.createTextChild(', ');
+      }
+      if (!canShowGaps && i !== index) {
         parentElement.appendChild(this._renderDisplayName(property.name));
         parentElement.createTextChild(': ');
       }
       parentElement.appendChild(this._renderPropertyPreviewOrAccessor([property]));
+      lastNonEmptyArrayIndex = index;
+      elementsAdded = true;
+    }
+
+    if (canShowGaps && arrayLength - lastNonEmptyArrayIndex > 1) {
+      if (elementsAdded)
+        parentElement.createTextChild(', ');
+      appendUndefined(arrayLength);
+    }
+
+    for (var i = 0; i < otherProperties.length; ++i) {
+      if (elementsAdded)
+        parentElement.createTextChild(', ');
+
+      var property = otherProperties[i];
+      parentElement.appendChild(this._renderDisplayName(property.name));
+      parentElement.createTextChild(': ');
+      parentElement.appendChild(this._renderPropertyPreviewOrAccessor([property]));
+      elementsAdded = true;
+    }
+
+    /**
+     * @param {number} index
+     */
+    function appendUndefined(index) {
+      var span = parentElement.createChild('span', 'object-value-undefined');
+      span.textContent = Common.UIString('undefined × %d', index - lastNonEmptyArrayIndex - 1);
+      elementsAdded = true;
     }
   }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js b/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js
index 884af2c..44007078 100644
--- a/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js
+++ b/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js
@@ -463,7 +463,7 @@
     switch (type) {
       case 'array':
       case 'typedarray':
-        element = this._formatParameterAsArray(output);
+        element = this._formatParameterAsObject(output, includePreview);
         break;
       case 'error':
         element = this._formatParameterAsError(output);
@@ -618,82 +618,6 @@
   }
 
   /**
-   * @param {!SDK.RemoteObject} array
-   * @return {!Element}
-   */
-  _formatParameterAsArray(array) {
-    var usePrintedArrayFormat = this._message.type !== SDK.ConsoleMessage.MessageType.DirXML &&
-        this._message.type !== SDK.ConsoleMessage.MessageType.Result;
-    var isLongArray = array.arrayLength() > 100;
-    if (usePrintedArrayFormat || isLongArray)
-      return this._formatParameterAsObject(array, usePrintedArrayFormat || !isLongArray);
-    var result = createElement('span');
-    array.getAllProperties(false, printArrayResult.bind(this));
-    return result;
-
-    /**
-     * @param {?Array.<!SDK.RemoteObjectProperty>} properties
-     * @this {!Console.ConsoleViewMessage}
-     */
-    function printArrayResult(properties) {
-      if (!properties) {
-        result.appendChild(this._formatParameterAsObject(array, false));
-        return;
-      }
-
-      var titleElement = createElementWithClass('span', 'console-object-preview');
-      if (array.subtype === 'typedarray')
-        titleElement.createTextChild(array.description + ' ');
-      var elements = {};
-      for (var i = 0; i < properties.length; ++i) {
-        var property = properties[i];
-        var name = property.name;
-        if (isNaN(name))
-          continue;
-        if (property.getter)
-          elements[name] = this._formatAsAccessorProperty(array, [name], true);
-        else if (property.value)
-          elements[name] = this._formatAsArrayEntry(property.value);
-      }
-
-      titleElement.createTextChild('[');
-      var lastNonEmptyIndex = -1;
-
-      function appendUndefined(titleElement, index) {
-        if (index - lastNonEmptyIndex <= 1)
-          return;
-        var span = titleElement.createChild('span', 'object-value-undefined');
-        span.textContent = Common.UIString('undefined × %d', index - lastNonEmptyIndex - 1);
-      }
-
-      var length = array.arrayLength();
-      for (var i = 0; i < length; ++i) {
-        var element = elements[i];
-        if (!element)
-          continue;
-
-        if (i - lastNonEmptyIndex > 1) {
-          appendUndefined(titleElement, i);
-          titleElement.createTextChild(', ');
-        }
-
-        titleElement.appendChild(element);
-        lastNonEmptyIndex = i;
-        if (i < length - 1)
-          titleElement.createTextChild(', ');
-      }
-      appendUndefined(titleElement, length);
-
-      titleElement.createTextChild(']');
-
-      var section = new Components.ObjectPropertiesSection(array, titleElement, this._linkifier);
-      section.element.classList.add('console-view-object-properties-section');
-      section.enableContextMenu();
-      result.appendChild(section.element);
-    }
-  }
-
-  /**
    * @param {!SDK.RemoteObject} output
    * @return {!Element}
    */
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeView.js b/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeView.js
index e79a21f..ce6aef2 100644
--- a/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeView.js
+++ b/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeView.js
@@ -453,18 +453,20 @@
       function paintScreenshot() {
         var pageImage = new Image();
         pageImage.src = 'data:image/png;base64,' + content;
-        ctx.drawImage(
-            pageImage, visiblePageRect.left, visiblePageRect.top, Math.min(pageImage.naturalWidth, screenRect.width),
-            Math.min(pageImage.naturalHeight, screenRect.height));
-        var url = mainTarget && mainTarget.inspectedURL();
-        var fileName = url ? url.trimURL().removeURLFragment() : '';
-        if (this._model.type() === Emulation.DeviceModeModel.Type.Device)
-          fileName += Common.UIString('(%s)', this._model.device().title);
-        // Trigger download.
-        var link = createElement('a');
-        link.download = fileName + '.png';
-        link.href = canvas.toDataURL('image/png');
-        link.click();
+        pageImage.onload = () => {
+          ctx.drawImage(
+              pageImage, visiblePageRect.left, visiblePageRect.top, Math.min(pageImage.naturalWidth, screenRect.width),
+              Math.min(pageImage.naturalHeight, screenRect.height));
+          var url = mainTarget && mainTarget.inspectedURL();
+          var fileName = url ? url.trimURL().removeURLFragment() : '';
+          if (this._model.type() === Emulation.DeviceModeModel.Type.Device)
+            fileName += Common.UIString('(%s)', this._model.device().title);
+          // Trigger download.
+          var link = createElement('a');
+          link.download = fileName + '.png';
+          link.href = canvas.toDataURL('image/png');
+          link.click();
+        };
       }
     }
   }
diff --git a/third_party/WebKit/Source/devtools/front_end/screencast/ScreencastView.js b/third_party/WebKit/Source/devtools/front_end/screencast/ScreencastView.js
index f270442..4dc8a7aff 100644
--- a/third_party/WebKit/Source/devtools/front_end/screencast/ScreencastView.js
+++ b/third_party/WebKit/Source/devtools/front_end/screencast/ScreencastView.js
@@ -148,27 +148,29 @@
   _screencastFrame(event) {
     var metadata = /** type {Protocol.Page.ScreencastFrameMetadata} */ (event.data.metadata);
     var base64Data = /** type {string} */ (event.data.data);
+    this._imageElement.onload = () => {
+      this._pageScaleFactor = metadata.pageScaleFactor;
+      this._screenOffsetTop = metadata.offsetTop;
+      this._scrollOffsetX = metadata.scrollOffsetX;
+      this._scrollOffsetY = metadata.scrollOffsetY;
+
+      var deviceSizeRatio = metadata.deviceHeight / metadata.deviceWidth;
+      var dimensionsCSS = this._viewportDimensions();
+
+      this._imageZoom = Math.min(
+          dimensionsCSS.width / this._imageElement.naturalWidth,
+          dimensionsCSS.height / (this._imageElement.naturalWidth * deviceSizeRatio));
+      this._viewportElement.classList.remove('hidden');
+      var bordersSize = Screencast.ScreencastView._bordersSize;
+      if (this._imageZoom < 1.01 / window.devicePixelRatio)
+        this._imageZoom = 1 / window.devicePixelRatio;
+      this._screenZoom = this._imageElement.naturalWidth * this._imageZoom / metadata.deviceWidth;
+      this._viewportElement.style.width = metadata.deviceWidth * this._screenZoom + bordersSize + 'px';
+      this._viewportElement.style.height = metadata.deviceHeight * this._screenZoom + bordersSize + 'px';
+
+      this.highlightDOMNode(this._highlightNode, this._highlightConfig);
+    };
     this._imageElement.src = 'data:image/jpg;base64,' + base64Data;
-    this._pageScaleFactor = metadata.pageScaleFactor;
-    this._screenOffsetTop = metadata.offsetTop;
-    this._scrollOffsetX = metadata.scrollOffsetX;
-    this._scrollOffsetY = metadata.scrollOffsetY;
-
-    var deviceSizeRatio = metadata.deviceHeight / metadata.deviceWidth;
-    var dimensionsCSS = this._viewportDimensions();
-
-    this._imageZoom = Math.min(
-        dimensionsCSS.width / this._imageElement.naturalWidth,
-        dimensionsCSS.height / (this._imageElement.naturalWidth * deviceSizeRatio));
-    this._viewportElement.classList.remove('hidden');
-    var bordersSize = Screencast.ScreencastView._bordersSize;
-    if (this._imageZoom < 1.01 / window.devicePixelRatio)
-      this._imageZoom = 1 / window.devicePixelRatio;
-    this._screenZoom = this._imageElement.naturalWidth * this._imageZoom / metadata.deviceWidth;
-    this._viewportElement.style.width = metadata.deviceWidth * this._screenZoom + bordersSize + 'px';
-    this._viewportElement.style.height = metadata.deviceHeight * this._screenZoom + bordersSize + 'px';
-
-    this.highlightDOMNode(this._highlightNode, this._highlightConfig);
   }
 
   _isGlassPaneActive() {
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineEventOverview.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineEventOverview.js
index 5408a32c..767c996 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineEventOverview.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineEventOverview.js
@@ -465,13 +465,12 @@
       var promise = new Promise(f => fulfill = f);
 
       var image = /** @type {!HTMLImageElement} */ (createElement('img'));
-      if (data)
+      if (data) {
         image.src = 'data:image/jpg;base64,' + data;
-      if (image.complete) {
-        fulfill(image);
-      } else {
         image.addEventListener('load', () => fulfill(image));
         image.addEventListener('error', () => fulfill(image));
+      } else {
+        fulfill(image);
       }
       return promise;
     }
diff --git a/third_party/WebKit/Source/modules/bluetooth/BUILD.gn b/third_party/WebKit/Source/modules/bluetooth/BUILD.gn
index 786cea77..36d5882 100644
--- a/third_party/WebKit/Source/modules/bluetooth/BUILD.gn
+++ b/third_party/WebKit/Source/modules/bluetooth/BUILD.gn
@@ -22,11 +22,13 @@
     "BluetoothRemoteGATTServer.h",
     "BluetoothRemoteGATTService.cpp",
     "BluetoothRemoteGATTService.h",
-    "BluetoothSupplement.cpp",
-    "BluetoothSupplement.h",
     "BluetoothUUID.cpp",
     "BluetoothUUID.h",
     "NavigatorBluetooth.cpp",
     "NavigatorBluetooth.h",
   ]
+
+  deps = [
+    "//device/bluetooth/public/interfaces:interfaces_blink",
+  ]
 }
diff --git a/third_party/WebKit/Source/modules/bluetooth/Bluetooth.cpp b/third_party/WebKit/Source/modules/bluetooth/Bluetooth.cpp
index 35c4e92a..b28791a 100644
--- a/third_party/WebKit/Source/modules/bluetooth/Bluetooth.cpp
+++ b/third_party/WebKit/Source/modules/bluetooth/Bluetooth.cpp
@@ -8,15 +8,17 @@
 #include "bindings/core/v8/ScriptPromise.h"
 #include "bindings/core/v8/ScriptPromiseResolver.h"
 #include "core/dom/DOMException.h"
+#include "core/dom/Document.h"
 #include "core/dom/ExceptionCode.h"
+#include "core/dom/ExecutionContext.h"
+#include "core/frame/LocalFrame.h"
 #include "modules/bluetooth/BluetoothDevice.h"
 #include "modules/bluetooth/BluetoothError.h"
-#include "modules/bluetooth/BluetoothSupplement.h"
+#include "modules/bluetooth/BluetoothRemoteGATTCharacteristic.h"
 #include "modules/bluetooth/BluetoothUUID.h"
 #include "modules/bluetooth/RequestDeviceOptions.h"
 #include "platform/UserGestureIndicator.h"
-#include "public/platform/modules/bluetooth/WebBluetooth.h"
-#include "public/platform/modules/bluetooth/WebRequestDeviceOptions.h"
+#include "public/platform/InterfaceProvider.h"
 #include <memory>
 #include <utility>
 
@@ -38,9 +40,10 @@
     "A device name can't be longer than 248 bytes.";
 }  // namespace
 
-static void canonicalizeFilter(const BluetoothScanFilterInit& filter,
-                               WebBluetoothScanFilter& canonicalizedFilter,
-                               ExceptionState& exceptionState) {
+static void canonicalizeFilter(
+    const BluetoothScanFilterInit& filter,
+    mojom::blink::WebBluetoothScanFilterPtr& canonicalizedFilter,
+    ExceptionState& exceptionState) {
   if (!(filter.hasServices() || filter.hasName() || filter.hasNamePrefix())) {
     exceptionState.throwTypeError(
         "A filter must restrict the devices in some way.");
@@ -53,18 +56,16 @@
           "'services', if present, must contain at least one service.");
       return;
     }
-    Vector<WebString> services;
+    canonicalizedFilter->services.emplace();
     for (const StringOrUnsignedLong& service : filter.services()) {
       const String& validatedService =
           BluetoothUUID::getService(service, exceptionState);
       if (exceptionState.hadException())
         return;
-      services.append(validatedService);
+      canonicalizedFilter->services->append(validatedService);
     }
-    canonicalizedFilter.services.assign(services);
   }
 
-  canonicalizedFilter.hasName = filter.hasName();
   if (filter.hasName()) {
     size_t nameLength = filter.name().utf8().length();
     if (nameLength > kMaxDeviceNameLength) {
@@ -75,7 +76,7 @@
       exceptionState.throwDOMException(NotFoundError, kFilterNameTooLong);
       return;
     }
-    canonicalizedFilter.name = filter.name();
+    canonicalizedFilter->name = filter.name();
   }
 
   if (filter.hasNamePrefix()) {
@@ -93,13 +94,14 @@
           "'namePrefix', if present, must me non-empty.");
       return;
     }
-    canonicalizedFilter.namePrefix = filter.namePrefix();
+    canonicalizedFilter->name_prefix = filter.namePrefix();
   }
 }
 
-static void convertRequestDeviceOptions(const RequestDeviceOptions& options,
-                                        WebRequestDeviceOptions& result,
-                                        ExceptionState& exceptionState) {
+static void convertRequestDeviceOptions(
+    const RequestDeviceOptions& options,
+    mojom::blink::WebBluetoothRequestDeviceOptionsPtr& result,
+    ExceptionState& exceptionState) {
   if (!(options.hasFilters() ^ options.acceptAllDevices())) {
     exceptionState.throwTypeError(
         "Either 'filters' should be present or 'acceptAllDevices' should be "
@@ -107,75 +109,64 @@
     return;
   }
 
-  result.acceptAllDevices = options.acceptAllDevices();
+  result->accept_all_devices = options.acceptAllDevices();
 
-  result.hasFilters = options.hasFilters();
-  if (result.hasFilters) {
+  if (options.hasFilters()) {
     if (options.filters().isEmpty()) {
       exceptionState.throwTypeError(
           "'filters' member must be non-empty to find any devices.");
       return;
     }
 
-    Vector<WebBluetoothScanFilter> filters;
+    result->filters.emplace();
+
     for (const BluetoothScanFilterInit& filter : options.filters()) {
-      WebBluetoothScanFilter canonicalizedFilter = WebBluetoothScanFilter();
+      auto canonicalizedFilter = mojom::blink::WebBluetoothScanFilter::New();
 
       canonicalizeFilter(filter, canonicalizedFilter, exceptionState);
 
       if (exceptionState.hadException())
         return;
 
-      filters.append(canonicalizedFilter);
+      result->filters.value().append(std::move(canonicalizedFilter));
     }
-
-    result.filters.assign(filters);
   }
 
   if (options.hasOptionalServices()) {
-    Vector<WebString> optionalServices;
     for (const StringOrUnsignedLong& optionalService :
          options.optionalServices()) {
       const String& validatedOptionalService =
           BluetoothUUID::getService(optionalService, exceptionState);
       if (exceptionState.hadException())
         return;
-      optionalServices.append(validatedOptionalService);
+      result->optional_services.append(validatedOptionalService);
     }
-    result.optionalServices.assign(optionalServices);
   }
 }
 
-class RequestDeviceCallback : public WebBluetoothRequestDeviceCallbacks {
- public:
-  RequestDeviceCallback(Bluetooth* bluetooth, ScriptPromiseResolver* resolver)
-      : m_bluetooth(bluetooth), m_resolver(resolver) {}
+void Bluetooth::dispose() {
+  // The pipe to this object must be closed when is marked unreachable to
+  // prevent messages from being dispatched before lazy sweeping.
+  if (m_clientBinding.is_bound())
+    m_clientBinding.Close();
+}
 
-  void onSuccess(std::unique_ptr<WebBluetoothDeviceInit> deviceInit) override {
-    if (!m_resolver->getExecutionContext() ||
-        m_resolver->getExecutionContext()->isContextDestroyed())
-      return;
+void Bluetooth::RequestDeviceCallback(
+    ScriptPromiseResolver* resolver,
+    mojom::blink::WebBluetoothResult result,
+    mojom::blink::WebBluetoothDevicePtr device) {
+  if (!resolver->getExecutionContext() ||
+      resolver->getExecutionContext()->isContextDestroyed())
+    return;
 
-    BluetoothDevice* device = m_bluetooth->getBluetoothDeviceRepresentingDevice(
-        std::move(deviceInit), m_resolver);
-
-    m_resolver->resolve(device);
+  if (result == mojom::blink::WebBluetoothResult::SUCCESS) {
+    BluetoothDevice* bluetoothDevice = getBluetoothDeviceRepresentingDevice(
+        device->id->device_id, device->name, resolver);
+    resolver->resolve(bluetoothDevice);
+  } else {
+    resolver->reject(BluetoothError::take(resolver, result));
   }
-
-  void onError(
-      int32_t
-          error /* Corresponds to WebBluetoothResult in web_bluetooth.mojom */)
-      override {
-    if (!m_resolver->getExecutionContext() ||
-        m_resolver->getExecutionContext()->isContextDestroyed())
-      return;
-    m_resolver->reject(BluetoothError::take(m_resolver, error));
-  }
-
- private:
-  Persistent<Bluetooth> m_bluetooth;
-  Persistent<ScriptPromiseResolver> m_resolver;
-};
+}
 
 // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-requestdevice
 ScriptPromise Bluetooth::requestDevice(ScriptState* scriptState,
@@ -201,40 +192,109 @@
             "Must be handling a user gesture to show a permission request."));
   }
 
-  WebBluetooth* webbluetooth =
-      BluetoothSupplement::fromScriptState(scriptState);
-  if (!webbluetooth)
+  if (!m_service) {
+    InterfaceProvider* interfaceProvider = nullptr;
+    ExecutionContext* executionContext = scriptState->getExecutionContext();
+    if (executionContext->isDocument()) {
+      Document* document = toDocument(executionContext);
+      if (document->frame())
+        interfaceProvider = document->frame()->interfaceProvider();
+    }
+
+    if (interfaceProvider)
+      interfaceProvider->getInterface(mojo::MakeRequest(&m_service));
+
+    if (m_service) {
+      // Create an associated interface ptr and pass it to the
+      // WebBluetoothService so that it can send us events without us
+      // prompting.
+      mojom::blink::WebBluetoothServiceClientAssociatedPtrInfo ptrInfo;
+      m_clientBinding.Bind(&ptrInfo, m_service.associated_group());
+      m_service->SetClient(std::move(ptrInfo));
+    }
+  }
+
+  if (!m_service) {
     return ScriptPromise::rejectWithDOMException(
         scriptState, DOMException::create(NotSupportedError));
+  }
 
   // In order to convert the arguments from service names and aliases to just
   // UUIDs, do the following substeps:
-  WebRequestDeviceOptions webOptions;
-  convertRequestDeviceOptions(options, webOptions, exceptionState);
+  auto deviceOptions = mojom::blink::WebBluetoothRequestDeviceOptions::New();
+  convertRequestDeviceOptions(options, deviceOptions, exceptionState);
+
   if (exceptionState.hadException())
     return exceptionState.reject(scriptState);
 
   // Subsequent steps are handled in the browser process.
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
   ScriptPromise promise = resolver->promise();
-  webbluetooth->requestDevice(webOptions,
-                              new RequestDeviceCallback(this, resolver));
+
+  service()->RequestDevice(
+      std::move(deviceOptions),
+      convertToBaseCallback(WTF::bind(&Bluetooth::RequestDeviceCallback,
+                                      wrapPersistent(this),
+                                      wrapPersistent(resolver))));
   return promise;
 }
 
+void Bluetooth::addDevice(const String& deviceId, BluetoothDevice* device) {
+  m_connectedDevices.add(deviceId, device);
+}
+
+void Bluetooth::removeDevice(const String& deviceId) {
+  m_connectedDevices.remove(deviceId);
+}
+
+void Bluetooth::registerCharacteristicObject(
+    const String& characteristicInstanceId,
+    BluetoothRemoteGATTCharacteristic* characteristic) {
+  m_activeCharacteristics.add(characteristicInstanceId, characteristic);
+}
+
+void Bluetooth::characteristicObjectRemoved(
+    const String& characteristicInstanceId) {
+  m_activeCharacteristics.remove(characteristicInstanceId);
+}
+
 DEFINE_TRACE(Bluetooth) {
   visitor->trace(m_deviceInstanceMap);
+  visitor->trace(m_activeCharacteristics);
+  visitor->trace(m_connectedDevices);
+}
+
+Bluetooth::Bluetooth() : m_clientBinding(this) {}
+
+void Bluetooth::RemoteCharacteristicValueChanged(
+    const WTF::String& characteristicInstanceId,
+    const WTF::Vector<uint8_t>& value) {
+  BluetoothRemoteGATTCharacteristic* characteristic =
+      m_activeCharacteristics.get(characteristicInstanceId);
+  if (characteristic)
+    characteristic->dispatchCharacteristicValueChanged(value);
+}
+
+void Bluetooth::GattServerDisconnected(
+    mojom::blink::WebBluetoothDeviceIdPtr deviceId) {
+  BluetoothDevice* device = m_connectedDevices.get(deviceId->device_id);
+  if (device) {
+    // Remove device from the map before calling dispatchGattServerDisconnected
+    // to avoid removing a device the gattserverdisconnected event handler might
+    // have re-connected.
+    m_connectedDevices.remove(deviceId->device_id);
+    device->dispatchGattServerDisconnected();
+  }
 }
 
 BluetoothDevice* Bluetooth::getBluetoothDeviceRepresentingDevice(
-    std::unique_ptr<WebBluetoothDeviceInit> deviceInit,
+    const String& id,
+    const String& name,
     ScriptPromiseResolver* resolver) {
-  BluetoothDevice* device = m_deviceInstanceMap.get(deviceInit->id);
+  BluetoothDevice* device = m_deviceInstanceMap.get(id);
   if (!device) {
-    String deviceId = deviceInit->id;
-    device = BluetoothDevice::take(resolver, std::move(deviceInit));
-
-    auto result = m_deviceInstanceMap.add(deviceId, device);
+    device = BluetoothDevice::take(resolver, id, name, this);
+    auto result = m_deviceInstanceMap.add(id, device);
     DCHECK(result.isNewEntry);
   }
   return device;
diff --git a/third_party/WebKit/Source/modules/bluetooth/Bluetooth.h b/third_party/WebKit/Source/modules/bluetooth/Bluetooth.h
index 53246494..9b0588957 100644
--- a/third_party/WebKit/Source/modules/bluetooth/Bluetooth.h
+++ b/third_party/WebKit/Source/modules/bluetooth/Bluetooth.h
@@ -8,40 +8,87 @@
 #include "bindings/core/v8/ScriptPromise.h"
 #include "bindings/core/v8/ScriptWrappable.h"
 #include "modules/bluetooth/BluetoothDevice.h"
+#include "mojo/public/cpp/bindings/associated_binding.h"
 #include "platform/heap/Handle.h"
+#include "public/platform/modules/bluetooth/web_bluetooth.mojom-blink.h"
 #include <memory>
 
 namespace blink {
 
+class BluetoothRemoteGATTCharacteristic;
 class RequestDeviceOptions;
 class ScriptPromise;
 class ScriptState;
 
-class Bluetooth : public GarbageCollected<Bluetooth>, public ScriptWrappable {
+class Bluetooth : public GarbageCollectedFinalized<Bluetooth>,
+                  public ScriptWrappable,
+                  public mojom::blink::WebBluetoothServiceClient {
   DEFINE_WRAPPERTYPEINFO();
+  USING_PRE_FINALIZER(Bluetooth, dispose);
 
  public:
   static Bluetooth* create() { return new Bluetooth(); }
 
+  void dispose();
+
   // BluetoothDiscovery interface
   ScriptPromise requestDevice(ScriptState*,
                               const RequestDeviceOptions&,
                               ExceptionState&);
 
+  mojom::blink::WebBluetoothService* service() { return m_service.get(); }
+
+  void addDevice(const String& deviceId, BluetoothDevice*);
+
+  void removeDevice(const String& deviceId);
+
+  void registerCharacteristicObject(const String& characteristicInstanceId,
+                                    BluetoothRemoteGATTCharacteristic*);
+  void characteristicObjectRemoved(const String& characteristicInstanceId);
+
   // Interface required by Garbage Collection:
   DECLARE_VIRTUAL_TRACE();
 
  private:
-  friend class RequestDeviceCallback;
+  Bluetooth();
 
-  BluetoothDevice* getBluetoothDeviceRepresentingDevice(
-      std::unique_ptr<WebBluetoothDeviceInit>,
-      ScriptPromiseResolver*);
+  // mojom::blink::WebBluetoothServiceClient:
+  void RemoteCharacteristicValueChanged(
+      const WTF::String& characteristicInstanceId,
+      const WTF::Vector<uint8_t>& value) override;
+  void GattServerDisconnected(mojom::blink::WebBluetoothDeviceIdPtr) override;
+
+  BluetoothDevice* getBluetoothDeviceRepresentingDevice(const String& id,
+                                                        const String& name,
+                                                        ScriptPromiseResolver*);
+
+  void RequestDeviceCallback(ScriptPromiseResolver*,
+                             mojom::blink::WebBluetoothResult,
+                             mojom::blink::WebBluetoothDevicePtr);
 
   // Map of device ids to BluetoothDevice objects.
   // Ensures only one BluetoothDevice instance represents each
   // Bluetooth device inside a single global object.
   HeapHashMap<String, Member<BluetoothDevice>> m_deviceInstanceMap;
+
+  // Map of characteristic instance ids to BluetoothRemoteGATTCharacteristic.
+  // When characteristicObjectRemoved is called the characteristic should be
+  // removed from the map. Keeps track of what characteristics have listeners.
+  HeapHashMap<String, Member<BluetoothRemoteGATTCharacteristic>>
+      m_activeCharacteristics;
+
+  // Map of device ids to BluetoothDevice. Added in
+  // BluetoothRemoteGATTServer::connect() and removed in
+  // BluetoothRemoteGATTServer::disconnect(). This means a device may not
+  // actually be connected while in this map, but that it will definitely be
+  // removed when the page navigates.
+  HeapHashMap<String, Member<BluetoothDevice>> m_connectedDevices;
+
+  mojom::blink::WebBluetoothServicePtr m_service;
+
+  // Binding associated with |m_service|.
+  mojo::AssociatedBinding<mojom::blink::WebBluetoothServiceClient>
+      m_clientBinding;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothAttributeInstanceMap.cpp b/third_party/WebKit/Source/modules/bluetooth/BluetoothAttributeInstanceMap.cpp
index f58be912..63d3283 100644
--- a/third_party/WebKit/Source/modules/bluetooth/BluetoothAttributeInstanceMap.cpp
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothAttributeInstanceMap.cpp
@@ -6,8 +6,6 @@
 
 #include "modules/bluetooth/BluetoothDevice.h"
 #include "modules/bluetooth/BluetoothRemoteGATTService.h"
-#include "public/platform/modules/bluetooth/WebBluetoothRemoteGATTCharacteristicInit.h"
-#include "public/platform/modules/bluetooth/WebBluetoothRemoteGATTService.h"
 #include <memory>
 #include <utility>
 
@@ -19,15 +17,16 @@
 
 BluetoothRemoteGATTService*
 BluetoothAttributeInstanceMap::getOrCreateBluetoothRemoteGATTService(
-    std::unique_ptr<WebBluetoothRemoteGATTService> webService) {
-  String serviceInstanceId = webService->serviceInstanceID;
-
+    const String& serviceInstanceId,
+    const String& uuid,
+    bool isPrimary,
+    const String& deviceInstanceId) {
   BluetoothRemoteGATTService* service =
       m_serviceIdToObject.get(serviceInstanceId);
 
   if (!service) {
-    service =
-        new BluetoothRemoteGATTService(std::move(webService), m_device.get());
+    service = new BluetoothRemoteGATTService(serviceInstanceId, uuid, isPrimary,
+                                             deviceInstanceId, m_device);
     m_serviceIdToObject.add(serviceInstanceId, service);
   }
 
@@ -42,16 +41,18 @@
 BluetoothRemoteGATTCharacteristic*
 BluetoothAttributeInstanceMap::getOrCreateBluetoothRemoteGATTCharacteristic(
     ExecutionContext* context,
-    std::unique_ptr<WebBluetoothRemoteGATTCharacteristicInit> webCharacteristic,
+    const String& characteristicInstanceId,
+    const String& serviceInstanceId,
+    const String& uuid,
+    uint32_t characteristicProperties,
     BluetoothRemoteGATTService* service) {
-  String characteristicInstanceId = webCharacteristic->characteristicInstanceID;
-
   BluetoothRemoteGATTCharacteristic* characteristic =
       m_characteristicIdToObject.get(characteristicInstanceId);
 
   if (!characteristic) {
     characteristic = BluetoothRemoteGATTCharacteristic::create(
-        context, std::move(webCharacteristic), service);
+        context, characteristicInstanceId, serviceInstanceId, uuid,
+        characteristicProperties, service, m_device);
     m_characteristicIdToObject.add(characteristicInstanceId, characteristic);
   }
 
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothAttributeInstanceMap.h b/third_party/WebKit/Source/modules/bluetooth/BluetoothAttributeInstanceMap.h
index 17177a84..50ba595 100644
--- a/third_party/WebKit/Source/modules/bluetooth/BluetoothAttributeInstanceMap.h
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothAttributeInstanceMap.h
@@ -16,9 +16,6 @@
 class BluetoothDevice;
 class ExecutionContext;
 
-struct WebBluetoothRemoteGATTCharacteristicInit;
-struct WebBluetoothRemoteGATTService;
-
 // Map that holds all GATT attributes, i.e. BluetoothRemoteGATTService,
 // BluetoothRemoteGATTCharacteristic, BluetoothRemoteGATTDescriptor, for
 // the BluetoothDevice passed in when constructing the object.
@@ -33,7 +30,10 @@
   // Otherwise returns the BluetoothRemoteGATTService object already
   // in the map.
   BluetoothRemoteGATTService* getOrCreateBluetoothRemoteGATTService(
-      std::unique_ptr<WebBluetoothRemoteGATTService>);
+      const String& serviceInstanceId,
+      const String& uuid,
+      bool isPrimary,
+      const String& deviceInstanceId);
 
   // Returns true if a BluetoothRemoteGATTService with |serviceInstanceId|
   // is in the map.
@@ -46,7 +46,10 @@
   BluetoothRemoteGATTCharacteristic*
   getOrCreateBluetoothRemoteGATTCharacteristic(
       ExecutionContext*,
-      std::unique_ptr<WebBluetoothRemoteGATTCharacteristicInit>,
+      const String& characteristicInstanceId,
+      const String& serviceInstanceId,
+      const String& uuid,
+      uint32_t characteristicProperties,
       BluetoothRemoteGATTService*);
 
   // Returns true if a BluetoothRemoteGATTCharacteristic with
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.cpp b/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.cpp
index edf8326..8ea588a4 100644
--- a/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.cpp
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.cpp
@@ -9,39 +9,51 @@
 #include "bindings/core/v8/ScriptPromiseResolver.h"
 #include "core/dom/DOMException.h"
 #include "core/events/Event.h"
+#include "modules/bluetooth/Bluetooth.h"
 #include "modules/bluetooth/BluetoothAttributeInstanceMap.h"
 #include "modules/bluetooth/BluetoothError.h"
 #include "modules/bluetooth/BluetoothRemoteGATTServer.h"
-#include "modules/bluetooth/BluetoothSupplement.h"
-#include "public/platform/modules/bluetooth/WebBluetooth.h"
-#include "public/platform/modules/bluetooth/WebBluetoothRemoteGATTCharacteristicInit.h"
 #include <memory>
 #include <utility>
 
 namespace blink {
 
-BluetoothDevice::BluetoothDevice(
-    ExecutionContext* context,
-    std::unique_ptr<WebBluetoothDeviceInit> webDevice)
+BluetoothDevice::BluetoothDevice(ExecutionContext* context,
+                                 const String& id,
+                                 const String& name,
+                                 Bluetooth* bluetooth)
     : ContextLifecycleObserver(context),
       m_attributeInstanceMap(new BluetoothAttributeInstanceMap(this)),
-      m_webDevice(std::move(webDevice)),
-      m_gatt(BluetoothRemoteGATTServer::create(this)) {
+      m_id(id),
+      m_name(name),
+      m_gatt(BluetoothRemoteGATTServer::create(this)),
+      m_bluetooth(bluetooth) {}
+
+// static
+BluetoothDevice* BluetoothDevice::take(ScriptPromiseResolver* resolver,
+                                       const String& id,
+                                       const String& name,
+                                       Bluetooth* bluetooth) {
+  return new BluetoothDevice(resolver->getExecutionContext(), id, name,
+                             bluetooth);
 }
 
-BluetoothDevice* BluetoothDevice::take(
-    ScriptPromiseResolver* resolver,
-    std::unique_ptr<WebBluetoothDeviceInit> webDevice) {
-  ASSERT(webDevice);
-  return new BluetoothDevice(resolver->getExecutionContext(),
-                             std::move(webDevice));
+// static
+mojom::blink::WebBluetoothDeviceIdPtr BluetoothDevice::createMojoDeviceId(
+    const String& deviceId) {
+  auto result = mojom::blink::WebBluetoothDeviceId::New();
+  result->device_id = deviceId;
+  return result;
 }
 
 BluetoothRemoteGATTService*
 BluetoothDevice::getOrCreateBluetoothRemoteGATTService(
-    std::unique_ptr<WebBluetoothRemoteGATTService> webService) {
+    const String& serviceInstanceId,
+    const String& uuid,
+    bool isPrimary,
+    const String& deviceInstanceId) {
   return m_attributeInstanceMap->getOrCreateBluetoothRemoteGATTService(
-      std::move(webService));
+      serviceInstanceId, uuid, isPrimary, deviceInstanceId);
 }
 
 bool BluetoothDevice::isValidService(const String& serviceInstanceId) {
@@ -51,10 +63,14 @@
 BluetoothRemoteGATTCharacteristic*
 BluetoothDevice::getOrCreateBluetoothRemoteGATTCharacteristic(
     ExecutionContext* context,
-    std::unique_ptr<WebBluetoothRemoteGATTCharacteristicInit> webCharacteristic,
+    const String& characteristicInstanceId,
+    const String& serviceInstanceId,
+    const String& uuid,
+    uint32_t characteristicProperties,
     BluetoothRemoteGATTService* service) {
   return m_attributeInstanceMap->getOrCreateBluetoothRemoteGATTCharacteristic(
-      context, std::move(webCharacteristic), service);
+      context, characteristicInstanceId, serviceInstanceId, uuid,
+      characteristicProperties, service);
 }
 
 bool BluetoothDevice::isValidCharacteristic(
@@ -75,8 +91,11 @@
   if (m_gatt->connected()) {
     m_gatt->setConnected(false);
     m_gatt->ClearActiveAlgorithms();
-    BluetoothSupplement::fromExecutionContext(getExecutionContext())
-        ->disconnect(id());
+    m_bluetooth->removeDevice(id());
+    mojom::blink::WebBluetoothService* service = m_bluetooth->service();
+    auto deviceId = mojom::blink::WebBluetoothDeviceId::New();
+    deviceId->device_id = id();
+    service->RemoteServerDisconnect(std::move(deviceId));
   }
 }
 
@@ -108,6 +127,7 @@
   ContextLifecycleObserver::trace(visitor);
   visitor->trace(m_attributeInstanceMap);
   visitor->trace(m_gatt);
+  visitor->trace(m_bluetooth);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.h b/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.h
index 1db9949..7cae3ba 100644
--- a/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.h
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.h
@@ -10,22 +10,19 @@
 #include "modules/EventTargetModules.h"
 #include "modules/bluetooth/BluetoothRemoteGATTServer.h"
 #include "platform/heap/Heap.h"
-#include "public/platform/modules/bluetooth/WebBluetoothDevice.h"
-#include "public/platform/modules/bluetooth/WebBluetoothDeviceInit.h"
+#include "public/platform/modules/bluetooth/web_bluetooth.mojom-blink.h"
 #include "wtf/text/WTFString.h"
 #include <memory>
 
 namespace blink {
 
+class Bluetooth;
 class BluetoothAttributeInstanceMap;
 class BluetoothRemoteGATTCharacteristic;
 class BluetoothRemoteGATTServer;
 class BluetoothRemoteGATTService;
 class ScriptPromiseResolver;
 
-struct WebBluetoothRemoteGATTCharacteristicInit;
-struct WebBluetoothRemoteGATTService;
-
 // BluetoothDevice represents a physical bluetooth device in the DOM. See IDL.
 //
 // Callbacks providing WebBluetoothDevice objects are handled by
@@ -33,28 +30,40 @@
 // "Interface required by CallbackPromiseAdapter" section and the
 // CallbackPromiseAdapter class comments.
 class BluetoothDevice final : public EventTargetWithInlineData,
-                              public ContextLifecycleObserver,
-                              public WebBluetoothDevice {
+                              public ContextLifecycleObserver {
   USING_PRE_FINALIZER(BluetoothDevice, dispose);
   DEFINE_WRAPPERTYPEINFO();
   USING_GARBAGE_COLLECTED_MIXIN(BluetoothDevice);
 
  public:
-  BluetoothDevice(ExecutionContext*, std::unique_ptr<WebBluetoothDeviceInit>);
+  BluetoothDevice(ExecutionContext*,
+                  const String& id,
+                  const String& name,
+                  Bluetooth*);
 
   // Interface required by CallbackPromiseAdapter:
-  using WebType = std::unique_ptr<WebBluetoothDeviceInit>;
   static BluetoothDevice* take(ScriptPromiseResolver*,
-                               std::unique_ptr<WebBluetoothDeviceInit>);
+                               const String& id,
+                               const String& name,
+                               Bluetooth*);
+
+  static mojom::blink::WebBluetoothDeviceIdPtr createMojoDeviceId(
+      const String& deviceId);
 
   BluetoothRemoteGATTService* getOrCreateBluetoothRemoteGATTService(
-      std::unique_ptr<WebBluetoothRemoteGATTService>);
+      const String& serviceInstanceId,
+      const String& uuid,
+      bool isPrimary,
+      const String& deviceInstanceId);
   bool isValidService(const String& serviceInstanceId);
 
   BluetoothRemoteGATTCharacteristic*
   getOrCreateBluetoothRemoteGATTCharacteristic(
       ExecutionContext*,
-      std::unique_ptr<WebBluetoothRemoteGATTCharacteristicInit>,
+      const String& characteristicInstanceId,
+      const String& serviceInstanceId,
+      const String& uuid,
+      uint32_t characteristicProperties,
       BluetoothRemoteGATTService*);
   bool isValidCharacteristic(const String& characteristicInstanceId);
 
@@ -88,15 +97,16 @@
   const AtomicString& interfaceName() const override;
   ExecutionContext* getExecutionContext() const override;
 
-  // WebBluetoothDevice interface:
-  void dispatchGattServerDisconnected() override;
+  void dispatchGattServerDisconnected();
+
+  Bluetooth* bluetooth() { return m_bluetooth; }
 
   // Interface required by Garbage Collection:
   DECLARE_VIRTUAL_TRACE();
 
   // IDL exposed interface:
-  String id() { return m_webDevice->id; }
-  String name() { return m_webDevice->name; }
+  String id() { return m_id; }
+  String name() { return m_name; }
   BluetoothRemoteGATTServer* gatt() { return m_gatt; }
 
   DEFINE_ATTRIBUTE_EVENT_LISTENER(gattserverdisconnected);
@@ -105,8 +115,10 @@
   // Holds all GATT Attributes associated with this BluetoothDevice.
   Member<BluetoothAttributeInstanceMap> m_attributeInstanceMap;
 
-  std::unique_ptr<WebBluetoothDeviceInit> m_webDevice;
+  const String m_id;
+  const String m_name;
   Member<BluetoothRemoteGATTServer> m_gatt;
+  Member<Bluetooth> m_bluetooth;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothError.cpp b/third_party/WebKit/Source/modules/bluetooth/BluetoothError.cpp
index cd703d4..643385a 100644
--- a/third_party/WebKit/Source/modules/bluetooth/BluetoothError.cpp
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothError.cpp
@@ -6,15 +6,12 @@
 
 #include "core/dom/DOMException.h"
 #include "core/dom/ExceptionCode.h"
-#include "third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom-blink.h"
 
 namespace blink {
 
-DOMException* BluetoothError::take(
-    ScriptPromiseResolver*,
-    int32_t
-        webError /* Corresponds to WebBluetoothResult in web_bluetooth.mojom */) {
-  switch (static_cast<mojom::blink::WebBluetoothResult>(webError)) {
+DOMException* BluetoothError::take(ScriptPromiseResolver*,
+                                   mojom::blink::WebBluetoothResult error) {
+  switch (error) {
     case mojom::blink::WebBluetoothResult::SUCCESS:
       ASSERT_NOT_REACHED();
       return DOMException::create(UnknownError);
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothError.h b/third_party/WebKit/Source/modules/bluetooth/BluetoothError.h
index 311677d..c9374283 100644
--- a/third_party/WebKit/Source/modules/bluetooth/BluetoothError.h
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothError.h
@@ -6,6 +6,7 @@
 #define BluetoothError_h
 
 #include "platform/heap/Handle.h"
+#include "third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom-blink.h"
 #include "wtf/Allocator.h"
 
 namespace blink {
@@ -20,12 +21,8 @@
 
  public:
   // Interface required by CallbackPromiseAdapter:
-  using WebType =
-      int32_t /* Corresponds to WebBluetoothResult in web_bluetooth.mojom */;
-  static DOMException* take(
-      ScriptPromiseResolver*,
-      int32_t
-          error /* Corresponds to WebBluetoothResult in web_bluetooth.mojom */);
+  static DOMException* take(ScriptPromiseResolver*,
+                            mojom::blink::WebBluetoothResult);
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTCharacteristic.cpp b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTCharacteristic.cpp
index 5f88b99..a1614922 100644
--- a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTCharacteristic.cpp
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTCharacteristic.cpp
@@ -11,11 +11,11 @@
 #include "core/dom/ExceptionCode.h"
 #include "core/events/Event.h"
 #include "core/inspector/ConsoleMessage.h"
+#include "modules/bluetooth/Bluetooth.h"
 #include "modules/bluetooth/BluetoothCharacteristicProperties.h"
+#include "modules/bluetooth/BluetoothDevice.h"
 #include "modules/bluetooth/BluetoothError.h"
 #include "modules/bluetooth/BluetoothRemoteGATTService.h"
-#include "modules/bluetooth/BluetoothSupplement.h"
-#include "public/platform/modules/bluetooth/WebBluetooth.h"
 #include <memory>
 
 namespace blink {
@@ -30,36 +30,47 @@
     "Characteristic is no longer valid. Remember to retrieve the "
     "characteristic again after reconnecting.";
 
-DOMDataView* ConvertWebVectorToDataView(const WebVector<uint8_t>& webVector) {
-  static_assert(sizeof(*webVector.data()) == 1,
+DOMDataView* ConvertWTFVectorToDataView(const Vector<uint8_t>& wtfVector) {
+  static_assert(sizeof(*wtfVector.data()) == 1,
                 "uint8_t should be a single byte");
   DOMArrayBuffer* domBuffer =
-      DOMArrayBuffer::create(webVector.data(), webVector.size());
-  return DOMDataView::create(domBuffer, 0, webVector.size());
+      DOMArrayBuffer::create(wtfVector.data(), wtfVector.size());
+  return DOMDataView::create(domBuffer, 0, wtfVector.size());
 }
 
 }  // anonymous namespace
 
 BluetoothRemoteGATTCharacteristic::BluetoothRemoteGATTCharacteristic(
     ExecutionContext* context,
-    std::unique_ptr<WebBluetoothRemoteGATTCharacteristicInit> webCharacteristic,
-    BluetoothRemoteGATTService* service)
+    const String& characteristicInstanceId,
+    const String& serviceInstanceId,
+    const String& uuid,
+    uint32_t characteristicProperties,
+    BluetoothRemoteGATTService* service,
+    BluetoothDevice* device)
     : ContextLifecycleObserver(context),
-      m_webCharacteristic(std::move(webCharacteristic)),
+      m_characteristicInstanceId(characteristicInstanceId),
+      m_serviceInstanceId(serviceInstanceId),
+      m_uuid(uuid),
+      m_characteristicProperties(characteristicProperties),
       m_service(service),
-      m_stopped(false) {
-  m_properties = BluetoothCharacteristicProperties::create(
-      m_webCharacteristic->characteristicProperties);
+      m_stopped(false),
+      m_device(device) {
+  m_properties =
+      BluetoothCharacteristicProperties::create(m_characteristicProperties);
 }
 
 BluetoothRemoteGATTCharacteristic* BluetoothRemoteGATTCharacteristic::create(
     ExecutionContext* context,
-    std::unique_ptr<WebBluetoothRemoteGATTCharacteristicInit> webCharacteristic,
-    BluetoothRemoteGATTService* service) {
-  DCHECK(webCharacteristic);
-
+    const String& characteristicInstanceId,
+    const String& serviceInstanceId,
+    const String& uuid,
+    uint32_t characteristicProperties,
+    BluetoothRemoteGATTService* service,
+    BluetoothDevice* device) {
   return new BluetoothRemoteGATTCharacteristic(
-      context, std::move(webCharacteristic), service);
+      context, characteristicInstanceId, serviceInstanceId, uuid,
+      characteristicProperties, service, device);
 }
 
 void BluetoothRemoteGATTCharacteristic::setValue(DOMDataView* domDataView) {
@@ -67,8 +78,8 @@
 }
 
 void BluetoothRemoteGATTCharacteristic::dispatchCharacteristicValueChanged(
-    const WebVector<uint8_t>& value) {
-  this->setValue(ConvertWebVectorToDataView(value));
+    const Vector<uint8_t>& value) {
+  this->setValue(ConvertWTFVectorToDataView(value));
   dispatchEvent(Event::create(EventTypeNames::characteristicvaluechanged));
 }
 
@@ -83,10 +94,8 @@
 void BluetoothRemoteGATTCharacteristic::notifyCharacteristicObjectRemoved() {
   if (!m_stopped) {
     m_stopped = true;
-    WebBluetooth* webbluetooth = BluetoothSupplement::fromExecutionContext(
-        ContextLifecycleObserver::getExecutionContext());
-    webbluetooth->characteristicObjectRemoved(
-        m_webCharacteristic->characteristicInstanceID, this);
+    m_device->bluetooth()->characteristicObjectRemoved(
+        m_characteristicInstanceId);
   }
 }
 
@@ -107,162 +116,106 @@
   // We will also need to unregister a characteristic once all the event
   // listeners have been removed. See http://crbug.com/541390
   if (eventType == EventTypeNames::characteristicvaluechanged) {
-    WebBluetooth* webbluetooth =
-        BluetoothSupplement::fromExecutionContext(getExecutionContext());
-    webbluetooth->registerCharacteristicObject(
-        m_webCharacteristic->characteristicInstanceID, this);
+    m_device->bluetooth()->registerCharacteristicObject(
+        m_characteristicInstanceId, this);
   }
 }
 
-class ReadValueCallback : public WebBluetoothReadValueCallbacks {
- public:
-  ReadValueCallback(BluetoothRemoteGATTCharacteristic* characteristic,
-                    ScriptPromiseResolver* resolver)
-      : m_characteristic(characteristic), m_resolver(resolver) {
-    // We always check that the device is connected before constructing this
-    // object.
-    CHECK(m_characteristic->gatt()->connected());
-    m_characteristic->gatt()->AddToActiveAlgorithms(m_resolver.get());
+void BluetoothRemoteGATTCharacteristic::ReadValueCallback(
+    ScriptPromiseResolver* resolver,
+    mojom::blink::WebBluetoothResult result,
+    const Optional<Vector<uint8_t>>& value) {
+  if (!resolver->getExecutionContext() ||
+      resolver->getExecutionContext()->isContextDestroyed())
+    return;
+
+  // If the resolver is not in the set of ActiveAlgorithms then the frame
+  // disconnected so we reject.
+  if (!gatt()->RemoveFromActiveAlgorithms(resolver)) {
+    resolver->reject(
+        DOMException::create(NetworkError, kGATTServerDisconnected));
+    return;
   }
 
-  void onSuccess(const WebVector<uint8_t>& value) override {
-    if (!m_resolver->getExecutionContext() ||
-        m_resolver->getExecutionContext()->isContextDestroyed())
-      return;
-
-    if (!m_characteristic->gatt()->RemoveFromActiveAlgorithms(
-            m_resolver.get())) {
-      m_resolver->reject(
-          DOMException::create(NetworkError, kGATTServerDisconnected));
-      return;
-    }
-
-    DOMDataView* domDataView = ConvertWebVectorToDataView(value);
-    if (m_characteristic)
-      m_characteristic->setValue(domDataView);
-
-    m_resolver->resolve(domDataView);
+  if (result == mojom::blink::WebBluetoothResult::SUCCESS) {
+    DCHECK(value);
+    DOMDataView* domDataView = ConvertWTFVectorToDataView(value.value());
+    setValue(domDataView);
+    resolver->resolve(domDataView);
+  } else {
+    resolver->reject(BluetoothError::take(resolver, result));
   }
-
-  void onError(
-      int32_t
-          error /* Corresponds to WebBluetoothResult in web_bluetooth.mojom */)
-      override {
-    if (!m_resolver->getExecutionContext() ||
-        m_resolver->getExecutionContext()->isContextDestroyed())
-      return;
-
-    if (!m_characteristic->gatt()->RemoveFromActiveAlgorithms(
-            m_resolver.get())) {
-      m_resolver->reject(
-          DOMException::create(NetworkError, kGATTServerDisconnected));
-      return;
-    }
-
-    m_resolver->reject(BluetoothError::take(m_resolver, error));
-  }
-
- private:
-  Persistent<BluetoothRemoteGATTCharacteristic> m_characteristic;
-  Persistent<ScriptPromiseResolver> m_resolver;
-};
+}
 
 ScriptPromise BluetoothRemoteGATTCharacteristic::readValue(
     ScriptState* scriptState) {
+  // We always check that the device is connected.
   if (!gatt()->connected()) {
     return ScriptPromise::rejectWithDOMException(
         scriptState,
         DOMException::create(NetworkError, kGATTServerNotConnected));
   }
 
-  if (!gatt()->device()->isValidCharacteristic(
-          m_webCharacteristic->characteristicInstanceID)) {
+  if (!gatt()->device()->isValidCharacteristic(m_characteristicInstanceId)) {
     return ScriptPromise::rejectWithDOMException(
         scriptState,
         DOMException::create(InvalidStateError, kInvalidCharacteristic));
   }
 
-  WebBluetooth* webbluetooth =
-      BluetoothSupplement::fromScriptState(scriptState);
-
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
   ScriptPromise promise = resolver->promise();
-  webbluetooth->readValue(m_webCharacteristic->characteristicInstanceID,
-                          new ReadValueCallback(this, resolver));
+  gatt()->AddToActiveAlgorithms(resolver);
+
+  mojom::blink::WebBluetoothService* service = m_device->bluetooth()->service();
+  service->RemoteCharacteristicReadValue(
+      m_characteristicInstanceId,
+      convertToBaseCallback(
+          WTF::bind(&BluetoothRemoteGATTCharacteristic::ReadValueCallback,
+                    wrapPersistent(this), wrapPersistent(resolver))));
 
   return promise;
 }
 
-class WriteValueCallback : public WebBluetoothWriteValueCallbacks {
- public:
-  WriteValueCallback(BluetoothRemoteGATTCharacteristic* characteristic,
-                     ScriptPromiseResolver* resolver)
-      : m_characteristic(characteristic), m_resolver(resolver) {
-    // We always check that the device is connected before constructing this
-    // object.
-    CHECK(m_characteristic->gatt()->connected());
-    m_characteristic->gatt()->AddToActiveAlgorithms(m_resolver.get());
+void BluetoothRemoteGATTCharacteristic::WriteValueCallback(
+    ScriptPromiseResolver* resolver,
+    const Vector<uint8_t>& value,
+    mojom::blink::WebBluetoothResult result) {
+  if (!resolver->getExecutionContext() ||
+      resolver->getExecutionContext()->isContextDestroyed())
+    return;
+
+  // If the resolver is not in the set of ActiveAlgorithms then the frame
+  // disconnected so we reject.
+  if (!gatt()->RemoveFromActiveAlgorithms(resolver)) {
+    resolver->reject(
+        DOMException::create(NetworkError, kGATTServerDisconnected));
+    return;
   }
 
-  void onSuccess(const WebVector<uint8_t>& value) override {
-    if (!m_resolver->getExecutionContext() ||
-        m_resolver->getExecutionContext()->isContextDestroyed())
-      return;
-
-    if (!m_characteristic->gatt()->RemoveFromActiveAlgorithms(
-            m_resolver.get())) {
-      m_resolver->reject(
-          DOMException::create(NetworkError, kGATTServerDisconnected));
-      return;
-    }
-
-    if (m_characteristic) {
-      m_characteristic->setValue(ConvertWebVectorToDataView(value));
-    }
-    m_resolver->resolve();
+  if (result == mojom::blink::WebBluetoothResult::SUCCESS) {
+    setValue(ConvertWTFVectorToDataView(value));
+    resolver->resolve();
+  } else {
+    resolver->reject(BluetoothError::take(resolver, result));
   }
-
-  void onError(
-      int32_t
-          error /* Corresponds to WebBluetoothResult in web_bluetooth.mojom */)
-      override {
-    if (!m_resolver->getExecutionContext() ||
-        m_resolver->getExecutionContext()->isContextDestroyed())
-      return;
-
-    if (!m_characteristic->gatt()->RemoveFromActiveAlgorithms(
-            m_resolver.get())) {
-      m_resolver->reject(
-          DOMException::create(NetworkError, kGATTServerDisconnected));
-      return;
-    }
-
-    m_resolver->reject(BluetoothError::take(m_resolver, error));
-  }
-
- private:
-  Persistent<BluetoothRemoteGATTCharacteristic> m_characteristic;
-  Persistent<ScriptPromiseResolver> m_resolver;
-};
+}
 
 ScriptPromise BluetoothRemoteGATTCharacteristic::writeValue(
     ScriptState* scriptState,
     const DOMArrayPiece& value) {
+  // We always check that the device is connected.
   if (!gatt()->connected()) {
     return ScriptPromise::rejectWithDOMException(
         scriptState,
         DOMException::create(NetworkError, kGATTServerNotConnected));
   }
 
-  if (!gatt()->device()->isValidCharacteristic(
-          m_webCharacteristic->characteristicInstanceID)) {
+  if (!gatt()->device()->isValidCharacteristic(m_characteristicInstanceId)) {
     return ScriptPromise::rejectWithDOMException(
         scriptState,
         DOMException::create(InvalidStateError, kInvalidCharacteristic));
   }
 
-  WebBluetooth* webbluetooth =
-      BluetoothSupplement::fromScriptState(scriptState);
   // Partial implementation of writeValue algorithm:
   // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-writevalue
 
@@ -275,112 +228,100 @@
                                           "Value can't exceed 512 bytes."));
 
   // Let valueVector be a copy of the bytes held by value.
-  WebVector<uint8_t> valueVector(value.bytes(), value.byteLength());
+  Vector<uint8_t> valueVector;
+  valueVector.append(value.bytes(), value.byteLength());
 
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
-
   ScriptPromise promise = resolver->promise();
-  webbluetooth->writeValue(m_webCharacteristic->characteristicInstanceID,
-                           valueVector, new WriteValueCallback(this, resolver));
+  gatt()->AddToActiveAlgorithms(resolver);
+
+  mojom::blink::WebBluetoothService* service = m_device->bluetooth()->service();
+  service->RemoteCharacteristicWriteValue(
+      m_characteristicInstanceId, valueVector,
+      convertToBaseCallback(WTF::bind(
+          &BluetoothRemoteGATTCharacteristic::WriteValueCallback,
+          wrapPersistent(this), wrapPersistent(resolver), valueVector)));
 
   return promise;
 }
 
-class NotificationsCallback : public WebBluetoothNotificationsCallbacks {
- public:
-  NotificationsCallback(BluetoothRemoteGATTCharacteristic* characteristic,
-                        ScriptPromiseResolver* resolver)
-      : m_characteristic(characteristic), m_resolver(resolver) {
-    // We always check that the device is connected before constructing this
-    // object.
-    CHECK(m_characteristic->gatt()->connected());
-    m_characteristic->gatt()->AddToActiveAlgorithms(m_resolver.get());
+void BluetoothRemoteGATTCharacteristic::NotificationsCallback(
+    ScriptPromiseResolver* resolver,
+    mojom::blink::WebBluetoothResult result) {
+  if (!resolver->getExecutionContext() ||
+      resolver->getExecutionContext()->isContextDestroyed())
+    return;
+
+  // If the resolver is not in the set of ActiveAlgorithms then the frame
+  // disconnected so we reject.
+  if (!gatt()->RemoveFromActiveAlgorithms(resolver)) {
+    resolver->reject(
+        DOMException::create(NetworkError, kGATTServerDisconnected));
+    return;
   }
 
-  void onSuccess() override {
-    if (!m_resolver->getExecutionContext() ||
-        m_resolver->getExecutionContext()->isContextDestroyed())
-      return;
-
-    if (!m_characteristic->gatt()->RemoveFromActiveAlgorithms(
-            m_resolver.get())) {
-      m_resolver->reject(
-          DOMException::create(NetworkError, kGATTServerDisconnected));
-      return;
-    }
-
-    m_resolver->resolve(m_characteristic);
+  if (result == mojom::blink::WebBluetoothResult::SUCCESS) {
+    resolver->resolve(this);
+  } else {
+    resolver->reject(BluetoothError::take(resolver, result));
   }
-
-  void onError(
-      int32_t
-          error /* Corresponds to WebBluetoothResult in web_bluetooth.mojom */)
-      override {
-    if (!m_resolver->getExecutionContext() ||
-        m_resolver->getExecutionContext()->isContextDestroyed())
-      return;
-
-    if (!m_characteristic->gatt()->RemoveFromActiveAlgorithms(
-            m_resolver.get())) {
-      m_resolver->reject(
-          DOMException::create(NetworkError, kGATTServerDisconnected));
-      return;
-    }
-
-    m_resolver->reject(BluetoothError::take(m_resolver, error));
-  }
-
- private:
-  Persistent<BluetoothRemoteGATTCharacteristic> m_characteristic;
-  Persistent<ScriptPromiseResolver> m_resolver;
-};
+}
 
 ScriptPromise BluetoothRemoteGATTCharacteristic::startNotifications(
     ScriptState* scriptState) {
+  // We always check that the device is connected.
   if (!gatt()->connected()) {
     return ScriptPromise::rejectWithDOMException(
         scriptState,
         DOMException::create(NetworkError, kGATTServerNotConnected));
   }
 
-  if (!gatt()->device()->isValidCharacteristic(
-          m_webCharacteristic->characteristicInstanceID)) {
+  if (!gatt()->device()->isValidCharacteristic(m_characteristicInstanceId)) {
     return ScriptPromise::rejectWithDOMException(
         scriptState,
         DOMException::create(InvalidStateError, kInvalidCharacteristic));
   }
 
-  WebBluetooth* webbluetooth =
-      BluetoothSupplement::fromScriptState(scriptState);
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
   ScriptPromise promise = resolver->promise();
-  webbluetooth->startNotifications(
-      m_webCharacteristic->characteristicInstanceID,
-      new NotificationsCallback(this, resolver));
+  gatt()->AddToActiveAlgorithms(resolver);
+
+  mojom::blink::WebBluetoothService* service = m_device->bluetooth()->service();
+  service->RemoteCharacteristicStartNotifications(
+      m_characteristicInstanceId,
+      convertToBaseCallback(
+          WTF::bind(&BluetoothRemoteGATTCharacteristic::NotificationsCallback,
+                    wrapPersistent(this), wrapPersistent(resolver))));
+
   return promise;
 }
 
 ScriptPromise BluetoothRemoteGATTCharacteristic::stopNotifications(
     ScriptState* scriptState) {
+  // We always check that the device is connected.
   if (!gatt()->connected()) {
     return ScriptPromise::rejectWithDOMException(
         scriptState,
         DOMException::create(NetworkError, kGATTServerNotConnected));
   }
 
-  if (!gatt()->device()->isValidCharacteristic(
-          m_webCharacteristic->characteristicInstanceID)) {
+  if (!gatt()->device()->isValidCharacteristic(m_characteristicInstanceId)) {
     return ScriptPromise::rejectWithDOMException(
         scriptState,
         DOMException::create(InvalidStateError, kInvalidCharacteristic));
   }
 
-  WebBluetooth* webbluetooth =
-      BluetoothSupplement::fromScriptState(scriptState);
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
   ScriptPromise promise = resolver->promise();
-  webbluetooth->stopNotifications(m_webCharacteristic->characteristicInstanceID,
-                                  new NotificationsCallback(this, resolver));
+  gatt()->AddToActiveAlgorithms(resolver);
+
+  mojom::blink::WebBluetoothService* service = m_device->bluetooth()->service();
+  service->RemoteCharacteristicStopNotifications(
+      m_characteristicInstanceId,
+      convertToBaseCallback(
+          WTF::bind(&BluetoothRemoteGATTCharacteristic::NotificationsCallback,
+                    wrapPersistent(this), wrapPersistent(resolver),
+                    mojom::blink::WebBluetoothResult::SUCCESS)));
   return promise;
 }
 
@@ -388,6 +329,7 @@
   visitor->trace(m_service);
   visitor->trace(m_properties);
   visitor->trace(m_value);
+  visitor->trace(m_device);
   EventTargetWithInlineData::trace(visitor);
   ContextLifecycleObserver::trace(visitor);
 }
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTCharacteristic.h b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTCharacteristic.h
index 97c5126..4f0135d 100644
--- a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTCharacteristic.h
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTCharacteristic.h
@@ -12,14 +12,14 @@
 #include "modules/EventTargetModules.h"
 #include "modules/bluetooth/BluetoothRemoteGATTService.h"
 #include "platform/heap/Handle.h"
-#include "public/platform/modules/bluetooth/WebBluetoothRemoteGATTCharacteristic.h"
-#include "public/platform/modules/bluetooth/WebBluetoothRemoteGATTCharacteristicInit.h"
+#include "public/platform/modules/bluetooth/web_bluetooth.mojom-blink.h"
 #include "wtf/text/WTFString.h"
 #include <memory>
 
 namespace blink {
 
 class BluetoothCharacteristicProperties;
+class BluetoothDevice;
 class ExecutionContext;
 class ScriptPromise;
 class ScriptState;
@@ -34,8 +34,7 @@
 // CallbackPromiseAdapter class comments.
 class BluetoothRemoteGATTCharacteristic final
     : public EventTargetWithInlineData,
-      public ContextLifecycleObserver,
-      public WebBluetoothRemoteGATTCharacteristic {
+      public ContextLifecycleObserver {
   USING_PRE_FINALIZER(BluetoothRemoteGATTCharacteristic, dispose);
   DEFINE_WRAPPERTYPEINFO();
   USING_GARBAGE_COLLECTED_MIXIN(BluetoothRemoteGATTCharacteristic);
@@ -43,19 +42,26 @@
  public:
   explicit BluetoothRemoteGATTCharacteristic(
       ExecutionContext*,
-      std::unique_ptr<WebBluetoothRemoteGATTCharacteristicInit>,
-      BluetoothRemoteGATTService*);
+      const String& characteristicInstanceId,
+      const String& serviceInstanceId,
+      const String& uuid,
+      uint32_t characteristicProperties,
+      BluetoothRemoteGATTService*,
+      BluetoothDevice*);
 
   static BluetoothRemoteGATTCharacteristic* create(
       ExecutionContext*,
-      std::unique_ptr<WebBluetoothRemoteGATTCharacteristicInit>,
-      BluetoothRemoteGATTService*);
+      const String& characteristicInstanceId,
+      const String& serviceInstanceId,
+      const String& uuid,
+      uint32_t characteristicProperties,
+      BluetoothRemoteGATTService*,
+      BluetoothDevice*);
 
   // Save value.
   void setValue(DOMDataView*);
 
-  // WebBluetoothRemoteGATTCharacteristic interface:
-  void dispatchCharacteristicValueChanged(const WebVector<uint8_t>&) override;
+  void dispatchCharacteristicValueChanged(const Vector<uint8_t>& value);
 
   // ContextLifecycleObserver interface.
   void contextDestroyed() override;
@@ -77,7 +83,7 @@
 
   // IDL exposed interface:
   BluetoothRemoteGATTService* service() { return m_service; }
-  String uuid() { return m_webCharacteristic->uuid; }
+  String uuid() { return m_uuid; }
   BluetoothCharacteristicProperties* properties() { return m_properties; }
   DOMDataView* value() const { return m_value; }
   ScriptPromise readValue(ScriptState*);
@@ -93,17 +99,26 @@
                           RegisteredEventListener&) override;
 
  private:
-  friend class ReadValueCallback;
-  friend class WriteValueCallback;
-  friend class NotificationsCallback;
-
   BluetoothRemoteGATTServer* gatt() { return m_service->device()->gatt(); }
 
-  std::unique_ptr<WebBluetoothRemoteGATTCharacteristicInit> m_webCharacteristic;
+  void ReadValueCallback(ScriptPromiseResolver*,
+                         mojom::blink::WebBluetoothResult,
+                         const Optional<Vector<uint8_t>>& value);
+  void WriteValueCallback(ScriptPromiseResolver*,
+                          const Vector<uint8_t>& value,
+                          mojom::blink::WebBluetoothResult);
+  void NotificationsCallback(ScriptPromiseResolver*,
+                             mojom::blink::WebBluetoothResult);
+
+  const String m_characteristicInstanceId;
+  const String m_serviceInstanceId;
+  const String m_uuid;
+  const uint32_t m_characteristicProperties;
   Member<BluetoothRemoteGATTService> m_service;
   bool m_stopped;
   Member<BluetoothCharacteristicProperties> m_properties;
   Member<DOMDataView> m_value;
+  Member<BluetoothDevice> m_device;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTServer.cpp b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTServer.cpp
index 1fbd1f6..0b5bf816 100644
--- a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTServer.cpp
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTServer.cpp
@@ -11,11 +11,10 @@
 #include "core/dom/ExceptionCode.h"
 #include "core/events/Event.h"
 #include "modules/bluetooth/Bluetooth.h"
+#include "modules/bluetooth/BluetoothDevice.h"
 #include "modules/bluetooth/BluetoothError.h"
 #include "modules/bluetooth/BluetoothRemoteGATTService.h"
-#include "modules/bluetooth/BluetoothSupplement.h"
 #include "modules/bluetooth/BluetoothUUID.h"
-#include "public/platform/modules/bluetooth/WebBluetooth.h"
 
 namespace blink {
 
@@ -25,7 +24,8 @@
     "GATT Server disconnected while retrieving services.";
 const char kGATTServerNotConnected[] =
     "GATT Server is disconnected. Cannot retrieve services.";
-}
+
+}  // namespace
 
 BluetoothRemoteGATTServer::BluetoothRemoteGATTServer(BluetoothDevice* device)
     : m_device(device), m_connected(false) {}
@@ -55,45 +55,36 @@
   visitor->trace(m_device);
 }
 
-class ConnectCallback : public WebBluetoothRemoteGATTServerConnectCallbacks {
- public:
-  ConnectCallback(BluetoothDevice* device, ScriptPromiseResolver* resolver)
-      : m_device(device), m_resolver(resolver) {}
+void BluetoothRemoteGATTServer::ConnectCallback(
+    ScriptPromiseResolver* resolver,
+    mojom::blink::WebBluetoothResult result) {
+  if (!resolver->getExecutionContext() ||
+      resolver->getExecutionContext()->isContextDestroyed())
+    return;
 
-  void onSuccess() override {
-    if (!m_resolver->getExecutionContext() ||
-        m_resolver->getExecutionContext()->isContextDestroyed())
-      return;
-    m_device->gatt()->setConnected(true);
-    m_resolver->resolve(m_device->gatt());
+  if (result == mojom::blink::WebBluetoothResult::SUCCESS) {
+    setConnected(true);
+    resolver->resolve(this);
+  } else {
+    resolver->reject(BluetoothError::take(resolver, result));
   }
-
-  void onError(
-      int32_t
-          error /* Corresponds to WebBluetoothResult in web_bluetooth.mojom */)
-      override {
-    if (!m_resolver->getExecutionContext() ||
-        m_resolver->getExecutionContext()->isContextDestroyed())
-      return;
-    m_resolver->reject(BluetoothError::take(m_resolver, error));
-  }
-
- private:
-  Persistent<BluetoothDevice> m_device;
-  Persistent<ScriptPromiseResolver> m_resolver;
-};
+}
 
 ScriptPromise BluetoothRemoteGATTServer::connect(ScriptState* scriptState) {
-  WebBluetooth* webbluetooth =
-      BluetoothSupplement::fromScriptState(scriptState);
-  if (!webbluetooth)
-    return ScriptPromise::rejectWithDOMException(
-        scriptState, DOMException::create(NotSupportedError));
+  m_device->bluetooth()->addDevice(device()->id(), device());
 
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
   ScriptPromise promise = resolver->promise();
-  webbluetooth->connect(device()->id(), device(),
-                        new ConnectCallback(device(), resolver));
+
+  mojom::blink::WebBluetoothService* service = m_device->bluetooth()->service();
+  mojom::blink::WebBluetoothDeviceIdPtr deviceId =
+      BluetoothDevice::createMojoDeviceId(device()->id());
+  service->RemoteServerConnect(
+      std::move(deviceId),
+      convertToBaseCallback(
+          WTF::bind(&BluetoothRemoteGATTServer::ConnectCallback,
+                    wrapPersistent(this), wrapPersistent(resolver))));
+
   return promise;
 }
 
@@ -101,79 +92,56 @@
   if (!m_connected)
     return;
   device()->cleanupDisconnectedDeviceAndFireEvent();
-  WebBluetooth* webbluetooth =
-      BluetoothSupplement::fromScriptState(scriptState);
-  webbluetooth->disconnect(device()->id());
+  m_device->bluetooth()->removeDevice(device()->id());
+  mojom::blink::WebBluetoothService* service = m_device->bluetooth()->service();
+  mojom::blink::WebBluetoothDeviceIdPtr deviceId =
+      BluetoothDevice::createMojoDeviceId(device()->id());
+  service->RemoteServerDisconnect(std::move(deviceId));
 }
 
-// Class that allows us to resolve the promise with a single service or
+// Callback that allows us to resolve the promise with a single service or
 // with a vector owning the services.
-class GetPrimaryServicesCallback
-    : public WebBluetoothGetPrimaryServicesCallbacks {
- public:
-  GetPrimaryServicesCallback(
-      BluetoothDevice* device,
-      mojom::blink::WebBluetoothGATTQueryQuantity quantity,
-      ScriptPromiseResolver* resolver)
-      : m_device(device), m_quantity(quantity), m_resolver(resolver) {
-    // We always check that the device is connected before constructing this
-    // object.
-    CHECK(m_device->gatt()->connected());
-    m_device->gatt()->AddToActiveAlgorithms(m_resolver.get());
+void BluetoothRemoteGATTServer::GetPrimaryServicesCallback(
+    mojom::blink::WebBluetoothGATTQueryQuantity quantity,
+    ScriptPromiseResolver* resolver,
+    mojom::blink::WebBluetoothResult result,
+    Optional<Vector<mojom::blink::WebBluetoothRemoteGATTServicePtr>> services) {
+  if (!resolver->getExecutionContext() ||
+      resolver->getExecutionContext()->isContextDestroyed())
+    return;
+
+  // If the resolver is not in the set of ActiveAlgorithms then the frame
+  // disconnected so we reject.
+  if (!RemoveFromActiveAlgorithms(resolver)) {
+    resolver->reject(
+        DOMException::create(NetworkError, kGATTServerDisconnected));
+    return;
   }
 
-  void onSuccess(
-      const WebVector<WebBluetoothRemoteGATTService*>& webServices) override {
-    if (!m_resolver->getExecutionContext() ||
-        m_resolver->getExecutionContext()->isContextDestroyed())
-      return;
+  if (result == mojom::blink::WebBluetoothResult::SUCCESS) {
+    DCHECK(services);
 
-    // If the resolver is not in the set of ActiveAlgorithms then the frame
-    // disconnected so we reject.
-    if (!m_device->gatt()->RemoveFromActiveAlgorithms(m_resolver.get())) {
-      m_resolver->reject(
-          DOMException::create(NetworkError, kGATTServerDisconnected));
+    if (quantity == mojom::blink::WebBluetoothGATTQueryQuantity::SINGLE) {
+      DCHECK_EQ(1u, services->size());
+      resolver->resolve(m_device->getOrCreateBluetoothRemoteGATTService(
+          services.value()[0]->instance_id, services.value()[0]->uuid,
+          true /* isPrimary */, device()->id()));
       return;
     }
 
-    if (m_quantity == mojom::blink::WebBluetoothGATTQueryQuantity::SINGLE) {
-      DCHECK_EQ(1u, webServices.size());
-      m_resolver->resolve(m_device->getOrCreateBluetoothRemoteGATTService(
-          WTF::wrapUnique(webServices[0])));
-      return;
-    }
+    HeapVector<Member<BluetoothRemoteGATTService>> gattServices;
+    gattServices.reserveInitialCapacity(services->size());
 
-    HeapVector<Member<BluetoothRemoteGATTService>> services;
-    services.reserveInitialCapacity(webServices.size());
-    for (WebBluetoothRemoteGATTService* webService : webServices) {
-      services.append(m_device->getOrCreateBluetoothRemoteGATTService(
-          WTF::wrapUnique(webService)));
+    for (const auto& service : services.value()) {
+      gattServices.append(m_device->getOrCreateBluetoothRemoteGATTService(
+          service->instance_id, service->uuid, true /* isPrimary */,
+          device()->id()));
     }
-    m_resolver->resolve(services);
+    resolver->resolve(gattServices);
+  } else {
+    resolver->reject(BluetoothError::take(resolver, result));
   }
-
-  void onError(
-      int32_t
-          error /* Corresponds to WebBluetoothResult in web_bluetooth.mojom */)
-      override {
-    if (!m_resolver->getExecutionContext() ||
-        m_resolver->getExecutionContext()->isContextDestroyed())
-      return;
-
-    if (!m_device->gatt()->RemoveFromActiveAlgorithms(m_resolver.get())) {
-      m_resolver->reject(
-          DOMException::create(NetworkError, kGATTServerDisconnected));
-      return;
-    }
-
-    m_resolver->reject(BluetoothError::take(m_resolver, error));
-  }
-
- private:
-  Persistent<BluetoothDevice> m_device;
-  mojom::blink::WebBluetoothGATTQueryQuantity m_quantity;
-  const Persistent<ScriptPromiseResolver> m_resolver;
-};
+}
 
 ScriptPromise BluetoothRemoteGATTServer::getPrimaryService(
     ScriptState* scriptState,
@@ -212,6 +180,7 @@
     ScriptState* scriptState,
     mojom::blink::WebBluetoothGATTQueryQuantity quantity,
     String servicesUUID) {
+  // We always check that the device is connected.
   if (!connected()) {
     return ScriptPromise::rejectWithDOMException(
         scriptState,
@@ -220,13 +189,20 @@
 
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
   ScriptPromise promise = resolver->promise();
+  AddToActiveAlgorithms(resolver);
 
-  WebBluetooth* webbluetooth =
-      BluetoothSupplement::fromScriptState(scriptState);
-  webbluetooth->getPrimaryServices(
-      device()->id(), static_cast<int32_t>(quantity), servicesUUID,
-      new GetPrimaryServicesCallback(device(), quantity, resolver));
+  mojom::blink::WebBluetoothService* service = m_device->bluetooth()->service();
+  mojom::blink::WebBluetoothDeviceIdPtr deviceId =
+      BluetoothDevice::createMojoDeviceId(device()->id());
+  WTF::Optional<String> uuid = WTF::nullopt;
+  if (!servicesUUID.isEmpty())
+    uuid = servicesUUID;
 
+  service->RemoteServerGetPrimaryServices(
+      std::move(deviceId), quantity, uuid,
+      convertToBaseCallback(
+          WTF::bind(&BluetoothRemoteGATTServer::GetPrimaryServicesCallback,
+                    wrapPersistent(this), quantity, wrapPersistent(resolver))));
   return promise;
 }
 
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTServer.h b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTServer.h
index d15e116b..1e33026c 100644
--- a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTServer.h
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTServer.h
@@ -9,7 +9,7 @@
 #include "bindings/modules/v8/StringOrUnsignedLong.h"
 #include "modules/bluetooth/BluetoothDevice.h"
 #include "platform/heap/Heap.h"
-#include "third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom-blink.h"
+#include "public/platform/modules/bluetooth/web_bluetooth.mojom-blink.h"
 #include "wtf/text/WTFString.h"
 
 namespace blink {
@@ -69,6 +69,15 @@
       mojom::blink::WebBluetoothGATTQueryQuantity,
       String serviceUUID = String());
 
+  void ConnectCallback(ScriptPromiseResolver*,
+                       mojom::blink::WebBluetoothResult);
+  void GetPrimaryServicesCallback(
+      mojom::blink::WebBluetoothGATTQueryQuantity,
+      ScriptPromiseResolver*,
+      mojom::blink::WebBluetoothResult,
+      Optional<Vector<mojom::blink::WebBluetoothRemoteGATTServicePtr>>
+          services);
+
   // Contains a ScriptPromiseResolver corresponding to each active algorithm
   // using this server’s connection.
   HeapHashSet<Member<ScriptPromiseResolver>> m_activeAlgorithms;
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTService.cpp b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTService.cpp
index 84d915f..729c1a6 100644
--- a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTService.cpp
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTService.cpp
@@ -9,11 +9,10 @@
 #include "core/dom/DOMException.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/inspector/ConsoleMessage.h"
+#include "modules/bluetooth/Bluetooth.h"
 #include "modules/bluetooth/BluetoothError.h"
 #include "modules/bluetooth/BluetoothRemoteGATTCharacteristic.h"
-#include "modules/bluetooth/BluetoothSupplement.h"
 #include "modules/bluetooth/BluetoothUUID.h"
-#include "public/platform/modules/bluetooth/WebBluetooth.h"
 #include "wtf/PtrUtil.h"
 #include <memory>
 #include <utility>
@@ -33,93 +32,69 @@
 }  // namespace
 
 BluetoothRemoteGATTService::BluetoothRemoteGATTService(
-    std::unique_ptr<WebBluetoothRemoteGATTService> webService,
+    const String& serviceInstanceId,
+    const String& uuid,
+    bool isPrimary,
+    const String& deviceInstanceId,
     BluetoothDevice* device)
-    : m_webService(std::move(webService)), m_device(device) {
-  DCHECK(m_webService);
-}
+    : m_serviceInstanceId(serviceInstanceId),
+      m_uuid(uuid),
+      m_isPrimary(isPrimary),
+      m_deviceInstanceId(deviceInstanceId),
+      m_device(device) {}
 
 DEFINE_TRACE(BluetoothRemoteGATTService) {
   visitor->trace(m_device);
 }
 
-// Class that allows us to resolve the promise with a single Characteristic or
-// with a vector owning the characteristics.
-class GetCharacteristicsCallback
-    : public WebBluetoothGetCharacteristicsCallbacks {
- public:
-  GetCharacteristicsCallback(
-      BluetoothRemoteGATTService* service,
-      mojom::blink::WebBluetoothGATTQueryQuantity quantity,
-      ScriptPromiseResolver* resolver)
-      : m_service(service), m_quantity(quantity), m_resolver(resolver) {
-    // We always check that the device is connected before constructing this
-    // object.
-    CHECK(m_service->device()->gatt()->connected());
-    m_service->device()->gatt()->AddToActiveAlgorithms(m_resolver.get());
+// Callback that allows us to resolve the promise with a single Characteristic
+// or with a vector owning the characteristics.
+void BluetoothRemoteGATTService::GetCharacteristicsCallback(
+    const String& serviceInstanceId,
+    mojom::blink::WebBluetoothGATTQueryQuantity quantity,
+    ScriptPromiseResolver* resolver,
+    mojom::blink::WebBluetoothResult result,
+    Optional<Vector<mojom::blink::WebBluetoothRemoteGATTCharacteristicPtr>>
+        characteristics) {
+  if (!resolver->getExecutionContext() ||
+      resolver->getExecutionContext()->isContextDestroyed())
+    return;
+
+  // If the resolver is not in the set of ActiveAlgorithms then the frame
+  // disconnected so we reject.
+  if (!device()->gatt()->RemoveFromActiveAlgorithms(resolver)) {
+    resolver->reject(
+        DOMException::create(NetworkError, kGATTServerDisconnected));
+    return;
   }
 
-  void onSuccess(const WebVector<WebBluetoothRemoteGATTCharacteristicInit*>&
-                     webCharacteristics) override {
-    if (!m_resolver->getExecutionContext() ||
-        m_resolver->getExecutionContext()->isContextDestroyed())
-      return;
+  if (result == mojom::blink::WebBluetoothResult::SUCCESS) {
+    DCHECK(characteristics);
 
-    // If the resolver is not in the set of ActiveAlgorithms then the frame
-    // disconnected so we reject.
-    if (!m_service->device()->gatt()->RemoveFromActiveAlgorithms(
-            m_resolver.get())) {
-      m_resolver->reject(
-          DOMException::create(NetworkError, kGATTServerDisconnected));
+    if (quantity == mojom::blink::WebBluetoothGATTQueryQuantity::SINGLE) {
+      DCHECK_EQ(1u, characteristics->size());
+      resolver->resolve(device()->getOrCreateBluetoothRemoteGATTCharacteristic(
+          resolver->getExecutionContext(),
+          characteristics.value()[0]->instance_id, serviceInstanceId,
+          characteristics.value()[0]->uuid,
+          characteristics.value()[0]->properties, this));
       return;
     }
 
-    if (m_quantity == mojom::blink::WebBluetoothGATTQueryQuantity::SINGLE) {
-      DCHECK_EQ(1u, webCharacteristics.size());
-      m_resolver->resolve(
-          m_service->device()->getOrCreateBluetoothRemoteGATTCharacteristic(
-              m_resolver->getExecutionContext(),
-              WTF::wrapUnique(webCharacteristics[0]), m_service));
-      return;
+    HeapVector<Member<BluetoothRemoteGATTCharacteristic>> gattCharacteristics;
+    gattCharacteristics.reserveInitialCapacity(characteristics->size());
+    for (const auto& characteristic : characteristics.value()) {
+      gattCharacteristics.append(
+          device()->getOrCreateBluetoothRemoteGATTCharacteristic(
+              resolver->getExecutionContext(), characteristic->instance_id,
+              serviceInstanceId, characteristic->uuid,
+              characteristic->properties, this));
     }
-
-    HeapVector<Member<BluetoothRemoteGATTCharacteristic>> characteristics;
-    characteristics.reserveInitialCapacity(webCharacteristics.size());
-    for (WebBluetoothRemoteGATTCharacteristicInit* webCharacteristic :
-         webCharacteristics) {
-      characteristics.append(
-          m_service->device()->getOrCreateBluetoothRemoteGATTCharacteristic(
-              m_resolver->getExecutionContext(),
-              WTF::wrapUnique(webCharacteristic), m_service));
-    }
-    m_resolver->resolve(characteristics);
+    resolver->resolve(gattCharacteristics);
+  } else {
+    resolver->reject(BluetoothError::take(resolver, result));
   }
-
-  void onError(
-      int32_t
-          error /* Corresponds to WebBluetoothResult in web_bluetooth.mojom */)
-      override {
-    if (!m_resolver->getExecutionContext() ||
-        m_resolver->getExecutionContext()->isContextDestroyed())
-      return;
-
-    // If the resolver is not in the set of ActiveAlgorithms then the frame
-    // disconnected so we reject.
-    if (!m_service->device()->gatt()->RemoveFromActiveAlgorithms(
-            m_resolver.get())) {
-      m_resolver->reject(
-          DOMException::create(NetworkError, kGATTServerDisconnected));
-      return;
-    }
-
-    m_resolver->reject(BluetoothError::take(m_resolver, error));
-  }
-
- private:
-  Persistent<BluetoothRemoteGATTService> m_service;
-  mojom::blink::WebBluetoothGATTQueryQuantity m_quantity;
-  const Persistent<ScriptPromiseResolver> m_resolver;
-};
+}
 
 ScriptPromise BluetoothRemoteGATTService::getCharacteristic(
     ScriptState* scriptState,
@@ -159,27 +134,34 @@
 ScriptPromise BluetoothRemoteGATTService::getCharacteristicsImpl(
     ScriptState* scriptState,
     mojom::blink::WebBluetoothGATTQueryQuantity quantity,
-    String characteristicsUUID) {
+    const String& characteristicsUUID) {
+  // We always check that the device is connected.
   if (!device()->gatt()->connected()) {
     return ScriptPromise::rejectWithDOMException(
         scriptState,
         DOMException::create(NetworkError, kGATTServerNotConnected));
   }
 
-  if (!device()->isValidService(m_webService->serviceInstanceID)) {
+  if (!device()->isValidService(m_serviceInstanceId)) {
     return ScriptPromise::rejectWithDOMException(
         scriptState, DOMException::create(InvalidStateError, kInvalidService));
   }
 
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
   ScriptPromise promise = resolver->promise();
+  device()->gatt()->AddToActiveAlgorithms(resolver);
 
-  WebBluetooth* webbluetooth =
-      BluetoothSupplement::fromScriptState(scriptState);
-  webbluetooth->getCharacteristics(
-      m_webService->serviceInstanceID, static_cast<int32_t>(quantity),
-      characteristicsUUID,
-      new GetCharacteristicsCallback(this, quantity, resolver));
+  mojom::blink::WebBluetoothService* service = m_device->bluetooth()->service();
+
+  WTF::Optional<String> uuid = WTF::nullopt;
+  if (!characteristicsUUID.isEmpty())
+    uuid = characteristicsUUID;
+  service->RemoteServiceGetCharacteristics(
+      m_serviceInstanceId, quantity, uuid,
+      convertToBaseCallback(
+          WTF::bind(&BluetoothRemoteGATTService::GetCharacteristicsCallback,
+                    wrapPersistent(this), m_serviceInstanceId, quantity,
+                    wrapPersistent(resolver))));
 
   return promise;
 }
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTService.h b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTService.h
index b74bbbcf..1c59fc8 100644
--- a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTService.h
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTService.h
@@ -10,7 +10,6 @@
 #include "modules/bluetooth/BluetoothDevice.h"
 #include "platform/heap/Handle.h"
 #include "platform/heap/Heap.h"
-#include "public/platform/modules/bluetooth/WebBluetoothRemoteGATTService.h"
 #include "public/platform/modules/bluetooth/web_bluetooth.mojom-blink.h"
 #include "wtf/text/WTFString.h"
 #include <memory>
@@ -34,16 +33,18 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  explicit BluetoothRemoteGATTService(
-      std::unique_ptr<WebBluetoothRemoteGATTService>,
-      BluetoothDevice*);
+  BluetoothRemoteGATTService(const String& serviceInstanceId,
+                             const String& uuid,
+                             bool isPrimary,
+                             const String& deviceInstanceId,
+                             BluetoothDevice*);
 
   // Interface required by garbage collection.
   DECLARE_VIRTUAL_TRACE();
 
   // IDL exposed interface:
-  String uuid() { return m_webService->uuid; }
-  bool isPrimary() { return m_webService->isPrimary; }
+  String uuid() { return m_uuid; }
+  bool isPrimary() { return m_isPrimary; }
   BluetoothDevice* device() { return m_device; }
   ScriptPromise getCharacteristic(ScriptState*,
                                   const StringOrUnsignedLong& characteristic,
@@ -54,12 +55,23 @@
   ScriptPromise getCharacteristics(ScriptState*, ExceptionState&);
 
  private:
+  void GetCharacteristicsCallback(
+      const String& serviceInstanceId,
+      mojom::blink::WebBluetoothGATTQueryQuantity,
+      ScriptPromiseResolver*,
+      mojom::blink::WebBluetoothResult,
+      Optional<Vector<mojom::blink::WebBluetoothRemoteGATTCharacteristicPtr>>
+          services);
+
   ScriptPromise getCharacteristicsImpl(
       ScriptState*,
       mojom::blink::WebBluetoothGATTQueryQuantity,
-      String characteristicUUID = String());
+      const String& characteristicUUID = String());
 
-  std::unique_ptr<WebBluetoothRemoteGATTService> m_webService;
+  const String m_serviceInstanceId;
+  const String m_uuid;
+  const bool m_isPrimary;
+  const String m_deviceInstanceId;
   Member<BluetoothDevice> m_device;
 };
 
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothSupplement.cpp b/third_party/WebKit/Source/modules/bluetooth/BluetoothSupplement.cpp
deleted file mode 100644
index 699f9a6..0000000
--- a/third_party/WebKit/Source/modules/bluetooth/BluetoothSupplement.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "modules/bluetooth/BluetoothSupplement.h"
-
-#include "core/dom/Document.h"
-
-namespace blink {
-
-const char* BluetoothSupplement::supplementName() {
-  return "BluetoothSupplement";
-}
-
-BluetoothSupplement::BluetoothSupplement(WebBluetooth* bluetooth)
-    : m_bluetooth(bluetooth) {}
-
-void BluetoothSupplement::provideTo(LocalFrame& frame,
-                                    WebBluetooth* bluetooth) {
-  BluetoothSupplement* bluetoothSupplement = new BluetoothSupplement(bluetooth);
-  Supplement<LocalFrame>::provideTo(frame, supplementName(),
-                                    bluetoothSupplement);
-};
-
-WebBluetooth* BluetoothSupplement::from(LocalFrame* frame) {
-  BluetoothSupplement* supplement = static_cast<BluetoothSupplement*>(
-      Supplement<LocalFrame>::from(frame, supplementName()));
-
-  ASSERT(supplement);
-  ASSERT(supplement->m_bluetooth);
-
-  return supplement->m_bluetooth;
-}
-
-WebBluetooth* BluetoothSupplement::fromScriptState(ScriptState* scriptState) {
-  return fromExecutionContext(scriptState->getExecutionContext());
-}
-
-WebBluetooth* BluetoothSupplement::fromExecutionContext(
-    ExecutionContext* executionContext) {
-  if (!executionContext->isDocument()) {
-    return nullptr;
-  }
-  return BluetoothSupplement::from(
-      static_cast<Document*>(executionContext)->frame());
-}
-
-DEFINE_TRACE(BluetoothSupplement) {
-  Supplement<LocalFrame>::trace(visitor);
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothSupplement.h b/third_party/WebKit/Source/modules/bluetooth/BluetoothSupplement.h
deleted file mode 100644
index 7b350587..0000000
--- a/third_party/WebKit/Source/modules/bluetooth/BluetoothSupplement.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BluetoothSupplement_h
-#define BluetoothSupplement_h
-
-#include "core/frame/LocalFrame.h"
-
-namespace blink {
-
-class WebBluetooth;
-
-// This class is attached to a LocalFrame in WebLocalFrameImpl::setCoreFrame, to
-// pass WebFrameClient::bluetooth() (accessible by web/ only) to the Bluetooth
-// code in modules/.
-class BLINK_EXPORT BluetoothSupplement
-    : public GarbageCollected<BluetoothSupplement>,
-      public Supplement<LocalFrame> {
-  WTF_MAKE_NONCOPYABLE(BluetoothSupplement);
-  USING_GARBAGE_COLLECTED_MIXIN(BluetoothSupplement);
-
- public:
-  static const char* supplementName();
-
-  static void provideTo(LocalFrame&, WebBluetooth*);
-
-  // Returns the WebBluetooth attached to the frame.
-  static WebBluetooth* from(LocalFrame*);
-
-  // Returns the WebBluetooth attached to the frame if the frame exists.
-  // Otherwise returns nullptr.
-  static WebBluetooth* fromScriptState(ScriptState*);
-  // Returns the WebBluetooth attached to the execution context.
-  static WebBluetooth* fromExecutionContext(ExecutionContext*);
-
-  DECLARE_VIRTUAL_TRACE();
-
- private:
-  explicit BluetoothSupplement(WebBluetooth*);
-
-  WebBluetooth* m_bluetooth;
-};
-
-}  // namespace blink
-
-#endif  // BluetoothRoutingId_h
diff --git a/third_party/WebKit/Source/modules/bluetooth/DEPS b/third_party/WebKit/Source/modules/bluetooth/DEPS
index 01d61a47..5c219f52 100644
--- a/third_party/WebKit/Source/modules/bluetooth/DEPS
+++ b/third_party/WebKit/Source/modules/bluetooth/DEPS
@@ -1,8 +1,10 @@
 include_rules = [
     "+bindings",
     "+core",
+    "+device/bluetooth/public/interfaces",
     "-modules",
     "+modules/bluetooth",
     "+modules/EventTargetModules.h",
+    "+mojo/public/cpp/bindings",
     "-web",
 ]
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn
index d4cab47..6935bf30 100644
--- a/third_party/WebKit/Source/platform/BUILD.gn
+++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -1128,6 +1128,7 @@
     "mhtml/MHTMLArchive.h",
     "mhtml/MHTMLParser.cpp",
     "mhtml/MHTMLParser.h",
+    "mojo/BluetoothStructTraits.cpp",
     "mojo/CommonCustomTypesStructTraits.cpp",
     "mojo/GeometryStructTraits.cpp",
     "mojo/MojoHelper.h",
diff --git a/third_party/WebKit/Source/platform/mojo/Bluetooth.typemap b/third_party/WebKit/Source/platform/mojo/Bluetooth.typemap
new file mode 100644
index 0000000..c657a6b
--- /dev/null
+++ b/third_party/WebKit/Source/platform/mojo/Bluetooth.typemap
@@ -0,0 +1,12 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mojom = "//device/bluetooth/public/interfaces/uuid.mojom"
+public_headers = [ "//third_party/WebKit/Source/wtf/text/WTFString.h" ]
+traits_headers =
+    [ "//third_party/WebKit/Source/platform/mojo/BluetoothStructTraits.h" ]
+deps = [
+  "//device/bluetooth",
+]
+type_mappings = [ "bluetooth.mojom.UUID=WTF::String" ]
diff --git a/third_party/WebKit/Source/platform/mojo/BluetoothStructTraits.cpp b/third_party/WebKit/Source/platform/mojo/BluetoothStructTraits.cpp
new file mode 100644
index 0000000..636be5a
--- /dev/null
+++ b/third_party/WebKit/Source/platform/mojo/BluetoothStructTraits.cpp
@@ -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.
+
+#include "platform/mojo/BluetoothStructTraits.h"
+
+#include "mojo/public/cpp/bindings/string_traits_wtf.h"
+
+namespace mojo {
+
+// static
+bool StructTraits<bluetooth::mojom::UUIDDataView, WTF::String>::Read(
+    bluetooth::mojom::UUIDDataView data,
+    WTF::String* output) {
+  return data.ReadUuid(output);
+}
+
+}  // namespace mojo
diff --git a/third_party/WebKit/Source/platform/mojo/BluetoothStructTraits.h b/third_party/WebKit/Source/platform/mojo/BluetoothStructTraits.h
new file mode 100644
index 0000000..905fcd5
--- /dev/null
+++ b/third_party/WebKit/Source/platform/mojo/BluetoothStructTraits.h
@@ -0,0 +1,22 @@
+// 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 BluetoothStructTraits_h
+#define BluetoothStructTraits_h
+
+#include "device/bluetooth/public/interfaces/uuid.mojom-blink.h"
+#include "wtf/text/WTFString.h"
+
+namespace mojo {
+
+template <>
+struct StructTraits<bluetooth::mojom::UUIDDataView, WTF::String> {
+  static const WTF::String& uuid(const WTF::String& input) { return input; }
+
+  static bool Read(bluetooth::mojom::UUIDDataView, WTF::String* output);
+};
+
+}  // namespace mojo
+
+#endif  // BluetoothStructTraits_h
diff --git a/third_party/WebKit/Source/platform/mojo/blink_typemaps.gni b/third_party/WebKit/Source/platform/mojo/blink_typemaps.gni
index af47d17..bbad913d 100644
--- a/third_party/WebKit/Source/platform/mojo/blink_typemaps.gni
+++ b/third_party/WebKit/Source/platform/mojo/blink_typemaps.gni
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 typemaps = [
+  "//third_party/WebKit/Source/platform/mojo/Bluetooth.typemap",
   "//third_party/WebKit/Source/platform/mojo/File.typemap",
   "//third_party/WebKit/Source/platform/mojo/Geometry.typemap",
   "//third_party/WebKit/Source/platform/mojo/KURL.typemap",
diff --git a/third_party/WebKit/Source/web/ChromeClientImpl.cpp b/third_party/WebKit/Source/web/ChromeClientImpl.cpp
index 2bb92168..809b39de 100644
--- a/third_party/WebKit/Source/web/ChromeClientImpl.cpp
+++ b/third_party/WebKit/Source/web/ChromeClientImpl.cpp
@@ -55,7 +55,6 @@
 #include "core/page/PopupOpeningObserver.h"
 #include "modules/accessibility/AXObject.h"
 #include "modules/audio_output_devices/AudioOutputDeviceClient.h"
-#include "modules/bluetooth/BluetoothSupplement.h"
 #include "modules/installedapp/InstalledAppController.h"
 #include "modules/mediastream/UserMediaController.h"
 #include "modules/presentation/PresentationController.h"
@@ -1148,9 +1147,6 @@
   provideNavigatorContentUtilsTo(
       frame, NavigatorContentUtilsClientImpl::create(webFrame));
 
-  if (RuntimeEnabledFeatures::webBluetoothEnabled())
-    BluetoothSupplement::provideTo(frame, client->bluetooth());
-
   ScreenOrientationControllerImpl::provideTo(
       frame, client->webScreenOrientationClient());
   if (RuntimeEnabledFeatures::presentationEnabled())
diff --git a/third_party/WebKit/Source/web/tests/ActivityLoggerTest.cpp b/third_party/WebKit/Source/web/tests/ActivityLoggerTest.cpp
index 4ee3247..e74dd129 100644
--- a/third_party/WebKit/Source/web/tests/ActivityLoggerTest.cpp
+++ b/third_party/WebKit/Source/web/tests/ActivityLoggerTest.cpp
@@ -580,12 +580,12 @@
   const char* expectedActivities =
       "blinkAddElement | iframe | data:text/html;charset=utf-8,A\n"
       "blinkRequestResource | Main resource | data:text/html;charset=utf-8,A\n"
-      "blinkRequestResource | Image | data:text/html;charset=utf-8,B\n"
       "blinkAddElement | link | stylesheet | data:text/html;charset=utf-8,C\n"
       "blinkRequestResource | CSS stylesheet | data:text/html;charset=utf-8,C\n"
       "blinkAddElement | script | data:text/html;charset=utf-8,D\n"
       "blinkRequestResource | Script | data:text/html;charset=utf-8,D\n"
-      "blinkRequestResource | XMLHttpRequest | data:text/html;charset=utf-8,E";
+      "blinkRequestResource | XMLHttpRequest | data:text/html;charset=utf-8,E\n"
+      "blinkRequestResource | Image | data:text/html;charset=utf-8,B\n";
   executeScriptInMainWorld(code);
   ASSERT_TRUE(verifyActivities(""));
   executeScriptInIsolatedWorld(code);
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl_unittest.py
index bf076f3..18c34af 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl_unittest.py
@@ -5,7 +5,7 @@
 import unittest
 
 from webkitpy.common.net.git_cl import GitCL
-from webkitpy.common.system.executive_mock import MockExecutive2
+from webkitpy.common.system.executive_mock import MockExecutive
 from webkitpy.common.host_mock import MockHost
 
 
@@ -13,7 +13,7 @@
 
     def test_run(self):
         host = MockHost()
-        host.executive = MockExecutive2(output='mock-output')
+        host.executive = MockExecutive(output='mock-output')
         git_cl = GitCL(host)
         output = git_cl.run(['command'])
         self.assertEqual(output, 'mock-output')
@@ -21,7 +21,7 @@
 
     def test_run_with_auth(self):
         host = MockHost()
-        host.executive = MockExecutive2(output='mock-output')
+        host.executive = MockExecutive(output='mock-output')
         git_cl = GitCL(host, auth_refresh_token_json='token.json')
         git_cl.run(['upload'])
         self.assertEqual(
@@ -30,20 +30,20 @@
 
     def test_some_commands_not_run_with_auth(self):
         host = MockHost()
-        host.executive = MockExecutive2(output='mock-output')
+        host.executive = MockExecutive(output='mock-output')
         git_cl = GitCL(host, auth_refresh_token_json='token.json')
         git_cl.run(['issue'])
         self.assertEqual(host.executive.calls, [['git', 'cl', 'issue']])
 
     def test_get_issue_number(self):
         host = MockHost()
-        host.executive = MockExecutive2(output='Issue number: 12345 (http://crrev.com/12345)')
+        host.executive = MockExecutive(output='Issue number: 12345 (http://crrev.com/12345)')
         git_cl = GitCL(host)
         self.assertEqual(git_cl.get_issue_number(), '12345')
 
     def test_get_issue_number_none(self):
         host = MockHost()
-        host.executive = MockExecutive2(output='Issue number: None (None)')
+        host.executive = MockExecutive(output='Issue number: None (None)')
         git_cl = GitCL(host)
         self.assertEqual(git_cl.get_issue_number(), 'None')
 
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/layout_test_results_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/layout_test_results_unittest.py
index f0ad5c076..d8f9daa 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/layout_test_results_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/layout_test_results_unittest.py
@@ -130,3 +130,29 @@
                 'fast/dom/prototype-taco.html',
                 'svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr.html',
             ])
+
+    def test_didnt_run_as_expected_slow_test(self):
+        results = LayoutTestResults({
+            "tests": {
+                "fast": {
+                    "dom": {
+                        "prototype-fast.html": {
+                            "expected": "PASS",
+                            "actual": "TEXT",
+                            "is_unexpected": True,
+                        },
+                        "prototype-slow.html": {
+                            "expected": "SLOW",
+                            "actual": "TEXT",
+                            "is_unexpected": True,
+                        }
+                    }
+                }
+            }
+        })
+        self.assertEqual(
+            [r.test_name() for r in results.didnt_run_as_expected_results()],
+            [
+                'fast/dom/prototype-fast.html',
+                'fast/dom/prototype-slow.html',
+            ])
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/system/executive_mock.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/system/executive_mock.py
index 0678254aeb..bf5d045 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/system/executive_mock.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/system/executive_mock.py
@@ -26,9 +26,9 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-import StringIO
 import logging
 import os
+import StringIO
 
 from webkitpy.common.system.executive import ScriptError
 
@@ -57,7 +57,6 @@
         return (self.stdout.getvalue(), self.stderr.getvalue())
 
 
-# FIXME: This should be unified with MockExecutive2 (http://crbug.com/626115).
 class MockExecutive(object):
     PIPE = "MOCK PIPE"
     STDOUT = "MOCK STDOUT"
@@ -191,41 +190,3 @@
 
     def process_dump(self):
         return []
-
-
-class MockExecutive2(MockExecutive):
-    """MockExecutive2 is like MockExecutive except it doesn't log anything."""
-
-    def __init__(self, output='', exit_code=0, exception=None, run_command_fn=None, stderr=''):
-        super(MockExecutive2, self).__init__()
-        self._output = output
-        self._stderr = stderr
-        self._exit_code = exit_code
-        self._exception = exception
-        self._run_command_fn = run_command_fn
-
-    def run_command(self,
-                    args,
-                    cwd=None,
-                    input=None,
-                    error_handler=None,
-                    return_exit_code=False,
-                    return_stderr=True,
-                    decode_output=False,
-                    env=None,
-                    debug_logging=False):
-        self.calls.append(args)
-        assert isinstance(args, list) or isinstance(args, tuple)
-        assert all(isinstance(arg, basestring) for arg in args)
-        if self._exception:
-            raise self._exception  # pylint: disable=raising-bad-type
-        if self._run_command_fn:
-            return self._run_command_fn(args)
-        if return_exit_code:
-            return self._exit_code
-        if self._exit_code and error_handler:
-            script_error = ScriptError(script_args=args, exit_code=self._exit_code, output=self._output)
-            error_handler(script_error)
-        if return_stderr:
-            return self._output + self._stderr
-        return self._output
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/system/platform_info_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/system/platform_info_unittest.py
index a6f6fb99..eda5bc7 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/system/platform_info_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/system/platform_info_unittest.py
@@ -31,7 +31,7 @@
 import unittest
 
 from webkitpy.common.system.executive import Executive
-from webkitpy.common.system.executive_mock import MockExecutive2
+from webkitpy.common.system.executive_mock import MockExecutive
 from webkitpy.common.system.filesystem import FileSystem
 from webkitpy.common.system.filesystem_mock import MockFileSystem
 from webkitpy.common.system.platform_info import PlatformInfo
@@ -68,8 +68,8 @@
 
 def fake_executive(output=None):
     if output:
-        return MockExecutive2(output=output)
-    return MockExecutive2(exception=SystemError)
+        return MockExecutive(output=output)
+    return MockExecutive(exception=SystemError)
 
 
 class TestPlatformInfo(unittest.TestCase):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android_unittest.py
index 96d89904..1a5d69aa 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android_unittest.py
@@ -34,7 +34,7 @@
 import time
 import unittest
 
-from webkitpy.common.system.executive_mock import MockExecutive2
+from webkitpy.common.system.executive_mock import MockExecutive
 from webkitpy.common.system.system_host_mock import MockSystemHost
 from webkitpy.layout_tests.port import android
 from webkitpy.layout_tests.port import driver_unittest
@@ -146,7 +146,7 @@
             return_value={'level': 100})
         self._mock_battery.start()
 
-        self._port = android.AndroidPort(MockSystemHost(executive=MockExecutive2()), 'android')
+        self._port = android.AndroidPort(MockSystemHost(executive=MockExecutive()), 'android')
         self._driver = android.ChromiumAndroidDriver(
             self._port,
             worker_number=0,
@@ -191,7 +191,7 @@
         self._mock_devices.stop()
 
     def test_two_drivers(self):
-        port = android.AndroidPort(MockSystemHost(executive=MockExecutive2()), 'android')
+        port = android.AndroidPort(MockSystemHost(executive=MockExecutive()), 'android')
         driver0 = android.ChromiumAndroidDriver(port, worker_number=0, pixel_tests=True,
                                                 driver_details=android.ContentShellDriverDetails(), android_devices=port._devices)
         driver1 = android.ChromiumAndroidDriver(port, worker_number=1, pixel_tests=True,
@@ -220,10 +220,10 @@
 
     def test_options_with_two_ports(self):
         port0 = android.AndroidPort(
-            MockSystemHost(executive=MockExecutive2()), 'android',
+            MockSystemHost(executive=MockExecutive()), 'android',
             options=optparse.Values({'additional_driver_flag': ['--foo=bar']}))
         port1 = android.AndroidPort(
-            MockSystemHost(executive=MockExecutive2()), 'android',
+            MockSystemHost(executive=MockExecutive()), 'android',
             options=optparse.Values({'driver_name': 'content_shell'}))
 
         self.assertEqual(1, port0.driver_cmd_line().count('--foo=bar'))
@@ -244,7 +244,7 @@
             return_value={'level': 100})
         self._mock_battery.start()
 
-        self._port = android.AndroidPort(MockSystemHost(executive=MockExecutive2()), 'android')
+        self._port = android.AndroidPort(MockSystemHost(executive=MockExecutive()), 'android')
         self._driver = android.ChromiumAndroidDriver(
             self._port,
             worker_number=0,
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py
index 9dcb679..0ca0e36 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py
@@ -32,17 +32,15 @@
 import tempfile
 import unittest
 
-from webkitpy.common.system.executive import ScriptError
 from webkitpy.common.system import executive_mock
-from webkitpy.common.system.filesystem_mock import MockFileSystem
-from webkitpy.common.system.platform_info_mock import MockPlatformInfo
+from webkitpy.common.system.executive import ScriptError
+from webkitpy.common.system.executive_mock import MockExecutive
 from webkitpy.common.system.output_capture import OutputCapture
-from webkitpy.common.system.executive_mock import MockExecutive2
+from webkitpy.common.system.platform_info_mock import MockPlatformInfo
 from webkitpy.common.system.system_host import SystemHost
 from webkitpy.common.system.system_host_mock import MockSystemHost
-
-from webkitpy.layout_tests.port.base import Port, VirtualTestSuite
 from webkitpy.layout_tests.models.test_expectations import TestExpectations
+from webkitpy.layout_tests.port.base import Port, VirtualTestSuite
 from webkitpy.layout_tests.port.test import add_unit_tests_to_mock_filesystem, LAYOUT_TEST_DIR, TestPort
 
 
@@ -86,7 +84,7 @@
         return new_file
 
     def test_pretty_patch_os_error(self):
-        port = self.make_port(executive=executive_mock.MockExecutive2(exception=OSError))
+        port = self.make_port(executive=executive_mock.MockExecutive(exception=OSError))
         oc = OutputCapture()
         oc.capture_output()
         self.assertEqual(port.pretty_patch_text("patch.txt"),
@@ -99,7 +97,7 @@
 
     def test_pretty_patch_script_error(self):
         # FIXME: This is some ugly white-box test hacking ...
-        port = self.make_port(executive=executive_mock.MockExecutive2(exception=ScriptError))
+        port = self.make_port(executive=executive_mock.MockExecutive(exception=ScriptError))
         port._pretty_patch_available = True
         self.assertEqual(port.pretty_patch_text("patch.txt"),
                          port._pretty_patch_error_html)
@@ -429,7 +427,7 @@
         self.assertFalse(port.http_server_supports_ipv6())
 
     def test_check_httpd_success(self):
-        port = self.make_port(executive=MockExecutive2())
+        port = self.make_port(executive=MockExecutive())
         port.path_to_apache = lambda: '/usr/sbin/httpd'
         capture = OutputCapture()
         capture.capture_output()
@@ -438,7 +436,7 @@
         self.assertEqual('', logs)
 
     def test_httpd_returns_error_code(self):
-        port = self.make_port(executive=MockExecutive2(exit_code=1))
+        port = self.make_port(executive=MockExecutive(exit_code=1))
         port.path_to_apache = lambda: '/usr/sbin/httpd'
         capture = OutputCapture()
         capture.capture_output()
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/browser_test_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/browser_test_unittest.py
index 0d331ef..d005b84 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/browser_test_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/browser_test_unittest.py
@@ -28,7 +28,7 @@
 
 import optparse
 
-from webkitpy.common.system.executive_mock import MockExecutive2
+from webkitpy.common.system.executive_mock import MockExecutive
 from webkitpy.layout_tests.models import test_run_results
 from webkitpy.layout_tests.port import browser_test
 from webkitpy.layout_tests.port import browser_test_driver
@@ -39,7 +39,7 @@
 
     def test_check_sys_deps(self):
         port = self.make_port()
-        port._executive = MockExecutive2(exit_code=0)
+        port._executive = MockExecutive(exit_code=0)  # pylint: disable=protected-access
         self.assertEqual(port.check_sys_deps(needs_http=False), test_run_results.OK_EXIT_STATUS)
 
     def test_driver_name_option(self):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/linux_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/linux_unittest.py
index 27af7b5..fe363f7 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/linux_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/linux_unittest.py
@@ -28,7 +28,7 @@
 
 import optparse
 
-from webkitpy.common.system import executive_mock
+from webkitpy.common.system.executive_mock import MockExecutive
 from webkitpy.common.system.system_host_mock import MockSystemHost
 from webkitpy.layout_tests.port import linux
 from webkitpy.layout_tests.port import port_testcase
@@ -47,7 +47,7 @@
         host = MockSystemHost(os_name=self.os_name, os_version=(os_version or self.os_version))
         host.filesystem.isfile = lambda x: 'content_shell' in x
         if driver_file_output:
-            host.executive = executive_mock.MockExecutive2(driver_file_output)
+            host.executive = MockExecutive(driver_file_output)
         port = self.make_port(host=host, port_name=port_name, os_version=os_version)
         self.assertEqual(port.name(), expected_name)
         self.assertEqual(port.version(), expected_version)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py
index 3ec9665..9f1d5b0 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py
@@ -34,7 +34,7 @@
 import socket
 import unittest
 
-from webkitpy.common.system.executive_mock import MockExecutive, MockExecutive2
+from webkitpy.common.system.executive_mock import MockExecutive
 from webkitpy.common.system.output_capture import OutputCapture
 from webkitpy.common.system.system_host import SystemHost
 from webkitpy.common.system.system_host_mock import MockSystemHost
@@ -179,6 +179,7 @@
         self.assertEqual(port.diff_image('foo', ''), ('foo', None))
 
     def test_diff_image(self):
+
         def _path_to_image_diff():
             return "/path/to/image_diff"
 
@@ -192,15 +193,15 @@
             return 1
 
         # Images are different.
-        port._executive = MockExecutive2(run_command_fn=mock_run_command)
+        port._executive = MockExecutive(run_command_fn=mock_run_command)  # pylint: disable=protected-access
         self.assertEqual(mock_image_diff, port.diff_image("EXPECTED", "ACTUAL")[0])
 
         # Images are the same.
-        port._executive = MockExecutive2(exit_code=0)
+        port._executive = MockExecutive(exit_code=0)  # pylint: disable=protected-access
         self.assertEqual(None, port.diff_image("EXPECTED", "ACTUAL")[0])
 
         # There was some error running image_diff.
-        port._executive = MockExecutive2(exit_code=2)
+        port._executive = MockExecutive(exit_code=2)  # pylint: disable=protected-access
         exception_raised = False
         try:
             port.diff_image("EXPECTED", "ACTUAL")
@@ -210,7 +211,7 @@
 
     def test_diff_image_crashed(self):
         port = self.make_port()
-        port._executive = MockExecutive2(exit_code=2)
+        port._executive = MockExecutive(exit_code=2)  # pylint: disable=protected-access
         self.assertEqual(port.diff_image("EXPECTED", "ACTUAL"),
                          (None, 'Image diff returned an exit code of 2. See http://crbug.com/278596'))
 
@@ -220,7 +221,7 @@
 
     def test_wdiff_text_fails(self):
         host = MockSystemHost(os_name=self.os_name, os_version=self.os_version)
-        host.executive = MockExecutive(should_throw=True)
+        host.executive = MockExecutive(should_throw=True)  # pylint: disable=protected-access
         port = self.make_port(host=host)
         port._executive = host.executive  # AndroidPortTest.make_port sets its own executive, so reset that as well.
 
@@ -291,9 +292,9 @@
 
     def test_check_sys_deps(self):
         port = self.make_port()
-        port._executive = MockExecutive2(exit_code=0)
+        port._executive = MockExecutive(exit_code=0)  # pylint: disable=protected-access
         self.assertEqual(port.check_sys_deps(needs_http=False), test_run_results.OK_EXIT_STATUS)
-        port._executive = MockExecutive2(exit_code=1, output='testing output failure')
+        port._executive = MockExecutive(exit_code=1, output='testing output failure')  # pylint: disable=protected-access
         self.assertEqual(port.check_sys_deps(needs_http=False), test_run_results.SYS_DEPS_EXIT_STATUS)
 
     def test_expectations_ordering(self):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl_unittest.py
index d8b5250..bba5489 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl_unittest.py
@@ -92,7 +92,12 @@
                             'actual': 'MISSING',
                             'is_unexpected': True,
                             'is_missing_text': True,
-                        }
+                        },
+                        'prototype-slowtest.html': {
+                            'expected': 'SLOW',
+                            'actual': 'TEXT',
+                            'is_unexpected': True,
+                        },
                     }
                 },
                 'svg': {
@@ -112,9 +117,10 @@
 
         self.tool.buildbot.set_retry_sumary_json(Build('MOCK Try Win', 5000), json.dumps({
             'failures': [
-                'fast/dom/prototype-newtest.html',
-                'fast/dom/prototype-taco.html',
                 'fast/dom/prototype-inheritance.html',
+                'fast/dom/prototype-newtest.html',
+                'fast/dom/prototype-slowtest.html',
+                'fast/dom/prototype-taco.html',
                 'svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr.html',
             ],
             'ignored': [],
@@ -154,6 +160,7 @@
         self.assertLog([
             'INFO: Rebaselining fast/dom/prototype-inheritance.html\n',
             'INFO: Rebaselining fast/dom/prototype-newtest.html\n',
+            'INFO: Rebaselining fast/dom/prototype-slowtest.html\n',
             'INFO: Rebaselining fast/dom/prototype-taco.html\n',
             'INFO: Rebaselining svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr.html\n',
         ])
@@ -172,6 +179,7 @@
         self.assertLog([
             'INFO: Rebaselining fast/dom/prototype-inheritance.html\n',
             'INFO: Rebaselining fast/dom/prototype-newtest.html\n',
+            'INFO: Rebaselining fast/dom/prototype-slowtest.html\n',
             'INFO: Rebaselining fast/dom/prototype-taco.html\n',
             'INFO: Rebaselining svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr.html\n',
         ])
@@ -216,6 +224,7 @@
             'WARNING: No retry summary available for build Build(builder_name=u\'MOCK Try Win\', build_number=5000).\n',
             'INFO: Rebaselining fast/dom/prototype-inheritance.html\n',
             'INFO: Rebaselining fast/dom/prototype-newtest.html\n',
+            'INFO: Rebaselining fast/dom/prototype-slowtest.html\n',
             'INFO: Rebaselining fast/dom/prototype-taco.html\n',
             'INFO: Rebaselining svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr.html\n',
         ])
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py
index 882cd5a..df5a7c6 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py
@@ -7,7 +7,7 @@
 
 from webkitpy.common.net.buildbot import Build
 from webkitpy.common.net.layout_test_results import LayoutTestResults
-from webkitpy.common.system.executive_mock import MockExecutive, MockExecutive2
+from webkitpy.common.system.executive_mock import MockExecutive
 from webkitpy.common.system.output_capture import OutputCapture
 from webkitpy.layout_tests.builder_list import BuilderList
 from webkitpy.tool.commands.rebaseline import (
@@ -149,7 +149,7 @@
             'original mac10.11 result')
 
     def test_copying_overwritten_baseline_to_multiple_locations(self):
-        self.tool.executive = MockExecutive2()
+        self.tool.executive = MockExecutive()
 
     def test_copy_baseline_win7_to_linux_trusty(self):
         port = self.tool.port_factory.get('test-win-win7')
@@ -298,7 +298,7 @@
         self.assertDictEqual(self.command.expectation_line_changes.to_dict(), {'remove-lines': []})
 
     def test_rebaseline_test_internal_with_port_that_lacks_buildbot(self):
-        self.tool.executive = MockExecutive2()
+        self.tool.executive = MockExecutive()
 
         port = self.tool.port_factory.get('test-win-win7')
         self._write(
@@ -381,7 +381,7 @@
 
     def setUp(self):
         super(TestRebaselineJson, self).setUp()
-        self.tool.executive = MockExecutive2()
+        self.tool.executive = MockExecutive()
 
     def tearDown(self):
         super(TestRebaselineJson, self).tearDown()
@@ -506,7 +506,7 @@
 
     def setUp(self):
         super(TestRebaselineJsonUpdatesExpectationsFiles, self).setUp()
-        self.tool.executive = MockExecutive2()
+        self.tool.executive = MockExecutive()
 
         def mock_run_command(*args, **kwargs):  # pylint: disable=unused-argument
             return '{"add": [], "remove-lines": [{"test": "userscripts/first-test.html", "builder": "MOCK Mac10.11"}]}\n'
@@ -695,7 +695,7 @@
     def test_rebaseline_expectations(self):
         self._zero_out_test_expectations()
 
-        self.tool.executive = MockExecutive2()
+        self.tool.executive = MockExecutive()
 
         for builder in ['MOCK Mac10.10', 'MOCK Mac10.11']:
             self.tool.buildbot.set_results(Build(builder), LayoutTestResults({
@@ -749,7 +749,7 @@
     def test_rebaseline_expectations_reftests(self):
         self._zero_out_test_expectations()
 
-        self.tool.executive = MockExecutive2()
+        self.tool.executive = MockExecutive()
 
         for builder in ['MOCK Mac10.10', 'MOCK Mac10.11']:
             self.tool.buildbot.set_results(Build(builder), LayoutTestResults({
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/chromium_commit_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/chromium_commit_unittest.py
index 63d3aae..f981168 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/chromium_commit_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/chromium_commit_unittest.py
@@ -3,8 +3,9 @@
 # found in the LICENSE file.
 
 import unittest
+
 from webkitpy.common.host_mock import MockHost
-from webkitpy.common.system.executive_mock import MockExecutive2
+from webkitpy.common.system.executive_mock import MockExecutive
 from webkitpy.w3c.chromium_commit import ChromiumCommit
 from webkitpy.w3c.test_exporter_unittest import mock_command_exec
 
@@ -21,7 +22,7 @@
 
     def test_derives_sha_from_position(self):
         host = MockHost()
-        host.executive = MockExecutive2(output='deadbeefcafe')
+        host.executive = MockExecutive(output='deadbeefcafe')
         pos = 'Cr-Commit-Position: refs/heads/master@{#789}'
         chromium_commit = ChromiumCommit(host, position=pos)
 
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater_unittest.py
index 57c6b76..806ca41 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater_unittest.py
@@ -4,9 +4,9 @@
 
 import unittest
 
-from webkitpy.w3c.deps_updater import DepsUpdater
 from webkitpy.common.host_mock import MockHost
-from webkitpy.common.system.executive_mock import MockExecutive2
+from webkitpy.common.system.executive_mock import MockExecutive
+from webkitpy.w3c.deps_updater import DepsUpdater
 
 
 class DepsUpdaterTest(unittest.TestCase):
@@ -64,7 +64,7 @@
 
     def test_cl_description_with_empty_environ(self):
         host = MockHost()
-        host.executive = MockExecutive2(output='Last commit message\n')
+        host.executive = MockExecutive(output='Last commit message\n')
         updater = DepsUpdater(host)
         description = updater._cl_description()
         self.assertEqual(
@@ -76,7 +76,7 @@
 
     def test_cl_description_with_environ_variables(self):
         host = MockHost()
-        host.executive = MockExecutive2(output='Last commit message\n')
+        host.executive = MockExecutive(output='Last commit message\n')
         updater = DepsUpdater(host)
         updater.host.environ['BUILDBOT_MASTERNAME'] = 'my.master'
         updater.host.environ['BUILDBOT_BUILDERNAME'] = 'b'
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/local_wpt_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/local_wpt_unittest.py
index 20085219..e9edad6d 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/local_wpt_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/local_wpt_unittest.py
@@ -3,10 +3,11 @@
 # found in the LICENSE file.
 
 import unittest
-from webkitpy.w3c.local_wpt import LocalWPT
+
 from webkitpy.common.host_mock import MockHost
-from webkitpy.common.system.executive_mock import MockExecutive2
+from webkitpy.common.system.executive_mock import MockExecutive
 from webkitpy.common.system.filesystem_mock import MockFileSystem
+from webkitpy.w3c.local_wpt import LocalWPT
 
 
 class LocalWPTTest(unittest.TestCase):
@@ -59,7 +60,7 @@
             '123',
             '9ea4fc353a4b1c11c6e524270b11baa4d1ddfde8',
         ]
-        host.executive = MockExecutive2(run_command_fn=lambda _: return_vals.pop())
+        host.executive = MockExecutive(run_command_fn=lambda _: return_vals.pop())
         host.filesystem = MockFileSystem()
         local_wpt = LocalWPT(host, no_fetch=True)
 
@@ -70,7 +71,7 @@
 
     def test_last_wpt_exported_commit_not_found(self):
         host = MockHost()
-        host.executive = MockExecutive2(run_command_fn=lambda _: None)
+        host.executive = MockExecutive(run_command_fn=lambda _: None)
         host.filesystem = MockFileSystem()
         local_wpt = LocalWPT(host)
 
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter_unittest.py
index 00e0e11..33c85ab 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter_unittest.py
@@ -5,7 +5,7 @@
 import unittest
 
 from webkitpy.common.host_mock import MockHost
-from webkitpy.common.system.executive_mock import MockExecutive2
+from webkitpy.common.system.executive_mock import MockExecutive
 from webkitpy.w3c.chromium_commit import ChromiumCommit
 from webkitpy.w3c.test_exporter import TestExporter
 from webkitpy.w3c.wpt_github_mock import MockWPTGitHub
@@ -15,7 +15,7 @@
     def run_fn(args):
         sub_command = args[1]
         return vals.get(sub_command, '')
-    return MockExecutive2(run_command_fn=run_fn)
+    return MockExecutive(run_command_fn=run_fn)
 
 
 class TestExporterTest(unittest.TestCase):
@@ -50,7 +50,7 @@
 
     def test_dry_run_stops_before_creating_pr(self):
         host = MockHost()
-        host.executive = MockExecutive2(output='beefcafe')
+        host.executive = MockExecutive(output='beefcafe')
         wpt_github = MockWPTGitHub(pull_requests=[{'number': 1, 'title': 'abc'}])
         TestExporter(host, wpt_github, dry_run=True).run()
 
@@ -71,7 +71,7 @@
             }
             return canned_git_outputs.get(args[1], '')
 
-        host.executive = MockExecutive2(run_command_fn=mock_command)
+        host.executive = MockExecutive(run_command_fn=mock_command)
         wpt_github = MockWPTGitHub(pull_requests=[])
 
         TestExporter(host, wpt_github).run()
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer_unittest.py
index f8683ee..1ff68fe 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer_unittest.py
@@ -29,8 +29,8 @@
 import unittest
 
 from webkitpy.common.host_mock import MockHost
+from webkitpy.common.system.executive_mock import MockExecutive, ScriptError
 from webkitpy.common.system.filesystem_mock import MockFileSystem
-from webkitpy.common.system.executive_mock import MockExecutive2, ScriptError
 from webkitpy.w3c.test_importer import TestImporter
 
 
@@ -65,7 +65,7 @@
 
     def test_import_dir_with_no_tests(self):
         host = MockHost()
-        host.executive = MockExecutive2(exception=ScriptError(
+        host.executive = MockExecutive(exception=ScriptError(
             "abort: no repository found in '/Volumes/Source/src/wk/Tools/Scripts/webkitpy/w3c'"))
         host.filesystem = MockFileSystem(files=FAKE_FILES)
         importer = TestImporter(host, FAKE_SOURCE_REPO_DIR, self.options())
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/update_w3c_test_expectations.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/update_w3c_test_expectations.py
index 15e3a29..221bd55 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/update_w3c_test_expectations.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/update_w3c_test_expectations.py
@@ -34,9 +34,11 @@
         self.finder = WebKitFinder(self.host.filesystem)
 
     def run(self, args=None):
+        """Downloads text new baselines and adds test expectations lines."""
         parser = argparse.ArgumentParser(description=__doc__)
         parser.add_argument('-v', '--verbose', action='store_true', help='More verbose logging.')
         args = parser.parse_args(args)
+
         log_level = logging.DEBUG if args.verbose else logging.INFO
         logging.basicConfig(level=log_level, format='%(message)s')
 
@@ -48,43 +50,34 @@
         rietveld = Rietveld(self.host.web)
         builds = rietveld.latest_try_jobs(issue_number, self.get_try_bots())
         _log.debug('Latest try jobs: %r', builds)
-
         if not builds:
             _log.error('No try job information was collected.')
             return 1
 
+        # Here we build up a dict of failing test results for all platforms.
         test_expectations = {}
         for build in builds:
             platform_results = self.get_failing_results_dict(build)
             test_expectations = self.merge_dicts(test_expectations, platform_results)
 
+        # And then we merge results for different platforms that had the same results.
         for test_name, platform_result in test_expectations.iteritems():
+            # platform_result is a dict mapping platforms to results.
             test_expectations[test_name] = self.merge_same_valued_keys(platform_result)
 
-        test_expectations = self.get_expected_txt_files(test_expectations)
+        test_expectations = self.download_text_baselines(test_expectations)
         test_expectation_lines = self.create_line_list(test_expectations)
         self.write_to_test_expectations(test_expectation_lines)
         return 0
 
     def get_issue_number(self):
+        """Returns current CL number. Can be replaced in unit tests."""
         return GitCL(self.host).get_issue_number()
 
     def get_try_bots(self):
+        """Returns try bot names. Can be replaced in unit tests."""
         return self.host.builders.all_try_builder_names()
 
-    def generate_results_dict(self, platform, result_list):
-        test_dict = {}
-        if '-' in platform:
-            platform = platform[platform.find('-') + 1:].capitalize()
-        for result in result_list:
-            test_dict[result.test_name()] = {
-                platform: {
-                    'expected': result.expected_results(),
-                    'actual': result.actual_results(),
-                    'bug': 'crbug.com/626703'
-                }}
-        return test_dict
-
     def get_failing_results_dict(self, build):
         """Returns a nested dict of failing test results.
 
@@ -111,10 +104,44 @@
             _log.warning('No results for build %s', build)
             return {}
         platform = self.host.builders.port_name_for_builder_name(build.builder_name)
-        result_list = layout_test_results.didnt_run_as_expected_results()
-        failing_results_dict = self.generate_results_dict(platform, result_list)
+        test_results = layout_test_results.didnt_run_as_expected_results()
+        failing_results_dict = self.generate_results_dict(platform, test_results)
         return failing_results_dict
 
+    def generate_results_dict(self, full_port_name, test_results):
+        """Makes a dict with results for one platform.
+
+        Args:
+            full_port_name: The full port name, e.g. "win-win10".
+            test_results: A list of LayoutTestResult objects.
+
+        Returns:
+            A dict mapping to platform string (e.g. "Win10") to a dict with
+            the results for that test and that platform.
+        """
+        platform = self._port_name_to_platform_specifier(full_port_name)
+        test_dict = {}
+        for result in test_results:
+            test_dict[result.test_name()] = {
+                platform: {
+                    'expected': result.expected_results(),
+                    'actual': result.actual_results(),
+                    'bug': 'crbug.com/626703'
+                }}
+        return test_dict
+
+    def _port_name_to_platform_specifier(self, port_name):
+        """Maps a port name to the string used in test expectations lines.
+
+        For example:
+            linux-trusty -> Trusty
+            mac-mac10.11 -> Mac10.11.
+        """
+        # TODO(qyearsley): Do this in a more robust way with Port classes.
+        if '-' in port_name:
+            return port_name[port_name.find('-') + 1:].capitalize()
+        return port_name
+
     def merge_dicts(self, target, source, path=None):
         """Recursively merges nested dictionaries.
 
@@ -286,12 +313,12 @@
     def _test_name_from_expectation_string(expectation_string):
         return TestExpectationLine.tokenize_line(filename='', expectation_string=expectation_string, line_number=0).name
 
-    def get_expected_txt_files(self, tests_results):
+    def download_text_baselines(self, tests_results):
         """Fetches new baseline files for tests that should be rebaselined.
 
-        Invokes webkit-patch rebaseline-from-try-jobs in order to download new
-        -expected.txt files for testharness.js tests that did not crash or time
-        out. Then, the platform-specific test is removed from the overall
+        Invokes `webkit-patch rebaseline-cl` in order to download new baselines
+        (-expected.txt files) for testharness.js tests that did not crash or
+        time out. Then, the platform-specific test is removed from the overall
         failure test dictionary.
 
         Args:
@@ -300,7 +327,7 @@
         Returns:
             An updated tests_results dictionary without the platform-specific
             testharness.js tests that required new baselines to be downloaded
-            from `webkit-patch rebaseline-from-try-jobs`.
+            from `webkit-patch rebaseline-cl`.
         """
         modified_tests = self.get_modified_existing_tests()
         tests_to_rebaseline, tests_results = self.get_tests_to_rebaseline(modified_tests, tests_results)
@@ -348,8 +375,8 @@
 
         Returns:
             A pair: A set of tests to be rebaselined, and a modified copy of
-            the test results dictionary. The tests to be rebaselined should include
-            testharness.js tests that failed due to a baseline mismatch.
+            the test results dictionary. The tests to be rebaselined should
+            include testharness.js tests that failed due to a baseline mismatch.
         """
         test_results = copy.deepcopy(test_results)
         tests_to_rebaseline = set()
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/update_w3c_test_expectations_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/update_w3c_test_expectations_unittest.py
index 0d7ccc3..fca0190 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/update_w3c_test_expectations_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/update_w3c_test_expectations_unittest.py
@@ -10,8 +10,8 @@
 from webkitpy.common.net.buildbot_mock import MockBuildBot
 from webkitpy.common.net.layout_test_results import LayoutTestResult, LayoutTestResults
 from webkitpy.common.net.web_mock import MockWeb
+from webkitpy.common.system.executive_mock import MockExecutive
 from webkitpy.common.system.log_testing import LoggingTestCase
-from webkitpy.common.system.executive_mock import MockExecutive2
 from webkitpy.layout_tests.builder_list import BuilderList
 from webkitpy.w3c.update_w3c_test_expectations import W3CExpectationsLineAdder, MARKER_COMMENT
 
@@ -287,6 +287,30 @@
         # The original dict isn't modified.
         self.assertEqual(test_results_dict, test_results_dict_copy)
 
+    def test_get_tests_to_rebaseline_also_returns_slow_tests(self):
+        test_results_dict = {
+            'imported/fake/test/path.html': {
+                'one': {'expected': 'SLOW', 'actual': 'TEXT', 'bug': 'crbug.com/626703'},
+                'two': {'expected': 'SLOW', 'actual': 'TIMEOUT', 'bug': 'crbug.com/626703'},
+            },
+        }
+        test_results_dict_copy = copy.deepcopy(test_results_dict)
+        self.host.filesystem.files['/mock-checkout/third_party/WebKit/LayoutTests/imported/fake/test/path.html'] = (
+            '<script src="/resources/testharness.js"></script>')
+        line_adder = W3CExpectationsLineAdder(self.host)
+        tests_to_rebaseline, modified_test_results = line_adder.get_tests_to_rebaseline(
+            ['imported/fake/test/path.html'], test_results_dict)
+        self.assertEqual(tests_to_rebaseline, ['imported/fake/test/path.html'])
+        # The record for the builder with a timeout is kept, but not with a text mismatch,
+        # since that should be covered by downloading a new baseline.
+        self.assertEqual(modified_test_results, {
+            'imported/fake/test/path.html': {
+                'two': {'expected': 'SLOW', 'actual': 'TIMEOUT', 'bug': 'crbug.com/626703'},
+            },
+        })
+        # The original dict isn't modified.
+        self.assertEqual(test_results_dict, test_results_dict_copy)
+
     def test_run_no_issue_number(self):
         line_adder = W3CExpectationsLineAdder(self.host)
         line_adder.get_issue_number = lambda: 'None'
@@ -323,7 +347,7 @@
         ]
         self.host.filesystem.files['/mock-checkout/third_party/WebKit/LayoutTests/a/b.html'] = ''
         self.host.filesystem.files['/mock-checkout/x/y/z.cc'] = ''
-        self.host.executive = MockExecutive2(output='\n'.join(modified_files))
+        self.host.executive = MockExecutive(output='\n'.join(modified_files))
         tests = line_adder.get_modified_existing_tests()
         self.assertEqual(tests, ['a/b.html'])
         self.assertEqual(self.host.executive.calls, [['git', 'diff', 'origin/master', '--name-only', '--diff-filter=AMR']])
diff --git a/third_party/WebKit/public/BUILD.gn b/third_party/WebKit/public/BUILD.gn
index 21de3101..139f1b6 100644
--- a/third_party/WebKit/public/BUILD.gn
+++ b/third_party/WebKit/public/BUILD.gn
@@ -326,13 +326,6 @@
     "platform/linux/WebFontRenderStyle.h",
     "platform/linux/WebSandboxSupport.h",
     "platform/mac/WebSandboxSupport.h",
-    "platform/modules/bluetooth/WebBluetooth.h",
-    "platform/modules/bluetooth/WebBluetoothDevice.h",
-    "platform/modules/bluetooth/WebBluetoothError.h",
-    "platform/modules/bluetooth/WebBluetoothRemoteGATTCharacteristic.h",
-    "platform/modules/bluetooth/WebBluetoothRemoteGATTCharacteristicInit.h",
-    "platform/modules/bluetooth/WebBluetoothRemoteGATTService.h",
-    "platform/modules/bluetooth/WebRequestDeviceOptions.h",
     "platform/modules/device_orientation/WebDeviceMotionData.h",
     "platform/modules/device_orientation/WebDeviceMotionListener.h",
     "platform/modules/device_orientation/WebDeviceOrientationData.h",
diff --git a/third_party/WebKit/public/platform/modules/bluetooth/WebBluetooth.h b/third_party/WebKit/public/platform/modules/bluetooth/WebBluetooth.h
deleted file mode 100644
index ccf8ddd..0000000
--- a/third_party/WebKit/public/platform/modules/bluetooth/WebBluetooth.h
+++ /dev/null
@@ -1,120 +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 WebBluetooth_h
-#define WebBluetooth_h
-
-#include "public/platform/WebCallbacks.h"
-#include "public/platform/WebString.h"
-#include "public/platform/WebVector.h"
-
-#include <memory>
-
-namespace blink {
-
-class WebBluetoothDevice;
-class WebBluetoothRemoteGATTCharacteristic;
-
-struct WebBluetoothDeviceInit;
-struct WebBluetoothRemoteGATTCharacteristicInit;
-struct WebBluetoothRemoteGATTService;
-struct WebRequestDeviceOptions;
-
-// Success and failure callbacks for requestDevice.
-using WebBluetoothRequestDeviceCallbacks = WebCallbacks<
-    std::unique_ptr<WebBluetoothDeviceInit>,
-    int32_t /* Corresponds to WebBluetoothResult in web_bluetooth.mojom */>;
-
-// Success and failure callbacks for GattServer.connect().
-using WebBluetoothRemoteGATTServerConnectCallbacks = WebCallbacks<
-    void,
-    int32_t /* Corresponds to WebBluetoothResult in web_bluetooth.mojom */>;
-
-// Success and failure callbacks for getPrimaryService(s).
-using WebBluetoothGetPrimaryServicesCallbacks = WebCallbacks<
-    const WebVector<WebBluetoothRemoteGATTService*>&,
-    int32_t /* Corresponds to WebBluetoothResult in web_bluetooth.mojom */>;
-
-// Success and failure callbacks for getCharacteristic(s).
-using WebBluetoothGetCharacteristicsCallbacks = WebCallbacks<
-    const WebVector<WebBluetoothRemoteGATTCharacteristicInit*>&,
-    int32_t /* Corresponds to WebBluetoothResult in web_bluetooth.mojom */>;
-
-// Success and failure callbacks for readValue.
-using WebBluetoothReadValueCallbacks = WebCallbacks<
-    const WebVector<uint8_t>&,
-    int32_t /* Corresponds to WebBluetoothResult in web_bluetooth.mojom */>;
-
-// Success and failure callbacks for writeValue.
-using WebBluetoothWriteValueCallbacks = WebCallbacks<
-    const WebVector<uint8_t>&,
-    int32_t /* Corresponds to WebBluetoothResult in web_bluetooth.mojom */>;
-
-// Success and failure callbacks for characteristic.startNotifications and
-// characteristic.stopNotifications.
-using WebBluetoothNotificationsCallbacks = WebCallbacks<
-    void,
-    int32_t /* Corresponds to WebBluetoothResult in web_bluetooth.mojom */>;
-
-class WebBluetooth {
- public:
-  virtual ~WebBluetooth() {}
-
-  // Bluetooth Methods:
-  // See https://webbluetoothcg.github.io/web-bluetooth/#device-discovery
-  // WebBluetoothRequestDeviceCallbacks ownership transferred to the client.
-  virtual void requestDevice(const WebRequestDeviceOptions&,
-                             WebBluetoothRequestDeviceCallbacks*) {}
-
-  // BluetoothDevice methods:
-
-  // BluetoothRemoteGATTServer methods:
-  // See
-  // https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattserver
-  virtual void connect(const WebString& deviceId,
-                       WebBluetoothDevice* device,
-                       WebBluetoothRemoteGATTServerConnectCallbacks*) {}
-  virtual void disconnect(const WebString& deviceId) = 0;
-  virtual void getPrimaryServices(
-      const WebString& deviceId,
-      // Corresponds to WebBluetoothGATTQueryQuantity in web_bluetooth.mojom:
-      int32_t quantity,
-      const WebString& servicesUUID,
-      WebBluetoothGetPrimaryServicesCallbacks*) = 0;
-
-  // BluetoothRemoteGATTService methods:
-  // See
-  // https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattservice
-  virtual void getCharacteristics(
-      const WebString& serviceInstanceID,
-      // Corresponds to WebBluetoothGATTQueryQuantity in web_bluetooth.mojom
-      int32_t quantity,
-      const WebString& characteristicsUUID,
-      WebBluetoothGetCharacteristicsCallbacks*) = 0;
-
-  // BluetoothRemoteGATTCharacteristic methods:
-  // See
-  // https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattcharacteristic
-  virtual void readValue(const WebString& characteristicInstanceID,
-                         WebBluetoothReadValueCallbacks*) {}
-  virtual void writeValue(const WebString& characteristicInstanceID,
-                          const WebVector<uint8_t>& value,
-                          WebBluetoothWriteValueCallbacks*) {}
-  virtual void startNotifications(const WebString& characteristicInstanceID,
-                                  WebBluetoothNotificationsCallbacks*) {}
-  virtual void stopNotifications(const WebString& characteristicInstanceID,
-                                 WebBluetoothNotificationsCallbacks*) {}
-
-  // Called when addEventListener is called on a characteristic.
-  virtual void registerCharacteristicObject(
-      const WebString& characteristicInstanceID,
-      WebBluetoothRemoteGATTCharacteristic*) = 0;
-  virtual void characteristicObjectRemoved(
-      const WebString& characteristicInstanceID,
-      WebBluetoothRemoteGATTCharacteristic*) {}
-};
-
-}  // namespace blink
-
-#endif  // WebBluetooth_h
diff --git a/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothDevice.h b/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothDevice.h
deleted file mode 100644
index 440117c..0000000
--- a/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothDevice.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 WebBluetoothDevice_h
-#define WebBluetoothDevice_h
-
-namespace blink {
-
-// An object through which the embedder can trigger events on a Document-bound
-// BluetoothDevice object.
-class WebBluetoothDevice {
- public:
-  virtual void dispatchGattServerDisconnected() = 0;
-};
-
-}  // namespace blink
-
-#endif  // WebBluetoothDevice_h
diff --git a/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothDeviceInit.h b/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothDeviceInit.h
deleted file mode 100644
index 1e4c34e..0000000
--- a/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothDeviceInit.h
+++ /dev/null
@@ -1,26 +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 WebBluetoothDeviceInit_h
-#define WebBluetoothDeviceInit_h
-
-#include "public/platform/WebString.h"
-#include "public/platform/WebVector.h"
-
-namespace blink {
-
-// Information provided by the platform to initialize BluetoothDevice objects
-// with attributes as specified in BluetoothDevice.idl.
-struct WebBluetoothDeviceInit {
-  WebBluetoothDeviceInit(const WebString& id, const WebString& name)
-      : id(id), name(name) {}
-
-  // Members corresponding to BluetoothDevice attributes as specified in IDL.
-  const WebString id;
-  const WebString name;
-};
-
-}  // namespace blink
-
-#endif  // WebBluetoothDeviceInit_h
diff --git a/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothRemoteGATTCharacteristic.h b/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothRemoteGATTCharacteristic.h
deleted file mode 100644
index dac5706e..0000000
--- a/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothRemoteGATTCharacteristic.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef WebBluetoothRemoteGATTCharacteristic_h
-#define WebBluetoothRemoteGATTCharacteristic_h
-
-#include "public/platform/WebVector.h"
-
-namespace blink {
-
-// An object through which the embedder can trigger events on a Document-bound
-// Web Bluetooth GATT Characteristic object.
-class WebBluetoothRemoteGATTCharacteristic {
- public:
-  // Used to notify blink that the characteristic's value changed.
-  virtual void dispatchCharacteristicValueChanged(
-      const WebVector<uint8_t>&) = 0;
-};
-
-}  // namespace blink
-
-#endif  // WebBluetoothRemoteGATTCharacteristicDelegate_h
diff --git a/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothRemoteGATTCharacteristicInit.h b/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothRemoteGATTCharacteristicInit.h
deleted file mode 100644
index f3105ef..0000000
--- a/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothRemoteGATTCharacteristicInit.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef WebBluetoothRemoteGATTCharacteristicInit_h
-#define WebBluetoothRemoteGATTCharacteristicInit_h
-
-#include "public/platform/WebString.h"
-#include "public/platform/WebVector.h"
-
-namespace blink {
-
-// Contains members corresponding to BluetoothRemoteGATTCharacteristic
-// attributes as specified in the IDL.
-struct WebBluetoothRemoteGATTCharacteristicInit {
-  WebBluetoothRemoteGATTCharacteristicInit(
-      const WebString& serviceInstanceID,
-      const WebString& characteristicInstanceID,
-      const WebString& uuid,
-      uint32_t characteristicProperties)
-      : characteristicInstanceID(characteristicInstanceID),
-        serviceInstanceID(serviceInstanceID),
-        uuid(uuid),
-        characteristicProperties(characteristicProperties) {}
-
-  const WebString characteristicInstanceID;
-  const WebString serviceInstanceID;
-  const WebString uuid;
-  const uint32_t characteristicProperties;
-  const WebVector<uint8_t> value;
-};
-
-}  // namespace blink
-
-#endif  // WebBluetoothRemoteGATTCharacteristicInit_h
diff --git a/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothRemoteGATTService.h b/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothRemoteGATTService.h
deleted file mode 100644
index c8899b74..0000000
--- a/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothRemoteGATTService.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef WebBluetoothRemoteGATTService_h
-#define WebBluetoothRemoteGATTService_h
-
-#include "public/platform/WebString.h"
-
-namespace blink {
-
-struct WebBluetoothRemoteGATTService {
-  WebBluetoothRemoteGATTService(const WebString& serviceInstanceID,
-                                const WebString& uuid,
-                                bool isPrimary,
-                                const WebString& deviceInstanceID)
-      : serviceInstanceID(serviceInstanceID),
-        uuid(uuid),
-        isPrimary(isPrimary),
-        deviceInstanceID(deviceInstanceID) {}
-
-  // Members corresponding to BluetoothRemoteGATTService attributes as
-  // specified in the IDL.
-  const WebString serviceInstanceID;
-  const WebString uuid;
-  const bool isPrimary;
-  const WebString deviceInstanceID;
-};
-
-}  // namespace blink
-
-#endif  // WebBluetoothRemoteGATTService_h
diff --git a/third_party/WebKit/public/platform/modules/bluetooth/WebRequestDeviceOptions.h b/third_party/WebKit/public/platform/modules/bluetooth/WebRequestDeviceOptions.h
deleted file mode 100644
index c7a96d3c..0000000
--- a/third_party/WebKit/public/platform/modules/bluetooth/WebRequestDeviceOptions.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef WebRequestDeviceOptions_h
-#define WebRequestDeviceOptions_h
-
-#include "public/platform/WebString.h"
-#include "public/platform/WebVector.h"
-
-namespace blink {
-
-// Contains members corresponding to BluetoothScanFilter members as
-// specified in the IDL.
-struct WebBluetoothScanFilter {
-  WebBluetoothScanFilter() {}
-
-  WebVector<WebString> services;
-  // We don't allow empty services or namePrefix but we do allow
-  // an empty name so we can't use name.isEmpty() to know if
-  // the filter contains a name or not.
-  bool hasName;
-  WebString name;
-  WebString namePrefix;
-};
-
-// Contains members corresponding to RequestDeviceOptions members as
-// specified in the IDL.
-struct WebRequestDeviceOptions {
-  WebRequestDeviceOptions() {}
-
-  WebVector<WebBluetoothScanFilter> filters;
-  bool hasFilters;
-  WebVector<WebString> optionalServices;
-  bool acceptAllDevices;
-};
-
-}  // namespace blink
-
-#endif  // WebRequestDeviceOptions_h
diff --git a/third_party/WebKit/public/web/WebFrameClient.h b/third_party/WebKit/public/web/WebFrameClient.h
index 1dc6db0..8549e52 100644
--- a/third_party/WebKit/public/web/WebFrameClient.h
+++ b/third_party/WebKit/public/web/WebFrameClient.h
@@ -72,7 +72,6 @@
 class InterfaceRegistry;
 class WebApplicationCacheHost;
 class WebApplicationCacheHostClient;
-class WebBluetooth;
 class WebColorChooser;
 class WebColorChooserClient;
 class WebContentDecryptionModule;
@@ -726,9 +725,6 @@
     return WebCustomHandlersNew;
   }
 
-  // Bluetooth -----------------------------------------------------------
-  virtual WebBluetooth* bluetooth() { return 0; }
-
   // Audio Output Devices API --------------------------------------------
 
   // Checks that the given audio sink exists and is authorized. The result is
diff --git a/third_party/gvr-android-sdk/BUILD.gn b/third_party/gvr-android-sdk/BUILD.gn
index a31bff9..4540008 100644
--- a/third_party/gvr-android-sdk/BUILD.gn
+++ b/third_party/gvr-android-sdk/BUILD.gn
@@ -12,9 +12,9 @@
 }
 
 android_aar_prebuilt("gvr_controller_java") {
-  aar_path = "src/libraries/controller/controller.aar"
+  aar_path = "src/libraries/sdk-controller-1.10.0.aar"
 }
 
 config("libgvr_config") {
-  include_dirs = [ "src/ndk/include/" ]
+  include_dirs = [ "src/libraries/headers/" ]
 }
diff --git a/third_party/gvr-android-sdk/README.chromium b/third_party/gvr-android-sdk/README.chromium
index b7cda7f0..07a9e796 100644
--- a/third_party/gvr-android-sdk/README.chromium
+++ b/third_party/gvr-android-sdk/README.chromium
@@ -1,9 +1,9 @@
 Name: Google VR SDK
 Short Name: gvr
 URL: https://github.com/googlevr/gvr-android-sdk
-Version: 1.0.0
-Date: 23 Sep 2016
-Revision: 25e7e14413229d4644a66be77e8f8ddeb3f91fe7
+Version: 1.10.0
+Date: 6 Dec 2016
+Revision: 8d1395957283ee13ebe2bc672ba24e5ca4ec343f
 License: Apache 2.0
 License File: LICENSE
 Security Critical: yes
diff --git a/third_party/gvr-android-sdk/common_library.aar.sha1 b/third_party/gvr-android-sdk/common_library.aar.sha1
index ec081310..b4f5f1f 100644
--- a/third_party/gvr-android-sdk/common_library.aar.sha1
+++ b/third_party/gvr-android-sdk/common_library.aar.sha1
@@ -1 +1 @@
-fc53a744c3b930eb2437fdab1492809befccf5ef
\ No newline at end of file
+6799b87b66355c76c3c1a62846d07fd50f522037
\ No newline at end of file
diff --git a/third_party/gvr-android-sdk/libgvr_shim_static_arm.a.sha1 b/third_party/gvr-android-sdk/libgvr_shim_static_arm.a.sha1
index 984506b..9cbf9e79 100644
--- a/third_party/gvr-android-sdk/libgvr_shim_static_arm.a.sha1
+++ b/third_party/gvr-android-sdk/libgvr_shim_static_arm.a.sha1
@@ -1 +1 @@
-0bb6cf9639805764e1c7b91f8aae62f4edf37c80
\ No newline at end of file
+a3f413d83c0c5badb295d888e20d0bb1ec079fe1
\ No newline at end of file
diff --git a/third_party/gvr-android-sdk/libgvr_shim_static_arm64.a.sha1 b/third_party/gvr-android-sdk/libgvr_shim_static_arm64.a.sha1
index d1e97c50..ee116d86 100644
--- a/third_party/gvr-android-sdk/libgvr_shim_static_arm64.a.sha1
+++ b/third_party/gvr-android-sdk/libgvr_shim_static_arm64.a.sha1
@@ -1 +1 @@
-6df67597db09e9123d75b2fc94806825c03a1d2c
\ No newline at end of file
+32da6a3cee8673e51ec722de2b8102389a77eae1
\ No newline at end of file
diff --git a/third_party/harfbuzz-ng/NEWS b/third_party/harfbuzz-ng/NEWS
index 6f46119..fb84c88 100644
--- a/third_party/harfbuzz-ng/NEWS
+++ b/third_party/harfbuzz-ng/NEWS
@@ -1,3 +1,51 @@
+Overview of changes leading to 1.3.4
+Monday, December 5, 2016
+====================================
+
+- Fix vertical glyph origin in hb-ot-font.
+- Implement CBDT/CBLC color font glyph extents in hb-ot-font.
+
+
+Overview of changes leading to 1.3.3
+Wednesday, September 28, 2016
+====================================
+
+- Implement parsing of OpenType MATH table.
+New API:
+HB_OT_TAG_MATH
+HB_OT_MATH_SCRIPT
+hb_ot_math_constant_t
+hb_ot_math_kern_t
+hb_ot_math_glyph_variant_t
+hb_ot_math_glyph_part_flags_t
+hb_ot_math_glyph_part_t
+hb_ot_math_has_data
+hb_ot_math_get_constant
+hb_ot_math_get_glyph_italics_correction
+hb_ot_math_get_glyph_top_accent_attachment
+hb_ot_math_get_glyph_kerning
+hb_ot_math_is_glyph_extended_shape
+hb_ot_math_get_glyph_variants
+hb_ot_math_get_min_connector_overlap
+hb_ot_math_get_glyph_assembly
+
+
+Overview of changes leading to 1.3.2
+Wednesday, September 27, 2016
+====================================
+
+- Fix build of hb-coretext on older OS X versions.
+
+
+Overview of changes leading to 1.3.1
+Wednesday, September 7, 2016
+====================================
+
+- Blacklist bad GDEF of more fonts (Padauk).
+- More CoreText backend crash fixes with OS X 10.9.5.
+- Misc fixes.
+
+
 Overview of changes leading to 1.3.0
 Thursday, July 21, 2016
 ====================================
diff --git a/third_party/harfbuzz-ng/README b/third_party/harfbuzz-ng/README
index 3fcdfb4c..69a1bdd 100644
--- a/third_party/harfbuzz-ng/README
+++ b/third_party/harfbuzz-ng/README
@@ -1,4 +1,5 @@
 [![Build Status](https://travis-ci.org/behdad/harfbuzz.svg)](https://travis-ci.org/behdad/harfbuzz)
+[![Build Status](https://ci.appveyor.com/api/projects/status/4oaq58ns2h0m2soa?svg=true)](https://ci.appveyor.com/project/behdad/harfbuzz)
 [![Coverage Status](https://img.shields.io/coveralls/behdad/harfbuzz.svg)](https://coveralls.io/r/behdad/harfbuzz)
 [ABI Tracker](http://abi-laboratory.pro/tracker/timeline/harfbuzz/)
 
diff --git a/third_party/harfbuzz-ng/README.chromium b/third_party/harfbuzz-ng/README.chromium
index d6d342d..f667f66 100644
--- a/third_party/harfbuzz-ng/README.chromium
+++ b/third_party/harfbuzz-ng/README.chromium
@@ -1,8 +1,8 @@
 Name: harfbuzz-ng
 Short Name: harfbuzz-ng
 URL: http://harfbuzz.org
-Version: 1.3.1
-Date: 20160907
+Version: 1.3.4
+Date: 20161205
 Security Critical: yes
 License: MIT
 License File: COPYING
diff --git a/third_party/harfbuzz-ng/src/hb-coretext.cc b/third_party/harfbuzz-ng/src/hb-coretext.cc
index ee7f91cc..507581b 100644
--- a/third_party/harfbuzz-ng/src/hb-coretext.cc
+++ b/third_party/harfbuzz-ng/src/hb-coretext.cc
@@ -152,7 +152,8 @@
    * operating system versions. Except for the emoji font, where _not_
    * reconfiguring the cascade list causes CoreText crashes. For details, see
    * crbug.com/549610 */
-  if (&CTGetCoreTextVersion != NULL && CTGetCoreTextVersion() < kCTVersionNumber10_10) {
+  // 0x00070000 stands for "kCTVersionNumber10_10", see CoreText.h
+  if (&CTGetCoreTextVersion != NULL && CTGetCoreTextVersion() < 0x00070000) {
     CFStringRef fontName = CTFontCopyPostScriptName (ct_font);
     bool isEmojiFont = CFStringCompare (fontName, CFSTR("AppleColorEmoji"), 0) == kCFCompareEqualTo;
     CFRelease (fontName);
diff --git a/third_party/harfbuzz-ng/src/hb-font-private.hh b/third_party/harfbuzz-ng/src/hb-font-private.hh
index 0b755779..cda97a6 100644
--- a/third_party/harfbuzz-ng/src/hb-font-private.hh
+++ b/third_party/harfbuzz-ng/src/hb-font-private.hh
@@ -116,8 +116,12 @@
 
 
   /* Convert from font-space to user-space */
-  inline hb_position_t em_scale_x (int16_t v) { return em_scale (v, this->x_scale); }
-  inline hb_position_t em_scale_y (int16_t v) { return em_scale (v, this->y_scale); }
+  inline int dir_scale (hb_direction_t direction)
+  { return HB_DIRECTION_IS_VERTICAL(direction) ? y_scale : x_scale; }
+  inline hb_position_t em_scale_x (int16_t v) { return em_scale (v, x_scale); }
+  inline hb_position_t em_scale_y (int16_t v) { return em_scale (v, y_scale); }
+  inline hb_position_t em_scale_dir (int16_t v, hb_direction_t direction)
+  { return em_scale (v, dir_scale (direction)); }
 
   /* Convert from parent-font user-space to our user-space */
   inline hb_position_t parent_scale_x_distance (hb_position_t v) {
@@ -292,24 +296,32 @@
 
   /* A bit higher-level, and with fallback */
 
+  inline void get_h_extents_with_fallback (hb_font_extents_t *extents)
+  {
+    if (!get_font_h_extents (extents))
+    {
+      extents->ascender = y_scale * .8;
+      extents->descender = extents->ascender - y_scale;
+      extents->line_gap = 0;
+    }
+  }
+  inline void get_v_extents_with_fallback (hb_font_extents_t *extents)
+  {
+    if (!get_font_v_extents (extents))
+    {
+      extents->ascender = x_scale / 2;
+      extents->descender = extents->ascender - x_scale;
+      extents->line_gap = 0;
+    }
+  }
+
   inline void get_extents_for_direction (hb_direction_t direction,
 					 hb_font_extents_t *extents)
   {
-    if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
-      if (!get_font_h_extents (extents))
-      {
-	extents->ascender = y_scale * .8;
-	extents->descender = y_scale - extents->ascender;
-	extents->line_gap = 0;
-      }
-    } else {
-      if (!get_font_v_extents (extents))
-      {
-	extents->ascender = x_scale / 2;
-	extents->descender = x_scale - extents->ascender;
-	extents->line_gap = 0;
-      }
-    }
+    if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
+      get_h_extents_with_fallback (extents);
+    else
+      get_v_extents_with_fallback (extents);
   }
 
   inline void get_glyph_advance_for_direction (hb_codepoint_t glyph,
@@ -325,14 +337,38 @@
     }
   }
 
-  /* Internal only */
   inline void guess_v_origin_minus_h_origin (hb_codepoint_t glyph,
 					     hb_position_t *x, hb_position_t *y)
   {
     *x = get_glyph_h_advance (glyph) / 2;
 
-    /* TODO use font_extents.ascender */
-    *y = y_scale;
+    /* TODO cache this somehow?! */
+    hb_font_extents_t extents;
+    get_h_extents_with_fallback (&extents);
+    *y = extents.ascender;
+  }
+
+  inline void get_glyph_h_origin_with_fallback (hb_codepoint_t glyph,
+						hb_position_t *x, hb_position_t *y)
+  {
+    if (!get_glyph_h_origin (glyph, x, y) &&
+	 get_glyph_v_origin (glyph, x, y))
+    {
+      hb_position_t dx, dy;
+      guess_v_origin_minus_h_origin (glyph, &dx, &dy);
+      *x -= dx; *y -= dy;
+    }
+  }
+  inline void get_glyph_v_origin_with_fallback (hb_codepoint_t glyph,
+						hb_position_t *x, hb_position_t *y)
+  {
+    if (!get_glyph_v_origin (glyph, x, y) &&
+	 get_glyph_h_origin (glyph, x, y))
+    {
+      hb_position_t dx, dy;
+      guess_v_origin_minus_h_origin (glyph, &dx, &dy);
+      *x += dx; *y += dy;
+    }
   }
 
   inline void get_glyph_origin_for_direction (hb_codepoint_t glyph,
@@ -340,25 +376,9 @@
 					      hb_position_t *x, hb_position_t *y)
   {
     if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
-    {
-      if (!get_glyph_h_origin (glyph, x, y) &&
-	   get_glyph_v_origin (glyph, x, y))
-      {
-	hb_position_t dx, dy;
-	guess_v_origin_minus_h_origin (glyph, &dx, &dy);
-	*x -= dx; *y -= dy;
-      }
-    }
+      get_glyph_h_origin_with_fallback (glyph, x, y);
     else
-    {
-      if (!get_glyph_v_origin (glyph, x, y) &&
-	   get_glyph_h_origin (glyph, x, y))
-      {
-	hb_position_t dx, dy;
-	guess_v_origin_minus_h_origin (glyph, &dx, &dy);
-	*x += dx; *y += dy;
-      }
-    }
+      get_glyph_v_origin_with_fallback (glyph, x, y);
   }
 
   inline void add_glyph_h_origin (hb_codepoint_t glyph,
@@ -366,7 +386,7 @@
   {
     hb_position_t origin_x, origin_y;
 
-    get_glyph_h_origin (glyph, &origin_x, &origin_y);
+    get_glyph_h_origin_with_fallback (glyph, &origin_x, &origin_y);
 
     *x += origin_x;
     *y += origin_y;
@@ -376,7 +396,7 @@
   {
     hb_position_t origin_x, origin_y;
 
-    get_glyph_v_origin (glyph, &origin_x, &origin_y);
+    get_glyph_v_origin_with_fallback (glyph, &origin_x, &origin_y);
 
     *x += origin_x;
     *y += origin_y;
@@ -398,7 +418,7 @@
   {
     hb_position_t origin_x, origin_y;
 
-    get_glyph_h_origin (glyph, &origin_x, &origin_y);
+    get_glyph_h_origin_with_fallback (glyph, &origin_x, &origin_y);
 
     *x -= origin_x;
     *y -= origin_y;
@@ -408,7 +428,7 @@
   {
     hb_position_t origin_x, origin_y;
 
-    get_glyph_v_origin (glyph, &origin_x, &origin_y);
+    get_glyph_v_origin_with_fallback (glyph, &origin_x, &origin_y);
 
     *x -= origin_x;
     *y -= origin_y;
@@ -504,7 +524,6 @@
     return false;
   }
 
-  private:
   inline hb_position_t em_scale (int16_t v, int scale)
   {
     int upem = face->get_upem ();
diff --git a/third_party/harfbuzz-ng/src/hb-gobject-structs.cc b/third_party/harfbuzz-ng/src/hb-gobject-structs.cc
index 6bd63368..fef0024 100644
--- a/third_party/harfbuzz-ng/src/hb-gobject-structs.cc
+++ b/third_party/harfbuzz-ng/src/hb-gobject-structs.cc
@@ -78,3 +78,6 @@
 HB_DEFINE_VALUE_TYPE (glyph_position)
 HB_DEFINE_VALUE_TYPE (segment_properties)
 HB_DEFINE_VALUE_TYPE (user_data_key)
+
+HB_DEFINE_VALUE_TYPE (ot_math_glyph_variant)
+HB_DEFINE_VALUE_TYPE (ot_math_glyph_part)
diff --git a/third_party/harfbuzz-ng/src/hb-open-type-private.hh b/third_party/harfbuzz-ng/src/hb-open-type-private.hh
index df683ca..66f1c08 100644
--- a/third_party/harfbuzz-ng/src/hb-open-type-private.hh
+++ b/third_party/harfbuzz-ng/src/hb-open-type-private.hh
@@ -650,6 +650,7 @@
   DEFINE_SIZE_STATIC (Size);
 };
 
+typedef	IntType<int8_t	, 1> CHAR;	/* 8-bit signed integer. */
 typedef	IntType<uint8_t	, 1> BYTE;	/* 8-bit unsigned integer. */
 typedef IntType<uint16_t, 2> USHORT;	/* 16-bit unsigned integer. */
 typedef IntType<int16_t,  2> SHORT;	/* 16-bit signed integer. */
@@ -805,6 +806,7 @@
     if (unlikely (!c->check_struct (this))) return_trace (false);
     unsigned int offset = *this;
     if (unlikely (!offset)) return_trace (true);
+    if (unlikely (!c->check_range (base, offset))) return_trace (false);
     const Type &obj = StructAtOffset<Type> (base, offset);
     return_trace (likely (obj.sanitize (c)) || neuter (c));
   }
@@ -815,6 +817,7 @@
     if (unlikely (!c->check_struct (this))) return_trace (false);
     unsigned int offset = *this;
     if (unlikely (!offset)) return_trace (true);
+    if (unlikely (!c->check_range (base, offset))) return_trace (false);
     const Type &obj = StructAtOffset<Type> (base, offset);
     return_trace (likely (obj.sanitize (c, user_data)) || neuter (c));
   }
diff --git a/third_party/harfbuzz-ng/src/hb-ot-cbdt-table.hh b/third_party/harfbuzz-ng/src/hb-ot-cbdt-table.hh
new file mode 100644
index 0000000..52897ab
--- /dev/null
+++ b/third_party/harfbuzz-ng/src/hb-ot-cbdt-table.hh
@@ -0,0 +1,384 @@
+/*
+ * Copyright © 2016  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Seigo Nonaka
+ */
+
+#ifndef HB_OT_CBDT_TABLE_HH
+#define HB_OT_CBDT_TABLE_HH
+
+#include "hb-open-type-private.hh"
+
+namespace OT {
+
+struct SmallGlyphMetrics
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  inline void get_extents (hb_glyph_extents_t *extents) const
+  {
+    extents->x_bearing = bearingX;
+    extents->y_bearing = bearingY;
+    extents->width = width;
+    extents->height = -height;
+  }
+
+  BYTE height;
+  BYTE width;
+  CHAR bearingX;
+  CHAR bearingY;
+  BYTE advance;
+
+  DEFINE_SIZE_STATIC(5);
+};
+
+struct BigGlyphMetrics : SmallGlyphMetrics
+{
+  CHAR vertBearingX;
+  CHAR vertBearingY;
+  BYTE vertAdvance;
+
+  DEFINE_SIZE_STATIC(8);
+};
+
+struct SBitLineMetrics
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  CHAR ascender;
+  CHAR decender;
+  BYTE widthMax;
+  CHAR caretSlopeNumerator;
+  CHAR caretSlopeDenominator;
+  CHAR caretOffset;
+  CHAR minOriginSB;
+  CHAR minAdvanceSB;
+  CHAR maxBeforeBL;
+  CHAR minAfterBL;
+  CHAR padding1;
+  CHAR padding2;
+
+  DEFINE_SIZE_STATIC(12);
+};
+
+
+/*
+ * Index Subtables.
+ */
+
+struct IndexSubtableHeader
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  USHORT indexFormat;
+  USHORT imageFormat;
+  ULONG imageDataOffset;
+
+  DEFINE_SIZE_STATIC(8);
+};
+
+template <typename OffsetType>
+struct IndexSubtableFormat1Or3
+{
+  inline bool sanitize (hb_sanitize_context_t *c, unsigned int glyph_count) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+		  c->check_array (offsetArrayZ, offsetArrayZ[0].static_size, glyph_count + 1));
+  }
+
+  bool get_image_data (unsigned int idx,
+		       unsigned int *offset,
+		       unsigned int *length) const
+  {
+    if (unlikely (offsetArrayZ[idx + 1] <= offsetArrayZ[idx]))
+      return false;
+
+    *offset = header.imageDataOffset + offsetArrayZ[idx];
+    *length = offsetArrayZ[idx + 1] - offsetArrayZ[idx];
+    return true;
+  }
+
+  IndexSubtableHeader header;
+  Offset<OffsetType> offsetArrayZ[VAR];
+
+  DEFINE_SIZE_ARRAY(8, offsetArrayZ);
+};
+
+struct IndexSubtableFormat1 : IndexSubtableFormat1Or3<ULONG> {};
+struct IndexSubtableFormat3 : IndexSubtableFormat1Or3<USHORT> {};
+
+struct IndexSubtable
+{
+  inline bool sanitize (hb_sanitize_context_t *c, unsigned int glyph_count) const
+  {
+    TRACE_SANITIZE (this);
+    if (!u.header.sanitize (c)) return_trace (false);
+    switch (u.header.indexFormat) {
+    case 1: return_trace (u.format1.sanitize (c, glyph_count));
+    case 3: return_trace (u.format3.sanitize (c, glyph_count));
+    default:return_trace (true);
+    }
+  }
+
+  inline bool get_extents (hb_glyph_extents_t *extents) const
+  {
+    switch (u.header.indexFormat) {
+    case 2: case 5: /* TODO */
+    case 1: case 3: case 4: /* Variable-metrics formats do not have metrics here. */
+    default:return (false);
+    }
+  }
+
+  bool get_image_data (unsigned int idx,
+		       unsigned int *offset,
+		       unsigned int *length,
+		       unsigned int *format) const
+  {
+    *format = u.header.imageFormat;
+    switch (u.header.indexFormat) {
+    case 1: return u.format1.get_image_data (idx, offset, length);
+    case 3: return u.format3.get_image_data (idx, offset, length);
+    default: return false;
+    }
+  }
+
+  protected:
+  union {
+  IndexSubtableHeader	header;
+  IndexSubtableFormat1	format1;
+  IndexSubtableFormat3	format3;
+  /* TODO: Format 2, 4, 5. */
+  } u;
+  public:
+  DEFINE_SIZE_UNION (8, header);
+};
+
+struct IndexSubtableRecord
+{
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+		  firstGlyphIndex <= lastGlyphIndex &&
+		  offsetToSubtable.sanitize (c, this, lastGlyphIndex - firstGlyphIndex + 1));
+  }
+
+  inline bool get_extents (hb_glyph_extents_t *extents) const
+  {
+    return (this+offsetToSubtable).get_extents (extents);
+  }
+
+  bool get_image_data (unsigned int gid,
+		       unsigned int *offset,
+		       unsigned int *length,
+		       unsigned int *format) const
+  {
+    if (gid < firstGlyphIndex || gid > lastGlyphIndex)
+    {
+      return false;
+    }
+    return (this+offsetToSubtable).get_image_data (gid - firstGlyphIndex,
+						   offset, length, format);
+  }
+
+  USHORT firstGlyphIndex;
+  USHORT lastGlyphIndex;
+  OffsetTo<IndexSubtable, ULONG> offsetToSubtable;
+
+  DEFINE_SIZE_STATIC(8);
+};
+
+struct IndexSubtableArray
+{
+  inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!c->check_array (&indexSubtablesZ, indexSubtablesZ[0].static_size, count)))
+      return_trace (false);
+    for (unsigned int i = 0; i < count; i++)
+      if (unlikely (!indexSubtablesZ[i].sanitize (c, this)))
+	return_trace (false);
+    return_trace (true);
+  }
+
+  public:
+  const IndexSubtableRecord* find_table (hb_codepoint_t glyph, unsigned int numTables) const
+  {
+    for (unsigned int i = 0; i < numTables; ++i)
+    {
+      unsigned int firstGlyphIndex = indexSubtablesZ[i].firstGlyphIndex;
+      unsigned int lastGlyphIndex = indexSubtablesZ[i].lastGlyphIndex;
+      if (firstGlyphIndex <= glyph && glyph <= lastGlyphIndex) {
+        return &indexSubtablesZ[i];
+      }
+    }
+    return NULL;
+  }
+
+  protected:
+  IndexSubtableRecord indexSubtablesZ[VAR];
+
+  public:
+  DEFINE_SIZE_ARRAY(0, indexSubtablesZ);
+};
+
+struct BitmapSizeTable
+{
+  friend struct CBLC;
+
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+		  indexSubtableArrayOffset.sanitize (c, base, numberOfIndexSubtables) &&
+		  c->check_range (&(base+indexSubtableArrayOffset), indexTablesSize) &&
+		  horizontal.sanitize (c) &&
+		  vertical.sanitize (c));
+  }
+
+  const IndexSubtableRecord *find_table (hb_codepoint_t glyph, const void *base) const
+  {
+    return (base+indexSubtableArrayOffset).find_table (glyph, numberOfIndexSubtables);
+  }
+
+  protected:
+  OffsetTo<IndexSubtableArray, ULONG> indexSubtableArrayOffset;
+  ULONG indexTablesSize;
+  ULONG numberOfIndexSubtables;
+  ULONG colorRef;
+  SBitLineMetrics horizontal;
+  SBitLineMetrics vertical;
+  USHORT startGlyphIndex;
+  USHORT endGlyphIndex;
+  BYTE ppemX;
+  BYTE ppemY;
+  BYTE bitDepth;
+  CHAR flags;
+
+public:
+  DEFINE_SIZE_STATIC(48);
+};
+
+
+/*
+ * Glyph Bitmap Data Formats.
+ */
+
+struct GlyphBitmapDataFormat17
+{
+  SmallGlyphMetrics glyphMetrics;
+  ULONG dataLen;
+  BYTE dataZ[VAR];
+
+  DEFINE_SIZE_ARRAY(9, dataZ);
+};
+
+
+/*
+ * CBLC -- Color Bitmap Location Table
+ */
+
+#define HB_OT_TAG_CBLC HB_TAG('C','B','L','C')
+
+struct CBLC
+{
+  static const hb_tag_t tableTag = HB_OT_TAG_CBLC;
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+		  likely (version.major == 2 || version.major == 3) &&
+		  sizeTables.sanitize (c, this));
+  }
+
+  public:
+  const IndexSubtableRecord *find_table (hb_codepoint_t glyph,
+					 unsigned int *x_ppem, unsigned int *y_ppem) const
+  {
+    /* TODO: Make it possible to select strike. */
+
+    unsigned int count = sizeTables.len;
+    for (uint32_t i = 0; i < count; ++i)
+    {
+      unsigned int startGlyphIndex = sizeTables.array[i].startGlyphIndex;
+      unsigned int endGlyphIndex = sizeTables.array[i].endGlyphIndex;
+      if (startGlyphIndex <= glyph && glyph <= endGlyphIndex)
+      {
+	*x_ppem = sizeTables[i].ppemX;
+	*y_ppem = sizeTables[i].ppemY;
+	return sizeTables[i].find_table (glyph, this);
+      }
+    }
+
+    return NULL;
+  }
+
+  protected:
+  FixedVersion<>version;
+  ArrayOf<BitmapSizeTable, ULONG> sizeTables;
+
+  public:
+  DEFINE_SIZE_ARRAY(8, sizeTables);
+};
+
+/*
+ * CBDT -- Color Bitmap Data Table
+ */
+#define HB_OT_TAG_CBDT HB_TAG('C','B','D','T')
+
+struct CBDT
+{
+  static const hb_tag_t tableTag = HB_OT_TAG_CBDT;
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+		  likely (version.major == 2 || version.major == 3));
+  }
+
+  protected:
+  FixedVersion<>version;
+  BYTE dataZ[VAR];
+
+  public:
+  DEFINE_SIZE_ARRAY(4, dataZ);
+};
+
+} /* namespace OT */
+
+#endif /* HB_OT_CBDT_TABLE_HH */
diff --git a/third_party/harfbuzz-ng/src/hb-ot-font.cc b/third_party/harfbuzz-ng/src/hb-ot-font.cc
index 0b7e31b..df01bc9 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-font.cc
+++ b/third_party/harfbuzz-ng/src/hb-ot-font.cc
@@ -31,6 +31,7 @@
 #include "hb-font-private.hh"
 
 #include "hb-ot-cmap-table.hh"
+#include "hb-ot-cbdt-table.hh"
 #include "hb-ot-glyf-table.hh"
 #include "hb-ot-head-table.hh"
 #include "hb-ot-hhea-table.hh"
@@ -47,6 +48,7 @@
   unsigned short ascender;
   unsigned short descender;
   unsigned short line_gap;
+  bool has_font_extents;
 
   const OT::_mtx *table;
   hb_blob_t *blob;
@@ -54,9 +56,10 @@
   inline void init (hb_face_t *face,
 		    hb_tag_t _hea_tag,
 		    hb_tag_t _mtx_tag,
-		    hb_tag_t os2_tag)
+		    hb_tag_t os2_tag,
+		    unsigned int default_advance = 0)
   {
-    this->default_advance = face->get_upem ();
+    this->default_advance = default_advance ? default_advance : face->get_upem ();
 
     bool got_font_extents = false;
     if (os2_tag)
@@ -82,9 +85,12 @@
       this->ascender = _hea->ascender;
       this->descender = _hea->descender;
       this->line_gap = _hea->lineGap;
+      got_font_extents = (this->ascender | this->descender) != 0;
     }
     hb_blob_destroy (_hea_blob);
 
+    this->has_font_extents = got_font_extents;
+
     this->blob = OT::Sanitizer<OT::_mtx>::sanitize (face->reference_table (_mtx_tag));
 
     /* Cap num_metrics() and num_advances() based on table length. */
@@ -202,6 +208,91 @@
   }
 };
 
+struct hb_ot_face_cbdt_accelerator_t
+{
+  hb_blob_t *cblc_blob;
+  hb_blob_t *cbdt_blob;
+  const OT::CBLC *cblc;
+  const OT::CBDT *cbdt;
+
+  unsigned int cbdt_len;
+  float upem;
+
+  inline void init (hb_face_t *face)
+  {
+    upem = face->get_upem();
+
+    cblc_blob = OT::Sanitizer<OT::CBLC>::sanitize (face->reference_table (HB_OT_TAG_CBLC));
+    cbdt_blob = OT::Sanitizer<OT::CBDT>::sanitize (face->reference_table (HB_OT_TAG_CBDT));
+    cbdt_len = hb_blob_get_length (cbdt_blob);
+
+    if (hb_blob_get_length (cblc_blob) == 0) {
+      cblc = NULL;
+      cbdt = NULL;
+      return;  /* Not a bitmap font. */
+    }
+    cblc = OT::Sanitizer<OT::CBLC>::lock_instance (cblc_blob);
+    cbdt = OT::Sanitizer<OT::CBDT>::lock_instance (cbdt_blob);
+
+  }
+
+  inline void fini (void)
+  {
+    hb_blob_destroy (this->cblc_blob);
+    hb_blob_destroy (this->cbdt_blob);
+  }
+
+  inline bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
+  {
+    unsigned int x_ppem = upem, y_ppem = upem; /* TODO Use font ppem if available. */
+
+    if (cblc == NULL)
+      return false;  // Not a color bitmap font.
+
+    const OT::IndexSubtableRecord *subtable_record = this->cblc->find_table(glyph, &x_ppem, &y_ppem);
+    if (subtable_record == NULL)
+      return false;
+
+    if (subtable_record->get_extents (extents))
+      return true;
+
+    unsigned int image_offset = 0, image_length = 0, image_format = 0;
+    if (!subtable_record->get_image_data (glyph, &image_offset, &image_length, &image_format))
+      return false;
+
+    {
+      /* TODO Move the following into CBDT struct when adding more formats. */
+
+      if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
+	return false;
+
+      switch (image_format)
+      {
+	case 17: {
+	  if (unlikely (image_length < OT::GlyphBitmapDataFormat17::min_size))
+	    return false;
+
+	  const OT::GlyphBitmapDataFormat17& glyphFormat17 =
+	      OT::StructAtOffset<OT::GlyphBitmapDataFormat17> (this->cbdt, image_offset);
+	  glyphFormat17.glyphMetrics.get_extents (extents);
+	}
+	break;
+	default:
+	  // TODO: Support other image formats.
+	  return false;
+      }
+    }
+
+    /* Convert to the font units. */
+    extents->x_bearing *= upem / (float) x_ppem;
+    extents->y_bearing *= upem / (float) y_ppem;
+    extents->width *= upem / (float) x_ppem;
+    extents->height *= upem / (float) y_ppem;
+
+    return true;
+  }
+};
+
 typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
 					  hb_codepoint_t codepoint,
 					  hb_codepoint_t *glyph);
@@ -374,6 +465,7 @@
   hb_ot_face_metrics_accelerator_t h_metrics;
   hb_ot_face_metrics_accelerator_t v_metrics;
   hb_lazy_loader_t<hb_ot_face_glyf_accelerator_t> glyf;
+  hb_lazy_loader_t<hb_ot_face_cbdt_accelerator_t> cbdt;
 };
 
 
@@ -387,8 +479,10 @@
 
   ot_font->cmap.init (face);
   ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, HB_OT_TAG_os2);
-  ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, HB_TAG_NONE); /* TODO Can we do this lazily? */
+  ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, HB_TAG_NONE,
+			   ot_font->h_metrics.ascender - ot_font->h_metrics.descender); /* TODO Can we do this lazily? */
   ot_font->glyf.init (face);
+  ot_font->cbdt.init (face);
 
   return ot_font;
 }
@@ -400,6 +494,7 @@
   ot_font->h_metrics.fini ();
   ot_font->v_metrics.fini ();
   ot_font->glyf.fini ();
+  ot_font->cbdt.fini ();
 
   free (ot_font);
 }
@@ -458,6 +553,8 @@
 {
   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
   bool ret = ot_font->glyf->get_extents (glyph, extents);
+  if (!ret)
+    ret = ot_font->cbdt->get_extents (glyph, extents);
   extents->x_bearing = font->em_scale_x (extents->x_bearing);
   extents->y_bearing = font->em_scale_y (extents->y_bearing);
   extents->width     = font->em_scale_x (extents->width);
@@ -475,7 +572,7 @@
   metrics->ascender = font->em_scale_y (ot_font->h_metrics.ascender);
   metrics->descender = font->em_scale_y (ot_font->h_metrics.descender);
   metrics->line_gap = font->em_scale_y (ot_font->h_metrics.line_gap);
-  return true;
+  return ot_font->h_metrics.has_font_extents;
 }
 
 static hb_bool_t
@@ -488,7 +585,7 @@
   metrics->ascender = font->em_scale_x (ot_font->v_metrics.ascender);
   metrics->descender = font->em_scale_x (ot_font->v_metrics.descender);
   metrics->line_gap = font->em_scale_x (ot_font->v_metrics.line_gap);
-  return true;
+  return ot_font->v_metrics.has_font_extents;
 }
 
 static hb_font_funcs_t *static_ot_funcs = NULL;
diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-math-table.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-math-table.hh
new file mode 100644
index 0000000..b52b121
--- /dev/null
+++ b/third_party/harfbuzz-ng/src/hb-ot-layout-math-table.hh
@@ -0,0 +1,722 @@
+/*
+ * Copyright © 2016  Igalia S.L.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Igalia Author(s): Frédéric Wang
+ */
+
+#ifndef HB_OT_LAYOUT_MATH_TABLE_HH
+#define HB_OT_LAYOUT_MATH_TABLE_HH
+
+#include "hb-open-type-private.hh"
+#include "hb-ot-layout-common-private.hh"
+#include "hb-ot-math.h"
+
+namespace OT {
+
+
+struct MathValueRecord
+{
+  inline hb_position_t get_x_value (hb_font_t *font, const void *base) const
+  { return font->em_scale_x (value) + (base+deviceTable).get_x_delta (font); }
+  inline hb_position_t get_y_value (hb_font_t *font, const void *base) const
+  { return font->em_scale_y (value) + (base+deviceTable).get_y_delta (font); }
+
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && deviceTable.sanitize (c, base));
+  }
+
+  protected:
+  SHORT			value;		/* The X or Y value in design units */
+  OffsetTo<Device>	deviceTable;	/* Offset to the device table - from the
+					 * beginning of parent table. May be NULL.
+					 * Suggested format for device table is 1. */
+
+  public:
+  DEFINE_SIZE_STATIC (4);
+};
+
+struct MathConstants
+{
+  inline bool sanitize_math_value_records (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+
+    unsigned int count = ARRAY_LENGTH (mathValueRecords);
+    for (unsigned int i = 0; i < count; i++)
+      if (!mathValueRecords[i].sanitize (c, this))
+	return_trace (false);
+
+    return_trace (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && sanitize_math_value_records(c));
+  }
+
+  inline hb_position_t get_value (hb_ot_math_constant_t constant,
+				  hb_font_t *font) const
+  {
+    switch (constant) {
+
+    case HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN:
+    case HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN:
+      return percentScaleDown[constant - HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN];
+
+    case HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT:
+    case HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT:
+      return font->em_scale_y (minHeight[constant - HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT]);
+
+    case HB_OT_MATH_CONSTANT_RADICAL_KERN_AFTER_DEGREE:
+    case HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE:
+    case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP:
+    case HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT:
+      return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_x_value(font, this);
+
+    case HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT:
+    case HB_OT_MATH_CONSTANT_AXIS_HEIGHT:
+    case HB_OT_MATH_CONSTANT_FLATTENED_ACCENT_BASE_HEIGHT:
+    case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN:
+    case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_GAP_MIN:
+    case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_SHIFT_DOWN:
+    case HB_OT_MATH_CONSTANT_FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN:
+    case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP:
+    case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_GAP_MIN:
+    case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_SHIFT_UP:
+    case HB_OT_MATH_CONSTANT_FRACTION_NUM_DISPLAY_STYLE_GAP_MIN:
+    case HB_OT_MATH_CONSTANT_FRACTION_RULE_THICKNESS:
+    case HB_OT_MATH_CONSTANT_LOWER_LIMIT_BASELINE_DROP_MIN:
+    case HB_OT_MATH_CONSTANT_LOWER_LIMIT_GAP_MIN:
+    case HB_OT_MATH_CONSTANT_MATH_LEADING:
+    case HB_OT_MATH_CONSTANT_OVERBAR_EXTRA_ASCENDER:
+    case HB_OT_MATH_CONSTANT_OVERBAR_RULE_THICKNESS:
+    case HB_OT_MATH_CONSTANT_OVERBAR_VERTICAL_GAP:
+    case HB_OT_MATH_CONSTANT_RADICAL_DISPLAY_STYLE_VERTICAL_GAP:
+    case HB_OT_MATH_CONSTANT_RADICAL_EXTRA_ASCENDER:
+    case HB_OT_MATH_CONSTANT_RADICAL_RULE_THICKNESS:
+    case HB_OT_MATH_CONSTANT_RADICAL_VERTICAL_GAP:
+    case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_VERTICAL_GAP:
+    case HB_OT_MATH_CONSTANT_STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN:
+    case HB_OT_MATH_CONSTANT_STACK_BOTTOM_SHIFT_DOWN:
+    case HB_OT_MATH_CONSTANT_STACK_DISPLAY_STYLE_GAP_MIN:
+    case HB_OT_MATH_CONSTANT_STACK_GAP_MIN:
+    case HB_OT_MATH_CONSTANT_STACK_TOP_DISPLAY_STYLE_SHIFT_UP:
+    case HB_OT_MATH_CONSTANT_STACK_TOP_SHIFT_UP:
+    case HB_OT_MATH_CONSTANT_STRETCH_STACK_BOTTOM_SHIFT_DOWN:
+    case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_ABOVE_MIN:
+    case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_BELOW_MIN:
+    case HB_OT_MATH_CONSTANT_STRETCH_STACK_TOP_SHIFT_UP:
+    case HB_OT_MATH_CONSTANT_SUBSCRIPT_BASELINE_DROP_MIN:
+    case HB_OT_MATH_CONSTANT_SUBSCRIPT_SHIFT_DOWN:
+    case HB_OT_MATH_CONSTANT_SUBSCRIPT_TOP_MAX:
+    case HB_OT_MATH_CONSTANT_SUB_SUPERSCRIPT_GAP_MIN:
+    case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BASELINE_DROP_MAX:
+    case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT:
+    case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MIN:
+    case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP:
+    case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP_CRAMPED:
+    case HB_OT_MATH_CONSTANT_UNDERBAR_EXTRA_DESCENDER:
+    case HB_OT_MATH_CONSTANT_UNDERBAR_RULE_THICKNESS:
+    case HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP:
+    case HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN:
+    case HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN:
+      return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_y_value(font, this);
+
+    case HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT:
+      return radicalDegreeBottomRaisePercent;
+
+    default:
+      return 0;
+    }
+  }
+
+  protected:
+  SHORT percentScaleDown[2];
+  USHORT minHeight[2];
+  MathValueRecord mathValueRecords[51];
+  SHORT radicalDegreeBottomRaisePercent;
+
+  public:
+  DEFINE_SIZE_STATIC (214);
+};
+
+struct MathItalicsCorrectionInfo
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+		  coverage.sanitize (c, this) &&
+		  italicsCorrection.sanitize (c, this));
+  }
+
+  inline hb_position_t get_value (hb_codepoint_t glyph,
+				  hb_font_t *font) const
+  {
+    unsigned int index = (this+coverage).get_coverage (glyph);
+    return italicsCorrection[index].get_x_value (font, this);
+  }
+
+  protected:
+  OffsetTo<Coverage>       coverage;		/* Offset to Coverage table -
+						 * from the beginning of
+						 * MathItalicsCorrectionInfo
+						 * table. */
+  ArrayOf<MathValueRecord> italicsCorrection;	/* Array of MathValueRecords
+						 * defining italics correction
+						 * values for each
+						 * covered glyph. */
+
+  public:
+  DEFINE_SIZE_ARRAY (4, italicsCorrection);
+};
+
+struct MathTopAccentAttachment
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+		  topAccentCoverage.sanitize (c, this) &&
+		  topAccentAttachment.sanitize (c, this));
+  }
+
+  inline hb_position_t get_value (hb_codepoint_t glyph,
+				  hb_font_t *font) const
+  {
+    unsigned int index = (this+topAccentCoverage).get_coverage (glyph);
+    if (index == NOT_COVERED)
+      return font->get_glyph_h_advance (glyph) / 2;
+    return topAccentAttachment[index].get_x_value(font, this);
+  }
+
+  protected:
+  OffsetTo<Coverage>       topAccentCoverage;   /* Offset to Coverage table -
+						 * from the beginning of
+						 * MathTopAccentAttachment
+						 * table. */
+  ArrayOf<MathValueRecord> topAccentAttachment; /* Array of MathValueRecords
+						 * defining top accent
+						 * attachment points for each
+						 * covered glyph. */
+
+  public:
+  DEFINE_SIZE_ARRAY (2 + 2, topAccentAttachment);
+};
+
+struct MathKern
+{
+  inline bool sanitize_math_value_records (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    unsigned int count = 2 * heightCount + 1;
+    for (unsigned int i = 0; i < count; i++)
+      if (!mathValueRecords[i].sanitize (c, this)) return_trace (false);
+    return_trace (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+		  c->check_array (mathValueRecords,
+				  mathValueRecords[0].static_size,
+				  2 * heightCount + 1) &&
+		  sanitize_math_value_records (c));
+  }
+
+  inline hb_position_t get_value (hb_position_t correction_height, hb_font_t *font) const
+  {
+    const MathValueRecord* correctionHeight = mathValueRecords;
+    const MathValueRecord* kernValue = mathValueRecords + heightCount;
+    int sign = font->y_scale < 0 ? -1 : +1;
+
+    /* The description of the MathKern table is a ambiguous, but interpreting
+     * "between the two heights found at those indexes" for 0 < i < len as
+     *
+     *   correctionHeight[i-1] < correction_height <= correctionHeight[i]
+     *
+     * makes the result consistent with the limit cases and we can just use the
+     * binary search algorithm of std::upper_bound:
+     */
+    unsigned int i = 0;
+    unsigned int count = heightCount;
+    while (count > 0)
+    {
+      unsigned int half = count / 2;
+      hb_position_t height = correctionHeight[i + half].get_y_value(font, this);
+      if (sign * height < sign * correction_height)
+      {
+	i += half + 1;
+	count -= half + 1;
+      } else
+	count = half;
+    }
+    return kernValue[i].get_x_value(font, this);
+  }
+
+  protected:
+  USHORT	  heightCount;
+  MathValueRecord mathValueRecords[VAR]; /* Array of correction heights at
+					  * which the kern value changes.
+					  * Sorted by the height value in
+					  * design units (heightCount entries),
+					  * Followed by:
+					  * Array of kern values corresponding
+					  * to heights. (heightCount+1 entries).
+					  */
+
+  public:
+  DEFINE_SIZE_ARRAY (2, mathValueRecords);
+};
+
+struct MathKernInfoRecord
+{
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+
+    unsigned int count = ARRAY_LENGTH (mathKern);
+    for (unsigned int i = 0; i < count; i++)
+      if (unlikely (!mathKern[i].sanitize (c, base)))
+	return_trace (false);
+
+    return_trace (true);
+  }
+
+  inline hb_position_t get_kerning (hb_ot_math_kern_t kern,
+				    hb_position_t correction_height,
+				    hb_font_t *font,
+				    const void *base) const
+  {
+    unsigned int idx = kern;
+    if (unlikely (idx >= ARRAY_LENGTH (mathKern))) return 0;
+    return (base+mathKern[idx]).get_value (correction_height, font);
+  }
+
+  protected:
+  /* Offset to MathKern table for each corner -
+   * from the beginning of MathKernInfo table. May be NULL. */
+  OffsetTo<MathKern> mathKern[4];
+
+  public:
+  DEFINE_SIZE_STATIC (8);
+};
+
+struct MathKernInfo
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+		  mathKernCoverage.sanitize (c, this) &&
+		  mathKernInfoRecords.sanitize (c, this));
+  }
+
+  inline hb_position_t get_kerning (hb_codepoint_t glyph,
+				    hb_ot_math_kern_t kern,
+				    hb_position_t correction_height,
+				    hb_font_t *font) const
+  {
+    unsigned int index = (this+mathKernCoverage).get_coverage (glyph);
+    return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this);
+  }
+
+  protected:
+  OffsetTo<Coverage>		mathKernCoverage;    /* Offset to Coverage table -
+						      * from the beginning of the
+						      * MathKernInfo table. */
+  ArrayOf<MathKernInfoRecord>	mathKernInfoRecords; /* Array of
+						      * MathKernInfoRecords,
+						      * per-glyph information for
+						      * mathematical positioning
+						      * of subscripts and
+						      * superscripts. */
+
+  public:
+  DEFINE_SIZE_ARRAY (4, mathKernInfoRecords);
+};
+
+struct MathGlyphInfo
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+		  mathItalicsCorrectionInfo.sanitize (c, this) &&
+		  mathTopAccentAttachment.sanitize (c, this) &&
+		  extendedShapeCoverage.sanitize (c, this) &&
+		  mathKernInfo.sanitize(c, this));
+  }
+
+  inline hb_position_t
+  get_italics_correction (hb_codepoint_t  glyph, hb_font_t *font) const
+  { return (this+mathItalicsCorrectionInfo).get_value (glyph, font); }
+
+  inline hb_position_t
+  get_top_accent_attachment (hb_codepoint_t  glyph, hb_font_t *font) const
+  { return (this+mathTopAccentAttachment).get_value (glyph, font); }
+
+  inline bool is_extended_shape (hb_codepoint_t glyph) const
+  { return (this+extendedShapeCoverage).get_coverage (glyph) != NOT_COVERED; }
+
+  inline hb_position_t get_kerning (hb_codepoint_t glyph,
+				    hb_ot_math_kern_t kern,
+				    hb_position_t correction_height,
+				    hb_font_t *font) const
+  { return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); }
+
+  protected:
+  /* Offset to MathItalicsCorrectionInfo table -
+   * from the beginning of MathGlyphInfo table. */
+  OffsetTo<MathItalicsCorrectionInfo> mathItalicsCorrectionInfo;
+
+  /* Offset to MathTopAccentAttachment table -
+   * from the beginning of MathGlyphInfo table. */
+  OffsetTo<MathTopAccentAttachment> mathTopAccentAttachment;
+
+  /* Offset to coverage table for Extended Shape glyphs -
+   * from the beginning of MathGlyphInfo table. When the left or right glyph of
+   * a box is an extended shape variant, the (ink) box (and not the default
+   * position defined by values in MathConstants table) should be used for
+   * vertical positioning purposes. May be NULL.. */
+  OffsetTo<Coverage> extendedShapeCoverage;
+
+   /* Offset to MathKernInfo table -
+    * from the beginning of MathGlyphInfo table. */
+  OffsetTo<MathKernInfo> mathKernInfo;
+
+  public:
+  DEFINE_SIZE_STATIC (8);
+};
+
+struct MathGlyphVariantRecord
+{
+  friend struct MathGlyphConstruction;
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  protected:
+  GlyphID variantGlyph;       /* Glyph ID for the variant. */
+  USHORT  advanceMeasurement; /* Advance width/height, in design units, of the
+			       * variant, in the direction of requested
+			       * glyph extension. */
+
+  public:
+  DEFINE_SIZE_STATIC (4);
+};
+
+struct PartFlags : USHORT
+{
+  enum Flags {
+    Extender	= 0x0001u, /* If set, the part can be skipped or repeated. */
+
+    Defined	= 0x0001u, /* All defined flags. */
+  };
+
+  public:
+  DEFINE_SIZE_STATIC (2);
+};
+
+struct MathGlyphPartRecord
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  inline void extract (hb_ot_math_glyph_part_t &out,
+		       int scale,
+		       hb_font_t *font) const
+  {
+    out.glyph			= glyph;
+
+    out.start_connector_length	= font->em_scale (startConnectorLength, scale);
+    out.end_connector_length	= font->em_scale (endConnectorLength, scale);
+    out.full_advance		= font->em_scale (fullAdvance, scale);
+
+    ASSERT_STATIC ((unsigned int) HB_MATH_GLYPH_PART_FLAG_EXTENDER ==
+		   (unsigned int) PartFlags::Extender);
+
+    out.flags = (hb_ot_math_glyph_part_flags_t)
+		(unsigned int)
+		(partFlags & PartFlags::Defined);
+  }
+
+  protected:
+  GlyphID   glyph;		  /* Glyph ID for the part. */
+  USHORT    startConnectorLength; /* Advance width/ height of the straight bar
+				   * connector material, in design units, is at
+				   * the beginning of the glyph, in the
+				   * direction of the extension. */
+  USHORT    endConnectorLength;   /* Advance width/ height of the straight bar
+				   * connector material, in design units, is at
+				   * the end of the glyph, in the direction of
+				   * the extension. */
+  USHORT    fullAdvance;	  /* Full advance width/height for this part,
+				   * in the direction of the extension.
+				   * In design units. */
+  PartFlags partFlags;		  /* Part qualifiers. */
+
+  public:
+  DEFINE_SIZE_STATIC (10);
+};
+
+struct MathGlyphAssembly
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+		  italicsCorrection.sanitize(c, this) &&
+		  partRecords.sanitize(c));
+  }
+
+  inline unsigned int get_parts (hb_direction_t direction,
+				 hb_font_t *font,
+				 unsigned int start_offset,
+				 unsigned int *parts_count, /* IN/OUT */
+				 hb_ot_math_glyph_part_t *parts /* OUT */,
+				 hb_position_t *italics_correction /* OUT */) const
+  {
+    if (parts_count)
+    {
+      int scale = font->dir_scale (direction);
+      const MathGlyphPartRecord *arr =
+	    partRecords.sub_array (start_offset, parts_count);
+      unsigned int count = *parts_count;
+      for (unsigned int i = 0; i < count; i++)
+	arr[i].extract (parts[i], scale, font);
+    }
+
+    if (italics_correction)
+      *italics_correction = italicsCorrection.get_x_value (font, this);
+
+    return partRecords.len;
+  }
+
+  protected:
+  MathValueRecord	   italicsCorrection; /* Italics correction of this
+					       * MathGlyphAssembly. Should not
+					       * depend on the assembly size. */
+  ArrayOf<MathGlyphPartRecord> partRecords;   /* Array of part records, from
+					       * left to right and bottom to
+					       * top. */
+
+  public:
+  DEFINE_SIZE_ARRAY (6, partRecords);
+};
+
+struct MathGlyphConstruction
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+		  glyphAssembly.sanitize(c, this) &&
+		  mathGlyphVariantRecord.sanitize(c));
+  }
+
+  inline const MathGlyphAssembly &get_assembly (void) const
+  { return this+glyphAssembly; }
+
+  inline unsigned int get_variants (hb_direction_t direction,
+				    hb_font_t *font,
+				    unsigned int start_offset,
+				    unsigned int *variants_count, /* IN/OUT */
+				    hb_ot_math_glyph_variant_t *variants /* OUT */) const
+  {
+    if (variants_count)
+    {
+      int scale = font->dir_scale (direction);
+      const MathGlyphVariantRecord *arr =
+	    mathGlyphVariantRecord.sub_array (start_offset, variants_count);
+      unsigned int count = *variants_count;
+      for (unsigned int i = 0; i < count; i++)
+      {
+	variants[i].glyph = arr[i].variantGlyph;
+	variants[i].advance = font->em_scale (arr[i].advanceMeasurement, scale);
+      }
+    }
+    return mathGlyphVariantRecord.len;
+  }
+
+  protected:
+  /* Offset to MathGlyphAssembly table for this shape - from the beginning of
+     MathGlyphConstruction table. May be NULL. */
+  OffsetTo<MathGlyphAssembly>	  glyphAssembly;
+
+  /* MathGlyphVariantRecords for alternative variants of the glyphs. */
+  ArrayOf<MathGlyphVariantRecord> mathGlyphVariantRecord;
+
+  public:
+  DEFINE_SIZE_ARRAY (4, mathGlyphVariantRecord);
+};
+
+struct MathVariants
+{
+  inline bool sanitize_offsets (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    unsigned int count = vertGlyphCount + horizGlyphCount;
+    for (unsigned int i = 0; i < count; i++)
+      if (!glyphConstruction[i].sanitize (c, this)) return_trace (false);
+    return_trace (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+		  vertGlyphCoverage.sanitize (c, this) &&
+		  horizGlyphCoverage.sanitize (c, this) &&
+		  c->check_array (glyphConstruction,
+				  glyphConstruction[0].static_size,
+				  vertGlyphCount + horizGlyphCount) &&
+		  sanitize_offsets (c));
+  }
+
+  inline hb_position_t get_min_connector_overlap (hb_direction_t direction,
+						  hb_font_t *font) const
+  { return font->em_scale_dir (minConnectorOverlap, direction); }
+
+  inline unsigned int get_glyph_variants (hb_codepoint_t glyph,
+					  hb_direction_t direction,
+					  hb_font_t *font,
+					  unsigned int start_offset,
+					  unsigned int *variants_count, /* IN/OUT */
+					  hb_ot_math_glyph_variant_t *variants /* OUT */) const
+  { return get_glyph_construction (glyph, direction, font)
+	   .get_variants (direction, font, start_offset, variants_count, variants); }
+
+  inline unsigned int get_glyph_parts (hb_codepoint_t glyph,
+				       hb_direction_t direction,
+				       hb_font_t *font,
+				       unsigned int start_offset,
+				       unsigned int *parts_count, /* IN/OUT */
+				       hb_ot_math_glyph_part_t *parts /* OUT */,
+				       hb_position_t *italics_correction /* OUT */) const
+  { return get_glyph_construction (glyph, direction, font)
+	   .get_assembly ()
+	   .get_parts (direction, font,
+		       start_offset, parts_count, parts,
+		       italics_correction); }
+
+  private:
+  inline const MathGlyphConstruction &
+		get_glyph_construction (hb_codepoint_t glyph,
+					hb_direction_t direction,
+					hb_font_t *font) const
+  {
+    bool vertical = HB_DIRECTION_IS_VERTICAL (direction);
+    unsigned int count = vertical ? vertGlyphCount : horizGlyphCount;
+    const OffsetTo<Coverage> &coverage = vertical ? vertGlyphCoverage
+						  : horizGlyphCoverage;
+
+    unsigned int index = (this+coverage).get_coverage (glyph);
+    if (unlikely (index >= count)) return Null(MathGlyphConstruction);
+
+    if (!vertical)
+      index += vertGlyphCount;
+
+    return this+glyphConstruction[index];
+  }
+
+  protected:
+  USHORT	     minConnectorOverlap; /* Minimum overlap of connecting
+					   * glyphs during glyph construction,
+					   * in design units. */
+  OffsetTo<Coverage> vertGlyphCoverage;   /* Offset to Coverage table -
+					   * from the beginning of MathVariants
+					   * table. */
+  OffsetTo<Coverage> horizGlyphCoverage;  /* Offset to Coverage table -
+					   * from the beginning of MathVariants
+					   * table. */
+  USHORT	     vertGlyphCount;      /* Number of glyphs for which
+					   * information is provided for
+					   * vertically growing variants. */
+  USHORT	     horizGlyphCount;     /* Number of glyphs for which
+					   * information is provided for
+					   * horizontally growing variants. */
+
+  /* Array of offsets to MathGlyphConstruction tables - from the beginning of
+     the MathVariants table, for shapes growing in vertical/horizontal
+     direction. */
+  OffsetTo<MathGlyphConstruction> glyphConstruction[VAR];
+
+  public:
+  DEFINE_SIZE_ARRAY (10, glyphConstruction);
+};
+
+
+/*
+ * MATH -- The MATH Table
+ */
+
+struct MATH
+{
+  static const hb_tag_t tableTag	= HB_OT_TAG_MATH;
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (version.sanitize (c) &&
+		  likely (version.major == 1) &&
+		  mathConstants.sanitize (c, this) &&
+		  mathGlyphInfo.sanitize (c, this) &&
+		  mathVariants.sanitize (c, this));
+  }
+
+  inline hb_position_t get_constant (hb_ot_math_constant_t  constant,
+				     hb_font_t		   *font) const
+  { return (this+mathConstants).get_value (constant, font); }
+
+  inline const MathGlyphInfo &get_math_glyph_info (void) const
+  { return this+mathGlyphInfo; }
+
+  inline const MathVariants &get_math_variants (void) const
+  { return this+mathVariants; }
+
+  protected:
+  FixedVersion<>version;		/* Version of the MATH table
+					 * initially set to 0x00010000u */
+  OffsetTo<MathConstants> mathConstants;/* MathConstants table */
+  OffsetTo<MathGlyphInfo> mathGlyphInfo;/* MathGlyphInfo table */
+  OffsetTo<MathVariants>  mathVariants;	/* MathVariants table */
+
+  public:
+  DEFINE_SIZE_STATIC (10);
+};
+
+} /* mathspace OT */
+
+
+#endif /* HB_OT_LAYOUT_MATH_TABLE_HH */
diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-private.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-private.hh
index 778b2c44..a4272de 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-layout-private.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-layout-private.hh
@@ -124,6 +124,7 @@
   struct GDEF;
   struct GSUB;
   struct GPOS;
+  struct MATH;
 }
 
 struct hb_ot_layout_lookup_accelerator_t
@@ -152,10 +153,12 @@
   hb_blob_t *gdef_blob;
   hb_blob_t *gsub_blob;
   hb_blob_t *gpos_blob;
+  hb_blob_t *math_blob;
 
   const struct OT::GDEF *gdef;
   const struct OT::GSUB *gsub;
   const struct OT::GPOS *gpos;
+  const struct OT::MATH *math;
 
   unsigned int gsub_lookup_count;
   unsigned int gpos_lookup_count;
diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout.cc b/third_party/harfbuzz-ng/src/hb-ot-layout.cc
index 5cb1491..0501181a 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-layout.cc
+++ b/third_party/harfbuzz-ng/src/hb-ot-layout.cc
@@ -35,6 +35,7 @@
 #include "hb-ot-layout-gsub-table.hh"
 #include "hb-ot-layout-gpos-table.hh"
 #include "hb-ot-layout-jstf-table.hh"
+#include "hb-ot-layout-math-table.hh"
 
 #include "hb-ot-map-private.hh"
 
@@ -60,6 +61,10 @@
   layout->gpos_blob = OT::Sanitizer<OT::GPOS>::sanitize (face->reference_table (HB_OT_TAG_GPOS));
   layout->gpos = OT::Sanitizer<OT::GPOS>::lock_instance (layout->gpos_blob);
 
+  /* The MATH table is rarely used, so only try and load it in _get_math. */
+  layout->math_blob = NULL;
+  layout->math = NULL;
+
   {
     /*
      * The ugly business of blacklisting individual fonts' tables happen here!
@@ -177,6 +182,7 @@
   hb_blob_destroy (layout->gdef_blob);
   hb_blob_destroy (layout->gsub_blob);
   hb_blob_destroy (layout->gpos_blob);
+  hb_blob_destroy (layout->math_blob);
 
   free (layout);
 }
@@ -199,6 +205,30 @@
   if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GPOS);
   return *hb_ot_layout_from_face (face)->gpos;
 }
+static inline const OT::MATH&
+_get_math (hb_face_t *face)
+{
+  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::MATH);
+
+  hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
+
+retry:
+  const OT::MATH *math = (const OT::MATH *) hb_atomic_ptr_get (&layout->math);
+
+  if (unlikely (!math))
+  {
+    hb_blob_t *blob = OT::Sanitizer<OT::MATH>::sanitize (face->reference_table (HB_OT_TAG_MATH));
+    math = OT::Sanitizer<OT::MATH>::lock_instance (blob);
+    if (!hb_atomic_ptr_cmpexch (&layout->math, NULL, math))
+    {
+      hb_blob_destroy (blob);
+      goto retry;
+    }
+    layout->math_blob = blob;
+  }
+
+  return *math;
+}
 
 
 /*
@@ -1190,3 +1220,221 @@
 {
   apply_string<GSUBProxy> (c, lookup, accel);
 }
+
+
+/*
+ * MATH
+ */
+/* TODO Move this to hb-ot-math.cc and separate it from hb_ot_layout_t. */
+
+/**
+ * hb_ot_math_has_data:
+ * @face: #hb_face_t to test
+ *
+ * This function allows to verify the presence of an OpenType MATH table on the
+ * face. If so, such a table will be loaded into memory and sanitized. You can
+ * then safely call other functions for math layout and shaping.
+ *
+ * Return value: #TRUE if face has a MATH table and #FALSE otherwise
+ *
+ * Since: 1.3.3
+ **/
+hb_bool_t
+hb_ot_math_has_data (hb_face_t *face)
+{
+  return &_get_math (face) != &OT::Null(OT::MATH);
+}
+
+/**
+ * hb_ot_math_get_constant:
+ * @font: #hb_font_t from which to retrieve the value
+ * @constant: #hb_ot_math_constant_t the constant to retrieve
+ *
+ * This function returns the requested math constants as a #hb_position_t.
+ * If the request constant is HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN,
+ * HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN or
+ * HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN then the return value is
+ * actually an integer between 0 and 100 representing that percentage.
+ *
+ * Return value: the requested constant or 0
+ *
+ * Since: 1.3.3
+ **/
+hb_position_t
+hb_ot_math_get_constant (hb_font_t *font,
+			 hb_ot_math_constant_t constant)
+{
+  const OT::MATH &math = _get_math (font->face);
+  return math.get_constant(constant, font);
+}
+
+/**
+ * hb_ot_math_get_glyph_italics_correction:
+ * @font: #hb_font_t from which to retrieve the value
+ * @glyph: glyph index from which to retrieve the value
+ *
+ * Return value: the italics correction of the glyph or 0
+ *
+ * Since: 1.3.3
+ **/
+hb_position_t
+hb_ot_math_get_glyph_italics_correction (hb_font_t *font,
+					 hb_codepoint_t glyph)
+{
+  const OT::MATH &math = _get_math (font->face);
+  return math.get_math_glyph_info().get_italics_correction (glyph, font);
+}
+
+/**
+ * hb_ot_math_get_glyph_top_accent_attachment:
+ * @font: #hb_font_t from which to retrieve the value
+ * @glyph: glyph index from which to retrieve the value
+ *
+ * Return value: the top accent attachment of the glyph or 0
+ *
+ * Since: 1.3.3
+ **/
+hb_position_t
+hb_ot_math_get_glyph_top_accent_attachment (hb_font_t *font,
+					    hb_codepoint_t glyph)
+{
+  const OT::MATH &math = _get_math (font->face);
+  return math.get_math_glyph_info().get_top_accent_attachment (glyph, font);
+}
+
+/**
+ * hb_ot_math_is_glyph_extended_shape:
+ * @font: a #hb_font_t to test
+ * @glyph: a glyph index to test
+ *
+ * Return value: #TRUE if the glyph is an extended shape and #FALSE otherwise
+ *
+ * Since: 1.3.3
+ **/
+hb_bool_t
+hb_ot_math_is_glyph_extended_shape (hb_face_t *face,
+				    hb_codepoint_t glyph)
+{
+  const OT::MATH &math = _get_math (face);
+  return math.get_math_glyph_info().is_extended_shape (glyph);
+}
+
+/**
+ * hb_ot_math_get_glyph_kerning:
+ * @font: #hb_font_t from which to retrieve the value
+ * @glyph: glyph index from which to retrieve the value
+ * @kern: the #hb_ot_math_kern_t from which to retrieve the value
+ * @correction_height: the correction height to use to determine the kerning.
+ *
+ * This function tries to retrieve the MathKern table for the specified font,
+ * glyph and #hb_ot_math_kern_t. Then it browses the list of heights from the
+ * MathKern table to find one value that is greater or equal to specified
+ * correction_height. If one is found the corresponding value from the list of
+ * kerns is returned and otherwise the last kern value is returned.
+ *
+ * Return value: requested kerning or 0
+ *
+ * Since: 1.3.3
+ **/
+hb_position_t
+hb_ot_math_get_glyph_kerning (hb_font_t *font,
+			      hb_codepoint_t glyph,
+			      hb_ot_math_kern_t kern,
+			      hb_position_t correction_height)
+{
+  const OT::MATH &math = _get_math (font->face);
+  return math.get_math_glyph_info().get_kerning (glyph, kern, correction_height, font);
+}
+
+/**
+ * hb_ot_math_get_glyph_variants:
+ * @font: #hb_font_t from which to retrieve the values
+ * @glyph: index of the glyph to stretch
+ * @direction: direction of the stretching
+ * @start_offset: offset of the first variant to retrieve
+ * @variants_count: maximum number of variants to retrieve after start_offset
+ * (IN) and actual number of variants retrieved (OUT)
+ * @variants: array of size at least @variants_count to store the result
+ *
+ * This function tries to retrieve the MathGlyphConstruction for the specified
+ * font, glyph and direction. Note that only the value of
+ * #HB_DIRECTION_IS_HORIZONTAL is considered. It provides the corresponding list
+ * of size variants as an array of hb_ot_math_glyph_variant_t structs.
+ *
+ * Return value: the total number of size variants available or 0
+ *
+ * Since: 1.3.3
+ **/
+unsigned int
+hb_ot_math_get_glyph_variants (hb_font_t *font,
+			       hb_codepoint_t glyph,
+			       hb_direction_t direction,
+			       unsigned int start_offset,
+			       unsigned int *variants_count, /* IN/OUT */
+			       hb_ot_math_glyph_variant_t *variants /* OUT */)
+{
+  const OT::MATH &math = _get_math (font->face);
+  return math.get_math_variants().get_glyph_variants (glyph, direction, font,
+						      start_offset,
+						      variants_count,
+						      variants);
+}
+
+/**
+ * hb_ot_math_get_min_connector_overlap:
+ * @font: #hb_font_t from which to retrieve the value
+ * @direction: direction of the stretching
+ *
+ * This function tries to retrieve the MathVariants table for the specified
+ * font and returns the minimum overlap of connecting glyphs to draw a glyph
+ * assembly in the specified direction. Note that only the value of
+ * #HB_DIRECTION_IS_HORIZONTAL is considered.
+ *
+ * Return value: requested min connector overlap or 0
+ *
+ * Since: 1.3.3
+ **/
+hb_position_t
+hb_ot_math_get_min_connector_overlap (hb_font_t *font,
+				      hb_direction_t direction)
+{
+  const OT::MATH &math = _get_math (font->face);
+  return math.get_math_variants().get_min_connector_overlap (direction, font);
+}
+
+/**
+ * hb_ot_math_get_glyph_assembly:
+ * @font: #hb_font_t from which to retrieve the values
+ * @glyph: index of the glyph to stretch
+ * @direction: direction of the stretching
+ * @start_offset: offset of the first glyph part to retrieve
+ * @parts_count: maximum number of glyph parts to retrieve after start_offset
+ * (IN) and actual number of parts retrieved (OUT)
+ * @parts: array of size at least @parts_count to store the result
+ * @italics_correction: italic correction of the glyph assembly
+ *
+ * This function tries to retrieve the GlyphAssembly for the specified font,
+ * glyph and direction. Note that only the value of #HB_DIRECTION_IS_HORIZONTAL
+ * is considered. It provides the information necessary to draw the glyph
+ * assembly as an array of #hb_ot_math_glyph_part_t.
+ *
+ * Return value: the total number of parts in the glyph assembly
+ *
+ * Since: 1.3.3
+ **/
+unsigned int
+hb_ot_math_get_glyph_assembly (hb_font_t *font,
+			       hb_codepoint_t glyph,
+			       hb_direction_t direction,
+			       unsigned int start_offset,
+			       unsigned int *parts_count, /* IN/OUT */
+			       hb_ot_math_glyph_part_t *parts, /* OUT */
+			       hb_position_t *italics_correction /* OUT */)
+{
+  const OT::MATH &math = _get_math (font->face);
+  return math.get_math_variants().get_glyph_parts (glyph, direction, font,
+						   start_offset,
+						   parts_count,
+						   parts,
+						   italics_correction);
+}
diff --git a/third_party/harfbuzz-ng/src/hb-ot-math.h b/third_party/harfbuzz-ng/src/hb-ot-math.h
new file mode 100644
index 0000000..521a5ca
--- /dev/null
+++ b/third_party/harfbuzz-ng/src/hb-ot-math.h
@@ -0,0 +1,209 @@
+/*
+ * Copyright © 2016  Igalia S.L.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Igalia Author(s): Frédéric Wang
+ */
+
+#ifndef HB_OT_H_IN
+#error "Include <hb-ot.h> instead."
+#endif
+
+#ifndef HB_OT_MATH_H
+#define HB_OT_MATH_H
+
+#include "hb.h"
+
+HB_BEGIN_DECLS
+
+
+/*
+ * MATH
+ */
+
+#define HB_OT_TAG_MATH HB_TAG('M','A','T','H')
+
+/* Use with hb_buffer_set_script() for math shaping. */
+#define HB_OT_MATH_SCRIPT HB_TAG('m','a','t','h')
+
+/* Types */
+
+/**
+ * hb_ot_math_constant_t:
+ *
+ * Since: 1.3.3
+ */
+typedef enum {
+  HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN = 0,
+  HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN = 1,
+  HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT = 2,
+  HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT = 3,
+  HB_OT_MATH_CONSTANT_MATH_LEADING = 4,
+  HB_OT_MATH_CONSTANT_AXIS_HEIGHT = 5,
+  HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT = 6,
+  HB_OT_MATH_CONSTANT_FLATTENED_ACCENT_BASE_HEIGHT = 7,
+  HB_OT_MATH_CONSTANT_SUBSCRIPT_SHIFT_DOWN = 8,
+  HB_OT_MATH_CONSTANT_SUBSCRIPT_TOP_MAX = 9,
+  HB_OT_MATH_CONSTANT_SUBSCRIPT_BASELINE_DROP_MIN = 10,
+  HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP = 11,
+  HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP_CRAMPED = 12,
+  HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MIN = 13,
+  HB_OT_MATH_CONSTANT_SUPERSCRIPT_BASELINE_DROP_MAX = 14,
+  HB_OT_MATH_CONSTANT_SUB_SUPERSCRIPT_GAP_MIN = 15,
+  HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT = 16,
+  HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT = 17,
+  HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN = 18,
+  HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN = 19,
+  HB_OT_MATH_CONSTANT_LOWER_LIMIT_GAP_MIN = 20,
+  HB_OT_MATH_CONSTANT_LOWER_LIMIT_BASELINE_DROP_MIN = 21,
+  HB_OT_MATH_CONSTANT_STACK_TOP_SHIFT_UP = 22,
+  HB_OT_MATH_CONSTANT_STACK_TOP_DISPLAY_STYLE_SHIFT_UP = 23,
+  HB_OT_MATH_CONSTANT_STACK_BOTTOM_SHIFT_DOWN = 24,
+  HB_OT_MATH_CONSTANT_STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN = 25,
+  HB_OT_MATH_CONSTANT_STACK_GAP_MIN = 26,
+  HB_OT_MATH_CONSTANT_STACK_DISPLAY_STYLE_GAP_MIN = 27,
+  HB_OT_MATH_CONSTANT_STRETCH_STACK_TOP_SHIFT_UP = 28,
+  HB_OT_MATH_CONSTANT_STRETCH_STACK_BOTTOM_SHIFT_DOWN = 29,
+  HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_ABOVE_MIN = 30,
+  HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_BELOW_MIN = 31,
+  HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_SHIFT_UP = 32,
+  HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP = 33,
+  HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_SHIFT_DOWN = 34,
+  HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN = 35,
+  HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_GAP_MIN = 36,
+  HB_OT_MATH_CONSTANT_FRACTION_NUM_DISPLAY_STYLE_GAP_MIN = 37,
+  HB_OT_MATH_CONSTANT_FRACTION_RULE_THICKNESS = 38,
+  HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_GAP_MIN = 39,
+  HB_OT_MATH_CONSTANT_FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN = 40,
+  HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP = 41,
+  HB_OT_MATH_CONSTANT_SKEWED_FRACTION_VERTICAL_GAP = 42,
+  HB_OT_MATH_CONSTANT_OVERBAR_VERTICAL_GAP = 43,
+  HB_OT_MATH_CONSTANT_OVERBAR_RULE_THICKNESS = 44,
+  HB_OT_MATH_CONSTANT_OVERBAR_EXTRA_ASCENDER = 45,
+  HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP = 46,
+  HB_OT_MATH_CONSTANT_UNDERBAR_RULE_THICKNESS = 47,
+  HB_OT_MATH_CONSTANT_UNDERBAR_EXTRA_DESCENDER = 48,
+  HB_OT_MATH_CONSTANT_RADICAL_VERTICAL_GAP = 49,
+  HB_OT_MATH_CONSTANT_RADICAL_DISPLAY_STYLE_VERTICAL_GAP = 50,
+  HB_OT_MATH_CONSTANT_RADICAL_RULE_THICKNESS = 51,
+  HB_OT_MATH_CONSTANT_RADICAL_EXTRA_ASCENDER = 52,
+  HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE = 53,
+  HB_OT_MATH_CONSTANT_RADICAL_KERN_AFTER_DEGREE = 54,
+  HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT = 55
+} hb_ot_math_constant_t;
+
+/**
+ * hb_ot_math_kern_t:
+ *
+ * Since: 1.3.3
+ */
+typedef enum {
+  HB_OT_MATH_KERN_TOP_RIGHT = 0,
+  HB_OT_MATH_KERN_TOP_LEFT = 1,
+  HB_OT_MATH_KERN_BOTTOM_RIGHT = 2,
+  HB_OT_MATH_KERN_BOTTOM_LEFT = 3
+} hb_ot_math_kern_t;
+
+/**
+ * hb_ot_math_glyph_variant_t:
+ *
+ * Since: 1.3.3
+ */
+typedef struct hb_ot_math_glyph_variant_t {
+  hb_codepoint_t glyph;
+  hb_position_t advance;
+} hb_ot_math_glyph_variant_t;
+
+/**
+ * hb_ot_math_glyph_part_flags_t:
+ *
+ * Since: 1.3.3
+ */
+typedef enum { /*< flags >*/
+  HB_MATH_GLYPH_PART_FLAG_EXTENDER	= 0x00000001u  /* Extender glyph */
+} hb_ot_math_glyph_part_flags_t;
+
+/**
+ * hb_ot_math_glyph_part_t:
+ *
+ * Since: 1.3.3
+ */
+typedef struct hb_ot_math_glyph_part_t {
+  hb_codepoint_t glyph;
+  hb_position_t start_connector_length;
+  hb_position_t end_connector_length;
+  hb_position_t full_advance;
+  hb_ot_math_glyph_part_flags_t flags;
+} hb_ot_math_glyph_part_t;
+
+/* Methods */
+
+HB_EXTERN hb_bool_t
+hb_ot_math_has_data (hb_face_t *face);
+
+HB_EXTERN hb_position_t
+hb_ot_math_get_constant (hb_font_t *font,
+			 hb_ot_math_constant_t constant);
+
+HB_EXTERN hb_position_t
+hb_ot_math_get_glyph_italics_correction (hb_font_t *font,
+					 hb_codepoint_t glyph);
+
+HB_EXTERN hb_position_t
+hb_ot_math_get_glyph_top_accent_attachment (hb_font_t *font,
+					    hb_codepoint_t glyph);
+
+HB_EXTERN hb_bool_t
+hb_ot_math_is_glyph_extended_shape (hb_face_t *face,
+				    hb_codepoint_t glyph);
+
+HB_EXTERN hb_position_t
+hb_ot_math_get_glyph_kerning (hb_font_t *font,
+			      hb_codepoint_t glyph,
+			      hb_ot_math_kern_t kern,
+			      hb_position_t correction_height);
+
+HB_EXTERN unsigned int
+hb_ot_math_get_glyph_variants (hb_font_t *font,
+			       hb_codepoint_t glyph,
+			       hb_direction_t direction,
+			       unsigned int start_offset,
+			       unsigned int *variants_count, /* IN/OUT */
+			       hb_ot_math_glyph_variant_t *variants /* OUT */);
+
+HB_EXTERN hb_position_t
+hb_ot_math_get_min_connector_overlap (hb_font_t *font,
+				      hb_direction_t direction);
+
+HB_EXTERN unsigned int
+hb_ot_math_get_glyph_assembly (hb_font_t *font,
+			       hb_codepoint_t glyph,
+			       hb_direction_t direction,
+			       unsigned int start_offset,
+			       unsigned int *parts_count, /* IN/OUT */
+			       hb_ot_math_glyph_part_t *parts, /* OUT */
+			       hb_position_t *italics_correction /* OUT */);
+
+
+HB_END_DECLS
+
+#endif /* HB_OT_MATH_H */
diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-myanmar-machine.hh b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-myanmar-machine.hh
index d2fe742..29fdf9a 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-myanmar-machine.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-myanmar-machine.hh
@@ -1,5 +1,5 @@
 
-#line 1 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 1 "hb-ot-shape-complex-myanmar-machine.rl"
 /*
  * Copyright © 2011,2012  Google, Inc.
  *
@@ -32,7 +32,7 @@
 #include "hb-private.hh"
 
 
-#line 36 "../../src/hb-ot-shape-complex-myanmar-machine.hh.tmp"
+#line 36 "hb-ot-shape-complex-myanmar-machine.hh"
 static const unsigned char _myanmar_syllable_machine_trans_keys[] = {
 	1u, 31u, 3u, 30u, 5u, 29u, 5u, 8u, 5u, 29u, 3u, 25u, 5u, 25u, 5u, 25u, 
 	3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 1u, 16u, 3u, 29u, 3u, 29u, 3u, 29u, 
@@ -261,11 +261,11 @@
 static const int myanmar_syllable_machine_en_main = 0;
 
 
-#line 36 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 36 "hb-ot-shape-complex-myanmar-machine.rl"
 
 
 
-#line 93 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 93 "hb-ot-shape-complex-myanmar-machine.rl"
 
 
 #define found_syllable(syllable_type) \
@@ -285,7 +285,7 @@
   int cs;
   hb_glyph_info_t *info = buffer->info;
   
-#line 289 "../../src/hb-ot-shape-complex-myanmar-machine.hh.tmp"
+#line 289 "hb-ot-shape-complex-myanmar-machine.hh"
 	{
 	cs = myanmar_syllable_machine_start;
 	ts = 0;
@@ -293,7 +293,7 @@
 	act = 0;
 	}
 
-#line 114 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 114 "hb-ot-shape-complex-myanmar-machine.rl"
 
 
   p = 0;
@@ -302,7 +302,7 @@
   unsigned int last = 0;
   unsigned int syllable_serial = 1;
   
-#line 306 "../../src/hb-ot-shape-complex-myanmar-machine.hh.tmp"
+#line 306 "hb-ot-shape-complex-myanmar-machine.hh"
 	{
 	int _slen;
 	int _trans;
@@ -316,7 +316,7 @@
 #line 1 "NONE"
 	{ts = p;}
 	break;
-#line 320 "../../src/hb-ot-shape-complex-myanmar-machine.hh.tmp"
+#line 320 "hb-ot-shape-complex-myanmar-machine.hh"
 	}
 
 	_keys = _myanmar_syllable_machine_trans_keys + (cs<<1);
@@ -335,38 +335,38 @@
 
 	switch ( _myanmar_syllable_machine_trans_actions[_trans] ) {
 	case 7:
-#line 85 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 85 "hb-ot-shape-complex-myanmar-machine.rl"
 	{te = p+1;{ found_syllable (consonant_syllable); }}
 	break;
 	case 5:
-#line 86 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 86 "hb-ot-shape-complex-myanmar-machine.rl"
 	{te = p+1;{ found_syllable (non_myanmar_cluster); }}
 	break;
 	case 10:
-#line 87 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 87 "hb-ot-shape-complex-myanmar-machine.rl"
 	{te = p+1;{ found_syllable (punctuation_cluster); }}
 	break;
 	case 4:
-#line 88 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 88 "hb-ot-shape-complex-myanmar-machine.rl"
 	{te = p+1;{ found_syllable (broken_cluster); }}
 	break;
 	case 3:
-#line 89 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 89 "hb-ot-shape-complex-myanmar-machine.rl"
 	{te = p+1;{ found_syllable (non_myanmar_cluster); }}
 	break;
 	case 6:
-#line 85 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 85 "hb-ot-shape-complex-myanmar-machine.rl"
 	{te = p;p--;{ found_syllable (consonant_syllable); }}
 	break;
 	case 8:
-#line 88 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 88 "hb-ot-shape-complex-myanmar-machine.rl"
 	{te = p;p--;{ found_syllable (broken_cluster); }}
 	break;
 	case 9:
-#line 89 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 89 "hb-ot-shape-complex-myanmar-machine.rl"
 	{te = p;p--;{ found_syllable (non_myanmar_cluster); }}
 	break;
-#line 370 "../../src/hb-ot-shape-complex-myanmar-machine.hh.tmp"
+#line 370 "hb-ot-shape-complex-myanmar-machine.hh"
 	}
 
 _again:
@@ -375,7 +375,7 @@
 #line 1 "NONE"
 	{ts = 0;}
 	break;
-#line 379 "../../src/hb-ot-shape-complex-myanmar-machine.hh.tmp"
+#line 379 "hb-ot-shape-complex-myanmar-machine.hh"
 	}
 
 	if ( ++p != pe )
@@ -391,7 +391,7 @@
 
 	}
 
-#line 123 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 123 "hb-ot-shape-complex-myanmar-machine.rl"
 
 }
 
diff --git a/third_party/harfbuzz-ng/src/hb-ot.h b/third_party/harfbuzz-ng/src/hb-ot.h
index 47c92a5..113e37b 100644
--- a/third_party/harfbuzz-ng/src/hb-ot.h
+++ b/third_party/harfbuzz-ng/src/hb-ot.h
@@ -32,6 +32,7 @@
 
 #include "hb-ot-font.h"
 #include "hb-ot-layout.h"
+#include "hb-ot-math.h"
 #include "hb-ot-tag.h"
 #include "hb-ot-shape.h"
 
diff --git a/third_party/harfbuzz-ng/src/hb-version.h b/third_party/harfbuzz-ng/src/hb-version.h
index 42148a77..65359fdc 100644
--- a/third_party/harfbuzz-ng/src/hb-version.h
+++ b/third_party/harfbuzz-ng/src/hb-version.h
@@ -38,9 +38,9 @@
 
 #define HB_VERSION_MAJOR 1
 #define HB_VERSION_MINOR 3
-#define HB_VERSION_MICRO 1
+#define HB_VERSION_MICRO 4
 
-#define HB_VERSION_STRING "1.3.1"
+#define HB_VERSION_STRING "1.3.4"
 
 #define HB_VERSION_ATLEAST(major,minor,micro) \
 	((major)*10000+(minor)*100+(micro) <= \
diff --git a/ui/views/controls/button/custom_button.cc b/ui/views/controls/button/custom_button.cc
index 21ebca3d..115dcb4 100644
--- a/ui/views/controls/button/custom_button.cc
+++ b/ui/views/controls/button/custom_button.cc
@@ -139,6 +139,7 @@
     GetInkDrop()->SetHovered(should_enter_hover_state);
   } else {
     SetState(STATE_DISABLED);
+    GetInkDrop()->SetHovered(false);
   }
 }
 
diff --git a/ui/views/controls/button/custom_button_unittest.cc b/ui/views/controls/button/custom_button_unittest.cc
index 889bc7be..14256415 100644
--- a/ui/views/controls/button/custom_button_unittest.cc
+++ b/ui/views/controls/button/custom_button_unittest.cc
@@ -465,6 +465,19 @@
   EXPECT_TRUE(button()->pressed());
 }
 
+TEST_F(CustomButtonTest, HideInkDropHighlightOnDisable) {
+  TestInkDrop* ink_drop = new TestInkDrop();
+  CreateButtonWithInkDrop(base::WrapUnique(ink_drop), false);
+
+  ui::test::EventGenerator generator(widget()->GetNativeWindow());
+  generator.MoveMouseToInHost(10, 10);
+  EXPECT_TRUE(ink_drop->is_hovered());
+  button()->SetEnabled(false);
+  EXPECT_FALSE(ink_drop->is_hovered());
+  button()->SetEnabled(true);
+  EXPECT_TRUE(ink_drop->is_hovered());
+}
+
 TEST_F(CustomButtonTest, InkDropAfterTryingToShowContextMenu) {
   TestInkDrop* ink_drop = new TestInkDrop();
   CreateButtonWithInkDrop(base::WrapUnique(ink_drop), false);