diff --git a/base/BUILD.gn b/base/BUILD.gn
index 70b91945..7abc68c 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -1515,6 +1515,7 @@
       "mac/scoped_typeref.h",
       "power_monitor/power_monitor_device_source_mac.mm",
       "time/time_conversion_posix.cc",
+      "time/time_exploded_posix.cc",
       "time/time_mac.cc",
     ]
 
diff --git a/base/time/time.h b/base/time/time.h
index 2befad3..017b9101 100644
--- a/base/time/time.h
+++ b/base/time/time.h
@@ -460,6 +460,31 @@
   static constexpr int64_t kQPCOverflowThreshold = INT64_C(0x8637BD05AF7);
 #endif
 
+// kExplodedMinYear and kExplodedMaxYear define the platform-specific limits
+// for values passed to FromUTCExploded() and FromLocalExploded(). Those
+// functions will return false if passed values outside these limits. The limits
+// are inclusive, meaning that the API should support all dates within a given
+// limit year.
+#if defined(OS_WIN)
+  static constexpr int kExplodedMinYear = 1601;
+  static constexpr int kExplodedMaxYear = 30827;
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+  static constexpr int kExplodedMinYear = 1902;
+  static constexpr int kExplodedMaxYear = std::numeric_limits<int>::max();
+#elif defined(OS_ANDROID)
+  // Though we use 64-bit time APIs on both 32 and 64 bit Android, some OS
+  // versions like KitKat (ARM but not x86 emulator) can't handle some early
+  // dates (e.g. before 1170). So we set min conservatively here.
+  static constexpr int kExplodedMinYear = 1902;
+  static constexpr int kExplodedMaxYear = std::numeric_limits<int>::max();
+#elif defined(OS_POSIX) && !defined(__LP64__) && !defined(OS_IOS)
+  static constexpr int kExplodedMinYear = 1970;
+  static constexpr int kExplodedMaxYear = 2037;
+#else
+  static constexpr int kExplodedMinYear = std::numeric_limits<int>::min();
+  static constexpr int kExplodedMaxYear = std::numeric_limits<int>::max();
+#endif
+
   // Represents an exploded time that can be formatted nicely. This is kind of
   // like the Win32 SYSTEMTIME structure or the Unix "struct tm" with a few
   // additions and changes to prevent errors.
diff --git a/base/time/time_exploded_posix.cc b/base/time/time_exploded_posix.cc
index 9100d05..627c6b4f8 100644
--- a/base/time/time_exploded_posix.cc
+++ b/base/time/time_exploded_posix.cc
@@ -24,10 +24,8 @@
 #include "base/os_compat_nacl.h"
 #endif
 
-// Ensure the Mac build does not include this module. Instead, non-POSIX
-// implementation is used to support Time::Exploded.
 #if defined(OS_MACOSX)
-#error "This implementation is for POSIX platforms other than Mac."
+static_assert(sizeof(time_t) >= 8, "Y2038 problem!");
 #endif
 
 namespace {
diff --git a/base/time/time_mac.cc b/base/time/time_mac.cc
index c4f8315..fdac0c4 100644
--- a/base/time/time_mac.cc
+++ b/base/time/time_mac.cc
@@ -171,6 +171,13 @@
   return Now();
 }
 
+// Note: These implementations of Time::FromExploded() and Time::Explode() are
+// only used on iOS now. Since Mac is now always 64-bit, we can use the POSIX
+// versions of these functions as time_t is not capped at year 2038 on 64-bit
+// builds. The POSIX functions are preferred since they don't suffer from some
+// performance problems that are present in these implementations.
+// See crbug.com/781601 for more details.
+#if defined(OS_IOS)
 // static
 bool Time::FromExploded(bool is_local, const Exploded& exploded, Time* time) {
   base::ScopedCFTypeRef<CFTimeZoneRef> time_zone(
@@ -258,6 +265,7 @@
                            (microsecond - kMicrosecondsPerMillisecond + 1) /
                                kMicrosecondsPerMillisecond;
 }
+#endif  // OS_IOS
 
 // TimeTicks ------------------------------------------------------------------
 
diff --git a/base/time/time_unittest.cc b/base/time/time_unittest.cc
index 8a82d9ee..a30c450 100644
--- a/base/time/time_unittest.cc
+++ b/base/time/time_unittest.cc
@@ -631,6 +631,41 @@
 }
 #endif  // OS_ANDROID
 
+TEST_F(TimeTest, FromExploded_MinMax) {
+  Time::Exploded exploded = {0};
+  exploded.month = 1;
+  exploded.day_of_month = 1;
+
+  Time parsed_time;
+
+  if (Time::kExplodedMinYear != std::numeric_limits<int>::min()) {
+    exploded.year = Time::kExplodedMinYear;
+    EXPECT_TRUE(Time::FromUTCExploded(exploded, &parsed_time));
+#if !defined(OS_WIN)
+    // On Windows, January 1, 1601 00:00:00 is actually the null time.
+    EXPECT_FALSE(parsed_time.is_null());
+#endif
+
+#if !defined(OS_ANDROID)
+    // The dates earlier than |kExplodedMinYear| that don't work are OS version
+    // dependent on Android.
+    exploded.year--;
+    EXPECT_FALSE(Time::FromUTCExploded(exploded, &parsed_time));
+    EXPECT_TRUE(parsed_time.is_null());
+#endif
+  }
+
+  if (Time::kExplodedMaxYear != std::numeric_limits<int>::max()) {
+    exploded.year = Time::kExplodedMaxYear;
+    EXPECT_TRUE(Time::FromUTCExploded(exploded, &parsed_time));
+    EXPECT_FALSE(parsed_time.is_null());
+
+    exploded.year++;
+    EXPECT_FALSE(Time::FromUTCExploded(exploded, &parsed_time));
+    EXPECT_TRUE(parsed_time.is_null());
+  }
+}
+
 TEST(TimeTicks, Deltas) {
   for (int index = 0; index < 50; index++) {
     TimeTicks ticks_start = TimeTicks::Now();
diff --git a/build/config/fuchsia/rules.gni b/build/config/fuchsia/rules.gni
index ef67ea4..1defe2c6 100644
--- a/build/config/fuchsia/rules.gni
+++ b/build/config/fuchsia/rules.gni
@@ -126,10 +126,12 @@
                            [
                              "testonly",
                              "exe_target",
+                             "data_deps",
                            ])
     runner_script = "exe_runner.py"
-    data_deps = [
-      exe_target,
-    ]
+    if (!defined(data_deps)) {
+      data_deps = []
+    }
+    data_deps += [ exe_target ]
   }
 }
diff --git a/cc/paint/BUILD.gn b/cc/paint/BUILD.gn
index 037891d4..7efa424 100644
--- a/cc/paint/BUILD.gn
+++ b/cc/paint/BUILD.gn
@@ -25,6 +25,8 @@
     "paint_export.h",
     "paint_flags.cc",
     "paint_flags.h",
+    "paint_font.cc",
+    "paint_font.h",
     "paint_image.cc",
     "paint_image.h",
     "paint_image_builder.cc",
@@ -43,6 +45,12 @@
     "paint_recorder.h",
     "paint_shader.cc",
     "paint_shader.h",
+    "paint_text_blob.cc",
+    "paint_text_blob.h",
+    "paint_text_blob_builder.cc",
+    "paint_text_blob_builder.h",
+    "paint_typeface.cc",
+    "paint_typeface.h",
     "record_paint_canvas.cc",
     "record_paint_canvas.h",
     "scoped_image_flags.cc",
diff --git a/cc/paint/paint_canvas.h b/cc/paint/paint_canvas.h
index 3d35c02..e62fee07e 100644
--- a/cc/paint/paint_canvas.h
+++ b/cc/paint/paint_canvas.h
@@ -11,6 +11,7 @@
 #include "build/build_config.h"
 #include "cc/paint/paint_export.h"
 #include "cc/paint/paint_image.h"
+#include "cc/paint/paint_text_blob.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 
 namespace cc {
@@ -139,7 +140,7 @@
     drawBitmap(bitmap, left, top, nullptr);
   }
 
-  virtual void drawTextBlob(sk_sp<SkTextBlob> blob,
+  virtual void drawTextBlob(scoped_refptr<PaintTextBlob> blob,
                             SkScalar x,
                             SkScalar y,
                             const PaintFlags& flags) = 0;
diff --git a/cc/paint/paint_font.cc b/cc/paint/paint_font.cc
new file mode 100644
index 0000000..d04d40b0
--- /dev/null
+++ b/cc/paint/paint_font.cc
@@ -0,0 +1,65 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/paint/paint_font.h"
+
+#include "cc/paint/paint_export.h"
+#include "cc/paint/paint_typeface.h"
+#include "third_party/skia/include/core/SkPaint.h"
+
+namespace cc {
+
+PaintFont::PaintFont() = default;
+PaintFont::~PaintFont() = default;
+
+void PaintFont::SetTextEncoding(SkPaint::TextEncoding encoding) {
+  sk_paint_.setTextEncoding(encoding);
+}
+
+void PaintFont::SetAntiAlias(bool use_anti_alias) {
+  sk_paint_.setAntiAlias(use_anti_alias);
+}
+
+void PaintFont::SetHinting(SkPaint::Hinting hinting) {
+  sk_paint_.setHinting(hinting);
+}
+
+void PaintFont::SetEmbeddedBitmapText(bool use_bitmaps) {
+  sk_paint_.setEmbeddedBitmapText(use_bitmaps);
+}
+
+void PaintFont::SetAutohinted(bool use_auto_hint) {
+  sk_paint_.setAutohinted(use_auto_hint);
+}
+
+void PaintFont::SetLcdRenderText(bool lcd_text) {
+  sk_paint_.setLCDRenderText(lcd_text);
+}
+
+void PaintFont::SetSubpixelText(bool subpixel_text) {
+  sk_paint_.setSubpixelText(subpixel_text);
+}
+
+void PaintFont::SetTextSize(SkScalar size) {
+  sk_paint_.setTextSize(size);
+}
+
+void PaintFont::SetTypeface(const PaintTypeface& typeface) {
+  typeface_ = typeface;
+  sk_paint_.setTypeface(typeface.ToSkTypeface());
+}
+
+void PaintFont::SetFakeBoldText(bool bold_text) {
+  sk_paint_.setFakeBoldText(bold_text);
+}
+
+void PaintFont::SetTextSkewX(SkScalar skew) {
+  sk_paint_.setTextSkewX(skew);
+}
+
+void PaintFont::SetFlags(uint32_t flags) {
+  sk_paint_.setFlags(flags);
+}
+
+}  // namespace cc
diff --git a/cc/paint/paint_font.h b/cc/paint/paint_font.h
new file mode 100644
index 0000000..bb947a0
--- /dev/null
+++ b/cc/paint/paint_font.h
@@ -0,0 +1,44 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_PAINT_PAINT_FONT_H_
+#define CC_PAINT_PAINT_FONT_H_
+
+#include "cc/paint/paint_export.h"
+#include "cc/paint/paint_typeface.h"
+#include "third_party/skia/include/core/SkPaint.h"
+
+namespace cc {
+
+class CC_PAINT_EXPORT PaintFont {
+ public:
+  PaintFont();
+  ~PaintFont();
+
+  void SetTextEncoding(SkPaint::TextEncoding encoding);
+  void SetAntiAlias(bool use_anti_alias);
+  void SetHinting(SkPaint::Hinting hinting);
+  void SetEmbeddedBitmapText(bool use_bitmaps);
+  void SetAutohinted(bool use_auto_hint);
+  void SetLcdRenderText(bool lcd_text);
+  void SetSubpixelText(bool subpixel_text);
+  void SetTextSize(SkScalar size);
+  void SetTypeface(const PaintTypeface& typeface);
+  void SetFakeBoldText(bool bold_text);
+  void SetTextSkewX(SkScalar skew);
+  void SetFlags(uint32_t flags);
+
+  uint32_t flags() const { return sk_paint_.getFlags(); }
+
+  const PaintTypeface& typeface() const { return typeface_; }
+  const SkPaint& ToSkPaint() const { return sk_paint_; }
+
+ private:
+  PaintTypeface typeface_;
+  SkPaint sk_paint_;
+};
+
+}  // namespace cc
+
+#endif  // CC_PAINT_PAINT_FONT_H_
diff --git a/cc/paint/paint_op_buffer.cc b/cc/paint/paint_op_buffer.cc
index 5e927be..849be691 100644
--- a/cc/paint/paint_op_buffer.cc
+++ b/cc/paint/paint_op_buffer.cc
@@ -1188,7 +1188,7 @@
                                      SkCanvas* canvas,
                                      const PlaybackParams& params) {
   SkPaint paint = flags->ToSkPaint();
-  canvas->drawTextBlob(op->blob.get(), op->x, op->y, paint);
+  canvas->drawTextBlob(op->blob->ToSkTextBlob().get(), op->x, op->y, paint);
 }
 
 void RestoreOp::Raster(const RestoreOp* op,
@@ -1382,7 +1382,8 @@
       return false;
     case PaintOpType::DrawTextBlob: {
       auto* text_op = static_cast<const DrawTextBlobOp*>(op);
-      *rect = text_op->blob->bounds().makeOffset(text_op->x, text_op->y);
+      *rect = text_op->blob->ToSkTextBlob()->bounds().makeOffset(text_op->x,
+                                                                 text_op->y);
       rect->sort();
       return true;
     }
@@ -1548,11 +1549,11 @@
 
 DrawTextBlobOp::DrawTextBlobOp() = default;
 
-DrawTextBlobOp::DrawTextBlobOp(sk_sp<SkTextBlob> blob,
+DrawTextBlobOp::DrawTextBlobOp(scoped_refptr<PaintTextBlob> paint_blob,
                                SkScalar x,
                                SkScalar y,
                                const PaintFlags& flags)
-    : PaintOpWithFlags(flags), blob(std::move(blob)), x(x), y(y) {}
+    : PaintOpWithFlags(flags), blob(std::move(paint_blob)), x(x), y(y) {}
 
 DrawTextBlobOp::~DrawTextBlobOp() = default;
 
diff --git a/cc/paint/paint_op_buffer.h b/cc/paint/paint_op_buffer.h
index 5deeb023..6a18a37 100644
--- a/cc/paint/paint_op_buffer.h
+++ b/cc/paint/paint_op_buffer.h
@@ -572,7 +572,7 @@
  public:
   static constexpr PaintOpType kType = PaintOpType::DrawTextBlob;
   static constexpr bool kIsDrawOp = true;
-  DrawTextBlobOp(sk_sp<SkTextBlob> blob,
+  DrawTextBlobOp(scoped_refptr<PaintTextBlob> blob,
                  SkScalar x,
                  SkScalar y,
                  const PaintFlags& flags);
@@ -584,7 +584,7 @@
   bool IsValid() const { return flags.IsValid(); }
   HAS_SERIALIZATION_FUNCTIONS();
 
-  sk_sp<SkTextBlob> blob;
+  scoped_refptr<PaintTextBlob> blob;
   SkScalar x;
   SkScalar y;
 
diff --git a/cc/paint/paint_op_buffer_unittest.cc b/cc/paint/paint_op_buffer_unittest.cc
index 56bdab6..f2049942c 100644
--- a/cc/paint/paint_op_buffer_unittest.cc
+++ b/cc/paint/paint_op_buffer_unittest.cc
@@ -1213,24 +1213,58 @@
      SkPoint::Make(9, 9), SkPoint::Make(50, 50), SkPoint::Make(100, 100)},
 };
 
-std::vector<sk_sp<SkTextBlob>> test_blobs = {
+std::vector<std::vector<PaintTypeface>> test_typefaces = {
+    [] { return std::vector<PaintTypeface>{PaintTypeface::TestTypeface()}; }(),
+    [] {
+      return std::vector<PaintTypeface>{PaintTypeface::TestTypeface(),
+                                        PaintTypeface::TestTypeface()};
+    }(),
+};
+
+std::vector<scoped_refptr<PaintTextBlob>> test_paint_blobs = {
     [] {
       SkPaint font;
       font.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+      font.setTypeface(test_typefaces[0][0].ToSkTypeface());
 
       SkTextBlobBuilder builder;
-      builder.allocRun(font, 5, 1.2f, 2.3f, &test_rects[0]);
-      return builder.make();
+      int glyph_count = 5;
+      const auto& run =
+          builder.allocRun(font, glyph_count, 1.2f, 2.3f, &test_rects[0]);
+      // allocRun() allocates only the glyph buffer.
+      std::fill(run.glyphs, run.glyphs + glyph_count, 0);
+      return base::MakeRefCounted<PaintTextBlob>(builder.make(),
+                                                 test_typefaces[0]);
     }(),
     [] {
       SkPaint font;
       font.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+      font.setTypeface(test_typefaces[1][0].ToSkTypeface());
 
       SkTextBlobBuilder builder;
-      builder.allocRun(font, 5, 1.2f, 2.3f, &test_rects[0]);
-      builder.allocRunPos(font, 16, &test_rects[1]);
-      builder.allocRunPosH(font, 8, 0, &test_rects[2]);
-      return builder.make();
+      int glyph_count = 5;
+      const auto& run1 =
+          builder.allocRun(font, glyph_count, 1.2f, 2.3f, &test_rects[0]);
+      // allocRun() allocates only the glyph buffer.
+      std::fill(run1.glyphs, run1.glyphs + glyph_count, 0);
+
+      glyph_count = 16;
+      const auto& run2 = builder.allocRunPos(font, glyph_count, &test_rects[1]);
+      // allocRun() allocates the glyph buffer, and 2 scalars per glyph for the
+      // pos buffer.
+      std::fill(run2.glyphs, run2.glyphs + glyph_count, 0);
+      std::fill(run2.pos, run2.pos + glyph_count * 2, 0);
+
+      font.setTypeface(test_typefaces[1][1].ToSkTypeface());
+      glyph_count = 8;
+      const auto& run3 =
+          builder.allocRunPosH(font, glyph_count, 0, &test_rects[2]);
+      // allocRun() allocates the glyph buffer, and 1 scalar per glyph for the
+      // pos buffer.
+      std::fill(run3.glyphs, run3.glyphs + glyph_count, 0);
+      std::fill(run3.pos, run3.pos + glyph_count, 0);
+      return base::MakeRefCounted<PaintTextBlob>(builder.make(),
+                                                 test_typefaces[1]);
     }(),
 };
 
@@ -1513,10 +1547,10 @@
 }
 
 void PushDrawTextBlobOps(PaintOpBuffer* buffer) {
-  size_t len = std::min(std::min(test_blobs.size(), test_flags.size()),
+  size_t len = std::min(std::min(test_paint_blobs.size(), test_flags.size()),
                         test_floats.size() - 1);
   for (size_t i = 0; i < len; ++i) {
-    buffer->push<DrawTextBlobOp>(test_blobs[i], test_floats[i],
+    buffer->push<DrawTextBlobOp>(test_paint_blobs[i], test_floats[i],
                                  test_floats[i + 1], test_flags[i]);
   }
   ValidateOps<DrawTextBlobOp>(buffer);
@@ -1747,27 +1781,18 @@
   EXPECT_EQ(original->x, written->x);
   EXPECT_EQ(original->y, written->y);
 
-  // TODO(enne): implement SkTextBlob serialization: http://crbug.com/737629
-  if (!original->blob || !written->blob)
-    return;
+  ASSERT_TRUE(*original->blob);
+  ASSERT_TRUE(*written->blob);
 
-  ASSERT_TRUE(original->blob);
-  ASSERT_TRUE(written->blob);
+  SkBinaryWriteBuffer original_flattened;
+  original->blob->ToSkTextBlob()->flatten(original_flattened);
+  std::vector<char> original_mem(original_flattened.bytesWritten());
+  original_flattened.writeToMemory(original_mem.data());
 
-  // No text blob operator==, so flatten them both and compare.
-  size_t max_size = original->skip;
-
-  std::vector<char> original_mem;
-  original_mem.resize(max_size);
-  SkBinaryWriteBuffer original_flattened(&original_mem[0], max_size);
-  original->blob->flatten(original_flattened);
-  original_mem.resize(original_flattened.bytesWritten());
-
-  std::vector<char> written_mem;
-  written_mem.resize(max_size);
-  SkBinaryWriteBuffer written_flattened(&written_mem[0], max_size);
-  written->blob->flatten(written_flattened);
-  written_mem.resize(written_flattened.bytesWritten());
+  SkBinaryWriteBuffer written_flattened;
+  written->blob->ToSkTextBlob()->flatten(written_flattened);
+  std::vector<char> written_mem(written_flattened.bytesWritten());
+  written_flattened.writeToMemory(written_mem.data());
 
   ASSERT_EQ(original_mem.size(), written_mem.size());
   EXPECT_EQ(original_mem, written_mem);
@@ -2565,7 +2590,10 @@
     auto* op = static_cast<DrawTextBlobOp*>(base_op);
 
     ASSERT_TRUE(PaintOp::GetBounds(op, &rect));
-    EXPECT_EQ(rect, op->blob->bounds().makeOffset(op->x, op->y).makeSorted());
+    EXPECT_EQ(rect, op->blob->ToSkTextBlob()
+                        ->bounds()
+                        .makeOffset(op->x, op->y)
+                        .makeSorted());
   }
 }
 
diff --git a/cc/paint/paint_op_reader.cc b/cc/paint/paint_op_reader.cc
index 19d64fe..32fb8b9 100644
--- a/cc/paint/paint_op_reader.cc
+++ b/cc/paint/paint_op_reader.cc
@@ -5,6 +5,7 @@
 #include "cc/paint/paint_op_reader.h"
 
 #include <stddef.h>
+#include <algorithm>
 
 #include "cc/paint/paint_flags.h"
 #include "cc/paint/paint_op_buffer.h"
@@ -17,9 +18,34 @@
 namespace cc {
 namespace {
 
+uint32_t kMaxTypefacesCount = 128;
+size_t kMaxFilenameSize = 1024;
+size_t kMaxFamilyNameSize = 128;
+
 // If we have more than this many colors, abort deserialization.
 const size_t kMaxShaderColorsSupported = 10000;
 
+struct TypefacesCatalog {
+  const std::vector<PaintTypeface>* typefaces;
+  bool had_null = false;
+};
+
+sk_sp<SkTypeface> ResolveTypeface(uint32_t id, void* ctx) {
+  TypefacesCatalog* catalog = static_cast<TypefacesCatalog*>(ctx);
+  auto typeface_it = std::find_if(
+      catalog->typefaces->begin(), catalog->typefaces->end(),
+      [id](const PaintTypeface& typeface) { return typeface.sk_id() == id; });
+  // TODO(vmpstr): The !*typeface check is here because not all typefaces are
+  // supported right now. Instead of making the reader invalid during the
+  // typeface deserialization, which results in an invalid op, instead just make
+  // the textblob be null by setting |had_null| to true.
+  if (typeface_it == catalog->typefaces->end() || !*typeface_it) {
+    catalog->had_null = true;
+    return nullptr;
+  }
+  return typeface_it->ToSkTypeface();
+}
+
 bool IsValidPaintShaderType(PaintShader::Type type) {
   return static_cast<uint8_t>(type) <
          static_cast<uint8_t>(PaintShader::Type::kShaderCount);
@@ -212,8 +238,112 @@
   remaining_bytes_ -= bytes;
 }
 
-void PaintOpReader::Read(sk_sp<SkTextBlob>* blob) {
-  // TODO(enne): implement SkTextBlob serialization: http://crbug.com/737629
+void PaintOpReader::Read(std::vector<PaintTypeface>* typefaces) {
+  uint32_t typefaces_count;
+  ReadSimple(&typefaces_count);
+  if (!valid_ || typefaces_count > kMaxTypefacesCount) {
+    valid_ = false;
+    return;
+  }
+  typefaces->reserve(typefaces_count);
+  for (uint32_t i = 0; i < typefaces_count; ++i) {
+    SkFontID id;
+    uint8_t type;
+    PaintTypeface typeface;
+    ReadSimple(&id);
+    ReadSimple(&type);
+    if (!valid_)
+      return;
+    switch (static_cast<PaintTypeface::Type>(type)) {
+      case PaintTypeface::Type::kTestTypeface:
+        typeface = PaintTypeface::TestTypeface();
+        break;
+      case PaintTypeface::Type::kSkTypeface:
+        // TODO(vmpstr): This shouldn't ever happen once everything is
+        // implemented. So this should be a failure (ie |valid_| = false).
+        break;
+      case PaintTypeface::Type::kFontConfigInterfaceIdAndTtcIndex: {
+        int font_config_interface_id;
+        int ttc_index;
+        ReadSimple(&font_config_interface_id);
+        ReadSimple(&ttc_index);
+        typeface = PaintTypeface::FromFontConfigInterfaceIdAndTtcIndex(
+            font_config_interface_id, ttc_index);
+        break;
+      }
+      case PaintTypeface::Type::kFilenameAndTtcIndex: {
+        size_t size;
+        ReadSimple(&size);
+        if (!valid_ || size > kMaxFilenameSize) {
+          valid_ = false;
+          return;
+        }
+
+        std::unique_ptr<char[]> buffer(new char[size]);
+        ReadData(size, buffer.get());
+        std::string filename(buffer.get(), size);
+
+        int ttc_index;
+        ReadSimple(&ttc_index);
+        typeface = PaintTypeface::FromFilenameAndTtcIndex(filename, ttc_index);
+        break;
+      }
+      case PaintTypeface::Type::kFamilyNameAndFontStyle: {
+        size_t size;
+        ReadSimple(&size);
+        if (!valid_ || size > kMaxFamilyNameSize) {
+          valid_ = false;
+          return;
+        }
+
+        std::unique_ptr<char[]> buffer(new char[size]);
+        ReadData(size, buffer.get());
+        std::string family_name(buffer.get(), size);
+
+        int weight;
+        int width;
+        SkFontStyle::Slant slant;
+        ReadSimple(&weight);
+        ReadSimple(&width);
+        ReadSimple(&slant);
+        typeface = PaintTypeface::FromFamilyNameAndFontStyle(
+            family_name, SkFontStyle(weight, width, slant));
+        break;
+      }
+    }
+    typeface.SetSkId(id);
+    typefaces->emplace_back(std::move(typeface));
+  }
+}
+
+void PaintOpReader::Read(const std::vector<PaintTypeface>& typefaces,
+                         sk_sp<SkTextBlob>* blob) {
+  sk_sp<SkData> data;
+  Read(&data);
+  if (!data || !valid_)
+    return;
+
+  TypefacesCatalog catalog;
+  catalog.typefaces = &typefaces;
+  *blob = SkTextBlob::Deserialize(data->data(), data->size(), &ResolveTypeface,
+                                  &catalog);
+  if (catalog.had_null)
+    *blob = nullptr;
+}
+
+void PaintOpReader::Read(scoped_refptr<PaintTextBlob>* paint_blob) {
+  std::vector<PaintTypeface> typefaces;
+  sk_sp<SkTextBlob> blob;
+
+  Read(&typefaces);
+  Read(typefaces, &blob);
+  // TODO(vmpstr): If we couldn't serialize |blob|, we should make |paint_blob|
+  // nullptr. However, this causes GL errors right now, because not all
+  // typefaces are serialized. Fix this once we serialize everything. For now
+  // the behavior is that the |paint_blob| op exists and is valid, but
+  // internally it has a nullptr SkTextBlob which skia ignores.
+  *paint_blob = base::MakeRefCounted<PaintTextBlob>(std::move(blob),
+                                                    std::move(typefaces));
 }
 
 void PaintOpReader::Read(sk_sp<PaintShader>* shader) {
diff --git a/cc/paint/paint_op_reader.h b/cc/paint/paint_op_reader.h
index afb8bea5..28ca15b 100644
--- a/cc/paint/paint_op_reader.h
+++ b/cc/paint/paint_op_reader.h
@@ -44,7 +44,7 @@
   void Read(PaintFlags* flags);
   void Read(PaintImage* image);
   void Read(sk_sp<SkData>* data);
-  void Read(sk_sp<SkTextBlob>* blob);
+  void Read(scoped_refptr<PaintTextBlob>* blob);
   void Read(sk_sp<PaintShader>* shader);
   void Read(SkMatrix* matrix);
 
@@ -76,6 +76,10 @@
   template <typename T>
   void ReadFlattenable(sk_sp<T>* val);
 
+  void Read(std::vector<PaintTypeface>* typefaces);
+  void Read(const std::vector<PaintTypeface>& typefaces,
+            sk_sp<SkTextBlob>* blob);
+
   // Attempts to align the memory to the given alignment. Returns false if there
   // is unsufficient bytes remaining to do this padding.
   bool AlignMemory(size_t alignment);
diff --git a/cc/paint/paint_op_writer.cc b/cc/paint/paint_op_writer.cc
index 67ec941..fecde0f3 100644
--- a/cc/paint/paint_op_writer.cc
+++ b/cc/paint/paint_op_writer.cc
@@ -11,6 +11,15 @@
 
 namespace cc {
 
+PaintOpWriter::PaintOpWriter(void* memory, size_t size)
+    : memory_(static_cast<char*>(memory) + HeaderBytes()),
+      size_(size),
+      remaining_bytes_(size - HeaderBytes()) {
+  // Leave space for header of type/skip.
+  DCHECK_GE(size, HeaderBytes());
+}
+PaintOpWriter::~PaintOpWriter() = default;
+
 template <typename T>
 void PaintOpWriter::WriteSimple(const T& val) {
   static_assert(base::is_trivially_copyable<T>::value, "");
@@ -113,8 +122,62 @@
   }
 }
 
+void PaintOpWriter::Write(const std::vector<PaintTypeface>& typefaces) {
+  WriteSimple(static_cast<uint32_t>(typefaces.size()));
+  for (const auto& typeface : typefaces) {
+    DCHECK(typeface);
+    WriteSimple(typeface.sk_id());
+    WriteSimple(static_cast<uint8_t>(typeface.type()));
+    switch (typeface.type()) {
+      case PaintTypeface::Type::kTestTypeface:
+        // Nothing to serialize here.
+        break;
+      case PaintTypeface::Type::kSkTypeface:
+        // Nothing to do here. This should never be the case when everything is
+        // implemented. This should be a NOTREACHED() eventually.
+        break;
+      case PaintTypeface::Type::kFontConfigInterfaceIdAndTtcIndex:
+        WriteSimple(typeface.font_config_interface_id());
+        WriteSimple(typeface.ttc_index());
+        break;
+      case PaintTypeface::Type::kFilenameAndTtcIndex:
+        WriteSimple(typeface.filename().size());
+        WriteData(typeface.filename().size(), typeface.filename().data());
+        WriteSimple(typeface.ttc_index());
+        break;
+      case PaintTypeface::Type::kFamilyNameAndFontStyle:
+        WriteSimple(typeface.family_name().size());
+        WriteData(typeface.family_name().size(), typeface.family_name().data());
+        WriteSimple(typeface.font_style().weight());
+        WriteSimple(typeface.font_style().width());
+        WriteSimple(typeface.font_style().slant());
+        break;
+    }
+#if DCHECK_IS_ON()
+    if (typeface)
+      last_serialized_typeface_ids_.insert(typeface.sk_id());
+#endif
+  }
+}
+
+// static
+void PaintOpWriter::TypefaceCataloger(SkTypeface* typeface, void* ctx) {
+  DCHECK(static_cast<PaintOpWriter*>(ctx)->last_serialized_typeface_ids_.count(
+             typeface->uniqueID()) != 0);
+}
+
 void PaintOpWriter::Write(const sk_sp<SkTextBlob>& blob) {
-  // TODO(enne): implement SkTextBlob serialization: http://crbug.com/737629
+  auto data = blob->serialize(&PaintOpWriter::TypefaceCataloger, this);
+  Write(data);
+
+#if DCHECK_IS_ON()
+  last_serialized_typeface_ids_.clear();
+#endif
+}
+
+void PaintOpWriter::Write(const scoped_refptr<PaintTextBlob>& blob) {
+  Write(blob->typefaces());
+  Write(blob->ToSkTextBlob());
 }
 
 void PaintOpWriter::Write(const PaintShader* shader) {
diff --git a/cc/paint/paint_op_writer.h b/cc/paint/paint_op_writer.h
index 8b00357..d16ad067 100644
--- a/cc/paint/paint_op_writer.h
+++ b/cc/paint/paint_op_writer.h
@@ -5,6 +5,8 @@
 #ifndef CC_PAINT_PAINT_OP_WRITER_H_
 #define CC_PAINT_PAINT_OP_WRITER_H_
 
+#include <unordered_set>
+
 #include "cc/paint/paint_canvas.h"
 #include "cc/paint/paint_export.h"
 
@@ -19,13 +21,8 @@
 
 class CC_PAINT_EXPORT PaintOpWriter {
  public:
-  PaintOpWriter(void* memory, size_t size)
-      : memory_(static_cast<char*>(memory) + HeaderBytes()),
-        size_(size),
-        remaining_bytes_(size - HeaderBytes()) {
-    // Leave space for header of type/skip.
-    DCHECK_GE(size, HeaderBytes());
-  }
+  PaintOpWriter(void* memory, size_t size);
+  ~PaintOpWriter();
 
   static size_t constexpr HeaderBytes() { return 4u; }
 
@@ -47,8 +44,8 @@
   void Write(const PaintFlags& flags);
   void Write(const PaintImage& image, ImageProvider* image_provider);
   void Write(const sk_sp<SkData>& data);
-  void Write(const sk_sp<SkTextBlob>& blob);
   void Write(const PaintShader* shader);
+  void Write(const scoped_refptr<PaintTextBlob>& blob);
 
   void Write(SkClipOp op) { Write(static_cast<uint8_t>(op)); }
   void Write(PaintCanvas::AnnotationType type) {
@@ -64,6 +61,10 @@
   void WriteSimple(const T& val);
 
   void WriteFlattenable(const SkFlattenable* val);
+  void Write(const std::vector<PaintTypeface>& typefaces);
+  void Write(const sk_sp<SkTextBlob>& blob);
+
+  static void TypefaceCataloger(SkTypeface* typeface, void* ctx);
 
   // Attempts to align the memory to the given alignment. Returns false if there
   // is unsufficient bytes remaining to do this padding.
@@ -73,6 +74,8 @@
   size_t size_ = 0u;
   size_t remaining_bytes_ = 0u;
   bool valid_ = true;
+  // This is here for DCHECKs.
+  std::unordered_set<SkFontID> last_serialized_typeface_ids_;
 };
 
 }  // namespace cc
diff --git a/cc/paint/paint_text_blob.cc b/cc/paint/paint_text_blob.cc
new file mode 100644
index 0000000..b992ae1ed
--- /dev/null
+++ b/cc/paint/paint_text_blob.cc
@@ -0,0 +1,20 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/paint/paint_text_blob.h"
+
+#include <vector>
+
+#include "cc/paint/paint_typeface.h"
+#include "third_party/skia/include/core/SkTextBlob.h"
+
+namespace cc {
+
+PaintTextBlob::PaintTextBlob() = default;
+PaintTextBlob::PaintTextBlob(sk_sp<SkTextBlob> blob,
+                             std::vector<PaintTypeface> typefaces)
+    : sk_blob_(std::move(blob)), typefaces_(std::move(typefaces)) {}
+PaintTextBlob::~PaintTextBlob() = default;
+
+}  // namespace cc
diff --git a/cc/paint/paint_text_blob.h b/cc/paint/paint_text_blob.h
new file mode 100644
index 0000000..2bdac367b
--- /dev/null
+++ b/cc/paint/paint_text_blob.h
@@ -0,0 +1,42 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_PAINT_PAINT_TEXT_BLOB_H_
+#define CC_PAINT_PAINT_TEXT_BLOB_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "cc/paint/paint_export.h"
+#include "cc/paint/paint_typeface.h"
+#include "third_party/skia/include/core/SkTextBlob.h"
+
+namespace cc {
+
+class CC_PAINT_EXPORT PaintTextBlob
+    : public base::RefCountedThreadSafe<PaintTextBlob> {
+ public:
+  PaintTextBlob();
+  PaintTextBlob(sk_sp<SkTextBlob> blob, std::vector<PaintTypeface> typefaces);
+
+  const sk_sp<SkTextBlob>& ToSkTextBlob() const { return sk_blob_; }
+  const std::vector<PaintTypeface> typefaces() const { return typefaces_; }
+
+  operator bool() const { return !!sk_blob_; }
+
+ private:
+  friend base::RefCountedThreadSafe<PaintTextBlob>;
+
+  ~PaintTextBlob();
+
+  sk_sp<SkTextBlob> sk_blob_;
+  std::vector<PaintTypeface> typefaces_;
+
+  DISALLOW_COPY_AND_ASSIGN(PaintTextBlob);
+};
+
+}  // namespace cc
+
+#endif  // CC_PAINT_PAINT_TEXT_BLOB_H_
diff --git a/cc/paint/paint_text_blob_builder.cc b/cc/paint/paint_text_blob_builder.cc
new file mode 100644
index 0000000..2f4550a0
--- /dev/null
+++ b/cc/paint/paint_text_blob_builder.cc
@@ -0,0 +1,36 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/paint/paint_text_blob_builder.h"
+
+namespace cc {
+
+PaintTextBlobBuilder::PaintTextBlobBuilder() = default;
+PaintTextBlobBuilder::~PaintTextBlobBuilder() = default;
+
+scoped_refptr<PaintTextBlob> PaintTextBlobBuilder::TakeTextBlob() {
+  auto result = base::MakeRefCounted<PaintTextBlob>(sk_builder_.make(),
+                                                    std::move(typefaces_));
+  typefaces_.clear();
+  return result;
+}
+
+const PaintTextBlobBuilder::RunBuffer& PaintTextBlobBuilder::AllocRunPosH(
+    const PaintFont& font,
+    int count,
+    SkScalar y,
+    const SkRect* bounds) {
+  typefaces_.push_back(font.typeface());
+  return sk_builder_.allocRunPosH(font.ToSkPaint(), count, y, bounds);
+}
+
+const PaintTextBlobBuilder::RunBuffer& PaintTextBlobBuilder::AllocRunPos(
+    const PaintFont& font,
+    int count,
+    const SkRect* bounds) {
+  typefaces_.push_back(font.typeface());
+  return sk_builder_.allocRunPos(font.ToSkPaint(), count, bounds);
+}
+
+}  // namespace cc
diff --git a/cc/paint/paint_text_blob_builder.h b/cc/paint/paint_text_blob_builder.h
new file mode 100644
index 0000000..57a86c13
--- /dev/null
+++ b/cc/paint/paint_text_blob_builder.h
@@ -0,0 +1,49 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_PAINT_PAINT_TEXT_BLOB_BUILDER_H_
+#define CC_PAINT_PAINT_TEXT_BLOB_BUILDER_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "cc/paint/paint_export.h"
+#include "cc/paint/paint_font.h"
+#include "cc/paint/paint_text_blob.h"
+#include "third_party/skia/include/core/SkRect.h"
+#include "third_party/skia/include/core/SkScalar.h"
+#include "third_party/skia/include/core/SkTextBlob.h"
+
+namespace cc {
+
+class CC_PAINT_EXPORT PaintTextBlobBuilder {
+ public:
+  using RunBuffer = SkTextBlobBuilder::RunBuffer;
+
+  PaintTextBlobBuilder();
+  ~PaintTextBlobBuilder();
+
+  scoped_refptr<PaintTextBlob> TakeTextBlob();
+
+  // These functions pass the calls through to SkTextBlobBuilder, see its
+  // interface for details.
+  const RunBuffer& AllocRunPosH(const PaintFont& font,
+                                int count,
+                                SkScalar y,
+                                const SkRect* bounds = nullptr);
+
+  const RunBuffer& AllocRunPos(const PaintFont& font,
+                               int count,
+                               const SkRect* bounds = nullptr);
+
+ private:
+  std::vector<PaintTypeface> typefaces_;
+  SkTextBlobBuilder sk_builder_;
+
+  DISALLOW_COPY_AND_ASSIGN(PaintTextBlobBuilder);
+};
+
+}  // namespace cc
+
+#endif  // CC_PAINT_PAINT_TEXT_BLOB_BUILDER_H_
diff --git a/cc/paint/paint_typeface.cc b/cc/paint/paint_typeface.cc
new file mode 100644
index 0000000..9935db2
--- /dev/null
+++ b/cc/paint/paint_typeface.cc
@@ -0,0 +1,114 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/paint/paint_typeface.h"
+#include "build/build_config.h"
+#include "third_party/skia/include/ports/SkFontConfigInterface.h"
+#include "third_party/skia/include/ports/SkFontMgr.h"
+
+namespace cc {
+
+// static
+PaintTypeface PaintTypeface::TestTypeface() {
+  PaintTypeface typeface;
+  typeface.type_ = Type::kTestTypeface;
+  typeface.sk_typeface_ = SkTypeface::MakeDefault();
+  typeface.CreateSkTypeface();
+  return typeface;
+}
+
+// static
+PaintTypeface PaintTypeface::FromSkTypeface(const sk_sp<SkTypeface>& tf) {
+  PaintTypeface typeface;
+  typeface.type_ = Type::kSkTypeface;
+  typeface.sk_typeface_ = tf;
+  typeface.CreateSkTypeface();
+  return typeface;
+}
+
+// static
+PaintTypeface PaintTypeface::FromFontConfigInterfaceIdAndTtcIndex(
+    int config_id,
+    int ttc_index) {
+  PaintTypeface typeface;
+  typeface.type_ = Type::kFontConfigInterfaceIdAndTtcIndex;
+  typeface.font_config_interface_id_ = config_id;
+  typeface.ttc_index_ = ttc_index;
+  typeface.CreateSkTypeface();
+  return typeface;
+}
+
+// static
+PaintTypeface PaintTypeface::FromFilenameAndTtcIndex(
+    const std::string& filename,
+    int ttc_index) {
+  PaintTypeface typeface;
+  typeface.type_ = Type::kFilenameAndTtcIndex;
+  typeface.filename_ = filename;
+  typeface.ttc_index_ = ttc_index;
+  typeface.CreateSkTypeface();
+  return typeface;
+}
+
+// static
+PaintTypeface PaintTypeface::FromFamilyNameAndFontStyle(
+    const std::string& family_name,
+    const SkFontStyle& font_style) {
+  PaintTypeface typeface;
+  typeface.type_ = Type::kFamilyNameAndFontStyle;
+  typeface.family_name_ = family_name;
+  typeface.font_style_ = font_style;
+  typeface.CreateSkTypeface();
+  return typeface;
+}
+
+PaintTypeface::PaintTypeface() = default;
+PaintTypeface::PaintTypeface(const PaintTypeface& other) = default;
+PaintTypeface::PaintTypeface(PaintTypeface&& other) = default;
+PaintTypeface::~PaintTypeface() = default;
+
+PaintTypeface& PaintTypeface::operator=(const PaintTypeface& other) = default;
+PaintTypeface& PaintTypeface::operator=(PaintTypeface&& other) = default;
+
+void PaintTypeface::CreateSkTypeface() {
+// MacOS doesn't support this type of creation and relies on NSFonts instead.
+#if !defined(OS_MACOSX)
+  switch (type_) {
+    case Type::kTestTypeface:
+      // Nothing to do here.
+      break;
+    case Type::kSkTypeface:
+      // Nothing to do here.
+      break;
+    case Type::kFontConfigInterfaceIdAndTtcIndex: {
+// Mimic FontCache::CreateTypeface defines to ensure same behavior.
+#if !defined(OS_WIN) && !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
+      sk_sp<SkFontConfigInterface> fci(SkFontConfigInterface::RefGlobal());
+      SkFontConfigInterface::FontIdentity font_identity;
+      font_identity.fID = font_config_interface_id_;
+      font_identity.fTTCIndex = ttc_index_;
+      sk_typeface_ = fci->makeTypeface(font_identity);
+#endif
+      break;
+    }
+    case Type::kFilenameAndTtcIndex:
+// Mimic FontCache::CreateTypeface defines to ensure same behavior.
+#if !defined(OS_WIN) && !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
+      sk_typeface_ = SkTypeface::MakeFromFile(filename_.c_str(), ttc_index_);
+#endif
+      break;
+    case Type::kFamilyNameAndFontStyle: {
+      // This is a fallthrough in all cases in FontCache::CreateTypeface, so
+      // this is done unconditionally. Since we create the typeface upon
+      // PaintTypeface creation, this should be safe in all cases.
+      auto fm(SkFontMgr::RefDefault());
+      sk_typeface_ = fm->legacyMakeTypeface(family_name_.c_str(), font_style_);
+      break;
+    }
+  }
+#endif  // !defined(OS_MACOSX)
+  sk_id_ = sk_typeface_ ? sk_typeface_->uniqueID() : 0;
+}
+
+}  // namespace cc
diff --git a/cc/paint/paint_typeface.h b/cc/paint/paint_typeface.h
new file mode 100644
index 0000000..56bae2b
--- /dev/null
+++ b/cc/paint/paint_typeface.h
@@ -0,0 +1,77 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_PAINT_PAINT_TYPEFACE_H_
+#define CC_PAINT_PAINT_TYPEFACE_H_
+
+#include "base/logging.h"
+#include "cc/paint/paint_export.h"
+#include "third_party/skia/include/core/SkTypeface.h"
+
+namespace cc {
+
+class CC_PAINT_EXPORT PaintTypeface {
+ public:
+  enum class Type : uint8_t {
+    kTestTypeface,  // This should only be used in tests.
+    kSkTypeface,
+    kFontConfigInterfaceIdAndTtcIndex,
+    kFilenameAndTtcIndex,
+    kFamilyNameAndFontStyle
+  };
+
+  static PaintTypeface TestTypeface();
+  static PaintTypeface FromSkTypeface(const sk_sp<SkTypeface>& typeface);
+  static PaintTypeface FromFontConfigInterfaceIdAndTtcIndex(int config_id,
+                                                            int ttc_index);
+  static PaintTypeface FromFilenameAndTtcIndex(const std::string& filename,
+                                               int ttc_index);
+  static PaintTypeface FromFamilyNameAndFontStyle(
+      const std::string& family_name,
+      const SkFontStyle& font_style);
+  // TODO(vmpstr): Need to add FromWebFont?
+
+  PaintTypeface();
+  PaintTypeface(const PaintTypeface& other);
+  PaintTypeface(PaintTypeface&& other);
+  ~PaintTypeface();
+
+  PaintTypeface& operator=(const PaintTypeface& other);
+  PaintTypeface& operator=(PaintTypeface&& other);
+  operator bool() const { return !!sk_typeface_; }
+
+  // This is used when deserialized to force a different typeface id so that it
+  // can be matched from SkTextBlob deserialization.
+  void SetSkId(SkFontID id) { sk_id_ = id; }
+
+  SkFontID sk_id() const { return sk_id_; }
+  const sk_sp<SkTypeface>& ToSkTypeface() const { return sk_typeface_; }
+
+  Type type() const { return type_; }
+  int font_config_interface_id() const { return font_config_interface_id_; }
+  int ttc_index() const { return ttc_index_; }
+  const std::string& filename() const { return filename_; }
+  const std::string& family_name() const { return family_name_; }
+  const SkFontStyle font_style() const { return font_style_; }
+
+ private:
+  void CreateSkTypeface();
+
+  // This is the font ID that should be used by this PaintTypeface, regardless
+  // of the sk_typeface_ on the deserialized end. This value is initialized but
+  // can be overridden by SetSkId().
+  SkFontID sk_id_;
+  sk_sp<SkTypeface> sk_typeface_;
+  Type type_ = Type::kSkTypeface;
+
+  int font_config_interface_id_ = 0;
+  int ttc_index_ = 0;
+  std::string filename_;
+  std::string family_name_;
+  SkFontStyle font_style_;
+};
+
+}  // namespace cc
+
+#endif  // CC_PAINT_PAINT_TYPEFACE_H_
diff --git a/cc/paint/record_paint_canvas.cc b/cc/paint/record_paint_canvas.cc
index f8d27db..0db456b 100644
--- a/cc/paint/record_paint_canvas.cc
+++ b/cc/paint/record_paint_canvas.cc
@@ -278,11 +278,11 @@
             left, top, flags);
 }
 
-void RecordPaintCanvas::drawTextBlob(sk_sp<SkTextBlob> blob,
+void RecordPaintCanvas::drawTextBlob(scoped_refptr<PaintTextBlob> blob,
                                      SkScalar x,
                                      SkScalar y,
                                      const PaintFlags& flags) {
-  list_->push<DrawTextBlobOp>(blob, x, y, flags);
+  list_->push<DrawTextBlobOp>(std::move(blob), x, y, flags);
 }
 
 void RecordPaintCanvas::drawPicture(sk_sp<const PaintRecord> record) {
diff --git a/cc/paint/record_paint_canvas.h b/cc/paint/record_paint_canvas.h
index 12b6dcc..49f1d7a8 100644
--- a/cc/paint/record_paint_canvas.h
+++ b/cc/paint/record_paint_canvas.h
@@ -15,6 +15,7 @@
 #include "cc/paint/paint_canvas.h"
 #include "cc/paint/paint_flags.h"
 #include "cc/paint/paint_record.h"
+#include "cc/paint/paint_text_blob.h"
 #include "third_party/skia/include/utils/SkNoDrawCanvas.h"
 
 namespace cc {
@@ -88,7 +89,7 @@
                   SkScalar top,
                   const PaintFlags* flags) override;
 
-  void drawTextBlob(sk_sp<SkTextBlob> blob,
+  void drawTextBlob(scoped_refptr<PaintTextBlob> blob,
                     SkScalar x,
                     SkScalar y,
                     const PaintFlags& flags) override;
diff --git a/cc/paint/skia_paint_canvas.cc b/cc/paint/skia_paint_canvas.cc
index 79428b8..1640406d 100644
--- a/cc/paint/skia_paint_canvas.cc
+++ b/cc/paint/skia_paint_canvas.cc
@@ -234,12 +234,12 @@
   }
 }
 
-void SkiaPaintCanvas::drawTextBlob(sk_sp<SkTextBlob> blob,
+void SkiaPaintCanvas::drawTextBlob(scoped_refptr<PaintTextBlob> blob,
                                    SkScalar x,
                                    SkScalar y,
                                    const PaintFlags& flags) {
   SkPaint paint = flags.ToSkPaint();
-  canvas_->drawTextBlob(blob.get(), x, y, paint);
+  canvas_->drawTextBlob(blob->ToSkTextBlob(), x, y, paint);
 }
 
 void SkiaPaintCanvas::drawPicture(sk_sp<const PaintRecord> record) {
diff --git a/cc/paint/skia_paint_canvas.h b/cc/paint/skia_paint_canvas.h
index f60610f8..2dbabb71 100644
--- a/cc/paint/skia_paint_canvas.h
+++ b/cc/paint/skia_paint_canvas.h
@@ -14,6 +14,7 @@
 #include "cc/paint/paint_canvas.h"
 #include "cc/paint/paint_flags.h"
 #include "cc/paint/paint_record.h"
+#include "cc/paint/paint_text_blob.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 
 namespace cc {
@@ -96,7 +97,7 @@
                   SkScalar top,
                   const PaintFlags* flags) override;
 
-  void drawTextBlob(sk_sp<SkTextBlob> blob,
+  void drawTextBlob(scoped_refptr<PaintTextBlob> blob,
                     SkScalar x,
                     SkScalar y,
                     const PaintFlags& flags) override;
diff --git a/cc/tiles/gpu_image_decode_cache.cc b/cc/tiles/gpu_image_decode_cache.cc
index 19c4850..9d20668 100644
--- a/cc/tiles/gpu_image_decode_cache.cc
+++ b/cc/tiles/gpu_image_decode_cache.cc
@@ -18,6 +18,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/memory_dump_manager.h"
 #include "cc/base/devtools_instrumentation.h"
+#include "cc/base/histograms.h"
 #include "cc/raster/tile_task.h"
 #include "cc/tiles/mipmap_util.h"
 #include "components/viz/common/gpu/context_provider.h"
@@ -497,6 +498,11 @@
       this);
   // Unregister this component with memory_coordinator::ClientRegistry.
   base::MemoryCoordinatorClientRegistry::GetInstance()->Unregister(this);
+
+  UMA_HISTOGRAM_CUSTOM_COUNTS(
+      base::StringPrintf("Compositing.%s.CachedImagesCount.Gpu",
+                         GetClientNameForMetrics()),
+      lifetime_max_items_in_cache_, 1, 1000, 20);
 }
 
 ImageDecodeCache::TaskResult GpuImageDecodeCache::GetTaskForImageAndRef(
@@ -1089,6 +1095,9 @@
                "GpuImageDecodeCache::EnsureCapacity");
   lock_.AssertAcquired();
 
+  lifetime_max_items_in_cache_ =
+      std::max(lifetime_max_items_in_cache_, persistent_cache_.size());
+
   if (CanFitInWorkingSet(required_size) && !ExceedsPreferredCount())
     return true;
 
diff --git a/cc/tiles/gpu_image_decode_cache.h b/cc/tiles/gpu_image_decode_cache.h
index ca6e5053..dafc5abf 100644
--- a/cc/tiles/gpu_image_decode_cache.h
+++ b/cc/tiles/gpu_image_decode_cache.h
@@ -403,6 +403,10 @@
   std::vector<SkImage*> images_pending_complete_lock_;
   std::vector<SkImage*> images_pending_unlock_;
   std::vector<sk_sp<SkImage>> images_pending_deletion_;
+
+  // Records the maximum number of items in the cache over the lifetime of the
+  // cache. This is updated anytime we are requested to reduce cache usage.
+  size_t lifetime_max_items_in_cache_ = 0u;
 };
 
 }  // namespace cc
diff --git a/cc/tiles/software_image_decode_cache.cc b/cc/tiles/software_image_decode_cache.cc
index b0d11bd..247ddd2 100644
--- a/cc/tiles/software_image_decode_cache.cc
+++ b/cc/tiles/software_image_decode_cache.cc
@@ -20,6 +20,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/memory_dump_manager.h"
 #include "cc/base/devtools_instrumentation.h"
+#include "cc/base/histograms.h"
 #include "cc/raster/tile_task.h"
 #include "cc/tiles/mipmap_util.h"
 #include "third_party/skia/include/core/SkCanvas.h"
@@ -37,8 +38,6 @@
 // if more items are locked. That is, locked items ignore this limit.
 // Depending on the memory state of the system, we limit the amount of items
 // differently.
-// TODO(vmpstr): UMA how many image we should keep around. This number seems
-// high.
 const size_t kNormalMaxItemsInCache = 1000;
 const size_t kThrottledMaxItemsInCache = 100;
 const size_t kSuspendedMaxItemsInCache = 0;
@@ -221,6 +220,11 @@
       this);
   // Unregister this component with memory_coordinator::ClientRegistry.
   base::MemoryCoordinatorClientRegistry::GetInstance()->Unregister(this);
+
+  UMA_HISTOGRAM_CUSTOM_COUNTS(
+      base::StringPrintf("Compositing.%s.CachedImagesCount.Software",
+                         GetClientNameForMetrics()),
+      lifetime_max_items_in_cache_, 1, 1000, 20);
 }
 
 ImageDecodeCache::TaskResult SoftwareImageDecodeCache::GetTaskForImageAndRef(
@@ -584,6 +588,8 @@
 void SoftwareImageDecodeCache::ReduceCacheUsageUntilWithinLimit(size_t limit) {
   TRACE_EVENT0("cc",
                "SoftwareImageDecodeCache::ReduceCacheUsageUntilWithinLimit");
+  lifetime_max_items_in_cache_ =
+      std::max(lifetime_max_items_in_cache_, decoded_images_.size());
   for (auto it = decoded_images_.rbegin();
        decoded_images_.size() > limit && it != decoded_images_.rend();) {
     if (it->second->ref_count != 0) {
diff --git a/cc/tiles/software_image_decode_cache.h b/cc/tiles/software_image_decode_cache.h
index 0b4c95c..7c510c6 100644
--- a/cc/tiles/software_image_decode_cache.h
+++ b/cc/tiles/software_image_decode_cache.h
@@ -313,6 +313,9 @@
 
   SkColorType color_type_;
   size_t max_items_in_cache_;
+  // Records the maximum number of items in the cache over the lifetime of the
+  // cache. This is updated anytime we are requested to reduce cache usage.
+  size_t lifetime_max_items_in_cache_ = 0u;
 };
 
 }  // namespace cc
diff --git a/chrome/browser/banners/app_banner_manager.cc b/chrome/browser/banners/app_banner_manager.cc
index 9392835..9f598ba2 100644
--- a/chrome/browser/banners/app_banner_manager.cc
+++ b/chrome/browser/banners/app_banner_manager.cc
@@ -577,8 +577,16 @@
   // requested in the beforeinstallprompt event handler), we keep going and show
   // the banner immediately.
   referrer_ = referrer;
-  if (reply == blink::mojom::AppBannerPromptReply::CANCEL)
+  if (reply == blink::mojom::AppBannerPromptReply::CANCEL) {
     TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_PREVENT_DEFAULT_CALLED);
+    if (IsDebugMode()) {
+      web_contents()->GetMainFrame()->AddMessageToConsole(
+          content::CONSOLE_MESSAGE_LEVEL_INFO,
+          "Banner not shown: beforeinstallpromptevent.preventDefault() called. "
+          "The page must call beforeinstallpromptevent.prompt() to show the "
+          "banner.");
+    }
+  }
 
   if (IsExperimentalAppBannersEnabled() ||
       reply == blink::mojom::AppBannerPromptReply::CANCEL) {
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index fa747ad7..dbd186436 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -181,6 +181,34 @@
 
 net::CertVerifier* g_cert_verifier_for_testing = nullptr;
 
+// A CertVerifier that forwards all requests to |g_cert_verifier_for_testing|.
+// This is used to allow Profiles to have their own
+// std::unique_ptr<net::CertVerifier> while forwarding calls to the shared
+// verifier.
+class WrappedTestingCertVerifier : public net::CertVerifier {
+ public:
+  ~WrappedTestingCertVerifier() override = default;
+
+  // CertVerifier implementation
+  int Verify(const RequestParams& params,
+             net::CRLSet* crl_set,
+             net::CertVerifyResult* verify_result,
+             const net::CompletionCallback& callback,
+             std::unique_ptr<Request>* out_req,
+             const net::NetLogWithSource& net_log) override {
+    verify_result->Reset();
+    if (!g_cert_verifier_for_testing)
+      return net::ERR_FAILED;
+    return g_cert_verifier_for_testing->Verify(params, crl_set, verify_result,
+                                               callback, out_req, net_log);
+  }
+  bool SupportsOCSPStapling() override {
+    if (!g_cert_verifier_for_testing)
+      return false;
+    return g_cert_verifier_for_testing->SupportsOCSPStapling();
+  }
+};
+
 #if BUILDFLAG(DEBUG_DEVTOOLS)
 bool IsSupportedDevToolsURL(const GURL& url, base::FilePath* path) {
   std::string bundled_path_prefix(chrome::kChromeUIDevToolsBundledPath);
@@ -1100,7 +1128,7 @@
 #endif
 
   if (g_cert_verifier_for_testing) {
-    builder->set_shared_cert_verifier(g_cert_verifier_for_testing);
+    builder->SetCertVerifier(std::make_unique<WrappedTestingCertVerifier>());
   } else {
     std::unique_ptr<net::CertVerifier> cert_verifier;
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
index c858e8c7..2820362 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -451,7 +451,7 @@
                 net::UnescapeRule::NONE, nullptr, nullptr, nullptr);
 
   ui::ScopedClipboardWriter scw(ui::CLIPBOARD_TYPE_COPY_PASTE);
-  scw.WriteURL(text);
+  scw.WriteText(text);
 }
 
 bool g_custom_id_ranges_initialized = false;
diff --git a/chrome/browser/sessions/session_restore.cc b/chrome/browser/sessions/session_restore.cc
index 5295f44..b640c36 100644
--- a/chrome/browser/sessions/session_restore.cc
+++ b/chrome/browser/sessions/session_restore.cc
@@ -19,7 +19,6 @@
 #include "base/debug/alias.h"
 #include "base/location.h"
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/run_loop.h"
@@ -145,9 +144,7 @@
 
     if (synchronous_) {
       {
-        base::MessageLoop::ScopedNestableTaskAllower allow(
-            base::MessageLoop::current());
-        base::RunLoop loop;
+        base::RunLoop loop(base::RunLoop::Type::kNestableTasksAllowed);
         quit_closure_for_sync_restore_ = loop.QuitClosure();
         loop.Run();
         quit_closure_for_sync_restore_ = base::Closure();
diff --git a/chrome/browser/ui/app_list/app_list_view_delegate.cc b/chrome/browser/ui/app_list/app_list_view_delegate.cc
index e11e601..1cf31010 100644
--- a/chrome/browser/ui/app_list/app_list_view_delegate.cc
+++ b/chrome/browser/ui/app_list/app_list_view_delegate.cc
@@ -233,7 +233,9 @@
   if (auto_launch)
     base::RecordAction(base::UserMetricsAction("AppList_AutoLaunched"));
 
-  RecordHistogram(model_->tablet_mode(), model_->state_fullscreen());
+  // Record the search metric if the SearchResult is not a suggested app.
+  if (result->display_type() != app_list::SearchResult::DISPLAY_RECOMMENDATION)
+    RecordHistogram(model_->tablet_mode(), model_->state_fullscreen());
 
   search_controller_->OpenResult(result, event_flags);
 }
diff --git a/chrome/browser/ui/app_list/search/arc_app_result.cc b/chrome/browser/ui/app_list/search/arc_app_result.cc
index a4386824..96cc8b0 100644
--- a/chrome/browser/ui/app_list/search/arc_app_result.cc
+++ b/chrome/browser/ui/app_list/search/arc_app_result.cc
@@ -44,7 +44,9 @@
 }
 
 void ArcAppResult::Open(int event_flags) {
-  RecordHistogram(APP_SEARCH_RESULT);
+  // Record the search metric if the result is not a suggested app.
+  if (display_type() != DISPLAY_RECOMMENDATION)
+    RecordHistogram(APP_SEARCH_RESULT);
 
   if (!arc::LaunchApp(profile(), app_id(), event_flags,
                       controller()->GetAppListDisplayId())) {
diff --git a/chrome/browser/ui/app_list/search/extension_app_result.cc b/chrome/browser/ui/app_list/search/extension_app_result.cc
index 8d4a393..d663fdd5c 100644
--- a/chrome/browser/ui/app_list/search/extension_app_result.cc
+++ b/chrome/browser/ui/app_list/search/extension_app_result.cc
@@ -50,7 +50,6 @@
 }
 
 void ExtensionAppResult::Open(int event_flags) {
-  RecordHistogram(APP_SEARCH_RESULT);
   const extensions::Extension* extension =
       extensions::ExtensionRegistry::Get(profile())->GetInstalledExtension(
           app_id());
@@ -61,11 +60,13 @@
   if (!extensions::util::IsAppLaunchable(app_id(), profile()))
     return;
 
-  // Check if enable flow is already running or should be started
+  // Check if enable flow is already running or should be started.
   if (RunExtensionEnableFlow())
     return;
 
+  // Record the search metrics if the SearchResult is not a suggested app.
   if (display_type() != DISPLAY_RECOMMENDATION) {
+    RecordHistogram(APP_SEARCH_RESULT);
     extensions::RecordAppListSearchLaunch(extension);
     base::RecordAction(base::UserMetricsAction("AppList_ClickOnAppFromSearch"));
   }
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
index 6812f48a..46865f6d 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -1033,10 +1033,7 @@
     UMA_HISTOGRAM_COUNTS(OmniboxEditModel::kCutOrCopyAllTextHistogram, 1);
 
   ui::ScopedClipboardWriter scoped_clipboard_writer(clipboard_type);
-  if (write_url)
-    scoped_clipboard_writer.WriteURL(selected_text);
-  else
-    scoped_clipboard_writer.WriteText(selected_text);
+  scoped_clipboard_writer.WriteText(selected_text);
 }
 
 void OmniboxViewViews::OnWriteDragData(ui::OSExchangeData* data) {
diff --git a/chromecast/BUILD.gn b/chromecast/BUILD.gn
index 68ceb463..410a9b02 100644
--- a/chromecast/BUILD.gn
+++ b/chromecast/BUILD.gn
@@ -450,6 +450,12 @@
 if (is_fuchsia) {
   fuchsia_executable_runner("cast_shell_fuchsia") {
     exe_target = ":cast_shell"
+
+    if (chromecast_branding != "public") {
+      data_deps = [
+        "//chromecast/internal:fuchsia_internal_data_deps",
+      ]
+    }
   }
 }
 
diff --git a/components/language/OWNERS b/components/language/OWNERS
index 77c1b0d..77a0ab0 100644
--- a/components/language/OWNERS
+++ b/components/language/OWNERS
@@ -2,6 +2,7 @@
 sammc@chromium.org
 jiameng@chromium.org
 renjieliu@chromium.org
+martis@chromium.org
 
 # TEAM: language@chromium.org
 # COMPONENT: UI>Browser>Language
diff --git a/docs/testing/json_test_results_format.md b/docs/testing/json_test_results_format.md
index 15732ca..a017e3f 100644
--- a/docs/testing/json_test_results_format.md
+++ b/docs/testing/json_test_results_format.md
@@ -38,7 +38,10 @@
               "ASTTest": {
                 "testNodeBase": {
                   "expected": "PASS",
-                  "actual": "PASS"
+                  "actual": "PASS",
+                  "artifacts": {
+                    "screenshot": ["screenshots/page.png"],
+                  }
                 }
               }
             }
@@ -52,6 +55,9 @@
       "num_failures_by_type": {
         "FAIL": 0,
         "PASS": 1
+      },
+      "artifact_types": {
+        "screenshot": "image/png"
       }
     }
 
@@ -76,6 +82,8 @@
 | `seconds_since_epoch` | float | **Required.** The start time of the test run expressed as a floating-point offset in seconds from the UNIX epoch. |
 | `tests` | dict | **Required.** The actual trie of test results. Each directory or module component in the test name is a node in the trie, and the leaf contains the dict of per-test fields as described below. |
 | `version` | integer | **Required.** Version of the file format. Current version is 3. |
+| `artifact_types` | dict | **Optional. Required if any artifacts are present for any tests.** MIME Type information for artifacts in this json file. All artifacts with the same name must share the same MIME type.  |
+| `artifact_permament_location` | string | **Optional.** The URI of the root location where the artifacts are stored. If present, any artifact locations are taken to be relative to this location. Currently only the `gs://` scheme is supported. |
 | `build_number` | string | **Optional.** If this test run was produced on a bot, this should be the build number of the run, e.g., "1234". |
 | `builder_name` | string | **Optional.** If this test run was produced on a bot, this should be the builder name of the bot, e.g., "Linux Tests". |
 | `chromium_revision` | string | **Optional.** The revision of the current Chromium checkout, if relevant, e.g. "356123". |
@@ -99,6 +107,7 @@
 |-------------|-----------|-------------|
 |  `actual` | string | **Required.** An ordered space-separated list of the results the test actually produced. `FAIL PASS` means that a test was run twice, failed the first time, and then passed when it was retried. If a test produces multiple different results, then it was actually flaky during the run. |
 |  `expected` | string | **Required.** An unordered space-separated list of the result types expected for the test, e.g. `FAIL PASS` means that a test is expected to either pass or fail. A test that contains multiple values is expected to be flaky. |
+|  `artifacts` | dict | **Optional.** A dictionary describing test artifacts generated by the execution of the test. The dictionary maps the name of the artifact (`screenshot`, `crash_log`) to a list of relative locations of the artifact (`screenshot/page.png`, `logs/crash.txt`). There is one entry in the list per test execution. If `artifact_permanent_location` is specified, then this location is relative to that path. Otherwise, it is assumed that this test file is in a known location by whatever is processing this test file, and so the location is relative to a known directory. |
 |  `bugs` | string | **Optional.** A comma-separated list of URLs to bug database entries associated with each test. |
 |  `is_unexpected` | bool | **Optional.** If present and true, the failure was unexpected (a regression). If false (or if the key is not present at all), the failure was expected and will be ignored. |
 |  `time` | float | **Optional.** If present, the time it took in seconds to execute the first invocation of the test. |
diff --git a/net/cert/x509_certificate.cc b/net/cert/x509_certificate.cc
index 26f4720..d888692 100644
--- a/net/cert/x509_certificate.cc
+++ b/net/cert/x509_certificate.cc
@@ -87,31 +87,25 @@
   exploded.hour = generalized.hours;
   exploded.minute = generalized.minutes;
   exploded.second = generalized.seconds;
-#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
+
   if (base::Time::FromUTCExploded(exploded, result))
     return true;
 
-  if (sizeof(time_t) == 4) {
-    // Fail on obviously bad dates before trying the 32-bit hacks.
-    if (!exploded.HasValidValues())
-      return false;
+  // Fail on obviously bad dates.
+  if (!exploded.HasValidValues())
+    return false;
 
-    // Hack to handle dates that can't be converted on 32-bit systems.
-    // TODO(mattm): consider consolidating this with
-    // SaturatedTimeFromUTCExploded from cookie_util.cc
-    if (generalized.year >= 2038) {
-      *result = base::Time::Max();
-      return true;
-    }
-    if (generalized.year < 1970) {
-      *result = base::Time::Min();
-      return true;
-    }
+  // TODO(mattm): consider consolidating this with
+  // SaturatedTimeFromUTCExploded from cookie_util.cc
+  if (generalized.year > base::Time::kExplodedMaxYear) {
+    *result = base::Time::Max();
+    return true;
+  }
+  if (generalized.year < base::Time::kExplodedMinYear) {
+    *result = base::Time::Min();
+    return true;
   }
   return false;
-#else
-  return base::Time::FromUTCExploded(exploded, result);
-#endif
 }
 
 // Sets |value| to the Value from a DER Sequence Tag-Length-Value and return
diff --git a/net/cookies/cookie_util.cc b/net/cookies/cookie_util.cc
index a1b274b..cf133b6 100644
--- a/net/cookies/cookie_util.cc
+++ b/net/cookies/cookie_util.cc
@@ -54,36 +54,16 @@
   // some invalid calendar dates in the out-of-range case.
   if (!exploded.HasValidValues())
     return false;
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
-  // Allow dates prior to unix epoch (which fail on non-Mac/iOS POSIX).
-  if (exploded.year < 1970) {
-    *out = MinNonNullTime();
-    return true;
-  }
 
-  // On 32-bit non-Mac/iOS POSIX systems, the time_t value that FromExploded()
-  // returns overflows in the middle of year 2038. In that case, return
-  // Time::Max().
-  if (sizeof(time_t) == 4u && exploded.year >= 2038) {
+  if (exploded.year > base::Time::kExplodedMaxYear) {
     *out = base::Time::Max();
     return true;
   }
-#endif  // defined(OS_POSIX) && !defined(OS_MACOSX)
-
-#if defined(OS_WIN)
-  // Allow dates prior to Windows epoch.
-  if (exploded.year < 1601) {
+  if (exploded.year < base::Time::kExplodedMinYear) {
     *out = MinNonNullTime();
     return true;
   }
 
-  // Allow dates after the Windows epoch.
-  if (exploded.year >= 30827) {
-    *out = base::Time::Max();
-    return true;
-  }
-#endif  //  defined(OS_WIN)
-
   return false;
 }
 
diff --git a/net/cookies/cookie_util_unittest.cc b/net/cookies/cookie_util_unittest.cc
index d261ec7..7d55dd9 100644
--- a/net/cookies/cookie_util_unittest.cc
+++ b/net/cookies/cookie_util_unittest.cc
@@ -171,21 +171,21 @@
 // succeed anyway (and return a minimal base::Time).
 TEST(CookieUtilTest, ParseCookieExpirationTimeBefore1970) {
   const char* kTests[] = {
-      // The unix epoch.
-      "1970 Jan 1 00:00:00",
-      // The windows epoch.
-      "1601 Jan 1 00:00:00",
-      // Other dates.
-      "1969 March 3 21:01:22", "1600 April 15 21:01:22",
+      // Times around the Unix epoch.
+      "1970 Jan 1 00:00:00", "1969 March 3 21:01:22",
+      // Times around the Windows epoch.
+      "1601 Jan 1 00:00:00", "1600 April 15 21:01:22",
+      // Times around kExplodedMinYear on Mac.
+      "1902 Jan 1 00:00:00", "1901 Jan 1 00:00:00",
   };
 
   for (auto* test : kTests) {
     base::Time parsed_time = cookie_util::ParseCookieExpirationTime(test);
-    EXPECT_FALSE(parsed_time.is_null());
+    EXPECT_FALSE(parsed_time.is_null()) << test;
 
     // It should either have an exact value, or should be base::Time(1)
     // For simplicity just check that it is less than the unix epoch.
-    EXPECT_LE(parsed_time, base::Time::UnixEpoch());
+    EXPECT_LE(parsed_time, base::Time::UnixEpoch()) << test;
   }
 }
 
diff --git a/net/nqe/network_quality_estimator.cc b/net/nqe/network_quality_estimator.cc
index 4ff9096b..4bfb9aa 100644
--- a/net/nqe/network_quality_estimator.cc
+++ b/net/nqe/network_quality_estimator.cc
@@ -738,7 +738,8 @@
          // response is not cached.
          !request.response_info().response_time.is_null() &&
          !request.was_cached() &&
-         request.creation_time() >= last_connection_change_;
+         request.creation_time() >= last_connection_change_ &&
+         request.method() == "GET";
 }
 
 void NetworkQualityEstimator::RecordExternalEstimateProviderMetrics(
diff --git a/net/nqe/throughput_analyzer.cc b/net/nqe/throughput_analyzer.cc
index e201e8df..e72821cd 100644
--- a/net/nqe/throughput_analyzer.cc
+++ b/net/nqe/throughput_analyzer.cc
@@ -29,6 +29,12 @@
 // degrade accuracy held in the memory.
 static const size_t kMaxRequestsSize = 300;
 
+// Returns true if the request should be discarded because it does not provide
+// meaningful observation.
+bool ShouldDiscardRequest(const URLRequest& request) {
+  return request.method() != "GET";
+}
+
 }  // namespace
 
 namespace nqe {
@@ -136,6 +142,8 @@
     EndThroughputObservationWindow();
     DCHECK(!IsCurrentlyTrackingThroughput());
     return;
+  } else if (ShouldDiscardRequest(request)) {
+    return;
   }
 
   EraseHangingRequests(request);
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index c28fc56..51dbcb2a 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -1346,17 +1346,7 @@
   SSLConfig ssl_config;
   int rv;
   ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
-
-#if defined(OS_WIN)
-  EXPECT_THAT(rv, IsError(ERR_SSL_SERVER_CERT_BAD_FORMAT));
-  EXPECT_FALSE(IsCertificateError(rv));
-#elif defined(OS_ANDROID)
-  // Android date handling behavior can vary depending on the platform.
-  EXPECT_THAT(rv, AnyOf(IsError(ERR_SSL_SERVER_CERT_BAD_FORMAT),
-                        IsError(ERR_CERT_DATE_INVALID)));
-#else  // !(defined(OS_WIN) || defined(OS_ANDROID))
   EXPECT_THAT(rv, IsError(ERR_CERT_DATE_INVALID));
-#endif
 }
 
 // Attempt to connect to a page which requests a client certificate. It should
diff --git a/net/url_request/url_request_context_builder.cc b/net/url_request/url_request_context_builder.cc
index 53c56e1..cbcf9eef 100644
--- a/net/url_request/url_request_context_builder.cc
+++ b/net/url_request/url_request_context_builder.cc
@@ -205,8 +205,7 @@
       pac_quick_check_enabled_(true),
       pac_sanitize_url_policy_(ProxyService::SanitizeUrlPolicy::SAFE),
       shared_proxy_delegate_(nullptr),
-      shared_http_auth_handler_factory_(nullptr),
-      shared_cert_verifier_(nullptr) {
+      shared_http_auth_handler_factory_(nullptr) {
 }
 
 URLRequestContextBuilder::~URLRequestContextBuilder() {}
@@ -282,16 +281,9 @@
 
 void URLRequestContextBuilder::SetCertVerifier(
     std::unique_ptr<CertVerifier> cert_verifier) {
-  DCHECK(!shared_cert_verifier_);
   cert_verifier_ = std::move(cert_verifier);
 }
 
-void URLRequestContextBuilder::set_shared_cert_verifier(
-    CertVerifier* shared_cert_verifier) {
-  DCHECK(!cert_verifier_);
-  shared_cert_verifier_ = shared_cert_verifier;
-}
-
 #if BUILDFLAG(ENABLE_REPORTING)
 void URLRequestContextBuilder::set_reporting_policy(
     std::unique_ptr<net::ReportingPolicy> reporting_policy) {
@@ -476,10 +468,7 @@
   }
 
   if (cert_verifier_) {
-    DCHECK(!shared_cert_verifier_);
     storage->set_cert_verifier(std::move(cert_verifier_));
-  } else if (shared_cert_verifier_) {
-    context->set_cert_verifier(shared_cert_verifier_);
   } else {
     storage->set_cert_verifier(CertVerifier::CreateDefault());
   }
diff --git a/net/url_request/url_request_context_builder.h b/net/url_request/url_request_context_builder.h
index 0e1ce71..eee4163 100644
--- a/net/url_request/url_request_context_builder.h
+++ b/net/url_request/url_request_context_builder.h
@@ -291,14 +291,6 @@
 
   void SetCertVerifier(std::unique_ptr<CertVerifier> cert_verifier);
 
-  // Makes the created URLRequestContext use a shared CertVerifier object.
-  // Should not be used it SetCertVerifier() is used. The consumer must ensure
-  // the CertVerifier outlives the URLRequestContext returned by the builder.
-  //
-  // TODO(mmenke): Figure out if consumers can use SetCertVerifier instead. See:
-  // https://crbug.com/743251.
-  void set_shared_cert_verifier(CertVerifier* shared_cert_verifier);
-
 #if BUILDFLAG(ENABLE_REPORTING)
   void set_reporting_policy(
       std::unique_ptr<net::ReportingPolicy> reporting_policy);
@@ -399,7 +391,6 @@
   std::unique_ptr<HttpAuthHandlerFactory> http_auth_handler_factory_;
   HttpAuthHandlerFactory* shared_http_auth_handler_factory_;
   std::unique_ptr<CertVerifier> cert_verifier_;
-  CertVerifier* shared_cert_verifier_;
   std::unique_ptr<CTVerifier> ct_verifier_;
   std::unique_ptr<CTPolicyEnforcer> ct_policy_enforcer_;
 #if BUILDFLAG(ENABLE_REPORTING)
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index 4be359a0..7c6b7da 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -1405,9 +1405,15 @@
 
   DCHECK(defer_page_unload_);
   defer_page_unload_ = false;
-  for (int page_index : deferred_page_unloads_)
+
+  // Store the pages to unload away because the act of unloading pages can cause
+  // there to be more pages to unload. We leave those extra pages to be unloaded
+  // on the next go around.
+  std::vector<int> pages_to_unload;
+  std::swap(pages_to_unload, deferred_page_unloads_);
+  for (int page_index : pages_to_unload)
     pages_[page_index]->Unload();
-  deferred_page_unloads_.clear();
+
   return rv;
 }
 
diff --git a/pdf/pdfium/pdfium_page.cc b/pdf/pdfium/pdfium_page.cc
index f2af2aa..c967a95 100644
--- a/pdf/pdfium/pdfium_page.cc
+++ b/pdf/pdfium/pdfium_page.cc
@@ -339,14 +339,14 @@
       FPDF_DEST dest = FPDFAction_GetDest(engine_->doc(), action);
       if (dest)
         return GetDestinationTarget(dest, target);
-      // TODO(thestig): We don't fully support all types of the in-document
-      // links. Need to implement that. There is a bug to track that:
-      // https://crbug.com/55776
+      // TODO(crbug.com/55776): We don't fully support all types of the
+      // in-document links.
       return NONSELECTABLE_AREA;
     }
     case PDFACTION_URI:
       return GetURITarget(action, target);
-    // TODO(thestig): Support remaining types for https://crbug.com/55776
+    // TODO(crbug.com/767191): Support PDFACTION_LAUNCH.
+    // TODO(crbug.com/142344): Support PDFACTION_REMOTEGOTO.
     case PDFACTION_LAUNCH:
     case PDFACTION_REMOTEGOTO:
     default:
diff --git a/services/resource_coordinator/BUILD.gn b/services/resource_coordinator/BUILD.gn
index d86ad6fd..8a762d9 100644
--- a/services/resource_coordinator/BUILD.gn
+++ b/services/resource_coordinator/BUILD.gn
@@ -45,6 +45,8 @@
     "observers/metrics_collector.h",
     "observers/page_signal_generator_impl.cc",
     "observers/page_signal_generator_impl.h",
+    "resource_coordinator_clock.cc",
+    "resource_coordinator_clock.h",
     "resource_coordinator_service.cc",
     "resource_coordinator_service.h",
   ]
diff --git a/services/resource_coordinator/coordination_unit/page_coordination_unit_impl.cc b/services/resource_coordinator/coordination_unit/page_coordination_unit_impl.cc
index fb1fc48c..fb931da 100644
--- a/services/resource_coordinator/coordination_unit/page_coordination_unit_impl.cc
+++ b/services/resource_coordinator/coordination_unit/page_coordination_unit_impl.cc
@@ -9,14 +9,14 @@
 #include "services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.h"
 #include "services/resource_coordinator/coordination_unit/process_coordination_unit_impl.h"
 #include "services/resource_coordinator/observers/coordination_unit_graph_observer.h"
+#include "services/resource_coordinator/resource_coordinator_clock.h"
 
 namespace resource_coordinator {
 
 PageCoordinationUnitImpl::PageCoordinationUnitImpl(
     const CoordinationUnitID& id,
     std::unique_ptr<service_manager::ServiceContextRef> service_ref)
-    : CoordinationUnitInterface(id, std::move(service_ref)),
-      clock_(new base::DefaultTickClock()) {}
+    : CoordinationUnitInterface(id, std::move(service_ref)) {}
 
 PageCoordinationUnitImpl::~PageCoordinationUnitImpl() {
   for (auto* child_frame : frame_coordination_units_)
@@ -117,22 +117,17 @@
 base::TimeDelta PageCoordinationUnitImpl::TimeSinceLastNavigation() const {
   if (navigation_committed_time_.is_null())
     return base::TimeDelta();
-  return clock_->NowTicks() - navigation_committed_time_;
+  return ResourceCoordinatorClock::NowTicks() - navigation_committed_time_;
 }
 
 base::TimeDelta PageCoordinationUnitImpl::TimeSinceLastVisibilityChange()
     const {
-  return clock_->NowTicks() - visibility_change_time_;
-}
-
-void PageCoordinationUnitImpl::SetClockForTest(
-    std::unique_ptr<base::TickClock> test_clock) {
-  clock_ = std::move(test_clock);
+  return ResourceCoordinatorClock::NowTicks() - visibility_change_time_;
 }
 
 void PageCoordinationUnitImpl::OnEventReceived(mojom::Event event) {
   if (event == mojom::Event::kNavigationCommitted)
-    navigation_committed_time_ = clock_->NowTicks();
+    navigation_committed_time_ = ResourceCoordinatorClock::NowTicks();
   for (auto& observer : observers())
     observer.OnPageEventReceived(this, event);
 }
@@ -141,7 +136,7 @@
     const mojom::PropertyType property_type,
     int64_t value) {
   if (property_type == mojom::PropertyType::kVisible)
-    visibility_change_time_ = clock_->NowTicks();
+    visibility_change_time_ = ResourceCoordinatorClock::NowTicks();
   for (auto& observer : observers())
     observer.OnPagePropertyChanged(this, property_type, value);
 }
diff --git a/services/resource_coordinator/coordination_unit/page_coordination_unit_impl.h b/services/resource_coordinator/coordination_unit/page_coordination_unit_impl.h
index 673da80..164b50f 100644
--- a/services/resource_coordinator/coordination_unit/page_coordination_unit_impl.h
+++ b/services/resource_coordinator/coordination_unit/page_coordination_unit_impl.h
@@ -6,7 +6,6 @@
 #define SERVICES_RESOURCE_COORDINATOR_COORDINATION_UNIT_PAGE_COORDINATION_UNIT_IMPL_H_
 
 #include "base/macros.h"
-#include "base/time/tick_clock.h"
 #include "base/time/time.h"
 #include "services/resource_coordinator/coordination_unit/coordination_unit_base.h"
 
@@ -56,8 +55,6 @@
   // PageCoordinationUnit.
   base::TimeDelta TimeSinceLastVisibilityChange() const;
 
-  void SetClockForTest(std::unique_ptr<base::TickClock> test_clock);
-
   const std::set<FrameCoordinationUnitImpl*>&
   frame_coordination_units_for_testing() const {
     return frame_coordination_units_;
@@ -79,7 +76,6 @@
 
   std::set<FrameCoordinationUnitImpl*> frame_coordination_units_;
 
-  std::unique_ptr<base::TickClock> clock_;
   base::TimeTicks visibility_change_time_;
   // Main frame navigation committed time.
   base::TimeTicks navigation_committed_time_;
diff --git a/services/resource_coordinator/coordination_unit/page_coordination_unit_impl_unittest.cc b/services/resource_coordinator/coordination_unit/page_coordination_unit_impl_unittest.cc
index a90230c..e6a0a54 100644
--- a/services/resource_coordinator/coordination_unit/page_coordination_unit_impl_unittest.cc
+++ b/services/resource_coordinator/coordination_unit/page_coordination_unit_impl_unittest.cc
@@ -12,13 +12,36 @@
 #include "services/resource_coordinator/coordination_unit/process_coordination_unit_impl.h"
 #include "services/resource_coordinator/public/cpp/coordination_unit_types.h"
 #include "services/resource_coordinator/public/interfaces/coordination_unit.mojom.h"
+#include "services/resource_coordinator/resource_coordinator_clock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace resource_coordinator {
 
 namespace {
 
-class PageCoordinationUnitImplTest : public CoordinationUnitTestHarness {};
+class PageCoordinationUnitImplTest : public CoordinationUnitTestHarness {
+ public:
+  void SetUp() override {
+    ResourceCoordinatorClock::SetClockForTesting(
+        std::make_unique<base::SimpleTestTickClock>());
+    clock_ = static_cast<base::SimpleTestTickClock*>(
+        ResourceCoordinatorClock::GetClockForTesting());
+
+    // Sets a valid starting time.
+    clock_->SetNowTicks(base::TimeTicks::Now());
+  }
+
+  void TearDown() override {
+    clock_ = nullptr;
+    ResourceCoordinatorClock::ResetClockForTesting();
+  }
+
+ protected:
+  void AdvanceClock(base::TimeDelta delta) { clock_->Advance(delta); }
+
+ private:
+  base::SimpleTestTickClock* clock_ = nullptr;
+};
 
 }  // namespace
 
@@ -129,48 +152,36 @@
 
 TEST_F(PageCoordinationUnitImplTest, TimeSinceLastVisibilityChange) {
   MockSinglePageInSingleProcessCoordinationUnitGraph cu_graph;
-  base::SimpleTestTickClock* clock = new base::SimpleTestTickClock();
-  cu_graph.page->SetClockForTest(
-      std::unique_ptr<base::SimpleTestTickClock>(clock));
 
   cu_graph.page->SetVisibility(true);
   EXPECT_TRUE(cu_graph.page->IsVisible());
-  clock->Advance(base::TimeDelta::FromSeconds(42));
+  AdvanceClock(base::TimeDelta::FromSeconds(42));
   EXPECT_EQ(base::TimeDelta::FromSeconds(42),
             cu_graph.page->TimeSinceLastVisibilityChange());
 
   cu_graph.page->SetVisibility(false);
-  clock->Advance(base::TimeDelta::FromSeconds(23));
+  AdvanceClock(base::TimeDelta::FromSeconds(23));
   EXPECT_EQ(base::TimeDelta::FromSeconds(23),
             cu_graph.page->TimeSinceLastVisibilityChange());
   EXPECT_FALSE(cu_graph.page->IsVisible());
-  // The clock is owned and destructed by the page cu.
-  clock = nullptr;
 }
 
 TEST_F(PageCoordinationUnitImplTest, TimeSinceLastNavigation) {
   MockSinglePageInSingleProcessCoordinationUnitGraph cu_graph;
-  base::SimpleTestTickClock* clock = new base::SimpleTestTickClock();
-  // Sets a valid starting time.
-  clock->SetNowTicks(base::TimeTicks::Now());
-  cu_graph.page->SetClockForTest(
-      std::unique_ptr<base::SimpleTestTickClock>(clock));
   // Before any commit events, timedelta should be 0.
   EXPECT_TRUE(cu_graph.page->TimeSinceLastNavigation().is_zero());
 
   // 1st navigation.
   cu_graph.page->OnMainFrameNavigationCommitted();
-  clock->Advance(base::TimeDelta::FromSeconds(11));
+  AdvanceClock(base::TimeDelta::FromSeconds(11));
   EXPECT_EQ(base::TimeDelta::FromSeconds(11),
             cu_graph.page->TimeSinceLastNavigation());
 
   // 2nd navigation.
   cu_graph.page->OnMainFrameNavigationCommitted();
-  clock->Advance(base::TimeDelta::FromSeconds(17));
+  AdvanceClock(base::TimeDelta::FromSeconds(17));
   EXPECT_EQ(base::TimeDelta::FromSeconds(17),
             cu_graph.page->TimeSinceLastNavigation());
-  // The clock is owned and destructed by the page cu.
-  clock = nullptr;
 }
 
 }  // namespace resource_coordinator
diff --git a/services/resource_coordinator/observers/metrics_collector.cc b/services/resource_coordinator/observers/metrics_collector.cc
index 997cd79..a42d8ce8 100644
--- a/services/resource_coordinator/observers/metrics_collector.cc
+++ b/services/resource_coordinator/observers/metrics_collector.cc
@@ -11,6 +11,7 @@
 #include "services/resource_coordinator/coordination_unit/process_coordination_unit_impl.h"
 #include "services/resource_coordinator/public/cpp/coordination_unit_id.h"
 #include "services/resource_coordinator/public/cpp/resource_coordinator_features.h"
+#include "services/resource_coordinator/resource_coordinator_clock.h"
 
 namespace resource_coordinator {
 
@@ -51,8 +52,7 @@
 }
 
 MetricsCollector::MetricsCollector()
-    : clock_(&default_tick_clock_),
-      max_ukm_cpu_usage_measurements_(kDefaultMaxCPUUsageMeasurements) {
+    : max_ukm_cpu_usage_measurements_(kDefaultMaxCPUUsageMeasurements) {
   UpdateWithFieldTrialParams();
 }
 
@@ -91,7 +91,7 @@
   if (property_type == mojom::PropertyType::kAudible) {
     bool audible = static_cast<bool>(value);
     if (!audible) {
-      frame_data.last_audible_time = clock_->NowTicks();
+      frame_data.last_audible_time = ResourceCoordinatorClock::NowTicks();
       return;
     }
     auto* page_cu = frame_cu->GetPageCoordinationUnit();
@@ -101,7 +101,7 @@
     }
     // Audio is considered to have started playing if the page has never
     // previously played audio, or has been silent for at least one minute.
-    auto now = clock_->NowTicks();
+    auto now = ResourceCoordinatorClock::NowTicks();
     if (frame_data.last_audible_time + kMaxAudioSlientTimeout < now) {
       MetricsReportRecord& record =
           metrics_report_record_map_.find(page_cu->id())->second;
@@ -199,10 +199,6 @@
   }
 }
 
-void MetricsCollector::SetClockForTest(base::TickClock* test_clock) {
-  const_cast<base::TickClock*&>(clock_) = test_clock;
-}
-
 bool MetricsCollector::ShouldReportMetrics(
     const PageCoordinationUnitImpl* page_cu) {
   return page_cu->TimeSinceLastNavigation() > kMetricsReportDelayTimeout;
diff --git a/services/resource_coordinator/observers/metrics_collector.h b/services/resource_coordinator/observers/metrics_collector.h
index 5056c715..fdaef15 100644
--- a/services/resource_coordinator/observers/metrics_collector.h
+++ b/services/resource_coordinator/observers/metrics_collector.h
@@ -7,7 +7,6 @@
 
 #include "base/macros.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/time/default_tick_clock.h"
 #include "base/time/time.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
@@ -56,8 +55,6 @@
   void OnPageEventReceived(const PageCoordinationUnitImpl* page_cu,
                            const mojom::Event event) override;
 
-  void SetClockForTest(base::TickClock* test_clock);
-
  private:
   struct MetricsReportRecord {
     MetricsReportRecord();
@@ -112,10 +109,6 @@
   void UpdateWithFieldTrialParams();
   void ResetMetricsReportRecord(CoordinationUnitID cu_id);
 
-  // Note: |clock_| is always |&default_tick_clock_|, except during unit
-  // testing.
-  base::DefaultTickClock default_tick_clock_;
-  base::TickClock* const clock_;
   std::map<CoordinationUnitID, FrameData> frame_data_map_;
   // The metrics_report_record_map_ is used to record whether a metric was
   // already reported to avoid reporting multiple metrics.
diff --git a/services/resource_coordinator/observers/metrics_collector_unittest.cc b/services/resource_coordinator/observers/metrics_collector_unittest.cc
index 7520fe7..21e9db8 100644
--- a/services/resource_coordinator/observers/metrics_collector_unittest.cc
+++ b/services/resource_coordinator/observers/metrics_collector_unittest.cc
@@ -10,6 +10,7 @@
 #include "services/resource_coordinator/coordination_unit/coordination_unit_test_harness.h"
 #include "services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.h"
 #include "services/resource_coordinator/coordination_unit/page_coordination_unit_impl.h"
+#include "services/resource_coordinator/resource_coordinator_clock.h"
 
 namespace resource_coordinator {
 
@@ -29,28 +30,26 @@
   MAYBE_MetricsCollectorTest() : CoordinationUnitTestHarness() {}
 
   void SetUp() override {
-    clock_ = new base::SimpleTestTickClock();
+    MetricsCollector* metrics_collector = new MetricsCollector();
+    ResourceCoordinatorClock::SetClockForTesting(
+        std::make_unique<base::SimpleTestTickClock>());
+    clock_ = static_cast<base::SimpleTestTickClock*>(
+        ResourceCoordinatorClock::GetClockForTesting());
+
     // Sets a valid starting time.
     clock_->SetNowTicks(base::TimeTicks::Now());
-    MetricsCollector* metrics_collector = new MetricsCollector();
-    metrics_collector->SetClockForTest(clock_);
     coordination_unit_manager().RegisterObserver(
         base::WrapUnique(metrics_collector));
   }
 
-  void TearDown() override { clock_ = nullptr; }
+  void TearDown() override {
+    clock_ = nullptr;
+    ResourceCoordinatorClock::ResetClockForTesting();
+  }
 
  protected:
   void AdvanceClock(base::TimeDelta delta) { clock_->Advance(delta); }
 
-  TestCoordinationUnitWrapper<PageCoordinationUnitImpl>
-  CreatePageCoordinationUnitWithClock() {
-    auto page_cu = CreateCoordinationUnit<PageCoordinationUnitImpl>();
-    page_cu->SetClockForTest(
-        std::unique_ptr<base::SimpleTestTickClock>(clock_));
-    return page_cu;
-  }
-
   base::HistogramTester histogram_tester_;
   base::SimpleTestTickClock* clock_ = nullptr;
 
@@ -59,7 +58,7 @@
 };
 
 TEST_F(MAYBE_MetricsCollectorTest, FromBackgroundedToFirstAudioStartsUMA) {
-  auto page_cu = CreatePageCoordinationUnitWithClock();
+  auto page_cu = CreateCoordinationUnit<PageCoordinationUnitImpl>();
   auto frame_cu = CreateCoordinationUnit<FrameCoordinationUnitImpl>();
   coordination_unit_manager().OnCoordinationUnitCreated(page_cu.get());
   coordination_unit_manager().OnCoordinationUnitCreated(frame_cu.get());
@@ -111,7 +110,7 @@
 
 TEST_F(MAYBE_MetricsCollectorTest,
        FromBackgroundedToFirstAudioStartsUMA5MinutesTimeout) {
-  auto page_cu = CreatePageCoordinationUnitWithClock();
+  auto page_cu = CreateCoordinationUnit<PageCoordinationUnitImpl>();
   auto frame_cu = CreateCoordinationUnit<FrameCoordinationUnitImpl>();
   coordination_unit_manager().OnCoordinationUnitCreated(page_cu.get());
   coordination_unit_manager().OnCoordinationUnitCreated(frame_cu.get());
@@ -133,7 +132,7 @@
 }
 
 TEST_F(MAYBE_MetricsCollectorTest, FromBackgroundedToFirstTitleUpdatedUMA) {
-  auto page_cu = CreatePageCoordinationUnitWithClock();
+  auto page_cu = CreateCoordinationUnit<PageCoordinationUnitImpl>();
   coordination_unit_manager().OnCoordinationUnitCreated(page_cu.get());
 
   page_cu->OnMainFrameNavigationCommitted();
@@ -166,7 +165,7 @@
 
 TEST_F(MAYBE_MetricsCollectorTest,
        FromBackgroundedToFirstTitleUpdatedUMA5MinutesTimeout) {
-  auto page_cu = CreatePageCoordinationUnitWithClock();
+  auto page_cu = CreateCoordinationUnit<PageCoordinationUnitImpl>();
   coordination_unit_manager().OnCoordinationUnitCreated(page_cu.get());
 
   page_cu->OnMainFrameNavigationCommitted();
@@ -183,7 +182,7 @@
 }
 
 TEST_F(MAYBE_MetricsCollectorTest, FromBackgroundedToFirstAlertFiredUMA) {
-  auto page_cu = CreatePageCoordinationUnitWithClock();
+  auto page_cu = CreateCoordinationUnit<PageCoordinationUnitImpl>();
   auto frame_cu = CreateCoordinationUnit<FrameCoordinationUnitImpl>();
   coordination_unit_manager().OnCoordinationUnitCreated(page_cu.get());
   coordination_unit_manager().OnCoordinationUnitCreated(frame_cu.get());
@@ -219,7 +218,7 @@
 
 TEST_F(MAYBE_MetricsCollectorTest,
        FromBackgroundedToFirstAlertFiredUMA5MinutesTimeout) {
-  auto page_cu = CreatePageCoordinationUnitWithClock();
+  auto page_cu = CreateCoordinationUnit<PageCoordinationUnitImpl>();
   auto frame_cu = CreateCoordinationUnit<FrameCoordinationUnitImpl>();
   coordination_unit_manager().OnCoordinationUnitCreated(page_cu.get());
   coordination_unit_manager().OnCoordinationUnitCreated(frame_cu.get());
@@ -240,7 +239,7 @@
 
 TEST_F(MAYBE_MetricsCollectorTest,
        FromBackgroundedToFirstNonPersistentNotificationCreatedUMA) {
-  auto page_cu = CreatePageCoordinationUnitWithClock();
+  auto page_cu = CreateCoordinationUnit<PageCoordinationUnitImpl>();
   auto frame_cu = CreateCoordinationUnit<FrameCoordinationUnitImpl>();
   coordination_unit_manager().OnCoordinationUnitCreated(page_cu.get());
   coordination_unit_manager().OnCoordinationUnitCreated(frame_cu.get());
@@ -277,7 +276,7 @@
 TEST_F(
     MAYBE_MetricsCollectorTest,
     FromBackgroundedToFirstNonPersistentNotificationCreatedUMA5MinutesTimeout) {
-  auto page_cu = CreatePageCoordinationUnitWithClock();
+  auto page_cu = CreateCoordinationUnit<PageCoordinationUnitImpl>();
   auto frame_cu = CreateCoordinationUnit<FrameCoordinationUnitImpl>();
   coordination_unit_manager().OnCoordinationUnitCreated(page_cu.get());
   coordination_unit_manager().OnCoordinationUnitCreated(frame_cu.get());
@@ -297,7 +296,7 @@
 }
 
 TEST_F(MAYBE_MetricsCollectorTest, FromBackgroundedToFirstFaviconUpdatedUMA) {
-  auto page_cu = CreatePageCoordinationUnitWithClock();
+  auto page_cu = CreateCoordinationUnit<PageCoordinationUnitImpl>();
   coordination_unit_manager().OnCoordinationUnitCreated(page_cu.get());
 
   page_cu->OnMainFrameNavigationCommitted();
@@ -330,7 +329,7 @@
 
 TEST_F(MAYBE_MetricsCollectorTest,
        FromBackgroundedToFirstFaviconUpdatedUMA5MinutesTimeout) {
-  auto page_cu = CreatePageCoordinationUnitWithClock();
+  auto page_cu = CreateCoordinationUnit<PageCoordinationUnitImpl>();
   coordination_unit_manager().OnCoordinationUnitCreated(page_cu.get());
 
   page_cu->OnMainFrameNavigationCommitted();
diff --git a/services/resource_coordinator/resource_coordinator_clock.cc b/services/resource_coordinator/resource_coordinator_clock.cc
new file mode 100644
index 0000000..bf3b237
--- /dev/null
+++ b/services/resource_coordinator/resource_coordinator_clock.cc
@@ -0,0 +1,39 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/resource_coordinator/resource_coordinator_clock.h"
+
+#include "base/time/tick_clock.h"
+
+namespace resource_coordinator {
+
+namespace {
+
+std::unique_ptr<base::TickClock>& g_tick_clock_for_testing() {
+  static std::unique_ptr<base::TickClock> tick_clock_for_testing = nullptr;
+  return tick_clock_for_testing;
+}
+
+}  // namespace
+
+base::TimeTicks ResourceCoordinatorClock::NowTicks() {
+  return g_tick_clock_for_testing() ? g_tick_clock_for_testing()->NowTicks()
+                                    : base::TimeTicks::Now();
+}
+
+base::TickClock* ResourceCoordinatorClock::GetClockForTesting() {
+  return g_tick_clock_for_testing().get();
+}
+
+void ResourceCoordinatorClock::ResetClockForTesting() {
+  g_tick_clock_for_testing().reset();
+}
+
+void ResourceCoordinatorClock::SetClockForTesting(
+    std::unique_ptr<base::TickClock> tick_clock) {
+  DCHECK(!g_tick_clock_for_testing());
+  g_tick_clock_for_testing() = std::move(tick_clock);
+}
+
+}  // namespace resource_coordinator
diff --git a/services/resource_coordinator/resource_coordinator_clock.h b/services/resource_coordinator/resource_coordinator_clock.h
new file mode 100644
index 0000000..ef45054
--- /dev/null
+++ b/services/resource_coordinator/resource_coordinator_clock.h
@@ -0,0 +1,42 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_RESOURCE_COORDINATOR_RESOURCE_COORDINATOR_CLOCK_H_
+#define SERVICES_RESOURCE_COORDINATOR_RESOURCE_COORDINATOR_CLOCK_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/time/time.h"
+
+namespace base {
+class TickClock;
+}
+
+namespace resource_coordinator {
+
+// ResourceCoordinatorClock provides timing methods that resource_coordinator/
+// needs at a central place, and facilitates testing across components when
+// clock manipulation is needed.
+class ResourceCoordinatorClock {
+ public:
+  // Returns time from the testing TickClock if set; otherwise returns time from
+  // TimeTicks::Now().
+  static base::TimeTicks NowTicks();
+
+  static base::TickClock* GetClockForTesting();
+
+  // Sets a TickClock for testing, the ownership of the |tick_clock| will be
+  // transferred to the global clock.
+  static void SetClockForTesting(std::unique_ptr<base::TickClock> tick_clock);
+
+  static void ResetClockForTesting();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ResourceCoordinatorClock);
+};
+
+}  // namespace resource_coordinator
+
+#endif  // SERVICES_RESOURCE_COORDINATOR_RESOURCE_COORDINATOR_CLOCK_H_
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 0e7eab7..bb74cd2 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -169,20 +169,6 @@
         "test": "compositor_unittests"
       },
       {
-        "args": [
-          "--enable-viz",
-          "--ozone-platform=headless",
-          "--override-use-software-gl-for-tests",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/viz.content_browsertests.filter"
-        ],
-        "name": "viz_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "shards": 2
-        },
-        "test": "content_browsertests"
-      },
-      {
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 2
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index adf8d8115..751e70e3 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -4393,7 +4393,8 @@
         "name": "viz_content_browsertests",
         "swarming": {
           "can_use_on_swarming_builders": true,
-          "shards": 2
+          "hard_timeout": 1500,
+          "shards": 5
         },
         "test": "content_browsertests"
       },
diff --git a/testing/buildbot/filters/BUILD.gn b/testing/buildbot/filters/BUILD.gn
index fe0bfe9..f45d205a 100644
--- a/testing/buildbot/filters/BUILD.gn
+++ b/testing/buildbot/filters/BUILD.gn
@@ -48,7 +48,6 @@
     "//testing/buildbot/filters/site-per-process.content_browsertests.filter",
     "//testing/buildbot/filters/mojo.fyi.mus.content_browsertests.filter",
     "//testing/buildbot/filters/mojo.fyi.viz.content_browsertests.filter",
-    "//testing/buildbot/filters/viz.content_browsertests.filter",
   ]
 }
 
diff --git a/testing/buildbot/filters/ash_unittests_mash.filter b/testing/buildbot/filters/ash_unittests_mash.filter
index 4807729..5f9bb4b 100644
--- a/testing/buildbot/filters/ash_unittests_mash.filter
+++ b/testing/buildbot/filters/ash_unittests_mash.filter
@@ -2,6 +2,7 @@
 # include a link. If a test should never run on mash, add an early exit to the
 # code instead of listing here. See Shell::GetAshConfig().
 
+# TODO: AppList needs to respond to fullscreen and VKB: crbug.com/610874
 -AppListPresenterDelegateTest.AppListViewDragHandler
 -AppListPresenterDelegateTest.AppListViewDragHandlerTabletModeFromSearch
 -AppListPresenterDelegateTest.BottomShelfAlignmentTextStateTransitions
@@ -20,23 +21,34 @@
 -AppListPresenterDelegateTest.TapAndClickOutsideClosesHalfAppList/0
 -AppListPresenterDelegateTest.TapAndClickOutsideClosesHalfAppList/1
 -AppListPresenterDelegateTest.WhitespaceQuery
+
+# TODO: CursorManagerTestApi. http://crbug.com/780637
 -CursorWindowControllerTest.DSF
 -CursorWindowControllerTest.MoveToDifferentDisplay
 -CursorWindowControllerTest.ShouldEnableCursorCompositing
 -CursorWindowControllerTest.VisibilityTest
+
 # TODO: Display manager. http://crbug.com/695569
 -DisplayManagerTest.SoftwareMirroringWithCompositingCursor
+
+# TODO: CursorManagerTestApi. http://crbug.com/780637
 -DragWindowResizerTest.CursorDeviceScaleFactor
+
+# TODO: Implement DragWindowController for mash? crbug.com/633782
 -DragWindowResizerTest.DragWindowController
 -DragWindowResizerTest.DragWindowControllerAcrossThreeDisplays
+
+# TODO: Implement/fix mouse warp in mash: crbug.com/747465
 -DragWindowResizerTest.MoveWindowAcrossDisplays
 -DragWindowResizerTest.WarpMousePointer
 -DragWindowResizerTest.WindowDragWithMultiDisplays
 -DragWindowResizerTest.WindowDragWithMultiDisplaysActiveRoot
 -DragWindowResizerTest.WindowDragWithMultiDisplaysRightToLeft
+
 # TODO: Extended desktop. http://crbug.com/695570
 -ExtendedDesktopTest.KeyEventsOnLockScreen
 -ExtendedDesktopTest.TestCursor
+
 # TODO: Top-of-screen mouse reveal doesn't work, maybe problem with
 # EventGenerator. http://crbug.com/698085
 -ImmersiveFullscreenControllerTest.Bubbles
@@ -51,6 +63,8 @@
 -ImmersiveFullscreenControllerTest.OnMouseEvent
 -ImmersiveFullscreenControllerTest.RevealViaGestureChildConsumesEvents
 -ImmersiveFullscreenControllerTest.Transient
+
+# TODO: Call CreateKeyboard() in Shell::OnSessionStateChanged: crbug.com/646565
 -LockActionHandlerLayoutManagerTest.KeyboardBounds
 -LockLayoutManagerTest.AccessibilityPanel
 -LockLayoutManagerTest.AccessibilityPanelWithMultipleMonitors
@@ -58,28 +72,35 @@
 -LockLayoutManagerTest.MaximizedFullscreenWindowBoundsAreEqualToScreen
 -LockLayoutManagerTest.MultipleMonitors
 -LockLayoutManagerTest.NorwmalWindowBoundsArePreserved
-# TODO: Fail because of broken input event routing. http://crbug.com/725257
--LockScreenSanityTest.PasswordSubmitCallsLockScreenClient
+
+# TODO: Triage
 -LoginMetricsRecorderTest.UnlockAttempts
 -LoginPasswordViewTest.PasswordSubmitClearsPassword
 -LoginPasswordViewTest.PasswordSubmitIncludesPasswordText
 -LoginPasswordViewTest.PasswordSubmitViaButton
+
+# TODO: Triage
 -MagnificationControllerTest.CenterTextCaretInViewport
 -MagnificationControllerTest.CenterTextCaretNotInsideViewport
 -MagnificationControllerTest.FollowTextInputFieldFocus
 -MagnificationControllerTest.FollowTextInputFieldKeyPress
 -MagnificationControllerTest.PanWindowToLeft
 -MagnificationControllerTest.PanWindowToRight
+
+# TODO: CursorManagerTestApi. http://crbug.com/780637
 -MirrorWindowControllerTest.MirrorCursorBasic
 -MirrorWindowControllerTest.MirrorCursorLocations
 -MirrorWindowControllerTest.MirrorCursorMoveOnEnter
 -MirrorWindowControllerTest.MirrorCursorRotate
 -MouseCursorEventFilterTest.CursorDeviceScaleFactor
+
+# TODO: Triage
 -MultiMirroringTest.CompositingCursorInMultiSoftwareMirroring
 -MultiMirroringTest.HardwareMirrorMode
 -MultiMirroringTest.SoftwareMirrorModeBasics
 -MultiMirroringTest.SourceAndDestinationInSoftwareMirrorMode
 -MultiMirroringTest.SwitchToAndFromSoftwareMirrorMode
+
 # TODO: MultiWindowResizeController. http://crbug.com/699172
 -MultiWindowResizeControllerTest.BasicTests
 -MultiWindowResizeControllerTest.ClickOutside
@@ -93,42 +114,55 @@
 -NativeCursorManagerAshTest.SetCursorSize
 -NativeCursorManagerAshTest.SetDeviceScaleFactorAndRotation
 -NativeCursorManagerAshTest.UIScaleShouldNotChangeCursor
+
 # TODO: Maybe due to dragging across displays. http://crbug.com/698888
 -NormalPanelPopup/PanelWindowResizerTransientTest.PanelWithTransientChild/0
+
+# TODO: Triage
 -OverviewGestureHandlerTest.HorizontalScrollInOverview
 -OverviewGestureHandlerTest.ScrollUpDownWithoutReleasing
 -OverviewGestureHandlerTest.VerticalScrolls
+
 # TODO: Maybe due to dragging across displays. http://crbug.com/698888
 -PanelWindowResizerTest.AttachToSecondDisplay
 -PanelWindowResizerTest.AttachToSecondFullscreenDisplay
 -PanelWindowResizerTest.DetachAcrossDisplays
 -PanelWindowResizerTest.DetachThenAttachToSecondDisplay
 -PanelWindowResizerTest.DetachThenDragAcrossDisplays
+
 # TODO: Needs cursor manager support. http://crbug.com/698033
 -PartialScreenshotControllerTest.CursorVisibilityTest
 -PartialScreenshotControllerTest.LargeCursor
+
 # TODO: Needs LockStateController. http://crbug.com/632189.
 -PreferredReservedAcceleratorsTest.AcceleratorsWithFullscreen
 -PreferredReservedAcceleratorsTest.AcceleratorsWithPinned
+
+# TODO: CursorManagerTestApi. http://crbug.com/780637
 -ResizeShadowAndCursorTest.MaximizeRestore
 -ResizeShadowAndCursorTest.Minimize
 -ResizeShadowAndCursorTest.MouseDrag
 -ResizeShadowAndCursorTest.MouseHover
 -ResizeShadowAndCursorTest.Touch
+
+# TODO: Triage
 -ShelfLayoutManagerTest.SwipingUpOnShelfInLaptopModeForFullscreenAppList
 -ShelfLayoutManagerTest.SwipingUpOnShelfInTabletModeForFullscreenAppList
 -ShelfLayoutManagerTest.AutoHide
 -ShelfLayoutManagerTest.AutoHideShelfOnScreenBoundary
 -ShelfLayoutManagerTest.GestureDrag
+
 # TODO: Needs virtual keyboard. http://crbug.com/698892
 -SystemModalContainerLayoutManagerTest.SystemModalDialogGetPushedButNotCroppedFromKeyboard
 -SystemModalContainerLayoutManagerTest.SystemModalDialogGetPushedButNotCroppedFromKeyboardIfNotCentered
 -SystemModalContainerLayoutManagerTest.SystemModalDialogGetPushedFromKeyboard
+
 # TODO: ShellPortMash::CreateTabletModeEventHandler. http://crbug.com/698093
 -TabletModeWindowManagerTest.ExitFullScreenWithEdgeSwipeFromBottom
 -TabletModeWindowManagerTest.ExitFullScreenWithEdgeSwipeFromTop
 -TabletModeWindowManagerTest.ExitFullScreenWithEdgeTouchAtBottom
 -TabletModeWindowManagerTest.ExitFullScreenWithEdgeTouchAtTop
+
 # TODO: Touch HUD. http://crbug.com/698032
 -TouchHudDebugTest.DualDisplays
 -TouchHudDebugTest.Headless
@@ -138,41 +172,46 @@
 -TouchHudDebugTest.SingleDisplay
 -TouchHudDebugTest.SwapPrimaryDisplay
 -TouchHudDebugTest.SwapPrimaryThenMirrorDisplays
+
 # TODO: Needs virtual keyboard. http://crbug.com/616909
 -TrayIMETest.HidesOnA11yEnabled
 -TrayIMETest.PerformActionOnDetailedView
-# TODO: wire up mirroring and unified display.
-# http://crbug.com/770243.
+
+# TODO: Wire up mirroring and unified display: http://crbug.com/770243.
 -UnifiedMouseWarpControllerTest.BoundaryTest
 -UnifiedMouseWarpControllerTest.BoundaryAndWarpSimpleTest
 -UnifiedMouseWarpControllerTest.BoundaryTestGrid
 -UnifiedMouseWarpControllerTest.WarpMouse
-# TODO: Needs virtual keyboard. http://crbug.com/616909
+
+# TODO: Call CreateKeyboard() in Shell::OnSessionStateChanged: crbug.com/646565
 -VirtualKeyboardAlwaysOnTopControllerTest.NotifyKeyboardBoundsChanged
--VirtualKeyboardControllerAlwaysEnabledTest.DoesNotSuppressKeyboard
+
+# TODO: Needs virtual keyboard. http://crbug.com/616909
 -VirtualKeyboardControllerAutoTest.DisabledIfInternalKeyboardPresent
 -VirtualKeyboardControllerAutoTest.DisabledIfNoTouchScreen
 -VirtualKeyboardControllerAutoTest.EnabledDuringTabletMode
--VirtualKeyboardControllerAutoTest.HandleMultipleKeyboardsPresent
 -VirtualKeyboardControllerAutoTest.SuppressedIfExternalKeyboardPresent
 -VirtualKeyboardControllerAutoTest.SuppressedInMaximizedMode
--VirtualKeyboardControllerTest.RestoreKeyboardDevices
+
 # TODO: http://crbug.com/698894
 -WindowCycleControllerTest.MouseEventsCaptured
 -WindowCycleControllerTest.TabKeyNotLeaked
+
 # TODO: Crashes in bounds_animator.cc. http://crbug.com/730759
 -WindowSelectorTest.MultipleDisplays
 -WindowSelectorTest.RemoveDisplay
 -WindowSelectorTest.RemoveDisplayWithAnimation
+
+# TODO: CursorManagerTestApi. http://crbug.com/780637
 -WindowTreeHostManagerTest.UpdateMouseLocationAfterDisplayChange_PrimaryDisconnected
 -WindowTreeHostManagerTest.UpdateMouseLocationAfterDisplayChange_SwapPrimary
-# TODO: fix this. It might fail because GL_OES_texture_npot is not supported.
-# http://crbug.com/775067.
--WorkspaceLayoutManagerBackdropTest.BackdropTest
+
+# TODO: Needs virtual keyboard. http://crbug.com/616909
 -WorkspaceLayoutManagerKeyboardTest.AdjustWindowForA11yKeyboard
 -WorkspaceLayoutManagerKeyboardTest.ChildWindowFocused
 -WorkspaceLayoutManagerKeyboardTest.IgnoreKeyboardBoundsChange
 -WorkspaceLayoutManagerKeyboardTest.IgnoreWorkAreaChangeinNonStickyMode
+
 # TODO: Needs CursorManager. http://crbug.com/631103
 -WorkspaceWindowResizerTest.MouseMoveWithTouchDrag
 
diff --git a/testing/buildbot/filters/mojo.fyi.viz.content_browsertests.filter b/testing/buildbot/filters/mojo.fyi.viz.content_browsertests.filter
index 0c04290..48074f8 100644
--- a/testing/buildbot/filters/mojo.fyi.viz.content_browsertests.filter
+++ b/testing/buildbot/filters/mojo.fyi.viz.content_browsertests.filter
@@ -1,4 +1,3 @@
-# TODO: further define failures, master issue http://crbug.com/760181
 -CaptureScreenshotTest.*
 -CompositedScrollingBrowserTest.*
 -ContentBrowserTestSanityTest.*
diff --git a/testing/buildbot/filters/viz.content_browsertests.filter b/testing/buildbot/filters/viz.content_browsertests.filter
deleted file mode 100644
index 0c04290..0000000
--- a/testing/buildbot/filters/viz.content_browsertests.filter
+++ /dev/null
@@ -1,57 +0,0 @@
-# TODO: further define failures, master issue http://crbug.com/760181
--CaptureScreenshotTest.*
--CompositedScrollingBrowserTest.*
--ContentBrowserTestSanityTest.*
--CrossProcessFrameTreeBrowserTest.*
--CrossSiteResourceHandlerTest.*
--CrossSiteTransferTest/CrossSiteTransferTest.*
--DevToolsProtocolTest.*
--DomSerializerTests.*
--DownloadContentTest.*
--DumpAccessibilityTreeTest.*
--FindRequestManagerTests/FindRequestManagerTest.*
--GLAndSoftwareCompositing/CompositingRenderWidgetHostViewBrowserTest.*
--GLAndSoftwareCompositing/CompositingRenderWidgetHostViewBrowserTestHiDPI.*
--GLAndSoftwareCompositing/CompositingRenderWidgetHostViewBrowserTestTabCapture.*
--GLAndSoftwareCompositing/CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI.*
--ImageTransportFactoryTearDownBrowserTest.*
--IndexedDBBrowserTestSingleProcess.*
--IsolateIcelandFrameTreeBrowserTest.*
--IsolatedDevToolsProtocolTest.*
--IsolatedOriginTest.*
--MHTMLGenerationSitePerProcessTest.*
--MainThreadEventQueueBrowserTest.*
--NonBlockingEventBrowserTest.*
--OpenedByDOMTest.*
--PointerLockBrowserTest.*
--RenderFrameHostManagerTest.*
--RenderThreadImplDiscardableMemoryBrowserTest.*
--RenderViewBrowserTest.*
--RenderWidgetHostViewBrowserTestBase.*
--RenderWidgetHostViewChildFrameTest.*
--RequestDelayingSitePerProcessBrowserTest.*
--ResourceFetcherTests.*
--SavableResourcesTest.*
--ScreenOrientationOOPIFBrowserTest.*
--ScrollLatencyBrowserTest.*
--SecurityExploitBrowserTest.*
--SitePerProcessAccessibilityBrowserTest.*
--SitePerProcessBrowserTest.*
--SitePerProcessDevToolsBrowserTest.*
--SitePerProcessDevToolsProtocolTest.*
--SitePerProcessEmbedderCSPEnforcementBrowserTest.*
--SitePerProcessFeaturePolicyBrowserTest.*
--SitePerProcessFeaturePolicyDisabledBrowserTest.*
--SitePerProcessGestureBrowserTest.*
--SitePerProcessHighDPIBrowserTest.*
--SitePerProcessIgnoreCertErrorsBrowserTest.*
--SitePerProcessMouseWheelBrowserTest.*
--SnapshotBrowserTest.*
--TopDocumentIsolationTest.*
--TouchActionBrowserTest.*
--TouchSelectionControllerClientAuraScaleFactorTest.*
--TouchSelectionControllerClientAuraTest.*
--TouchSelectionForCrossProcessFramesTests/TouchSelectionControllerClientAuraSiteIsolationTest.*
--WakeLockTest.*
--WheelScrollLatchingBrowserTest.*
--WheelScrollLatchingDisabledBrowserTest.*
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/detached-context.https.html b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/detached-context.https.html
new file mode 100644
index 0000000..0d030b3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/detached-context.https.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Service WorkerRegistration from a removed iframe</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+// NOTE: This file tests corner case behavior that might not be defined in the
+// spec. See https://github.com/w3c/ServiceWorker/issues/1221
+
+promise_test(t => {
+    const url = 'resources/blank.html';
+    const scope_for_iframe = 'removed-registration'
+    const scope_for_main = 'resources/' + scope_for_iframe;
+    const script = 'resources/empty-worker.js';
+    let frame;
+
+    return service_worker_unregister(t, scope_for_main)
+      .then(() => {
+          return with_iframe(url);
+        })
+      .then(f => {
+          frame = f;
+          return navigator.serviceWorker.register(script,
+                                                  {scope: scope_for_main});
+        })
+      .then(r => {
+          add_completion_callback(() => { r.unregister(); });
+          return wait_for_state(t, r.installing, 'activated');
+        })
+      .then(() => {
+          return frame.contentWindow.navigator.serviceWorker.getRegistration(
+            scope_for_iframe);
+        })
+      .then(r => {
+          frame.remove();
+          assert_equals(r.installing, null);
+          assert_equals(r.waiting, null);
+          assert_equals(r.active.state, 'activated');
+          assert_equals(r.scope, normalizeURL(scope_for_main));
+          r.onupdatefound = () => { /* empty */ };
+          return Promise.all([
+              promise_rejects(t, 'InvalidStateError', r.unregister()),
+              promise_rejects(t, 'InvalidStateError', r.update())]);
+        })
+  }, 'accessing a ServiceWorkerRegistration from a removed iframe');
+
+promise_test(t => {
+    const script = 'resources/empty-worker.js';
+    const scope = 'resources/scope/serviceworker-from-detached';
+
+    return service_worker_unregister_and_register(t, script, scope)
+      .then(registration => {
+          add_completion_callback(() => { registration.unregister(); });
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(() => { return with_iframe(scope); })
+      .then(frame => {
+          const worker = frame.contentWindow.navigator.serviceWorker.controller;
+          frame.remove();
+          assert_equals(worker.scriptURL, normalizeURL(script));
+          assert_equals(worker.state, 'activated');
+          worker.onstatechange = () => { /* empty */ };
+          assert_throws(
+              { name: 'InvalidStateError' },
+              () => { worker.postMessage(''); },
+              'postMessage on a detached client should throw an exception.');
+        });
+  }, 'accessing a ServiceWorker object from a removed iframe');
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/extendable-message-event.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/extendable-message-event.html
deleted file mode 100644
index 600b0d6..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/extendable-message-event.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html>
-<title>ServiceWorkerGlobalScope: ExtendableMessageEvent</title>
-<script src='../../resources/testharness.js'></script>
-<script src='../../resources/testharnessreport.js'></script>
-<script src='../resources/test-helpers.js'></script>
-<script>
-
-// This test should be in chromium/ because the spec does not define behavior in
-// the case where postMessage() is called from a detached client.
-promise_test(function(t) {
-    var script = 'resources/empty-worker.js';
-    var scope = 'resources/scope/extendable-message-event-from-detached';
-
-    return service_worker_unregister_and_register(t, script, scope)
-      .then(function(registration) {
-          add_completion_callback(function() { registration.unregister(); });
-          return wait_for_state(t, registration.installing, 'activated');
-        })
-      .then(function() { return with_iframe(scope); })
-      .then(function(frame) {
-          var worker = frame.contentWindow.navigator.serviceWorker.controller;
-          frame.remove();
-          assert_throws(
-              { name: 'InvalidStateError' },
-              function() { worker.postMessage(''); },
-              'postMessage on a detached client should throw an exception.');
-        });
-  }, 'Post an extendable message from a detached client');
-
-</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/unregister-on-detached-iframe.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/unregister-on-detached-iframe.html
deleted file mode 100644
index b983801..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/unregister-on-detached-iframe.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>Service Worker: Unregistration on detached iframe context</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../resources/test-helpers.js"></script>
-<script>
-promise_test(function(t) {
-    var url = './resources/blank.html';
-    var scope_for_iframe = './unregister-on-detached-iframe'
-    var scope_for_main = './resources/' + scope_for_iframe;
-    var script = './resources/empty-worker.js';
-    var frame;
-
-    return service_worker_unregister(t, scope_for_main)
-      .then(function() {
-          return with_iframe(url);
-        })
-      .then(function(f) {
-          frame = f;
-          return navigator.serviceWorker.register(script,
-                                                  {scope: scope_for_main});
-        })
-      .then(function(r) {
-          add_completion_callback(function() { r.unregister(); } );
-          return frame.contentWindow.navigator.serviceWorker.getRegistration(
-            scope_for_iframe);
-        })
-      .then(function(r) {
-          frame.remove();
-          return promise_rejects(t, 'InvalidStateError', r.unregister());
-        });
-  }, 'Unregistration on a detached iframe should fail and throw ' +
-     'InvalidStateError exception');
-</script>
diff --git a/third_party/WebKit/Source/core/animation/ElementAnimations.h b/third_party/WebKit/Source/core/animation/ElementAnimations.h
index 5cc1728f..a829328 100644
--- a/third_party/WebKit/Source/core/animation/ElementAnimations.h
+++ b/third_party/WebKit/Source/core/animation/ElementAnimations.h
@@ -36,7 +36,6 @@
 #include "platform/wtf/HashCountedSet.h"
 #include "platform/wtf/HashMap.h"
 #include "platform/wtf/RefPtr.h"
-#include "platform/wtf/Vector.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/animation/PrimitiveInterpolation.h b/third_party/WebKit/Source/core/animation/PrimitiveInterpolation.h
index ae24125..e7f0bb8 100644
--- a/third_party/WebKit/Source/core/animation/PrimitiveInterpolation.h
+++ b/third_party/WebKit/Source/core/animation/PrimitiveInterpolation.h
@@ -11,7 +11,6 @@
 #include "platform/animation/AnimationUtilities.h"
 #include "platform/heap/Handle.h"
 #include "platform/wtf/PtrUtil.h"
-#include "platform/wtf/Vector.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/css/CSSFontFaceSourceTest.cpp b/third_party/WebKit/Source/core/css/CSSFontFaceSourceTest.cpp
index 85ca7fa..bd1dcb4b 100644
--- a/third_party/WebKit/Source/core/css/CSSFontFaceSourceTest.cpp
+++ b/third_party/WebKit/Source/core/css/CSSFontFaceSourceTest.cpp
@@ -18,8 +18,9 @@
   scoped_refptr<SimpleFontData> CreateFontData(
       const FontDescription&,
       const FontSelectionCapabilities&) override {
-    return SimpleFontData::Create(
-        FontPlatformData(SkTypeface::MakeDefault(), "", 0, false, false));
+    return SimpleFontData::Create(FontPlatformData(
+        PaintTypeface::FromSkTypeface(SkTypeface::MakeDefault()), "", 0, false,
+        false));
   }
 
   DummyFontFaceSource() {}
diff --git a/third_party/WebKit/Source/core/css/FontFaceSetDocument.h b/third_party/WebKit/Source/core/css/FontFaceSetDocument.h
index 07ceed5..037afcf 100644
--- a/third_party/WebKit/Source/core/css/FontFaceSetDocument.h
+++ b/third_party/WebKit/Source/core/css/FontFaceSetDocument.h
@@ -39,7 +39,6 @@
 #include "platform/AsyncMethodRunner.h"
 #include "platform/heap/Handle.h"
 #include "platform/wtf/Allocator.h"
-#include "platform/wtf/Vector.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/css/FontFaceSetWorker.h b/third_party/WebKit/Source/core/css/FontFaceSetWorker.h
index 924dcb7be..ba901a5 100644
--- a/third_party/WebKit/Source/core/css/FontFaceSetWorker.h
+++ b/third_party/WebKit/Source/core/css/FontFaceSetWorker.h
@@ -15,7 +15,6 @@
 #include "platform/AsyncMethodRunner.h"
 #include "platform/heap/Handle.h"
 #include "platform/wtf/Allocator.h"
-#include "platform/wtf/Vector.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/css/parser/CSSLazyParsingState.h b/third_party/WebKit/Source/core/css/parser/CSSLazyParsingState.h
index 3f177f38d..a1b520f 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSLazyParsingState.h
+++ b/third_party/WebKit/Source/core/css/parser/CSSLazyParsingState.h
@@ -8,7 +8,6 @@
 #include "core/css/CSSSelectorList.h"
 #include "core/css/StyleSheetContents.h"
 #include "core/css/parser/CSSParserMode.h"
-#include "platform/wtf/Vector.h"
 #include "platform/wtf/text/WTFString.h"
 
 namespace blink {
diff --git a/third_party/WebKit/Source/core/css/parser/CSSLazyPropertyParserImpl.h b/third_party/WebKit/Source/core/css/parser/CSSLazyPropertyParserImpl.h
index 43f3af9..573e7d4 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSLazyPropertyParserImpl.h
+++ b/third_party/WebKit/Source/core/css/parser/CSSLazyPropertyParserImpl.h
@@ -8,7 +8,6 @@
 #include "core/css/StylePropertySet.h"
 #include "core/css/parser/CSSParserTokenRange.h"
 #include "core/css/parser/CSSTokenizer.h"
-#include "platform/wtf/Vector.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserObserver.h b/third_party/WebKit/Source/core/css/parser/CSSParserObserver.h
index 7c406171..69eccb4c 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSParserObserver.h
+++ b/third_party/WebKit/Source/core/css/parser/CSSParserObserver.h
@@ -26,7 +26,6 @@
 #define CSSParserObserver_h
 
 #include "core/css/CSSPropertySourceData.h"
-#include "platform/wtf/Vector.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/css/parser/MediaQueryParser.cpp b/third_party/WebKit/Source/core/css/parser/MediaQueryParser.cpp
index b465a63..b0cfde99 100644
--- a/third_party/WebKit/Source/core/css/parser/MediaQueryParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/MediaQueryParser.cpp
@@ -6,7 +6,6 @@
 
 #include "core/css/parser/CSSTokenizer.h"
 #include "core/media_type_names.h"
-#include "platform/wtf/Vector.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleResolver.h b/third_party/WebKit/Source/core/css/resolver/StyleResolver.h
index 0ff816c8..4eb2413 100644
--- a/third_party/WebKit/Source/core/css/resolver/StyleResolver.h
+++ b/third_party/WebKit/Source/core/css/resolver/StyleResolver.h
@@ -39,7 +39,6 @@
 #include "platform/wtf/HashSet.h"
 #include "platform/wtf/ListHashSet.h"
 #include "platform/wtf/RefPtr.h"
-#include "platform/wtf/Vector.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/editing/iterators/SimplifiedBackwardsTextIteratorTest.cpp b/third_party/WebKit/Source/core/editing/iterators/SimplifiedBackwardsTextIteratorTest.cpp
index 680a7a7..7709127e 100644
--- a/third_party/WebKit/Source/core/editing/iterators/SimplifiedBackwardsTextIteratorTest.cpp
+++ b/third_party/WebKit/Source/core/editing/iterators/SimplifiedBackwardsTextIteratorTest.cpp
@@ -7,7 +7,6 @@
 #include "core/editing/EphemeralRange.h"
 #include "core/editing/SelectionTemplate.h"
 #include "core/editing/testing/EditingTestBase.h"
-#include "platform/wtf/Vector.h"
 #include "platform/wtf/text/StringBuilder.h"
 #include "platform/wtf/text/WTFString.h"
 
diff --git a/third_party/WebKit/Source/core/editing/serializers/MarkupAccumulator.h b/third_party/WebKit/Source/core/editing/serializers/MarkupAccumulator.h
index d04b5062..4fb620e8 100644
--- a/third_party/WebKit/Source/core/editing/serializers/MarkupAccumulator.h
+++ b/third_party/WebKit/Source/core/editing/serializers/MarkupAccumulator.h
@@ -31,7 +31,6 @@
 #include "core/editing/serializers/MarkupFormatter.h"
 #include "core/editing/serializers/Serialization.h"
 #include "platform/wtf/HashMap.h"
-#include "platform/wtf/Vector.h"
 #include "platform/wtf/text/StringBuilder.h"
 
 namespace blink {
diff --git a/third_party/WebKit/Source/core/editing/serializers/MarkupFormatter.h b/third_party/WebKit/Source/core/editing/serializers/MarkupFormatter.h
index f47b5262..3103f8b0 100644
--- a/third_party/WebKit/Source/core/editing/serializers/MarkupFormatter.h
+++ b/third_party/WebKit/Source/core/editing/serializers/MarkupFormatter.h
@@ -30,7 +30,6 @@
 #include "core/editing/EditingStrategy.h"
 #include "core/editing/serializers/Serialization.h"
 #include "platform/wtf/HashMap.h"
-#include "platform/wtf/Vector.h"
 #include "platform/wtf/text/StringBuilder.h"
 
 namespace blink {
diff --git a/third_party/WebKit/Source/core/exported/WebDevToolsAgentImpl.cpp b/third_party/WebKit/Source/core/exported/WebDevToolsAgentImpl.cpp
index f40e4be..6bebedf 100644
--- a/third_party/WebKit/Source/core/exported/WebDevToolsAgentImpl.cpp
+++ b/third_party/WebKit/Source/core/exported/WebDevToolsAgentImpl.cpp
@@ -32,6 +32,7 @@
 
 #include <v8-inspector.h>
 #include <memory>
+#include <utility>
 
 #include "bindings/core/v8/ScriptController.h"
 #include "bindings/core/v8/V8BindingForCore.h"
@@ -80,6 +81,7 @@
 #include "platform/wtf/MathExtras.h"
 #include "platform/wtf/Noncopyable.h"
 #include "platform/wtf/PtrUtil.h"
+#include "platform/wtf/Vector.h"
 #include "platform/wtf/text/WTFString.h"
 #include "public/platform/Platform.h"
 #include "public/platform/WebLayerTreeView.h"
diff --git a/third_party/WebKit/Source/core/exported/WebDevToolsAgentImpl.h b/third_party/WebKit/Source/core/exported/WebDevToolsAgentImpl.h
index 4d6f07c..bd1d69c 100644
--- a/third_party/WebKit/Source/core/exported/WebDevToolsAgentImpl.h
+++ b/third_party/WebKit/Source/core/exported/WebDevToolsAgentImpl.h
@@ -41,7 +41,6 @@
 #include "core/inspector/InspectorTracingAgent.h"
 #include "platform/heap/Handle.h"
 #include "platform/wtf/Forward.h"
-#include "platform/wtf/Vector.h"
 #include "public/platform/WebSize.h"
 #include "public/platform/WebThread.h"
 #include "public/web/WebDevToolsAgent.h"
diff --git a/third_party/WebKit/Source/core/exported/WebPluginContainerImpl.h b/third_party/WebKit/Source/core/exported/WebPluginContainerImpl.h
index 49f77501..bd7380d 100644
--- a/third_party/WebKit/Source/core/exported/WebPluginContainerImpl.h
+++ b/third_party/WebKit/Source/core/exported/WebPluginContainerImpl.h
@@ -38,7 +38,6 @@
 #include "platform/heap/Handle.h"
 #include "platform/wtf/Compiler.h"
 #include "platform/wtf/RefPtr.h"
-#include "platform/wtf/Vector.h"
 #include "platform/wtf/text/WTFString.h"
 #include "public/platform/WebCoalescedInputEvent.h"
 #include "public/platform/WebTouchEvent.h"
diff --git a/third_party/WebKit/Source/core/frame/Frame.h b/third_party/WebKit/Source/core/frame/Frame.h
index 138c82a..67d4bb1 100644
--- a/third_party/WebKit/Source/core/frame/Frame.h
+++ b/third_party/WebKit/Source/core/frame/Frame.h
@@ -55,6 +55,7 @@
 class LocalFrame;
 class KURL;
 class Page;
+class ResourceTimingInfo;
 class SecurityContext;
 class Settings;
 class WindowProxy;
@@ -87,6 +88,8 @@
   virtual void Navigate(const FrameLoadRequest&) = 0;
   virtual void Reload(FrameLoadType, ClientRedirectPolicy) = 0;
 
+  virtual void AddResourceTiming(const ResourceTimingInfo&) = 0;
+
   virtual void Detach(FrameDetachType);
   void DisconnectOwnerElement();
   virtual bool ShouldClose() = 0;
diff --git a/third_party/WebKit/Source/core/frame/LayoutSubtreeRootList.h b/third_party/WebKit/Source/core/frame/LayoutSubtreeRootList.h
index 6ee81d3c..d23f268 100644
--- a/third_party/WebKit/Source/core/frame/LayoutSubtreeRootList.h
+++ b/third_party/WebKit/Source/core/frame/LayoutSubtreeRootList.h
@@ -8,7 +8,6 @@
 #include "core/layout/DepthOrderedLayoutObjectList.h"
 #include "platform/wtf/Allocator.h"
 #include "platform/wtf/HashSet.h"
-#include "platform/wtf/Vector.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/frame/LocalFrame.cpp b/third_party/WebKit/Source/core/frame/LocalFrame.cpp
index ff971b6..17d1b9c 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrame.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalFrame.cpp
@@ -79,6 +79,7 @@
 #include "core/plugins/PluginView.h"
 #include "core/probe/CoreProbes.h"
 #include "core/svg/SVGDocumentExtensions.h"
+#include "core/timing/DOMWindowPerformance.h"
 #include "core/timing/Performance.h"
 #include "platform/Histogram.h"
 #include "platform/WebFrameScheduler.h"
@@ -265,6 +266,11 @@
   }
 }
 
+void LocalFrame::AddResourceTiming(const ResourceTimingInfo& info) {
+  DCHECK(IsAttached());
+  DOMWindowPerformance::performance(*DomWindow())->AddResourceTiming(info);
+}
+
 void LocalFrame::Detach(FrameDetachType type) {
   // Note that detach() can be re-entered, so it's not possible to
   // DCHECK(isAttached()) here.
diff --git a/third_party/WebKit/Source/core/frame/LocalFrame.h b/third_party/WebKit/Source/core/frame/LocalFrame.h
index d24fe54..685e0090e 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrame.h
+++ b/third_party/WebKit/Source/core/frame/LocalFrame.h
@@ -112,6 +112,7 @@
                 UserGestureStatus) override;
   void Navigate(const FrameLoadRequest&) override;
   void Reload(FrameLoadType, ClientRedirectPolicy) override;
+  void AddResourceTiming(const ResourceTimingInfo&) override;
   void Detach(FrameDetachType) override;
   bool ShouldClose() override;
   SecurityContext* GetSecurityContext() const override;
diff --git a/third_party/WebKit/Source/core/frame/PlatformEventDispatcher.h b/third_party/WebKit/Source/core/frame/PlatformEventDispatcher.h
index 2156be9..8d1665c 100644
--- a/third_party/WebKit/Source/core/frame/PlatformEventDispatcher.h
+++ b/third_party/WebKit/Source/core/frame/PlatformEventDispatcher.h
@@ -7,7 +7,6 @@
 
 #include "core/CoreExport.h"
 #include "platform/heap/Handle.h"
-#include "platform/wtf/Vector.h"
 
 namespace blink {
 class PlatformEventController;
diff --git a/third_party/WebKit/Source/core/frame/RemoteFrame.cpp b/third_party/WebKit/Source/core/frame/RemoteFrame.cpp
index c63e2c2..cfe9dd63 100644
--- a/third_party/WebKit/Source/core/frame/RemoteFrame.cpp
+++ b/third_party/WebKit/Source/core/frame/RemoteFrame.cpp
@@ -18,6 +18,7 @@
 #include "core/paint/PaintLayer.h"
 #include "platform/graphics/GraphicsLayer.h"
 #include "platform/loader/fetch/ResourceRequest.h"
+#include "platform/loader/fetch/ResourceTimingInfo.h"
 #include "platform/plugins/PluginScriptForbiddenScope.h"
 #include "platform/weborigin/SecurityPolicy.h"
 #include "public/platform/WebLayer.h"
@@ -79,6 +80,11 @@
   Client()->Reload(frame_load_type, client_redirect_policy);
 }
 
+void RemoteFrame::AddResourceTiming(const ResourceTimingInfo& info) {
+  DCHECK(info.IsMainResource());
+  // TODO(dcheng): Perform origin check, filter out fields, and forward via IPC.
+}
+
 void RemoteFrame::Detach(FrameDetachType type) {
   lifecycle_.AdvanceTo(FrameLifecycle::kDetaching);
 
diff --git a/third_party/WebKit/Source/core/frame/RemoteFrame.h b/third_party/WebKit/Source/core/frame/RemoteFrame.h
index a0e262a..5720265c 100644
--- a/third_party/WebKit/Source/core/frame/RemoteFrame.h
+++ b/third_party/WebKit/Source/core/frame/RemoteFrame.h
@@ -32,6 +32,7 @@
                 UserGestureStatus) override;
   void Navigate(const FrameLoadRequest& passed_request) override;
   void Reload(FrameLoadType, ClientRedirectPolicy) override;
+  void AddResourceTiming(const ResourceTimingInfo&) override;
   void Detach(FrameDetachType) override;
   RemoteSecurityContext* GetSecurityContext() const override;
   void PrintNavigationErrorMessage(const Frame&, const char* reason) override {}
diff --git a/third_party/WebKit/Source/core/frame/WebFrameSerializerImpl.h b/third_party/WebKit/Source/core/frame/WebFrameSerializerImpl.h
index 74ee256..c76e2d90 100644
--- a/third_party/WebKit/Source/core/frame/WebFrameSerializerImpl.h
+++ b/third_party/WebKit/Source/core/frame/WebFrameSerializerImpl.h
@@ -34,7 +34,6 @@
 #include "platform/text/WebEntities.h"
 #include "platform/wtf/Forward.h"
 #include "platform/wtf/HashMap.h"
-#include "platform/wtf/Vector.h"
 #include "platform/wtf/text/StringBuilder.h"
 #include "platform/wtf/text/StringHash.h"
 #include "platform/wtf/text/WTFString.h"
diff --git a/third_party/WebKit/Source/core/html/forms/HTMLOptionElement.cpp b/third_party/WebKit/Source/core/html/forms/HTMLOptionElement.cpp
index f30df03..b52d5a6 100644
--- a/third_party/WebKit/Source/core/html/forms/HTMLOptionElement.cpp
+++ b/third_party/WebKit/Source/core/html/forms/HTMLOptionElement.cpp
@@ -40,7 +40,6 @@
 #include "core/html_names.h"
 #include "core/layout/LayoutTheme.h"
 #include "core/style/ComputedStyle.h"
-#include "platform/wtf/Vector.h"
 #include "platform/wtf/text/StringBuilder.h"
 
 namespace blink {
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
index b179b4c..1fd2ad1f 100644
--- a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
@@ -64,7 +64,6 @@
 #include "core/paint/FirstMeaningfulPaintDetector.h"
 #include "core/probe/CoreProbes.h"
 #include "core/svg/graphics/SVGImageChromeClient.h"
-#include "core/timing/DOMWindowPerformance.h"
 #include "core/timing/Performance.h"
 #include "core/timing/PerformanceBase.h"
 #include "platform/WebFrameScheduler.h"
@@ -682,13 +681,20 @@
 }
 
 void FrameFetchContext::AddResourceTiming(const ResourceTimingInfo& info) {
-  Document* initiator_document = document_ && info.IsMainResource()
-                                     ? document_->ParentDocument()
-                                     : document_.Get();
-  if (!initiator_document || !initiator_document->domWindow())
+  // Normally, |document_| is cleared on Document shutdown. However, Documents
+  // for HTML imports will also not have a LocalFrame set: in that case, also
+  // early return, as there is nothing to report the resource timing to.
+  if (!document_ || !document_->GetFrame())
     return;
-  DOMWindowPerformance::performance(*initiator_document->domWindow())
-      ->AddResourceTiming(info);
+
+  Frame* initiator_frame = info.IsMainResource()
+                               ? document_->GetFrame()->Tree().Parent()
+                               : document_->GetFrame();
+
+  if (!initiator_frame)
+    return;
+
+  initiator_frame->AddResourceTiming(info);
 }
 
 bool FrameFetchContext::AllowImage(bool images_enabled, const KURL& url) const {
diff --git a/third_party/WebKit/Source/core/page/ChromeClient.h b/third_party/WebKit/Source/core/page/ChromeClient.h
index 08f47db..9b61be8 100644
--- a/third_party/WebKit/Source/core/page/ChromeClient.h
+++ b/third_party/WebKit/Source/core/page/ChromeClient.h
@@ -43,7 +43,6 @@
 #include "platform/text/TextDirection.h"
 #include "platform/wtf/Forward.h"
 #include "platform/wtf/Optional.h"
-#include "platform/wtf/Vector.h"
 #include "public/platform/BlameContext.h"
 #include "public/platform/WebDragOperation.h"
 #include "public/platform/WebEventListenerProperties.h"
diff --git a/third_party/WebKit/Source/core/page/FrameTree.cpp b/third_party/WebKit/Source/core/page/FrameTree.cpp
index 1532ca54..013b2b9a 100644
--- a/third_party/WebKit/Source/core/page/FrameTree.cpp
+++ b/third_party/WebKit/Source/core/page/FrameTree.cpp
@@ -30,7 +30,6 @@
 #include "core/frame/UseCounter.h"
 #include "core/page/Page.h"
 #include "platform/wtf/Assertions.h"
-#include "platform/wtf/Vector.h"
 #include "platform/wtf/text/CString.h"
 #include "platform/wtf/text/StringBuilder.h"
 
diff --git a/third_party/WebKit/Source/core/page/scrolling/SnapCoordinator.h b/third_party/WebKit/Source/core/page/scrolling/SnapCoordinator.h
index cdc7a90..38b1704f 100644
--- a/third_party/WebKit/Source/core/page/scrolling/SnapCoordinator.h
+++ b/third_party/WebKit/Source/core/page/scrolling/SnapCoordinator.h
@@ -8,7 +8,6 @@
 #include "core/CoreExport.h"
 #include "core/css/CSSPrimitiveValueMappings.h"
 #include "platform/heap/Handle.h"
-#include "platform/wtf/Vector.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/paint/InlinePainter.h b/third_party/WebKit/Source/core/paint/InlinePainter.h
index 0006abc..51987046 100644
--- a/third_party/WebKit/Source/core/paint/InlinePainter.h
+++ b/third_party/WebKit/Source/core/paint/InlinePainter.h
@@ -7,7 +7,6 @@
 
 #include "core/style/ComputedStyleConstants.h"
 #include "platform/wtf/Allocator.h"
-#include "platform/wtf/Vector.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/paint/ObjectPainter.cpp b/third_party/WebKit/Source/core/paint/ObjectPainter.cpp
index f0eb456..2cb0e9cd 100644
--- a/third_party/WebKit/Source/core/paint/ObjectPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/ObjectPainter.cpp
@@ -14,6 +14,7 @@
 #include "platform/geometry/LayoutPoint.h"
 #include "platform/graphics/GraphicsContextStateSaver.h"
 #include "platform/graphics/paint/DrawingRecorder.h"
+#include "platform/wtf/Vector.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/paint/ObjectPainter.h b/third_party/WebKit/Source/core/paint/ObjectPainter.h
index 0c5a2c6..90e71d8 100644
--- a/third_party/WebKit/Source/core/paint/ObjectPainter.h
+++ b/third_party/WebKit/Source/core/paint/ObjectPainter.h
@@ -9,7 +9,6 @@
 #include "core/style/ComputedStyleConstants.h"
 #include "platform/runtime_enabled_features.h"
 #include "platform/wtf/Allocator.h"
-#include "platform/wtf/Vector.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/paint/PrePaintTreeWalkTest.cpp b/third_party/WebKit/Source/core/paint/PrePaintTreeWalkTest.cpp
index 896a00869..752a3ab 100644
--- a/third_party/WebKit/Source/core/paint/PrePaintTreeWalkTest.cpp
+++ b/third_party/WebKit/Source/core/paint/PrePaintTreeWalkTest.cpp
@@ -17,7 +17,6 @@
 #include "platform/testing/UnitTestHelpers.h"
 #include "platform/text/TextStream.h"
 #include "platform/wtf/HashMap.h"
-#include "platform/wtf/Vector.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace blink {
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn
index 6f2d799db..515e2f49 100644
--- a/third_party/WebKit/Source/platform/BUILD.gn
+++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -1140,6 +1140,7 @@
     "graphics/paint/PaintController.h",
     "graphics/paint/PaintControllerDebugData.cpp",
     "graphics/paint/PaintFlags.h",
+    "graphics/paint/PaintFont.h",
     "graphics/paint/PaintPropertyNode.cpp",
     "graphics/paint/PaintPropertyNode.h",
     "graphics/paint/PaintRecord.h",
@@ -1147,6 +1148,8 @@
     "graphics/paint/PaintRecordBuilder.h",
     "graphics/paint/PaintRecorder.h",
     "graphics/paint/PaintShader.h",
+    "graphics/paint/PaintTextBlob.h",
+    "graphics/paint/PaintTypeface.h",
     "graphics/paint/PropertyTreeState.cpp",
     "graphics/paint/PropertyTreeState.h",
     "graphics/paint/RasterInvalidationTracking.cpp",
diff --git a/third_party/WebKit/Source/platform/fonts/Font.cpp b/third_party/WebKit/Source/platform/fonts/Font.cpp
index 33a589a..9314539c1 100644
--- a/third_party/WebKit/Source/platform/fonts/Font.cpp
+++ b/third_party/WebKit/Source/platform/fonts/Font.cpp
@@ -37,6 +37,7 @@
 #include "platform/geometry/FloatRect.h"
 #include "platform/graphics/paint/PaintCanvas.h"
 #include "platform/graphics/paint/PaintFlags.h"
+#include "platform/graphics/paint/PaintTextBlob.h"
 #include "platform/text/BidiResolver.h"
 #include "platform/text/Character.h"
 #include "platform/text/TextRun.h"
@@ -296,8 +297,9 @@
     SkScalar* offset_intercepts_buffer = nullptr;
     if (intercepts_buffer)
       offset_intercepts_buffer = &intercepts_buffer[num_intervals];
-    num_intervals += paint.getTextBlobIntercepts(
-        blob_info.blob.get(), bounds_array, offset_intercepts_buffer);
+    num_intervals +=
+        paint.getTextBlobIntercepts(blob_info.blob->ToSkTextBlob().get(),
+                                    bounds_array, offset_intercepts_buffer);
   }
   return num_intervals;
 }
diff --git a/third_party/WebKit/Source/platform/fonts/FontCache.h b/third_party/WebKit/Source/platform/fonts/FontCache.h
index c280fd8..cc64a18 100644
--- a/third_party/WebKit/Source/platform/fonts/FontCache.h
+++ b/third_party/WebKit/Source/platform/fonts/FontCache.h
@@ -277,9 +277,9 @@
       float font_size);
 
   // Implemented on skia platforms.
-  sk_sp<SkTypeface> CreateTypeface(const FontDescription&,
-                                   const FontFaceCreationParams&,
-                                   CString& name);
+  PaintTypeface CreateTypeface(const FontDescription&,
+                               const FontFaceCreationParams&,
+                               CString& name);
 
 #if defined(OS_ANDROID) || defined(OS_LINUX)
   static AtomicString GetFamilyNameForCharacter(SkFontMgr*,
diff --git a/third_party/WebKit/Source/platform/fonts/FontCustomPlatformData.cpp b/third_party/WebKit/Source/platform/fonts/FontCustomPlatformData.cpp
index 23fd39f..2be843c6 100644
--- a/third_party/WebKit/Source/platform/fonts/FontCustomPlatformData.cpp
+++ b/third_party/WebKit/Source/platform/fonts/FontCustomPlatformData.cpp
@@ -44,6 +44,7 @@
 #endif
 #include "platform/fonts/opentype/FontSettings.h"
 #include "platform/fonts/opentype/VariableFontCheck.h"
+#include "platform/graphics/paint/PaintTypeface.h"
 #include "third_party/skia/include/core/SkStream.h"
 #include "third_party/skia/include/core/SkTypeface.h"
 #if defined(OS_WIN) || defined(OS_MACOSX)
@@ -139,7 +140,9 @@
     ReportWebFontInstantiationResult(kSuccessConventionalWebFont);
   }
 
-  return FontPlatformData(return_typeface, "", size,
+  // TODO(vmpstr): Handle web fonts PaintTypefaces.
+  PaintTypeface paint_tf = PaintTypeface::FromSkTypeface(return_typeface);
+  return FontPlatformData(std::move(paint_tf), "", size,
                           bold && !base_typeface_->isBold(),
                           italic && !base_typeface_->isItalic(), orientation);
 }
diff --git a/third_party/WebKit/Source/platform/fonts/FontPlatformData.cpp b/third_party/WebKit/Source/platform/fonts/FontPlatformData.cpp
index 903b74b..7557f389 100644
--- a/third_party/WebKit/Source/platform/fonts/FontPlatformData.cpp
+++ b/third_party/WebKit/Source/platform/fonts/FontPlatformData.cpp
@@ -39,8 +39,7 @@
 namespace blink {
 
 FontPlatformData::FontPlatformData(WTF::HashTableDeletedValueType)
-    : typeface_(nullptr),
-      text_size_(0),
+    : text_size_(0),
       synthetic_bold_(false),
       synthetic_italic_(false),
       avoid_embedded_bitmaps_(false),
@@ -54,8 +53,7 @@
 }
 
 FontPlatformData::FontPlatformData()
-    : typeface_(nullptr),
-      text_size_(0),
+    : text_size_(0),
       synthetic_bold_(false),
       synthetic_italic_(false),
       avoid_embedded_bitmaps_(false),
@@ -72,8 +70,7 @@
                                    bool synthetic_bold,
                                    bool synthetic_italic,
                                    FontOrientation orientation)
-    : typeface_(nullptr),
-      text_size_(size),
+    : text_size_(size),
       synthetic_bold_(synthetic_bold),
       synthetic_italic_(synthetic_italic),
       avoid_embedded_bitmaps_(false),
@@ -87,7 +84,7 @@
 }
 
 FontPlatformData::FontPlatformData(const FontPlatformData& source)
-    : typeface_(source.typeface_),
+    : paint_typeface_(source.paint_typeface_),
 #if !defined(OS_WIN)
       family_(source.family_),
 #endif
@@ -109,7 +106,7 @@
 }
 
 FontPlatformData::FontPlatformData(const FontPlatformData& src, float text_size)
-    : typeface_(src.typeface_),
+    : paint_typeface_(src.paint_typeface_),
 #if !defined(OS_WIN)
       family_(src.family_),
 #endif
@@ -119,9 +116,10 @@
       avoid_embedded_bitmaps_(false),
       orientation_(src.orientation_),
 #if defined(OS_LINUX) || defined(OS_ANDROID)
-      style_(FontRenderStyle::QuerySystem(family_,
-                                          text_size_,
-                                          typeface_->fontStyle())),
+      style_(FontRenderStyle::QuerySystem(
+          family_,
+          text_size_,
+          paint_typeface_.ToSkTypeface()->fontStyle())),
 #endif
       harf_buzz_face_(nullptr),
       is_hash_table_deleted_value_(false)
@@ -135,13 +133,13 @@
 #endif
 }
 
-FontPlatformData::FontPlatformData(sk_sp<SkTypeface> tf,
+FontPlatformData::FontPlatformData(const PaintTypeface& paint_tf,
                                    const char* family,
                                    float text_size,
                                    bool synthetic_bold,
                                    bool synthetic_italic,
                                    FontOrientation orientation)
-    : typeface_(std::move(tf)),
+    : paint_typeface_(paint_tf),
 #if !defined(OS_WIN)
       family_(family),
 #endif
@@ -151,9 +149,10 @@
       avoid_embedded_bitmaps_(false),
       orientation_(orientation),
 #if defined(OS_LINUX) || defined(OS_ANDROID)
-      style_(FontRenderStyle::QuerySystem(family_,
-                                          text_size_,
-                                          typeface_->fontStyle())),
+      style_(FontRenderStyle::QuerySystem(
+          family_,
+          text_size_,
+          paint_typeface_.ToSkTypeface()->fontStyle())),
 #endif
       is_hash_table_deleted_value_(false)
 #if defined(OS_WIN)
@@ -170,7 +169,7 @@
 
 #if defined(OS_MACOSX)
 CTFontRef FontPlatformData::CtFont() const {
-  return SkTypeface_GetCTFontRef(typeface_.get());
+  return SkTypeface_GetCTFontRef(paint_typeface_.ToSkTypeface().get());
 };
 
 CGFontRef FontPlatformData::CgFont() const {
@@ -186,7 +185,7 @@
   if (this == &other)
     return *this;
 
-  typeface_ = other.typeface_;
+  paint_typeface_ = other.paint_typeface_;
 #if !defined(OS_WIN)
   family_ = other.family_;
 #endif
@@ -244,7 +243,7 @@
 }
 
 SkTypeface* FontPlatformData::Typeface() const {
-  return typeface_.get();
+  return paint_typeface_.ToSkTypeface().get();
 }
 
 HarfBuzzFace* FontPlatformData::GetHarfBuzzFace() const {
@@ -323,12 +322,12 @@
 
 #if !defined(OS_MACOSX)
 bool FontPlatformData::FontContainsCharacter(UChar32 character) {
-  SkPaint paint;
-  SetupPaint(&paint);
-  paint.setTextEncoding(SkPaint::kUTF32_TextEncoding);
+  PaintFont font;
+  SetupPaintFont(&font);
+  font.SetTextEncoding(SkPaint::kUTF32_TextEncoding);
 
   uint16_t glyph;
-  paint.textToGlyphs(&character, sizeof(character), &glyph);
+  font.ToSkPaint().textToGlyphs(&character, sizeof(character), &glyph);
   return glyph;
 }
 
@@ -342,12 +341,17 @@
 Vector<char> FontPlatformData::OpenTypeTable(SkFontTableTag tag) const {
   Vector<char> table_buffer;
 
-  const size_t table_size = typeface_->getTableSize(tag);
+  auto* typeface = paint_typeface_.ToSkTypeface().get();
+  const size_t table_size = typeface->getTableSize(tag);
   if (table_size) {
     table_buffer.resize(table_size);
-    typeface_->getTableData(tag, 0, table_size, &table_buffer[0]);
+    typeface->getTableData(tag, 0, table_size, &table_buffer[0]);
   }
   return table_buffer;
 }
 
+const PaintTypeface& FontPlatformData::GetPaintTypeface() const {
+  return paint_typeface_;
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/FontPlatformData.h b/third_party/WebKit/Source/platform/fonts/FontPlatformData.h
index 9b27b5f..b31fe702 100644
--- a/third_party/WebKit/Source/platform/fonts/FontPlatformData.h
+++ b/third_party/WebKit/Source/platform/fonts/FontPlatformData.h
@@ -39,6 +39,8 @@
 #include "platform/fonts/FontOrientation.h"
 #include "platform/fonts/SmallCapsIterator.h"
 #include "platform/fonts/opentype/OpenTypeVerticalData.h"
+#include "platform/graphics/paint/PaintFont.h"
+#include "platform/graphics/paint/PaintTypeface.h"
 #include "platform/wtf/Allocator.h"
 #include "platform/wtf/Forward.h"
 #include "platform/wtf/HashTableDeletedValueType.h"
@@ -102,7 +104,7 @@
                    FontOrientation,
                    FontVariationSettings*);
 #endif
-  FontPlatformData(sk_sp<SkTypeface>,
+  FontPlatformData(const PaintTypeface&,
                    const char* name,
                    float text_size,
                    bool synthetic_bold,
@@ -160,9 +162,10 @@
   // FontRenderStyle::NoPreference.
   const FontRenderStyle& GetFontRenderStyle() const { return style_; }
 #endif
-  void SetupPaint(SkPaint*,
-                  float device_scale_factor = 1,
-                  const Font* = 0) const;
+  void SetupPaintFont(PaintFont*,
+                      float device_scale_factor = 1,
+                      const Font* = 0) const;
+  const PaintTypeface& GetPaintTypeface() const;
 
 #if defined(OS_WIN)
   int PaintTextFlags() const { return paint_text_flags_; }
@@ -173,7 +176,7 @@
   void QuerySystemForRenderStyle();
 #endif
 
-  sk_sp<SkTypeface> typeface_;
+  PaintTypeface paint_typeface_;
 #if !defined(OS_WIN)
   CString family_;
 #endif
diff --git a/third_party/WebKit/Source/platform/fonts/SimpleFontData.cpp b/third_party/WebKit/Source/platform/fonts/SimpleFontData.cpp
index 3bac20378..b90dbee8 100644
--- a/third_party/WebKit/Source/platform/fonts/SimpleFontData.cpp
+++ b/third_party/WebKit/Source/platform/fonts/SimpleFontData.cpp
@@ -101,8 +101,10 @@
 
   SkPaint::FontMetrics metrics;
 
-  platform_data_.SetupPaint(&paint_);
-  paint_.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+  PaintFont font;
+  platform_data_.SetupPaintFont(&font);
+  font.SetTextEncoding(SkPaint::kGlyphID_TextEncoding);
+  paint_ = font.ToSkPaint();
   paint_.getFontMetrics(&metrics);
   SkTypeface* face = paint_.getTypeface();
   DCHECK(face);
diff --git a/third_party/WebKit/Source/platform/fonts/fuchsia/FontPlatformDataFuchsia.cpp b/third_party/WebKit/Source/platform/fonts/fuchsia/FontPlatformDataFuchsia.cpp
index 040e4c5..da55523 100644
--- a/third_party/WebKit/Source/platform/fonts/fuchsia/FontPlatformDataFuchsia.cpp
+++ b/third_party/WebKit/Source/platform/fonts/fuchsia/FontPlatformDataFuchsia.cpp
@@ -32,10 +32,10 @@
 
 namespace blink {
 
-void FontPlatformData::SetupPaint(SkPaint* paint,
-                                  float device_scale_factor,
-                                  const Font*) const {
-  paint->setTypeface(typeface_);
+void FontPlatformData::SetupPaintFont(PaintFont* font,
+                                      float device_scale_factor,
+                                      const Font*) const {
+  font->SetTypeface(paint_typeface_);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/linux/FontPlatformDataLinux.cpp b/third_party/WebKit/Source/platform/fonts/linux/FontPlatformDataLinux.cpp
index d3f075d..eb20cdc 100644
--- a/third_party/WebKit/Source/platform/fonts/linux/FontPlatformDataLinux.cpp
+++ b/third_party/WebKit/Source/platform/fonts/linux/FontPlatformDataLinux.cpp
@@ -35,18 +35,18 @@
 
 namespace blink {
 
-void FontPlatformData::SetupPaint(SkPaint* paint,
-                                  float device_scale_factor,
-                                  const Font*) const {
-  style_.ApplyToPaint(*paint, device_scale_factor);
+void FontPlatformData::SetupPaintFont(PaintFont* font,
+                                      float device_scale_factor,
+                                      const Font*) const {
+  style_.ApplyToPaintFont(*font, device_scale_factor);
 
   const float ts = text_size_ >= 0 ? text_size_ : 12;
-  paint->setTextSize(SkFloatToScalar(ts));
-  paint->setTypeface(typeface_);
-  paint->setFakeBoldText(synthetic_bold_);
-  paint->setTextSkewX(synthetic_italic_ ? -SK_Scalar1 / 4 : 0);
+  font->SetTextSize(SkFloatToScalar(ts));
+  font->SetTypeface(paint_typeface_);
+  font->SetFakeBoldText(synthetic_bold_);
+  font->SetTextSkewX(synthetic_italic_ ? -SK_Scalar1 / 4 : 0);
 
-  paint->setEmbeddedBitmapText(!avoid_embedded_bitmaps_);
+  font->SetEmbeddedBitmapText(!avoid_embedded_bitmaps_);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/linux/FontRenderStyle.cpp b/third_party/WebKit/Source/platform/fonts/linux/FontRenderStyle.cpp
index 658bc84..2457f90 100644
--- a/third_party/WebKit/Source/platform/fonts/linux/FontRenderStyle.cpp
+++ b/third_party/WebKit/Source/platform/fonts/linux/FontRenderStyle.cpp
@@ -99,24 +99,25 @@
   return result;
 }
 
-void FontRenderStyle::ApplyToPaint(SkPaint& paint,
-                                   float device_scale_factor) const {
-  paint.setAntiAlias(use_anti_alias);
-  paint.setHinting(static_cast<SkPaint::Hinting>(hint_style));
-  paint.setEmbeddedBitmapText(use_bitmaps);
-  paint.setAutohinted(use_auto_hint);
+void FontRenderStyle::ApplyToPaintFont(PaintFont& font,
+                                       float device_scale_factor) const {
+  auto sk_hint_style = static_cast<SkPaint::Hinting>(hint_style);
+  font.SetAntiAlias(use_anti_alias);
+  font.SetHinting(sk_hint_style);
+  font.SetEmbeddedBitmapText(use_bitmaps);
+  font.SetAutohinted(use_auto_hint);
   if (use_anti_alias)
-    paint.setLCDRenderText(use_subpixel_rendering);
+    font.SetLcdRenderText(use_subpixel_rendering);
 
   // Do not enable subpixel text on low-dpi if full hinting is requested.
-  bool use_subpixel_text = (paint.getHinting() != SkPaint::kFull_Hinting ||
-                            device_scale_factor > 1.0f);
+  bool use_subpixel_text =
+      (sk_hint_style != SkPaint::kFull_Hinting || device_scale_factor > 1.0f);
 
   // TestRunner specifically toggles the subpixel positioning flag.
   if (use_subpixel_text && !LayoutTestSupport::IsRunningLayoutTest())
-    paint.setSubpixelText(true);
+    font.SetSubpixelText(true);
   else
-    paint.setSubpixelText(use_subpixel_positioning);
+    font.SetSubpixelText(use_subpixel_positioning);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/linux/FontRenderStyle.h b/third_party/WebKit/Source/platform/fonts/linux/FontRenderStyle.h
index 6594f6fb..7e3ceaa 100644
--- a/third_party/WebKit/Source/platform/fonts/linux/FontRenderStyle.h
+++ b/third_party/WebKit/Source/platform/fonts/linux/FontRenderStyle.h
@@ -33,6 +33,7 @@
 #include "SkFontStyle.h"
 #include "SkPaint.h"
 #include "platform/PlatformExport.h"
+#include "platform/graphics/paint/PaintFont.h"
 #include "platform/wtf/Allocator.h"
 #include "platform/wtf/text/CString.h"
 
@@ -72,7 +73,7 @@
   static FontRenderStyle QuerySystem(const CString& family,
                                      float text_size,
                                      SkFontStyle);
-  void ApplyToPaint(SkPaint&, float device_scale_factor) const;
+  void ApplyToPaintFont(PaintFont&, float device_scale_factor) const;
 
   // Each of the use* members below can take one of three values:
   //   0: off
diff --git a/third_party/WebKit/Source/platform/fonts/mac/FontPlatformDataMac.mm b/third_party/WebKit/Source/platform/fonts/mac/FontPlatformDataMac.mm
index 36129f3..a379b1e0 100644
--- a/third_party/WebKit/Source/platform/fonts/mac/FontPlatformDataMac.mm
+++ b/third_party/WebKit/Source/platform/fonts/mac/FontPlatformDataMac.mm
@@ -111,9 +111,9 @@
   return return_font;
 }
 
-void FontPlatformData::SetupPaint(SkPaint* paint,
-                                  float,
-                                  const Font* font) const {
+void FontPlatformData::SetupPaintFont(PaintFont* paint_font,
+                                      float,
+                                      const Font* font) const {
   bool should_smooth_fonts = true;
   bool should_antialias = true;
 
@@ -141,15 +141,15 @@
                        LayoutTestSupport::IsFontAntialiasingEnabledForTest();
   }
 
-  paint->setAntiAlias(should_antialias);
-  paint->setEmbeddedBitmapText(false);
+  paint_font->SetAntiAlias(should_antialias);
+  paint_font->SetEmbeddedBitmapText(false);
   const float ts = text_size_ >= 0 ? text_size_ : 12;
-  paint->setTextSize(SkFloatToScalar(ts));
-  paint->setTypeface(typeface_);
-  paint->setFakeBoldText(synthetic_bold_);
-  paint->setTextSkewX(synthetic_italic_ ? -SK_Scalar1 / 4 : 0);
-  paint->setLCDRenderText(should_smooth_fonts);
-  paint->setSubpixelText(true);
+  paint_font->SetTextSize(SkFloatToScalar(ts));
+  paint_font->SetTypeface(paint_typeface_);
+  paint_font->SetFakeBoldText(synthetic_bold_);
+  paint_font->SetTextSkewX(synthetic_italic_ ? -SK_Scalar1 / 4 : 0);
+  paint_font->SetLcdRenderText(should_smooth_fonts);
+  paint_font->SetSubpixelText(true);
 
   // When rendering using CoreGraphics, disable hinting when
   // webkit-font-smoothing:antialiased or text-rendering:geometricPrecision is
@@ -157,7 +157,7 @@
   if (font &&
       (font->GetFontDescription().FontSmoothing() == kAntialiased ||
        font->GetFontDescription().TextRendering() == kGeometricPrecision))
-    paint->setHinting(SkPaint::kNo_Hinting);
+    paint_font->SetHinting(SkPaint::kNo_Hinting);
 }
 
 FontPlatformData::FontPlatformData(NSFont* ns_font,
@@ -172,13 +172,14 @@
       orientation_(orientation),
       is_hash_table_deleted_value_(false) {
   DCHECK(ns_font);
+  sk_sp<SkTypeface> typeface;
   if (CanLoadInProcess(ns_font)) {
-    typeface_.reset(SkCreateTypefaceFromCTFont(toCTFontRef(ns_font)));
+    typeface.reset(SkCreateTypefaceFromCTFont(toCTFontRef(ns_font)));
   } else {
     // In process loading fails for cases where third party font manager
     // software registers fonts in non system locations such as /Library/Fonts
     // and ~/Library Fonts, see crbug.com/72727 or crbug.com/108645.
-    typeface_ = LoadFromBrowserProcess(ns_font, size);
+    typeface = LoadFromBrowserProcess(ns_font, size);
   }
 
   if (variation_settings && variation_settings->size() < UINT16_MAX) {
@@ -191,10 +192,12 @@
     sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
     // TODO crbug.com/670246: Refactor this to a future Skia API that acccepts
     // axis parameters on system fonts directly.
-    typeface_ = fm->makeFromStream(
-        typeface_->openStream(nullptr)->duplicate(),
+    typeface = fm->makeFromStream(
+        typeface->openStream(nullptr)->duplicate(),
         SkFontArguments().setAxes(axes, variation_settings->size()));
   }
+  // TODO(vmpstr): Save the creation parameters in PaintTypeface instead.
+  paint_typeface_ = PaintTypeface::FromSkTypeface(typeface);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzFace.cpp b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzFace.cpp
index 916a309..d45e704 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzFace.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzFace.cpp
@@ -334,8 +334,10 @@
 
 hb_font_t* HarfBuzzFace::GetScaledFont(
     scoped_refptr<UnicodeRangeSet> range_set) const {
-  platform_data_->SetupPaint(&harf_buzz_font_data_->paint_);
-  harf_buzz_font_data_->paint_.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+  PaintFont paint_font;
+  platform_data_->SetupPaintFont(&paint_font);
+  paint_font.SetTextEncoding(SkPaint::kGlyphID_TextEncoding);
+  harf_buzz_font_data_->paint_ = paint_font.ToSkPaint();
   harf_buzz_font_data_->range_set_ = std::move(range_set);
   harf_buzz_font_data_->UpdateSimpleFontData(platform_data_);
 
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBloberizer.cpp b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBloberizer.cpp
index 542de7b0..f0094b1 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBloberizer.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBloberizer.cpp
@@ -40,15 +40,15 @@
     builder_rotation_ = pending_rotation;
   }
 
-  SkPaint run_paint;
-  run_paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
-  pending_font_data_->PlatformData().SetupPaint(&run_paint,
-                                                device_scale_factor_, &font_);
+  PaintFont run_font;
+  run_font.SetTextEncoding(SkPaint::kGlyphID_TextEncoding);
+  pending_font_data_->PlatformData().SetupPaintFont(
+      &run_font, device_scale_factor_, &font_);
 
   const auto run_size = pending_glyphs_.size();
   const auto& buffer = HasPendingVerticalOffsets()
-                           ? builder_.allocRunPos(run_paint, run_size)
-                           : builder_.allocRunPosH(run_paint, run_size, 0);
+                           ? builder_.AllocRunPos(run_font, run_size)
+                           : builder_.AllocRunPosH(run_font, run_size, 0);
 
   std::copy(pending_glyphs_.begin(), pending_glyphs_.end(), buffer.glyphs);
   std::copy(pending_offsets_.begin(), pending_offsets_.end(), buffer.pos);
@@ -62,7 +62,7 @@
   if (!builder_run_count_)
     return;
 
-  blobs_.emplace_back(builder_.make(), builder_rotation_);
+  blobs_.emplace_back(builder_.TakeTextBlob(), builder_rotation_);
   builder_run_count_ = 0;
 }
 
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBloberizer.h b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBloberizer.h
index 7834867..70a5d2a0 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBloberizer.h
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBloberizer.h
@@ -10,6 +10,8 @@
 #include "platform/fonts/SimpleFontData.h"
 #include "platform/fonts/shaping/ShapeResultBuffer.h"
 #include "platform/geometry/FloatPoint.h"
+#include "platform/graphics/paint/PaintTextBlob.h"
+#include "platform/graphics/paint/PaintTypeface.h"
 #include "platform/wtf/Allocator.h"
 #include "platform/wtf/Vector.h"
 #include "third_party/skia/include/core/SkTextBlob.h"
@@ -85,9 +87,9 @@
 
   enum class BlobRotation { kNoRotation, kCCWRotation };
   struct BlobInfo {
-    BlobInfo(sk_sp<SkTextBlob> b, BlobRotation r)
+    BlobInfo(scoped_refptr<PaintTextBlob> b, BlobRotation r)
         : blob(std::move(b)), rotation(r) {}
-    sk_sp<SkTextBlob> blob;
+    scoped_refptr<PaintTextBlob> blob;
     BlobRotation rotation;
   };
 
@@ -138,7 +140,7 @@
   const Type type_;
 
   // Current text blob state.
-  SkTextBlobBuilder builder_;
+  PaintTextBlobBuilder builder_;
   BlobRotation builder_rotation_ = BlobRotation::kNoRotation;
   size_t builder_run_count_ = 0;
 
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBloberizerTest.cpp b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBloberizerTest.cpp
index a67331d9..2df94f9 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBloberizerTest.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBloberizerTest.cpp
@@ -11,6 +11,7 @@
 #include "platform/fonts/opentype/OpenTypeVerticalData.h"
 #include "platform/fonts/shaping/CachingWordShaper.h"
 #include "platform/fonts/shaping/ShapeResultTestInfo.h"
+#include "platform/graphics/paint/PaintTypeface.h"
 #include "platform/wtf/Optional.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -24,7 +25,8 @@
  public:
   static scoped_refptr<TestSimpleFontData> Create(bool force_rotation = false) {
     FontPlatformData platform_data(
-        SkTypeface::MakeDefault(), nullptr, 10, false, false,
+        PaintTypeface::FromSkTypeface(SkTypeface::MakeDefault()), nullptr, 10,
+        false, false,
         force_rotation ? FontOrientation::kVerticalUpright
                        : FontOrientation::kHorizontal);
     scoped_refptr<OpenTypeVerticalData> vertical_data(
diff --git a/third_party/WebKit/Source/platform/fonts/skia/FontCacheSkia.cpp b/third_party/WebKit/Source/platform/fonts/skia/FontCacheSkia.cpp
index 85cad02..1e0fffa 100644
--- a/third_party/WebKit/Source/platform/fonts/skia/FontCacheSkia.cpp
+++ b/third_party/WebKit/Source/platform/fonts/skia/FontCacheSkia.cpp
@@ -54,20 +54,6 @@
 #include "public/platform/Platform.h"
 #include "public/platform/linux/WebSandboxSupport.h"
 
-#if !defined(OS_WIN) && !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
-#include "SkFontConfigInterface.h"
-
-static sk_sp<SkTypeface> typefaceForFontconfigInterfaceIdAndTtcIndex(
-    int fontconfigInterfaceId,
-    int ttcIndex) {
-  sk_sp<SkFontConfigInterface> fci(SkFontConfigInterface::RefGlobal());
-  SkFontConfigInterface::FontIdentity fontIdentity;
-  fontIdentity.fID = fontconfigInterfaceId;
-  fontIdentity.fTTCIndex = ttcIndex;
-  return fci->makeTypeface(fontIdentity);
-}
-#endif
-
 namespace blink {
 
 AtomicString ToAtomicString(const SkString& str) {
@@ -225,7 +211,7 @@
   return FontDataFromFontPlatformData(font_platform_data, should_retain);
 }
 
-sk_sp<SkTypeface> FontCache::CreateTypeface(
+PaintTypeface FontCache::CreateTypeface(
     const FontDescription& font_description,
     const FontFaceCreationParams& creation_params,
     CString& name) {
@@ -233,11 +219,12 @@
   // TODO(fuchsia): Revisit this and other font code for Fuchsia.
 
   if (creation_params.CreationType() == kCreateFontByFciIdAndTtcIndex) {
-    if (Platform::Current()->GetSandboxSupport())
-      return typefaceForFontconfigInterfaceIdAndTtcIndex(
+    if (Platform::Current()->GetSandboxSupport()) {
+      return PaintTypeface::FromFontConfigInterfaceIdAndTtcIndex(
           creation_params.FontconfigInterfaceId(), creation_params.TtcIndex());
-    return SkTypeface::MakeFromFile(creation_params.Filename().data(),
-                                    creation_params.TtcIndex());
+    }
+    return PaintTypeface::FromFilenameAndTtcIndex(
+        creation_params.Filename().data(), creation_params.TtcIndex());
   }
 #endif
 
@@ -253,11 +240,12 @@
   }
 
 #if defined(OS_WIN)
+  // TODO(vmpstr): Deal with paint typeface here.
   if (sideloaded_fonts_) {
     HashMap<String, sk_sp<SkTypeface>>::iterator sideloaded_font =
         sideloaded_fonts_->find(name.data());
     if (sideloaded_font != sideloaded_fonts_->end())
-      return sideloaded_font->value;
+      return PaintTypeface::FromSkTypeface(sideloaded_font->value);
   }
 #endif
 
@@ -266,15 +254,20 @@
   // the embedder provided font Manager rather than calling
   // SkTypeface::CreateFromName which may redirect the call to the default font
   // Manager.  On Windows the font manager is always present.
-  if (font_manager_)
-    return sk_sp<SkTypeface>(font_manager_->matchFamilyStyle(
+  if (font_manager_) {
+    // TODO(vmpstr): Handle creating paint typefaces here directly. We need to
+    // figure out whether it's safe to give |font_manager_| to PaintTypeface and
+    // what that means on the GPU side.
+    auto tf = sk_sp<SkTypeface>(font_manager_->matchFamilyStyle(
         name.data(), font_description.SkiaFontStyle()));
+    return PaintTypeface::FromSkTypeface(std::move(tf));
+  }
 #endif
 
   // FIXME: Use m_fontManager, matchFamilyStyle instead of
   // legacyCreateTypeface on all platforms.
-  sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
-  return fm->legacyMakeTypeface(name.data(), font_description.SkiaFontStyle());
+  return PaintTypeface::FromFamilyNameAndFontStyle(
+      name.data(), font_description.SkiaFontStyle());
 }
 
 #if !defined(OS_WIN)
@@ -284,14 +277,15 @@
     float font_size,
     AlternateFontName) {
   CString name;
-  sk_sp<SkTypeface> tf =
+  PaintTypeface paint_tf =
       CreateTypeface(font_description, creation_params, name);
-  if (!tf)
+  if (!paint_tf)
     return nullptr;
 
+  const auto& tf = paint_tf.ToSkTypeface();
   std::unique_ptr<FontPlatformData> font_platform_data =
       WTF::WrapUnique(new FontPlatformData(
-          tf, name.data(), font_size,
+          paint_tf, name.data(), font_size,
           (font_description.Weight() >
                FontSelectionValue(200) +
                    FontSelectionValue(tf->fontStyle().weight()) ||
diff --git a/third_party/WebKit/Source/platform/fonts/win/FontCacheSkiaWin.cpp b/third_party/WebKit/Source/platform/fonts/win/FontCacheSkiaWin.cpp
index e8cb30e..c44f529 100644
--- a/third_party/WebKit/Source/platform/fonts/win/FontCacheSkiaWin.cpp
+++ b/third_party/WebKit/Source/platform/fonts/win/FontCacheSkiaWin.cpp
@@ -339,12 +339,13 @@
   DCHECK_EQ(creation_params.CreationType(), kCreateFontByFamily);
 
   CString name;
-  sk_sp<SkTypeface> tf =
+  PaintTypeface paint_tf =
       CreateTypeface(font_description, creation_params, name);
   // Windows will always give us a valid pointer here, even if the face name
   // is non-existent. We have to double-check and see if the family name was
   // really used.
-  if (!tf || !TypefacesMatchesFamily(tf.get(), creation_params.Family())) {
+  if (!paint_tf || !TypefacesMatchesFamily(paint_tf.ToSkTypeface().get(),
+                                           creation_params.Family())) {
     AtomicString adjusted_name;
     FontSelectionValue variant_weight;
     FontSelectionValue variant_stretch;
@@ -364,34 +365,40 @@
     }
 
     if (alternate_font_name == AlternateFontName::kLastResort) {
-      if (!tf)
+      if (!paint_tf)
         return nullptr;
     } else if (TypefacesHasWeightSuffix(creation_params.Family(), adjusted_name,
                                         variant_weight)) {
       FontFaceCreationParams adjusted_params(adjusted_name);
       FontDescription adjusted_font_description = font_description;
       adjusted_font_description.SetWeight(variant_weight);
-      tf = CreateTypeface(adjusted_font_description, adjusted_params, name);
-      if (!tf || !TypefacesMatchesFamily(tf.get(), adjusted_name))
+      paint_tf =
+          CreateTypeface(adjusted_font_description, adjusted_params, name);
+      if (!paint_tf || !TypefacesMatchesFamily(paint_tf.ToSkTypeface().get(),
+                                               adjusted_name)) {
         return nullptr;
+      }
 
     } else if (TypefacesHasStretchSuffix(creation_params.Family(),
                                          adjusted_name, variant_stretch)) {
       FontFaceCreationParams adjusted_params(adjusted_name);
       FontDescription adjusted_font_description = font_description;
       adjusted_font_description.SetStretch(variant_stretch);
-      tf = CreateTypeface(adjusted_font_description, adjusted_params, name);
-      if (!tf || !TypefacesMatchesFamily(tf.get(), adjusted_name))
+      paint_tf =
+          CreateTypeface(adjusted_font_description, adjusted_params, name);
+      if (!paint_tf || !TypefacesMatchesFamily(paint_tf.ToSkTypeface().get(),
+                                               adjusted_name)) {
         return nullptr;
-
+      }
     } else {
       return nullptr;
     }
   }
 
+  const auto& tf = paint_tf.ToSkTypeface();
   std::unique_ptr<FontPlatformData> result =
       WTF::WrapUnique(new FontPlatformData(
-          tf, name.data(), font_size,
+          paint_tf, name.data(), font_size,
           (font_description.Weight() >= BoldThreshold() && !tf->isBold()) ||
               font_description.IsSyntheticBold(),
           ((font_description.Style() == ItalicSlopeValue()) &&
diff --git a/third_party/WebKit/Source/platform/fonts/win/FontPlatformDataWin.cpp b/third_party/WebKit/Source/platform/fonts/win/FontPlatformDataWin.cpp
index ba898990..f4d9c72e 100644
--- a/third_party/WebKit/Source/platform/fonts/win/FontPlatformDataWin.cpp
+++ b/third_party/WebKit/Source/platform/fonts/win/FontPlatformDataWin.cpp
@@ -44,15 +44,17 @@
 // if available.
 const float kMaxSizeForEmbeddedBitmap = 24.0f;
 
-void FontPlatformData::SetupPaint(SkPaint* paint, float, const Font*) const {
+void FontPlatformData::SetupPaintFont(PaintFont* font,
+                                      float,
+                                      const Font*) const {
   const float ts = text_size_ >= 0 ? text_size_ : 12;
-  paint->setTextSize(SkFloatToScalar(text_size_));
-  paint->setTypeface(typeface_);
-  paint->setFakeBoldText(synthetic_bold_);
-  paint->setTextSkewX(synthetic_italic_ ? -SK_Scalar1 / 4 : 0);
+  font->SetTextSize(SkFloatToScalar(text_size_));
+  font->SetTypeface(paint_typeface_);
+  font->SetFakeBoldText(synthetic_bold_);
+  font->SetTextSkewX(synthetic_italic_ ? -SK_Scalar1 / 4 : 0);
 
   uint32_t text_flags = PaintTextFlags();
-  uint32_t flags = paint->getFlags();
+  uint32_t flags = font->flags();
   static const uint32_t kTextFlagsMask =
       SkPaint::kAntiAlias_Flag | SkPaint::kLCDRenderText_Flag |
       SkPaint::kEmbeddedBitmapText_Flag | SkPaint::kSubpixelText_Flag;
@@ -73,9 +75,9 @@
   SkASSERT(!(text_flags & ~kTextFlagsMask));
   flags |= text_flags;
 
-  paint->setFlags(flags);
+  font->SetFlags(flags);
 
-  paint->setEmbeddedBitmapText(!avoid_embedded_bitmaps_);
+  font->SetEmbeddedBitmapText(!avoid_embedded_bitmaps_);
 }
 
 static bool IsWebFont(const String& family_name) {
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintFont.h b/third_party/WebKit/Source/platform/graphics/paint/PaintFont.h
new file mode 100644
index 0000000..a84d2ab0
--- /dev/null
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintFont.h
@@ -0,0 +1,14 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PaintFont_h
+#define PaintFont_h
+
+#include "cc/paint/paint_font.h"
+
+namespace blink {
+using cc::PaintFont;
+}
+
+#endif  // PaintFont_h
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintTextBlob.h b/third_party/WebKit/Source/platform/graphics/paint/PaintTextBlob.h
new file mode 100644
index 0000000..2c2aeec
--- /dev/null
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintTextBlob.h
@@ -0,0 +1,16 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PaintTextBlob_h
+#define PaintTextBlob_h
+
+#include "cc/paint/paint_text_blob.h"
+#include "cc/paint/paint_text_blob_builder.h"
+
+namespace blink {
+using cc::PaintTextBlob;
+using cc::PaintTextBlobBuilder;
+}  // namespace blink
+
+#endif  // PaintTextBlob_h
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintTypeface.h b/third_party/WebKit/Source/platform/graphics/paint/PaintTypeface.h
new file mode 100644
index 0000000..23bff0b
--- /dev/null
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintTypeface.h
@@ -0,0 +1,14 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PaintTypeface_h
+#define PaintTypeface_h
+
+#include "cc/paint/paint_typeface.h"
+
+namespace blink {
+using cc::PaintTypeface;
+}
+
+#endif  // PaintTypeface_h
diff --git a/third_party/WebKit/Source/platform/graphics/test/MockPaintCanvas.h b/third_party/WebKit/Source/platform/graphics/test/MockPaintCanvas.h
index 7385388..d3ab977 100644
--- a/third_party/WebKit/Source/platform/graphics/test/MockPaintCanvas.h
+++ b/third_party/WebKit/Source/platform/graphics/test/MockPaintCanvas.h
@@ -6,6 +6,7 @@
 #define MockPaintCanvas_h
 
 #include "platform/graphics/paint/PaintCanvas.h"
+#include "platform/graphics/paint/PaintTextBlob.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/skia/include/core/SkMetaData.h"
 
@@ -78,19 +79,8 @@
                     SkScalar left,
                     SkScalar top,
                     const PaintFlags* flags));
-  MOCK_METHOD5(drawText,
-               void(const void* text,
-                    size_t byte_length,
-                    SkScalar x,
-                    SkScalar y,
-                    const PaintFlags& flags));
-  MOCK_METHOD4(drawPosText,
-               void(const void* text,
-                    size_t byte_length,
-                    const SkPoint pos[],
-                    const PaintFlags& flags));
   MOCK_METHOD4(drawTextBlob,
-               void(sk_sp<SkTextBlob> blob,
+               void(scoped_refptr<PaintTextBlob>,
                     SkScalar x,
                     SkScalar y,
                     const PaintFlags& flags));
diff --git a/third_party/WebKit/Source/platform/runtime_enabled_features.json5 b/third_party/WebKit/Source/platform/runtime_enabled_features.json5
index f83c41e2..5faf096d3 100644
--- a/third_party/WebKit/Source/platform/runtime_enabled_features.json5
+++ b/third_party/WebKit/Source/platform/runtime_enabled_features.json5
@@ -440,7 +440,7 @@
     },
     {
       name: "FractionalMouseTypePointerEvent",
-      status: "experimental",
+      status: "stable",
     },
     {
       name: "FractionalScrollOffsets",
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index cf8dd9eb..701d8bd 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -9839,6 +9839,15 @@
   </summary>
 </histogram>
 
+<histogram name="Compositing.Browser.CachedImagesCount" units="count">
+  <owner>vmpstr@chromium.org</owner>
+  <summary>
+    The maximum number of images that were cached in the browser over the
+    lifetime of the image decode cache. This is recorded at the image cache
+    destruction. It is further split up by Software and Gpu rasterization.
+  </summary>
+</histogram>
+
 <histogram
     name="Compositing.Browser.DisplayListRecordingSource.UpdateInvalidatedAreaPerMs"
     units="pixels/ms">
@@ -10164,6 +10173,15 @@
   </summary>
 </histogram>
 
+<histogram name="Compositing.Renderer.CachedImagesCount" units="count">
+  <owner>vmpstr@chromium.org</owner>
+  <summary>
+    The maximum number of images that were cached in the renderer over the
+    lifetime of the image decode cache. This is recorded at the image cache
+    destruction. It is further split up by Software and Gpu rasterization.
+  </summary>
+</histogram>
+
 <histogram name="Compositing.Renderer.CALayerResult" enum="CALayerResult">
   <owner>ccameron@chromium.org</owner>
   <summary>
@@ -105392,9 +105410,11 @@
   <suffix name="" label="This metric includes both gpu and software raster."/>
   <suffix name="Gpu" label="This metric is for only gpu raster."/>
   <suffix name="Software" label="This metric is for only software raster."/>
+  <affected-histogram name="Compositing.Browser.CachedImagesCount"/>
   <affected-histogram name="Compositing.Browser.RasterTask.RasterPixelsPerMs"/>
   <affected-histogram name="Compositing.Browser.RasterTask.RasterPixelsPerMs2"/>
   <affected-histogram name="Compositing.Browser.RasterTask.RasterUs"/>
+  <affected-histogram name="Compositing.Renderer.CachedImagesCount"/>
   <affected-histogram name="Compositing.Renderer.RasterTask.RasterPixelsPerMs"/>
   <affected-histogram
       name="Compositing.Renderer.RasterTask.RasterPixelsPerMs2"/>
diff --git a/ui/app_list/search_controller.cc b/ui/app_list/search_controller.cc
index b1cc525..8cb77e92 100644
--- a/ui/app_list/search_controller.cc
+++ b/ui/app_list/search_controller.cc
@@ -52,14 +52,15 @@
   if (!result)
     return;
 
-  // Count AppList.Search here because it is composed of search + action.
-  base::RecordAction(base::UserMetricsAction("AppList_Search"));
-
   UMA_HISTOGRAM_ENUMERATION(kSearchResultOpenDisplayTypeHistogram,
                             result->display_type(),
                             SearchResult::DISPLAY_TYPE_LAST);
 
+  // Record the search metric if the SearchResult is not a suggested app.
   if (result->display_type() != SearchResult::DISPLAY_RECOMMENDATION) {
+    // Count AppList.Search here because it is composed of search + action.
+    base::RecordAction(base::UserMetricsAction("AppList_Search"));
+
     UMA_HISTOGRAM_COUNTS_100(kSearchQueryLength, search_box_->text().size());
 
     if (result->distance_from_origin() >= 0) {
diff --git a/ui/app_list/views/apps_grid_view_unittest.cc b/ui/app_list/views/apps_grid_view_unittest.cc
index 013b8fd..8129136 100644
--- a/ui/app_list/views/apps_grid_view_unittest.cc
+++ b/ui/app_list/views/apps_grid_view_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/histogram_tester.h"
 #include "base/test/icu_test_util.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
@@ -37,6 +38,7 @@
 #include "ui/app_list/views/contents_view.h"
 #include "ui/app_list/views/expand_arrow_view.h"
 #include "ui/app_list/views/search_box_view.h"
+#include "ui/app_list/views/search_result_tile_item_view.h"
 #include "ui/app_list/views/suggestions_container_view.h"
 #include "ui/app_list/views/test/apps_grid_view_test_api.h"
 #include "ui/aura/window.h"
@@ -844,6 +846,31 @@
   EXPECT_TRUE(CheckNoSelection());
 }
 
+// Tests that UMA is properly collected when either a suggested or normal app is
+// launched.
+TEST_F(AppsGridViewTest, UMATestForLaunchingApps) {
+  base::HistogramTester histogram_tester;
+  model_->PopulateApps(5);
+
+  // Select the first suggested app and launch it.
+  contents_view_->app_list_main_view()->ActivateApp(GetItemViewAt(0)->item(),
+                                                    0);
+
+  // Test that histograms recorded that a regular app launched.
+  histogram_tester.ExpectBucketCount("Apps.AppListAppLaunchedFullscreen", 0, 1);
+  // Test that histograms did not record that a suggested launched.
+  histogram_tester.ExpectBucketCount("Apps.AppListAppLaunchedFullscreen", 1, 0);
+
+  // Launch a suggested app.
+  suggestions_container_->child_at(0)->OnKeyPressed(
+      ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_RETURN, ui::EF_NONE));
+
+  // Test that histograms recorded that a suggested app launched, and that the
+  // count for regular apps launched is unchanged.
+  histogram_tester.ExpectBucketCount("Apps.AppListAppLaunchedFullscreen", 0, 1);
+  histogram_tester.ExpectBucketCount("Apps.AppListAppLaunchedFullscreen", 1, 1);
+}
+
 // Tests that moving selection backwards (left in ltr, right in rtl) from the
 // first app selects nothing, and that selection returns to the suggested apps
 // when selection moves forwards (right in ltr, left in rtl).
diff --git a/ui/app_list/views/search_result_tile_item_view.cc b/ui/app_list/views/search_result_tile_item_view.cc
index e1f2c10..792884e 100644
--- a/ui/app_list/views/search_result_tile_item_view.cc
+++ b/ui/app_list/views/search_result_tile_item_view.cc
@@ -216,13 +216,17 @@
 
 void SearchResultTileItemView::ButtonPressed(views::Button* sender,
                                              const ui::Event& event) {
-  LogAppLaunch();
+  if (is_suggested_app_)
+    LogAppLaunch();
+
   view_delegate_->OpenSearchResult(item_, false, event.flags());
 }
 
 bool SearchResultTileItemView::OnKeyPressed(const ui::KeyEvent& event) {
   if (event.key_code() == ui::VKEY_RETURN) {
-    LogAppLaunch();
+    if (is_suggested_app_)
+      LogAppLaunch();
+
     view_delegate_->OpenSearchResult(item_, false, event.flags());
     return true;
   }
diff --git a/ui/base/clipboard/clipboard_test_template.h b/ui/base/clipboard/clipboard_test_template.h
index 486b1cba..7827e7d 100644
--- a/ui/base/clipboard/clipboard_test_template.h
+++ b/ui/base/clipboard/clipboard_test_template.h
@@ -354,7 +354,7 @@
 
   {
     ScopedClipboardWriter clipboard_writer(CLIPBOARD_TYPE_COPY_PASTE);
-    clipboard_writer.WriteURL(url);
+    clipboard_writer.WriteText(url);
   }
 
   EXPECT_THAT(this->GetAvailableTypes(CLIPBOARD_TYPE_COPY_PASTE),
@@ -604,7 +604,6 @@
   {
     ScopedClipboardWriter writer(CLIPBOARD_TYPE_COPY_PASTE);
     writer.WriteText(UTF8ToUTF16("foo"));
-    writer.WriteURL(UTF8ToUTF16("foo"));
     writer.WriteHTML(UTF8ToUTF16("foo"), "bar");
     writer.WriteBookmark(UTF8ToUTF16("foo"), "bar");
     writer.WriteHyperlink(ASCIIToUTF16("foo"), "bar");
@@ -650,11 +649,6 @@
   scw.WriteText(base::string16());
 }
 
-TYPED_TEST(ClipboardTest, WriteURLEmptyParams) {
-  ScopedClipboardWriter scw(CLIPBOARD_TYPE_COPY_PASTE);
-  scw.WriteURL(base::string16());
-}
-
 TYPED_TEST(ClipboardTest, WriteHTMLEmptyParams) {
   ScopedClipboardWriter scw(CLIPBOARD_TYPE_COPY_PASTE);
   scw.WriteHTML(base::string16(), std::string());
diff --git a/ui/base/clipboard/scoped_clipboard_writer.cc b/ui/base/clipboard/scoped_clipboard_writer.cc
index 6850cd46..63b5d47 100644
--- a/ui/base/clipboard/scoped_clipboard_writer.cc
+++ b/ui/base/clipboard/scoped_clipboard_writer.cc
@@ -24,11 +24,12 @@
 }
 
 void ScopedClipboardWriter::WriteText(const base::string16& text) {
-  WriteTextOrURL(text, false);
-}
+  std::string utf8_text = base::UTF16ToUTF8(text);
 
-void ScopedClipboardWriter::WriteURL(const base::string16& text) {
-  WriteTextOrURL(text, true);
+  Clipboard::ObjectMapParams parameters;
+  parameters.push_back(
+      Clipboard::ObjectMapParam(utf8_text.begin(), utf8_text.end()));
+  objects_[Clipboard::CBF_TEXT] = parameters;
 }
 
 void ScopedClipboardWriter::WriteHTML(const base::string16& markup,
@@ -121,25 +122,8 @@
 }
 
 void ScopedClipboardWriter::Reset() {
-  url_text_.clear();
   objects_.clear();
   bitmap_.reset();
 }
 
-void ScopedClipboardWriter::WriteTextOrURL(const base::string16& text,
-                                           bool is_url) {
-  std::string utf8_text = base::UTF16ToUTF8(text);
-
-  Clipboard::ObjectMapParams parameters;
-  parameters.push_back(Clipboard::ObjectMapParam(utf8_text.begin(),
-                                                 utf8_text.end()));
-  objects_[Clipboard::CBF_TEXT] = parameters;
-
-  if (is_url) {
-    url_text_ = utf8_text;
-  } else {
-    url_text_.clear();
-  }
-}
-
 }  // namespace ui
diff --git a/ui/base/clipboard/scoped_clipboard_writer.h b/ui/base/clipboard/scoped_clipboard_writer.h
index a7e06456..bb889c9 100644
--- a/ui/base/clipboard/scoped_clipboard_writer.h
+++ b/ui/base/clipboard/scoped_clipboard_writer.h
@@ -38,10 +38,6 @@
   // Converts |text| to UTF-8 and adds it to the clipboard.
   void WriteText(const base::string16& text);
 
-  // Converts the text of the URL to UTF-8 and adds it to the clipboard, then
-  // notifies the Clipboard that we just wrote a URL.
-  void WriteURL(const base::string16& text);
-
   // Adds HTML to the clipboard.  The url parameter is optional, but especially
   // useful if the HTML fragment contains relative links.
   void WriteHTML(const base::string16& markup, const std::string& source_url);
@@ -71,10 +67,6 @@
   void Reset();
 
  private:
-  // Converts |text| to UTF-8 and adds it to the clipboard.  If it's a URL, we
-  // also notify the clipboard of that fact.
-  void WriteTextOrURL(const base::string16& text, bool is_url);
-
   // We accumulate the data passed to the various targets in the |objects_|
   // vector, and pass it to Clipboard::WriteObjects() during object destruction.
   Clipboard::ObjectMap objects_;
@@ -82,10 +74,6 @@
 
   SkBitmap bitmap_;
 
-  // We keep around the UTF-8 text of the URL in order to pass it to
-  // Clipboard::DidWriteURL().
-  std::string url_text_;
-
   DISALLOW_COPY_AND_ASSIGN(ScopedClipboardWriter);
 };
 
diff --git a/ui/gfx/render_text.cc b/ui/gfx/render_text.cc
index 2ecbfca..cb77d5b 100644
--- a/ui/gfx/render_text.cc
+++ b/ui/gfx/render_text.cc
@@ -22,6 +22,7 @@
 #include "build/build_config.h"
 #include "cc/paint/paint_canvas.h"
 #include "cc/paint/paint_shader.h"
+#include "cc/paint/paint_text_blob.h"
 #include "third_party/icu/source/common/unicode/rbbi.h"
 #include "third_party/icu/source/common/unicode/utf16.h"
 #include "third_party/skia/include/core/SkDrawLooper.h"
@@ -241,7 +242,12 @@
   static_assert(sizeof(*pos) == 2 * sizeof(*run_buffer.pos), "");
   memcpy(run_buffer.pos, pos, glyph_count * sizeof(*pos));
 
-  canvas_skia_->drawTextBlob(builder.make(), 0, 0, flags_);
+  // TODO(vmpstr): In order to OOP raster this, we would have to plumb PaintFont
+  // here instead of |flags_|.
+  canvas_skia_->drawTextBlob(
+      base::MakeRefCounted<cc::PaintTextBlob>(builder.make(),
+                                              std::vector<cc::PaintTypeface>{}),
+      0, 0, flags_);
 }
 
 void SkiaTextRenderer::DrawUnderline(int x, int y, int width) {