diff --git a/DEPS b/DEPS
index aef1cb1..8aae631 100644
--- a/DEPS
+++ b/DEPS
@@ -74,7 +74,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '7ffbcf909d365eb22c5e22b776aeac7b7472fbf3',
+  'skia_revision': '60b1b6e76e984228baa2e74513ea2174898c049b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -94,7 +94,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': 'a0aa5fdeee12bc42616fe13ef3ea62edb1b9f166',
+  'swiftshader_revision': '05bcbe6b7a2dffc284b38ad0f2731d2894972cd8',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -308,7 +308,7 @@
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
-      'url': Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + '7092a3102eae259d6ccca85a8f68d0ebf78394d2',
+      'url': Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + '5c4b603461a79a731cfcb4554f244a42f7e8679d',
       'condition': 'checkout_linux',
   },
 
@@ -634,7 +634,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '05591bbeae6592fd924caec8e728a4ea86cbb8c9',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '31cee3a0d51eed2417dabb7d88ec19ef59444d86', # commit position 20628
+    Var('webrtc_git') + '/src.git' + '@' + '83d27683a83d8c4307ca9275779e822cb4604ccf', # commit position 20628
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
diff --git a/android_webview/browser/aw_render_thread_context_provider.cc b/android_webview/browser/aw_render_thread_context_provider.cc
index ccf24453..fb559a9 100644
--- a/android_webview/browser/aw_render_thread_context_provider.cc
+++ b/android_webview/browser/aw_render_thread_context_provider.cc
@@ -67,7 +67,7 @@
   context_ = gpu::GLInProcessContext::CreateWithoutInit();
   context_->Initialize(service, surface, surface->IsOffscreen(),
                        gpu::kNullSurfaceHandle, nullptr /* share_context */,
-                       attributes, limits, nullptr, nullptr, nullptr);
+                       attributes, limits, nullptr, nullptr, nullptr, nullptr);
 
   context_->GetImplementation()->SetLostContextCallback(base::Bind(
       &AwRenderThreadContextProvider::OnLostContext, base::Unretained(this)));
diff --git a/base/allocator/partition_allocator/partition_alloc.cc b/base/allocator/partition_allocator/partition_alloc.cc
index 0f034ea7..46f061c 100644
--- a/base/allocator/partition_allocator/partition_alloc.cc
+++ b/base/allocator/partition_allocator/partition_alloc.cc
@@ -53,10 +53,6 @@
 
 }  // namespace
 
-PartitionPage* GetSentinelPageForTesting() {
-  return &g_sentinel_page;
-}
-
 PartitionRootBase::PartitionRootBase() = default;
 PartitionRootBase::~PartitionRootBase() = default;
 PartitionRoot::PartitionRoot() = default;
@@ -75,19 +71,15 @@
     nullptr;
 PartitionAllocHooks::FreeHook* PartitionAllocHooks::free_hook_ = nullptr;
 
-// Find the best number of System Pages to allocate for |size| to minimize
-// wasted space. Uses a heuristic that looks at number of bytes wasted after
-// the last slot and attempts to account for the PTE usage of each System Page.
-//
 // TODO(ajwong): This seems to interact badly with
-// PartitionBucketPartitionPages() which rounds the value from this up to a
+// get_pages_per_slot_span() which rounds the value from this up to a
 // multiple of kNumSystemPagesPerPartitionPage (aka 4) anyways.
 // http://crbug.com/776537
 //
 // TODO(ajwong): The waste calculation seems wrong. The PTE usage should cover
 // both used and unsed pages.
 // http://crbug.com/776537
-static uint8_t PartitionBucketNumSystemPages(size_t size) {
+uint8_t PartitionBucket::get_system_pages_per_slot_span() {
   // This works out reasonably for the current bucket sizes of the generic
   // allocator, and the current values of partition page size and constants.
   // Specifically, we have enough room to always pack the slots perfectly into
@@ -100,23 +92,23 @@
   // to using fewer system pages.
   double best_waste_ratio = 1.0f;
   uint16_t best_pages = 0;
-  if (size > kMaxSystemPagesPerSlotSpan * kSystemPageSize) {
+  if (this->slot_size > kMaxSystemPagesPerSlotSpan * kSystemPageSize) {
     // TODO(ajwong): Why is there a DCHECK here for this?
     // http://crbug.com/776537
-    DCHECK(!(size % kSystemPageSize));
-    best_pages = static_cast<uint16_t>(size / kSystemPageSize);
+    DCHECK(!(this->slot_size % kSystemPageSize));
+    best_pages = static_cast<uint16_t>(this->slot_size / kSystemPageSize);
     // TODO(ajwong): Should this be checking against
     // kMaxSystemPagesPerSlotSpan or numeric_limits<uint8_t>::max?
     // http://crbug.com/776537
     CHECK(best_pages < (1 << 8));
     return static_cast<uint8_t>(best_pages);
   }
-  DCHECK(size <= kMaxSystemPagesPerSlotSpan * kSystemPageSize);
+  DCHECK(this->slot_size <= kMaxSystemPagesPerSlotSpan * kSystemPageSize);
   for (uint16_t i = kNumSystemPagesPerPartitionPage - 1;
        i <= kMaxSystemPagesPerSlotSpan; ++i) {
     size_t page_size = kSystemPageSize * i;
-    size_t num_slots = page_size / size;
-    size_t waste = page_size - (num_slots * size);
+    size_t num_slots = page_size / this->slot_size;
+    size_t waste = page_size - (num_slots * this->slot_size);
     // Leaving a page unfaulted is not free; the page will occupy an empty page
     // table entry.  Make a simple attempt to account for that.
     //
@@ -159,14 +151,13 @@
   root->inverted_self = ~reinterpret_cast<uintptr_t>(root);
 }
 
-static void PartitionBucketInitBase(PartitionBucket* bucket,
-                                    PartitionRootBase* root) {
-  bucket->active_pages_head = &g_sentinel_page;
-  bucket->empty_pages_head = nullptr;
-  bucket->decommitted_pages_head = nullptr;
-  bucket->num_full_pages = 0;
-  bucket->num_system_pages_per_slot_span =
-      PartitionBucketNumSystemPages(bucket->slot_size);
+void PartitionBucket::Init(uint32_t new_slot_size) {
+  slot_size = new_slot_size;
+  active_pages_head = &g_sentinel_page;
+  empty_pages_head = nullptr;
+  decommitted_pages_head = nullptr;
+  num_full_pages = 0;
+  num_system_pages_per_slot_span = get_system_pages_per_slot_span();
 }
 
 void PartitionAllocGlobalInit(void (*oom_handling_function)()) {
@@ -183,10 +174,9 @@
   for (i = 0; i < this->num_buckets; ++i) {
     PartitionBucket* bucket = &this->buckets()[i];
     if (!i)
-      bucket->slot_size = kAllocationGranularity;
+      bucket->Init(kAllocationGranularity);
     else
-      bucket->slot_size = i << kBucketShift;
-    PartitionBucketInitBase(bucket, this);
+      bucket->Init(i << kBucketShift);
   }
 }
 
@@ -235,8 +225,7 @@
   PartitionBucket* bucket = &this->buckets[0];
   for (i = 0; i < kGenericNumBucketedOrders; ++i) {
     for (j = 0; j < kGenericNumBucketsPerOrder; ++j) {
-      bucket->slot_size = current_size;
-      PartitionBucketInitBase(bucket, this);
+      bucket->Init(current_size);
       // Disable psuedo buckets so that touching them faults.
       if (current_size % kGenericSmallestBucket)
         bucket->active_pages_head = nullptr;
@@ -257,7 +246,7 @@
         // Use the bucket of the finest granularity for malloc(0) etc.
         *bucketPtr++ = &this->buckets[0];
       } else if (order > kGenericMaxBucketedOrder) {
-        *bucketPtr++ = &g_sentinel_bucket;
+        *bucketPtr++ = PartitionBucket::get_sentinel_bucket();
       } else {
         PartitionBucket* validBucket = bucket;
         // Skip over invalid buckets.
@@ -273,7 +262,7 @@
                           ((kBitsPerSizeT + 1) * kGenericNumBucketsPerOrder));
   // And there's one last bucket lookup that will be hit for e.g. malloc(-1),
   // which tries to overflow to a non-existant order.
-  *bucketPtr = &g_sentinel_bucket;
+  *bucketPtr = PartitionBucket::get_sentinel_bucket();
 }
 
 #if !defined(ARCH_CPU_64_BITS)
@@ -302,7 +291,7 @@
   OOM_CRASH();
 }
 
-static NOINLINE void PartitionBucketFull() {
+NOINLINE void PartitionBucket::OnFull() {
   OOM_CRASH();
 }
 
@@ -377,7 +366,7 @@
   PartitionIncreaseCommittedPages(root, length);
 }
 
-static ALWAYS_INLINE void* PartitionAllocPartitionPages(
+ALWAYS_INLINE void* PartitionBucket::AllocNewSlotSpan(
     PartitionRootBase* root,
     int flags,
     uint16_t num_partition_pages) {
@@ -495,37 +484,28 @@
   return ret;
 }
 
-// Returns a natural number of PartitionPages (calculated by
-// PartitionBucketNumSystemPages()) to allocate from the current SuperPage
-// when the bucket runs out of slots.
-static ALWAYS_INLINE uint16_t
-PartitionBucketPartitionPages(const PartitionBucket* bucket) {
+ALWAYS_INLINE uint16_t PartitionBucket::get_pages_per_slot_span() {
   // Rounds up to nearest multiple of kNumSystemPagesPerPartitionPage.
-  return (bucket->num_system_pages_per_slot_span +
+  return (num_system_pages_per_slot_span +
           (kNumSystemPagesPerPartitionPage - 1)) /
          kNumSystemPagesPerPartitionPage;
 }
 
-static ALWAYS_INLINE void PartitionPageReset(PartitionPage* page) {
-  DCHECK(PartitionPageStateIsDecommitted(page));
+ALWAYS_INLINE void PartitionPage::Reset() {
+  DCHECK(PartitionPageStateIsDecommitted(this));
 
-  page->num_unprovisioned_slots = page->bucket->get_slots_per_span();
-  DCHECK(page->num_unprovisioned_slots);
+  num_unprovisioned_slots = bucket->get_slots_per_span();
+  DCHECK(num_unprovisioned_slots);
 
-  page->next_page = nullptr;
+  next_page = nullptr;
 }
 
-// Each bucket allocates a slot span when it runs out of slots.
-// A slot span's size is equal to PartitionBucketPartitionPages(bucket)
-// number of PartitionPages. This function initializes all pages within the
-// span.
-static ALWAYS_INLINE void PartitionPageSetup(PartitionPage* page,
-                                             PartitionBucket* bucket) {
+ALWAYS_INLINE void PartitionBucket::InitializeSlotSpan(PartitionPage* page) {
   // The bucket never changes. We set it up once.
-  page->bucket = bucket;
+  page->bucket = this;
   page->empty_cache_index = -1;
 
-  PartitionPageReset(page);
+  page->Reset();
 
   // If this page has just a single slot, do not set up page offsets for any
   // page metadata other than the first one. This ensures that attempts to
@@ -533,7 +513,7 @@
   if (page->num_unprovisioned_slots == 1)
     return;
 
-  uint16_t num_partition_pages = PartitionBucketPartitionPages(bucket);
+  uint16_t num_partition_pages = get_pages_per_slot_span();
   char* page_char_ptr = reinterpret_cast<char*>(page);
   for (uint16_t i = 1; i < num_partition_pages; ++i) {
     page_char_ptr += kPageMetadataSize;
@@ -543,21 +523,19 @@
   }
 }
 
-static ALWAYS_INLINE char* PartitionPageAllocAndFillFreelist(
-    PartitionPage* page) {
-  DCHECK(page != &g_sentinel_page);
+ALWAYS_INLINE char* PartitionBucket::AllocAndFillFreelist(PartitionPage* page) {
+  DCHECK(page != PartitionPage::get_sentinel_page());
   uint16_t num_slots = page->num_unprovisioned_slots;
   DCHECK(num_slots);
-  PartitionBucket* bucket = page->bucket;
   // We should only get here when _every_ slot is either used or unprovisioned.
   // (The third state is "on the freelist". If we have a non-empty freelist, we
   // should not get here.)
-  DCHECK(num_slots + page->num_allocated_slots == bucket->get_slots_per_span());
+  DCHECK(num_slots + page->num_allocated_slots == this->get_slots_per_span());
   // Similarly, make explicitly sure that the freelist is empty.
   DCHECK(!page->freelist_head);
   DCHECK(page->num_allocated_slots >= 0);
 
-  size_t size = bucket->slot_size;
+  size_t size = this->slot_size;
   char* base = reinterpret_cast<char*>(PartitionPage::ToPointer(page));
   char* return_object = base + (size * page->num_allocated_slots);
   char* firstFreelistPointer = return_object + size;
@@ -602,67 +580,59 @@
       freelist_pointer += size;
       PartitionFreelistEntry* next_entry =
           reinterpret_cast<PartitionFreelistEntry*>(freelist_pointer);
-      entry->next = PartitionFreelistMask(next_entry);
+      entry->next = PartitionFreelistEntry::Transform(next_entry);
       entry = next_entry;
     }
-    entry->next = PartitionFreelistMask(nullptr);
+    entry->next = PartitionFreelistEntry::Transform(nullptr);
   } else {
     page->freelist_head = nullptr;
   }
   return return_object;
 }
 
-// This helper function scans a bucket's active page list for a suitable new
-// active page.
-// When it finds a suitable new active page (one that has free slots and is not
-// empty), it is set as the new active page. If there is no suitable new
-// active page, the current active page is set to &g_sentinel_page.
-// As potential pages are scanned, they are tidied up according to their state.
-// Empty pages are swept on to the empty page list, decommitted pages on to the
-// decommitted page list and full pages are unlinked from any list.
-static bool PartitionSetNewActivePage(PartitionBucket* bucket) {
-  PartitionPage* page = bucket->active_pages_head;
-  if (page == &g_sentinel_page)
+bool PartitionBucket::SetNewActivePage() {
+  PartitionPage* page = this->active_pages_head;
+  if (page == PartitionPage::get_sentinel_page())
     return false;
 
   PartitionPage* next_page;
 
   for (; page; page = next_page) {
     next_page = page->next_page;
-    DCHECK(page->bucket == bucket);
-    DCHECK(page != bucket->empty_pages_head);
-    DCHECK(page != bucket->decommitted_pages_head);
+    DCHECK(page->bucket == this);
+    DCHECK(page != this->empty_pages_head);
+    DCHECK(page != this->decommitted_pages_head);
 
     // Deal with empty and decommitted pages.
     if (LIKELY(PartitionPageStateIsActive(page))) {
       // This page is usable because it has freelist entries, or has
       // unprovisioned slots we can create freelist entries from.
-      bucket->active_pages_head = page;
+      this->active_pages_head = page;
       return true;
     }
     if (LIKELY(PartitionPageStateIsEmpty(page))) {
-      page->next_page = bucket->empty_pages_head;
-      bucket->empty_pages_head = page;
+      page->next_page = this->empty_pages_head;
+      this->empty_pages_head = page;
     } else if (LIKELY(PartitionPageStateIsDecommitted(page))) {
-      page->next_page = bucket->decommitted_pages_head;
-      bucket->decommitted_pages_head = page;
+      page->next_page = this->decommitted_pages_head;
+      this->decommitted_pages_head = page;
     } else {
       DCHECK(PartitionPageStateIsFull(page));
       // If we get here, we found a full page. Skip over it too, and also
       // tag it as full (via a negative value). We need it tagged so that
       // free'ing can tell, and move it back into the active page list.
       page->num_allocated_slots = -page->num_allocated_slots;
-      ++bucket->num_full_pages;
+      ++this->num_full_pages;
       // num_full_pages is a uint16_t for efficient packing so guard against
       // overflow to be safe.
-      if (UNLIKELY(!bucket->num_full_pages))
-        PartitionBucketFull();
+      if (UNLIKELY(!this->num_full_pages))
+        OnFull();
       // Not necessary but might help stop accidents.
       page->next_page = nullptr;
     }
   }
 
-  bucket->active_pages_head = &g_sentinel_page;
+  this->active_pages_head = PartitionPage::get_sentinel_page();
   return false;
 }
 
@@ -741,7 +711,7 @@
   page->freelist_head = reinterpret_cast<PartitionFreelistEntry*>(slot);
   PartitionFreelistEntry* next_entry =
       reinterpret_cast<PartitionFreelistEntry*>(slot);
-  next_entry->next = PartitionFreelistMask(nullptr);
+  next_entry->next = PartitionFreelistEntry::Transform(nullptr);
 
   DCHECK(!bucket->active_pages_head);
   DCHECK(!bucket->empty_pages_head);
@@ -814,13 +784,13 @@
   // branches.
   //
   // Note: The ordering of the conditionals matter! In particular,
-  // PartitionSetNewActivePage() has a side-effect even when returning
+  // SetNewActivePage() has a side-effect even when returning
   // false where it sweeps the active page list and may move things into
   // the empty or decommitted lists which affects the subsequent conditional.
   bool returnNull = flags & PartitionAllocReturnNull;
   if (UNLIKELY(this->is_direct_mapped())) {
     DCHECK(size > kGenericMaxBucketed);
-    DCHECK(this == &g_sentinel_bucket);
+    DCHECK(this == get_sentinel_bucket());
     DCHECK(this->active_pages_head == &g_sentinel_page);
     if (size > kGenericMaxDirectMapped) {
       if (returnNull)
@@ -828,7 +798,7 @@
       PartitionExcessiveAllocationSize();
     }
     new_page = PartitionDirectMap(root, flags, size);
-  } else if (LIKELY(PartitionSetNewActivePage(this))) {
+  } else if (LIKELY(this->SetNewActivePage())) {
     // First, did we find an active page in the active pages list?
     new_page = this->active_pages_head;
     DCHECK(PartitionPageStateIsActive(new_page));
@@ -860,17 +830,16 @@
       void* addr = PartitionPage::ToPointer(new_page);
       PartitionRecommitSystemPages(root, addr,
                                    new_page->bucket->get_bytes_per_span());
-      PartitionPageReset(new_page);
+      new_page->Reset();
     }
     DCHECK(new_page);
   } else {
     // Third. If we get here, we need a brand new page.
-    uint16_t num_partition_pages = PartitionBucketPartitionPages(this);
-    void* rawPages =
-        PartitionAllocPartitionPages(root, flags, num_partition_pages);
+    uint16_t num_partition_pages = this->get_pages_per_slot_span();
+    void* rawPages = AllocNewSlotSpan(root, flags, num_partition_pages);
     if (LIKELY(rawPages != nullptr)) {
       new_page = PartitionPage::FromPointerNoAlignmentCheck(rawPages);
-      PartitionPageSetup(new_page, this);
+      InitializeSlotSpan(new_page);
     }
   }
 
@@ -886,7 +855,7 @@
   // It seems like in many of the conditional branches above, |this| ==
   // |new_page->bucket|. Maybe pull this into another function?
   PartitionBucket* bucket = new_page->bucket;
-  DCHECK(bucket != &g_sentinel_bucket);
+  DCHECK(bucket != get_sentinel_bucket());
   bucket->active_pages_head = new_page;
   PartitionPageSetRawSize(new_page, size);
 
@@ -894,14 +863,19 @@
   // usable freelist head.
   if (LIKELY(new_page->freelist_head != nullptr)) {
     PartitionFreelistEntry* entry = new_page->freelist_head;
-    PartitionFreelistEntry* new_head = PartitionFreelistMask(entry->next);
+    PartitionFreelistEntry* new_head =
+        PartitionFreelistEntry::Transform(entry->next);
     new_page->freelist_head = new_head;
     new_page->num_allocated_slots++;
     return entry;
   }
   // Otherwise, we need to build the freelist.
   DCHECK(new_page->num_unprovisioned_slots);
-  return PartitionPageAllocAndFillFreelist(new_page);
+  return AllocAndFillFreelist(new_page);
+}
+
+PartitionBucket* PartitionBucket::get_sentinel_bucket() {
+  return &g_sentinel_bucket;
 }
 
 static ALWAYS_INLINE void PartitionDecommitPage(PartitionRootBase* root,
@@ -972,6 +946,10 @@
   }
 }
 
+PartitionPage* PartitionPage::get_sentinel_page() {
+  return &g_sentinel_page;
+}
+
 void PartitionPage::FreeSlowPath() {
   DCHECK(this != &g_sentinel_page);
   if (LIKELY(this->num_allocated_slots == 0)) {
@@ -983,7 +961,7 @@
     // If it's the current active page, change it. We bounce the page to
     // the empty list as a force towards defragmentation.
     if (LIKELY(this == bucket->active_pages_head))
-      PartitionSetNewActivePage(bucket);
+      bucket->SetNewActivePage();
     DCHECK(bucket->active_pages_head != this);
 
     PartitionPageSetRawSize(this, 0);
@@ -1181,14 +1159,14 @@
     size_t slotIndex = (reinterpret_cast<char*>(entry) - ptr) / slot_size;
     DCHECK(slotIndex < num_slots);
     slot_usage[slotIndex] = 0;
-    entry = PartitionFreelistMask(entry->next);
+    entry = PartitionFreelistEntry::Transform(entry->next);
 #if !defined(OS_WIN)
     // If we have a slot where the masked freelist entry is 0, we can
     // actually discard that freelist entry because touching a discarded
     // page is guaranteed to return original content or 0.
     // (Note that this optimization won't fire on big endian machines
     // because the masking function is negation.)
-    if (!PartitionFreelistMask(entry))
+    if (!PartitionFreelistEntry::Transform(entry))
       last_slot = slotIndex;
 #endif
   }
@@ -1229,7 +1207,7 @@
           continue;
         auto* entry = reinterpret_cast<PartitionFreelistEntry*>(
             ptr + (slot_size * slotIndex));
-        *entry_ptr = PartitionFreelistMask(entry);
+        *entry_ptr = PartitionFreelistEntry::Transform(entry);
         entry_ptr = reinterpret_cast<PartitionFreelistEntry**>(entry);
         num_new_entries++;
 #if !defined(OS_WIN)
@@ -1239,7 +1217,8 @@
       // Terminate the freelist chain.
       *entry_ptr = nullptr;
       // The freelist head is stored unmasked.
-      page->freelist_head = PartitionFreelistMask(page->freelist_head);
+      page->freelist_head =
+          PartitionFreelistEntry::Transform(page->freelist_head);
       DCHECK(num_new_entries == num_slots - page->num_allocated_slots);
       // Discard the memory.
       DiscardSystemPages(begin_ptr, unprovisioned_bytes);
diff --git a/base/allocator/partition_allocator/partition_alloc.h b/base/allocator/partition_allocator/partition_alloc.h
index 157ceff..5ee7c3b 100644
--- a/base/allocator/partition_allocator/partition_alloc.h
+++ b/base/allocator/partition_allocator/partition_alloc.h
@@ -230,8 +230,31 @@
 struct PartitionBucket;
 struct PartitionRootBase;
 
+// TODO(ajwong): Introduce an EncodedFreelistEntry type and then replace
+// Transform() with Encode()/Decode() such that the API provides some static
+// type safety.
+//
+// https://crbug.com/787153
 struct PartitionFreelistEntry {
   PartitionFreelistEntry* next;
+
+  static ALWAYS_INLINE PartitionFreelistEntry* Transform(
+      PartitionFreelistEntry* ptr) {
+// We use bswap on little endian as a fast mask for two reasons:
+// 1) If an object is freed and its vtable used where the attacker doesn't
+// get the chance to run allocations between the free and use, the vtable
+// dereference is likely to fault.
+// 2) If the attacker has a linear buffer overflow and elects to try and
+// corrupt a freelist pointer, partial pointer overwrite attacks are
+// thwarted.
+// For big endian, similar guarantees are arrived at with a negation.
+#if defined(ARCH_CPU_BIG_ENDIAN)
+    uintptr_t masked = ~reinterpret_cast<uintptr_t>(ptr);
+#else
+    uintptr_t masked = ByteSwapUintPtrT(reinterpret_cast<uintptr_t>(ptr));
+#endif
+    return reinterpret_cast<PartitionFreelistEntry*>(masked);
+  }
 };
 
 // Some notes on page states. A page can be in one of four major states:
@@ -295,6 +318,11 @@
   }
 
   ALWAYS_INLINE size_t get_raw_size() const;
+
+  ALWAYS_INLINE void Reset();
+
+  // TODO(ajwong): Can this be made private?  https://crbug.com/787153
+  BASE_EXPORT static PartitionPage* get_sentinel_page();
 };
 static_assert(sizeof(PartitionPage) <= kPageMetadataSize,
               "PartitionPage must be able to fit in a metadata slot");
@@ -310,6 +338,7 @@
   unsigned num_full_pages : 24;
 
   // Public API.
+  void Init(uint32_t new_slot_size);
 
   // Note the matching Free() functions are in PartitionPage.
   BASE_EXPORT void* Alloc(PartitionRootBase* root, int flags, size_t size);
@@ -328,6 +357,60 @@
     // TODO(ajwong): Chagne to CheckedMul. https://crbug.com/787153
     return static_cast<uint16_t>(get_bytes_per_span() / slot_size);
   }
+
+  // TODO(ajwong): Can this be made private?  https://crbug.com/787153
+  static PartitionBucket* get_sentinel_bucket();
+
+  // This helper function scans a bucket's active page list for a suitable new
+  // active page.  When it finds a suitable new active page (one that has
+  // free slots and is not empty), it is set as the new active page. If there
+  // is no suitable new active page, the current active page is set to
+  // PartitionPage::get_sentinel_page(). As potential pages are scanned, they
+  // are tidied up according to their state. Empty pages are swept on to the
+  // empty page list, decommitted pages on to the decommitted page list and full
+  // pages are unlinked from any list.
+  //
+  // This is where the guts of the bucket maintenance is done!
+  bool SetNewActivePage();
+
+ private:
+  static void OutOfMemory(const PartitionRootBase* root);
+  static void OutOfMemoryWithLotsOfUncommitedPages();
+
+  static NOINLINE void OnFull();
+
+  // Returns a natural number of PartitionPages (calculated by
+  // get_system_pages_per_slot_span()) to allocate from the current
+  // SuperPage when the bucket runs out of slots.
+  ALWAYS_INLINE uint16_t get_pages_per_slot_span();
+
+  // Returns the number of system pages in a slot span.
+  //
+  // The calculation attemps to find the best number of System Pages to
+  // allocate for the given slot_size to minimize wasted space. It uses a
+  // heuristic that looks at number of bytes wasted after the last slot and
+  // attempts to account for the PTE usage of each System Page.
+  uint8_t get_system_pages_per_slot_span();
+
+  // Allocates a new slot span with size |num_partition_pages| from the
+  // current extent. Metadata within this slot span will be uninitialized.
+  // Returns nullptr on error.
+  ALWAYS_INLINE void* AllocNewSlotSpan(PartitionRootBase* root,
+                                       int flags,
+                                       uint16_t num_partition_pages);
+
+  // Each bucket allocates a slot span when it runs out of slots.
+  // A slot span's size is equal to get_pages_per_slot_span() number of
+  // PartitionPages. This function initializes all PartitionPage within the
+  // span to point to the first PartitionPage which holds all the metadata
+  // for the span and registers this bucket as the owner of the span. It does
+  // NOT put the slots into the bucket's freelist.
+  ALWAYS_INLINE void InitializeSlotSpan(PartitionPage* page);
+
+  // Allocates one slot from the given |page| and then adds the remainder to
+  // the current bucket. If the |page| was freshly allocated, it must have been
+  // passed through InitializeSlotSpan() first.
+  ALWAYS_INLINE char* AllocAndFillFreelist(PartitionPage* page);
 };
 
 // An "extent" is a span of consecutive superpages. We link to the partition's
@@ -555,24 +638,6 @@
   static FreeHook* free_hook_;
 };
 
-ALWAYS_INLINE PartitionFreelistEntry* PartitionFreelistMask(
-    PartitionFreelistEntry* ptr) {
-// We use bswap on little endian as a fast mask for two reasons:
-// 1) If an object is freed and its vtable used where the attacker doesn't
-// get the chance to run allocations between the free and use, the vtable
-// dereference is likely to fault.
-// 2) If the attacker has a linear buffer overflow and elects to try and
-// corrupt a freelist pointer, partial pointer overwrite attacks are
-// thwarted.
-// For big endian, similar guarantees are arrived at with a negation.
-#if defined(ARCH_CPU_BIG_ENDIAN)
-  uintptr_t masked = ~reinterpret_cast<uintptr_t>(ptr);
-#else
-  uintptr_t masked = ByteSwapUintPtrT(reinterpret_cast<uintptr_t>(ptr));
-#endif
-  return reinterpret_cast<PartitionFreelistEntry*>(masked);
-}
-
 ALWAYS_INLINE size_t PartitionCookieSizeAdjustAdd(size_t size) {
 #if DCHECK_IS_ON()
   // Add space for cookies, checking for integer overflow. TODO(palmer):
@@ -728,8 +793,8 @@
     // All large allocations must go through the slow path to correctly
     // update the size metadata.
     DCHECK(page->get_raw_size() == 0);
-    PartitionFreelistEntry* new_head =
-        PartitionFreelistMask(static_cast<PartitionFreelistEntry*>(ret)->next);
+    PartitionFreelistEntry* new_head = PartitionFreelistEntry::Transform(
+        static_cast<PartitionFreelistEntry*>(ret)->next);
     page->freelist_head = new_head;
     page->num_allocated_slots++;
   } else {
@@ -802,9 +867,10 @@
                                PartitionPage::FromPointer(freelist_head)));
   CHECK(ptr != freelist_head);  // Catches an immediate double free.
   // Look for double free one level deeper in debug.
-  DCHECK(!freelist_head || ptr != PartitionFreelistMask(freelist_head->next));
+  DCHECK(!freelist_head ||
+         ptr != PartitionFreelistEntry::Transform(freelist_head->next));
   PartitionFreelistEntry* entry = static_cast<PartitionFreelistEntry*>(ptr);
-  entry->next = PartitionFreelistMask(freelist_head);
+  entry->next = PartitionFreelistEntry::Transform(freelist_head);
   freelist_head = entry;
   --this->num_allocated_slots;
   if (UNLIKELY(this->num_allocated_slots <= 0)) {
@@ -973,8 +1039,6 @@
   PartitionRootGeneric partition_root_;
 };
 
-BASE_EXPORT PartitionPage* GetSentinelPageForTesting();
-
 }  // namespace base
 
 #endif  // BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_H_
diff --git a/base/allocator/partition_allocator/partition_alloc_unittest.cc b/base/allocator/partition_allocator/partition_alloc_unittest.cc
index 5bd790e..3c774825 100644
--- a/base/allocator/partition_allocator/partition_alloc_unittest.cc
+++ b/base/allocator/partition_allocator/partition_alloc_unittest.cc
@@ -139,7 +139,8 @@
                              bucket->active_pages_head->num_allocated_slots));
     EXPECT_EQ(nullptr, bucket->active_pages_head->freelist_head);
     EXPECT_TRUE(bucket->active_pages_head);
-    EXPECT_TRUE(bucket->active_pages_head != GetSentinelPageForTesting());
+    EXPECT_TRUE(bucket->active_pages_head !=
+                PartitionPage::get_sentinel_page());
     return bucket->active_pages_head;
   }
 
@@ -380,7 +381,7 @@
 // Check that the most basic of allocate / free pairs work.
 TEST_F(PartitionAllocTest, Basic) {
   PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex];
-  PartitionPage* seedPage = GetSentinelPageForTesting();
+  PartitionPage* seedPage = PartitionPage::get_sentinel_page();
 
   EXPECT_FALSE(bucket->empty_pages_head);
   EXPECT_FALSE(bucket->decommitted_pages_head);
@@ -445,7 +446,7 @@
   PartitionPage* page = GetFullPage(kTestAllocSize);
   FreeFullPage(page);
   EXPECT_TRUE(bucket->empty_pages_head);
-  EXPECT_EQ(GetSentinelPageForTesting(), bucket->active_pages_head);
+  EXPECT_EQ(PartitionPage::get_sentinel_page(), bucket->active_pages_head);
   EXPECT_EQ(nullptr, page->next_page);
   EXPECT_EQ(0, page->num_allocated_slots);
 
@@ -464,7 +465,7 @@
   FreeFullPage(page);
   EXPECT_EQ(0, page->num_allocated_slots);
   EXPECT_TRUE(bucket->empty_pages_head);
-  EXPECT_EQ(GetSentinelPageForTesting(), bucket->active_pages_head);
+  EXPECT_EQ(PartitionPage::get_sentinel_page(), bucket->active_pages_head);
 
   // Allocate a new page, it should pull from the freelist.
   page = GetFullPage(kTestAllocSize);
@@ -560,7 +561,7 @@
   EXPECT_EQ(pages[numToFillFreeListPage - 1], bucket->active_pages_head);
   for (i = 0; i < numToFillFreeListPage; ++i)
     FreeFullPage(pages[i]);
-  EXPECT_EQ(GetSentinelPageForTesting(), bucket->active_pages_head);
+  EXPECT_EQ(PartitionPage::get_sentinel_page(), bucket->active_pages_head);
   EXPECT_TRUE(bucket->empty_pages_head);
 
   // Allocate / free in a different bucket size so we get control of a
@@ -578,7 +579,7 @@
 
   for (i = 0; i < numToFillFreeListPage; ++i)
     FreeFullPage(pages[i]);
-  EXPECT_EQ(GetSentinelPageForTesting(), bucket->active_pages_head);
+  EXPECT_EQ(PartitionPage::get_sentinel_page(), bucket->active_pages_head);
   EXPECT_TRUE(bucket->empty_pages_head);
 }
 
@@ -1301,14 +1302,14 @@
 
   EXPECT_TRUE(bucket->empty_pages_head);
   EXPECT_TRUE(bucket->empty_pages_head->next_page);
-  EXPECT_EQ(GetSentinelPageForTesting(), bucket->active_pages_head);
+  EXPECT_EQ(PartitionPage::get_sentinel_page(), bucket->active_pages_head);
 
   // At this moment, we have two decommitted pages, on the empty list.
   ptr = generic_allocator.root()->Alloc(size, type_name);
   EXPECT_TRUE(ptr);
   generic_allocator.root()->Free(ptr);
 
-  EXPECT_EQ(GetSentinelPageForTesting(), bucket->active_pages_head);
+  EXPECT_EQ(PartitionPage::get_sentinel_page(), bucket->active_pages_head);
   EXPECT_TRUE(bucket->empty_pages_head);
   EXPECT_TRUE(bucket->decommitted_pages_head);
 
diff --git a/cc/paint/oop_pixeltest.cc b/cc/paint/oop_pixeltest.cc
index 3f21bbe..cddef1a 100644
--- a/cc/paint/oop_pixeltest.cc
+++ b/cc/paint/oop_pixeltest.cc
@@ -61,7 +61,7 @@
     auto result = context_->Initialize(
         nullptr, nullptr, is_offscreen, gpu::kNullSurfaceHandle, nullptr,
         attribs, gpu::SharedMemoryLimits(), &gpu_memory_buffer_manager_,
-        &image_factory_, base::ThreadTaskRunnerHandle::Get());
+        &image_factory_, nullptr, base::ThreadTaskRunnerHandle::Get());
 
     ASSERT_EQ(result, gpu::ContextResult::kSuccess);
     ASSERT_TRUE(context_->GetCapabilities().supports_oop_raster);
diff --git a/cc/paint/transfer_cache_unittest.cc b/cc/paint/transfer_cache_unittest.cc
index 3d6d016..25145930 100644
--- a/cc/paint/transfer_cache_unittest.cc
+++ b/cc/paint/transfer_cache_unittest.cc
@@ -57,7 +57,7 @@
     auto result = context_->Initialize(
         nullptr, nullptr, is_offscreen, gpu::kNullSurfaceHandle, nullptr,
         attribs, gpu::SharedMemoryLimits(), &gpu_memory_buffer_manager_,
-        &image_factory_, base::ThreadTaskRunnerHandle::Get());
+        &image_factory_, nullptr, base::ThreadTaskRunnerHandle::Get());
 
     ASSERT_EQ(result, gpu::ContextResult::kSuccess);
     ASSERT_TRUE(context_->GetCapabilities().supports_oop_raster);
diff --git a/cc/test/test_in_process_context_provider.cc b/cc/test/test_in_process_context_provider.cc
index 2952964..aa79b74 100644
--- a/cc/test/test_in_process_context_provider.cc
+++ b/cc/test/test_in_process_context_provider.cc
@@ -47,7 +47,7 @@
   auto result = context->Initialize(
       nullptr, nullptr, is_offscreen, gpu::kNullSurfaceHandle, shared_context,
       attribs, gpu::SharedMemoryLimits(), gpu_memory_buffer_manager,
-      image_factory, std::move(task_runner));
+      image_factory, nullptr, std::move(task_runner));
 
   DCHECK_EQ(result, gpu::ContextResult::kSuccess);
   return context;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java
index 8e6615f6..f666b3f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java
@@ -285,7 +285,15 @@
         if (mBookmarkModel == null) return;
 
         if (mBookmarkModel.isBookmarkModelLoaded()) {
+            BookmarkUIState searchState = null;
+            if (!mStateStack.isEmpty()
+                    && mStateStack.peek().mState == BookmarkUIState.STATE_SEARCHING) {
+                searchState = mStateStack.pop();
+            }
+
             setState(BookmarkUIState.createStateFromUrl(url, mBookmarkModel));
+
+            if (searchState != null) setState(searchState);
         } else {
             mInitialUrl = url;
         }
@@ -330,8 +338,9 @@
         }
         mStateStack.push(state);
 
-        if (state.mState != BookmarkUIState.STATE_LOADING) {
-            // Loading state may be pushed to the stack but should never be stored in preferences.
+        if (state.mState == BookmarkUIState.STATE_FOLDER) {
+            // Loading and searching states may be pushed to the stack but should never be stored in
+            // preferences.
             BookmarkUtils.setLastUsedUrl(mActivity, state.mUrl);
             // If a loading state is replaced by another loading state, do not notify this change.
             if (mNativePage != null) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java
index f840f61..ebfb21c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java
@@ -27,7 +27,6 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.base.test.util.RetryOnFailure;
@@ -320,7 +319,6 @@
 
     @Test
     @MediumTest
-    @DisabledTest(message = "crbug.com/791485")
     public void testSearchBookmarks_Delete() throws Exception {
         BookmarkPromoHeader.forcePromoStateForTests(BookmarkPromoHeader.PromoState.PROMO_NONE);
         BookmarkId testFolder = addFolder(TEST_FOLDER_TITLE);
@@ -331,12 +329,14 @@
         BookmarkItemsAdapter adapter = ((BookmarkItemsAdapter) mItemsContainer.getAdapter());
         BookmarkManager manager = (BookmarkManager) adapter.getDelegateForTesting();
 
-        Assert.assertEquals(BookmarkUIState.STATE_FOLDER, manager.getCurrentState());
+        Assert.assertEquals("Wrong state, should be in folder", BookmarkUIState.STATE_FOLDER,
+                manager.getCurrentState());
         assertBookmarkItems("Wrong number of items before starting search.", 3, adapter, manager);
 
         // Start searching without entering a query.
         ThreadUtils.runOnUiThreadBlocking(manager::openSearchUI);
-        Assert.assertEquals(BookmarkUIState.STATE_SEARCHING, manager.getCurrentState());
+        Assert.assertEquals("Wrong state, should be searching", BookmarkUIState.STATE_SEARCHING,
+                manager.getCurrentState());
 
         // Select the folder and delete it.
         ThreadUtils.runOnUiThreadBlocking(
@@ -348,12 +348,14 @@
                                         R.id.selection_mode_delete_menu_id)));
 
         // Search should be exited and the folder should be gone.
-        Assert.assertEquals(BookmarkUIState.STATE_FOLDER, manager.getCurrentState());
+        Assert.assertEquals("Wrong state, should be in folder", BookmarkUIState.STATE_FOLDER,
+                manager.getCurrentState());
         assertBookmarkItems("Wrong number of items before starting search.", 2, adapter, manager);
 
         // Start searching, enter a query.
         ThreadUtils.runOnUiThreadBlocking(manager::openSearchUI);
-        Assert.assertEquals(BookmarkUIState.STATE_SEARCHING, manager.getCurrentState());
+        Assert.assertEquals("Wrong state, should be searching", BookmarkUIState.STATE_SEARCHING,
+                manager.getCurrentState());
         searchBookmarks("Google");
         assertBookmarkItems(
                 "Wrong number of items after searching.", 1, mItemsContainer.getAdapter(), manager);
@@ -362,7 +364,8 @@
         removeBookmark(testBookmark);
 
         // The user should still be searching, and the bookmark should be gone.
-        Assert.assertEquals(BookmarkUIState.STATE_SEARCHING, manager.getCurrentState());
+        Assert.assertEquals("Wrong state, should be searching", BookmarkUIState.STATE_SEARCHING,
+                manager.getCurrentState());
         assertBookmarkItems(
                 "Wrong number of items after searching.", 0, mItemsContainer.getAdapter(), manager);
 
@@ -370,7 +373,8 @@
         ThreadUtils.runOnUiThreadBlocking(() -> manager.getUndoControllerForTests().onAction(null));
 
         // The user should still be searching, and the bookmark should reappear.
-        Assert.assertEquals(BookmarkUIState.STATE_SEARCHING, manager.getCurrentState());
+        Assert.assertEquals("Wrong state, should be searching", BookmarkUIState.STATE_SEARCHING,
+                manager.getCurrentState());
         assertBookmarkItems(
                 "Wrong number of items after searching.", 1, mItemsContainer.getAdapter(), manager);
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTransitionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTransitionTest.java
index 20c9415..8909e91 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTransitionTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTransitionTest.java
@@ -212,8 +212,7 @@
     public void testControlsVisibleAfterExitingVr() throws InterruptedException {
         mVrTestFramework.loadUrlAndAwaitInitialization(
                 VrTestFramework.getHtmlTestFile("generic_webvr_page"), PAGE_LOAD_TIMEOUT_S);
-        VrTransitionUtils.enterPresentationAndWait(
-                mVrTestFramework.getFirstTabCvc(), mVrTestFramework.getFirstTabWebContents());
+        VrTransitionUtils.enterPresentationOrFail(mVrTestFramework.getFirstTabCvc());
         VrTransitionUtils.forceExitVr();
         // The hiding of the controls may only propagate after VR has exited, so give it a chance
         // to propagate. In the worst case this test will erroneously pass, but should never
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index cd99f48..daa64c6 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3318,6 +3318,11 @@
      flag_descriptions::kEnableNetworkServiceDescription, kOsAll,
      FEATURE_VALUE_TYPE(features::kNetworkService)},
 
+    {"network-service-in-process",
+     flag_descriptions::kEnableNetworkServiceInProcessName,
+     flag_descriptions::kEnableNetworkServiceInProcessDescription, kOsAll,
+     FEATURE_VALUE_TYPE(features::kNetworkServiceInProcess)},
+
     {"out-of-blink-cors", flag_descriptions::kEnableOutOfBlinkCORSName,
      flag_descriptions::kEnableOutOfBlinkCORSDescription, kOsAll,
      FEATURE_VALUE_TYPE(features::kOutOfBlinkCORS)},
diff --git a/chrome/browser/autofill/form_structure_browsertest.cc b/chrome/browser/autofill/form_structure_browsertest.cc
index 01425032..f70e6cee 100644
--- a/chrome/browser/autofill/form_structure_browsertest.cc
+++ b/chrome/browser/autofill/form_structure_browsertest.cc
@@ -5,6 +5,7 @@
 #include <algorithm>
 #include <vector>
 
+#include "base/bind.h"
 #include "base/command_line.h"
 #include "base/feature_list.h"
 #include "base/files/file_enumerator.h"
@@ -28,6 +29,10 @@
 #include "components/autofill/core/browser/form_structure.h"
 #include "components/autofill/core/common/autofill_features.h"
 #include "content/public/common/content_switches.h"
+#include "net/http/http_status_code.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
 #include "url/gurl.h"
 
 #if defined(OS_MACOSX)
@@ -37,21 +42,15 @@
 namespace autofill {
 namespace {
 
+using net::test_server::BasicHttpResponse;
+using net::test_server::HttpRequest;
+using net::test_server::HttpResponse;
+
 const base::FilePath::CharType kTestName[] = FILE_PATH_LITERAL("heuristics");
 
-// Convert the |html| snippet to a data URI.
-GURL HTMLToDataURI(const std::string& html) {
-  // GURL requires data URLs to be UTF-8 and will fail below if it's not.
-  CHECK(base::IsStringUTF8(html)) << "Input file is not UTF-8.";
-
-  // Strip `\n`, `\t`, `\r` from |html| to match old `data:` URL behavior.
-  std::string stripped_html;
-  for (const auto& character : html) {
-    if (character == '\n' || character == '\t' || character == '\r')
-      continue;
-    stripped_html.push_back(character);
-  }
-  return GURL(std::string("data:text/html;charset=utf-8,") + stripped_html);
+const std::set<base::FilePath::StringType>& GetFailingTestNames() {
+  static auto* failing_test_names = new std::set<base::FilePath::StringType>{};
+  return *failing_test_names;
 }
 
 const base::FilePath& GetTestDataDir() {
@@ -65,16 +64,17 @@
   return dir;
 }
 
-const std::vector<base::FilePath> GetTestFiles() {
-  base::FilePath dir;
-  CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &dir));
-  dir = dir.AppendASCII("components")
-            .AppendASCII("test")
-            .AppendASCII("data")
-            .AppendASCII("autofill")
-            .Append(kTestName)
-            .AppendASCII("input");
-  base::FileEnumerator input_files(dir, false, base::FileEnumerator::FILES);
+const base::FilePath GetInputDir() {
+  static base::FilePath input_dir = GetTestDataDir()
+                                        .AppendASCII("autofill")
+                                        .Append(kTestName)
+                                        .AppendASCII("input");
+  return input_dir;
+}
+
+std::vector<base::FilePath> GetTestFiles() {
+  base::FileEnumerator input_files(GetInputDir(), false,
+                                   base::FileEnumerator::FILES);
   std::vector<base::FilePath> files;
   for (base::FilePath input_file = input_files.Next(); !input_file.empty();
        input_file = input_files.Next()) {
@@ -89,14 +89,20 @@
   return files;
 }
 
-const std::set<base::FilePath::StringType>& GetFailingTestNames() {
-  // TODO(crbug.com/789944): Reenable these tests.
-  static std::set<base::FilePath::StringType>* failing_test_names =
-      new std::set<base::FilePath::StringType>{
-          FILE_PATH_LITERAL("067_register_rei.com.html"),
-          FILE_PATH_LITERAL("074_register_threadless.com.html"),
-      };
-  return *failing_test_names;
+std::string FormStructuresToString(
+    const std::vector<std::unique_ptr<FormStructure>>& forms) {
+  std::string forms_string;
+  for (const auto& form : forms) {
+    for (const auto& field : *form) {
+      forms_string += field->Type().ToString();
+      forms_string += " | " + base::UTF16ToUTF8(field->name);
+      forms_string += " | " + base::UTF16ToUTF8(field->label);
+      forms_string += " | " + base::UTF16ToUTF8(field->value);
+      forms_string += " | " + field->section();
+      forms_string += "\n";
+    }
+  }
+  return forms_string;
 }
 
 }  // namespace
@@ -113,21 +119,24 @@
   ~FormStructureBrowserTest() override;
 
   // InProcessBrowserTest
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    // Suppress most output logs because we can't really control the output for
-    // arbitrary test sites.
-    command_line->AppendSwitchASCII(switches::kLoggingLevel, "2");
-  }
+  void SetUpCommandLine(base::CommandLine* command_line) override;
+
+  // BrowserTestBase
+  void SetUpOnMainThread() override;
 
   // DataDrivenTest:
   void GenerateResults(const std::string& input, std::string* output) override;
 
-  // Serializes the given |forms| into a string.
-  std::string FormStructuresToString(
-      const std::vector<std::unique_ptr<FormStructure>>& forms);
-
  private:
+  std::unique_ptr<HttpResponse> HandleRequest(const HttpRequest& request);
+
   base::test::ScopedFeatureList feature_list_;
+
+  // The response content to be returned by the embedded test server. Note that
+  // this is populated in the main thread as a part of the setup in the
+  // GenerateResults method but it is consumed later in the IO thread by the
+  // embedded test server to generate the response.
+  std::string html_content_;
   DISALLOW_COPY_AND_ASSIGN(FormStructureBrowserTest);
 };
 
@@ -140,11 +149,42 @@
 FormStructureBrowserTest::~FormStructureBrowserTest() {
 }
 
+void FormStructureBrowserTest::SetUpCommandLine(
+    base::CommandLine* command_line) {
+  InProcessBrowserTest::SetUpCommandLine(command_line);
+  // Suppress most output logs because we can't really control the output for
+  // arbitrary test sites.
+  command_line->AppendSwitchASCII(switches::kLoggingLevel, "2");
+}
+
+void FormStructureBrowserTest::SetUpOnMainThread() {
+  InProcessBrowserTest::SetUpOnMainThread();
+
+  embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
+      &FormStructureBrowserTest::HandleRequest, base::Unretained(this)));
+  ASSERT_TRUE(embedded_test_server()->Start());
+}
+
 void FormStructureBrowserTest::GenerateResults(const std::string& input,
                                                std::string* output) {
-  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(),
-                                                       HTMLToDataURI(input)));
+  // Cache the content to be returned by the embedded test server. This data
+  // is readonly after this point.
+  html_content_.clear();
+  html_content_.reserve(input.length());
+  for (const char c : input) {
+    // Strip `\n`, `\t`, `\r` from |html| to match old `data:` URL behavior.
+    // TODO(crbug/239819): the tests expect weird concatenation behavior based
+    //   legacy data URL behavior. Fix this so the the tests better represent
+    //   the parsing being done in the wild.
+    if (c != '\r' && c != '\n' && c != '\t')
+      html_content_.push_back(c);
+  }
 
+  // Navigate to the test html content.
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browser(), embedded_test_server()->GetURL("/test.html")));
+
+  // Dump the form fields (and their inferred field types).
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
   ContentAutofillDriver* autofill_driver =
@@ -158,20 +198,13 @@
   *output = FormStructuresToString(forms);
 }
 
-std::string FormStructureBrowserTest::FormStructuresToString(
-    const std::vector<std::unique_ptr<FormStructure>>& forms) {
-  std::string forms_string;
-  for (const auto& form : forms) {
-    for (const auto& field : *form) {
-      forms_string += field->Type().ToString();
-      forms_string += " | " + base::UTF16ToUTF8(field->name);
-      forms_string += " | " + base::UTF16ToUTF8(field->label);
-      forms_string += " | " + base::UTF16ToUTF8(field->value);
-      forms_string += " | " + field->section();
-      forms_string += "\n";
-    }
-  }
-  return forms_string;
+std::unique_ptr<HttpResponse> FormStructureBrowserTest::HandleRequest(
+    const HttpRequest& request) {
+  auto response = std::make_unique<BasicHttpResponse>();
+  response->set_code(net::HTTP_OK);
+  response->set_content(html_content_);
+  response->set_content_type("text/html; charset=utf-8");
+  return std::move(response);
 }
 
 IN_PROC_BROWSER_TEST_P(FormStructureBrowserTest, DataDrivenHeuristics) {
diff --git a/chrome/browser/chromeos/system_logs/single_debug_daemon_log_source.cc b/chrome/browser/chromeos/system_logs/single_debug_daemon_log_source.cc
index 445beb9..aaf7e7eb 100644
--- a/chrome/browser/chromeos/system_logs/single_debug_daemon_log_source.cc
+++ b/chrome/browser/chromeos/system_logs/single_debug_daemon_log_source.cc
@@ -9,7 +9,6 @@
 #include "base/bind.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/debug_daemon_client.h"
-#include "components/feedback/anonymizer_tool.h"
 #include "content/public/browser/browser_thread.h"
 
 namespace system_logs {
@@ -65,10 +64,8 @@
   // DebugDaemonClient, which does not use the SystemLogsResponse alias.
   auto response = std::make_unique<SystemLogsResponse>();
   // Return an empty result if the call to GetLog() failed.
-  if (result.has_value()) {
-    response->emplace(log_name,
-                      feedback::AnonymizerTool().Anonymize(result.value()));
-  }
+  if (result.has_value())
+    response->emplace(log_name, result.value());
 
   callback.Run(std::move(response));
 }
diff --git a/chrome/browser/chromeos/system_logs/single_log_file_log_source.cc b/chrome/browser/chromeos/system_logs/single_log_file_log_source.cc
index d59944f..84e92bdc 100644
--- a/chrome/browser/chromeos/system_logs/single_log_file_log_source.cc
+++ b/chrome/browser/chromeos/system_logs/single_log_file_log_source.cc
@@ -169,8 +169,7 @@
   num_bytes_read_ += size_read;
 
   // Pass it back to the callback.
-  AppendToSystemLogsResponse(result, source_name(),
-                             anonymizer_.Anonymize(result_string));
+  AppendToSystemLogsResponse(result, source_name(), result_string);
 
   // If the file was rotated, close the file handle and call this function
   // again, to read from the new file.
diff --git a/chrome/browser/chromeos/system_logs/single_log_file_log_source.h b/chrome/browser/chromeos/system_logs/single_log_file_log_source.h
index 28f44540..2a1c22ff 100644
--- a/chrome/browser/chromeos/system_logs/single_log_file_log_source.h
+++ b/chrome/browser/chromeos/system_logs/single_log_file_log_source.h
@@ -11,7 +11,6 @@
 #include "base/files/file.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "components/feedback/anonymizer_tool.h"
 #include "components/feedback/system_logs/system_logs_source.h"
 
 namespace base {
@@ -97,9 +96,6 @@
   // was originally opened for reading.
   ino_t file_inode_;
 
-  // For removing PII from log results.
-  feedback::AnonymizerTool anonymizer_;
-
   base::WeakPtrFactory<SingleLogFileLogSource> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(SingleLogFileLogSource);
diff --git a/chrome/browser/chromeos/system_logs/single_log_file_log_source_unittest.cc b/chrome/browser/chromeos/system_logs/single_log_file_log_source_unittest.cc
index f6d42c1a..1597e32 100644
--- a/chrome/browser/chromeos/system_logs/single_log_file_log_source_unittest.cc
+++ b/chrome/browser/chromeos/system_logs/single_log_file_log_source_unittest.cc
@@ -270,32 +270,6 @@
   EXPECT_EQ("Goodbye world\n", latest_response());
 }
 
-TEST_F(SingleLogFileLogSourceTest, Anonymize) {
-  InitializeSource(SingleLogFileLogSource::SupportedSource::kUiLatest);
-
-  EXPECT_TRUE(AppendToFile(base::FilePath("ui/ui.LATEST"),
-                           "My MAC address is: 11:22:33:44:55:66\n"));
-  FetchFromSource();
-
-  EXPECT_EQ(1, num_callback_calls());
-  EXPECT_EQ("My MAC address is: 11:22:33:00:00:01\n", latest_response());
-
-  // Suppose the write operation is not atomic, and the MAC address is written
-  // across two separate writes.
-  EXPECT_TRUE(AppendToFile(base::FilePath("ui/ui.LATEST"),
-                           "Your MAC address is: AB:88:C"));
-  FetchFromSource();
-
-  EXPECT_EQ(2, num_callback_calls());
-  EXPECT_EQ("", latest_response());
-
-  EXPECT_TRUE(AppendToFile(base::FilePath("ui/ui.LATEST"), "D:99:EF:77\n"));
-  FetchFromSource();
-
-  EXPECT_EQ(3, num_callback_calls());
-  EXPECT_EQ("Your MAC address is: ab:88:cd:00:00:02\n", latest_response());
-}
-
 TEST_F(SingleLogFileLogSourceTest, HandleLogFileRotation) {
   InitializeSource(SingleLogFileLogSource::SupportedSource::kMessages);
 
diff --git a/chrome/browser/component_updater/cros_component_installer.cc b/chrome/browser/component_updater/cros_component_installer.cc
index 5c27da1..b519d4d 100644
--- a/chrome/browser/component_updater/cros_component_installer.cc
+++ b/chrome/browser/component_updater/cros_component_installer.cc
@@ -40,7 +40,11 @@
    {"star-cups-driver",                                                      \
     {{"env_version", "1.1"},                                                 \
      {"sha2hashstr",                                                         \
-      "6d24de30f671da5aee6d463d9e446cafe9ddac672800a9defe86877dcde6c466"}}}};
+      "6d24de30f671da5aee6d463d9e446cafe9ddac672800a9defe86877dcde6c466"}}}, \
+   {"cros-cellular",                                                         \
+    {{"env_version", "1.0"},                                                 \
+     {"sha2hashstr",                                                         \
+      "5714811c04f0a63aac96b39096faa759ace4c04e9b68291e7c9716128f5a2722"}}}};
 
 using content::BrowserThread;
 
diff --git a/chrome/browser/devtools/devtools_sanity_browsertest.cc b/chrome/browser/devtools/devtools_sanity_browsertest.cc
index e447142..6a09eb6 100644
--- a/chrome/browser/devtools/devtools_sanity_browsertest.cc
+++ b/chrome/browser/devtools/devtools_sanity_browsertest.cc
@@ -1838,9 +1838,8 @@
   CloseDevToolsWindow();
 }
 
-// Flaky on multiple platforms. See http://crbug.com/432444
 IN_PROC_BROWSER_TEST_F(WorkerDevToolsSanityTest,
-                       DISABLED_PauseInSharedWorkerInitialization) {
+                       PauseInSharedWorkerInitialization) {
   ASSERT_TRUE(spawned_test_server()->Start());
   GURL url = spawned_test_server()->GetURL(kReloadSharedWorkerTestPage);
   ui_test_utils::NavigateToURL(browser(), url);
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index d7c25a0..39599ce5 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -464,6 +464,11 @@
     "Enables the network service, which makes network requests through a "
     "separate service. Note: most features don't work with this yet.";
 
+const char kEnableNetworkServiceInProcessName[] =
+    "Runs network service in-process";
+const char kEnableNetworkServiceInProcessDescription[] =
+    "Runs the network service in the browser process.";
+
 const char kEnableNewPrintPreview[] = "Enable new Print Preview UI";
 const char kEnableNewPrintPreviewDescription[] =
     "If enabled, Print Preview will display a newer UI";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 6141903..61132b4 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -298,6 +298,9 @@
 extern const char kEnableNetworkServiceName[];
 extern const char kEnableNetworkServiceDescription[];
 
+extern const char kEnableNetworkServiceInProcessName[];
+extern const char kEnableNetworkServiceInProcessDescription[];
+
 extern const char kEnableNewPrintPreview[];
 extern const char kEnableNewPrintPreviewDescription[];
 
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index d144111c..e842932 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -34,7 +34,6 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/data_usage/tab_id_annotator.h"
 #include "chrome/browser/data_use_measurement/chrome_data_use_ascriber.h"
-#include "chrome/browser/net/chrome_mojo_proxy_resolver_factory.h"
 #include "chrome/browser/net/chrome_network_delegate.h"
 #include "chrome/browser/net/dns_probe_service.h"
 #include "chrome/browser/net/proxy_service_factory.h"
@@ -724,24 +723,10 @@
 
 void IOThread::SetUpProxyService(
     content::URLRequestContextBuilderMojo* builder) const {
-  const base::CommandLine& command_line =
-      *base::CommandLine::ForCurrentProcess();
-
-  // TODO(eroman): Figure out why this doesn't work in single-process mode.
-  // Should be possible now that a private isolate is used.
-  // http://crbug.com/474654
-  if (!command_line.HasSwitch(switches::kWinHttpProxyResolver)) {
-    if (command_line.HasSwitch(switches::kSingleProcess)) {
-      LOG(ERROR) << "Cannot use V8 Proxy resolver in single process mode.";
-    } else {
-      builder->SetMojoProxyResolverFactory(
-          ChromeMojoProxyResolverFactory::CreateWithStrongBinding());
 #if defined(OS_CHROMEOS)
-      builder->SetDhcpFetcherFactory(
-          base::MakeUnique<chromeos::DhcpProxyScriptFetcherFactoryChromeos>());
+  builder->SetDhcpFetcherFactory(
+      base::MakeUnique<chromeos::DhcpProxyScriptFetcherFactoryChromeos>());
 #endif
-    }
-  }
 
   builder->set_pac_quick_check_enabled(WpadQuickCheckEnabled());
   builder->set_pac_sanitize_url_policy(
diff --git a/chrome/browser/io_thread.h b/chrome/browser/io_thread.h
index 33e4ce8e..5144df5 100644
--- a/chrome/browser/io_thread.h
+++ b/chrome/browser/io_thread.h
@@ -35,8 +35,8 @@
 #include "net/base/network_change_notifier.h"
 #include "net/nqe/network_quality_estimator.h"
 
-class PrefService;
 class PrefRegistrySimple;
+class PrefService;
 class SystemNetworkContextManager;
 
 #if defined(OS_ANDROID)
@@ -210,8 +210,7 @@
   bool WpadQuickCheckEnabled() const;
   bool PacHttpsUrlStrippingEnabled() const;
 
-  // Configures |builder|'s ProxyService based on prefs, policies, and the
-  // command line.
+  // Configures |builder|'s ProxyService based on prefs and policies.
   void SetUpProxyService(content::URLRequestContextBuilderMojo* builder) const;
 
   // Gets a pointer to the NetworkService. Can only be called on the UI thread.
diff --git a/chrome/browser/io_thread_browsertest.cc b/chrome/browser/io_thread_browsertest.cc
index 29082fab..b4e8d4a 100644
--- a/chrome/browser/io_thread_browsertest.cc
+++ b/chrome/browser/io_thread_browsertest.cc
@@ -301,52 +301,4 @@
   connection_listener_->WaitForConnections();
 }
 
-class IOThreadBrowserTestWithPacFileURL : public IOThreadBrowserTest {
- public:
-  IOThreadBrowserTestWithPacFileURL() {
-    EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
-  }
-
-  ~IOThreadBrowserTestWithPacFileURL() override {}
-
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    base::FilePath pac_file_path;
-    ASSERT_TRUE(
-        base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &pac_file_path));
-
-    std::string pac_script = base::StringPrintf(
-        "function FindProxyForURL(url, host){ return 'PROXY %s;'; }",
-        net::HostPortPair::FromURL(embedded_test_server()->base_url())
-            .ToString()
-            .c_str());
-    ASSERT_EQ(
-        static_cast<int>(pac_script.size()),
-        base::WriteFile(pac_file_path, pac_script.c_str(), pac_script.size()));
-
-    command_line->AppendSwitchASCII(
-        switches::kProxyPacUrl, net::FilePathToFileURL(pac_file_path).spec());
-  }
-
- protected:
-  base::ScopedTempDir temp_dir_;
-};
-
-// Make sure the system URLRequestContext can hadle fetching PAC scripts from
-// file URLs.
-IN_PROC_BROWSER_TEST_F(IOThreadBrowserTestWithPacFileURL, FilePac) {
-  TestURLFetcherDelegate fetcher_delegate;
-  std::unique_ptr<net::URLFetcher> fetcher =
-      net::URLFetcher::Create(GURL("http://foo.test:12345/echoheader?Foo"),
-                              net::URLFetcher::GET, &fetcher_delegate);
-  fetcher->AddExtraRequestHeader("Foo: Bar");
-  fetcher->SetRequestContext(
-      g_browser_process->io_thread()->system_url_request_context_getter());
-  fetcher->Start();
-  fetcher_delegate.WaitForCompletion();
-  EXPECT_EQ(200, fetcher->GetResponseCode());
-  std::string response;
-  ASSERT_TRUE(fetcher->GetResponseAsString(&response));
-  EXPECT_EQ("Bar", response);
-}
-
 }  // namespace
diff --git a/chrome/browser/net/chrome_mojo_proxy_resolver_factory.cc b/chrome/browser/net/chrome_mojo_proxy_resolver_factory.cc
index afe11d0b..253ec38 100644
--- a/chrome/browser/net/chrome_mojo_proxy_resolver_factory.cc
+++ b/chrome/browser/net/chrome_mojo_proxy_resolver_factory.cc
@@ -14,23 +14,12 @@
 #include "content/public/common/service_manager_connection.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 
-namespace {
-
-void BindConnectorOnUIThread(service_manager::mojom::ConnectorRequest request) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  content::ServiceManagerConnection::GetForProcess()
-      ->GetConnector()
-      ->BindConnectorRequest(std::move(request));
-}
-
-}  // namespace
-
 ChromeMojoProxyResolverFactory::ChromeMojoProxyResolverFactory() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 }
 
 ChromeMojoProxyResolverFactory::~ChromeMojoProxyResolverFactory() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 }
 
 proxy_resolver::mojom::ProxyResolverFactoryPtr
@@ -45,34 +34,16 @@
     const std::string& pac_script,
     proxy_resolver::mojom::ProxyResolverRequest req,
     proxy_resolver::mojom::ProxyResolverFactoryRequestClientPtr client) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-
-  InitServiceManagerConnector();
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   // Bind a ProxyResolverFactory backed by the proxy resolver service, have it
   // create a ProxyResolverFactory and then destroy the factory, to avoid
   // keeping the service alive after all resolvers have been destroyed.
   proxy_resolver::mojom::ProxyResolverFactoryPtr resolver_factory;
-  service_manager_connector_->BindInterface(
-      proxy_resolver::mojom::kProxyResolverServiceName,
-      mojo::MakeRequest(&resolver_factory));
+  content::ServiceManagerConnection::GetForProcess()
+      ->GetConnector()
+      ->BindInterface(proxy_resolver::mojom::kProxyResolverServiceName,
+                      mojo::MakeRequest(&resolver_factory));
   resolver_factory->CreateResolver(pac_script, std::move(req),
                                    std::move(client));
 }
-
-void ChromeMojoProxyResolverFactory::InitServiceManagerConnector() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-
-  if (service_manager_connector_)
-    return;
-
-  // The existing ServiceManagerConnection retrieved with
-  // ServiceManagerConnection::GetForProcess() lives on the UI thread, so we
-  // can't access it from here. We create our own connector so it can be used
-  // right away and will bind it on the UI thread.
-  service_manager::mojom::ConnectorRequest request;
-  service_manager_connector_ = service_manager::Connector::Create(&request);
-  content::BrowserThread::PostTask(
-      content::BrowserThread::UI, FROM_HERE,
-      base::Bind(&BindConnectorOnUIThread, base::Passed(&request)));
-}
diff --git a/chrome/browser/net/chrome_mojo_proxy_resolver_factory.h b/chrome/browser/net/chrome_mojo_proxy_resolver_factory.h
index c3e21ab1..8e5199b 100644
--- a/chrome/browser/net/chrome_mojo_proxy_resolver_factory.h
+++ b/chrome/browser/net/chrome_mojo_proxy_resolver_factory.h
@@ -17,7 +17,7 @@
 // Starts the service as needed, and maintains no active mojo pipes to it,
 // so that it's automatically shut down as needed.
 //
-// ChromeMojoProxyResolverFactories must be created and used only on the IO
+// ChromeMojoProxyResolverFactories must be created and used only on the UI
 // thread.
 class ChromeMojoProxyResolverFactory
     : public proxy_resolver::mojom::ProxyResolverFactory {
@@ -38,9 +38,6 @@
       override;
 
  private:
-  // Initializes the ServiceManager's connector if it hasn't been already.
-  void InitServiceManagerConnector();
-
   std::unique_ptr<service_manager::Connector> service_manager_connector_;
 
   DISALLOW_COPY_AND_ASSIGN(ChromeMojoProxyResolverFactory);
diff --git a/chrome/browser/net/chrome_mojo_proxy_resolver_factory_browsertest.cc b/chrome/browser/net/chrome_mojo_proxy_resolver_factory_browsertest.cc
index 74a0833..2723a07 100644
--- a/chrome/browser/net/chrome_mojo_proxy_resolver_factory_browsertest.cc
+++ b/chrome/browser/net/chrome_mojo_proxy_resolver_factory_browsertest.cc
@@ -110,34 +110,6 @@
   DISALLOW_COPY_AND_ASSIGN(TestServiceManagerListener);
 };
 
-// Creates a ProxyResolverFactory on the IO thread that can then be used on the
-// UI thread.
-proxy_resolver::mojom::ProxyResolverFactoryPtr
-CreateResolverFactoryOnIOThread() {
-  base::RunLoop run_loop;
-  proxy_resolver::mojom::ProxyResolverFactoryPtrInfo resolver_factory_info;
-
-  content::BrowserThread::PostTaskAndReply(
-      content::BrowserThread::IO, FROM_HERE,
-      base::Bind(
-          [](mojo::InterfacePtrInfo<
-              proxy_resolver::mojom::ProxyResolverFactory>*
-                 resolver_factory_info) {
-            // Getting the InterfacePtr to an InterfacePtrInfo allows it to be
-            // passed to another thread.
-            *resolver_factory_info =
-                ChromeMojoProxyResolverFactory::CreateWithStrongBinding()
-                    .PassInterface();
-          },
-          &resolver_factory_info),
-      run_loop.QuitClosure());
-  run_loop.Run();
-
-  proxy_resolver::mojom::ProxyResolverFactoryPtr resolver_factory;
-  resolver_factory.Bind(std::move(resolver_factory_info));
-  return resolver_factory;
-}
-
 // Dummy consumer of a ProxyResolverFactory. It just calls CreateResolver, and
 // keeps Mojo objects alive from when CreateResolver() is called until it's
 // destroyed.
@@ -206,7 +178,7 @@
                        ServiceLifecycle) {
   // Set up the ProxyResolverFactory.
   proxy_resolver::mojom::ProxyResolverFactoryPtr resolver_factory =
-      CreateResolverFactoryOnIOThread();
+      ChromeMojoProxyResolverFactory::CreateWithStrongBinding();
 
   // Create a resolver, this should create and start the service.
   std::unique_ptr<DumbProxyResolverFactoryRequestClient> resolver_client1 =
@@ -246,7 +218,7 @@
                        DestroyFactory) {
   // Set up the ProxyResolverFactory.
   proxy_resolver::mojom::ProxyResolverFactoryPtr resolver_factory =
-      CreateResolverFactoryOnIOThread();
+      ChromeMojoProxyResolverFactory::CreateWithStrongBinding();
 
   // Create a resolver, this should create and start the service.
   std::unique_ptr<DumbProxyResolverFactoryRequestClient> resolver_client1 =
@@ -288,7 +260,7 @@
                        DestroyAndCreateService) {
   // Set up the ProxyResolverFactory.
   proxy_resolver::mojom::ProxyResolverFactoryPtr resolver_factory =
-      CreateResolverFactoryOnIOThread();
+      ChromeMojoProxyResolverFactory::CreateWithStrongBinding();
 
   // Create a resolver, this should create and start the service.
   std::unique_ptr<DumbProxyResolverFactoryRequestClient> resolver_client =
diff --git a/chrome/browser/net/default_network_context_params.cc b/chrome/browser/net/default_network_context_params.cc
index 795f1875..fa76267f 100644
--- a/chrome/browser/net/default_network_context_params.cc
+++ b/chrome/browser/net/default_network_context_params.cc
@@ -6,17 +6,22 @@
 
 #include <string>
 
+#include "base/command_line.h"
 #include "base/feature_list.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/net/chrome_mojo_proxy_resolver_factory.h"
 #include "chrome/common/channel_info.h"
+#include "chrome/common/chrome_switches.h"
 #include "components/policy/core/common/policy_namespace.h"
 #include "components/policy/core/common/policy_service.h"
 #include "components/policy/policy_constants.h"
 #include "components/version_info/version_info.h"
 #include "content/public/common/content_features.h"
+#include "content/public/common/content_switches.h"
 #include "content/public/common/user_agent.h"
+#include "services/proxy_resolver/public/interfaces/proxy_resolver.mojom.h"
 
 content::mojom::NetworkContextParamsPtr CreateDefaultNetworkContextParams() {
   content::mojom::NetworkContextParamsPtr network_context_params =
@@ -34,6 +39,23 @@
   quic_user_agent_id.append(content::BuildOSCpuInfo());
   network_context_params->quic_user_agent_id = quic_user_agent_id;
 
+  const base::CommandLine& command_line =
+      *base::CommandLine::ForCurrentProcess();
+
+  // TODO(eroman): Figure out why this doesn't work in single-process mode,
+  // or if it does work, now.
+  // Should be possible now that a private isolate is used.
+  // http://crbug.com/474654
+  if (!command_line.HasSwitch(switches::kWinHttpProxyResolver)) {
+    if (command_line.HasSwitch(switches::kSingleProcess)) {
+      LOG(ERROR) << "Cannot use V8 Proxy resolver in single process mode.";
+    } else {
+      network_context_params->proxy_resolver_factory =
+          ChromeMojoProxyResolverFactory::CreateWithStrongBinding()
+              .PassInterface();
+    }
+  }
+
   bool http_09_on_non_default_ports_enabled = false;
   const base::Value* value =
       g_browser_process->policy_service()
diff --git a/chrome/browser/net/network_context_configuration_browsertest.cc b/chrome/browser/net/network_context_configuration_browsertest.cc
index 3ef47eea..02fbd773 100644
--- a/chrome/browser/net/network_context_configuration_browsertest.cc
+++ b/chrome/browser/net/network_context_configuration_browsertest.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/net/system_network_context_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "components/network_session_configurator/common/network_switches.h"
 #include "components/prefs/pref_service.h"
@@ -43,6 +44,9 @@
 #include "net/base/net_errors.h"
 #include "net/http/http_response_headers.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
+#include "net/test/spawned_test_server/spawned_test_server.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -119,6 +123,16 @@
     }
   }
 
+  // Returns, as a string, a PAC script that will use the EmbeddedTestServer as
+  // a proxy.
+  std::string GetPacScript() const {
+    return base::StringPrintf(
+        "function FindProxyForURL(url, host){ return 'PROXY %s;'; }",
+        net::HostPortPair::FromURL(embedded_test_server()->base_url())
+            .ToString()
+            .c_str());
+  }
+
   content::mojom::URLLoaderFactory* loader_factory() const {
     return loader_factory_;
   }
@@ -183,10 +197,34 @@
     }
   }
 
+  // Sends a request and expects it to be handled by embedded_test_server()
+  // acting as a proxy;
+  void TestProxyConfigured() {
+    std::unique_ptr<content::ResourceRequest> request =
+        std::make_unique<content::ResourceRequest>();
+    // This URL should be directed to the test server because of the proxy.
+    request->url = GURL("http://jabberwocky.test:1872/echo");
+
+    content::SimpleURLLoaderTestHelper simple_loader_helper;
+    std::unique_ptr<content::SimpleURLLoader> simple_loader =
+        content::SimpleURLLoader::Create(std::move(request),
+                                         TRAFFIC_ANNOTATION_FOR_TESTS);
+
+    simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
+        loader_factory(), simple_loader_helper.GetCallback());
+    simple_loader_helper.WaitForCallback();
+
+    EXPECT_EQ(net::OK, simple_loader->NetError());
+    ASSERT_TRUE(simple_loader_helper.response_body());
+    EXPECT_EQ(*simple_loader_helper.response_body(), "Echo");
+  }
+
  private:
   content::mojom::NetworkContext* network_context_ = nullptr;
   content::mojom::URLLoaderFactory* loader_factory_ = nullptr;
   base::test::ScopedFeatureList feature_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(NetworkContextConfigurationBrowserTest);
 };
 
 IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, BasicRequest) {
@@ -381,24 +419,7 @@
 
 IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, ProxyConfig) {
   SetProxyPref(embedded_test_server()->host_port_pair());
-
-  std::unique_ptr<content::ResourceRequest> request =
-      std::make_unique<content::ResourceRequest>();
-  // This URL should be directed to the test server because of the proxy.
-  request->url = GURL("http://jabberwocky.com:1872/echo");
-
-  content::SimpleURLLoaderTestHelper simple_loader_helper;
-  std::unique_ptr<content::SimpleURLLoader> simple_loader =
-      content::SimpleURLLoader::Create(std::move(request),
-                                       TRAFFIC_ANNOTATION_FOR_TESTS);
-
-  simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
-      loader_factory(), simple_loader_helper.GetCallback());
-  simple_loader_helper.WaitForCallback();
-
-  EXPECT_EQ(net::OK, simple_loader->NetError());
-  ASSERT_TRUE(simple_loader_helper.response_body());
-  EXPECT_EQ(*simple_loader_helper.response_body(), "Echo");
+  TestProxyConfigured();
 }
 
 class NetworkContextConfigurationFixedPortBrowserTest
@@ -450,16 +471,147 @@
         switches::kProxyServer,
         embedded_test_server()->host_port_pair().ToString());
   }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NetworkContextConfigurationProxyOnStartBrowserTest);
 };
 
 // Test that when there's a proxy configuration at startup, the initial requests
 // use that configuration.
 IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationProxyOnStartBrowserTest,
                        TestInitialProxyConfig) {
+  TestProxyConfigured();
+}
+
+// Make sure the system URLRequestContext can handle fetching PAC scripts from
+// http URLs.
+class NetworkContextConfigurationHttpPacBrowserTest
+    : public NetworkContextConfigurationBrowserTest {
+ public:
+  NetworkContextConfigurationHttpPacBrowserTest()
+      : pac_test_server_(net::test_server::EmbeddedTestServer::TYPE_HTTP) {}
+
+  ~NetworkContextConfigurationHttpPacBrowserTest() override {}
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    pac_test_server_.RegisterRequestHandler(base::Bind(
+        &NetworkContextConfigurationHttpPacBrowserTest::HandlePacRequest,
+        GetPacScript()));
+    EXPECT_TRUE(pac_test_server_.Start());
+
+    command_line->AppendSwitchASCII(switches::kProxyPacUrl,
+                                    pac_test_server_.base_url().spec().c_str());
+  }
+
+  static std::unique_ptr<net::test_server::HttpResponse> HandlePacRequest(
+      const std::string& pac_script,
+      const net::test_server::HttpRequest& request) {
+    std::unique_ptr<net::test_server::BasicHttpResponse> response =
+        std::make_unique<net::test_server::BasicHttpResponse>();
+    response->set_content(pac_script);
+    return response;
+  }
+
+ private:
+  net::test_server::EmbeddedTestServer pac_test_server_;
+
+  DISALLOW_COPY_AND_ASSIGN(NetworkContextConfigurationHttpPacBrowserTest);
+};
+
+IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationHttpPacBrowserTest, HttpPac) {
+  TestProxyConfigured();
+}
+
+// Make sure the system URLRequestContext can handle fetching PAC scripts from
+// file URLs.
+class NetworkContextConfigurationFilePacBrowserTest
+    : public NetworkContextConfigurationBrowserTest {
+ public:
+  NetworkContextConfigurationFilePacBrowserTest() {}
+
+  ~NetworkContextConfigurationFilePacBrowserTest() override {}
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    const char kPacFileName[] = "foo.pac";
+
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    base::FilePath pac_file_path =
+        temp_dir_.GetPath().AppendASCII(kPacFileName);
+
+    std::string pac_script = GetPacScript();
+    ASSERT_EQ(
+        static_cast<int>(pac_script.size()),
+        base::WriteFile(pac_file_path, pac_script.c_str(), pac_script.size()));
+
+    command_line->AppendSwitchASCII(
+        switches::kProxyPacUrl, net::FilePathToFileURL(pac_file_path).spec());
+  }
+
+ private:
+  base::ScopedTempDir temp_dir_;
+
+  DISALLOW_COPY_AND_ASSIGN(NetworkContextConfigurationFilePacBrowserTest);
+};
+
+IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationFilePacBrowserTest, FilePac) {
+  TestProxyConfigured();
+}
+
+// Make sure the system URLRequestContext can handle fetching PAC scripts from
+// data URLs.
+class NetworkContextConfigurationDataPacBrowserTest
+    : public NetworkContextConfigurationBrowserTest {
+ public:
+  NetworkContextConfigurationDataPacBrowserTest() {}
+  ~NetworkContextConfigurationDataPacBrowserTest() override {}
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    std::string contents;
+    // Read in kPACScript contents.
+    command_line->AppendSwitchASCII(switches::kProxyPacUrl,
+                                    "data:," + GetPacScript());
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NetworkContextConfigurationDataPacBrowserTest);
+};
+
+IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationDataPacBrowserTest, DataPac) {
+  TestProxyConfigured();
+}
+
+// Make sure the system URLRequestContext can handle fetching PAC scripts from
+// ftp URLs. Unlike the other PAC tests, this test uses a PAC script that
+// results in an error, since the spawned test server is designed so that it can
+// run remotely (So can't just write a script to a local file and have the
+// server serve it).
+class NetworkContextConfigurationFtpPacBrowserTest
+    : public NetworkContextConfigurationBrowserTest {
+ public:
+  NetworkContextConfigurationFtpPacBrowserTest()
+      : ftp_server_(net::SpawnedTestServer::TYPE_FTP,
+                    base::FilePath(FILE_PATH_LITERAL("chrome/test/data"))) {
+    EXPECT_TRUE(ftp_server_.Start());
+  }
+  ~NetworkContextConfigurationFtpPacBrowserTest() override {}
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    command_line->AppendSwitchASCII(
+        switches::kProxyPacUrl,
+        ftp_server_.GetURL("bad_server.pac").spec().c_str());
+  }
+
+ private:
+  net::SpawnedTestServer ftp_server_;
+
+  DISALLOW_COPY_AND_ASSIGN(NetworkContextConfigurationFtpPacBrowserTest);
+};
+
+IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationFtpPacBrowserTest, FtpPac) {
   std::unique_ptr<content::ResourceRequest> request =
       std::make_unique<content::ResourceRequest>();
   // This URL should be directed to the test server because of the proxy.
-  request->url = GURL("http://jabberwocky.com:1872/echo");
+  request->url = GURL("http://jabberwocky.test:1872/echo");
 
   content::SimpleURLLoaderTestHelper simple_loader_helper;
   std::unique_ptr<content::SimpleURLLoader> simple_loader =
@@ -470,9 +622,7 @@
       loader_factory(), simple_loader_helper.GetCallback());
   simple_loader_helper.WaitForCallback();
 
-  EXPECT_EQ(net::OK, simple_loader->NetError());
-  ASSERT_TRUE(simple_loader_helper.response_body());
-  EXPECT_EQ(*simple_loader_helper.response_body(), "Echo");
+  EXPECT_EQ(net::ERR_PROXY_CONNECTION_FAILED, simple_loader->NetError());
 }
 
 // Instiates tests with a prefix indicating which NetworkContext is being
@@ -505,5 +655,13 @@
     NetworkContextConfigurationFixedPortBrowserTest);
 INSTANTIATE_TEST_CASES_FOR_TEST_FIXTURE(
     NetworkContextConfigurationProxyOnStartBrowserTest);
+INSTANTIATE_TEST_CASES_FOR_TEST_FIXTURE(
+    NetworkContextConfigurationHttpPacBrowserTest);
+INSTANTIATE_TEST_CASES_FOR_TEST_FIXTURE(
+    NetworkContextConfigurationFilePacBrowserTest);
+INSTANTIATE_TEST_CASES_FOR_TEST_FIXTURE(
+    NetworkContextConfigurationDataPacBrowserTest);
+INSTANTIATE_TEST_CASES_FOR_TEST_FIXTURE(
+    NetworkContextConfigurationFtpPacBrowserTest);
 
 }  // namespace
diff --git a/chrome/browser/net/proxy_browsertest.cc b/chrome/browser/net/proxy_browsertest.cc
index 3411515b..9d8b9fc 100644
--- a/chrome/browser/net/proxy_browsertest.cc
+++ b/chrome/browser/net/proxy_browsertest.cc
@@ -179,107 +179,6 @@
   VerifyProxyScript(browser());
 }
 
-// Fetch PAC script via a file:// URL.
-class FileProxyScriptBrowserTest : public InProcessBrowserTest {
- public:
-  FileProxyScriptBrowserTest() {}
-  ~FileProxyScriptBrowserTest() override {}
-
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    command_line->AppendSwitchASCII(switches::kProxyPacUrl,
-        ui_test_utils::GetTestUrl(
-            base::FilePath(base::FilePath::kCurrentDirectory),
-            base::FilePath(kPACScript)).spec());
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(FileProxyScriptBrowserTest);
-};
-
-IN_PROC_BROWSER_TEST_F(FileProxyScriptBrowserTest, Verify) {
-  VerifyProxyScript(browser());
-}
-
-// Fetch PAC script via an ftp:// URL.
-class FtpProxyScriptBrowserTest : public InProcessBrowserTest {
- public:
-  FtpProxyScriptBrowserTest()
-      : ftp_server_(net::SpawnedTestServer::TYPE_FTP,
-                    base::FilePath(FILE_PATH_LITERAL("chrome/test/data"))) {}
-  ~FtpProxyScriptBrowserTest() override {}
-
-  void SetUp() override {
-    ASSERT_TRUE(ftp_server_.Start());
-    InProcessBrowserTest::SetUp();
-  }
-
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    base::FilePath pac_script_path(kPACScript);
-    command_line->AppendSwitchASCII(
-        switches::kProxyPacUrl,
-        ftp_server_.GetURL(pac_script_path.MaybeAsASCII()).spec());
-  }
-
- private:
-  net::SpawnedTestServer ftp_server_;
-
-  DISALLOW_COPY_AND_ASSIGN(FtpProxyScriptBrowserTest);
-};
-
-IN_PROC_BROWSER_TEST_F(FtpProxyScriptBrowserTest, Verify) {
-  VerifyProxyScript(browser());
-}
-
-// Fetch PAC script via a data: URL.
-class DataProxyScriptBrowserTest : public InProcessBrowserTest {
- public:
-  DataProxyScriptBrowserTest() {}
-  ~DataProxyScriptBrowserTest() override {}
-
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    std::string contents;
-    // Read in kPACScript contents.
-    ASSERT_TRUE(base::ReadFileToString(ui_test_utils::GetTestFilePath(
-        base::FilePath(base::FilePath::kCurrentDirectory),
-        base::FilePath(kPACScript)),
-        &contents));
-    command_line->AppendSwitchASCII(switches::kProxyPacUrl,
-        std::string("data:,") + contents);
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(DataProxyScriptBrowserTest);
-};
-
-IN_PROC_BROWSER_TEST_F(DataProxyScriptBrowserTest, Verify) {
-  VerifyProxyScript(browser());
-}
-
-// Fetch PAC script via a data: URL.
-class OutOfProcessProxyResolverBrowserTest : public InProcessBrowserTest {
- public:
-  OutOfProcessProxyResolverBrowserTest() {}
-  ~OutOfProcessProxyResolverBrowserTest() override {}
-
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    std::string contents;
-    // Read in kPACScript contents.
-    ASSERT_TRUE(base::ReadFileToString(ui_test_utils::GetTestFilePath(
-        base::FilePath(base::FilePath::kCurrentDirectory),
-        base::FilePath(kPACScript)),
-        &contents));
-    command_line->AppendSwitchASCII(
-        switches::kProxyPacUrl, "data:," + contents);
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(OutOfProcessProxyResolverBrowserTest);
-};
-
-IN_PROC_BROWSER_TEST_F(OutOfProcessProxyResolverBrowserTest, Verify) {
-  VerifyProxyScript(browser());
-}
-
 // Fetch PAC script via a hanging http:// URL.
 class HangingPacRequestProxyScriptBrowserTest : public InProcessBrowserTest {
  public:
diff --git a/chrome/browser/printing/cloud_print/privet_http_impl.cc b/chrome/browser/printing/cloud_print/privet_http_impl.cc
index e8c7f0b..ae282e6 100644
--- a/chrome/browser/printing/cloud_print/privet_http_impl.cc
+++ b/chrome/browser/printing/cloud_print/privet_http_impl.cc
@@ -113,7 +113,7 @@
   return privet_client_;
 }
 
-void PrivetInfoOperationImpl::OnError(PrivetURLFetcher* fetcher,
+void PrivetInfoOperationImpl::OnError(int response_code,
                                       PrivetURLFetcher::ErrorType error) {
   callback_.Run(nullptr);
 }
@@ -173,14 +173,14 @@
   return privet_client_;
 }
 
-void PrivetRegisterOperationImpl::OnError(PrivetURLFetcher* fetcher,
+void PrivetRegisterOperationImpl::OnError(int response_code,
                                           PrivetURLFetcher::ErrorType error) {
   ongoing_ = false;
   int visible_http_code = -1;
   FailureReason reason = FAILURE_NETWORK;
 
   if (error == PrivetURLFetcher::RESPONSE_CODE_ERROR) {
-    visible_http_code = fetcher->response_code();
+    visible_http_code = response_code;
     reason = FAILURE_HTTP_ERROR;
   } else if (error == PrivetURLFetcher::JSON_PARSE_ERROR) {
     reason = FAILURE_MALFORMED_RESPONSE;
@@ -218,7 +218,6 @@
 }
 
 void PrivetRegisterOperationImpl::OnNeedPrivetToken(
-    PrivetURLFetcher* fetcher,
     const PrivetURLFetcher::TokenCallback& callback) {
   privet_client_->RefreshPrivetToken(callback);
 }
@@ -319,9 +318,8 @@
 }
 
 void PrivetRegisterOperationImpl::Cancelation::OnError(
-    PrivetURLFetcher* fetcher,
-    PrivetURLFetcher::ErrorType error) {
-}
+    int response_code,
+    PrivetURLFetcher::ErrorType error) {}
 
 void PrivetRegisterOperationImpl::Cancelation::OnParsedJson(
     PrivetURLFetcher* fetcher,
@@ -359,9 +357,8 @@
   return privet_client_;
 }
 
-void PrivetJSONOperationImpl::OnError(
-    PrivetURLFetcher* fetcher,
-    PrivetURLFetcher::ErrorType error) {
+void PrivetJSONOperationImpl::OnError(int response_code,
+                                      PrivetURLFetcher::ErrorType error) {
   callback_.Run(nullptr);
 }
 
@@ -372,7 +369,6 @@
 }
 
 void PrivetJSONOperationImpl::OnNeedPrivetToken(
-    PrivetURLFetcher* fetcher,
     const PrivetURLFetcher::TokenCallback& callback) {
   privet_client_->RefreshPrivetToken(callback);
 }
@@ -611,9 +607,8 @@
   return privet_client_;
 }
 
-void PrivetLocalPrintOperationImpl::OnError(
-    PrivetURLFetcher* fetcher,
-    PrivetURLFetcher::ErrorType error) {
+void PrivetLocalPrintOperationImpl::OnError(int response_code,
+                                            PrivetURLFetcher::ErrorType error) {
   delegate_->OnPrivetPrintingError(this, -1);
 }
 
@@ -626,7 +621,6 @@
 }
 
 void PrivetLocalPrintOperationImpl::OnNeedPrivetToken(
-    PrivetURLFetcher* fetcher,
     const PrivetURLFetcher::TokenCallback& callback) {
   privet_client_->RefreshPrivetToken(callback);
 }
diff --git a/chrome/browser/printing/cloud_print/privet_http_impl.h b/chrome/browser/printing/cloud_print/privet_http_impl.h
index 23011b9..d70977b 100644
--- a/chrome/browser/printing/cloud_print/privet_http_impl.h
+++ b/chrome/browser/printing/cloud_print/privet_http_impl.h
@@ -34,8 +34,7 @@
 
   PrivetHTTPClient* GetHTTPClient() override;
 
-  void OnError(PrivetURLFetcher* fetcher,
-               PrivetURLFetcher::ErrorType error) override;
+  void OnError(int response_code, PrivetURLFetcher::ErrorType error) override;
   void OnParsedJson(PrivetURLFetcher* fetcher,
                     const base::DictionaryValue& value,
                     bool has_error) override;
@@ -60,15 +59,13 @@
   void Cancel() override;
   void CompleteRegistration() override;
 
-  void OnError(PrivetURLFetcher* fetcher,
-               PrivetURLFetcher::ErrorType error) override;
+  void OnError(int response_code, PrivetURLFetcher::ErrorType error) override;
 
   void OnParsedJson(PrivetURLFetcher* fetcher,
                     const base::DictionaryValue& value,
                     bool has_error) override;
 
   void OnNeedPrivetToken(
-      PrivetURLFetcher* fetcher,
       const PrivetURLFetcher::TokenCallback& callback) override;
 
   PrivetHTTPClient* GetHTTPClient() override;
@@ -79,8 +76,7 @@
     Cancelation(PrivetHTTPClient* privet_client, const std::string& user);
     ~Cancelation() override;
 
-    void OnError(PrivetURLFetcher* fetcher,
-                 PrivetURLFetcher::ErrorType error) override;
+    void OnError(int response_code, PrivetURLFetcher::ErrorType error) override;
 
     void OnParsedJson(PrivetURLFetcher* fetcher,
                       const base::DictionaryValue& value,
@@ -131,13 +127,11 @@
 
   PrivetHTTPClient* GetHTTPClient() override;
 
-  void OnError(PrivetURLFetcher* fetcher,
-               PrivetURLFetcher::ErrorType error) override;
+  void OnError(int response_code, PrivetURLFetcher::ErrorType error) override;
   void OnParsedJson(PrivetURLFetcher* fetcher,
                     const base::DictionaryValue& value,
                     bool has_error) override;
   void OnNeedPrivetToken(
-      PrivetURLFetcher* fetcher,
       const PrivetURLFetcher::TokenCallback& callback) override;
 
  private:
@@ -172,13 +166,11 @@
   PrivetHTTPClient* GetHTTPClient() override;
 
   // PrivetURLFetcher::Delegate:
-  void OnError(PrivetURLFetcher* fetcher,
-               PrivetURLFetcher::ErrorType error) override;
+  void OnError(int response_code, PrivetURLFetcher::ErrorType error) override;
   void OnParsedJson(PrivetURLFetcher* fetcher,
                     const base::DictionaryValue& value,
                     bool has_error) override;
   void OnNeedPrivetToken(
-      PrivetURLFetcher* fetcher,
       const PrivetURLFetcher::TokenCallback& callback) override;
 
  private:
diff --git a/chrome/browser/printing/cloud_print/privet_http_unittest.cc b/chrome/browser/printing/cloud_print/privet_http_unittest.cc
index 233ae95..13f22abb 100644
--- a/chrome/browser/printing/cloud_print/privet_http_unittest.cc
+++ b/chrome/browser/printing/cloud_print/privet_http_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 #include <utility>
+#include <vector>
 
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
@@ -1056,13 +1057,11 @@
   }
 
   void OnNeedPrivetToken(
-      PrivetURLFetcher* fetcher,
       const PrivetURLFetcher::TokenCallback& callback) override {
     callback.Run("abc");
   }
 
-  void OnError(PrivetURLFetcher* fetcher,
-               PrivetURLFetcher::ErrorType error) override {
+  void OnError(int response_code, PrivetURLFetcher::ErrorType error) override {
     done_ = true;
     success_ = false;
     error_ = error;
@@ -1077,8 +1076,7 @@
     base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_);
   }
 
-  bool OnRawData(PrivetURLFetcher* fetcher,
-                 bool response_is_file,
+  bool OnRawData(bool response_is_file,
                  const std::string& data_string,
                  const base::FilePath& data_file) override {
     done_ = true;
diff --git a/chrome/browser/printing/cloud_print/privet_url_fetcher.cc b/chrome/browser/printing/cloud_print/privet_url_fetcher.cc
index 15a630d1..0b1de91 100644
--- a/chrome/browser/printing/cloud_print/privet_url_fetcher.cc
+++ b/chrome/browser/printing/cloud_print/privet_url_fetcher.cc
@@ -8,6 +8,7 @@
 
 #include <algorithm>
 #include <limits>
+#include <map>
 #include <memory>
 
 #include "base/bind.h"
@@ -58,13 +59,11 @@
 }  // namespace
 
 void PrivetURLFetcher::Delegate::OnNeedPrivetToken(
-    PrivetURLFetcher* fetcher,
     const TokenCallback& callback) {
-  OnError(fetcher, TOKEN_ERROR);
+  OnError(0, TOKEN_ERROR);
 }
 
-bool PrivetURLFetcher::Delegate::OnRawData(PrivetURLFetcher* fetcher,
-                                           bool response_is_file,
+bool PrivetURLFetcher::Delegate::OnRawData(bool response_is_file,
                                            const std::string& data_string,
                                            const base::FilePath& data_file) {
   return false;
@@ -191,16 +190,15 @@
 
     url_fetcher_->Start();
   } else {
-    delegate_->OnError(this, UNKNOWN_ERROR);
+    delegate_->OnError(0, UNKNOWN_ERROR);
   }
 }
 
 void PrivetURLFetcher::Start() {
   DCHECK_EQ(tries_, 0);  // We haven't called |Start()| yet.
 
-  if (!url_.is_valid()) {
-    return delegate_->OnError(this, UNKNOWN_ERROR);
-  }
+  if (!url_.is_valid())
+    return delegate_->OnError(0, UNKNOWN_ERROR);
 
   if (!send_empty_privet_token_) {
     std::string privet_access_token;
@@ -256,7 +254,7 @@
 bool PrivetURLFetcher::OnURLFetchCompleteDoNotParseData(
     const net::URLFetcher* source) {
   if (source->GetStatus().status() == net::URLRequestStatus::CANCELED) {
-    delegate_->OnError(this, REQUEST_CANCELED);
+    delegate_->OnError(0, REQUEST_CANCELED);
     return true;
   }
 
@@ -268,7 +266,7 @@
   if (source->GetResponseCode() != net::HTTP_OK &&
       source->GetResponseCode() != net::HTTP_PARTIAL_CONTENT &&
       source->GetResponseCode() != net::HTTP_BAD_REQUEST) {
-    delegate_->OnError(this, RESPONSE_CODE_ERROR);
+    delegate_->OnError(response_code(), RESPONSE_CODE_ERROR);
     return true;
   }
 
@@ -276,21 +274,20 @@
     base::FilePath response_file_path;
 
     if (!source->GetResponseAsFilePath(true, &response_file_path)) {
-      delegate_->OnError(this, UNKNOWN_ERROR);
+      delegate_->OnError(0, UNKNOWN_ERROR);
       return true;
     }
 
-    return delegate_->OnRawData(this, true, std::string(), response_file_path);
-  } else {
-    std::string response_str;
-
-    if (!source->GetResponseAsString(&response_str)) {
-      delegate_->OnError(this, UNKNOWN_ERROR);
-      return true;
-    }
-
-    return delegate_->OnRawData(this, false, response_str, base::FilePath());
+    return delegate_->OnRawData(true, std::string(), response_file_path);
   }
+
+  std::string response_str;
+  if (!source->GetResponseAsString(&response_str)) {
+    delegate_->OnError(0, UNKNOWN_ERROR);
+    return true;
+  }
+
+  return delegate_->OnRawData(false, response_str, base::FilePath());
 }
 
 void PrivetURLFetcher::OnURLFetchCompleteParseData(
@@ -298,27 +295,27 @@
   // Response contains error description.
   bool is_error_response = false;
   if (source->GetResponseCode() != net::HTTP_OK) {
-    delegate_->OnError(this, RESPONSE_CODE_ERROR);
+    delegate_->OnError(response_code(), RESPONSE_CODE_ERROR);
     return;
   }
 
   std::string response_str;
   if (!source->GetResponseAsString(&response_str)) {
-    delegate_->OnError(this, UNKNOWN_ERROR);
+    delegate_->OnError(0, UNKNOWN_ERROR);
     return;
   }
 
   base::JSONReader json_reader(base::JSON_ALLOW_TRAILING_COMMAS);
   std::unique_ptr<base::Value> value = json_reader.ReadToValue(response_str);
   if (!value) {
-    delegate_->OnError(this, JSON_PARSE_ERROR);
+    delegate_->OnError(0, JSON_PARSE_ERROR);
     return;
   }
 
   const base::DictionaryValue* dictionary_value = NULL;
 
   if (!value->GetAsDictionary(&dictionary_value)) {
-    delegate_->OnError(this, JSON_PARSE_ERROR);
+    delegate_->OnError(0, JSON_PARSE_ERROR);
     return;
   }
 
@@ -367,13 +364,12 @@
 
 void PrivetURLFetcher::RequestTokenRefresh() {
   delegate_->OnNeedPrivetToken(
-      this,
       base::Bind(&PrivetURLFetcher::RefreshToken, weak_factory_.GetWeakPtr()));
 }
 
 void PrivetURLFetcher::RefreshToken(const std::string& token) {
   if (token.empty()) {
-    delegate_->OnError(this, TOKEN_ERROR);
+    delegate_->OnError(0, TOKEN_ERROR);
   } else {
     SetTokenForHost(GetHostString(), token);
     Try();
diff --git a/chrome/browser/printing/cloud_print/privet_url_fetcher.h b/chrome/browser/printing/cloud_print/privet_url_fetcher.h
index 5c5816e4..4309d248 100644
--- a/chrome/browser/printing/cloud_print/privet_url_fetcher.h
+++ b/chrome/browser/printing/cloud_print/privet_url_fetcher.h
@@ -46,20 +46,18 @@
 
     // If you do not implement this method for PrivetV1 callers, you will always
     // get a TOKEN_ERROR error when your token is invalid.
-    virtual void OnNeedPrivetToken(
-        PrivetURLFetcher* fetcher,
-        const TokenCallback& callback);
+    virtual void OnNeedPrivetToken(const TokenCallback& callback);
 
-    virtual void OnError(PrivetURLFetcher* fetcher, ErrorType error) = 0;
+    // |response_code| is only needed for RESPONSE_CODE_ERROR.
+    virtual void OnError(int response_code, ErrorType error) = 0;
     virtual void OnParsedJson(PrivetURLFetcher* fetcher,
                               const base::DictionaryValue& value,
                               bool has_error) = 0;
 
     // If this method is returns true, the data will not be parsed as JSON, and
-    // |OnParsedJson| will not be called. Otherwise, |OnParsedJson| will be
+    // OnParsedJson() will not be called. Otherwise, OnParsedJson() will be
     // called.
-    virtual bool OnRawData(PrivetURLFetcher* fetcher,
-                           bool response_is_file,
+    virtual bool OnRawData(bool response_is_file,
                            const std::string& data_string,
                            const base::FilePath& data_file);
   };
@@ -87,11 +85,11 @@
 
   void SendEmptyPrivetToken();
 
-  // Set the contents of the Range header. |OnRawData| must return true if this
+  // Set the contents of the Range header. OnRawData() must return true if this
   // is called.
   void SetByteRange(int start, int end);
 
-  // Save the response to a file. |OnRawData| must return true if this is
+  // Save the response to a file. OnRawData() must return true if this is
   // called.
   void SaveResponseToFile();
 
diff --git a/chrome/browser/printing/cloud_print/privet_url_fetcher_unittest.cc b/chrome/browser/printing/cloud_print/privet_url_fetcher_unittest.cc
index 016fb20..1bc11ec 100644
--- a/chrome/browser/printing/cloud_print/privet_url_fetcher_unittest.cc
+++ b/chrome/browser/printing/cloud_print/privet_url_fetcher_unittest.cc
@@ -40,8 +40,7 @@
   ~MockPrivetURLFetcherDelegate() override {
   }
 
-  void OnError(PrivetURLFetcher* fetcher,
-               PrivetURLFetcher::ErrorType error) override {
+  void OnError(int response_code, PrivetURLFetcher::ErrorType error) override {
     OnErrorInternal(error);
   }
 
@@ -57,12 +56,10 @@
   MOCK_METHOD1(OnParsedJsonInternal, void(bool has_error));
 
   virtual void OnNeedPrivetToken(
-      PrivetURLFetcher* fetcher,
       const PrivetURLFetcher::TokenCallback& callback) {
   }
 
-  bool OnRawData(PrivetURLFetcher* fetcher,
-                 bool response_is_file,
+  bool OnRawData(bool response_is_file,
                  const std::string& data,
                  const base::FilePath& response_file) {
     if (!raw_mode_) return false;
@@ -130,7 +127,7 @@
 TEST_F(PrivetURLFetcherTest, FetchSuccess) {
   privet_urlfetcher_->Start();
   net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
-  ASSERT_TRUE(fetcher != NULL);
+  ASSERT_TRUE(fetcher);
   fetcher->SetResponseString(kSampleParsableJSON);
   fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::SUCCESS,
                                             net::OK));
@@ -141,7 +138,7 @@
 
   const base::DictionaryValue* value = delegate_.saved_value();
   int hello_value;
-  ASSERT_TRUE(value != NULL);
+  ASSERT_TRUE(value);
   ASSERT_TRUE(value->GetInteger("hello", &hello_value));
   EXPECT_EQ(2, hello_value);
 }
@@ -149,7 +146,7 @@
 TEST_F(PrivetURLFetcherTest, HTTP503Retry) {
   privet_urlfetcher_->Start();
   net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
-  ASSERT_TRUE(fetcher != NULL);
+  ASSERT_TRUE(fetcher);
   fetcher->SetResponseString(kSampleParsableJSON);
   fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::SUCCESS,
                                             net::OK));
@@ -160,7 +157,7 @@
   RunFor(base::TimeDelta::FromSeconds(7));
   fetcher = fetcher_factory_.GetFetcherByID(0);
 
-  ASSERT_TRUE(fetcher != NULL);
+  ASSERT_TRUE(fetcher);
   fetcher->SetResponseString(kSampleParsableJSON);
   fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::SUCCESS,
                                             net::OK));
@@ -173,7 +170,7 @@
 TEST_F(PrivetURLFetcherTest, ResponseCodeError) {
   privet_urlfetcher_->Start();
   net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
-  ASSERT_TRUE(fetcher != NULL);
+  ASSERT_TRUE(fetcher);
   fetcher->SetResponseString(kSampleParsableJSON);
   fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::SUCCESS,
                                             net::OK));
@@ -187,7 +184,7 @@
 TEST_F(PrivetURLFetcherTest, JsonParseError) {
   privet_urlfetcher_->Start();
   net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
-  ASSERT_TRUE(fetcher != NULL);
+  ASSERT_TRUE(fetcher);
   fetcher->SetResponseString(kSampleUnparsableJSON);
   fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::SUCCESS,
                                             net::OK));
@@ -201,7 +198,7 @@
 TEST_F(PrivetURLFetcherTest, Header) {
   privet_urlfetcher_->Start();
   net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
-  ASSERT_TRUE(fetcher != NULL);
+  ASSERT_TRUE(fetcher);
   net::HttpRequestHeaders headers;
   fetcher->GetExtraRequestHeaders(&headers);
 
@@ -218,7 +215,7 @@
   privet_urlfetcher_->Start();
 
   net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
-  ASSERT_TRUE(fetcher != NULL);
+  ASSERT_TRUE(fetcher);
   net::HttpRequestHeaders headers;
   fetcher->GetExtraRequestHeaders(&headers);
 
@@ -235,7 +232,7 @@
   privet_urlfetcher_->Start();
 
   net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
-  ASSERT_TRUE(fetcher != NULL);
+  ASSERT_TRUE(fetcher);
   net::HttpRequestHeaders headers;
   fetcher->GetExtraRequestHeaders(&headers);
 
@@ -247,7 +244,7 @@
 TEST_F(PrivetURLFetcherTest, FetchHasError) {
   privet_urlfetcher_->Start();
   net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
-  ASSERT_TRUE(fetcher != NULL);
+  ASSERT_TRUE(fetcher);
   fetcher->SetResponseString(kSampleJSONWithError);
   fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::SUCCESS,
                                             net::OK));
@@ -261,7 +258,7 @@
   delegate_.SetRawMode(true);
   privet_urlfetcher_->Start();
   net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
-  ASSERT_TRUE(fetcher != NULL);
+  ASSERT_TRUE(fetcher);
   fetcher->SetResponseString(kSampleJSONWithError);
   fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::SUCCESS,
                                             net::OK));
@@ -276,7 +273,7 @@
   privet_urlfetcher_->SetByteRange(200, 300);
   privet_urlfetcher_->Start();
   net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
-  ASSERT_TRUE(fetcher != NULL);
+  ASSERT_TRUE(fetcher);
   net::HttpRequestHeaders headers;
   fetcher->GetExtraRequestHeaders(&headers);
 
@@ -290,7 +287,7 @@
   privet_urlfetcher_->SaveResponseToFile();
   privet_urlfetcher_->Start();
   net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
-  ASSERT_TRUE(fetcher != NULL);
+  ASSERT_TRUE(fetcher);
   fetcher->SetResponseFilePath(
       base::FilePath(FILE_PATH_LITERAL("sample/file")));
   fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::SUCCESS,
diff --git a/chrome/browser/ui/search_engines/template_url_table_model.cc b/chrome/browser/ui/search_engines/template_url_table_model.cc
index d764a177..cb9726f0 100644
--- a/chrome/browser/ui/search_engines/template_url_table_model.cc
+++ b/chrome/browser/ui/search_engines/template_url_table_model.cc
@@ -16,11 +16,6 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/models/table_model_observer.h"
 
-// Group IDs used by TemplateURLTableModel.
-static const int kMainGroupID = 0;
-static const int kOtherGroupID = 1;
-static const int kExtensionGroupID = 2;
-
 TemplateURLTableModel::TemplateURLTableModel(
     TemplateURLService* template_url_service)
     : observer_(NULL), template_url_service_(template_url_service) {
@@ -96,41 +91,6 @@
   observer_ = observer;
 }
 
-bool TemplateURLTableModel::HasGroups() {
-  return true;
-}
-
-TemplateURLTableModel::Groups TemplateURLTableModel::GetGroups() {
-  Groups groups;
-
-  Group search_engine_group;
-  search_engine_group.title =
-      l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_EDITOR_MAIN_SEPARATOR);
-  search_engine_group.id = kMainGroupID;
-  groups.push_back(search_engine_group);
-
-  Group other_group;
-  other_group.title =
-      l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_EDITOR_OTHER_SEPARATOR);
-  other_group.id = kOtherGroupID;
-  groups.push_back(other_group);
-
-  Group extension_group;
-  extension_group.title =
-      l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_EDITOR_EXTENSIONS_SEPARATOR);
-  extension_group.id = kExtensionGroupID;
-  groups.push_back(extension_group);
-
-  return groups;
-}
-
-int TemplateURLTableModel::GetGroupID(int row) {
-  DCHECK(row >= 0 && row < RowCount());
-  if (row < last_search_engine_index_)
-    return kMainGroupID;
-  return row < last_other_engine_index_ ? kOtherGroupID : kExtensionGroupID;
-}
-
 void TemplateURLTableModel::Remove(int index) {
   // Remove the observer while we modify the model, that way we don't need to
   // worry about the model calling us back when we mutate it.
diff --git a/chrome/browser/ui/search_engines/template_url_table_model.h b/chrome/browser/ui/search_engines/template_url_table_model.h
index 1646f6c..354eeeb 100644
--- a/chrome/browser/ui/search_engines/template_url_table_model.h
+++ b/chrome/browser/ui/search_engines/template_url_table_model.h
@@ -44,9 +44,6 @@
   int RowCount() override;
   base::string16 GetText(int row, int column) override;
   void SetObserver(ui::TableModelObserver* observer) override;
-  bool HasGroups() override;
-  Groups GetGroups() override;
-  int GetGroupID(int row) override;
 
   // Removes the entry at the specified index.
   void Remove(int index);
diff --git a/chrome/browser/vr/elements/text.cc b/chrome/browser/vr/elements/text.cc
index ec70ddf..b5a610b 100644
--- a/chrome/browser/vr/elements/text.cc
+++ b/chrome/browser/vr/elements/text.cc
@@ -13,6 +13,10 @@
 #include "ui/gfx/geometry/vector2d.h"
 #include "ui/gfx/render_text.h"
 
+namespace {
+constexpr float kCursorWidthRatio = 0.07f;
+}
+
 namespace vr {
 
 class TextTexture : public UiTexture {
@@ -29,11 +33,20 @@
   }
 
   void SetMultiLine(bool multiline) { SetAndDirty(&multiline_, multiline); }
+  void SetCursorEnabled(bool enabled) {
+    SetAndDirty(&cursor_enabled_, enabled);
+  }
+
+  void SetCursorPosition(int position) {
+    SetAndDirty(&cursor_position_, position);
+  }
 
   void SetTextWidth(float width) { SetAndDirty(&text_width_, width); }
 
   gfx::SizeF GetDrawnSize() const override { return size_; }
 
+  gfx::Rect get_cursor_bounds() { return cursor_bounds_; }
+
   // This method does all text preparation for the element other than drawing to
   // the texture. This allows for deeper unit testing of the Text element
   // without having to mock canvases and simulate frame rendering. The state of
@@ -56,6 +69,9 @@
   TextAlignment alignment_ = kTextAlignmentCenter;
   bool multiline_ = true;
   SkColor color_ = SK_ColorBLACK;
+  bool cursor_enabled_ = false;
+  int cursor_position_ = 0;
+  gfx::Rect cursor_bounds_;
 
   DISALLOW_COPY_AND_ASSIGN(TextTexture);
 };
@@ -81,6 +97,25 @@
   texture_->SetMultiLine(multiline);
 }
 
+void Text::SetCursorEnabled(bool enabled) {
+  texture_->SetCursorEnabled(enabled);
+}
+
+void Text::SetCursorPosition(int position) {
+  texture_->SetCursorPosition(position);
+}
+
+gfx::RectF Text::GetCursorBounds() {
+  // Note that gfx:: cursor bounds always indicate a one-pixel width, so we
+  // override the width here to be a percentage of height for the sake of
+  // arbitrary texture sizes.
+  gfx::Rect bounds = texture_->get_cursor_bounds();
+  float scale = size().width() / texture_->GetDrawnSize().width();
+  return gfx::RectF(
+      bounds.CenterPoint().x() * scale, bounds.CenterPoint().y() * scale,
+      bounds.height() * scale * kCursorWidthRatio, bounds.height() * scale);
+}
+
 void Text::OnSetSize(gfx::SizeF size) {
   texture_->SetTextWidth(size.width());
 }
@@ -113,6 +148,13 @@
           text_, fonts, color_, &text_bounds, alignment_,
           multiline_ ? kWrappingBehaviorWrap : kWrappingBehaviorNoWrap);
 
+  if (cursor_enabled_) {
+    DCHECK(!multiline_);
+    lines.front()->SetCursorEnabled(true);
+    lines.front()->SetCursorPosition(cursor_position_);
+    cursor_bounds_ = lines.front()->GetUpdatedCursorBounds();
+  }
+
   // Note, there is no padding here whatsoever.
   size_ = gfx::SizeF(text_bounds.size());
 
diff --git a/chrome/browser/vr/elements/text.h b/chrome/browser/vr/elements/text.h
index 6eb63c42..43a9641 100644
--- a/chrome/browser/vr/elements/text.h
+++ b/chrome/browser/vr/elements/text.h
@@ -10,6 +10,7 @@
 #include "chrome/browser/vr/elements/textured_element.h"
 #include "chrome/browser/vr/elements/ui_texture.h"
 #include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkRect.h"
 
 namespace gfx {
 class RenderText;
@@ -30,6 +31,16 @@
   void SetTextAlignment(UiTexture::TextAlignment alignment);
   void SetMultiLine(bool multiline);
 
+  // This text element does not typically feature a cursor, but since the cursor
+  // position is deterined while laying out text, a parent may wish to supply
+  // cursor parameters and determine where the cursor was last drawn.
+  void SetCursorEnabled(bool enabled);
+  void SetCursorPosition(int position);
+
+  // Returns the most recently computed cursor position, in DMM, relative to the
+  // corner of the element.
+  gfx::RectF GetCursorBounds();
+
   void OnSetSize(gfx::SizeF size) override;
 
   std::vector<std::unique_ptr<gfx::RenderText>> LayOutTextForTest(
diff --git a/chrome/browser/vr/elements/text_input.cc b/chrome/browser/vr/elements/text_input.cc
index cbd93505..b110e7a 100644
--- a/chrome/browser/vr/elements/text_input.cc
+++ b/chrome/browser/vr/elements/text_input.cc
@@ -5,93 +5,59 @@
 #include "chrome/browser/vr/elements/text_input.h"
 
 #include "base/memory/ptr_util.h"
-#include "cc/paint/skia_paint_canvas.h"
+#include "chrome/browser/vr/elements/rect.h"
+#include "chrome/browser/vr/elements/text.h"
 #include "chrome/browser/vr/elements/ui_texture.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/font_list.h"
 #include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/rect_f.h"
-#include "ui/gfx/render_text.h"
+
+namespace {
+constexpr int kCursorBlinkHalfPeriodMs = 600;
+}
 
 namespace vr {
 
-class TextInputTexture : public UiTexture {
- public:
-  TextInputTexture(float font_height, float text_width)
-      : font_height_(font_height), text_width_(text_width) {}
-  ~TextInputTexture() override {}
-
-  void SetText(const base::string16& text) { SetAndDirty(&text_, text); }
-
-  void SetCursorPosition(int position) {
-    SetAndDirty(&cursor_position_, position);
-  }
-
-  void SetColor(SkColor color) { SetAndDirty(&color_, color); }
-
-  void SetCursorVisible(bool visible) {
-    SetAndDirty(&cursor_visible_, visible);
-  }
-
-  void Draw(SkCanvas* sk_canvas, const gfx::Size& texture_size) override {
-    cc::SkiaPaintCanvas paint_canvas(sk_canvas);
-    gfx::Canvas gfx_canvas(&paint_canvas, 1.0f);
-    gfx::Canvas* canvas = &gfx_canvas;
-
-    gfx::FontList font_list;
-    float pixels_per_meter = texture_size.width() / text_width_;
-    int pixel_font_height = static_cast<int>(font_height_ * pixels_per_meter);
-    GetDefaultFontList(pixel_font_height, text_, &font_list);
-    gfx::Rect text_bounds(texture_size.width(), pixel_font_height);
-    size_ = gfx::SizeF(text_bounds.size());
-
-    std::unique_ptr<gfx::RenderText> render_text(CreateRenderText());
-    render_text->SetText(text_);
-    render_text->SetFontList(font_list);
-    render_text->SetColor(color_);
-    render_text->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-    render_text->SetDisplayRect(text_bounds);
-    if (cursor_visible_) {
-      render_text->SetCursorEnabled(true);
-      render_text->SetCursorPosition(cursor_position_);
-    }
-    render_text->Draw(canvas);
-
-    if (cursor_visible_) {
-      auto bounds = render_text->GetUpdatedCursorBounds();
-      canvas->DrawRect(gfx::RectF(bounds), 0xFF000080);
-    }
-  }
-
- private:
-  gfx::Size GetPreferredTextureSize(int width) const override {
-    return gfx::Size(width, width * font_height_ / text_width_);
-  }
-
-  gfx::SizeF GetDrawnSize() const override { return size_; }
-
-  gfx::SizeF size_;
-  base::string16 text_;
-  int cursor_position_ = 0;
-  float font_height_;
-  float text_width_;
-  SkColor color_ = SK_ColorBLACK;
-  bool cursor_visible_ = false;
-
-  DISALLOW_COPY_AND_ASSIGN(TextInputTexture);
-};
-
 TextInput::TextInput(int maximum_width_pixels,
                      float font_height_meters,
-                     float text_width_meters,
                      OnFocusChangedCallback focus_changed_callback,
                      OnInputEditedCallback input_edit_callback)
-    : TexturedElement(maximum_width_pixels),
-      texture_(base::MakeUnique<TextInputTexture>(font_height_meters,
-                                                  text_width_meters)),
-      focus_changed_callback_(focus_changed_callback),
+    : focus_changed_callback_(focus_changed_callback),
       input_edit_callback_(input_edit_callback) {
-  SetSize(text_width_meters, font_height_meters);
+  auto text = base::MakeUnique<Text>(maximum_width_pixels, font_height_meters);
+  text->set_type(kTypeTextInputHint);
+  text->set_draw_phase(kPhaseForeground);
+  text->set_hit_testable(false);
+  text->set_x_anchoring(LEFT);
+  text->set_x_centering(LEFT);
+  text->SetSize(1, 1);
+  text->SetMultiLine(false);
+  text->SetTextAlignment(UiTexture::kTextAlignmentLeft);
+  hint_element_ = text.get();
+  this->AddChild(std::move(text));
+
+  text = base::MakeUnique<Text>(maximum_width_pixels, font_height_meters);
+  text->set_type(kTypeTextInputText);
+  text->set_draw_phase(kPhaseForeground);
+  text->set_hit_testable(false);
+  text->set_x_anchoring(LEFT);
+  text->set_x_centering(LEFT);
+  text->SetSize(1, 1);
+  text->SetMultiLine(false);
+  text->SetTextAlignment(UiTexture::kTextAlignmentLeft);
+  text->SetCursorEnabled(true);
+  text_element_ = text.get();
+  this->AddChild(std::move(text));
+
+  auto cursor = base::MakeUnique<Rect>();
+  cursor->set_type(kTypeTextInputCursor);
+  cursor->set_draw_phase(kPhaseForeground);
+  cursor->set_hit_testable(false);
+  cursor->set_x_anchoring(LEFT);
+  cursor->set_y_anchoring(BOTTOM);
+  cursor->SetColor(SK_ColorBLUE);
+  cursor_element_ = cursor.get();
+  text_element_->AddChild(std::move(cursor));
+
+  set_bounds_contain_children(true);
 }
 
 TextInput::~TextInput() {}
@@ -105,20 +71,28 @@
 }
 
 void TextInput::OnButtonUp(const gfx::PointF& position) {
+  RequestFocus();
+}
+
+void TextInput::OnFocusChanged(bool focused) {
+  focused_ = focused;
+
+  // Update the keyboard with the current text.
+  if (delegate_ && focused)
+    delegate_->UpdateInput(text_info_);
+
+  focus_changed_callback_.Run(focused);
+}
+
+void TextInput::RequestFocus() {
   if (!delegate_)
     return;
 
   delegate_->RequestFocus(id());
 }
 
-void TextInput::OnFocusChanged(bool focused) {
-  focused_ = focused;
-  texture_->SetCursorVisible(focused);
-  // Update the keyboard with the current text.
-  if (delegate_ && focused)
-    delegate_->UpdateInput(text_info_);
-
-  focus_changed_callback_.Run(focused);
+void TextInput::SetHintText(const base::string16& text) {
+  hint_element_->SetText(text);
 }
 
 void TextInput::OnInputEdited(const TextInputInfo& info) {
@@ -127,33 +101,61 @@
 
 void TextInput::OnInputCommitted(const TextInputInfo& info) {}
 
-void TextInput::SetColor(SkColor color) {
-  texture_->SetColor(color);
+void TextInput::SetTextColor(SkColor color) {
+  text_element_->SetColor(color);
+}
+
+void TextInput::SetCursorColor(SkColor color) {
+  cursor_element_->SetColor(color);
 }
 
 void TextInput::UpdateInput(const TextInputInfo& info) {
   if (text_info_ == info)
     return;
-
   text_info_ = info;
-  texture_->SetText(info.text);
-  texture_->SetCursorPosition(info.selection_end);
 
   if (delegate_ && focused_)
     delegate_->UpdateInput(info);
+
+  text_element_->SetText(info.text);
+  text_element_->SetCursorPosition(info.selection_end);
+  hint_element_->SetVisible(info.text.empty());
 }
 
 bool TextInput::OnBeginFrame(const base::TimeTicks& time,
                              const gfx::Vector3dF& look_at) {
-  base::TimeDelta delta = time - base::TimeTicks();
-  if (focused_)
-    texture_->SetCursorVisible(delta.InMilliseconds() / 500 % 2);
-
-  return false;
+  return SetCursorBlinkState(time);
 }
 
-UiTexture* TextInput::GetTexture() const {
-  return texture_.get();
+void TextInput::OnSetSize(gfx::SizeF size) {
+  hint_element_->SetSize(size.width(), size.height());
+  text_element_->SetSize(size.width(), size.height());
+}
+
+void TextInput::OnSetName() {
+  hint_element_->set_owner_name_for_test(name());
+  text_element_->set_owner_name_for_test(name());
+  cursor_element_->set_owner_name_for_test(name());
+}
+
+void TextInput::LayOutChildren() {
+  // To avoid re-rendering a texture when the cursor blinks, the texture is a
+  // separate element. Once the text has been laid out, we can position the
+  // cursor appropriately relative to the text field.
+  gfx::RectF bounds = text_element_->GetCursorBounds();
+  cursor_element_->SetTranslate(bounds.x(), bounds.y(), 0);
+  cursor_element_->SetSize(bounds.width(), bounds.height());
+}
+
+bool TextInput::SetCursorBlinkState(const base::TimeTicks& time) {
+  base::TimeDelta delta = time - base::TimeTicks();
+  bool visible =
+      focused_ && delta.InMilliseconds() / kCursorBlinkHalfPeriodMs % 2;
+  if (cursor_visible_ == visible)
+    return false;
+  cursor_visible_ = visible;
+  cursor_element_->SetVisible(visible);
+  return true;
 }
 
 }  // namespace vr
diff --git a/chrome/browser/vr/elements/text_input.h b/chrome/browser/vr/elements/text_input.h
index f998643..67d0bc6 100644
--- a/chrome/browser/vr/elements/text_input.h
+++ b/chrome/browser/vr/elements/text_input.h
@@ -5,9 +5,8 @@
 #ifndef CHROME_BROWSER_VR_ELEMENTS_TEXT_INPUT_H_
 #define CHROME_BROWSER_VR_ELEMENTS_TEXT_INPUT_H_
 
-#include <memory>
-
 #include "base/callback.h"
+#include "base/macros.h"
 #include "chrome/browser/vr/elements/textured_element.h"
 #include "chrome/browser/vr/elements/ui_texture.h"
 #include "chrome/browser/vr/model/text_input_info.h"
@@ -16,12 +15,10 @@
 
 namespace vr {
 
-class TextInputTexture;
+class Rect;
+class Text;
 
-// TODO(cjgrant): This class must be refactored to reuse Text and Rect elements
-// for the text and cursor. It exists as-is to facilitate initial integration of
-// the keyboard and omnibox.
-class TextInput : public TexturedElement {
+class TextInput : public UiElement {
  public:
   // Called when this element recieves focus.
   typedef base::RepeatingCallback<void(bool)> OnFocusChangedCallback;
@@ -30,7 +27,6 @@
       OnInputEditedCallback;
   TextInput(int maximum_width_pixels,
             float font_height_meters,
-            float text_width_meters,
             OnFocusChangedCallback focus_changed_callback,
             OnInputEditedCallback input_edit_callback);
   ~TextInput() override;
@@ -41,22 +37,33 @@
   void OnInputEdited(const TextInputInfo& info) override;
   void OnInputCommitted(const TextInputInfo& info) override;
 
-  void SetTextInputDelegate(TextInputDelegate* text_input_delegate);
-  void SetColor(SkColor color);
+  void RequestFocus();
   void UpdateInput(const TextInputInfo& info);
 
+  void SetHintText(const base::string16& text);
+  void SetTextColor(SkColor color);
+  void SetCursorColor(SkColor color);
+  void SetTextInputDelegate(TextInputDelegate* text_input_delegate);
+
   bool OnBeginFrame(const base::TimeTicks& time,
-                    const gfx::Vector3dF& look_at) override;
+                    const gfx::Vector3dF& look_at) final;
+  void OnSetSize(gfx::SizeF size) final;
+  void OnSetName() final;
 
  private:
-  UiTexture* GetTexture() const override;
+  void LayOutChildren() final;
+  bool SetCursorBlinkState(const base::TimeTicks& time);
 
-  std::unique_ptr<TextInputTexture> texture_;
   OnFocusChangedCallback focus_changed_callback_;
   OnInputEditedCallback input_edit_callback_;
   TextInputDelegate* delegate_ = nullptr;
   TextInputInfo text_info_;
   bool focused_ = false;
+  bool cursor_visible_ = false;
+
+  Text* hint_element_ = nullptr;
+  Text* text_element_ = nullptr;
+  Rect* cursor_element_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(TextInput);
 };
diff --git a/chrome/browser/vr/elements/ui_element_type.cc b/chrome/browser/vr/elements/ui_element_type.cc
index c2d209c..9d2fda7 100644
--- a/chrome/browser/vr/elements/ui_element_type.cc
+++ b/chrome/browser/vr/elements/ui_element_type.cc
@@ -24,6 +24,9 @@
     "kTypeOmniboxSuggestionIcon",
     "kTypeOmniboxSuggestionContentText",
     "kTypeOmniboxSuggestionDescriptionText",
+    "kTypeTextInputHint",
+    "kTypeTextInputText",
+    "kTypeTextInputCursor",
 };
 
 static_assert(
diff --git a/chrome/browser/vr/elements/ui_element_type.h b/chrome/browser/vr/elements/ui_element_type.h
index 1ecdd6d..627c410 100644
--- a/chrome/browser/vr/elements/ui_element_type.h
+++ b/chrome/browser/vr/elements/ui_element_type.h
@@ -24,6 +24,9 @@
   kTypeOmniboxSuggestionIcon,
   kTypeOmniboxSuggestionContentText,
   kTypeOmniboxSuggestionDescriptionText,
+  kTypeTextInputHint,
+  kTypeTextInputText,
+  kTypeTextInputCursor,
 
   // This must be last.
   kNumUiElementTypes,
diff --git a/chrome/browser/vr/model/color_scheme.cc b/chrome/browser/vr/model/color_scheme.cc
index 2474154f..c399653 100644
--- a/chrome/browser/vr/model/color_scheme.cc
+++ b/chrome/browser/vr/model/color_scheme.cc
@@ -116,6 +116,7 @@
   normal_scheme.omnibox_text = 0xFF595959;
   normal_scheme.omnibox_suggestion_content = 0xFF595959;
   normal_scheme.omnibox_suggestion_description = 0xFF5595FE;
+  normal_scheme.cursor = 0xFF5595FE;
 
   g_fullscreen_scheme.Get() = normal_scheme;
   ColorScheme& fullscreen_scheme = g_fullscreen_scheme.Get();
diff --git a/chrome/browser/vr/model/color_scheme.h b/chrome/browser/vr/model/color_scheme.h
index e094bc39..bda98a5 100644
--- a/chrome/browser/vr/model/color_scheme.h
+++ b/chrome/browser/vr/model/color_scheme.h
@@ -108,6 +108,8 @@
   SkColor omnibox_text;
   SkColor omnibox_suggestion_content;
   SkColor omnibox_suggestion_description;
+
+  SkColor cursor;
 };
 
 }  // namespace vr
diff --git a/chrome/browser/vr/testapp/vr_test_context.cc b/chrome/browser/vr/testapp/vr_test_context.cc
index d70b00c2..e0a0fa88 100644
--- a/chrome/browser/vr/testapp/vr_test_context.cc
+++ b/chrome/browser/vr/testapp/vr_test_context.cc
@@ -11,11 +11,13 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/vr/controller_mesh.h"
+#include "chrome/browser/vr/keyboard_delegate.h"
 #include "chrome/browser/vr/model/model.h"
 #include "chrome/browser/vr/model/omnibox_suggestions.h"
 #include "chrome/browser/vr/model/toolbar_state.h"
 #include "chrome/browser/vr/speech_recognizer.h"
 #include "chrome/browser/vr/test/constants.h"
+#include "chrome/browser/vr/text_input_delegate.h"
 #include "chrome/browser/vr/ui.h"
 #include "chrome/browser/vr/ui_element_renderer.h"
 #include "chrome/browser/vr/ui_input_manager.h"
@@ -56,6 +58,31 @@
 
 }  // namespace
 
+// This stub delegate does nothing today, but can be expanded to offer
+// legitimate keyboard support if required.
+class TestKeyboardDelegate : KeyboardDelegate {
+ public:
+  // KeyboardDelegate implemenation.
+  void ShowKeyboard() override {}
+  void HideKeyboard() override {}
+  void SetTransform(const gfx::Transform&) override {}
+  bool HitTest(const gfx::Point3F& ray_origin,
+               const gfx::Point3F& ray_target,
+               gfx::Point3F* hit_position) override {
+    return false;
+  }
+  void Draw(const CameraModel&) override {}
+
+  // Testapp-specific hooks.
+  void SetUiInterface(vr::KeyboardUiInterface* keyboard) {
+    keyboard_interface_ = keyboard;
+  }
+  void UpdateInput(const vr::TextInputInfo& info) {}
+
+ private:
+  vr::KeyboardUiInterface* keyboard_interface_ = nullptr;
+};
+
 VrTestContext::VrTestContext() : view_scale_factor_(kDefaultViewScaleFactor) {
   base::FilePath pak_path;
   PathService::Get(base::DIR_MODULE, &pak_path);
@@ -64,7 +91,19 @@
 
   base::i18n::InitializeICU();
 
-  ui_ = base::MakeUnique<Ui>(this, nullptr, nullptr, nullptr, UiInitialState());
+  text_input_delegate_ = base::MakeUnique<vr::TextInputDelegate>();
+  keyboard_delegate_ = base::MakeUnique<vr::TestKeyboardDelegate>();
+
+  ui_ = base::MakeUnique<Ui>(this, nullptr, nullptr, text_input_delegate_.get(),
+                             UiInitialState());
+
+  text_input_delegate_->SetRequestFocusCallback(
+      base::BindRepeating(&vr::Ui::RequestFocus, base::Unretained(ui_.get())));
+  text_input_delegate_->SetUpdateInputCallback(
+      base::BindRepeating(&TestKeyboardDelegate::UpdateInput,
+                          base::Unretained(keyboard_delegate_.get())));
+  keyboard_delegate_->SetUiInterface(ui_.get());
+
   model_ = ui_->model_for_test();
 
   ToolbarState state(GURL("https://dangerous.com/dir/file.html"),
@@ -107,8 +146,6 @@
   if (model_->web_vr_has_produced_frames()) {
     ui_->ui_renderer()->DrawWebVrOverlayForeground(render_info);
   }
-
-  // TODO(cjgrant): Render viewport-aware elements.
 }
 
 void VrTestContext::HandleInput(ui::Event* event) {
@@ -149,6 +186,10 @@
       case ui::DomCode::US_R:
         ui_->OnWebVrFrameAvailable();
         break;
+      case ui::DomCode::US_A: {
+        CreateFakeTextInput();
+        break;
+      }
       default:
         break;
     }
@@ -307,10 +348,24 @@
   return texture_id;
 }
 
+void VrTestContext::CreateFakeTextInput() {
+  // Every time this method is called, change the number of suggestions shown.
+  const std::string text =
+      "what is the actual meaning of life when considering all factors";
+
+  static int len = 0;
+  len = (len + 1) % text.size();
+
+  TextInputInfo info;
+  info.text = base::UTF8ToUTF16(text.substr(0, len));
+  info.selection_start = len;
+  info.selection_end = len;
+  ui_->OnInputEdited(info);
+}
+
 void VrTestContext::CreateFakeOmniboxSuggestions() {
   // Every time this method is called, change the number of suggestions shown.
   static int num_suggestions = 0;
-  num_suggestions = (num_suggestions + 1) % 4;
 
   auto result = base::MakeUnique<OmniboxSuggestions>();
   for (int i = 0; i < num_suggestions; i++) {
@@ -323,6 +378,9 @@
   }
   model_->omnibox_input_active = true;
   ui_->SetOmniboxSuggestions(std::move(result));
+
+  num_suggestions++;
+  num_suggestions %= 5;
 }
 
 void VrTestContext::CreateFakeVoiceSearchResult() {
diff --git a/chrome/browser/vr/testapp/vr_test_context.h b/chrome/browser/vr/testapp/vr_test_context.h
index e23d41b..3ae5024 100644
--- a/chrome/browser/vr/testapp/vr_test_context.h
+++ b/chrome/browser/vr/testapp/vr_test_context.h
@@ -20,6 +20,8 @@
 
 namespace vr {
 
+class TextInputDelegate;
+class TestKeyboardDelegate;
 class Ui;
 struct Model;
 
@@ -56,6 +58,7 @@
   unsigned int CreateFakeContentTexture();
   void CreateFakeOmniboxSuggestions();
   void CreateFakeVoiceSearchResult();
+  void CreateFakeTextInput();
   void CycleWebVrModes();
   void ToggleSplashScreen();
   gfx::Transform ProjectionMatrix() const;
@@ -86,6 +89,9 @@
 
   ControllerModel last_controller_model_;
 
+  std::unique_ptr<TextInputDelegate> text_input_delegate_;
+  std::unique_ptr<TestKeyboardDelegate> keyboard_delegate_;
+
   DISALLOW_COPY_AND_ASSIGN(VrTestContext);
 };
 
diff --git a/chrome/browser/vr/text_input_unittest.cc b/chrome/browser/vr/text_input_unittest.cc
index 094ad9b3..07db52c7 100644
--- a/chrome/browser/vr/text_input_unittest.cc
+++ b/chrome/browser/vr/text_input_unittest.cc
@@ -85,7 +85,7 @@
         base::MakeUnique<StrictMock<MockTextInputDelegate>>();
     text_input_info_ = base::MakeUnique<TextInputInfo>();
     auto text_input = UiSceneCreator::CreateTextInput(
-        512, 1, 1, model_, text_input_info_.get(), text_input_delegate_.get());
+        512, 1, model_, text_input_info_.get(), text_input_delegate_.get());
     text_input_ = text_input.get();
     scene_->AddUiElement(k2dBrowsingForeground, std::move(text_input));
     EXPECT_TRUE(OnBeginFrame());
diff --git a/chrome/browser/vr/ui_input_manager_unittest.cc b/chrome/browser/vr/ui_input_manager_unittest.cc
index 8c2bf22..c8ccd58d 100644
--- a/chrome/browser/vr/ui_input_manager_unittest.cc
+++ b/chrome/browser/vr/ui_input_manager_unittest.cc
@@ -57,7 +57,6 @@
   MockTextInput()
       : TextInput(512,
                   1,
-                  1,
                   base::RepeatingCallback<void(bool)>(),
                   base::RepeatingCallback<void(const TextInputInfo&)>()) {}
   ~MockTextInput() override = default;
diff --git a/chrome/browser/vr/ui_scene_creator.cc b/chrome/browser/vr/ui_scene_creator.cc
index ea269b53..518ca00 100644
--- a/chrome/browser/vr/ui_scene_creator.cc
+++ b/chrome/browser/vr/ui_scene_creator.cc
@@ -982,12 +982,11 @@
 std::unique_ptr<TextInput> UiSceneCreator::CreateTextInput(
     int maximum_width_pixels,
     float font_height_meters,
-    float text_width_meters,
     Model* model,
     TextInputInfo* text_input_model,
     TextInputDelegate* text_input_delegate) {
   auto text_input = base::MakeUnique<TextInput>(
-      maximum_width_pixels, font_height_meters, text_width_meters,
+      maximum_width_pixels, font_height_meters,
       base::BindRepeating(
           [](Model* model, bool focused) { model->editing_input = focused; },
           base::Unretained(model)),
@@ -996,9 +995,8 @@
             *model = text_input_info;
           },
           base::Unretained(text_input_model)));
-  text_input->set_draw_phase(kPhaseForeground);
+  text_input->set_draw_phase(kPhaseNone);
   text_input->SetTextInputDelegate(text_input_delegate);
-  text_input->set_hit_testable(true);
   text_input->AddBinding(base::MakeUnique<Binding<TextInputInfo>>(
       base::BindRepeating([](TextInputInfo* info) { return *info; },
                           base::Unretained(text_input_model)),
@@ -1121,7 +1119,7 @@
 
   float width = kOmniboxWidthDMM - 2 * kOmniboxTextMarginDMM;
   auto omnibox_text_field =
-      CreateTextInput(1024, kOmniboxTextHeightDMM, width, model_,
+      CreateTextInput(1024, kOmniboxTextHeightDMM, model_,
                       &model_->omnibox_text_field_info, text_input_delegate_);
   omnibox_text_field->AddBinding(
       VR_BIND(TextInputInfo, Model, model_, omnibox_text_field_info,
@@ -1131,6 +1129,21 @@
   omnibox_text_field->set_x_anchoring(LEFT);
   omnibox_text_field->set_x_centering(LEFT);
   omnibox_text_field->SetTranslate(kOmniboxTextMarginDMM, 0, 0);
+  omnibox_text_field->AddBinding(base::MakeUnique<Binding<bool>>(
+      base::BindRepeating([](Model* m) { return m->omnibox_input_active; },
+                          base::Unretained(model_)),
+      base::BindRepeating(
+          [](TextInput* e, const bool& v) {
+            if (v) {
+              e->RequestFocus();
+            }
+          },
+          base::Unretained(omnibox_text_field.get()))));
+  BindColor(model_, omnibox_text_field.get(), &ColorScheme::omnibox_text,
+            &TextInput::SetTextColor);
+  BindColor(model_, omnibox_text_field.get(), &ColorScheme::cursor,
+            &TextInput::SetCursorColor);
+
   scene_->AddUiElement(kOmniboxContainer, std::move(omnibox_text_field));
 
   auto close_button = Create<Button>(
diff --git a/chrome/browser/vr/ui_scene_creator.h b/chrome/browser/vr/ui_scene_creator.h
index e1762c5..de5dd7a1 100644
--- a/chrome/browser/vr/ui_scene_creator.h
+++ b/chrome/browser/vr/ui_scene_creator.h
@@ -33,7 +33,6 @@
   static std::unique_ptr<TextInput> CreateTextInput(
       int maximum_width_pixels,
       float font_height_meters,
-      float text_width_meters,
       Model* model,
       TextInputInfo* text_input_model,
       TextInputDelegate* text_input_delegate);
diff --git a/chrome/browser/vr/ui_unittest.cc b/chrome/browser/vr/ui_unittest.cc
index 3b5ed0c..7fd84f9 100644
--- a/chrome/browser/vr/ui_unittest.cc
+++ b/chrome/browser/vr/ui_unittest.cc
@@ -122,7 +122,9 @@
     "kAudioPermissionPromptShadow",
     "kAudioPermissionPrompt",
     "kOmniboxContainer",
-    "kOmniboxTextField",
+    "kOmniboxTextField:kTypeTextInputHint",
+    "kOmniboxTextField:kTypeTextInputText",
+    "kOmniboxTextField:kTypeTextInputCursor",
     "kOmniboxCloseButton",
     "kOmniboxCloseButton:kTypeButtonBackground",
     "kOmniboxCloseButton:kTypeButtonForeground",
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc
index d98360b..6bad5882 100644
--- a/components/autofill/core/browser/form_structure.cc
+++ b/components/autofill/core/browser/form_structure.cc
@@ -32,6 +32,8 @@
 #include "components/autofill/core/browser/rationalization_util.h"
 #include "components/autofill/core/browser/validation.h"
 #include "components/autofill/core/common/autofill_constants.h"
+#include "components/autofill/core/common/autofill_regex_constants.h"
+#include "components/autofill/core/common/autofill_regexes.h"
 #include "components/autofill/core/common/autofill_util.h"
 #include "components/autofill/core/common/form_data.h"
 #include "components/autofill/core/common/form_data_predictions.h"
@@ -645,10 +647,11 @@
     return false;
   }
 
-  // Rule out http(s)://*/search?...
-  //  e.g. http://www.google.com/search?q=...
-  //       http://search.yahoo.com/search?p=...
-  if (target_url_.path_piece() == "/search") {
+  // Rule out search forms.
+  static const base::string16 kUrlSearchActionPattern =
+      base::UTF8ToUTF16(kUrlSearchActionRe);
+  if (MatchesPattern(base::UTF8ToUTF16(target_url_.path_piece()),
+                     kUrlSearchActionPattern)) {
     return false;
   }
 
diff --git a/components/autofill/core/common/autofill_regex_constants.cc b/components/autofill/core/common/autofill_regex_constants.cc
index 2a3dbc1..014c096 100644
--- a/components/autofill/core/common/autofill_regex_constants.cc
+++ b/components/autofill/core/common/autofill_regex_constants.cc
@@ -297,6 +297,10 @@
 const char kPhoneExtensionRe[] =
     "\\bext|ext\\b|extension"
     "|ramal";  // pt-BR, pt-PT
+
+/////////////////////////////////////////////////////////////////////////////
+// validation.cc
+/////////////////////////////////////////////////////////////////////////////
 const char kUPIVirtualPaymentAddressRe[] =
     "^\\w+@("
     "allbank|"      // Allahabad Bank UPI
@@ -348,4 +352,9 @@
     "yesbank"       // NuPay
     ")$";
 
+/////////////////////////////////////////////////////////////////////////////
+// form_structure.cc
+/////////////////////////////////////////////////////////////////////////////
+const char kUrlSearchActionRe[] = "/search(/|((\\w*\\.\\w+)?$))";
+
 }  // namespace autofill
diff --git a/components/autofill/core/common/autofill_regex_constants.h b/components/autofill/core/common/autofill_regex_constants.h
index 8be7b2c..96de9e7a 100644
--- a/components/autofill/core/common/autofill_regex_constants.h
+++ b/components/autofill/core/common/autofill_regex_constants.h
@@ -62,6 +62,14 @@
 //   - https://upipayments.co.in/virtual-payment-address-vpa/
 extern const char kUPIVirtualPaymentAddressRe[];
 
+// Match the path values for form actions that look like generic search:
+//  e.g. /search
+//       /search/
+//       /search/products...
+//       /products/search/
+//       /blah/search_all.jsp
+extern const char kUrlSearchActionRe[];
+
 }  // namespace autofill
 
 #endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_REGEX_CONSTANTS_H_
diff --git a/components/exo/BUILD.gn b/components/exo/BUILD.gn
index 73388783..1a00d7a 100644
--- a/components/exo/BUILD.gn
+++ b/components/exo/BUILD.gn
@@ -127,6 +127,7 @@
   sources = [
     "../../ui/events/ozone/gamepad/gamepad_event.cc",
     "buffer_unittest.cc",
+    "client_controlled_shell_surface_unittest.cc",
     "data_device_unittest.cc",
     "data_offer_unittest.cc",
     "data_source_unittest.cc",
diff --git a/components/exo/client_controlled_shell_surface_unittest.cc b/components/exo/client_controlled_shell_surface_unittest.cc
new file mode 100644
index 0000000..2218686
--- /dev/null
+++ b/components/exo/client_controlled_shell_surface_unittest.cc
@@ -0,0 +1,483 @@
+// 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 "components/exo/client_controlled_shell_surface.h"
+
+#include "ash/public/cpp/window_properties.h"
+#include "ash/public/interfaces/window_pin_type.mojom.h"
+#include "ash/shell.h"
+#include "ash/shell_port.h"
+#include "ash/system/tray/system_tray.h"
+#include "ash/wm/tablet_mode/tablet_mode_controller.h"
+#include "ash/wm/window_positioning_utils.h"
+#include "ash/wm/window_state.h"
+#include "ash/wm/window_util.h"
+#include "components/exo/buffer.h"
+#include "components/exo/display.h"
+#include "components/exo/pointer.h"
+#include "components/exo/sub_surface.h"
+#include "components/exo/surface.h"
+#include "components/exo/test/exo_test_base.h"
+#include "components/exo/test/exo_test_helper.h"
+#include "components/exo/wm_helper.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/window.h"
+#include "ui/events/test/event_generator.h"
+#include "ui/views/widget/widget.h"
+#include "ui/wm/core/shadow.h"
+#include "ui/wm/core/shadow_controller.h"
+#include "ui/wm/core/shadow_types.h"
+
+namespace exo {
+namespace {
+using ClientControlledShellSurfaceTest = test::ExoTestBase;
+
+bool IsWidgetPinned(views::Widget* widget) {
+  ash::mojom::WindowPinType type =
+      widget->GetNativeWindow()->GetProperty(ash::kWindowPinTypeKey);
+  return type == ash::mojom::WindowPinType::PINNED ||
+         type == ash::mojom::WindowPinType::TRUSTED_PINNED;
+}
+
+wm::ShadowElevation GetShadowElevation(aura::Window* window) {
+  return window->GetProperty(wm::kShadowElevationKey);
+}
+
+}  // namespace
+
+TEST_F(ClientControlledShellSurfaceTest, SetPinned) {
+  gfx::Size buffer_size(256, 256);
+  std::unique_ptr<Buffer> buffer(
+      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+  std::unique_ptr<Surface> surface(new Surface);
+  auto shell_surface(
+      exo_test_helper()->CreateClientControlledShellSurface(surface.get()));
+
+  shell_surface->SetPinned(ash::mojom::WindowPinType::TRUSTED_PINNED);
+  EXPECT_TRUE(IsWidgetPinned(shell_surface->GetWidget()));
+
+  shell_surface->SetPinned(ash::mojom::WindowPinType::NONE);
+  EXPECT_FALSE(IsWidgetPinned(shell_surface->GetWidget()));
+
+  shell_surface->SetPinned(ash::mojom::WindowPinType::PINNED);
+  EXPECT_TRUE(IsWidgetPinned(shell_surface->GetWidget()));
+
+  shell_surface->SetPinned(ash::mojom::WindowPinType::NONE);
+  EXPECT_FALSE(IsWidgetPinned(shell_surface->GetWidget()));
+}
+
+TEST_F(ClientControlledShellSurfaceTest, SetSystemUiVisibility) {
+  gfx::Size buffer_size(256, 256);
+  std::unique_ptr<Buffer> buffer(
+      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+  std::unique_ptr<Surface> surface(new Surface);
+  auto shell_surface =
+      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+  surface->Attach(buffer.get());
+  surface->Commit();
+
+  shell_surface->SetSystemUiVisibility(true);
+  EXPECT_TRUE(
+      ash::wm::GetWindowState(shell_surface->GetWidget()->GetNativeWindow())
+          ->autohide_shelf_when_maximized_or_fullscreen());
+
+  shell_surface->SetSystemUiVisibility(false);
+  EXPECT_FALSE(
+      ash::wm::GetWindowState(shell_surface->GetWidget()->GetNativeWindow())
+          ->autohide_shelf_when_maximized_or_fullscreen());
+}
+
+TEST_F(ClientControlledShellSurfaceTest, SetTopInset) {
+  gfx::Size buffer_size(64, 64);
+  std::unique_ptr<Buffer> buffer(
+      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+  std::unique_ptr<Surface> surface(new Surface);
+  auto shell_surface =
+      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+
+  surface->Attach(buffer.get());
+  surface->Commit();
+
+  aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
+  ASSERT_TRUE(window);
+  EXPECT_EQ(0, window->GetProperty(aura::client::kTopViewInset));
+  int top_inset_height = 20;
+  shell_surface->SetTopInset(top_inset_height);
+  surface->Commit();
+  EXPECT_EQ(top_inset_height, window->GetProperty(aura::client::kTopViewInset));
+}
+
+TEST_F(ClientControlledShellSurfaceTest, ModalWindowDefaultActive) {
+  std::unique_ptr<Surface> surface(new Surface);
+  auto shell_surface =
+      exo_test_helper()->CreateClientControlledShellSurface(surface.get(),
+                                                            /*is_modal=*/true);
+
+  gfx::Size desktop_size(640, 480);
+  std::unique_ptr<Buffer> desktop_buffer(
+      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(desktop_size)));
+  surface->Attach(desktop_buffer.get());
+  surface->SetInputRegion(gfx::Rect(10, 10, 100, 100));
+  ASSERT_FALSE(shell_surface->GetWidget());
+  shell_surface->SetSystemModal(true);
+  surface->Commit();
+
+  EXPECT_TRUE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
+  EXPECT_TRUE(shell_surface->GetWidget()->IsActive());
+}
+
+TEST_F(ClientControlledShellSurfaceTest, UpdateModalWindow) {
+  std::unique_ptr<Surface> surface(new Surface);
+  auto shell_surface = exo_test_helper()->CreateClientControlledShellSurface(
+      surface.get(), /*is_modal=*/true);
+  gfx::Size desktop_size(640, 480);
+  std::unique_ptr<Buffer> desktop_buffer(
+      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(desktop_size)));
+  surface->Attach(desktop_buffer.get());
+  surface->SetInputRegion(cc::Region());
+  surface->Commit();
+
+  EXPECT_FALSE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
+  EXPECT_FALSE(shell_surface->GetWidget()->IsActive());
+
+  // Creating a surface without input region should not make it modal.
+  std::unique_ptr<Display> display(new Display);
+  std::unique_ptr<Surface> child = display->CreateSurface();
+  gfx::Size buffer_size(128, 128);
+  std::unique_ptr<Buffer> child_buffer(
+      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+  child->Attach(child_buffer.get());
+  std::unique_ptr<SubSurface> sub_surface(
+      display->CreateSubSurface(child.get(), surface.get()));
+  surface->SetSubSurfacePosition(child.get(), gfx::Point(10, 10));
+  child->Commit();
+  surface->Commit();
+  EXPECT_FALSE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
+  EXPECT_FALSE(shell_surface->GetWidget()->IsActive());
+
+  // Making the surface opaque shouldn't make it modal either.
+  child->SetBlendMode(SkBlendMode::kSrc);
+  child->Commit();
+  surface->Commit();
+  EXPECT_FALSE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
+  EXPECT_FALSE(shell_surface->GetWidget()->IsActive());
+
+  // Setting input regions won't make it modal either.
+  surface->SetInputRegion(gfx::Rect(10, 10, 100, 100));
+  surface->Commit();
+  EXPECT_FALSE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
+  EXPECT_FALSE(shell_surface->GetWidget()->IsActive());
+
+  // Only SetSystemModal changes modality.
+  shell_surface->SetSystemModal(true);
+
+  EXPECT_TRUE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
+  EXPECT_TRUE(shell_surface->GetWidget()->IsActive());
+
+  shell_surface->SetSystemModal(false);
+
+  EXPECT_FALSE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
+  EXPECT_FALSE(shell_surface->GetWidget()->IsActive());
+
+  // If the non modal system window was active,
+  shell_surface->GetWidget()->Activate();
+  EXPECT_TRUE(shell_surface->GetWidget()->IsActive());
+
+  shell_surface->SetSystemModal(true);
+  EXPECT_TRUE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
+  EXPECT_TRUE(shell_surface->GetWidget()->IsActive());
+
+  shell_surface->SetSystemModal(false);
+  EXPECT_FALSE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
+  EXPECT_TRUE(shell_surface->GetWidget()->IsActive());
+}
+
+TEST_F(ClientControlledShellSurfaceTest,
+       ModalWindowSetSystemModalBeforeCommit) {
+  std::unique_ptr<Surface> surface(new Surface);
+  auto shell_surface = exo_test_helper()->CreateClientControlledShellSurface(
+      surface.get(), /*is_modal=*/true);
+  gfx::Size desktop_size(640, 480);
+  std::unique_ptr<Buffer> desktop_buffer(
+      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(desktop_size)));
+  surface->Attach(desktop_buffer.get());
+  surface->SetInputRegion(cc::Region());
+
+  // Set SetSystemModal before any commit happens. Widget is not created at
+  // this time.
+  EXPECT_FALSE(shell_surface->GetWidget());
+  shell_surface->SetSystemModal(true);
+
+  surface->Commit();
+
+  // It is expected that modal window is shown.
+  EXPECT_TRUE(shell_surface->GetWidget());
+  EXPECT_TRUE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
+
+  // Now widget is created and setting modal state should be applied
+  // immediately.
+  shell_surface->SetSystemModal(false);
+  EXPECT_FALSE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
+}
+
+TEST_F(ClientControlledShellSurfaceTest, SurfaceShadow) {
+  gfx::Size buffer_size(128, 128);
+  std::unique_ptr<Buffer> buffer(
+      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+  std::unique_ptr<Surface> surface(new Surface);
+  auto shell_surface =
+      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+  surface->Attach(buffer.get());
+  surface->Commit();
+
+  aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
+
+  // 1) Initial state, no shadow.
+  wm::Shadow* shadow = wm::ShadowController::GetShadowForWindow(window);
+  ASSERT_TRUE(shadow);
+  EXPECT_FALSE(shadow->layer()->visible());
+
+  std::unique_ptr<Display> display(new Display);
+
+  // 2) Just creating a sub surface won't create a shadow.
+  std::unique_ptr<Surface> child = display->CreateSurface();
+  std::unique_ptr<Buffer> child_buffer(
+      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+  child->Attach(child_buffer.get());
+  std::unique_ptr<SubSurface> sub_surface(
+      display->CreateSubSurface(child.get(), surface.get()));
+  surface->Commit();
+
+  EXPECT_FALSE(shadow->layer()->visible());
+
+  // 3) Create a shadow.
+  shell_surface->SetShadowBounds(gfx::Rect(10, 10, 100, 100));
+  surface->Commit();
+  EXPECT_TRUE(shadow->layer()->visible());
+
+  gfx::Rect before = shadow->layer()->bounds();
+
+  // 4) Shadow bounds is independent of the sub surface.
+  gfx::Size new_buffer_size(256, 256);
+  std::unique_ptr<Buffer> new_child_buffer(
+      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(new_buffer_size)));
+  child->Attach(new_child_buffer.get());
+  child->Commit();
+  surface->Commit();
+
+  EXPECT_EQ(before, shadow->layer()->bounds());
+
+  // 4) Updating the widget's window bounds should not change the shadow bounds.
+  // TODO(oshima): The following scenario only worked with Xdg/ShellSurface,
+  // which never uses SetShadowBounds. This is broken with correct scenario, and
+  // will be fixed when the bounds control is delegated to the client.
+  //
+  // window->SetBounds(gfx::Rect(10, 10, 100, 100));
+  // EXPECT_EQ(before, shadow->layer()->bounds());
+
+  // 5) This should disable shadow.
+  shell_surface->SetShadowBounds(gfx::Rect());
+  surface->Commit();
+
+  EXPECT_EQ(wm::ShadowElevation::NONE, GetShadowElevation(window));
+  EXPECT_FALSE(shadow->layer()->visible());
+
+  // 6) This should enable non surface shadow again.
+  shell_surface->SetShadowBounds(gfx::Rect(10, 10, 100, 100));
+  surface->Commit();
+
+  EXPECT_EQ(wm::ShadowElevation::DEFAULT, GetShadowElevation(window));
+  EXPECT_TRUE(shadow->layer()->visible());
+}
+
+TEST_F(ClientControlledShellSurfaceTest, ShadowWithStateChange) {
+  gfx::Size buffer_size(64, 64);
+  std::unique_ptr<Buffer> buffer(
+      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+  std::unique_ptr<Surface> surface(new Surface);
+  auto shell_surface =
+      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+
+  // Postion the widget at 10,10 so that we get non zero offset.
+  const gfx::Size content_size(100, 100);
+  const gfx::Rect original_bounds(gfx::Point(10, 10), content_size);
+  shell_surface->SetGeometry(original_bounds);
+  surface->Attach(buffer.get());
+  surface->Commit();
+
+  // Placing a shadow at screen origin will make the shadow's origin (-10, -10).
+  const gfx::Rect shadow_bounds(content_size);
+
+  // Expected shadow position/bounds in parent coordinates.
+  const gfx::Point expected_shadow_origin(-10, -10);
+  const gfx::Rect expected_shadow_bounds(expected_shadow_origin, content_size);
+
+  views::Widget* widget = shell_surface->GetWidget();
+  aura::Window* window = widget->GetNativeWindow();
+  wm::Shadow* shadow = wm::ShadowController::GetShadowForWindow(window);
+
+  shell_surface->SetShadowBounds(shadow_bounds);
+  surface->Commit();
+  EXPECT_EQ(wm::ShadowElevation::DEFAULT, GetShadowElevation(window));
+
+  EXPECT_TRUE(shadow->layer()->visible());
+  // Origin must be in sync.
+  EXPECT_EQ(expected_shadow_origin, shadow->content_bounds().origin());
+
+  const gfx::Rect work_area =
+      display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
+  // Maximizing window hides the shadow.
+  widget->Maximize();
+  ASSERT_TRUE(widget->IsMaximized());
+  EXPECT_FALSE(shadow->layer()->visible());
+
+  shell_surface->SetShadowBounds(work_area);
+  surface->Commit();
+  EXPECT_FALSE(shadow->layer()->visible());
+
+  // Restoring bounds will re-enable shadow. It's content size is set to work
+  // area,/ thus not visible until new bounds is committed.
+  widget->Restore();
+  EXPECT_TRUE(shadow->layer()->visible());
+  const gfx::Rect shadow_in_maximized(expected_shadow_origin, work_area.size());
+  EXPECT_EQ(shadow_in_maximized, shadow->content_bounds());
+
+  // The bounds is updated.
+  shell_surface->SetShadowBounds(shadow_bounds);
+  surface->Commit();
+  EXPECT_EQ(expected_shadow_bounds, shadow->content_bounds());
+}
+
+TEST_F(ClientControlledShellSurfaceTest, ShadowWithTransform) {
+  gfx::Size buffer_size(64, 64);
+  std::unique_ptr<Buffer> buffer(
+      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+  std::unique_ptr<Surface> surface(new Surface);
+  auto shell_surface =
+      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+
+  // Postion the widget at 10,10 so that we get non zero offset.
+  const gfx::Size content_size(100, 100);
+  const gfx::Rect original_bounds(gfx::Point(10, 10), content_size);
+  shell_surface->SetGeometry(original_bounds);
+  surface->Attach(buffer.get());
+  surface->Commit();
+
+  aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
+  wm::Shadow* shadow = wm::ShadowController::GetShadowForWindow(window);
+
+  // Placing a shadow at screen origin will make the shadow's origin (-10, -10).
+  const gfx::Rect shadow_bounds(content_size);
+
+  // Shadow bounds relative to its parent should not be affected by a transform.
+  gfx::Transform transform;
+  transform.Translate(50, 50);
+  window->SetTransform(transform);
+  shell_surface->SetShadowBounds(shadow_bounds);
+  surface->Commit();
+  EXPECT_TRUE(shadow->layer()->visible());
+  EXPECT_EQ(gfx::Rect(-10, -10, 100, 100), shadow->content_bounds());
+}
+
+TEST_F(ClientControlledShellSurfaceTest, ShadowStartMaximized) {
+  std::unique_ptr<Surface> surface(new Surface);
+  auto shell_surface =
+      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+  shell_surface->Maximize();
+  views::Widget* widget = shell_surface->GetWidget();
+  aura::Window* window = widget->GetNativeWindow();
+
+  // There is no shadow when started in maximized state.
+  EXPECT_FALSE(wm::ShadowController::GetShadowForWindow(window));
+
+  // Sending a shadow bounds in maximized state won't create a shaodw.
+  shell_surface->SetShadowBounds(gfx::Rect(10, 10, 100, 100));
+  surface->Commit();
+  EXPECT_FALSE(wm::ShadowController::GetShadowForWindow(window));
+
+  // Restore the window and make sure the shadow is created, visible and
+  // has the latest bounds.
+  widget->Restore();
+  wm::Shadow* shadow = wm::ShadowController::GetShadowForWindow(window);
+  ASSERT_TRUE(shadow);
+  EXPECT_TRUE(shadow->layer()->visible());
+  EXPECT_EQ(gfx::Rect(10, 10, 100, 100), shadow->content_bounds());
+}
+
+TEST_F(ClientControlledShellSurfaceTest, CompositorLockInRotation) {
+  UpdateDisplay("800x600");
+  const gfx::Size buffer_size(800, 600);
+  std::unique_ptr<Buffer> buffer(
+      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+  std::unique_ptr<Surface> surface(new Surface);
+  auto shell_surface =
+      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+  ash::Shell* shell = ash::Shell::Get();
+  shell->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+
+  // Start in maximized.
+  shell_surface->Maximize();
+  surface->Attach(buffer.get());
+  surface->Commit();
+
+  gfx::Rect maximum_bounds =
+      display::Screen::GetScreen()->GetPrimaryDisplay().bounds();
+  shell_surface->SetGeometry(maximum_bounds);
+  shell_surface->SetOrientation(Orientation::LANDSCAPE);
+  surface->Commit();
+
+  ui::Compositor* compositor =
+      shell_surface->GetWidget()->GetNativeWindow()->layer()->GetCompositor();
+
+  EXPECT_FALSE(compositor->IsLocked());
+
+  UpdateDisplay("800x600/r");
+
+  EXPECT_TRUE(compositor->IsLocked());
+
+  shell_surface->SetOrientation(Orientation::PORTRAIT);
+  surface->Commit();
+
+  EXPECT_FALSE(compositor->IsLocked());
+}
+
+// If system tray is shown by click. It should be activated if user presses tab
+// key while shell surface is active.
+TEST_F(ClientControlledShellSurfaceTest, KeyboardNavigationWithSystemTray) {
+  const gfx::Size buffer_size(800, 600);
+  std::unique_ptr<Buffer> buffer(
+      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+  std::unique_ptr<Surface> surface(new Surface());
+  std::unique_ptr<ShellSurface> shell_surface =
+      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+
+  surface->Attach(buffer.get());
+  surface->Commit();
+
+  EXPECT_TRUE(shell_surface->GetWidget()->IsActive());
+
+  // Show system tray by perfoming a gesture tap at tray.
+  ash::SystemTray* system_tray = GetPrimarySystemTray();
+  ui::GestureEvent tap(0, 0, 0, base::TimeTicks(),
+                       ui::GestureEventDetails(ui::ET_GESTURE_TAP));
+  system_tray->PerformAction(tap);
+  ASSERT_TRUE(system_tray->GetWidget());
+
+  // Confirm that system tray is not active at this time.
+  EXPECT_TRUE(shell_surface->GetWidget()->IsActive());
+  EXPECT_FALSE(
+      system_tray->GetSystemBubble()->bubble_view()->GetWidget()->IsActive());
+
+  // Send tab key event.
+  ui::test::EventGenerator& event_generator = GetEventGenerator();
+  event_generator.PressKey(ui::VKEY_TAB, ui::EF_NONE);
+  event_generator.ReleaseKey(ui::VKEY_TAB, ui::EF_NONE);
+
+  // Confirm that system tray is activated.
+  EXPECT_FALSE(shell_surface->GetWidget()->IsActive());
+  EXPECT_TRUE(
+      system_tray->GetSystemBubble()->bubble_view()->GetWidget()->IsActive());
+}
+
+}  // namespace exo
diff --git a/components/exo/shell_surface_unittest.cc b/components/exo/shell_surface_unittest.cc
index 79c51c3..e32aca6a 100644
--- a/components/exo/shell_surface_unittest.cc
+++ b/components/exo/shell_surface_unittest.cc
@@ -6,13 +6,9 @@
 
 #include "ash/accessibility/accessibility_delegate.h"
 #include "ash/public/cpp/shell_window_ids.h"
-#include "ash/public/cpp/window_properties.h"
-#include "ash/public/interfaces/window_pin_type.mojom.h"
 #include "ash/shell.h"
 #include "ash/shell_port.h"
 #include "ash/shell_test_api.h"
-#include "ash/system/tray/system_tray.h"
-#include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/wm_event.h"
 #include "ash/wm/workspace/workspace_window_resizer.h"
@@ -29,7 +25,6 @@
 #include "components/exo/test/exo_test_helper.h"
 #include "components/exo/wm_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
 #include "ui/base/hit_test.h"
 #include "ui/compositor/compositor.h"
@@ -37,7 +32,6 @@
 #include "ui/display/display.h"
 #include "ui/display/manager/display_manager.h"
 #include "ui/display/screen.h"
-#include "ui/events/test/event_generator.h"
 #include "ui/views/widget/widget.h"
 #include "ui/wm/core/shadow.h"
 #include "ui/wm/core/shadow_controller.h"
@@ -59,17 +53,6 @@
   return serial;
 }
 
-wm::ShadowElevation GetShadowElevation(aura::Window* window) {
-  return window->GetProperty(wm::kShadowElevationKey);
-}
-
-bool IsWidgetPinned(views::Widget* widget) {
-  ash::mojom::WindowPinType type =
-      widget->GetNativeWindow()->GetProperty(ash::kWindowPinTypeKey);
-  return type == ash::mojom::WindowPinType::PINNED ||
-         type == ash::mojom::WindowPinType::TRUSTED_PINNED;
-}
-
 class ShellSurfaceBoundsModeTest
     : public ShellSurfaceTest,
       public testing::WithParamInterface<ShellSurface::BoundsMode> {
@@ -273,48 +256,6 @@
             shell_surface->GetWidget()->GetWindowBoundsInScreen().ToString());
 }
 
-TEST_F(ShellSurfaceTest, SetPinned) {
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface(
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get()));
-
-  shell_surface->SetPinned(ash::mojom::WindowPinType::TRUSTED_PINNED);
-  EXPECT_TRUE(IsWidgetPinned(shell_surface->GetWidget()));
-
-  shell_surface->SetPinned(ash::mojom::WindowPinType::NONE);
-  EXPECT_FALSE(IsWidgetPinned(shell_surface->GetWidget()));
-
-  shell_surface->SetPinned(ash::mojom::WindowPinType::PINNED);
-  EXPECT_TRUE(IsWidgetPinned(shell_surface->GetWidget()));
-
-  shell_surface->SetPinned(ash::mojom::WindowPinType::NONE);
-  EXPECT_FALSE(IsWidgetPinned(shell_surface->GetWidget()));
-}
-
-TEST_F(ShellSurfaceTest, SetSystemUiVisibility) {
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  surface->Attach(buffer.get());
-  surface->Commit();
-
-  shell_surface->SetSystemUiVisibility(true);
-  EXPECT_TRUE(
-      ash::wm::GetWindowState(shell_surface->GetWidget()->GetNativeWindow())
-          ->autohide_shelf_when_maximized_or_fullscreen());
-
-  shell_surface->SetSystemUiVisibility(false);
-  EXPECT_FALSE(
-      ash::wm::GetWindowState(shell_surface->GetWidget()->GetNativeWindow())
-          ->autohide_shelf_when_maximized_or_fullscreen());
-}
-
 TEST_F(ShellSurfaceTest, SetTitle) {
   std::unique_ptr<Surface> surface(new Surface);
   std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
@@ -487,26 +428,6 @@
       shell_surface->host_window()->layer()->GetTargetTransform().ToString());
 }
 
-TEST_F(ShellSurfaceTest, SetTopInset) {
-  gfx::Size buffer_size(64, 64);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  surface->Attach(buffer.get());
-  surface->Commit();
-
-  aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
-  ASSERT_TRUE(window);
-  EXPECT_EQ(0, window->GetProperty(aura::client::kTopViewInset));
-  int top_inset_height = 20;
-  shell_surface->SetTopInset(top_inset_height);
-  surface->Commit();
-  EXPECT_EQ(top_inset_height, window->GetProperty(aura::client::kTopViewInset));
-}
-
 void Close(int* close_call_count) {
   (*close_call_count)++;
 }
@@ -615,372 +536,6 @@
   EXPECT_TRUE(is_resizing);
 }
 
-TEST_F(ShellSurfaceTest, ModalWindowDefaultActive) {
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get(),
-                                                            /*is_modal=*/true);
-
-  gfx::Size desktop_size(640, 480);
-  std::unique_ptr<Buffer> desktop_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(desktop_size)));
-  surface->Attach(desktop_buffer.get());
-  surface->SetInputRegion(gfx::Rect(10, 10, 100, 100));
-  ASSERT_FALSE(shell_surface->GetWidget());
-  shell_surface->SetSystemModal(true);
-  surface->Commit();
-
-  EXPECT_TRUE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
-  EXPECT_TRUE(shell_surface->GetWidget()->IsActive());
-}
-
-TEST_F(ShellSurfaceTest, UpdateModalWindow) {
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface = exo_test_helper()->CreateClientControlledShellSurface(
-      surface.get(), /*is_modal=*/true);
-  gfx::Size desktop_size(640, 480);
-  std::unique_ptr<Buffer> desktop_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(desktop_size)));
-  surface->Attach(desktop_buffer.get());
-  surface->SetInputRegion(cc::Region());
-  surface->Commit();
-
-  EXPECT_FALSE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
-  EXPECT_FALSE(shell_surface->GetWidget()->IsActive());
-
-  // Creating a surface without input region should not make it modal.
-  std::unique_ptr<Display> display(new Display);
-  std::unique_ptr<Surface> child = display->CreateSurface();
-  gfx::Size buffer_size(128, 128);
-  std::unique_ptr<Buffer> child_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  child->Attach(child_buffer.get());
-  std::unique_ptr<SubSurface> sub_surface(
-      display->CreateSubSurface(child.get(), surface.get()));
-  surface->SetSubSurfacePosition(child.get(), gfx::Point(10, 10));
-  child->Commit();
-  surface->Commit();
-  EXPECT_FALSE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
-  EXPECT_FALSE(shell_surface->GetWidget()->IsActive());
-
-  // Making the surface opaque shouldn't make it modal either.
-  child->SetBlendMode(SkBlendMode::kSrc);
-  child->Commit();
-  surface->Commit();
-  EXPECT_FALSE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
-  EXPECT_FALSE(shell_surface->GetWidget()->IsActive());
-
-  // Setting input regions won't make it modal either.
-  surface->SetInputRegion(gfx::Rect(10, 10, 100, 100));
-  surface->Commit();
-  EXPECT_FALSE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
-  EXPECT_FALSE(shell_surface->GetWidget()->IsActive());
-
-  // Only SetSystemModal changes modality.
-  shell_surface->SetSystemModal(true);
-
-  EXPECT_TRUE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
-  EXPECT_TRUE(shell_surface->GetWidget()->IsActive());
-
-  shell_surface->SetSystemModal(false);
-
-  EXPECT_FALSE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
-  EXPECT_FALSE(shell_surface->GetWidget()->IsActive());
-
-  // If the non modal system window was active,
-  shell_surface->GetWidget()->Activate();
-  EXPECT_TRUE(shell_surface->GetWidget()->IsActive());
-
-  shell_surface->SetSystemModal(true);
-  EXPECT_TRUE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
-  EXPECT_TRUE(shell_surface->GetWidget()->IsActive());
-
-  shell_surface->SetSystemModal(false);
-  EXPECT_FALSE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
-  EXPECT_TRUE(shell_surface->GetWidget()->IsActive());
-}
-
-TEST_F(ShellSurfaceTest, ModalWindowSetSystemModalBeforeCommit) {
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface = exo_test_helper()->CreateClientControlledShellSurface(
-      surface.get(), /*is_modal=*/true);
-  gfx::Size desktop_size(640, 480);
-  std::unique_ptr<Buffer> desktop_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(desktop_size)));
-  surface->Attach(desktop_buffer.get());
-  surface->SetInputRegion(cc::Region());
-
-  // Set SetSystemModal before any commit happens. Widget is not created at
-  // this time.
-  EXPECT_FALSE(shell_surface->GetWidget());
-  shell_surface->SetSystemModal(true);
-
-  surface->Commit();
-
-  // It is expected that modal window is shown.
-  EXPECT_TRUE(shell_surface->GetWidget());
-  EXPECT_TRUE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
-
-  // Now widget is created and setting modal state should be applied
-  // immediately.
-  shell_surface->SetSystemModal(false);
-  EXPECT_FALSE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
-}
-
-TEST_F(ShellSurfaceTest, SurfaceShadow) {
-  gfx::Size buffer_size(128, 128);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  surface->Attach(buffer.get());
-  surface->Commit();
-
-  aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
-
-  // 1) Initial state, no shadow.
-  wm::Shadow* shadow = wm::ShadowController::GetShadowForWindow(window);
-  ASSERT_TRUE(shadow);
-  EXPECT_FALSE(shadow->layer()->visible());
-
-  std::unique_ptr<Display> display(new Display);
-
-  // 2) Just creating a sub surface won't create a shadow.
-  std::unique_ptr<Surface> child = display->CreateSurface();
-  std::unique_ptr<Buffer> child_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  child->Attach(child_buffer.get());
-  std::unique_ptr<SubSurface> sub_surface(
-      display->CreateSubSurface(child.get(), surface.get()));
-  surface->Commit();
-
-  EXPECT_FALSE(shadow->layer()->visible());
-
-  // 3) Create a shadow.
-  shell_surface->SetShadowBounds(gfx::Rect(10, 10, 100, 100));
-  surface->Commit();
-  EXPECT_TRUE(shadow->layer()->visible());
-
-  gfx::Rect before = shadow->layer()->bounds();
-
-  // 4) Shadow bounds is independent of the sub surface.
-  gfx::Size new_buffer_size(256, 256);
-  std::unique_ptr<Buffer> new_child_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(new_buffer_size)));
-  child->Attach(new_child_buffer.get());
-  child->Commit();
-  surface->Commit();
-
-  EXPECT_EQ(before, shadow->layer()->bounds());
-
-  // 4) Updating the widget's window bounds should not change the shadow bounds.
-  // TODO(oshima): The following scenario only worked with Xdg/ShellSurface,
-  // which never uses SetShadowBounds. This is broken with correct scenario, and
-  // will be fixed when the bounds control is delegated to the client.
-  //
-  // window->SetBounds(gfx::Rect(10, 10, 100, 100));
-  // EXPECT_EQ(before, shadow->layer()->bounds());
-
-  // 5) This should disable shadow.
-  shell_surface->SetShadowBounds(gfx::Rect());
-  surface->Commit();
-
-  EXPECT_EQ(wm::ShadowElevation::NONE, GetShadowElevation(window));
-  EXPECT_FALSE(shadow->layer()->visible());
-
-  // 6) This should enable non surface shadow again.
-  shell_surface->SetShadowBounds(gfx::Rect(10, 10, 100, 100));
-  surface->Commit();
-
-  EXPECT_EQ(wm::ShadowElevation::DEFAULT, GetShadowElevation(window));
-  EXPECT_TRUE(shadow->layer()->visible());
-}
-
-TEST_F(ShellSurfaceTest, NonSurfaceShadow) {
-  gfx::Size buffer_size(128, 128);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(
-      surface.get(), ShellSurface::BoundsMode::SHELL, gfx::Point(), true, false,
-      ash::kShellWindowId_DefaultContainer));
-  surface->Attach(buffer.get());
-  surface->Commit();
-
-  aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
-
-  // 1) Initial state, no shadow.
-  wm::Shadow* shadow = wm::ShadowController::GetShadowForWindow(window);
-  ASSERT_TRUE(shadow);
-  EXPECT_FALSE(shadow->layer()->visible());
-
-  std::unique_ptr<Display> display(new Display);
-
-  // 2) Just creating a sub surface won't create a shadow.
-  std::unique_ptr<Surface> child = display->CreateSurface();
-  std::unique_ptr<Buffer> child_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  child->Attach(child_buffer.get());
-  std::unique_ptr<SubSurface> sub_surface(
-      display->CreateSubSurface(child.get(), surface.get()));
-  surface->Commit();
-
-  EXPECT_FALSE(shadow->layer()->visible());
-
-  // 3) Enable a shadow.
-  shell_surface->OnSetFrame(SurfaceFrameType::SHADOW);
-  surface->Commit();
-  EXPECT_TRUE(shadow->layer()->visible());
-
-  gfx::Rect before = shadow->layer()->bounds();
-
-  // 4) Shadow bounds is independent of the sub surface.
-  gfx::Size new_buffer_size(256, 256);
-  std::unique_ptr<Buffer> new_child_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(new_buffer_size)));
-  child->Attach(new_child_buffer.get());
-  child->Commit();
-  surface->Commit();
-
-  EXPECT_EQ(before, shadow->layer()->bounds());
-
-  // 4) Updating the widget's window bounds should change the non surface shadow
-  // bounds.
-  const gfx::Rect new_bounds(50, 50, 100, 100);
-  window->SetBounds(new_bounds);
-  EXPECT_NE(before, shadow->layer()->bounds());
-  EXPECT_NE(new_bounds, shadow->layer()->bounds());
-
-  // 5) This should disable shadow.
-  surface->SetFrame(SurfaceFrameType::NONE);
-  surface->Commit();
-
-  EXPECT_EQ(wm::ShadowElevation::NONE, GetShadowElevation(window));
-  EXPECT_FALSE(shadow->layer()->visible());
-
-  // 6) This should enable non surface shadow.
-  surface->SetFrame(SurfaceFrameType::SHADOW);
-  surface->Commit();
-
-  EXPECT_EQ(wm::ShadowElevation::DEFAULT, GetShadowElevation(window));
-  EXPECT_TRUE(shadow->layer()->visible());
-}
-
-TEST_F(ShellSurfaceTest, ShadowWithStateChange) {
-  gfx::Size buffer_size(64, 64);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  // Postion the widget at 10,10 so that we get non zero offset.
-  const gfx::Size content_size(100, 100);
-  const gfx::Rect original_bounds(gfx::Point(10, 10), content_size);
-  shell_surface->SetGeometry(original_bounds);
-  surface->Attach(buffer.get());
-  surface->Commit();
-
-  // Placing a shadow at screen origin will make the shadow's origin (-10, -10).
-  const gfx::Rect shadow_bounds(content_size);
-
-  // Expected shadow position/bounds in parent coordinates.
-  const gfx::Point expected_shadow_origin(-10, -10);
-  const gfx::Rect expected_shadow_bounds(expected_shadow_origin, content_size);
-
-  views::Widget* widget = shell_surface->GetWidget();
-  aura::Window* window = widget->GetNativeWindow();
-  wm::Shadow* shadow = wm::ShadowController::GetShadowForWindow(window);
-
-  shell_surface->SetShadowBounds(shadow_bounds);
-  surface->Commit();
-  EXPECT_EQ(wm::ShadowElevation::DEFAULT, GetShadowElevation(window));
-
-  EXPECT_TRUE(shadow->layer()->visible());
-  // Origin must be in sync.
-  EXPECT_EQ(expected_shadow_origin, shadow->content_bounds().origin());
-
-  const gfx::Rect work_area =
-      display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
-  // Maximizing window hides the shadow.
-  widget->Maximize();
-  ASSERT_TRUE(widget->IsMaximized());
-  EXPECT_FALSE(shadow->layer()->visible());
-
-  shell_surface->SetShadowBounds(work_area);
-  surface->Commit();
-  EXPECT_FALSE(shadow->layer()->visible());
-
-  // Restoring bounds will re-enable shadow. It's content size is set to work
-  // area,/ thus not visible until new bounds is committed.
-  widget->Restore();
-  EXPECT_TRUE(shadow->layer()->visible());
-  const gfx::Rect shadow_in_maximized(expected_shadow_origin, work_area.size());
-  EXPECT_EQ(shadow_in_maximized, shadow->content_bounds());
-
-  // The bounds is updated.
-  shell_surface->SetShadowBounds(shadow_bounds);
-  surface->Commit();
-  EXPECT_EQ(expected_shadow_bounds, shadow->content_bounds());
-}
-
-TEST_F(ShellSurfaceTest, ShadowWithTransform) {
-  gfx::Size buffer_size(64, 64);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  // Postion the widget at 10,10 so that we get non zero offset.
-  const gfx::Size content_size(100, 100);
-  const gfx::Rect original_bounds(gfx::Point(10, 10), content_size);
-  shell_surface->SetGeometry(original_bounds);
-  surface->Attach(buffer.get());
-  surface->Commit();
-
-  aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
-  wm::Shadow* shadow = wm::ShadowController::GetShadowForWindow(window);
-
-  // Placing a shadow at screen origin will make the shadow's origin (-10, -10).
-  const gfx::Rect shadow_bounds(content_size);
-
-  // Shadow bounds relative to its parent should not be affected by a transform.
-  gfx::Transform transform;
-  transform.Translate(50, 50);
-  window->SetTransform(transform);
-  shell_surface->SetShadowBounds(shadow_bounds);
-  surface->Commit();
-  EXPECT_TRUE(shadow->layer()->visible());
-  EXPECT_EQ(gfx::Rect(-10, -10, 100, 100), shadow->content_bounds());
-}
-
-TEST_F(ShellSurfaceTest, ShadowStartMaximized) {
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  shell_surface->Maximize();
-  views::Widget* widget = shell_surface->GetWidget();
-  aura::Window* window = widget->GetNativeWindow();
-
-  // There is no shadow when started in maximized state.
-  EXPECT_FALSE(wm::ShadowController::GetShadowForWindow(window));
-
-  // Sending a shadow bounds in maximized state won't create a shaodw.
-  shell_surface->SetShadowBounds(gfx::Rect(10, 10, 100, 100));
-  surface->Commit();
-  EXPECT_FALSE(wm::ShadowController::GetShadowForWindow(window));
-
-  // Restore the window and make sure the shadow is created, visible and
-  // has the latest bounds.
-  widget->Restore();
-  wm::Shadow* shadow = wm::ShadowController::GetShadowForWindow(window);
-  ASSERT_TRUE(shadow);
-  EXPECT_TRUE(shadow->layer()->visible());
-  EXPECT_EQ(gfx::Rect(10, 10, 100, 100), shadow->content_bounds());
-}
-
 TEST_P(ShellSurfaceBoundsModeTest, ToggleFullscreen) {
   gfx::Size buffer_size(256, 256);
   std::unique_ptr<Buffer> buffer(
@@ -1028,80 +583,5 @@
   }
 }
 
-TEST_F(ShellSurfaceTest, CompositorLockInRotation) {
-  UpdateDisplay("800x600");
-  const gfx::Size buffer_size(800, 600);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  ash::Shell* shell = ash::Shell::Get();
-  shell->tablet_mode_controller()->EnableTabletModeWindowManager(true);
-
-  // Start in maximized.
-  shell_surface->Maximize();
-  surface->Attach(buffer.get());
-  surface->Commit();
-
-  gfx::Rect maximum_bounds =
-      display::Screen::GetScreen()->GetPrimaryDisplay().bounds();
-  shell_surface->SetGeometry(maximum_bounds);
-  shell_surface->SetOrientation(Orientation::LANDSCAPE);
-  surface->Commit();
-
-  ui::Compositor* compositor =
-      shell_surface->GetWidget()->GetNativeWindow()->layer()->GetCompositor();
-
-  EXPECT_FALSE(compositor->IsLocked());
-
-  UpdateDisplay("800x600/r");
-
-  EXPECT_TRUE(compositor->IsLocked());
-
-  shell_surface->SetOrientation(Orientation::PORTRAIT);
-  surface->Commit();
-
-  EXPECT_FALSE(compositor->IsLocked());
-}
-
-// If system tray is shown by click. It should be activated if user presses tab
-// key while shell surface is active.
-TEST_F(ShellSurfaceTest, KeyboardNavigationWithSystemTray) {
-  const gfx::Size buffer_size(800, 600);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface());
-  std::unique_ptr<ShellSurface> shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  surface->Attach(buffer.get());
-  surface->Commit();
-
-  EXPECT_TRUE(shell_surface->GetWidget()->IsActive());
-
-  // Show system tray by perfoming a gesture tap at tray.
-  ash::SystemTray* system_tray = GetPrimarySystemTray();
-  ui::GestureEvent tap(0, 0, 0, base::TimeTicks(),
-                       ui::GestureEventDetails(ui::ET_GESTURE_TAP));
-  system_tray->PerformAction(tap);
-  ASSERT_TRUE(system_tray->GetWidget());
-
-  // Confirm that system tray is not active at this time.
-  EXPECT_TRUE(shell_surface->GetWidget()->IsActive());
-  EXPECT_FALSE(
-      system_tray->GetSystemBubble()->bubble_view()->GetWidget()->IsActive());
-
-  // Send tab key event.
-  ui::test::EventGenerator& event_generator = GetEventGenerator();
-  event_generator.PressKey(ui::VKEY_TAB, ui::EF_NONE);
-  event_generator.ReleaseKey(ui::VKEY_TAB, ui::EF_NONE);
-
-  // Confirm that system tray is activated.
-  EXPECT_FALSE(shell_surface->GetWidget()->IsActive());
-  EXPECT_TRUE(
-      system_tray->GetSystemBubble()->bubble_view()->GetWidget()->IsActive());
-}
-
 }  // namespace
 }  // namespace exo
diff --git a/components/network_session_configurator/common/BUILD.gn b/components/network_session_configurator/common/BUILD.gn
index ba484f0..ca1a132 100644
--- a/components/network_session_configurator/common/BUILD.gn
+++ b/components/network_session_configurator/common/BUILD.gn
@@ -2,10 +2,12 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-static_library("common") {
+component("common") {
+  output_name = "network_session_configurator"
   sources = [
     "network_features.cc",
     "network_features.h",
+    "network_session_configurator_export.h",
     "network_switch_list.h",
     "network_switches.cc",
     "network_switches.h",
@@ -14,4 +16,6 @@
   public_deps = [
     "//base",
   ]
+
+  defines = [ "NETWORK_SESSION_CONFIGURATOR_IMPLEMENTATION" ]
 }
diff --git a/components/network_session_configurator/common/network_features.h b/components/network_session_configurator/common/network_features.h
index 1d6981d7..dbcc98c 100644
--- a/components/network_session_configurator/common/network_features.h
+++ b/components/network_session_configurator/common/network_features.h
@@ -6,12 +6,13 @@
 #define COMPONENTS_NETWORK_SESSION_CONFIGURATOR_COMMON_NETWORK_FEATURES_H_
 
 #include "base/feature_list.h"
+#include "network_session_configurator_export.h"
 
 namespace features {
 
 // Enables token binding
 // (https://www.ietf.org/id/draft-ietf-tokbind-protocol-04.txt).
-extern const base::Feature kTokenBinding;
+NETWORK_SESSION_CONFIGURATOR_EXPORT extern const base::Feature kTokenBinding;
 
 }  // namespace features
 
diff --git a/components/network_session_configurator/common/network_session_configurator_export.h b/components/network_session_configurator/common/network_session_configurator_export.h
new file mode 100644
index 0000000..d4a224d
--- /dev/null
+++ b/components/network_session_configurator/common/network_session_configurator_export.h
@@ -0,0 +1,35 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_NETWORK_SESSION_CONFIGURATOR_NETWORK_SESSION_CONFIGURATOR_EXPORT_H_
+#define COMPONENTS_NETWORK_SESSION_CONFIGURATOR_NETWORK_SESSION_CONFIGURATOR_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+
+#if defined(WIN32)
+
+#if defined(NETWORK_SESSION_CONFIGURATOR_IMPLEMENTATION)
+#define NETWORK_SESSION_CONFIGURATOR_EXPORT __declspec(dllexport)
+#else
+#define NETWORK_SESSION_CONFIGURATOR_EXPORT __declspec(dllimport)
+#endif  // defined(NETWORK_SESSION_CONFIGURATOR_IMPLEMENTATION)
+
+#else  // defined(WIN32)
+
+#if defined(NETWORK_SESSION_CONFIGURATOR_IMPLEMENTATION)
+#define NETWORK_SESSION_CONFIGURATOR_EXPORT \
+  __attribute__((visibility("default")))
+#else
+#define NETWORK_SESSION_CONFIGURATOR_EXPORT
+#endif  // defined(NETWORK_SESSION_CONFIGURATOR_IMPLEMENTATION)
+
+#endif  // defined(WIN32)
+
+#else  // defined(COMPONENT_BUILD)
+
+#define NETWORK_SESSION_CONFIGURATOR_EXPORT
+
+#endif  // defined(COMPONENT_BUILD)
+
+#endif  // COMPONENTS_NETWORK_SESSION_CONFIGURATOR_NETWORK_SESSION_CONFIGURATOR_EXPORT_H_
diff --git a/components/network_session_configurator/common/network_switches.h b/components/network_session_configurator/common/network_switches.h
index 7a511f5..ee5ea75 100644
--- a/components/network_session_configurator/common/network_switches.h
+++ b/components/network_session_configurator/common/network_switches.h
@@ -5,13 +5,16 @@
 #ifndef COMPONENTS_NETWORK_SESSION_CONFIGURATOR_COMMON_NETWORK_SWITCHES_H_
 #define COMPONENTS_NETWORK_SESSION_CONFIGURATOR_COMMON_NETWORK_SWITCHES_H_
 
+#include "network_session_configurator_export.h"
+
 namespace base {
 class CommandLine;
 }
 
 namespace switches {
 
-#define NETWORK_SWITCH(name, value) extern const char name[];
+#define NETWORK_SWITCH(name, value) \
+  NETWORK_SESSION_CONFIGURATOR_EXPORT extern const char name[];
 #include "components/network_session_configurator/common/network_switch_list.h"
 #undef NETWORK_SWITCH
 
@@ -21,8 +24,9 @@
 
 // Copies all command line switches the configurator handles from the |src|
 // CommandLine to the |dest| one.
-void CopyNetworkSwitches(const base::CommandLine& src_command_line,
-                         base::CommandLine* dest_command_line);
+NETWORK_SESSION_CONFIGURATOR_EXPORT void CopyNetworkSwitches(
+    const base::CommandLine& src_command_line,
+    base::CommandLine* dest_command_line);
 
 }  // namespace network_session_configurator
 
diff --git a/components/test/data/autofill/heuristics/output/018_checkout_ae.com.out b/components/test/data/autofill/heuristics/output/018_checkout_ae.com.out
index 8966f63..b1c804b7 100644
--- a/components/test/data/autofill/heuristics/output/018_checkout_ae.com.out
+++ b/components/test/data/autofill/heuristics/output/018_checkout_ae.com.out
@@ -3,10 +3,6 @@
 UNKNOWN_TYPE | zip | Find a store | Enter ZIP/Postal | zip_1-default
 UNKNOWN_TYPE | username | Access your wish list | Email | username_1-default
 UNKNOWN_TYPE | password | Password | Password | username_1-default
-NAME_FIRST | firstName | Search wish lists by name | First Name | firstName_1-default
-NAME_LAST | lastName | Last Name | Last Name | firstName_1-default
-EMAIL_ADDRESS | email | Or search wish lists by email | Email | firstName_1-default
-UNKNOWN_TYPE | /aeo/commerce/search/formhandlers/AEOQueryFormHandler.searchRequest.question | Keyword or Style # | Keyword or Style # | /aeo/commerce/search/formhandlers/AEOQueryFormHandler.searchRequest.question_1-default
 ADDRESS_HOME_COUNTRY | countryType | Country Type | usa | countryType_1-default
 ADDRESS_HOME_COUNTRY | country | Country, APO/FPO | US | countryType_1-default
 NAME_FIRST | firstName | First Name |  | countryType_1-default
diff --git a/components/test/data/autofill/heuristics/output/035_checkout_petco.com.out b/components/test/data/autofill/heuristics/output/035_checkout_petco.com.out
index c0cc80b..fa05429 100644
--- a/components/test/data/autofill/heuristics/output/035_checkout_petco.com.out
+++ b/components/test/data/autofill/heuristics/output/035_checkout_petco.com.out
@@ -1,5 +1,3 @@
-UNKNOWN_TYPE | zip | Your ZIP Code | Your ZIP Code | zip_1-default
-UNKNOWN_TYPE | Ntt | Search PETCO.com | Search PETCO.com | Ntt_1-default
 UNKNOWN_TYPE | txtEmail | Your Email Address | Your Email Address | txtEmail_1-default
 NAME_FIRST | ctl00$ctl00$cphBody$cphBody$txtSA_FirstName | First Name * |  | ctl00$ctl00$cphBody$cphBody$txtSA_FirstName_1-default
 NAME_LAST | ctl00$ctl00$cphBody$cphBody$txtSA_LastName | Last Name * |  | ctl00$ctl00$cphBody$cphBody$txtSA_FirstName_1-default
diff --git a/components/test/data/autofill/heuristics/output/036_checkout_petsmart.com.out b/components/test/data/autofill/heuristics/output/036_checkout_petsmart.com.out
index e3f9e226..1453706 100644
--- a/components/test/data/autofill/heuristics/output/036_checkout_petsmart.com.out
+++ b/components/test/data/autofill/heuristics/output/036_checkout_petsmart.com.out
@@ -1,4 +1,3 @@
-UNKNOWN_TYPE | kw | search petsmart.com | search petsmart.com | kw_1-default
 ADDRESS_HOME_COUNTRY | billCountry | • Country: | US | billCountry_1-default
 NAME_FIRST | billFname | • First Name: |  | billCountry_1-default
 NAME_LAST | billLname | • Last Name: |  | billCountry_1-default
diff --git a/components/test/data/autofill/heuristics/output/040_checkout_urbanoutfitters.com.out b/components/test/data/autofill/heuristics/output/040_checkout_urbanoutfitters.com.out
index 3baba2f..7a14a4d 100644
--- a/components/test/data/autofill/heuristics/output/040_checkout_urbanoutfitters.com.out
+++ b/components/test/data/autofill/heuristics/output/040_checkout_urbanoutfitters.com.out
@@ -1,4 +1,3 @@
-UNKNOWN_TYPE | searchPhrase |  |  | searchPhrase_1-default
 UNKNOWN_TYPE | shipto | Select a Saved Shipping Address |  | shipto_1-default
 NAME_FIRST | shippingFirstName | First Name | First Name | shipto_1-default
 NAME_LAST | shippingLastName | Last Name | Last Name | shipto_1-default
diff --git a/components/test/data/autofill/heuristics/output/042_checkout_williams-sonoma.com.out b/components/test/data/autofill/heuristics/output/042_checkout_williams-sonoma.com.out
index c4b9d08..617ef775 100644
--- a/components/test/data/autofill/heuristics/output/042_checkout_williams-sonoma.com.out
+++ b/components/test/data/autofill/heuristics/output/042_checkout_williams-sonoma.com.out
@@ -1,4 +1,3 @@
-UNKNOWN_TYPE | words | Search by keyword, recipe or item # | Enter keyword, recipe or item # | words_1-default
 NAME_FULL | shipTos[0].address.fullName | Full Name* |  | shipTos[0].address.fullName_1-default
 ADDRESS_HOME_LINE1 | shipTos[0].address.addrLine1 | Address* |  | shipTos[0].address.fullName_1-default
 ADDRESS_HOME_LINE2 | shipTos[0].address.addrLine2 | Address Line 2 |  | shipTos[0].address.fullName_1-default
diff --git a/components/test/data/autofill/heuristics/output/059_register_macys.com.out b/components/test/data/autofill/heuristics/output/059_register_macys.com.out
index 1608a64..142ad425 100644
--- a/components/test/data/autofill/heuristics/output/059_register_macys.com.out
+++ b/components/test/data/autofill/heuristics/output/059_register_macys.com.out
@@ -1,4 +1,3 @@
-UNKNOWN_TYPE | Keyword |  |  | Keyword_1-default
 NAME_FIRST | FirstName | First Name |  | FirstName_1-default
 NAME_LAST | LastName | Last Name |  | FirstName_1-default
 ADDRESS_HOME_LINE1 | Address1 | Address |  | FirstName_1-default
diff --git a/components/test/data/autofill/heuristics/output/060_register_mcphee.com.out b/components/test/data/autofill/heuristics/output/060_register_mcphee.com.out
index aa6ed3df..725c53f8 100644
--- a/components/test/data/autofill/heuristics/output/060_register_mcphee.com.out
+++ b/components/test/data/autofill/heuristics/output/060_register_mcphee.com.out
@@ -1,4 +1,3 @@
-UNKNOWN_TYPE | search_query | Search |  | search_query_1-default
 EMAIL_ADDRESS | FormField[1][1] | * Email Address: |  | FormField[1][1]_1-default
 UNKNOWN_TYPE | FormField[1][2] | * Password: |  | FormField[1][1]_1-default
 UNKNOWN_TYPE | FormField[1][3] | * Confirm Password: |  | FormField[1][1]_1-default
diff --git a/components/test/data/autofill/heuristics/output/061_register_myspace.com.out b/components/test/data/autofill/heuristics/output/061_register_myspace.com.out
index ec0fe34..6c22a7a 100644
--- a/components/test/data/autofill/heuristics/output/061_register_myspace.com.out
+++ b/components/test/data/autofill/heuristics/output/061_register_myspace.com.out
@@ -1,4 +1,3 @@
-UNKNOWN_TYPE | q | Search People |  | q_1-default
 UNKNOWN_TYPE | accountType | Personal | 2 | accountType_1-default
 UNKNOWN_TYPE | accountType | Musician | 7 | accountType_1-default
 UNKNOWN_TYPE | accountType | Comedian | 15 | accountType_1-default
diff --git a/components/test/data/autofill/heuristics/output/063_register_officedepot.com.out b/components/test/data/autofill/heuristics/output/063_register_officedepot.com.out
index 62fb696..a5c5a975 100644
--- a/components/test/data/autofill/heuristics/output/063_register_officedepot.com.out
+++ b/components/test/data/autofill/heuristics/output/063_register_officedepot.com.out
@@ -1,5 +1,4 @@
 UNKNOWN_TYPE | zip |  |  | zip_1-default
-UNKNOWN_TYPE | Ntt | Search |  | Ntt_1-default
 NAME_FIRST | addrsForm[0].firstName | *First Name: |  | addrsForm[0].firstName_1-default
 NAME_MIDDLE_INITIAL | addrsForm[0].middleInitial | Middle Initial: |  | addrsForm[0].firstName_1-default
 NAME_LAST | addrsForm[0].lastName | *Last Name: |  | addrsForm[0].firstName_1-default
diff --git a/components/test/data/autofill/heuristics/output/064_register_officemax.com.out b/components/test/data/autofill/heuristics/output/064_register_officemax.com.out
index 2264b5b..0630083 100644
--- a/components/test/data/autofill/heuristics/output/064_register_officemax.com.out
+++ b/components/test/data/autofill/heuristics/output/064_register_officemax.com.out
@@ -6,4 +6,3 @@
 ADDRESS_HOME_ZIP | /atg/userprofiling/ProfileFormHandler.value.zip | * Zip: |  | /atg/userprofiling/ProfileFormHandler.value.maxPerks_1-default
 UNKNOWN_TYPE | /atg/userprofiling/ProfileFormHandler.value.password | * Password: |  | /atg/userprofiling/ProfileFormHandler.value.maxPerks_1-default
 UNKNOWN_TYPE | /atg/userprofiling/ProfileFormHandler.value.confirmPassword | * Confirm Password: |  | /atg/userprofiling/ProfileFormHandler.value.maxPerks_1-default
-UNKNOWN_TYPE | freeText | Search by Keyword or Item # | Search by Keyword or Item # | freeText_1-default
diff --git a/components/test/data/autofill/heuristics/output/065_register_pyramidcollection.com.out b/components/test/data/autofill/heuristics/output/065_register_pyramidcollection.com.out
index 15ecbc5..262a4f0 100644
--- a/components/test/data/autofill/heuristics/output/065_register_pyramidcollection.com.out
+++ b/components/test/data/autofill/heuristics/output/065_register_pyramidcollection.com.out
@@ -1,4 +1,3 @@
-UNKNOWN_TYPE | q | search | enter keyword(s) or item number | q_1-default
 EMAIL_ADDRESS | E1 | Email Address * |  | E1_1-default
 NAME_FIRST | F1 | First Name * |  | E1_1-default
 NAME_LAST | L1 | Last Name * |  | E1_1-default
diff --git a/components/test/data/autofill/heuristics/output/071_register_sourceforge.net.out b/components/test/data/autofill/heuristics/output/071_register_sourceforge.net.out
index 285f7b1..4afcfce 100644
--- a/components/test/data/autofill/heuristics/output/071_register_sourceforge.net.out
+++ b/components/test/data/autofill/heuristics/output/071_register_sourceforge.net.out
@@ -1,4 +1,3 @@
-UNKNOWN_TYPE | q | Find Open Source Software |  | q_1-default
 NAME_FULL | X1mRVeMqejLnZpd1etxNGHllat2M | Name: |  | X1mRVeMqejLnZpd1etxNGHllat2M_1-default
 EMAIL_ADDRESS | X129ZdMbfixhIflk8_zHDFWB72qk | Email: |  | X1mRVeMqejLnZpd1etxNGHllat2M_1-default
 UNKNOWN_TYPE | X2n9HcN3dx1-mSbLywp_L-szMydw | Username: |  | X1mRVeMqejLnZpd1etxNGHllat2M_1-default
diff --git a/components/viz/common/gl_helper_benchmark.cc b/components/viz/common/gl_helper_benchmark.cc
index 410868e..2f77caf3 100644
--- a/components/viz/common/gl_helper_benchmark.cc
+++ b/components/viz/common/gl_helper_benchmark.cc
@@ -67,15 +67,17 @@
     attributes.gpu_preference = gl::PreferDiscreteGpu;
 
     context_ = gpu::GLInProcessContext::CreateWithoutInit();
-    auto result = context_->Initialize(nullptr,                 /* service */
-                                       nullptr,                 /* surface */
-                                       true,                    /* offscreen */
-                                       gpu::kNullSurfaceHandle, /* window */
-                                       nullptr, /* share_context */
-                                       attributes, gpu::SharedMemoryLimits(),
-                                       nullptr, /* gpu_memory_buffer_manager */
-                                       nullptr, /* image_factory */
-                                       base::ThreadTaskRunnerHandle::Get());
+    auto result =
+        context_->Initialize(nullptr,                 /* service */
+                             nullptr,                 /* surface */
+                             true,                    /* offscreen */
+                             gpu::kNullSurfaceHandle, /* window */
+                             nullptr,                 /* share_context */
+                             attributes, gpu::SharedMemoryLimits(),
+                             nullptr, /* gpu_memory_buffer_manager */
+                             nullptr, /* image_factory */
+                             nullptr /* gpu_channel_manager_delegate */,
+                             base::ThreadTaskRunnerHandle::Get());
     DCHECK_EQ(result, gpu::ContextResult::kSuccess);
     gl_ = context_->GetImplementation();
     gpu::ContextSupport* support = context_->GetImplementation();
diff --git a/components/viz/common/gl_helper_unittest.cc b/components/viz/common/gl_helper_unittest.cc
index ddcb914..6c184d1 100644
--- a/components/viz/common/gl_helper_unittest.cc
+++ b/components/viz/common/gl_helper_unittest.cc
@@ -61,15 +61,17 @@
     attributes.bind_generates_resource = false;
 
     context_ = gpu::GLInProcessContext::CreateWithoutInit();
-    auto result = context_->Initialize(nullptr,                 /* service */
-                                       nullptr,                 /* surface */
-                                       true,                    /* offscreen */
-                                       gpu::kNullSurfaceHandle, /* window */
-                                       nullptr, /* share_context */
-                                       attributes, gpu::SharedMemoryLimits(),
-                                       nullptr, /* gpu_memory_buffer_manager */
-                                       nullptr, /* image_factory */
-                                       base::ThreadTaskRunnerHandle::Get());
+    auto result =
+        context_->Initialize(nullptr,                 /* service */
+                             nullptr,                 /* surface */
+                             true,                    /* offscreen */
+                             gpu::kNullSurfaceHandle, /* window */
+                             nullptr,                 /* share_context */
+                             attributes, gpu::SharedMemoryLimits(),
+                             nullptr, /* gpu_memory_buffer_manager */
+                             nullptr, /* image_factory */
+                             nullptr /* gpu_channel_manager_delegate */,
+                             base::ThreadTaskRunnerHandle::Get());
     DCHECK_EQ(result, gpu::ContextResult::kSuccess);
     gl_ = context_->GetImplementation();
     gpu::ContextSupport* support = context_->GetImplementation();
diff --git a/components/viz/common/gpu/in_process_context_provider.cc b/components/viz/common/gpu/in_process_context_provider.cc
index 46c479fb..99a5619 100644
--- a/components/viz/common/gpu/in_process_context_provider.cc
+++ b/components/viz/common/gpu/in_process_context_provider.cc
@@ -54,6 +54,7 @@
     gpu::SurfaceHandle surface_handle,
     gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
     gpu::ImageFactory* image_factory,
+    gpu::GpuChannelManagerDelegate* gpu_channel_manager_delegate,
     const gpu::SharedMemoryLimits& limits,
     InProcessContextProvider* shared_context)
     : attributes_(CreateAttributes()),
@@ -68,6 +69,7 @@
           limits,
           gpu_memory_buffer_manager,
           image_factory,
+          gpu_channel_manager_delegate,
           base::ThreadTaskRunnerHandle::Get())),
       cache_controller_(std::make_unique<ContextCacheController>(
           context_->GetImplementation(),
diff --git a/components/viz/common/gpu/in_process_context_provider.h b/components/viz/common/gpu/in_process_context_provider.h
index eeef36d..da16824 100644
--- a/components/viz/common/gpu/in_process_context_provider.h
+++ b/components/viz/common/gpu/in_process_context_provider.h
@@ -22,6 +22,7 @@
 
 namespace gpu {
 class GLInProcessContext;
+class GpuChannelManagerDelegate;
 class GpuMemoryBufferManager;
 class ImageFactory;
 struct SharedMemoryLimits;
@@ -33,6 +34,10 @@
 
 namespace viz {
 
+// A ContextProvider used in the viz process to setup command buffers between
+// the compositor and gpu thread.
+// TODO(kylechar): Rename VizProcessContextProvider and move to
+// components/viz/service.
 class VIZ_COMMON_EXPORT InProcessContextProvider : public ContextProvider {
  public:
   InProcessContextProvider(
@@ -40,6 +45,7 @@
       gpu::SurfaceHandle surface_handle,
       gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
       gpu::ImageFactory* image_factory,
+      gpu::GpuChannelManagerDelegate* gpu_channel_manager_delegate,
       const gpu::SharedMemoryLimits& limits,
       InProcessContextProvider* shared_context);
 
diff --git a/components/viz/common/yuv_readback_unittest.cc b/components/viz/common/yuv_readback_unittest.cc
index 045e934..ff5b30e5 100644
--- a/components/viz/common/yuv_readback_unittest.cc
+++ b/components/viz/common/yuv_readback_unittest.cc
@@ -42,15 +42,17 @@
     attributes.bind_generates_resource = false;
 
     context_ = gpu::GLInProcessContext::CreateWithoutInit();
-    auto result = context_->Initialize(nullptr,                 /* service */
-                                       nullptr,                 /* surface */
-                                       true,                    /* offscreen */
-                                       gpu::kNullSurfaceHandle, /* window */
-                                       nullptr, /* share_context */
-                                       attributes, gpu::SharedMemoryLimits(),
-                                       nullptr, /* gpu_memory_buffer_manager */
-                                       nullptr, /* image_factory */
-                                       base::ThreadTaskRunnerHandle::Get());
+    auto result =
+        context_->Initialize(nullptr,                 /* service */
+                             nullptr,                 /* surface */
+                             true,                    /* offscreen */
+                             gpu::kNullSurfaceHandle, /* window */
+                             nullptr,                 /* share_context */
+                             attributes, gpu::SharedMemoryLimits(),
+                             nullptr, /* gpu_memory_buffer_manager */
+                             nullptr, /* image_factory */
+                             nullptr /* gpu_channel_manager_delegate */,
+                             base::ThreadTaskRunnerHandle::Get());
     DCHECK_EQ(result, gpu::ContextResult::kSuccess);
     gl_ = context_->GetImplementation();
     gpu::ContextSupport* support = context_->GetImplementation();
diff --git a/components/viz/service/display_embedder/gpu_display_provider.cc b/components/viz/service/display_embedder/gpu_display_provider.cc
index b7184da3..863f533 100644
--- a/components/viz/service/display_embedder/gpu_display_provider.cc
+++ b/components/viz/service/display_embedder/gpu_display_provider.cc
@@ -24,6 +24,7 @@
 #include "gpu/command_buffer/service/image_factory.h"
 #include "gpu/ipc/common/surface_handle.h"
 #include "gpu/ipc/service/gpu_channel_manager.h"
+#include "gpu/ipc/service/gpu_channel_manager_delegate.h"
 #include "gpu/ipc/service/gpu_memory_buffer_factory.h"
 #include "ui/base/ui_base_switches.h"
 
@@ -66,6 +67,7 @@
     CompositingModeReporterImpl* compositing_mode_reporter)
     : restart_id_(restart_id),
       gpu_service_(std::move(gpu_service)),
+      gpu_channel_manager_delegate_(gpu_channel_manager->delegate()),
       gpu_memory_buffer_manager_(
           base::MakeUnique<InProcessGpuMemoryBufferManager>(
               gpu_channel_manager)),
@@ -113,8 +115,8 @@
   } else {
     auto context_provider = base::MakeRefCounted<InProcessContextProvider>(
         gpu_service_, surface_handle, gpu_memory_buffer_manager_.get(),
-        image_factory_, gpu::SharedMemoryLimits(),
-        nullptr /* shared_context */);
+        image_factory_, gpu_channel_manager_delegate_,
+        gpu::SharedMemoryLimits(), nullptr /* shared_context */);
 
     // TODO(rjkroege): If there is something better to do than CHECK, add it.
     // TODO(danakj): Should retry if the result is kTransientFailure.
diff --git a/components/viz/service/display_embedder/gpu_display_provider.h b/components/viz/service/display_embedder/gpu_display_provider.h
index 4a93727..8900ba3e 100644
--- a/components/viz/service/display_embedder/gpu_display_provider.h
+++ b/components/viz/service/display_embedder/gpu_display_provider.h
@@ -20,6 +20,7 @@
 
 namespace gpu {
 class GpuChannelManager;
+class GpuChannelManagerDelegate;
 class ImageFactory;
 }  // namespace gpu
 
@@ -54,6 +55,7 @@
 
   const uint32_t restart_id_;
   scoped_refptr<gpu::InProcessCommandBuffer::Service> gpu_service_;
+  gpu::GpuChannelManagerDelegate* const gpu_channel_manager_delegate_;
   std::unique_ptr<gpu::GpuMemoryBufferManager> gpu_memory_buffer_manager_;
   gpu::ImageFactory* const image_factory_;
   CompositingModeReporterImpl* const compositing_mode_reporter_;
diff --git a/content/browser/DEPS b/content/browser/DEPS
index 94e0ad4..f28416fa 100644
--- a/content/browser/DEPS
+++ b/content/browser/DEPS
@@ -100,6 +100,7 @@
   "+third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationType.h",
   "+third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerError.h",
   "+third_party/WebKit/public/public_features.h",
+  "+third_party/WebKit/public/web/devtools_frontend.mojom.h",
   "+third_party/WebKit/public/web/WebAXEnums.h",
   "+third_party/WebKit/public/web/WebConsoleMessage.h",
   "+third_party/WebKit/public/web/WebContextMenuData.h",
diff --git a/content/browser/compositor/viz_process_transport_factory.cc b/content/browser/compositor/viz_process_transport_factory.cc
index 4c718787..8fd77c1 100644
--- a/content/browser/compositor/viz_process_transport_factory.cc
+++ b/content/browser/compositor/viz_process_transport_factory.cc
@@ -30,6 +30,10 @@
 #include "services/ui/public/cpp/gpu/context_provider_command_buffer.h"
 #include "ui/compositor/reflector.h"
 
+#if defined(OS_WIN)
+#include "ui/gfx/win/rendering_window_manager.h"
+#endif
+
 namespace content {
 namespace {
 
@@ -149,6 +153,11 @@
 
 void VizProcessTransportFactory::CreateLayerTreeFrameSink(
     base::WeakPtr<ui::Compositor> compositor) {
+#if defined(OS_WIN)
+  gfx::RenderingWindowManager::GetInstance()->UnregisterParent(
+      compositor->widget());
+#endif
+
   if (is_gpu_compositing_disabled_ || compositor->force_software_compositor()) {
     OnEstablishedGpuChannel(compositor, nullptr);
     return;
@@ -165,6 +174,13 @@
 }
 
 void VizProcessTransportFactory::RemoveCompositor(ui::Compositor* compositor) {
+#if defined(OS_WIN)
+  // TODO(crbug.com/791660): Make sure that GpuProcessHost::SetChildSurface()
+  // doesn't crash the GPU process after parent is unregistered.
+  gfx::RenderingWindowManager::GetInstance()->UnregisterParent(
+      compositor->widget());
+#endif
+
   compositor_data_map_.erase(compositor);
 }
 
@@ -381,6 +397,11 @@
     }
   }
 
+#if defined(OS_WIN)
+  gfx::RenderingWindowManager::GetInstance()->RegisterParent(
+      compositor->widget());
+#endif
+
   // TODO(crbug.com/776050): Deal with context loss.
 
   // Create interfaces for a root CompositorFrameSink.
@@ -429,6 +450,11 @@
   compositor->SetLayerTreeFrameSink(
       std::make_unique<viz::ClientLayerTreeFrameSink>(
           std::move(compositor_context), std::move(worker_context), &params));
+
+#if defined(OS_WIN)
+  gfx::RenderingWindowManager::GetInstance()->DoSetParentOnChild(
+      compositor->widget());
+#endif
 }
 
 bool VizProcessTransportFactory::CreateContextProviders(
diff --git a/content/browser/devtools/devtools_frontend_host_impl.cc b/content/browser/devtools/devtools_frontend_host_impl.cc
index afa8104..813056c 100644
--- a/content/browser/devtools/devtools_frontend_host_impl.cc
+++ b/content/browser/devtools/devtools_frontend_host_impl.cc
@@ -36,7 +36,7 @@
     RenderFrameHost* frame_host,
     const std::string& extension_api) {
   DCHECK(frame_host->GetParent());
-  mojom::DevToolsFrontendAssociatedPtr frontend;
+  blink::mojom::DevToolsFrontendAssociatedPtr frontend;
   frame_host->GetRemoteAssociatedInterfaces()->GetInterface(&frontend);
   frontend->SetupDevToolsExtensionAPI(extension_api);
 }
@@ -59,13 +59,13 @@
     : web_contents_(WebContents::FromRenderFrameHost(frame_host)),
       handle_message_callback_(handle_message_callback),
       binding_(this) {
-  mojom::DevToolsFrontendAssociatedPtr frontend;
+  blink::mojom::DevToolsFrontendAssociatedPtr frontend;
   frame_host->GetRemoteAssociatedInterfaces()->GetInterface(&frontend);
   std::string api_script =
       content::DevToolsFrontendHost::GetFrontendResource(kCompatibilityScript)
           .as_string() +
       kCompatibilityScriptSourceURL;
-  mojom::DevToolsFrontendHostAssociatedPtrInfo host;
+  blink::mojom::DevToolsFrontendHostAssociatedPtrInfo host;
   binding_.Bind(mojo::MakeRequest(&host));
   frontend->SetupDevToolsFrontend(api_script, std::move(host));
 }
diff --git a/content/browser/devtools/devtools_frontend_host_impl.h b/content/browser/devtools/devtools_frontend_host_impl.h
index 054cf5a..0b4275e5 100644
--- a/content/browser/devtools/devtools_frontend_host_impl.h
+++ b/content/browser/devtools/devtools_frontend_host_impl.h
@@ -6,16 +6,16 @@
 #define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_FRONTEND_HOST_IMPL_H_
 
 #include "base/macros.h"
-#include "content/common/devtools.mojom.h"
 #include "content/public/browser/devtools_frontend_host.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
+#include "third_party/WebKit/public/web/devtools_frontend.mojom.h"
 
 namespace content {
 
 class WebContents;
 
 class DevToolsFrontendHostImpl : public DevToolsFrontendHost,
-                                 public mojom::DevToolsFrontendHost {
+                                 public blink::mojom::DevToolsFrontendHost {
  public:
   DevToolsFrontendHostImpl(
       RenderFrameHost* frame_host,
@@ -25,12 +25,12 @@
   void BadMessageRecieved() override;
 
  private:
-  // mojom::DevToolsFrontendHost implementation.
+  // blink::mojom::DevToolsFrontendHost implementation.
   void DispatchEmbedderMessage(const std::string& message) override;
 
   WebContents* web_contents_;
   HandleMessageCallback handle_message_callback_;
-  mojo::AssociatedBinding<mojom::DevToolsFrontendHost> binding_;
+  mojo::AssociatedBinding<blink::mojom::DevToolsFrontendHost> binding_;
 
   DISALLOW_COPY_AND_ASSIGN(DevToolsFrontendHostImpl);
 };
diff --git a/content/browser/loader/resource_scheduler.cc b/content/browser/loader/resource_scheduler.cc
index af17d6d..6a44b62 100644
--- a/content/browser/loader/resource_scheduler.cc
+++ b/content/browser/loader/resource_scheduler.cc
@@ -24,6 +24,7 @@
 #include "content/common/resource_messages.h"
 #include "content/public/browser/resource_request_info.h"
 #include "content/public/browser/resource_throttle.h"
+#include "content/public/common/content_features.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/load_flags.h"
 #include "net/base/request_priority.h"
@@ -423,7 +424,15 @@
             resource_scheduler->throttle_delayable_.GetMaxDelayableRequests(
                 network_quality_estimator)),
         resource_scheduler_(resource_scheduler),
-        weak_ptr_factory_(this) {}
+        weak_ptr_factory_(this) {
+    if (base::FeatureList::IsEnabled(
+            features::kRendererSideResourceScheduler)) {
+      // When kRendererSideResourceScheduler is enabled, "layout blocking"
+      // concept is moved to the renderer side, so the shceduler works always
+      // with the normal mode.
+      has_html_body_ = true;
+    }
+  }
 
   ~Client() {}
 
@@ -488,6 +497,14 @@
 
   void OnNavigate() {
     has_html_body_ = false;
+    if (base::FeatureList::IsEnabled(
+            features::kRendererSideResourceScheduler)) {
+      // When kRendererSideResourceScheduler is enabled, "layout blocking"
+      // concept is moved to the renderer side, so the shceduler works always
+      // with the normal mode.
+      has_html_body_ = true;
+    }
+
     is_loaded_ = false;
     max_delayable_requests_ =
         resource_scheduler_->throttle_delayable_.GetMaxDelayableRequests(
@@ -960,6 +977,8 @@
   bool is_loaded_;
   // Tracks if the main HTML parser has reached the body which marks the end of
   // layout-blocking resources.
+  // This is disabled and the is always true when kRendererSideResourceScheduler
+  // is enabled.
   bool has_html_body_;
   bool using_spdy_proxy_;
   RequestQueue pending_requests_;
diff --git a/content/browser/service_manager/service_manager_context.cc b/content/browser/service_manager/service_manager_context.cc
index fb85ee0..1f862b78 100644
--- a/content/browser/service_manager/service_manager_context.cc
+++ b/content/browser/service_manager/service_manager_context.cc
@@ -30,6 +30,7 @@
 #include "content/browser/wake_lock/wake_lock_context_host.h"
 #include "content/common/service_manager/service_manager_connection_impl.h"
 #include "content/grit/content_resources.h"
+#include "content/network/network_service_impl.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/gpu_service_registry.h"
@@ -280,6 +281,12 @@
 }
 #endif
 
+std::unique_ptr<service_manager::Service> CreateNetworkService() {
+  // TODO(jam): make in-process network service work with test interfaces.
+  return std::make_unique<NetworkServiceImpl>(
+      std::make_unique<service_manager::BinderRegistry>());
+}
+
 }  // namespace
 
 // State which lives on the IO thread and drives the ServiceManager.
@@ -494,9 +501,20 @@
 
   bool network_service_enabled =
       base::FeatureList::IsEnabled(features::kNetworkService);
+  bool network_service_in_process =
+      base::FeatureList::IsEnabled(features::kNetworkServiceInProcess);
   if (network_service_enabled) {
-    out_of_process_services[content::mojom::kNetworkServiceName] =
-        base::ASCIIToUTF16("Network Service");
+    if (network_service_in_process) {
+      service_manager::EmbeddedServiceInfo network_service_info;
+      network_service_info.factory = base::BindRepeating(CreateNetworkService);
+      network_service_info.task_runner =
+          BrowserThread::GetTaskRunnerForThread(BrowserThread::IO);
+      packaged_services_connection_->AddEmbeddedService(
+          mojom::kNetworkServiceName, network_service_info);
+    } else {
+      out_of_process_services[mojom::kNetworkServiceName] =
+          base::ASCIIToUTF16("Network Service");
+    }
   }
 
   if (base::FeatureList::IsEnabled(video_capture::kMojoVideoCapture)) {
@@ -541,7 +559,7 @@
   RegisterCommonBrowserInterfaces(browser_connection);
   browser_connection->Start();
 
-  if (network_service_enabled) {
+  if (network_service_enabled && !network_service_in_process) {
     // Start the network service process as soon as possible, since it is
     // critical to start up performance.
     browser_connection->GetConnector()->StartService(
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 1d3faaf..223ab4b 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -80,6 +80,7 @@
 #include "content/public/test/test_frame_navigation_observer.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "content/public/test/test_utils.h"
+#include "content/public/test/url_loader_interceptor.h"
 #include "content/shell/browser/shell.h"
 #include "content/shell/common/shell_switches.h"
 #include "content/test/content_browser_test_utils_internal.h"
@@ -3100,43 +3101,6 @@
   }
 }
 
-namespace {
-class FailingURLLoaderImpl : public mojom::URLLoader {
- public:
-  explicit FailingURLLoaderImpl(mojom::URLLoaderClientPtr client) {
-    network::URLLoaderCompletionStatus status;
-    status.error_code = net::ERR_NOT_IMPLEMENTED;
-    client->OnComplete(status);
-  }
-
-  void FollowRedirect() override {}
-  void SetPriority(net::RequestPriority priority,
-                   int32_t intra_priority_value) override {}
-  void PauseReadingBodyFromNet() override {}
-  void ResumeReadingBodyFromNet() override {}
-};
-
-class FailingLoadFactory : public mojom::URLLoaderFactory {
- public:
-  FailingLoadFactory() {}
-  ~FailingLoadFactory() override {}
-
-  void CreateLoaderAndStart(mojom::URLLoaderRequest loader,
-                            int32_t routing_id,
-                            int32_t request_id,
-                            uint32_t options,
-                            const ResourceRequest& request,
-                            mojom::URLLoaderClientPtr client,
-                            const net::MutableNetworkTrafficAnnotationTag&
-                                traffic_annotation) override {
-    new FailingURLLoaderImpl(std::move(client));
-  }
-
-  void Clone(mojom::URLLoaderFactoryRequest request) override { NOTREACHED(); }
-};
-
-}  // namespace
-
 // Ensure that a cross-site page ends up in the correct process when it
 // successfully loads after earlier encountering a network error for it.
 // See https://crbug.com/560511.
@@ -3157,14 +3121,19 @@
   GURL url_b = embedded_test_server()->GetURL("b.com", "/title3.html");
   bool network_service =
       base::FeatureList::IsEnabled(features::kNetworkService);
-  FailingLoadFactory failing_factory;
-  StoragePartitionImpl* storage_partition = nullptr;
+  std::unique_ptr<URLLoaderInterceptor> url_loader_interceptor;
   if (network_service) {
-    storage_partition = static_cast<StoragePartitionImpl*>(
+    StoragePartition* storage_partition =
         BrowserContext::GetDefaultStoragePartition(
-            shell()->web_contents()->GetBrowserContext()));
-    storage_partition->url_loader_factory_getter()->SetNetworkFactoryForTesting(
-        &failing_factory);
+            shell()->web_contents()->GetBrowserContext());
+    url_loader_interceptor = std::make_unique<URLLoaderInterceptor>(
+        base::BindRepeating([](URLLoaderInterceptor::RequestParams* params) {
+          network::URLLoaderCompletionStatus status;
+          status.error_code = net::ERR_NOT_IMPLEMENTED;
+          params->client->OnComplete(status);
+          return true;
+        }),
+        storage_partition);
   } else {
     host_resolver()->ClearRules();
   }
@@ -3202,8 +3171,7 @@
 
   // Try again after re-enabling host resolution.
   if (network_service) {
-    storage_partition->url_loader_factory_getter()->SetNetworkFactoryForTesting(
-        nullptr);
+    url_loader_interceptor.reset();
   } else {
     host_resolver()->AddRule("*", "127.0.0.1");
   }
diff --git a/content/common/devtools.mojom b/content/common/devtools.mojom
index 8ef6200..2c5f2640 100644
--- a/content/common/devtools.mojom
+++ b/content/common/devtools.mojom
@@ -6,38 +6,6 @@
 
 import "ui/gfx/geometry/mojo/geometry.mojom";
 
-// Provides extra capabilities required for DevTools frontend to function.
-// This includes communication channel from/to inspected target which implements
-// remote debugging protocol. Protocol messages go through browser process.
-// This interface is implemented in DevTools renderer.
-//
-// Instances of this interface must be associated with navigation-related
-// interface, since we should setup DevToolsFrontend before the navigation
-// commits in the frame.
-interface DevToolsFrontend {
-  // Sets up a main frame as a DevTools frontend. This exposes DevToolsHost
-  // object (see DevToolsHost.idl for details). The |api_script| is executed
-  // on each navigation in the frame before the DevTools frontend starts
-  // loading. It makes use of DevToolsHost to expose embedder capabilities to
-  // DevTools (e.g. connection to the inspected target).
-  SetupDevToolsFrontend(string api_script,
-                        associated DevToolsFrontendHost host);
-
-  // Sets up a child frame to expose DevTools extension API by executing script
-  // |extension_api| on each navigation in the frame. This script provides
-  // required capabilities for DevTools extensions to function, implementing
-  // chrome.devtools extension API.
-  SetupDevToolsExtensionAPI(string extension_api);
-};
-
-// Provides embedder functionality to a frame serving as DevTools frontend.
-// This interface is implemented in browser.
-interface DevToolsFrontendHost {
-  // Sends a message to DevTools frontend embedder.
-  DispatchEmbedderMessage(string message);
-};
-
-
 // Used to send large messages in chunks from session to a host.
 struct DevToolsMessageChunk {
   // Whether this is a first chunk in a message.
diff --git a/content/network/network_context.cc b/content/network/network_context.cc
index 1d5ab88..a056a3b 100644
--- a/content/network/network_context.cc
+++ b/content/network/network_context.cc
@@ -34,6 +34,7 @@
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/network/ignore_errors_cert_verifier.h"
+#include "content/public/network/url_request_context_builder_mojo.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "net/dns/host_resolver.h"
 #include "net/dns/mapped_host_resolver.h"
@@ -69,7 +70,7 @@
     NetworkServiceImpl* network_service,
     mojom::NetworkContextRequest request,
     mojom::NetworkContextParamsPtr params,
-    std::unique_ptr<net::URLRequestContextBuilder> builder)
+    std::unique_ptr<URLRequestContextBuilderMojo> builder)
     : network_service_(network_service),
       params_(std::move(params)),
       binding_(this, std::move(request)) {
@@ -203,7 +204,7 @@
 
 std::unique_ptr<net::URLRequestContext> NetworkContext::MakeURLRequestContext(
     mojom::NetworkContextParams* network_context_params) {
-  net::URLRequestContextBuilder builder;
+  URLRequestContextBuilderMojo builder;
   const base::CommandLine* command_line =
       base::CommandLine::ForCurrentProcess();
 
@@ -231,7 +232,7 @@
 }
 
 void NetworkContext::ApplyContextParamsToBuilder(
-    net::URLRequestContextBuilder* builder,
+    URLRequestContextBuilderMojo* builder,
     mojom::NetworkContextParams* network_context_params) {
   // |network_service_| may be nullptr in tests.
   if (network_service_)
@@ -241,6 +242,12 @@
   if (network_context_params->context_name)
     builder->set_name(*network_context_params->context_name);
 
+  if (network_context_params->proxy_resolver_factory) {
+    builder->SetMojoProxyResolverFactory(
+        proxy_resolver::mojom::ProxyResolverFactoryPtr(
+            std::move(network_context_params->proxy_resolver_factory)));
+  }
+
   if (!network_context_params->http_cache_enabled) {
     builder->DisableHttpCache();
   } else {
diff --git a/content/network/network_context.h b/content/network/network_context.h
index 015dd27..cc66fc9 100644
--- a/content/network/network_context.h
+++ b/content/network/network_context.h
@@ -25,13 +25,13 @@
 
 namespace net {
 class URLRequestContext;
-class URLRequestContextBuilder;
 class HttpServerPropertiesManager;
 }
 
 namespace content {
 class NetworkServiceImpl;
 class URLLoader;
+class URLRequestContextBuilderMojo;
 
 // A NetworkContext creates and manages access to a URLRequestContext.
 //
@@ -42,7 +42,7 @@
 //
 // When the network service is disabled, NetworkContexts may be created through
 // NetworkServiceImpl::CreateNetworkContextWithBuilder, and take in a
-// URLRequestContextBuilder to seed construction of the NetworkContext's
+// URLRequestContextBuilderMojo to seed construction of the NetworkContext's
 // URLRequestContext. When that happens, the consumer takes ownership of the
 // NetworkContext directly, has direct access to its URLRequestContext, and is
 // responsible for destroying it before the NetworkService.
@@ -53,11 +53,11 @@
                  mojom::NetworkContextParamsPtr params);
 
   // Temporary constructor that allows creating an in-process NetworkContext
-  // with a pre-populated URLRequestContextBuilder.
+  // with a pre-populated URLRequestContextBuilderMojo.
   NetworkContext(NetworkServiceImpl* network_service,
                  mojom::NetworkContextRequest request,
                  mojom::NetworkContextParamsPtr params,
-                 std::unique_ptr<net::URLRequestContextBuilder> builder);
+                 std::unique_ptr<URLRequestContextBuilderMojo> builder);
 
   // Creates a NetworkContext that wraps a consumer-provided URLRequestContext
   // that the NetworkContext does not own. In this case, there is no
@@ -115,7 +115,7 @@
 
   // Applies the values in |network_context_params| to |builder|.
   void ApplyContextParamsToBuilder(
-      net::URLRequestContextBuilder* builder,
+      URLRequestContextBuilderMojo* builder,
       mojom::NetworkContextParams* network_context_params);
 
   NetworkServiceImpl* const network_service_;
diff --git a/content/network/network_service_impl.cc b/content/network/network_service_impl.cc
index f56582b..4321d869 100644
--- a/content/network/network_service_impl.cc
+++ b/content/network/network_service_impl.cc
@@ -13,6 +13,7 @@
 #include "build/build_config.h"
 #include "content/network/network_context.h"
 #include "content/public/common/content_switches.h"
+#include "content/public/network/url_request_context_builder_mojo.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "net/base/logging_network_change_observer.h"
 #include "net/base/network_change_notifier.h"
@@ -138,7 +139,7 @@
 NetworkServiceImpl::CreateNetworkContextWithBuilder(
     content::mojom::NetworkContextRequest request,
     content::mojom::NetworkContextParamsPtr params,
-    std::unique_ptr<net::URLRequestContextBuilder> builder,
+    std::unique_ptr<URLRequestContextBuilderMojo> builder,
     net::URLRequestContext** url_request_context) {
   std::unique_ptr<NetworkContext> network_context =
       std::make_unique<NetworkContext>(this, std::move(request),
diff --git a/content/network/network_service_impl.h b/content/network/network_service_impl.h
index ea7aac6..2806b56 100644
--- a/content/network/network_service_impl.h
+++ b/content/network/network_service_impl.h
@@ -23,12 +23,12 @@
 class NetLog;
 class LoggingNetworkChangeObserver;
 class URLRequestContext;
-class URLRequestContextBuilder;
 }  // namespace net
 
 namespace content {
 
 class NetworkContext;
+class URLRequestContextBuilderMojo;
 
 class CONTENT_EXPORT NetworkServiceImpl : public service_manager::Service,
                                           public NetworkService {
@@ -47,7 +47,7 @@
   std::unique_ptr<mojom::NetworkContext> CreateNetworkContextWithBuilder(
       content::mojom::NetworkContextRequest request,
       content::mojom::NetworkContextParamsPtr params,
-      std::unique_ptr<net::URLRequestContextBuilder> builder,
+      std::unique_ptr<URLRequestContextBuilderMojo> builder,
       net::URLRequestContext** url_request_context) override;
 
   static std::unique_ptr<NetworkServiceImpl> CreateForTesting();
diff --git a/content/public/common/BUILD.gn b/content/public/common/BUILD.gn
index fe882fea..46f2aef 100644
--- a/content/public/common/BUILD.gn
+++ b/content/public/common/BUILD.gn
@@ -374,6 +374,7 @@
     ":resource_type_bindings",
     "//mojo/common:common_custom_types",
     "//services/network/public/interfaces",
+    "//services/proxy_resolver/public/interfaces",
     "//url/mojo:url_mojom_gurl",
     "//url/mojo:url_mojom_origin",
   ]
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 8f8e0e1..262fa2e 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -165,6 +165,10 @@
 const base::Feature kNetworkService{"NetworkService",
                                     base::FEATURE_DISABLED_BY_DEFAULT};
 
+// If the network service is enabled, runs it in process.
+const base::Feature kNetworkServiceInProcess{"NetworkServiceInProcess",
+                                             base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Kill switch for Web Notification content images.
 const base::Feature kNotificationContentImage{"NotificationContentImage",
                                               base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index d5289ad0..8da6cae 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -53,6 +53,7 @@
 CONTENT_EXPORT extern const base::Feature kMediaDevicesSystemMonitorCache;
 CONTENT_EXPORT extern const base::Feature kMemoryCoordinator;
 CONTENT_EXPORT extern const base::Feature kNetworkService;
+CONTENT_EXPORT extern const base::Feature kNetworkServiceInProcess;
 CONTENT_EXPORT extern const base::Feature kNotificationContentImage;
 CONTENT_EXPORT extern const base::Feature kMainThreadBusyScrollIntervention;
 CONTENT_EXPORT extern const base::Feature kMojoBlobs;
diff --git a/content/public/common/network_service.mojom b/content/public/common/network_service.mojom
index b5333a9..0ef8af9c 100644
--- a/content/public/common/network_service.mojom
+++ b/content/public/common/network_service.mojom
@@ -14,6 +14,7 @@
 import "services/network/public/interfaces/cookie_manager.mojom";
 import "services/network/public/interfaces/network_change_manager.mojom";
 import "services/network/public/interfaces/restricted_cookie_manager.mojom";
+import "services/proxy_resolver/public/interfaces/proxy_resolver.mojom";
 
 [Native]
 struct SSLInfo;
@@ -29,6 +30,11 @@
   // QUIC user agent.
   string quic_user_agent_id;
 
+  // Handles PAC script execution. If not populated, will attempt to use
+  // platform implementation to execute PAC scripts, if available (Only
+  // available on Windows and Mac).
+  proxy_resolver.mojom.ProxyResolverFactory? proxy_resolver_factory;
+
   // Points to the cookie file. Currently ignored. An in-memory cookie store is
   // always used instead.
   // TODO(mmenke): Respect this parameter.
diff --git a/content/public/network/network_service.h b/content/public/network/network_service.h
index 31d3112..bc161ff 100644
--- a/content/public/network/network_service.h
+++ b/content/public/network/network_service.h
@@ -13,11 +13,12 @@
 namespace net {
 class NetLog;
 class URLRequestContext;
-class URLRequestContextBuilder;
 }  // namespace net
 
 namespace content {
 
+class URLRequestContextBuilderMojo;
+
 // Allows an in-process NetworkService to be set up.
 class CONTENT_EXPORT NetworkService : public mojom::NetworkService {
  public:
@@ -44,7 +45,7 @@
   CreateNetworkContextWithBuilder(
       mojom::NetworkContextRequest request,
       mojom::NetworkContextParamsPtr params,
-      std::unique_ptr<net::URLRequestContextBuilder> builder,
+      std::unique_ptr<URLRequestContextBuilderMojo> builder,
       net::URLRequestContext** url_request_context) = 0;
 
   ~NetworkService() override {}
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 36d95599..f088918 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -97,8 +97,6 @@
     "devtools/devtools_agent.h",
     "devtools/devtools_cpu_throttler.cc",
     "devtools/devtools_cpu_throttler.h",
-    "devtools/devtools_frontend_impl.cc",
-    "devtools/devtools_frontend_impl.h",
     "devtools/render_widget_screen_metrics_emulator.cc",
     "devtools/render_widget_screen_metrics_emulator.h",
     "devtools/render_widget_screen_metrics_emulator_delegate.h",
diff --git a/content/renderer/devtools/devtools_frontend_impl.cc b/content/renderer/devtools/devtools_frontend_impl.cc
deleted file mode 100644
index 1400750e..0000000
--- a/content/renderer/devtools/devtools_frontend_impl.cc
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/renderer/devtools/devtools_frontend_impl.h"
-
-#include "base/strings/utf_string_conversions.h"
-#include "content/renderer/render_frame_impl.h"
-#include "content/renderer/render_thread_impl.h"
-#include "third_party/WebKit/public/platform/WebString.h"
-#include "third_party/WebKit/public/web/WebDevToolsFrontend.h"
-
-namespace content {
-
-// static
-void DevToolsFrontendImpl::CreateMojoService(
-    RenderFrame* render_frame,
-    mojom::DevToolsFrontendAssociatedRequest request) {
-  // Self-destructs on render frame deletion.
-  new DevToolsFrontendImpl(render_frame, std::move(request));
-}
-
-DevToolsFrontendImpl::DevToolsFrontendImpl(
-    RenderFrame* render_frame,
-    mojom::DevToolsFrontendAssociatedRequest request)
-    : RenderFrameObserver(render_frame), binding_(this, std::move(request)) {}
-
-DevToolsFrontendImpl::~DevToolsFrontendImpl() {}
-
-void DevToolsFrontendImpl::DidClearWindowObject() {
-  if (!api_script_.empty())
-    render_frame()->ExecuteJavaScript(base::UTF8ToUTF16(api_script_));
-}
-
-void DevToolsFrontendImpl::OnDestruct() {
-  delete this;
-}
-
-void DevToolsFrontendImpl::SendMessageToEmbedder(
-    const blink::WebString& message) {
-  if (host_)
-    host_->DispatchEmbedderMessage(message.Utf8());
-}
-
-bool DevToolsFrontendImpl::IsUnderTest() {
-  return RenderThreadImpl::current()->layout_test_mode();
-}
-
-void DevToolsFrontendImpl::SetupDevToolsFrontend(
-    const std::string& api_script,
-    mojom::DevToolsFrontendHostAssociatedPtrInfo host) {
-  DCHECK(render_frame()->IsMainFrame());
-  api_script_ = api_script;
-  web_devtools_frontend_.reset(
-      blink::WebDevToolsFrontend::Create(render_frame()->GetWebFrame(), this));
-  host_.Bind(std::move(host));
-  host_.set_connection_error_handler(base::BindOnce(
-      &DevToolsFrontendImpl::OnDestruct, base::Unretained(this)));
-}
-
-void DevToolsFrontendImpl::SetupDevToolsExtensionAPI(
-    const std::string& extension_api) {
-  DCHECK(!render_frame()->IsMainFrame());
-  api_script_ = extension_api;
-}
-
-}  // namespace content
diff --git a/content/renderer/devtools/devtools_frontend_impl.h b/content/renderer/devtools/devtools_frontend_impl.h
deleted file mode 100644
index 6bab4f3..0000000
--- a/content/renderer/devtools/devtools_frontend_impl.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_DEVTOOLS_DEVTOOLS_FRONTEND_IMPL_H_
-#define CONTENT_RENDERER_DEVTOOLS_DEVTOOLS_FRONTEND_IMPL_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-
-#include "base/macros.h"
-#include "content/common/devtools.mojom.h"
-#include "content/public/renderer/render_frame_observer.h"
-#include "mojo/public/cpp/bindings/associated_binding.h"
-#include "third_party/WebKit/public/web/WebDevToolsFrontendClient.h"
-
-namespace blink {
-class WebDevToolsFrontend;
-class WebString;
-}  // namespace blink
-
-namespace content {
-
-// Implementation of content.mojom.DevToolsFrontend interface.
-class DevToolsFrontendImpl : public RenderFrameObserver,
-                             public blink::WebDevToolsFrontendClient,
-                             public mojom::DevToolsFrontend {
- public:
-  ~DevToolsFrontendImpl() override;
-
-  static void CreateMojoService(
-      RenderFrame* render_frame,
-      mojom::DevToolsFrontendAssociatedRequest request);
-
- private:
-  DevToolsFrontendImpl(RenderFrame* render_frame,
-                       mojom::DevToolsFrontendAssociatedRequest request);
-
-  // RenderFrameObserver overrides.
-  void DidClearWindowObject() override;
-  void OnDestruct() override;
-
-  // WebDevToolsFrontendClient implementation.
-  void SendMessageToEmbedder(const blink::WebString& message) override;
-  bool IsUnderTest() override;
-
-  // mojom::DevToolsFrontend implementation.
-  void SetupDevToolsFrontend(
-      const std::string& api_script,
-      mojom::DevToolsFrontendHostAssociatedPtrInfo host) override;
-  void SetupDevToolsExtensionAPI(const std::string& extension_api) override;
-
-  std::unique_ptr<blink::WebDevToolsFrontend> web_devtools_frontend_;
-  std::string api_script_;
-  mojom::DevToolsFrontendHostAssociatedPtr host_;
-  mojo::AssociatedBinding<mojom::DevToolsFrontend> binding_;
-
-  DISALLOW_COPY_AND_ASSIGN(DevToolsFrontendImpl);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_DEVTOOLS_DEVTOOLS_FRONTEND_IMPL_H_
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index bd485e59..52ee7b4 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -98,7 +98,6 @@
 #include "content/renderer/content_security_policy_util.h"
 #include "content/renderer/context_menu_params_builder.h"
 #include "content/renderer/devtools/devtools_agent.h"
-#include "content/renderer/devtools/devtools_frontend_impl.h"
 #include "content/renderer/dom_automation_controller.h"
 #include "content/renderer/effective_connection_type_helper.h"
 #include "content/renderer/external_popup_menu.h"
@@ -7064,9 +7063,6 @@
   registry_.AddInterface(
       base::Bind(&RenderFrameImpl::BindWidget, weak_factory_.GetWeakPtr()));
 
-  GetAssociatedInterfaceRegistry()->AddInterface(base::Bind(
-      &DevToolsFrontendImpl::CreateMojoService, base::Unretained(this)));
-
   if (!frame_->Parent()) {
     // Only main frame have ImageDownloader service.
     registry_.AddInterface(base::Bind(&ImageDownloaderImpl::CreateMojoService,
diff --git a/device/geolocation/public/interfaces/geolocation.mojom b/device/geolocation/public/interfaces/geolocation.mojom
index 027f53e5..0dda9e3 100644
--- a/device/geolocation/public/interfaces/geolocation.mojom
+++ b/device/geolocation/public/interfaces/geolocation.mojom
@@ -10,11 +10,21 @@
 // provides updates with low accuracy, but |SetHighAccuracy()| may be called
 // to change this.
 interface Geolocation {
+  // Select between high and low accuracy, if supported by the implementation.
+  // Ignored if unsupported.
   SetHighAccuracy(bool high_accuracy);
 
-  // Position is reported once it changes or immediately (to report the initial
-  // position) if this is the first call to QueryNextPosition on this instance.
-  // Position updates may be throttled by the service. Overlapping calls to
-  // this method are prohibited and will be treated as a connection error.
+  // Use this method to get notified of future position updates, by calling
+  // QueryNextPosition once, and then calling it again when/if it returns.
+  //
+  // When first called:
+  //   Returns the latest known Geoposition.
+  // When subsequently called:
+  //   Issues a request for a single position update, which the implementation
+  //   may fulfill at its discretion (e.g. when the next geoposition change is
+  //   detected).
+  //
+  // Overlapping calls to this method are prohibited and will be treated as a
+  // connection error. Position updates may be throttled by the service.
   QueryNextPosition() => (Geoposition geoposition);
 };
diff --git a/docs/testing/json_test_results_format.md b/docs/testing/json_test_results_format.md
index a017e3f..5b82614 100644
--- a/docs/testing/json_test_results_format.md
+++ b/docs/testing/json_test_results_format.md
@@ -107,7 +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. |
+|  `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`). Any '/' characters in the file paths are meant to be platform agnostic; tools will replace them with the appropriate per platform path separators. 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, the path is assumed to be relative to the location of the json file which contains this. |
 |  `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/extensions/browser/api/feedback_private/feedback_private_api_chromeos_unittest.cc b/extensions/browser/api/feedback_private/feedback_private_api_chromeos_unittest.cc
index 0d7ec4c..fe7f2d3 100644
--- a/extensions/browser/api/feedback_private/feedback_private_api_chromeos_unittest.cc
+++ b/extensions/browser/api/feedback_private/feedback_private_api_chromeos_unittest.cc
@@ -186,6 +186,31 @@
   EXPECT_NE("", RunReadLogSourceFunctionWithError(params));
 }
 
+TEST_F(FeedbackPrivateApiUnittest, Anonymize) {
+  const TimeDelta timeout(TimeDelta::FromMilliseconds(0));
+  LogSourceAccessManager::SetRateLimitingTimeoutForTesting(&timeout);
+
+  ReadLogSourceParams params;
+  params.source = api::feedback_private::LOG_SOURCE_MESSAGES;
+  params.incremental = true;
+
+  int result_reader_id = 0;
+  std::string result_string;
+  // Skip over all the alphabetic results, to test anonymization of the
+  // subsequent MAC address.
+  for (int i = 0; i < 26; ++i) {
+    EXPECT_TRUE(
+        RunReadLogSourceFunction(params, &result_reader_id, &result_string));
+    EXPECT_GT(result_reader_id, 0);
+    params.reader_id = std::make_unique<int>(result_reader_id);
+  }
+
+  EXPECT_TRUE(
+      RunReadLogSourceFunction(params, &result_reader_id, &result_string));
+  EXPECT_EQ(*params.reader_id, result_reader_id);
+  EXPECT_EQ("11:22:33:00:00:01", result_string);
+}
+
 TEST_F(FeedbackPrivateApiUnittest, ReadLogSourceMultipleSources) {
   const TimeDelta timeout(TimeDelta::FromMilliseconds(0));
   LogSourceAccessManager::SetRateLimitingTimeoutForTesting(&timeout);
diff --git a/extensions/browser/api/feedback_private/feedback_private_api_unittest_base_chromeos.cc b/extensions/browser/api/feedback_private/feedback_private_api_unittest_base_chromeos.cc
index 1b82a15..cdbe136 100644
--- a/extensions/browser/api/feedback_private/feedback_private_api_unittest_base_chromeos.cc
+++ b/extensions/browser/api/feedback_private/feedback_private_api_unittest_base_chromeos.cc
@@ -28,6 +28,9 @@
 using system_logs::SystemLogsResponse;
 using system_logs::SystemLogsSource;
 
+// A fake MAC address used to test anonymization.
+const char kDummyMacAddress[] = "11:22:33:44:55:66";
+
 std::unique_ptr<KeyedService> ApiResourceManagerTestFactory(
     content::BrowserContext* context) {
   return std::make_unique<ApiResourceManager<LogSourceResource>>(context);
@@ -43,15 +46,12 @@
   ~TestSingleLogSource() override = default;
 
   // Fetch() will return a single different string each time, in the following
-  // sequence: "a", " bb", "  ccc", until 25 spaces followed by 26 z's. Will
-  // never return an empty result.
+  // sequence: "a", " bb", "  ccc", until 25 spaces followed by 26 z's. After
+  // that, it returns |kDummyMacAddress| before repeating the entire process.
+  // It will never return an empty result.
   void Fetch(const system_logs::SysLogsSourceCallback& callback) override {
-    int count_modulus = call_count_ % kNumCharsToIterate;
-    std::string result =
-        std::string(count_modulus, ' ') +
-        std::string(count_modulus + 1, kInitialChar + count_modulus);
+    std::string result = GetNextLogResult();
     DCHECK_GT(result.size(), 0U);
-    ++call_count_;
 
     auto result_map = std::make_unique<SystemLogsResponse>();
     result_map->emplace("", result);
@@ -64,6 +64,18 @@
   }
 
  private:
+  std::string GetNextLogResult() {
+    if (call_count_ == kNumCharsToIterate) {
+      call_count_ = 0;
+      return kDummyMacAddress;
+    }
+    std::string result =
+        std::string(call_count_, ' ') +
+        std::string(call_count_ + 1, kInitialChar + call_count_);
+    ++call_count_;
+    return result;
+  }
+
   // Iterate over the whole lowercase alphabet, starting from 'a'.
   const int kNumCharsToIterate = 26;
   const char kInitialChar = 'a';
diff --git a/extensions/browser/api/feedback_private/log_source_access_manager.cc b/extensions/browser/api/feedback_private/log_source_access_manager.cc
index 70c29ad..4d555ef2 100644
--- a/extensions/browser/api/feedback_private/log_source_access_manager.cc
+++ b/extensions/browser/api/feedback_private/log_source_access_manager.cc
@@ -57,6 +57,7 @@
 LogSourceAccessManager::LogSourceAccessManager(content::BrowserContext* context)
     : context_(context),
       tick_clock_(std::make_unique<base::DefaultTickClock>()),
+      anonymizer_(std::make_unique<feedback::AnonymizerTool>()),
       weak_factory_(this) {}
 
 LogSourceAccessManager::~LogSourceAccessManager() {}
@@ -121,6 +122,10 @@
   result.reader_id = delete_resource ? kInvalidResourceId : resource_id;
 
   GetLogLinesFromSystemLogsResponse(*response, &result.log_lines);
+
+  for (std::string& line : result.log_lines)
+    line = anonymizer_->Anonymize(line);
+
   if (delete_resource) {
     // This should also remove the entry from |sources_|.
     ApiResourceManager<LogSourceResource>::Get(context_)->Remove(extension_id,
diff --git a/extensions/browser/api/feedback_private/log_source_access_manager.h b/extensions/browser/api/feedback_private/log_source_access_manager.h
index 78a4ca5..343b42f 100644
--- a/extensions/browser/api/feedback_private/log_source_access_manager.h
+++ b/extensions/browser/api/feedback_private/log_source_access_manager.h
@@ -16,6 +16,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/time/tick_clock.h"
 #include "base/time/time.h"
+#include "components/feedback/anonymizer_tool.h"
 #include "components/feedback/system_logs/system_logs_source.h"
 #include "content/public/browser/browser_context.h"
 #include "extensions/browser/api/feedback_private/access_rate_limiter.h"
@@ -150,6 +151,9 @@
   // Can override the default clock for testing.
   std::unique_ptr<base::TickClock> tick_clock_;
 
+  // For removing PII from log strings from log sources.
+  std::unique_ptr<feedback::AnonymizerTool> anonymizer_;
+
   base::WeakPtrFactory<LogSourceAccessManager> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(LogSourceAccessManager);
diff --git a/extensions/renderer/BUILD.gn b/extensions/renderer/BUILD.gn
index da4defd..9ce2ab0d 100644
--- a/extensions/renderer/BUILD.gn
+++ b/extensions/renderer/BUILD.gn
@@ -284,8 +284,6 @@
     "//extensions/common",
     "//extensions/common/api",
     "//gin",
-    "//mojo/edk/js",
-    "//mojo/public/js",
     "//skia",
     "//third_party/WebKit/public:blink",
     "//third_party/cld_3/src/src:cld_3",
@@ -368,11 +366,7 @@
   testonly = true
   sources = [
     "activity_log_converter_strategy_unittest.cc",
-    "api/mojo_private/mojo_private_unittest.cc",
     "api_activity_logger_unittest.cc",
-    "api_test_base.cc",
-    "api_test_base.h",
-    "api_test_base_unittest.cc",
     "bindings/api_binding_hooks_test_delegate.cc",
     "bindings/api_binding_hooks_test_delegate.h",
     "bindings/api_binding_js_util_unittest.cc",
@@ -428,7 +422,6 @@
     "//gin",
     "//gin:gin_test",
     "//ipc:test_support",
-    "//mojo/edk/js",
     "//testing/gmock",
     "//testing/gtest",
     "//third_party/WebKit/public:blink",
diff --git a/extensions/renderer/api/mojo_private/mojo_private_unittest.cc b/extensions/renderer/api/mojo_private/mojo_private_unittest.cc
deleted file mode 100644
index 9693bf28..0000000
--- a/extensions/renderer/api/mojo_private/mojo_private_unittest.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "extensions/renderer/api_test_base.h"
-
-#include "base/macros.h"
-#include "extensions/common/extension_builder.h"
-#include "extensions/common/value_builder.h"
-
-// A test launcher for tests for the mojoPrivate API defined in
-// extensions/test/data/mojo_private_unittest.js.
-
-namespace extensions {
-
-class MojoPrivateApiTest : public ApiTestBase {
- public:
-  MojoPrivateApiTest() = default;
-
-  scoped_refptr<const Extension> CreateExtension() override {
-    std::unique_ptr<base::DictionaryValue> manifest =
-        DictionaryBuilder()
-            .Set("name", "test")
-            .Set("version", "1.0")
-            .Set("manifest_version", 2)
-            .Build();
-    // Return an extension whitelisted for the mojoPrivate API.
-    return ExtensionBuilder()
-        .SetManifest(std::move(manifest))
-        .SetID("pkedcjkdefgpdelpbcmbmeomcjbeemfm")
-        .Build();
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(MojoPrivateApiTest);
-};
-
-TEST_F(MojoPrivateApiTest, RequireAsync) {
-  env()->RegisterModule(
-      "add", "exports.$set('returnValue', function(x, y) { return x + y; });");
-  ASSERT_NO_FATAL_FAILURE(
-      RunTest("mojo_private_unittest.js", "testRequireAsync"));
-}
-
-}  // namespace extensions
diff --git a/extensions/renderer/api_test_base.cc b/extensions/renderer/api_test_base.cc
deleted file mode 100644
index 0bd6ae36..0000000
--- a/extensions/renderer/api_test_base.cc
+++ /dev/null
@@ -1,261 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "extensions/renderer/api_test_base.h"
-
-#include <utility>
-#include <vector>
-
-#include "base/feature_list.h"
-#include "base/location.h"
-#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/strings/string_piece.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "extensions/common/extension_features.h"
-#include "extensions/common/extension_urls.h"
-#include "extensions/renderer/dispatcher.h"
-#include "extensions/renderer/process_info_native_handler.h"
-#include "gin/converter.h"
-#include "gin/dictionary.h"
-#include "gin/modules/console.h"
-#include "gin/modules/timer.h"
-#include "mojo/edk/js/core.h"
-#include "mojo/edk/js/handle.h"
-#include "mojo/edk/js/support.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
-#include "mojo/public/cpp/system/core.h"
-
-namespace extensions {
-namespace {
-
-// Natives for the implementation of the unit test version of chrome.test. Calls
-// the provided |quit_closure| when either notifyPass or notifyFail is called.
-class TestNatives : public gin::Wrappable<TestNatives> {
- public:
-  static gin::Handle<TestNatives> Create(v8::Isolate* isolate,
-                                         const base::Closure& quit_closure) {
-    return gin::CreateHandle(isolate, new TestNatives(quit_closure));
-  }
-
-  gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
-      v8::Isolate* isolate) override {
-    return Wrappable<TestNatives>::GetObjectTemplateBuilder(isolate)
-        .SetMethod("Log", &TestNatives::Log)
-        .SetMethod("NotifyPass", &TestNatives::NotifyPass)
-        .SetMethod("NotifyFail", &TestNatives::NotifyFail);
-  }
-
-  void Log(const std::string& value) { logs_ += value + "\n"; }
-  void NotifyPass() { FinishTesting(); }
-
-  void NotifyFail(const std::string& message) {
-    FinishTesting();
-    FAIL() << logs_ << message;
-  }
-
-  void FinishTesting() {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure_);
-  }
-
-  static gin::WrapperInfo kWrapperInfo;
-
- private:
-  explicit TestNatives(const base::Closure& quit_closure)
-      : quit_closure_(quit_closure) {}
-
-  const base::Closure quit_closure_;
-  std::string logs_;
-};
-
-gin::WrapperInfo TestNatives::kWrapperInfo = {gin::kEmbedderNativeGin};
-
-}  // namespace
-
-gin::WrapperInfo TestInterfaceProvider::kWrapperInfo =
-    {gin::kEmbedderNativeGin};
-
-gin::Handle<TestInterfaceProvider> TestInterfaceProvider::Create(
-    v8::Isolate* isolate) {
-  return gin::CreateHandle(isolate, new TestInterfaceProvider());
-}
-
-TestInterfaceProvider::~TestInterfaceProvider() {
-}
-
-gin::ObjectTemplateBuilder TestInterfaceProvider::GetObjectTemplateBuilder(
-    v8::Isolate* isolate) {
-  return Wrappable<TestInterfaceProvider>::GetObjectTemplateBuilder(isolate)
-      .SetMethod("getInterface", &TestInterfaceProvider::GetInterface);
-}
-
-mojo::Handle TestInterfaceProvider::GetInterface(
-    const std::string& interface_name) {
-  EXPECT_EQ(1u, factories_.count(interface_name))
-      << "Unregistered interface " << interface_name << " requested.";
-  mojo::MessagePipe pipe;
-  std::map<std::string,
-           base::Callback<void(mojo::ScopedMessagePipeHandle)> >::iterator it =
-      factories_.find(interface_name);
-  if (it != factories_.end())
-    it->second.Run(std::move(pipe.handle0));
-  return pipe.handle1.release();
-}
-
-TestInterfaceProvider::TestInterfaceProvider() {
-}
-
-// static
-void TestInterfaceProvider::IgnoreHandle(mojo::ScopedMessagePipeHandle handle) {
-}
-
-ApiTestEnvironment::ApiTestEnvironment(
-    ModuleSystemTestEnvironment* environment) {
-  env_ = environment;
-  InitializeEnvironment();
-  RegisterModules();
-}
-
-ApiTestEnvironment::~ApiTestEnvironment() {
-}
-
-void ApiTestEnvironment::RegisterModules() {
-  v8_schema_registry_.reset(new V8SchemaRegistry);
-  const std::vector<Dispatcher::JsResourceInfo> resources =
-      Dispatcher::GetJsResources();
-  for (const auto& resource : resources) {
-    if (base::StringPiece(resource.name) !=
-        "test_environment_specific_bindings") {
-      env()->RegisterModule(resource.name, resource.id, resource.gzipped);
-    }
-  }
-  Dispatcher::RegisterNativeHandlers(env()->module_system(),
-                                     env()->context(),
-                                     NULL,
-                                     NULL,
-                                     v8_schema_registry_.get());
-  env()->module_system()->RegisterNativeHandler(
-      "process", std::unique_ptr<NativeHandler>(new ProcessInfoNativeHandler(
-                     env()->context(), env()->context()->GetExtensionID(),
-                     env()->context()->GetContextTypeDescription(), false,
-                     false, 2, false)));
-  env()->RegisterTestFile("test_environment_specific_bindings",
-                          "unit_test_environment_specific_bindings.js");
-
-  env()->OverrideNativeHandler("activityLogger",
-                               "exports.$set('LogAPICall', function() {});");
-  env()->OverrideNativeHandler(
-      "apiDefinitions",
-      "exports.$set('GetExtensionAPIDefinitionsForTest',"
-                    "function() { return [] });");
-  env()->OverrideNativeHandler(
-      "event_natives",
-      "exports.$set('AttachEvent', function() {});"
-      "exports.$set('DetachEvent', function() {});"
-      "exports.$set('AttachFilteredEvent', function() {});"
-      "exports.$set('AttachFilteredEvent', function() {});"
-      "exports.$set('MatchAgainstEventFilter', function() { return [] });");
-
-  gin::ModuleRegistry::From(env()->context()->v8_context())
-      ->AddBuiltinModule(env()->isolate(), gin::Console::kModuleName,
-                         gin::Console::GetModule(env()->isolate()));
-  gin::ModuleRegistry::From(env()->context()->v8_context())
-      ->AddBuiltinModule(env()->isolate(), gin::TimerModule::kName,
-                         gin::TimerModule::GetModule(env()->isolate()));
-  gin::ModuleRegistry::From(env()->context()->v8_context())
-      ->AddBuiltinModule(env()->isolate(), mojo::edk::js::Core::kModuleName,
-                         mojo::edk::js::Core::GetModule(env()->isolate()));
-  gin::ModuleRegistry::From(env()->context()->v8_context())
-      ->AddBuiltinModule(env()->isolate(), mojo::edk::js::Support::kModuleName,
-                         mojo::edk::js::Support::GetModule(env()->isolate()));
-  gin::Handle<TestInterfaceProvider> interface_provider =
-    TestInterfaceProvider::Create(env()->isolate());
-  interface_provider_ = interface_provider.get();
-  gin::ModuleRegistry::From(env()->context()->v8_context())
-      ->AddBuiltinModule(env()->isolate(),
-                         "content/public/renderer/frame_interfaces",
-                         interface_provider.ToV8());
-}
-
-void ApiTestEnvironment::InitializeEnvironment() {
-  // With native bindings, we use the actual bindings system to set up the
-  // context, so there's no need to provide these stubs.
-  if (base::FeatureList::IsEnabled(features::kNativeCrxBindings))
-    return;
-
-  gin::Dictionary global(env()->isolate(),
-                         env()->context()->v8_context()->Global());
-  gin::Dictionary navigator(gin::Dictionary::CreateEmpty(env()->isolate()));
-  navigator.Set("appVersion", base::StringPiece(""));
-  global.Set("navigator", navigator);
-  gin::Dictionary chrome(gin::Dictionary::CreateEmpty(env()->isolate()));
-  global.Set("chrome", chrome);
-  gin::Dictionary runtime(gin::Dictionary::CreateEmpty(env()->isolate()));
-  chrome.Set("runtime", runtime);
-}
-
-void ApiTestEnvironment::RunTest(const std::string& file_name,
-                                 const std::string& test_name) {
-  env()->RegisterTestFile("testBody", file_name);
-  base::RunLoop run_loop;
-  gin::ModuleRegistry::From(env()->context()->v8_context())->AddBuiltinModule(
-      env()->isolate(),
-      "testNatives",
-      TestNatives::Create(env()->isolate(), run_loop.QuitClosure()).ToV8());
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::Bind(&ApiTestEnvironment::RunTestInner, base::Unretained(this),
-                 test_name, run_loop.QuitClosure()));
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(&ApiTestEnvironment::RunPromisesAgain,
-                            base::Unretained(this)));
-  run_loop.Run();
-}
-
-void ApiTestEnvironment::RunTestInner(const std::string& test_name,
-                                      const base::Closure& quit_closure) {
-  v8::HandleScope scope(env()->isolate());
-  ModuleSystem::NativesEnabledScope natives_enabled(env()->module_system());
-  v8::Local<v8::Value> result;
-  bool did_run = false;
-  auto callback = [](bool* did_run, const base::Closure& quit_closure,
-                     const std::string& test_name,
-                     const std::vector<v8::Local<v8::Value>>& result) {
-    *did_run = true;
-    if (result.empty() || result[0].IsEmpty() || !result[0]->IsTrue()) {
-      base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure);
-      FAIL() << "Failed to run test \"" << test_name << "\"";
-    }
-  };
-
-  ASSERT_FALSE(
-      env()->module_system()->Require("testBody").ToLocalChecked().IsEmpty());
-  env()->module_system()->CallModuleMethodSafe(
-      "testBody", test_name, 0, nullptr,
-      base::Bind(callback, &did_run, quit_closure, test_name));
-  ASSERT_TRUE(did_run);
-}
-
-void ApiTestEnvironment::RunPromisesAgain() {
-  v8::MicrotasksScope::PerformCheckpoint(env()->isolate());
-}
-
-ApiTestBase::ApiTestBase() {
-}
-
-ApiTestBase::~ApiTestBase() {
-}
-
-void ApiTestBase::SetUp() {
-  ModuleSystemTest::SetUp();
-  test_env_.reset(new ApiTestEnvironment(env()));
-}
-
-void ApiTestBase::RunTest(const std::string& file_name,
-                          const std::string& test_name) {
-  ExpectNoAssertionsMade();
-  test_env_->RunTest(file_name, test_name);
-}
-
-}  // namespace extensions
diff --git a/extensions/renderer/api_test_base.h b/extensions/renderer/api_test_base.h
deleted file mode 100644
index 6eb8776..0000000
--- a/extensions/renderer/api_test_base.h
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef EXTENSIONS_RENDERER_API_TEST_BASE_H_
-#define EXTENSIONS_RENDERER_API_TEST_BASE_H_
-
-#include <map>
-#include <string>
-#include <utility>
-
-#include "base/run_loop.h"
-#include "extensions/renderer/module_system_test.h"
-#include "extensions/renderer/v8_schema_registry.h"
-#include "gin/handle.h"
-#include "gin/modules/module_registry.h"
-#include "gin/object_template_builder.h"
-#include "gin/wrappable.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
-#include "mojo/public/cpp/system/core.h"
-
-namespace extensions {
-
-class V8SchemaRegistry;
-
-// An InterfaceProvider that provides access from JS modules to interfaces
-// registered by AddInterface() calls.
-class TestInterfaceProvider : public gin::Wrappable<TestInterfaceProvider> {
- public:
-  static gin::Handle<TestInterfaceProvider> Create(v8::Isolate* isolate);
-  ~TestInterfaceProvider() override;
-
-  gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
-      v8::Isolate* isolate) override;
-
-  template <typename Interface>
-  void AddInterface(
-      const base::Callback<void(mojo::InterfaceRequest<Interface>)>
-          factory_callback) {
-    factories_.insert(std::make_pair(
-        Interface::Name_,
-        base::Bind(ForwardToInterfaceFactory<Interface>, factory_callback)));
-  }
-
-  // Ignore requests for Interface.
-  template <typename Interface>
-  void IgnoreInterfaceRequests() {
-    factories_.insert(std::make_pair(
-        Interface::Name_, base::Bind(&TestInterfaceProvider::IgnoreHandle)));
-  }
-
-  static gin::WrapperInfo kWrapperInfo;
-
- private:
-   TestInterfaceProvider();
-
-  mojo::Handle GetInterface(const std::string& interface_name);
-
-  template <typename Interface>
-  static void ForwardToInterfaceFactory(
-      const base::Callback<void(mojo::InterfaceRequest<Interface>)>
-          factory_callback,
-      mojo::ScopedMessagePipeHandle handle) {
-    factory_callback.Run(mojo::InterfaceRequest<Interface>(std::move(handle)));
-  }
-
-  static void IgnoreHandle(mojo::ScopedMessagePipeHandle handle);
-
-  std::map<std::string, base::Callback<void(mojo::ScopedMessagePipeHandle)> >
-      factories_;
-};
-
-// An environment for unit testing apps/extensions API custom bindings
-// implemented on Mojo interfaces. This augments a ModuleSystemTestEnvironment
-// with a TestInterfaceProvider and other modules available in a real extensions
-// environment.
-class ApiTestEnvironment {
- public:
-  explicit ApiTestEnvironment(ModuleSystemTestEnvironment* environment);
-  ~ApiTestEnvironment();
-  void RunTest(const std::string& file_name, const std::string& test_name);
-  TestInterfaceProvider* interface_provider() { return interface_provider_; }
-  ModuleSystemTestEnvironment* env() { return env_; }
-
- private:
-  void RegisterModules();
-  void InitializeEnvironment();
-  void RunTestInner(const std::string& test_name,
-                    const base::Closure& quit_closure);
-  void RunPromisesAgain();
-
-  ModuleSystemTestEnvironment* env_;
-  TestInterfaceProvider* interface_provider_;
-  std::unique_ptr<V8SchemaRegistry> v8_schema_registry_;
-};
-
-// A base class for unit testing apps/extensions API custom bindings implemented
-// on Mojo interfaces. To use:
-// 1. Register test Mojo interface implementations on interface_provider().
-// 2. Write JS tests in extensions/test/data/test_file.js.
-// 3. Write one C++ test function for each JS test containing
-//    RunTest("test_file.js", "testFunctionName").
-// See extensions/renderer/api_test_base_unittest.cc and
-// extensions/test/data/api_test_base_unittest.js for sample usage.
-class ApiTestBase : public ModuleSystemTest {
- protected:
-  ApiTestBase();
-  ~ApiTestBase() override;
-  void SetUp() override;
-  void RunTest(const std::string& file_name, const std::string& test_name);
-
-  ApiTestEnvironment* api_test_env() { return test_env_.get(); }
-  TestInterfaceProvider* interface_provider() {
-    return test_env_->interface_provider();
-  }
-
- private:
-  std::unique_ptr<ApiTestEnvironment> test_env_;
-};
-
-}  // namespace extensions
-
-#endif  // EXTENSIONS_RENDERER_API_TEST_BASE_H_
diff --git a/extensions/renderer/api_test_base_unittest.cc b/extensions/renderer/api_test_base_unittest.cc
deleted file mode 100644
index 149e34e..0000000
--- a/extensions/renderer/api_test_base_unittest.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "extensions/renderer/api_test_base.h"
-
-namespace extensions {
-
-class ApiTestBaseTest : public ApiTestBase {
- public:
-  void SetUp() override { ApiTestBase::SetUp(); }
-};
-
-TEST_F(ApiTestBaseTest, TestEnvironment) {
-  RunTest("api_test_base_unittest.js", "testEnvironment");
-}
-
-TEST_F(ApiTestBaseTest, TestPromisesRun) {
-  RunTest("api_test_base_unittest.js", "testPromisesRun");
-}
-
-TEST_F(ApiTestBaseTest, TestCommonModulesAreAvailable) {
-  RunTest("api_test_base_unittest.js", "testCommonModulesAreAvailable");
-}
-
-TEST_F(ApiTestBaseTest, TestMojoModulesAreAvailable) {
-  RunTest("api_test_base_unittest.js", "testMojoModulesAreAvailable");
-}
-
-TEST_F(ApiTestBaseTest, TestTestBindings) {
-  RunTest("api_test_base_unittest.js", "testTestBindings");
-}
-
-}  // namespace extensions
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc
index 4e12af83..0773ddf 100644
--- a/extensions/renderer/dispatcher.cc
+++ b/extensions/renderer/dispatcher.cc
@@ -101,7 +101,6 @@
 #include "extensions/renderer/worker_script_context_set.h"
 #include "extensions/renderer/worker_thread_dispatcher.h"
 #include "gin/converter.h"
-#include "mojo/public/js/constants.h"
 #include "mojo/public/js/grit/mojo_bindings_resources.h"
 #include "third_party/WebKit/public/platform/WebRuntimeFeatures.h"
 #include "third_party/WebKit/public/platform/WebString.h"
@@ -685,31 +684,6 @@
       {"webViewEvents", IDR_WEB_VIEW_EVENTS_JS},
       {"webViewInternal", IDR_WEB_VIEW_INTERNAL_CUSTOM_BINDINGS_JS},
 
-      {mojo::kAssociatedBindingsModuleName, IDR_MOJO_ASSOCIATED_BINDINGS_JS},
-      {mojo::kBindingsModuleName, IDR_MOJO_BINDINGS_JS_DEPRECATED},
-      {mojo::kBufferModuleName, IDR_MOJO_BUFFER_JS},
-      {mojo::kCodecModuleName, IDR_MOJO_CODEC_JS},
-      {mojo::kConnectorModuleName, IDR_MOJO_CONNECTOR_JS},
-      {mojo::kControlMessageHandlerModuleName,
-       IDR_MOJO_CONTROL_MESSAGE_HANDLER_JS},
-      {mojo::kControlMessageProxyModuleName, IDR_MOJO_CONTROL_MESSAGE_PROXY_JS},
-      {mojo::kInterfaceControlMessagesMojom,
-       IDR_MOJO_INTERFACE_CONTROL_MESSAGES_MOJOM_JS},
-      {mojo::kInterfaceEndpointClientModuleName,
-       IDR_MOJO_INTERFACE_ENDPOINT_CLIENT_JS},
-      {mojo::kInterfaceEndpointHandleModuleName,
-       IDR_MOJO_INTERFACE_ENDPOINT_HANDLE_JS},
-      {mojo::kInterfaceTypesModuleName, IDR_MOJO_INTERFACE_TYPES_JS},
-      {mojo::kPipeControlMessageHandlerModuleName,
-       IDR_MOJO_PIPE_CONTROL_MESSAGE_HANDLER_JS},
-      {mojo::kPipeControlMessageProxyModuleName,
-       IDR_MOJO_PIPE_CONTROL_MESSAGE_PROXY_JS},
-      {mojo::kPipeControlMessagesMojom,
-       IDR_MOJO_PIPE_CONTROL_MESSAGES_MOJOM_JS},
-      {mojo::kRouterModuleName, IDR_MOJO_ROUTER_JS},
-      {mojo::kUnicodeModuleName, IDR_MOJO_UNICODE_JS},
-      {mojo::kValidatorModuleName, IDR_MOJO_VALIDATOR_JS},
-      {"async_waiter", IDR_ASYNC_WAITER_JS},
       {"keep_alive", IDR_KEEP_ALIVE_JS},
       {"mojo_bindings", IDR_MOJO_BINDINGS_JS, true},
       {"extensions/common/mojo/keep_alive.mojom", IDR_KEEP_ALIVE_MOJOM_JS},
diff --git a/extensions/renderer/module_system.cc b/extensions/renderer/module_system.cc
index c71192a0..5dea4bb 100644
--- a/extensions/renderer/module_system.cc
+++ b/extensions/renderer/module_system.cc
@@ -24,7 +24,6 @@
 #include "extensions/renderer/source_map.h"
 #include "extensions/renderer/v8_helpers.h"
 #include "gin/converter.h"
-#include "gin/modules/module_registry.h"
 #include "third_party/WebKit/public/web/WebContextFeatures.h"
 #include "third_party/WebKit/public/web/WebFrame.h"
 
@@ -169,17 +168,13 @@
       context_(context),
       source_map_(source_map),
       natives_enabled_(0),
-      exception_handler_(new DefaultExceptionHandler(context)),
-      weak_factory_(this) {
+      exception_handler_(new DefaultExceptionHandler(context)) {
   RouteFunction(
       "require",
       base::Bind(&ModuleSystem::RequireForJs, base::Unretained(this)));
   RouteFunction(
       "requireNative",
       base::Bind(&ModuleSystem::RequireNative, base::Unretained(this)));
-  RouteFunction(
-      "requireAsync",
-      base::Bind(&ModuleSystem::RequireAsync, base::Unretained(this)));
   RouteFunction("loadScript",
                 base::Bind(&ModuleSystem::LoadScript, base::Unretained(this)));
   RouteFunction("privates",
@@ -190,12 +185,9 @@
   SetPrivate(global, kModulesField, v8::Object::New(isolate));
   SetPrivate(global, kModuleSystem, v8::External::New(isolate, this));
 
-  gin::ModuleRegistry::From(context->v8_context())->AddObserver(this);
   if (context_->GetRenderFrame() &&
       context_->context_type() == Feature::BLESSED_EXTENSION_CONTEXT &&
       ContextNeedsMojoBindings(context_)) {
-    context_->GetRenderFrame()->EnsureMojoBuiltinsAreAvailable(
-        context->isolate(), context->v8_context());
     blink::WebContextFeatures::EnableMojoJS(context->v8_context(), true);
   }
 }
@@ -631,36 +623,6 @@
   return i->second->NewInstance();
 }
 
-void ModuleSystem::RequireAsync(
-    const v8::FunctionCallbackInfo<v8::Value>& args) {
-  CHECK_EQ(1, args.Length());
-  std::string module_name = *v8::String::Utf8Value(args[0]);
-  v8::Local<v8::Context> v8_context = context_->v8_context();
-  v8::Local<v8::Promise::Resolver> resolver(
-      v8::Promise::Resolver::New(v8_context).ToLocalChecked());
-  args.GetReturnValue().Set(resolver->GetPromise());
-  std::unique_ptr<v8::Global<v8::Promise::Resolver>> global_resolver(
-      new v8::Global<v8::Promise::Resolver>(GetIsolate(), resolver));
-  gin::ModuleRegistry* module_registry =
-      gin::ModuleRegistry::From(v8_context);
-  if (!module_registry) {
-    Warn(GetIsolate(), "Extension view no longer exists");
-    auto maybe = resolver->Reject(
-        v8_context,
-        v8::Exception::Error(ToV8StringUnsafe(
-            GetIsolate(),
-            "Extension view no longer exists")));
-    CHECK(IsTrue(maybe));
-    return;
-  }
-  module_registry->LoadModule(
-      GetIsolate(), module_name,
-      base::Bind(&ModuleSystem::OnModuleLoaded, weak_factory_.GetWeakPtr(),
-                 base::Passed(&global_resolver)));
-  if (module_registry->available_modules().count(module_name) == 0)
-    LoadModule(module_name);
-}
-
 void ModuleSystem::LoadScript(const v8::FunctionCallbackInfo<v8::Value>& args) {
   CHECK_EQ(1, args.Length());
   std::string module_name = *v8::String::Utf8Value(args[0]);
@@ -687,9 +649,9 @@
   // Keep in order with the arguments in RequireForJsInner.
   v8::Local<v8::String> left = ToV8StringUnsafe(
       GetIsolate(),
-      "(function(define, require, requireNative, requireAsync, loadScript, "
-      "exports, console, privates, apiBridge, bindingUtil, getInternalApi,"
-      "$Array, $Function, $JSON, $Object, $RegExp, $String, $Error) {"
+      "(function(require, requireNative, loadScript, exports, console, "
+      "privates, apiBridge, bindingUtil, getInternalApi, $Array, $Function, "
+      "$JSON, $Object, $RegExp, $String, $Error) {"
       "'use strict';");
   v8::Local<v8::String> right = ToV8StringUnsafe(GetIsolate(), "\n})");
   return handle_scope.Escape(v8::Local<v8::String>(
@@ -759,9 +721,6 @@
 
   v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(func_as_value);
 
-  v8::Local<v8::Object> define_object = v8::Object::New(GetIsolate());
-  gin::ModuleRegistry::InstallGlobals(GetIsolate(), define_object);
-
   v8::Local<v8::Object> exports = v8::Object::New(GetIsolate());
 
   v8::Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(
@@ -810,15 +769,11 @@
 
   // These must match the argument order in WrapSource.
   v8::Local<v8::Value> args[] = {
-      // AMD.
-      GetPropertyUnsafe(v8_context, define_object, "define"),
       // CommonJS.
       GetPropertyUnsafe(v8_context, natives, "require",
                         v8::NewStringType::kInternalized),
       GetPropertyUnsafe(v8_context, natives, "requireNative",
                         v8::NewStringType::kInternalized),
-      GetPropertyUnsafe(v8_context, natives, "requireAsync",
-                        v8::NewStringType::kInternalized),
       GetPropertyUnsafe(v8_context, natives, "loadScript",
                         v8::NewStringType::kInternalized),
       exports,
@@ -850,39 +805,6 @@
   return handle_scope.Escape(exports);
 }
 
-void ModuleSystem::OnDidAddPendingModule(
-    const std::string& id,
-    const std::vector<std::string>& dependencies) {
-  bool module_system_managed = source_map_->Contains(id);
-
-  gin::ModuleRegistry* registry =
-      gin::ModuleRegistry::From(context_->v8_context());
-  DCHECK(registry);
-  for (const auto& dependency : dependencies) {
-    // If a dependency is not available, and either the module or this
-    // dependency is managed by ModuleSystem, attempt to load it. Other
-    // gin::ModuleRegistry users (WebUI and users of the mojoPrivate API) are
-    // responsible for loading their module dependencies when required.
-    if (registry->available_modules().count(dependency) == 0 &&
-        (module_system_managed || source_map_->Contains(dependency))) {
-      LoadModule(dependency);
-    }
-  }
-  registry->AttemptToLoadMoreModules(GetIsolate());
-}
-
-void ModuleSystem::OnModuleLoaded(
-    std::unique_ptr<v8::Global<v8::Promise::Resolver>> resolver,
-    v8::Local<v8::Value> value) {
-  if (!is_valid())
-    return;
-  v8::HandleScope handle_scope(GetIsolate());
-  v8::Local<v8::Promise::Resolver> resolver_local(
-      v8::Local<v8::Promise::Resolver>::New(GetIsolate(), *resolver));
-  auto maybe = resolver_local->Resolve(context()->v8_context(), value);
-  CHECK(IsTrue(maybe));
-}
-
 void ModuleSystem::ClobberExistingNativeHandler(const std::string& name) {
   NativeHandlerMap::iterator existing_handler = native_handler_map_.find(name);
   if (existing_handler != native_handler_map_.end()) {
diff --git a/extensions/renderer/module_system.h b/extensions/renderer/module_system.h
index e941616..b7844b1 100644
--- a/extensions/renderer/module_system.h
+++ b/extensions/renderer/module_system.h
@@ -17,7 +17,6 @@
 #include "extensions/renderer/native_handler.h"
 #include "extensions/renderer/object_backed_native_handler.h"
 #include "extensions/renderer/script_injection_callback.h"
-#include "gin/modules/module_registry_observer.h"
 #include "v8/include/v8.h"
 
 namespace extensions {
@@ -41,10 +40,7 @@
 // Note that a ModuleSystem must be used only in conjunction with a single
 // v8::Context.
 // TODO(koz): Rename this to JavaScriptModuleSystem.
-// TODO(yzshen): crbug.com/718047 Remove all gin-related things. Mojo no longer
-// relies on gin.
-class ModuleSystem : public ObjectBackedNativeHandler,
-                     public gin::ModuleRegistryObserver {
+class ModuleSystem : public ObjectBackedNativeHandler {
  public:
   class ExceptionHandler {
    public:
@@ -212,10 +208,6 @@
       const std::string& native_name);
   void RequireNative(const v8::FunctionCallbackInfo<v8::Value>& args);
 
-  // Return a promise for a requested module.
-  // |args[0]| - the name of a module.
-  void RequireAsync(const v8::FunctionCallbackInfo<v8::Value>& args);
-
   // |args[0]| - the name of a module.
   // This method directly executes the script in the current scope.
   void LoadScript(const v8::FunctionCallbackInfo<v8::Value>& args);
@@ -232,17 +224,6 @@
       const std::string& module_name,
       v8::Local<v8::Value> api_object);
 
-  // Invoked when a module is loaded in response to a requireAsync call.
-  // Resolves |resolver| with |value|.
-  void OnModuleLoaded(
-      std::unique_ptr<v8::Global<v8::Promise::Resolver>> resolver,
-      v8::Local<v8::Value> value);
-
-  // gin::ModuleRegistryObserver overrides.
-  void OnDidAddPendingModule(
-      const std::string& id,
-      const std::vector<std::string>& dependencies) override;
-
   // Marks any existing NativeHandler named |name| as clobbered.
   // See |clobbered_native_handlers_|.
   void ClobberExistingNativeHandler(const std::string& name);
@@ -287,8 +268,6 @@
   // The set of modules that we've attempted to load.
   std::set<std::string> loaded_modules_;
 
-  base::WeakPtrFactory<ModuleSystem> weak_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(ModuleSystem);
 };
 
diff --git a/extensions/renderer/module_system_unittest.cc b/extensions/renderer/module_system_unittest.cc
index 071be3f9..52f895e 100644
--- a/extensions/renderer/module_system_unittest.cc
+++ b/extensions/renderer/module_system_unittest.cc
@@ -10,7 +10,6 @@
 #include <utility>
 
 #include "extensions/renderer/module_system_test.h"
-#include "gin/modules/module_registry.h"
 
 namespace extensions {
 
@@ -279,232 +278,6 @@
   env()->module_system()->Require("test");
 }
 
-TEST_F(ModuleSystemTest, TestRequireAsync) {
-  ModuleSystem::NativesEnabledScope natives_enabled_scope(
-      env()->module_system());
-  env()->RegisterModule("add",
-                        "define('add', [], function() {"
-                        "  return { Add: function(x, y) { return x + y; } };"
-                        "});");
-  env()->RegisterModule("math",
-                        "define('math', ['add'], function(add) {"
-                        "  return { Add: add.Add };"
-                        "});");
-  env()->RegisterModule(
-      "test",
-      "requireAsync('math').then(function(math) {"
-      "  requireNative('assert').AssertTrue(math.Add(3, 5) == 8);"
-      "});");
-  env()->module_system()->Require("test");
-  RunResolvedPromises();
-}
-
-TEST_F(ModuleSystemTest, TestRequireAsyncInParallel) {
-  ModuleSystem::NativesEnabledScope natives_enabled_scope(
-      env()->module_system());
-  env()->RegisterModule("add",
-                        "define('add', [], function() {"
-                        "  return { Add: function(x, y) { return x + y; } };"
-                        "});");
-  env()->RegisterModule(
-      "subtract",
-      "define('subtract', [], function() {"
-      "  return { Subtract: function(x, y) { return x - y; } };"
-      "});");
-  env()->RegisterModule(
-      "math",
-      "exports.$set('AddAndSubtract', function(x, y, z) {"
-      "  return Promise.all([requireAsync('add'),"
-      "                      requireAsync('subtract')"
-      "  ]).then(function(modules) {"
-      "    return modules[1].Subtract(modules[0].Add(x, y), z);"
-      "  });"
-      "});");
-  env()->RegisterModule("test",
-                        "var AddAndSubtract = require('math').AddAndSubtract;"
-                        "AddAndSubtract(3, 5, 2).then(function(result) {"
-                        "  requireNative('assert').AssertTrue(result == 6);"
-                        "});");
-  env()->module_system()->Require("test");
-  RunResolvedPromises();
-}
-
-TEST_F(ModuleSystemTest, TestNestedRequireAsyncs) {
-  ModuleSystem::NativesEnabledScope natives_enabled_scope(
-      env()->module_system());
-  env()->RegisterModule("first",
-                        "define('first', [], function() {"
-                        "  return { next: 'second' };"
-                        "});");
-  env()->RegisterModule("second",
-                        "define('second', [], function() {"
-                        "  return { next: '' };"
-                        "});");
-  env()->RegisterModule(
-      "test",
-      "requireAsync('first').then(function(module) {"
-      "  return requireAsync(module.next)"
-      "}).then(function(module) {"
-      "  requireNative('assert').AssertTrue(module.next === '');"
-      "});");
-  env()->module_system()->Require("test");
-  RunResolvedPromises();
-}
-
-TEST_F(ModuleSystemTest, TestRequireFromAMDModule) {
-  ModuleSystem::NativesEnabledScope natives_enabled_scope(
-      env()->module_system());
-  env()->RegisterModule(
-      "add", "exports.$set('Add', function(x, y) { return x + y; });");
-  env()->RegisterModule("math",
-                        "define('math', [], function() {"
-                        "  var add = require('add');"
-                        "  return { Add: add.Add };"
-                        "});");
-  env()->RegisterModule(
-      "test",
-      "requireAsync('math').then(function(math) {"
-      "  requireNative('assert').AssertTrue(math.Add(3, 5) == 8);"
-      "});");
-  env()->module_system()->Require("test");
-  RunResolvedPromises();
-}
-
-TEST_F(ModuleSystemTest, TestRequireAsyncFromAMDModule) {
-  ModuleSystem::NativesEnabledScope natives_enabled_scope(
-      env()->module_system());
-  env()->RegisterModule("add",
-                        "define('add', [], function() {"
-                        "  return { Add: function(x, y) { return x + y; } };"
-                        "});");
-  env()->RegisterModule("math",
-                        "define('math', [], function() {"
-                        "  function Add(x, y) {"
-                        "    return requireAsync('add').then(function(add) {"
-                        "      return add.Add(x, y);"
-                        "    });"
-                        "  }"
-                        "  return { Add: Add };"
-                        "});");
-  env()->RegisterModule("test",
-                        "requireAsync('math').then(function(math) {"
-                        "  return math.Add(3, 6);"
-                        "}).then(function(result) {"
-                        "  requireNative('assert').AssertTrue(result == 9);"
-                        "});");
-  env()->module_system()->Require("test");
-  RunResolvedPromises();
-}
-
-TEST_F(ModuleSystemTest, TestRequireAsyncFromAnotherContext) {
-  ModuleSystem::NativesEnabledScope natives_enabled_scope(
-      env()->module_system());
-  env()->RegisterModule(
-      "test",
-      "requireAsync('natives').then(function(natives) {"
-      "  natives.requireAsync('ping').then(function(ping) {"
-      "    return ping();"
-      "  }).then(function(result) {"
-      "    requireNative('assert').AssertTrue(result == 'pong');"
-      "  });"
-      "});");
-  std::unique_ptr<ModuleSystemTestEnvironment> other_env = CreateEnvironment();
-  other_env->RegisterModule("ping",
-                            "define('ping', ['natives'], function(natives) {"
-                            "  return function() {"
-                            "    return 'pong';"
-                            "  }"
-                            "});");
-  gin::ModuleRegistry::From(env()->context()->v8_context())
-      ->AddBuiltinModule(
-          env()->isolate(), "natives",
-          other_env->module_system()->NewInstance());
-  gin::ModuleRegistry::From(other_env->context()->v8_context())
-      ->AddBuiltinModule(
-          env()->isolate(), "natives",
-          env()->module_system()->NewInstance());
-  env()->module_system()->Require("test");
-  RunResolvedPromises();
-}
-
-TEST_F(ModuleSystemTest, TestRequireAsyncBetweenContexts) {
-  ModuleSystem::NativesEnabledScope natives_enabled_scope(
-      env()->module_system());
-  env()->RegisterModule("pong",
-                        "define('pong', [], function() {"
-                        "  return function() { return 'done'; };"
-                        "});");
-  env()->RegisterModule(
-      "test",
-      "requireAsync('natives').then(function(natives) {"
-      "  natives.requireAsync('ping').then(function(ping) {"
-      "    return ping();"
-      "  }).then(function(pong) {"
-      "    return pong();"
-      "  }).then(function(result) {"
-      "    requireNative('assert').AssertTrue(result == 'done');"
-      "  });"
-      "});");
-  std::unique_ptr<ModuleSystemTestEnvironment> other_env = CreateEnvironment();
-  other_env->RegisterModule("ping",
-                            "define('ping', ['natives'], function(natives) {"
-                            "  return function() {"
-                            "    return natives.requireAsync('pong');"
-                            "  }"
-                            "});");
-  gin::ModuleRegistry::From(env()->context()->v8_context())
-      ->AddBuiltinModule(
-          env()->isolate(), "natives",
-          other_env->module_system()->NewInstance());
-  gin::ModuleRegistry::From(other_env->context()->v8_context())
-      ->AddBuiltinModule(
-          env()->isolate(), "natives",
-          env()->module_system()->NewInstance());
-  env()->module_system()->Require("test");
-  RunResolvedPromises();
-}
-
-TEST_F(ModuleSystemTest, TestRequireAsyncFromContextWithNoModuleRegistry) {
-  ModuleSystem::NativesEnabledScope natives_enabled_scope(
-      env()->module_system());
-  env()->RegisterModule("test",
-                        "requireAsync('natives').then(function(natives) {"
-                        "  var AssertTrue = requireNative('assert').AssertTrue;"
-                        "  natives.requireAsync('foo').then(function() {"
-                        "    AssertTrue(false);"
-                        "  }).catch(function(error) {"
-                        "    AssertTrue(error.message == "
-                        "               'Extension view no longer exists');"
-                        "  });"
-                        "});");
-  std::unique_ptr<ModuleSystemTestEnvironment> other_env = CreateEnvironment();
-  gin::ModuleRegistry::From(env()->context()->v8_context())
-      ->AddBuiltinModule(
-          env()->isolate(), "natives",
-          other_env->module_system()->NewInstance());
-  other_env->ShutdownGin();
-  env()->module_system()->Require("test");
-  RunResolvedPromises();
-}
-
-TEST_F(ModuleSystemTest, TestRequireAsyncFromContextWithNoModuleSystem) {
-  ModuleSystem::NativesEnabledScope natives_enabled_scope(
-      env()->module_system());
-  env()->RegisterModule("test",
-                        "requireAsync('natives').then(function(natives) {"
-                        "  requireNative('assert').AssertTrue("
-                        "      natives.requireAsync('foo') === undefined);"
-                        "});");
-  std::unique_ptr<ModuleSystemTestEnvironment> other_env = CreateEnvironment();
-  gin::ModuleRegistry::From(env()->context()->v8_context())
-      ->AddBuiltinModule(
-          env()->isolate(), "natives",
-          other_env->module_system()->NewInstance());
-  other_env->ShutdownModuleSystem();
-  env()->module_system()->Require("test");
-  RunResolvedPromises();
-}
-
 TEST_F(ModuleSystemTest, TestPrivatesIsPrivate) {
   ModuleSystem::NativesEnabledScope natives_enabled_scope(
       env()->module_system());
diff --git a/extensions/renderer/resources/async_waiter.js b/extensions/renderer/resources/async_waiter.js
deleted file mode 100644
index 6470f64b..0000000
--- a/extensions/renderer/resources/async_waiter.js
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-define('async_waiter', [
-    'mojo/public/js/support',
-], function(supportModule) {
-  /**
-   * @module async_waiter
-   */
-
-  /**
-   * @callback module:async_waiter.AsyncWaiter.Callback
-   * @param {number} result The result of waiting.
-   */
-
-  /**
-   * A waiter that waits for a handle to be ready for either reading or writing.
-   * @param {!MojoHandle} handle The handle to wait on.
-   * @param {number} signals The signals to wait for handle to be ready for.
-   * @param {module:async_waiter.AsyncWaiter.Callback} callback The callback to
-   *     call when handle is ready.
-   * @constructor
-   * @alias module:async_waiter.AsyncWaiter
-   */
-  function AsyncWaiter(handle, signals, callback) {
-    /**
-     * The handle to wait on.
-     * @type {!MojoHandle}
-     * @private
-     */
-    this.handle_ = handle;
-
-    /**
-     * The signals to wait for.
-     * @type {number}
-     * @private
-     */
-    this.signals_ = signals;
-
-    /**
-     * The callback to invoke when
-     * |[handle_]{@link module:async_waiter.AsyncWaiter#handle_}| is ready.
-     * @type {module:async_waiter.AsyncWaiter.Callback}
-     * @private
-     */
-    this.callback_ = callback;
-    this.id_ = null;
-  }
-
-  /**
-   * Start waiting for the handle to be ready.
-   * @throws Will throw if this is already waiting.
-   */
-  AsyncWaiter.prototype.start = function() {
-    if (this.id_)
-      throw new Error('Already started');
-    this.id_ = supportModule.asyncWait(
-        this.handle_, this.signals_, this.onHandleReady_.bind(this));
-  };
-
-  /**
-   * Stop waiting for the handle to be ready.
-   */
-  AsyncWaiter.prototype.stop = function() {
-    if (!this.id_)
-      return;
-
-    supportModule.cancelWait(this.id_);
-    this.id_ = null;
-  };
-
-  /**
-   * Returns whether this {@link AsyncWaiter} is waiting.
-   * @return {boolean} Whether this AsyncWaiter is waiting.
-   */
-  AsyncWaiter.prototype.isWaiting = function() {
-    return !!this.id_;
-  };
-
-  /**
-   * Invoked when |[handle_]{@link module:async_waiter.AsyncWaiter#handle_}| is
-   * ready.
-   * @param {number} result The result of the wait.
-   * @private
-   */
-  AsyncWaiter.prototype.onHandleReady_ = function(result) {
-    this.id_ = null;
-    this.callback_(result);
-  };
-
-  return {AsyncWaiter: AsyncWaiter};
-});
diff --git a/extensions/renderer/resources/extensions_renderer_resources.grd b/extensions/renderer/resources/extensions_renderer_resources.grd
index 01f1a14..e06a844 100644
--- a/extensions/renderer/resources/extensions_renderer_resources.grd
+++ b/extensions/renderer/resources/extensions_renderer_resources.grd
@@ -10,7 +10,6 @@
     <includes>
       <!-- Extension libraries. -->
       <include name="IDR_APP_VIEW_JS" file="guest_view/app_view/app_view.js" type="BINDATA" />
-      <include name="IDR_ASYNC_WAITER_JS" file="async_waiter.js" type="BINDATA" />
       <include name="IDR_BROWSER_TEST_ENVIRONMENT_SPECIFIC_BINDINGS_JS" file="browser_test_environment_specific_bindings.js" type="BINDATA" />
       <include name="IDR_ENTRY_ID_MANAGER" file="entry_id_manager.js" type="BINDATA" />
       <include name="IDR_EVENT_BINDINGS_JS" file="event.js" type="BINDATA" />
@@ -85,26 +84,6 @@
 
       <!-- Extension styles. -->
       <include name="IDR_EXTENSION_FONTS_CSS" file="extension_fonts.css" type="BINDATA"/>
-
-      <!-- Old Mojo JS bindings library. -->
-      <include name="IDR_MOJO_ASSOCIATED_BINDINGS_JS" file="../../../mojo/public/js/associated_bindings.js" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_MOJO_BINDINGS_JS_DEPRECATED" file="../../../mojo/public/js/bindings.js" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_MOJO_BUFFER_JS" file="../../../mojo/public/js/buffer.js" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_MOJO_CODEC_JS" file="../../../mojo/public/js/codec.js" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_MOJO_CONNECTOR_JS" file="../../../mojo/public/js/connector.js" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_MOJO_CONTROL_MESSAGE_HANDLER_JS" file="../../../mojo/public/js/lib/control_message_handler.js" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_MOJO_CONTROL_MESSAGE_PROXY_JS" file="../../../mojo/public/js/lib/control_message_proxy.js" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_MOJO_INTERFACE_CONTROL_MESSAGES_MOJOM_JS" file="${mojom_root}/mojo/public/interfaces/bindings/interface_control_messages.mojom.js" use_base_dir="false" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_MOJO_PIPE_CONTROL_MESSAGES_MOJOM_JS" file="${mojom_root}/mojo/public/interfaces/bindings/pipe_control_messages.mojom.js" use_base_dir="false" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_MOJO_INTERFACE_TYPES_JS" file="../../../mojo/public/js/interface_types.js" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_MOJO_ROUTER_JS" file="../../../mojo/public/js/router.js" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_MOJO_UNICODE_JS" file="../../../mojo/public/js/unicode.js" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_MOJO_VALIDATOR_JS" file="../../../mojo/public/js/validator.js" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_MOJO_INTERFACE_ENDPOINT_CLIENT_JS" file="../../../mojo/public/js/lib/interface_endpoint_client.js" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_MOJO_INTERFACE_ENDPOINT_HANDLE_JS" file="../../../mojo/public/js/lib/interface_endpoint_handle.js" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_MOJO_PIPE_CONTROL_MESSAGE_HANDLER_JS" file="../../../mojo/public/js/lib/pipe_control_message_handler.js" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_MOJO_PIPE_CONTROL_MESSAGE_PROXY_JS" file="../../../mojo/public/js/lib/pipe_control_message_proxy.js" flattenhtml="true" type="BINDATA" />
-
     </includes>
     <structures>
       <!-- Extension styles. -->
diff --git a/extensions/test/data/api_test_base_unittest.js b/extensions/test/data/api_test_base_unittest.js
deleted file mode 100644
index 334b938..0000000
--- a/extensions/test/data/api_test_base_unittest.js
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-var test = requireNative('apiGetter').get('test');
-var unittestBindings = require('test_environment_specific_bindings');
-
-unittestBindings.exportTests([
-  function testEnvironment() {
-    test.assertTrue(!!$Array);
-    test.assertTrue(!!$Function);
-    test.assertTrue(!!$JSON);
-    test.assertTrue(!!$Object);
-    test.assertTrue(!!$RegExp);
-    test.assertTrue(!!$String);
-    test.assertTrue(!!privates);
-    test.assertTrue(!!define);
-    test.assertTrue(!!require);
-    test.assertTrue(!!requireNative);
-    test.assertTrue(!!requireAsync);
-    test.assertEq(undefined, chrome.runtime.lastError);
-    // chrome.extension is defined at the //chrome layer, and so won't be
-    // available.
-    test.assertEq(undefined, chrome.extension);
-    test.succeed();
-  },
-  function testPromisesRun() {
-    Promise.resolve().then(test.callbackPass());
-  },
-  function testCommonModulesAreAvailable() {
-    var binding = bindingUtil || require('binding');
-    var sendRequest =
-        bindingUtil ? bindingUtil.sendRequest : require('sendRequest');
-    var lastError =
-        bindingUtil ? bindingUtil.setLastError : require('lastError');
-    test.assertTrue(!!binding);
-    test.assertTrue(!!sendRequest);
-    test.assertTrue(!!lastError);
-    test.succeed();
-  },
-  function testMojoModulesAreAvailable() {
-    Promise.all([
-      requireAsync('mojo/public/js/bindings'),
-      requireAsync('mojo/public/js/core'),
-      requireAsync('content/public/renderer/frame_interfaces'),
-    ]).then(test.callback(function(modules) {
-      var bindings = modules[0];
-      var core = modules[1];
-      var frameInterfaces = modules[2];
-      test.assertTrue(!!bindings.Binding);
-      test.assertTrue(!!core.createMessagePipe);
-      test.assertTrue(!!frameInterfaces.getInterface);
-    }));
-  },
-  function testTestBindings() {
-    var counter = 0;
-    function increment() {
-      counter++;
-    }
-    test.runWithUserGesture(increment);
-    test.runWithoutUserGesture(increment);
-    test.assertEq(2, counter);
-    test.assertFalse(test.isProcessingUserGesture());
-    test.assertTrue(!!test.getApiFeatures());
-    test.assertEq(0, test.getApiDefinitions().length);
-    test.succeed();
-  }
-], test.runTests, exports);
diff --git a/extensions/test/data/mojo_private_unittest.js b/extensions/test/data/mojo_private_unittest.js
deleted file mode 100644
index cfdc9db..0000000
--- a/extensions/test/data/mojo_private_unittest.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-'use strict';
-
-let getApi = requireNative('apiGetter').get;
-let mojoPrivate = getApi('mojoPrivate');
-let test = getApi('test');
-let unittestBindings = require('test_environment_specific_bindings');
-
-unittestBindings.exportTests([
-  function testRequireAsync() {
-    mojoPrivate.requireAsync('add').then(
-        test.callbackPass(function(add) {
-          test.assertEq('function', typeof add);
-        }));
-  },
-], test.runTests, exports);
diff --git a/extensions/test/data/unit_test_environment_specific_bindings.js b/extensions/test/data/unit_test_environment_specific_bindings.js
deleted file mode 100644
index e8d03dcc..0000000
--- a/extensions/test/data/unit_test_environment_specific_bindings.js
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-var sendRequestNatives = requireNative('sendRequest');
-
-function registerHooks(api) {
-  var apiFunctions = api.apiFunctions;
-
-  apiFunctions.setHandleRequest('notifyPass', function() {
-    requireAsync('testNatives').then(function(natives) {
-      natives.NotifyPass();
-    });
-  });
-
-  apiFunctions.setHandleRequest('notifyFail', function(message) {
-    requireAsync('testNatives').then(function(natives) {
-      natives.NotifyFail(message);
-    });
-  });
-
-  apiFunctions.setHandleRequest('log', function() {
-    requireAsync('testNatives').then(function(natives) {
-      natives.Log($Array.join(arguments, ' '));
-    });
-  });
-
-}
-
-function testDone(runNextTest) {
-    // Use a promise here to allow previous test contexts to be eligible for
-    // garbage collection.
-    Promise.resolve().then(function() {
-      runNextTest();
-    });
-}
-
-function exportTests(tests, runTests, exports) {
-  $Array.forEach(tests, function(test) {
-    exports[test.name] = function() {
-      runTests([test]);
-      return true;
-    };
-  });
-}
-
-/**
- * A fake implementation of setTimeout and clearTimeout.
- * @constructor
- */
-function TimeoutManager() {
-  this.timeouts_ = {};
-  this.nextTimeoutId_ = 0;
-  this.currentTime = 0;
-  this.autorunEnabled_ = false;
-}
-
-/**
- * Installs setTimeout and clearTimeout into the global object.
- */
-TimeoutManager.prototype.installGlobals = function() {
-  var global = sendRequestNatives.GetGlobal({});
-  global.setTimeout = this.setTimeout_.bind(this);
-  global.clearTimeout = this.clearTimeout_.bind(this);
-};
-
-/**
- * Starts auto-running of timeout callbacks. Until |numCallbacksToRun| callbacks
- * have run, any timeout callbacks set by calls to setTimeout (including before
- * the call to run) will cause the currentTime to be advanced to the time of
- * the timeout.
- */
-TimeoutManager.prototype.run = function(numCallbacksToRun) {
-  this.numCallbacksToRun_ = numCallbacksToRun;
-  Promise.resolve().then(this.autoRun_.bind(this));
-};
-
-/**
- * Runs timeout callbacks with earliest timeout.
- * @private
- */
-TimeoutManager.prototype.autoRun_ = function() {
-  if (this.numCallbacksToRun_ <= 0 || $Object.keys(this.timeouts_).length == 0)
-    return;
-
-  // Bucket the timeouts by their timeout time.
-  var timeoutsByTimeout = {};
-  var timeoutIds = $Object.keys(this.timeouts_);
-  for (var i = 0; i < timeoutIds.length; i++) {
-    var timeout = this.timeouts_[timeoutIds[i]];
-    var timeMs = timeout.timeMs;
-    if (!timeoutsByTimeout[timeMs])
-      timeoutsByTimeout[timeMs] = [];
-    timeoutsByTimeout[timeMs].push(timeout);
-  }
-  this.currentTime =
-      $Function.apply(Math.min, null, $Object.keys((timeoutsByTimeout)));
-  // Run all timeouts in the earliest timeout bucket.
-  var timeouts = timeoutsByTimeout[this.currentTime];
-  for (var i = 0; i < timeouts.length; i++) {
-    var currentTimeout = timeouts[i];
-    if (!this.timeouts_[currentTimeout.id])
-      continue;
-    this.numCallbacksToRun_--;
-    delete this.timeouts_[currentTimeout.id];
-    try {
-      currentTimeout.target();
-    } catch (e) {
-      console.log('error calling timeout target ' + e.stack);
-    }
-  }
-  // Continue running any later callbacks.
-  Promise.resolve().then(this.autoRun_.bind(this));
-};
-
-/**
- * A fake implementation of setTimeout. This does not support passing callback
- * arguments.
- * @private
- */
-TimeoutManager.prototype.setTimeout_ = function(target, timeoutMs) {
-  var timeoutId = this.nextTimeoutId_++;
-  this.timeouts_[timeoutId] = {
-    id: timeoutId,
-    target: target,
-    timeMs: timeoutMs + this.currentTime,
-  };
-  if (this.autorunEnabled_)
-    Promise.resolve().then(this.autoRun_.bind(this));
-  return timeoutId;
-};
-
-/**
- * A fake implementation of clearTimeout.
- * @private
- */
-TimeoutManager.prototype.clearTimeout_ = function(timeoutId) {
-  if (this.timeouts_[timeoutId])
-    delete this.timeouts_[timeoutId];
-};
-
-exports.registerHooks = registerHooks;
-exports.testDone = testDone;
-exports.exportTests = exportTests;
-exports.TimeoutManager = TimeoutManager;
diff --git a/gpu/ipc/client/gpu_in_process_context_tests.cc b/gpu/ipc/client/gpu_in_process_context_tests.cc
index dba3e7e..e0c7349b 100644
--- a/gpu/ipc/client/gpu_in_process_context_tests.cc
+++ b/gpu/ipc/client/gpu_in_process_context_tests.cc
@@ -36,15 +36,16 @@
     attributes.bind_generates_resource = false;
 
     auto context = gpu::GLInProcessContext::CreateWithoutInit();
-    auto result = context->Initialize(nullptr,                 /* service */
-                                      nullptr,                 /* surface */
-                                      true,                    /* offscreen */
-                                      gpu::kNullSurfaceHandle, /* window */
-                                      nullptr, /* share_context */
-                                      attributes, gpu::SharedMemoryLimits(),
-                                      gpu_memory_buffer_manager_.get(),
-                                      nullptr, /* image_factory */
-                                      base::ThreadTaskRunnerHandle::Get());
+    auto result = context->Initialize(
+        nullptr,                 /* service */
+        nullptr,                 /* surface */
+        true,                    /* offscreen */
+        gpu::kNullSurfaceHandle, /* window */
+        nullptr,                 /* share_context */
+        attributes, gpu::SharedMemoryLimits(), gpu_memory_buffer_manager_.get(),
+        nullptr, /* image_factory */
+        nullptr /* gpu_channel_manager_delegate */,
+        base::ThreadTaskRunnerHandle::Get());
     DCHECK_EQ(result, gpu::ContextResult::kSuccess);
     return context;
   }
diff --git a/gpu/ipc/gl_in_process_context.cc b/gpu/ipc/gl_in_process_context.cc
index 0f65c60c..a983202 100644
--- a/gpu/ipc/gl_in_process_context.cc
+++ b/gpu/ipc/gl_in_process_context.cc
@@ -63,6 +63,7 @@
       const SharedMemoryLimits& mem_limits,
       GpuMemoryBufferManager* gpu_memory_buffer_manager,
       ImageFactory* image_factory,
+      GpuChannelManagerDelegate* gpu_channel_manager_delegate,
       scoped_refptr<base::SingleThreadTaskRunner> task_runner) override;
   const gpu::Capabilities& GetCapabilities() const override;
   const gpu::GpuFeatureInfo& GetGpuFeatureInfo() const override;
@@ -157,6 +158,7 @@
     const SharedMemoryLimits& mem_limits,
     GpuMemoryBufferManager* gpu_memory_buffer_manager,
     ImageFactory* image_factory,
+    GpuChannelManagerDelegate* gpu_channel_manager_delegate,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
   // If a surface is provided, we are running in a webview and should not have
   // a task runner. We must have a task runner in all other cases.
@@ -183,7 +185,8 @@
 
   auto result = command_buffer_->Initialize(
       surface, is_offscreen, window, attribs, share_command_buffer,
-      gpu_memory_buffer_manager, image_factory, std::move(task_runner));
+      gpu_memory_buffer_manager, image_factory, gpu_channel_manager_delegate,
+      std::move(task_runner));
   if (result != gpu::ContextResult::kSuccess) {
     DLOG(ERROR) << "Failed to initialize InProcessCommmandBuffer";
     return result;
diff --git a/gpu/ipc/gl_in_process_context.h b/gpu/ipc/gl_in_process_context.h
index a21556e..d160b8da 100644
--- a/gpu/ipc/gl_in_process_context.h
+++ b/gpu/ipc/gl_in_process_context.h
@@ -11,8 +11,8 @@
 #include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "base/single_thread_task_runner.h"
-#include "gl_in_process_context_export.h"
 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/ipc/gl_in_process_context_export.h"
 #include "gpu/ipc/in_process_command_buffer.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/gl/gl_surface.h"
@@ -36,13 +36,14 @@
   static std::unique_ptr<GLInProcessContext> CreateWithoutInit();
 
   // Initialize the GLInProcessContext, if |is_offscreen| is true, renders to an
-  // offscreen context. |attrib_list| must be NULL or a NONE-terminated list
+  // offscreen context. |attrib_list| must be null or a NONE-terminated list
   // of attribute/value pairs.
-  // If |surface| is not NULL, then it must match |is_offscreen|,
+  // If |surface| is not null, then it must match |is_offscreen|,
   // |window| must be gfx::kNullAcceleratedWidget, and the command buffer
   // service must run on the same thread as this client because GLSurface is
-  // not thread safe. If |surface| is NULL, then the other parameters are used
+  // not thread safe. If |surface| is null, then the other parameters are used
   // to correctly create a surface.
+  // |gpu_channel_manager| should be non-null when used in the GPU process.
   virtual gpu::ContextResult Initialize(
       scoped_refptr<gpu::InProcessCommandBuffer::Service> service,
       scoped_refptr<gl::GLSurface> surface,
@@ -53,6 +54,7 @@
       const SharedMemoryLimits& memory_limits,
       GpuMemoryBufferManager* gpu_memory_buffer_manager,
       ImageFactory* image_factory,
+      GpuChannelManagerDelegate* gpu_channel_manager_delegate,
       scoped_refptr<base::SingleThreadTaskRunner> task_runner) = 0;
 
   virtual const gpu::Capabilities& GetCapabilities() const = 0;
diff --git a/gpu/ipc/in_process_command_buffer.cc b/gpu/ipc/in_process_command_buffer.cc
index 2f87686..6fd2adb 100644
--- a/gpu/ipc/in_process_command_buffer.cc
+++ b/gpu/ipc/in_process_command_buffer.cc
@@ -47,6 +47,7 @@
 #include "gpu/config/gpu_crash_keys.h"
 #include "gpu/config/gpu_feature_info.h"
 #include "gpu/ipc/gpu_in_process_thread_service.h"
+#include "gpu/ipc/service/gpu_channel_manager_delegate.h"
 #include "gpu/ipc/service/image_transport_surface.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gl/gl_context.h"
@@ -189,17 +190,6 @@
     const scoped_refptr<Service>& service)
     : command_buffer_id_(CommandBufferId::FromUnsafeValue(
           g_next_command_buffer_id.GetNext() + 1)),
-      delayed_work_pending_(false),
-      image_factory_(nullptr),
-      snapshot_requested_(false),
-      gpu_control_client_(nullptr),
-#if DCHECK_IS_ON()
-      context_lost_(false),
-#endif
-      last_put_offset_(-1),
-      gpu_memory_buffer_manager_(nullptr),
-      next_fence_sync_release_(1),
-      flushed_fence_sync_release_(0),
       flush_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
                    base::WaitableEvent::InitialState::NOT_SIGNALED),
       service_(GetInitialService(service)),
@@ -251,9 +241,13 @@
     InProcessCommandBuffer* share_group,
     GpuMemoryBufferManager* gpu_memory_buffer_manager,
     ImageFactory* image_factory,
+    GpuChannelManagerDelegate* gpu_channel_manager_delegate,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
   DCHECK(!share_group || service_.get() == share_group->service_.get());
 
+  gpu_memory_buffer_manager_ = gpu_memory_buffer_manager;
+  gpu_channel_manager_delegate_ = gpu_channel_manager_delegate;
+
   if (surface) {
     // If a surface is provided, we are running in a webview and should not have
     // a task runner.
@@ -285,8 +279,6 @@
                              &result, &completion));
   completion.Wait();
 
-  gpu_memory_buffer_manager_ = gpu_memory_buffer_manager;
-
   if (result == gpu::ContextResult::kSuccess)
     capabilities_ = capabilities;
 
@@ -1036,7 +1028,15 @@
 void InProcessCommandBuffer::DidCreateAcceleratedSurfaceChildWindow(
     SurfaceHandle parent_window,
     SurfaceHandle child_window) {
-  ::SetParent(child_window, parent_window);
+  // In the browser process call ::SetParent() directly.
+  if (!gpu_channel_manager_delegate_) {
+    ::SetParent(child_window, parent_window);
+    return;
+  }
+
+  // In the GPU process forward the request back to the browser process.
+  gpu_channel_manager_delegate_->SendAcceleratedSurfaceCreatedChildWindow(
+      parent_window, child_window);
 }
 #endif
 
diff --git a/gpu/ipc/in_process_command_buffer.h b/gpu/ipc/in_process_command_buffer.h
index 1d2cd3fab..9067cb6b 100644
--- a/gpu/ipc/in_process_command_buffer.h
+++ b/gpu/ipc/in_process_command_buffer.h
@@ -72,6 +72,7 @@
 class ShaderTranslatorCache;
 }
 
+class GpuChannelManagerDelegate;
 class GpuMemoryBufferManager;
 class ImageFactory;
 class TransferBufferManager;
@@ -94,6 +95,8 @@
   // If |surface| is not null, use it directly; in this case, the command
   // buffer gpu thread must be the same as the client thread. Otherwise create
   // a new GLSurface.
+  // |gpu_channel_manager_delegate| should be non-null when the command buffer
+  // is used in the GPU process for compositor to gpu thread communication.
   gpu::ContextResult Initialize(
       scoped_refptr<gl::GLSurface> surface,
       bool is_offscreen,
@@ -102,6 +105,7 @@
       InProcessCommandBuffer* share_group,
       GpuMemoryBufferManager* gpu_memory_buffer_manager,
       ImageFactory* image_factory,
+      GpuChannelManagerDelegate* gpu_channel_manager_delegate,
       scoped_refptr<base::SingleThreadTaskRunner> task_runner);
 
   // CommandBuffer implementation:
@@ -339,24 +343,25 @@
   scoped_refptr<SyncPointClientState> sync_point_client_state_;
   base::Closure context_lost_callback_;
   // Used to throttle PerformDelayedWorkOnGpuThread.
-  bool delayed_work_pending_;
-  ImageFactory* image_factory_;
+  bool delayed_work_pending_ = false;
+  ImageFactory* image_factory_ = nullptr;
+  GpuChannelManagerDelegate* gpu_channel_manager_delegate_ = nullptr;
 
   base::Closure snapshot_requested_callback_;
-  bool snapshot_requested_;
+  bool snapshot_requested_ = false;
 
   // Members accessed on the client thread:
-  GpuControlClient* gpu_control_client_;
+  GpuControlClient* gpu_control_client_ = nullptr;
 #if DCHECK_IS_ON()
-  bool context_lost_;
+  bool context_lost_ = false;
 #endif
   State last_state_;
   base::Lock last_state_lock_;
-  int32_t last_put_offset_;
+  int32_t last_put_offset_ = -1;
   Capabilities capabilities_;
-  GpuMemoryBufferManager* gpu_memory_buffer_manager_;
-  uint64_t next_fence_sync_release_;
-  uint64_t flushed_fence_sync_release_;
+  GpuMemoryBufferManager* gpu_memory_buffer_manager_ = nullptr;
+  uint64_t next_fence_sync_release_ = 1;
+  uint64_t flushed_fence_sync_release_ = 0;
 
   // Accessed on both threads:
   std::unique_ptr<CommandBufferService> command_buffer_;
diff --git a/headless/test/headless_render_browsertest.cc b/headless/test/headless_render_browsertest.cc
index dac8b52..a8759c0 100644
--- a/headless/test/headless_render_browsertest.cc
+++ b/headless/test/headless_render_browsertest.cc
@@ -139,6 +139,10 @@
   return arg.second == expected;
 }
 
+MATCHER_P(CookieValue, expected, "") {
+  return arg->GetValue() == expected;
+}
+
 const DOMNode* FindTag(const GetSnapshotResult* snapshot, const char* name) {
   auto tags = FindTags(snapshot, name);
   if (tags.empty())
@@ -875,4 +879,112 @@
 };
 HEADLESS_RENDER_BROWSERTEST(RedirectNewFragment);
 
+class WindowLocationFragments : public HeadlessRenderTest {
+ private:
+  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
+    GetProtocolHandler()->InsertResponse("http://www.example.com/#fragment1",
+                                         HttpOk(R"|(
+ <script>
+   if (window.location.hash == '#fragment1') {
+     document.write('<iframe src="iframe#fragment2"></iframe>');
+   }
+ </script>)|"));
+    GetProtocolHandler()->InsertResponse(
+        "http://www.example.com/iframe#fragment2", HttpOk(R"|(
+ <script>
+   if (window.location.hash == '#fragment2') {
+     document.location = 'http://www.example.com/pass';
+   }
+ </script>)|"));
+    GetProtocolHandler()->InsertResponse("http://www.example.com/pass",
+                                         HttpOk("<p>Pass</p>"));
+    return GURL("http://www.example.com/#fragment1");
+  }
+
+  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
+    EXPECT_THAT(GetProtocolHandler()->urls_requested(),
+                ElementsAre("http://www.example.com/#fragment1",
+                            "http://www.example.com/iframe#fragment2",
+                            "http://www.example.com/pass"));
+    EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "P")),
+                NodeValue("Pass"));
+  }
+};
+HEADLESS_RENDER_BROWSERTEST(WindowLocationFragments);
+
+class CookieSetFromJs : public HeadlessRenderTest {
+ private:
+  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
+    GetProtocolHandler()->InsertResponse("http://www.example.com/", HttpOk(R"|(
+<html><head><script>
+document.cookie = 'SessionID=123';
+n = document.cookie.indexOf('SessionID');
+if (n < 0) {
+  top.location = '/epicfail';
+}
+</script></head><body>Pass</body></html>)|"));
+    return GURL("http://www.example.com/");
+  }
+
+  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
+    EXPECT_THAT(GetProtocolHandler()->urls_requested(),
+                ElementsAre("http://www.example.com/"));
+    EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "BODY")),
+                NodeValue("Pass"));
+  }
+};
+HEADLESS_RENDER_BROWSERTEST(CookieSetFromJs);
+
+class CookieSetFromJs_NoCookies : public CookieSetFromJs {
+ private:
+  void OverrideWebPreferences(WebPreferences* preferences) override {
+    HeadlessRenderTest::OverrideWebPreferences(preferences);
+    preferences->cookie_enabled = false;
+  }
+
+  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
+    EXPECT_THAT(GetProtocolHandler()->urls_requested(),
+                ElementsAre("http://www.example.com/",
+                            "http://www.example.com/epicfail"));
+  }
+};
+HEADLESS_RENDER_BROWSERTEST(CookieSetFromJs_NoCookies);
+
+class CookieUpdatedFromJs : public HeadlessRenderTest {
+ private:
+  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
+    client->GetNetwork()->SetCookie(network::SetCookieParams::Builder()
+                                        .SetUrl("http://www.example.com/")
+                                        .SetName("foo")
+                                        .SetValue("bar")
+                                        .Build());
+    GetProtocolHandler()->InsertResponse("http://www.example.com/", HttpOk(R"|(
+<html><head><script>
+var x = document.cookie;
+document.cookie = x + 'baz';
+</script></head><body>Pass</body></html>)|"));
+    return GURL("http://www.example.com/");
+  }
+
+  void OnPageRenderCompleted() override {
+    devtools_client_->GetNetwork()->GetCookies(
+        network::GetCookiesParams::Builder()
+            .SetUrls({"http://www.example.com/"})
+            .Build(),
+        base::Bind(&CookieUpdatedFromJs::OnGetCookies, base::Unretained(this)));
+  }
+
+  void OnGetCookies(std::unique_ptr<network::GetCookiesResult> result) {
+    const auto& cookies = *result->GetCookies();
+    EXPECT_THAT(cookies, ElementsAre(CookieValue("barbaz")));
+    HeadlessRenderTest::OnPageRenderCompleted();
+  }
+
+  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
+    EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "BODY")),
+                NodeValue("Pass"));
+  }
+};
+HEADLESS_RENDER_BROWSERTEST(CookieUpdatedFromJs);
+
 }  // namespace headless
diff --git a/ios/chrome/browser/ui/BUILD.gn b/ios/chrome/browser/ui/BUILD.gn
index 443d811..b17b573 100644
--- a/ios/chrome/browser/ui/BUILD.gn
+++ b/ios/chrome/browser/ui/BUILD.gn
@@ -316,11 +316,14 @@
     "//ios/chrome/browser/ui/first_run",
     "//ios/chrome/browser/ui/fullscreen",
     "//ios/chrome/browser/ui/fullscreen:legacy_fullscreen",
+    "//ios/chrome/browser/ui/fullscreen:new_fullscreen",
     "//ios/chrome/browser/ui/history",
     "//ios/chrome/browser/ui/history_popup:coordinator",
     "//ios/chrome/browser/ui/history_popup/requirements",
     "//ios/chrome/browser/ui/keyboard",
     "//ios/chrome/browser/ui/main:feature_flags",
+    "//ios/chrome/browser/ui/main_content:main_content_ui",
+    "//ios/chrome/browser/ui/main_content:main_content_ui_broadcasting_util",
     "//ios/chrome/browser/ui/ntp",
     "//ios/chrome/browser/ui/ntp:modal_ntp",
     "//ios/chrome/browser/ui/ntp:ntp_controller",
@@ -346,6 +349,7 @@
     "//ios/chrome/browser/ui/tabs:coordinator",
     "//ios/chrome/browser/ui/tabs/requirements",
     "//ios/chrome/browser/ui/toolbar:toolbar_ui",
+    "//ios/chrome/browser/ui/toolbar:toolbar_ui_broadcasting_util",
     "//ios/chrome/browser/ui/toolbar/public:toolbar_base_feature",
     "//ios/chrome/browser/ui/tools_menu",
     "//ios/chrome/browser/ui/tools_menu:configuration",
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
index fe9ad46..a1de2aa4 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
@@ -559,6 +559,10 @@
   }
 }
 
+- (BOOL)isAtTopOfNavigation:(BookmarkTableView*)view {
+  return (self.navigationController.topViewController == self);
+}
+
 #pragma mark - BookmarkFolderViewControllerDelegate
 
 - (void)folderPicker:(BookmarkFolderViewController*)folderPicker
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_table_view.h b/ios/chrome/browser/ui/bookmarks/bookmark_table_view.h
index b8cd267..6e278c5 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_table_view.h
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_table_view.h
@@ -64,6 +64,9 @@
 // Tells the delegate to refresh the context bar.
 - (void)bookmarkTableViewRefreshContextBar:(BookmarkTableView*)view;
 
+// Returns true if this table is at the top of the navigation stack.
+- (BOOL)isAtTopOfNavigation:(BookmarkTableView*)view;
+
 @end
 
 @interface BookmarkTableView : UIView
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_table_view.mm b/ios/chrome/browser/ui/bookmarks/bookmark_table_view.mm
index f88390d2..05797f1 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_table_view.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_table_view.mm
@@ -42,6 +42,9 @@
 
 // Cell height, in points.
 CGFloat kCellHeightPt = 56.0;
+
+// Minimium spacing between keyboard and the titleText when creating new folder.
+CGFloat keyboardSpacing = 16.0;
 }
 
 using bookmarks::BookmarkNode;
@@ -937,21 +940,32 @@
 
 // Called when the UIKeyboardDidShowNotification is sent
 - (void)keyboardWasShown:(NSNotification*)aNotification {
+  if (![self.delegate isAtTopOfNavigation:self]) {
+    return;
+  }
   NSDictionary* info = [aNotification userInfo];
-  CGSize kbSize =
-      [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
+  CGFloat keyboardTop =
+      [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].origin.y;
+  CGFloat tableBottom =
+      CGRectGetMaxY([self convertRect:self.tableView.frame toView:nil]);
+  CGFloat shiftY = tableBottom - keyboardTop + keyboardSpacing;
 
-  UIEdgeInsets previousContentInsets = self.tableView.contentInset;
-  // Shift the content inset by the height of the keyboard so we can scoll to
-  // the bottom of the content that is potentially behind the keyboard.
-  UIEdgeInsets contentInsets =
-      UIEdgeInsetsMake(previousContentInsets.top, 0.0, kbSize.height, 0.0);
-  self.tableView.contentInset = contentInsets;
-  self.tableView.scrollIndicatorInsets = contentInsets;
+  if (shiftY >= 0) {
+    UIEdgeInsets previousContentInsets = self.tableView.contentInset;
+    // Shift the content inset to prevent the editing content from being hidden
+    // by the keyboard.
+    UIEdgeInsets contentInsets =
+        UIEdgeInsetsMake(previousContentInsets.top, 0.0, shiftY, 0.0);
+    self.tableView.contentInset = contentInsets;
+    self.tableView.scrollIndicatorInsets = contentInsets;
+  }
 }
 
 // Called when the UIKeyboardWillHideNotification is sent
 - (void)keyboardWillBeHidden:(NSNotification*)aNotification {
+  if (![self.delegate isAtTopOfNavigation:self]) {
+    return;
+  }
   UIEdgeInsets previousContentInsets = self.tableView.contentInset;
   // Restore the content inset now that the keyboard has been hidden.
   UIEdgeInsets contentInsets =
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index 04f67b39..d12f3f5 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -143,6 +143,8 @@
 #import "ios/chrome/browser/ui/external_search/external_search_coordinator.h"
 #import "ios/chrome/browser/ui/find_bar/find_bar_controller_ios.h"
 #import "ios/chrome/browser/ui/first_run/welcome_to_chrome_view_controller.h"
+#import "ios/chrome/browser/ui/fullscreen/fullscreen_controller.h"
+#import "ios/chrome/browser/ui/fullscreen/fullscreen_controller_factory.h"
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_features.h"
 #import "ios/chrome/browser/ui/fullscreen/legacy_fullscreen_controller.h"
 #import "ios/chrome/browser/ui/history_popup/requirements/tab_history_presentation.h"
@@ -150,6 +152,10 @@
 #import "ios/chrome/browser/ui/key_commands_provider.h"
 #import "ios/chrome/browser/ui/location_bar_notification_names.h"
 #import "ios/chrome/browser/ui/main/main_feature_flags.h"
+#import "ios/chrome/browser/ui/main_content/main_content_ui.h"
+#import "ios/chrome/browser/ui/main_content/main_content_ui_broadcasting_util.h"
+#import "ios/chrome/browser/ui/main_content/main_content_ui_state.h"
+#import "ios/chrome/browser/ui/main_content/web_scroll_view_main_content_ui_forwarder.h"
 #import "ios/chrome/browser/ui/ntp/modal_ntp.h"
 #import "ios/chrome/browser/ui/ntp/new_tab_page_controller.h"
 #import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_handset_coordinator.h"
@@ -184,6 +190,7 @@
 #include "ios/chrome/browser/ui/toolbar/toolbar_model_ios.h"
 #import "ios/chrome/browser/ui/toolbar/toolbar_snapshot_providing.h"
 #import "ios/chrome/browser/ui/toolbar/toolbar_ui.h"
+#import "ios/chrome/browser/ui/toolbar/toolbar_ui_broadcasting_util.h"
 #import "ios/chrome/browser/ui/toolbar/web_toolbar_controller.h"
 #import "ios/chrome/browser/ui/tools_menu/public/tools_menu_configuration_provider.h"
 #import "ios/chrome/browser/ui/tools_menu/public/tools_menu_presentation_provider.h"
@@ -393,6 +400,7 @@
                                     InfobarContainerStateDelegate,
                                     KeyCommandsPlumbing,
                                     NetExportTabHelperDelegate,
+                                    MainContentUI,
                                     ManageAccountsDelegate,
                                     MFMailComposeViewControllerDelegate,
                                     NewTabPageControllerObserver,
@@ -573,6 +581,12 @@
   // The toolbar UI updater for the toolbar managed by |_toolbarCoordinator|.
   LegacyToolbarUIUpdater* _toolbarUIUpdater;
 
+  // The main content UI updater for the content displayed by this BVC.
+  MainContentUIStateUpdater* _mainContentUIUpdater;
+
+  // The forwarder for web scroll view interation events.
+  WebScrollViewMainContentUIForwarder* _webMainContentUIForwarder;
+
   // Coordinator for the External Search UI.
   ExternalSearchCoordinator* _externalSearchCoordinator;
 
@@ -606,6 +620,8 @@
 // Whether the controller's view is currently visible.
 // YES from viewDidAppear to viewWillDisappear.
 @property(nonatomic, assign) BOOL viewVisible;
+// Whether the controller should broadcast its UI.
+@property(nonatomic, assign, getter=isBroadcasting) BOOL broadcasting;
 // Whether the controller is currently dismissing a presented view controller.
 @property(nonatomic, assign, getter=isDismissingModal) BOOL dismissingModal;
 // Returns YES if the toolbar has not been scrolled out by fullscreen.
@@ -732,9 +748,9 @@
 - (UIImageView*)pageFullScreenOpenCloseAnimationView;
 // Updates the toolbar display based on the current tab.
 - (void)updateToolbar;
-// Starts or stops broadcasting the toolbar UI depending on whether the BVC is
-// visible and active.
-- (void)updateToolbarBroadcastState;
+// Starts or stops broadcasting the toolbar UI and main content UI depending on
+// whether the BVC is visible and active.
+- (void)updateBroadcastState;
 // Updates |dialogPresenter|'s |active| property to account for the BVC's
 // |active|, |visible|, and |inNewTabAnimation| properties.
 - (void)updateDialogPresenterActiveState;
@@ -909,6 +925,7 @@
 @synthesize active = _active;
 @synthesize visible = _visible;
 @synthesize viewVisible = _viewVisible;
+@synthesize broadcasting = _broadcasting;
 @synthesize dismissingModal = _dismissingModal;
 @synthesize hideStatusBar = _hideStatusBar;
 @synthesize activityOverlayCoordinator = _activityOverlayCoordinator;
@@ -1044,7 +1061,7 @@
 
   [_model setWebUsageEnabled:active];
   [self updateDialogPresenterActiveState];
-  [self updateToolbarBroadcastState];
+  [self updateBroadcastState];
 
   if (active) {
     // Make sure the tab (if any; it's possible to get here without a current
@@ -1068,7 +1085,7 @@
   [_model setPrimary:primary];
   if (primary) {
     [self updateDialogPresenterActiveState];
-    [self updateToolbarBroadcastState];
+    [self updateBroadcastState];
   } else {
     self.dialogPresenter.active = false;
   }
@@ -1155,7 +1172,42 @@
   _viewVisible = viewVisible;
   self.visible = viewVisible;
   [self updateDialogPresenterActiveState];
-  [self updateToolbarBroadcastState];
+  [self updateBroadcastState];
+}
+
+- (void)setBroadcasting:(BOOL)broadcasting {
+  if (_broadcasting == broadcasting)
+    return;
+  _broadcasting = broadcasting;
+  if (base::FeatureList::IsEnabled(fullscreen::features::kNewFullscreen)) {
+    // TODO(crbug.com/790886): Use the Browser's broadcaster once Browsers are
+    // supported.
+    ChromeBroadcaster* broadcaster = FullscreenControllerFactory::GetInstance()
+                                         ->GetForBrowserState(_browserState)
+                                         ->broadcaster();
+    if (_broadcasting) {
+      _toolbarUIUpdater = [[LegacyToolbarUIUpdater alloc]
+          initWithToolbarUI:[[ToolbarUIState alloc] init]
+               toolbarOwner:self
+               webStateList:[_model webStateList]];
+      [_toolbarUIUpdater startUpdating];
+      StartBroadcastingToolbarUI(_toolbarUIUpdater.toolbarUI, broadcaster);
+      _mainContentUIUpdater = [[MainContentUIStateUpdater alloc]
+          initWithState:[[MainContentUIState alloc] init]];
+      _webMainContentUIForwarder = [[WebScrollViewMainContentUIForwarder alloc]
+          initWithUpdater:_mainContentUIUpdater
+             webStateList:[_model webStateList]];
+      StartBroadcastingMainContentUI(self, broadcaster);
+    } else {
+      StopBroadcastingToolbarUI(broadcaster);
+      StopBroadcastingMainContentUI(broadcaster);
+      [_toolbarUIUpdater stopUpdating];
+      _toolbarUIUpdater = nil;
+      _mainContentUIUpdater = nil;
+      [_webMainContentUIForwarder disconnect];
+      _webMainContentUIForwarder = nil;
+    }
+  }
 }
 
 - (BOOL)isToolbarOnScreen {
@@ -1167,7 +1219,7 @@
     return;
   _inNewTabAnimation = inNewTabAnimation;
   [self updateDialogPresenterActiveState];
-  [self updateToolbarBroadcastState];
+  [self updateBroadcastState];
 }
 
 - (BOOL)isInNewTabAnimation {
@@ -1276,7 +1328,7 @@
   [super viewDidAppear:animated];
   self.viewVisible = YES;
   [self updateDialogPresenterActiveState];
-  [self updateToolbarBroadcastState];
+  [self updateBroadcastState];
 
   // |viewDidAppear| can be called after |browserState| is destroyed. Since
   // |presentBubblesIfEligible| requires that |self.browserState| is not NULL,
@@ -1310,7 +1362,7 @@
 - (void)viewWillDisappear:(BOOL)animated {
   self.viewVisible = NO;
   [self updateDialogPresenterActiveState];
-  [self updateToolbarBroadcastState];
+  [self updateBroadcastState];
   [[_model currentTab] wasHidden];
   [_bookmarkInteractionController dismissSnackbar];
   if (IsIPadIdiom() && _infoBarContainer) {
@@ -1866,7 +1918,7 @@
   [_dispatcher startDispatchingToTarget:_toolbarCoordinator
                             forProtocol:@protocol(OmniboxFocuser)];
   [_toolbarCoordinator setTabCount:[_model count]];
-  [self updateToolbarBroadcastState];
+  [self updateBroadcastState];
   if (_voiceSearchController)
     _voiceSearchController->SetDelegate(
         [_toolbarCoordinator voiceSearchDelegate]);
@@ -2124,22 +2176,9 @@
   }
 }
 
-- (void)updateToolbarBroadcastState {
-  BOOL shouldBroadcast =
+- (void)updateBroadcastState {
+  self.broadcasting =
       self.active && self.viewVisible && !self.inNewTabAnimation;
-  BOOL broadcasting = _toolbarUIUpdater != nil;
-  if (shouldBroadcast == broadcasting)
-    return;
-  if (shouldBroadcast) {
-    _toolbarUIUpdater = [[LegacyToolbarUIUpdater alloc]
-        initWithToolbarUI:[[ToolbarUIState alloc] init]
-             toolbarOwner:self
-             webStateList:[_model webStateList]];
-    [_toolbarUIUpdater startUpdating];
-  } else {
-    [_toolbarUIUpdater stopUpdating];
-    _toolbarUIUpdater = nil;
-  }
 }
 
 - (void)updateDialogPresenterActiveState {
@@ -3899,6 +3938,12 @@
   [_toolbarCoordinator focusOmnibox];
 }
 
+#pragma mark - MainContentUI
+
+- (MainContentUIState*)mainContentUIState {
+  return _mainContentUIUpdater.state;
+}
+
 #pragma mark - UIResponder
 
 - (NSArray*)keyCommands {
diff --git a/ios/chrome/browser/ui/main_content/BUILD.gn b/ios/chrome/browser/ui/main_content/BUILD.gn
index 482dbf32..4ac3e6d8 100644
--- a/ios/chrome/browser/ui/main_content/BUILD.gn
+++ b/ios/chrome/browser/ui/main_content/BUILD.gn
@@ -24,6 +24,8 @@
     "main_content_ui.h",
     "main_content_ui_state.h",
     "main_content_ui_state.mm",
+    "web_scroll_view_main_content_ui_forwarder.h",
+    "web_scroll_view_main_content_ui_forwarder.mm",
   ]
 
   configs += [ "//build/config/compiler:enable_arc" ]
@@ -32,6 +34,8 @@
     "//base",
     "//ios/chrome/browser/ui:ui_util",
     "//ios/chrome/browser/ui/broadcaster",
+    "//ios/chrome/browser/web_state_list",
+    "//ios/web/public",
   ]
 }
 
diff --git a/ios/chrome/browser/ui/main_content/web_scroll_view_main_content_ui_forwarder.h b/ios/chrome/browser/ui/main_content/web_scroll_view_main_content_ui_forwarder.h
new file mode 100644
index 0000000..73d382aa
--- /dev/null
+++ b/ios/chrome/browser/ui/main_content/web_scroll_view_main_content_ui_forwarder.h
@@ -0,0 +1,31 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_MAIN_CONTENT_WEB_SCROLL_VIEW_MAIN_CONTENT_UI_FORWARDER_H_
+#define IOS_CHROME_BROWSER_UI_MAIN_CONTENT_WEB_SCROLL_VIEW_MAIN_CONTENT_UI_FORWARDER_H_
+
+#import <Foundation/Foundation.h>
+
+@class MainContentUIStateUpdater;
+class WebStateList;
+
+// Helper object that forwards a CRWWebViewScrollViewProxy events to a
+// MainContentUIStateUpdater.
+@interface WebScrollViewMainContentUIForwarder : NSObject
+
+// Designated initializer for a forwarder that sends the scroll events from
+// |webStateList|'s active WebState's scroll view proxy to |updater|.
+- (nullable instancetype)initWithUpdater:
+                             (nonnull MainContentUIStateUpdater*)updater
+                            webStateList:(nonnull WebStateList*)webStateList
+    NS_DESIGNATED_INITIALIZER;
+- (nullable instancetype)init NS_UNAVAILABLE;
+
+// Instructs the forwarder to stop observing the WebStateList and the active
+// WebState's scroll view proxy.
+- (void)disconnect;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_MAIN_CONTENT_WEB_SCROLL_VIEW_MAIN_CONTENT_UI_FORWARDER_H_
diff --git a/ios/chrome/browser/ui/main_content/web_scroll_view_main_content_ui_forwarder.mm b/ios/chrome/browser/ui/main_content/web_scroll_view_main_content_ui_forwarder.mm
new file mode 100644
index 0000000..c8d3897e
--- /dev/null
+++ b/ios/chrome/browser/ui/main_content/web_scroll_view_main_content_ui_forwarder.mm
@@ -0,0 +1,117 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/main_content/web_scroll_view_main_content_ui_forwarder.h"
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#import "ios/chrome/browser/ui/main_content/main_content_ui_state.h"
+#import "ios/chrome/browser/web_state_list/web_state_list.h"
+#import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h"
+#import "ios/web/public/web_state/ui/crw_web_view_proxy.h"
+#import "ios/web/public/web_state/ui/crw_web_view_scroll_view_proxy.h"
+#import "ios/web/public/web_state/web_state.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@interface WebScrollViewMainContentUIForwarder ()<
+    CRWWebViewScrollViewProxyObserver,
+    WebStateListObserving> {
+  // The observer bridge.
+  std::unique_ptr<WebStateListObserver> _bridge;
+}
+
+// The updater being driven by this object.
+@property(nonatomic, readonly, strong) MainContentUIStateUpdater* updater;
+// The WebStateList whose active WebState's scroll state is being forwaded.
+@property(nonatomic, readonly) WebStateList* webStateList;
+// The scroll view proxy whose scroll events are forwarded to |updater|.
+@property(nonatomic, readonly, strong) CRWWebViewScrollViewProxy* proxy;
+@end
+
+@implementation WebScrollViewMainContentUIForwarder
+@synthesize updater = _updater;
+@synthesize webStateList = _webStateList;
+@synthesize proxy = _proxy;
+
+- (instancetype)initWithUpdater:(MainContentUIStateUpdater*)updater
+                   webStateList:(WebStateList*)webStateList {
+  if (self = [super init]) {
+    _updater = updater;
+    DCHECK(_updater);
+    _webStateList = webStateList;
+    DCHECK(_webStateList);
+    _bridge = base::MakeUnique<WebStateListObserverBridge>(self);
+    _webStateList->AddObserver(_bridge.get());
+    web::WebState* activeWebState = webStateList->GetActiveWebState();
+    if (activeWebState) {
+      _proxy = activeWebState->GetWebViewProxy().scrollViewProxy;
+      [_proxy addObserver:self];
+    }
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self disconnect];
+}
+
+#pragma mark Accessors
+
+- (void)setProxy:(CRWWebViewScrollViewProxy*)proxy {
+  if (_proxy == proxy)
+    return;
+  [_proxy removeObserver:self];
+  _proxy = proxy;
+  [_proxy addObserver:self];
+}
+
+#pragma mark Public
+
+- (void)disconnect {
+  self.webStateList->RemoveObserver(_bridge.get());
+  _bridge = nullptr;
+  self.proxy = nil;
+}
+
+#pragma mark CRWWebViewScrollViewObserver
+
+- (void)webViewScrollViewDidScroll:
+    (CRWWebViewScrollViewProxy*)webViewScrollViewProxy {
+  [self.updater scrollViewDidScrollToOffset:self.proxy.contentOffset];
+}
+
+- (void)webViewScrollViewWillBeginDragging:
+    (CRWWebViewScrollViewProxy*)webViewScrollViewProxy {
+  [self.updater
+      scrollViewWillBeginDraggingWithGesture:self.proxy.panGestureRecognizer];
+}
+
+- (void)webViewScrollViewWillEndDragging:
+            (CRWWebViewScrollViewProxy*)webViewScrollViewProxy
+                            withVelocity:(CGPoint)velocity
+                     targetContentOffset:(inout CGPoint*)targetContentOffset {
+  [self.updater
+      scrollViewDidEndDraggingWithGesture:self.proxy.panGestureRecognizer
+                         residualVelocity:velocity];
+}
+
+- (void)webViewScrollViewDidEndDecelerating:
+    (CRWWebViewScrollViewProxy*)webViewScrollViewProxy {
+  [self.updater scrollViewDidEndDecelerating];
+}
+
+#pragma mark - WebStateListObserving
+
+- (void)webStateList:(WebStateList*)webStateList
+    didChangeActiveWebState:(web::WebState*)newWebState
+                oldWebState:(web::WebState*)oldWebState
+                    atIndex:(int)atIndex
+                 userAction:(BOOL)userAction {
+  self.proxy = newWebState->GetWebViewProxy().scrollViewProxy;
+}
+
+@end
diff --git a/media/blink/cdm_result_promise_helper.cc b/media/blink/cdm_result_promise_helper.cc
index b65a2247..93dd4da7 100644
--- a/media/blink/cdm_result_promise_helper.cc
+++ b/media/blink/cdm_result_promise_helper.cc
@@ -5,7 +5,7 @@
 #include "media/blink/cdm_result_promise_helper.h"
 
 #include "base/logging.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_functions.h"
 
 namespace media {
 
@@ -69,12 +69,7 @@
   if (uma_name.empty())
     return;
 
-  base::LinearHistogram::FactoryGet(
-      uma_name,
-      1,
-      NUM_RESULT_CODES,
-      NUM_RESULT_CODES + 1,
-      base::HistogramBase::kUmaTargetedHistogramFlag)->Add(result);
+  base::UmaHistogramEnumeration(uma_name, result, NUM_RESULT_CODES);
 }
 
 }  // namespace media
diff --git a/media/blink/webencryptedmediaclient_impl.cc b/media/blink/webencryptedmediaclient_impl.cc
index c907360..5a0e760 100644
--- a/media/blink/webencryptedmediaclient_impl.cc
+++ b/media/blink/webencryptedmediaclient_impl.cc
@@ -8,7 +8,7 @@
 
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "media/base/key_systems.h"
@@ -72,12 +72,8 @@
 
  private:
   void Report(KeySystemSupportStatus status) {
-    // Not using UMA_HISTOGRAM_ENUMERATION directly because UMA_* macros
-    // require the names to be constant throughout the process' lifetime.
-    base::LinearHistogram::FactoryGet(
-        uma_name_, 1, KEY_SYSTEM_SUPPORT_STATUS_COUNT,
-        KEY_SYSTEM_SUPPORT_STATUS_COUNT + 1,
-        base::Histogram::kUmaTargetedHistogramFlag)->Add(status);
+    base::UmaHistogramEnumeration(uma_name_, status,
+                                  KEY_SYSTEM_SUPPORT_STATUS_COUNT);
   }
 
   const std::string uma_name_;
diff --git a/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java b/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java
index 90029c48..0063308a 100644
--- a/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java
+++ b/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java
@@ -317,46 +317,60 @@
                 this.fd = mPfd.getFileDescriptor();
             }
 
+            @Override
             protected void accept(SocketImpl s) {
                 throw new RuntimeException("accept not implemented");
             }
+            @Override
             protected int available() {
                 throw new RuntimeException("accept not implemented");
             }
+            @Override
             protected void bind(InetAddress host, int port) {
                 throw new RuntimeException("accept not implemented");
             }
+            @Override
             protected void close() {
                 // Detach from |fd| to avoid leak detection false positives without closing |fd|.
                 mPfd.detachFd();
             }
+            @Override
             protected void connect(InetAddress address, int port) {
                 throw new RuntimeException("connect not implemented");
             }
+            @Override
             protected void connect(SocketAddress address, int timeout) {
                 throw new RuntimeException("connect not implemented");
             }
+            @Override
             protected void connect(String host, int port) {
                 throw new RuntimeException("connect not implemented");
             }
+            @Override
             protected void create(boolean stream) {
                 throw new RuntimeException("create not implemented");
             }
+            @Override
             protected InputStream getInputStream() {
                 throw new RuntimeException("getInputStream not implemented");
             }
+            @Override
             protected OutputStream getOutputStream() {
                 throw new RuntimeException("getOutputStream not implemented");
             }
+            @Override
             protected void listen(int backlog) {
                 throw new RuntimeException("listen not implemented");
             }
+            @Override
             protected void sendUrgentData(int data) {
                 throw new RuntimeException("sendUrgentData not implemented");
             }
+            @Override
             public Object getOption(int optID) {
                 throw new RuntimeException("getOption not implemented");
             }
+            @Override
             public void setOption(int optID, Object value) {
                 throw new RuntimeException("setOption not implemented");
             }
diff --git a/services/device/geolocation/BUILD.gn b/services/device/geolocation/BUILD.gn
index cdb97071..648d52a 100644
--- a/services/device/geolocation/BUILD.gn
+++ b/services/device/geolocation/BUILD.gn
@@ -8,6 +8,8 @@
   visibility = [ "//services/device:*" ]
 
   sources = [
+    "public_ip_address_geolocation_provider.cc",
+    "public_ip_address_geolocation_provider.h",
     "public_ip_address_geolocator.cc",
     "public_ip_address_geolocator.h",
     "public_ip_address_location_notifier.cc",
@@ -19,5 +21,6 @@
     "//device/geolocation",
     "//mojo/public/cpp/bindings",
     "//net",
+    "//services/device/public/interfaces",
   ]
 }
diff --git a/services/device/geolocation/public_ip_address_geolocation_provider.cc b/services/device/geolocation/public_ip_address_geolocation_provider.cc
new file mode 100644
index 0000000..4c570ba
--- /dev/null
+++ b/services/device/geolocation/public_ip_address_geolocation_provider.cc
@@ -0,0 +1,50 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/device/geolocation/public_ip_address_geolocation_provider.h"
+
+#include "services/device/geolocation/public_ip_address_geolocator.h"
+
+namespace device {
+
+PublicIpAddressGeolocationProvider::PublicIpAddressGeolocationProvider() {
+  DETACH_FROM_SEQUENCE(sequence_checker_);
+}
+
+PublicIpAddressGeolocationProvider::~PublicIpAddressGeolocationProvider() {}
+
+void PublicIpAddressGeolocationProvider::Initialize(
+    GeolocationProvider::RequestContextProducer request_context_producer,
+    const std::string& api_key) {
+  // Bind sequence_checker_ to the initialization sequence.
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  public_ip_address_location_notifier_ =
+      std::make_unique<PublicIpAddressLocationNotifier>(
+          request_context_producer, api_key);
+}
+
+void PublicIpAddressGeolocationProvider::Bind(
+    mojom::PublicIpAddressGeolocationProviderRequest request) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(public_ip_address_location_notifier_);
+  provider_binding_set_.AddBinding(this, std::move(request));
+}
+
+void PublicIpAddressGeolocationProvider::CreateGeolocation(
+    const net::MutablePartialNetworkTrafficAnnotationTag& tag,
+    mojom::GeolocationRequest request) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(public_ip_address_location_notifier_);
+  geolocation_binding_set_.AddBinding(
+      std::make_unique<PublicIpAddressGeolocator>(
+          static_cast<net::PartialNetworkTrafficAnnotationTag>(tag),
+          public_ip_address_location_notifier_.get(),
+          base::Bind(
+              &mojo::StrongBindingSet<mojom::Geolocation>::ReportBadMessage,
+              base::Unretained(&geolocation_binding_set_))),
+      std::move(request));
+}
+
+}  // namespace device
diff --git a/services/device/geolocation/public_ip_address_geolocation_provider.h b/services/device/geolocation/public_ip_address_geolocation_provider.h
new file mode 100644
index 0000000..57ee445
--- /dev/null
+++ b/services/device/geolocation/public_ip_address_geolocation_provider.h
@@ -0,0 +1,76 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_DEVICE_GEOLOCATION_PUBLIC_IP_ADDRESS_GEOLOCATION_PROVIDER_H_
+#define SERVICES_DEVICE_GEOLOCATION_PUBLIC_IP_ADDRESS_GEOLOCATION_PROVIDER_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "device/geolocation/public/interfaces/geolocation.mojom.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/strong_binding_set.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/device/geolocation/public_ip_address_geolocator.h"
+#include "services/device/geolocation/public_ip_address_location_notifier.h"
+#include "services/device/public/interfaces/public_ip_address_geolocation_provider.mojom.h"
+
+namespace device {
+
+// Implementation of PublicIpAddressGeolocationProvider Mojo interface that will
+// provide mojom::Geolocation implementations that use IP-only geolocation.
+// Binds multiple PublicIpAddressGeolocationProvider requests.
+//
+// Sequencing:
+// * Must be used and destroyed on the same sequence.
+// * Provides mojom::Geolocation instances that are bound on the same sequence.
+// * Requires two-step construction: Construct on any sequence, then invoke
+//   Initialize() on the sequence on which this object will run.
+class PublicIpAddressGeolocationProvider
+    : public mojom::PublicIpAddressGeolocationProvider {
+ public:
+  // After construction, invoke Initialize() (on the appropriate sequence) to
+  // finish initialization.
+  PublicIpAddressGeolocationProvider();
+  ~PublicIpAddressGeolocationProvider() override;
+
+  // Finishes initialization, using the specified Google |api_key| and a URL
+  // request context produced by |request_context_producer| for network location
+  // requests.
+  // After this call is made, this object must be used only on the sequence on
+  // which this call was made.
+  void Initialize(
+      GeolocationProvider::RequestContextProducer request_context_producer,
+      const std::string& api_key);
+
+  // Binds a PublicIpAddressGeolocationProvider request to this instance.
+  void Bind(mojom::PublicIpAddressGeolocationProviderRequest request);
+
+ private:
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  // mojom::PublicIpAddressGeolocationProvider implementation:
+  // Provides a Geolocation instance that performs IP-geolocation only.
+  void CreateGeolocation(
+      const net::MutablePartialNetworkTrafficAnnotationTag& tag,
+      mojom::GeolocationRequest request) override;
+
+  // Central PublicIpAddressLocationNotifier for use by all implementations of
+  // mojom::Geolocation provided by the CreateGeolocation method.
+  // Note that this must be before the StrongBindingSet<mojom::Geolocation> as
+  // it must outlive the Geolocation implementations.
+  std::unique_ptr<PublicIpAddressLocationNotifier>
+      public_ip_address_location_notifier_;
+
+  mojo::BindingSet<mojom::PublicIpAddressGeolocationProvider>
+      provider_binding_set_;
+
+  mojo::StrongBindingSet<mojom::Geolocation> geolocation_binding_set_;
+
+  DISALLOW_COPY_AND_ASSIGN(PublicIpAddressGeolocationProvider);
+};
+
+}  // namespace device
+
+#endif  // SERVICES_DEVICE_GEOLOCATION_PUBLIC_IP_ADDRESS_GEOLOCATION_PROVIDER_H_
diff --git a/services/device/public/interfaces/BUILD.gn b/services/device/public/interfaces/BUILD.gn
index 8914b53..bc08e02 100644
--- a/services/device/public/interfaces/BUILD.gn
+++ b/services/device/public/interfaces/BUILD.gn
@@ -14,6 +14,7 @@
     "nfc.mojom",
     "nfc_provider.mojom",
     "power_monitor.mojom",
+    "public_ip_address_geolocation_provider.mojom",
     "serial.mojom",
     "time_zone_monitor.mojom",
     "vibration_manager.mojom",
@@ -22,9 +23,17 @@
     "wake_lock_provider.mojom",
   ]
 
+  deps = [
+    "//device/geolocation/public/interfaces",
+    "//services/network/public/interfaces:interfaces",
+  ]
+
   public_deps = [
     ":constants",
   ]
+
+  overridden_deps_blink = [ "//services/network/public/interfaces:interfaces" ]
+  component_deps_blink = [ "//third_party/WebKit/Source/platform" ]
 }
 
 mojom("generic_sensor") {
diff --git a/services/device/public/interfaces/public_ip_address_geolocation_provider.mojom b/services/device/public/interfaces/public_ip_address_geolocation_provider.mojom
new file mode 100644
index 0000000..214912e
--- /dev/null
+++ b/services/device/public/interfaces/public_ip_address_geolocation_provider.mojom
@@ -0,0 +1,18 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module device.mojom;
+
+import "device/geolocation/public/interfaces/geolocation.mojom";
+import "services/network/public/interfaces/mutable_partial_network_traffic_annotation_tag.mojom";
+
+// Provides a coarse-grained device.mojom.Geolocation which, subject to
+// case-by-case privacy review, may be able to operate without explicit user
+// consent.
+//
+// WARNING: DO NOT USE WITHOUT PRIVACY REVIEW.
+interface PublicIpAddressGeolocationProvider {
+  CreateGeolocation(network.mojom.MutablePartialNetworkTrafficAnnotationTag tag,
+                    Geolocation& request);
+};
diff --git a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
index 15e418d..b7e9293 100644
--- a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
@@ -486,7 +486,6 @@
 # use Mojo APIs instead.
 -HangingPacRequestProxyScriptBrowserTest.Shutdown
 -IOThreadBrowserTestWithHangingPacRequest.Shutdown
--IOThreadBrowserTestWithPacFileURL.FilePac
 -ProxySettingsApiTest.ProxyEventsParseError
 
 # http://crbug.com/783996
diff --git a/third_party/WebKit/Source/controller/BUILD.gn b/third_party/WebKit/Source/controller/BUILD.gn
index 714113d..cd39792d 100644
--- a/third_party/WebKit/Source/controller/BUILD.gn
+++ b/third_party/WebKit/Source/controller/BUILD.gn
@@ -37,6 +37,8 @@
     "BlinkInitializer.cpp",
     "BlinkInitializer.h",
     "ControllerExport.h",
+    "DevToolsFrontendImpl.cpp",
+    "DevToolsFrontendImpl.h",
     "OomInterventionImpl.cpp",
     "OomInterventionImpl.h",
   ]
diff --git a/third_party/WebKit/Source/controller/BlinkInitializer.cpp b/third_party/WebKit/Source/controller/BlinkInitializer.cpp
index 6bc760c0..9e303da 100644
--- a/third_party/WebKit/Source/controller/BlinkInitializer.cpp
+++ b/third_party/WebKit/Source/controller/BlinkInitializer.cpp
@@ -33,6 +33,7 @@
 #include "bindings/core/v8/V8Initializer.h"
 #include "bindings/modules/v8/V8ContextSnapshotExternalReferences.h"
 #include "build/build_config.h"
+#include "controller/DevToolsFrontendImpl.h"
 #include "controller/OomInterventionImpl.h"
 #include "core/animation/AnimationClock.h"
 #include "core/frame/LocalFrame.h"
@@ -126,4 +127,20 @@
                         main_thread->GetSingleThreadTaskRunner());
 }
 
+void BlinkInitializer::InitLocalFrame(LocalFrame& frame) const {
+  frame.GetInterfaceRegistry()->AddAssociatedInterface(WTF::BindRepeating(
+      &DevToolsFrontendImpl::BindMojoRequest, WrapWeakPersistent(&frame)));
+  ModulesInitializer::InitLocalFrame(frame);
+}
+
+void BlinkInitializer::OnClearWindowObjectInMainWorld(
+    Document& document,
+    const Settings& settings) const {
+  if (DevToolsFrontendImpl* devtools_frontend =
+          DevToolsFrontendImpl::From(document.GetFrame())) {
+    devtools_frontend->DidClearWindowObject();
+  }
+  ModulesInitializer::OnClearWindowObjectInMainWorld(document, settings);
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/controller/BlinkInitializer.h b/third_party/WebKit/Source/controller/BlinkInitializer.h
index cae3ebd..822cfa3 100644
--- a/third_party/WebKit/Source/controller/BlinkInitializer.h
+++ b/third_party/WebKit/Source/controller/BlinkInitializer.h
@@ -12,6 +12,9 @@
 class BlinkInitializer : public ModulesInitializer {
  public:
   void RegisterInterfaces(InterfaceRegistry&) override;
+  void OnClearWindowObjectInMainWorld(Document&,
+                                      const Settings&) const override;
+  void InitLocalFrame(LocalFrame&) const override;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/controller/DevToolsFrontendImpl.cpp b/third_party/WebKit/Source/controller/DevToolsFrontendImpl.cpp
new file mode 100644
index 0000000..eb30034
--- /dev/null
+++ b/third_party/WebKit/Source/controller/DevToolsFrontendImpl.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "controller/DevToolsFrontendImpl.h"
+
+#include "bindings/core/v8/ScriptController.h"
+#include "bindings/core/v8/V8BindingForCore.h"
+#include "bindings/core/v8/V8DevToolsHost.h"
+#include "core/exported/WebViewImpl.h"
+#include "core/frame/LocalFrame.h"
+#include "core/frame/WebLocalFrameImpl.h"
+#include "core/inspector/DevToolsHost.h"
+#include "core/page/Page.h"
+#include "platform/LayoutTestSupport.h"
+
+namespace blink {
+
+// static
+void DevToolsFrontendImpl::BindMojoRequest(
+    LocalFrame* local_frame,
+    mojom::blink::DevToolsFrontendAssociatedRequest request) {
+  if (!local_frame)
+    return;
+  local_frame->ProvideSupplement(
+      SupplementName(),
+      new DevToolsFrontendImpl(*local_frame, std::move(request)));
+}
+
+// static
+DevToolsFrontendImpl* DevToolsFrontendImpl::From(LocalFrame* local_frame) {
+  if (!local_frame)
+    return nullptr;
+  return static_cast<DevToolsFrontendImpl*>(
+      local_frame->RequireSupplement(SupplementName()));
+}
+
+// static
+const char* DevToolsFrontendImpl::SupplementName() {
+  return "DevToolsFrontendImpl";
+}
+
+DevToolsFrontendImpl::DevToolsFrontendImpl(
+    LocalFrame& frame,
+    mojom::blink::DevToolsFrontendAssociatedRequest request)
+    : Supplement<LocalFrame>(frame), binding_(this, std::move(request)) {}
+
+DevToolsFrontendImpl::~DevToolsFrontendImpl() {}
+
+void DevToolsFrontendImpl::DidClearWindowObject() {
+  if (host_) {
+    v8::Isolate* isolate = v8::Isolate::GetCurrent();
+    // Use higher limit for DevTools isolate so that it does not OOM when
+    // profiling large heaps.
+    isolate->IncreaseHeapLimitForDebugging();
+    ScriptState* script_state = ToScriptStateForMainWorld(GetSupplementable());
+    DCHECK(script_state);
+    ScriptState::Scope scope(script_state);
+    if (devtools_host_)
+      devtools_host_->DisconnectClient();
+    devtools_host_ = DevToolsHost::Create(this, GetSupplementable());
+    v8::Local<v8::Object> global = script_state->GetContext()->Global();
+    v8::Local<v8::Value> devtools_host_obj =
+        ToV8(devtools_host_.Get(), global, script_state->GetIsolate());
+    DCHECK(!devtools_host_obj.IsEmpty());
+    global->Set(V8AtomicString(isolate, "DevToolsHost"), devtools_host_obj);
+  }
+
+  if (!api_script_.IsEmpty()) {
+    GetSupplementable()->GetScriptController().ExecuteScriptInMainWorld(
+        api_script_);
+  }
+}
+
+void DevToolsFrontendImpl::SetupDevToolsFrontend(
+    const String& api_script,
+    mojom::blink::DevToolsFrontendHostAssociatedPtrInfo host) {
+  DCHECK(GetSupplementable()->IsMainFrame());
+  api_script_ = api_script;
+  host_.Bind(std::move(host));
+  host_.set_connection_error_handler(ConvertToBaseCallback(WTF::Bind(
+      &DevToolsFrontendImpl::DestroyOnHostGone, WrapWeakPersistent(this))));
+  GetSupplementable()->GetPage()->SetDefaultPageScaleLimits(1.f, 1.f);
+}
+
+void DevToolsFrontendImpl::SetupDevToolsExtensionAPI(
+    const String& extension_api) {
+  DCHECK(!GetSupplementable()->IsMainFrame());
+  api_script_ = extension_api;
+}
+
+void DevToolsFrontendImpl::SendMessageToEmbedder(const String& message) {
+  if (host_)
+    host_->DispatchEmbedderMessage(message);
+}
+
+bool DevToolsFrontendImpl::IsUnderTest() {
+  return LayoutTestSupport::IsRunningLayoutTest();
+}
+
+void DevToolsFrontendImpl::ShowContextMenu(LocalFrame* target_frame,
+                                           float x,
+                                           float y,
+                                           ContextMenuProvider* menu_provider) {
+  WebLocalFrameImpl::FromFrame(target_frame)
+      ->ViewImpl()
+      ->ShowContextMenuAtPoint(x, y, menu_provider);
+}
+
+void DevToolsFrontendImpl::DestroyOnHostGone() {
+  if (devtools_host_)
+    devtools_host_->DisconnectClient();
+  GetSupplementable()->RemoveSupplement(SupplementName());
+}
+
+void DevToolsFrontendImpl::Trace(blink::Visitor* visitor) {
+  visitor->Trace(devtools_host_);
+  Supplement<LocalFrame>::Trace(visitor);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/controller/DevToolsFrontendImpl.h b/third_party/WebKit/Source/controller/DevToolsFrontendImpl.h
new file mode 100644
index 0000000..8b68762
--- /dev/null
+++ b/third_party/WebKit/Source/controller/DevToolsFrontendImpl.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DevToolsFrontendImpl_h
+#define DevToolsFrontendImpl_h
+
+#include "base/macros.h"
+#include "core/inspector/InspectorFrontendClient.h"
+#include "mojo/public/cpp/bindings/associated_binding.h"
+#include "platform/Supplementable.h"
+#include "platform/heap/Handle.h"
+#include "platform/wtf/HashMap.h"
+#include "platform/wtf/text/WTFString.h"
+#include "public/web/devtools_frontend.mojom-blink.h"
+
+namespace blink {
+
+class DevToolsHost;
+class LocalFrame;
+
+// This class lives as long as a frame (being a supplement), or until
+// it's host (mojom.DevToolsFrontendHost) is destroyed.
+class DevToolsFrontendImpl final
+    : public GarbageCollectedFinalized<DevToolsFrontendImpl>,
+      public Supplement<LocalFrame>,
+      public mojom::blink::DevToolsFrontend,
+      public InspectorFrontendClient {
+  USING_GARBAGE_COLLECTED_MIXIN(DevToolsFrontendImpl);
+
+ public:
+  static void BindMojoRequest(LocalFrame*,
+                              mojom::blink::DevToolsFrontendAssociatedRequest);
+  static DevToolsFrontendImpl* From(LocalFrame*);
+
+  ~DevToolsFrontendImpl() override;
+  void DidClearWindowObject();
+  void Trace(blink::Visitor*);
+
+ private:
+  DevToolsFrontendImpl(LocalFrame&,
+                       mojom::blink::DevToolsFrontendAssociatedRequest);
+  static const char* SupplementName();
+  void DestroyOnHostGone();
+
+  // mojom::blink::DevToolsFrontend implementation.
+  void SetupDevToolsFrontend(
+      const String& api_script,
+      mojom::blink::DevToolsFrontendHostAssociatedPtrInfo) override;
+  void SetupDevToolsExtensionAPI(const String& extension_api) override;
+
+  // InspectorFrontendClient implementation.
+  void SendMessageToEmbedder(const String&) override;
+  bool IsUnderTest() override;
+  void ShowContextMenu(LocalFrame*,
+                       float x,
+                       float y,
+                       ContextMenuProvider*) override;
+
+  Member<DevToolsHost> devtools_host_;
+  String api_script_;
+  mojom::blink::DevToolsFrontendHostAssociatedPtr host_;
+  mojo::AssociatedBinding<mojom::blink::DevToolsFrontend> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(DevToolsFrontendImpl);
+};
+
+}  // namespace blink
+
+#endif
diff --git a/third_party/WebKit/Source/core/exported/BUILD.gn b/third_party/WebKit/Source/core/exported/BUILD.gn
index d6a6cdf..e8132ed 100644
--- a/third_party/WebKit/Source/core/exported/BUILD.gn
+++ b/third_party/WebKit/Source/core/exported/BUILD.gn
@@ -25,8 +25,6 @@
     "WebDateTimeSuggestion.cpp",
     "WebDevToolsAgentImpl.cpp",
     "WebDevToolsAgentImpl.h",
-    "WebDevToolsFrontendImpl.cpp",
-    "WebDevToolsFrontendImpl.h",
     "WebDocument.cpp",
     "WebDocumentLoaderImpl.cpp",
     "WebDocumentLoaderImpl.h",
diff --git a/third_party/WebKit/Source/core/exported/LocalFrameClientImpl.cpp b/third_party/WebKit/Source/core/exported/LocalFrameClientImpl.cpp
index 3f685c8..aa2f029f 100644
--- a/third_party/WebKit/Source/core/exported/LocalFrameClientImpl.cpp
+++ b/third_party/WebKit/Source/core/exported/LocalFrameClientImpl.cpp
@@ -42,7 +42,6 @@
 #include "core/events/UIEventWithKeyState.h"
 #include "core/exported/SharedWorkerRepositoryClientImpl.h"
 #include "core/exported/WebDevToolsAgentImpl.h"
-#include "core/exported/WebDevToolsFrontendImpl.h"
 #include "core/exported/WebDocumentLoaderImpl.h"
 #include "core/exported/WebPluginContainerImpl.h"
 #include "core/exported/WebViewImpl.h"
@@ -175,13 +174,6 @@
                                                                     *settings);
     }
   }
-  // FIXME: when extensions go out of process, this whole concept stops working.
-  WebDevToolsFrontendImpl* dev_tools_frontend =
-      web_frame_->Top()->IsWebLocalFrame()
-          ? ToWebLocalFrameImpl(web_frame_->Top())->DevToolsFrontend()
-          : nullptr;
-  if (dev_tools_frontend)
-    dev_tools_frontend->DidClearWindowObject(web_frame_);
 }
 
 void LocalFrameClientImpl::DocumentElementAvailable() {
diff --git a/third_party/WebKit/Source/core/exported/WebDevToolsFrontendImpl.cpp b/third_party/WebKit/Source/core/exported/WebDevToolsFrontendImpl.cpp
deleted file mode 100644
index ebbe3314f..0000000
--- a/third_party/WebKit/Source/core/exported/WebDevToolsFrontendImpl.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2010 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "core/exported/WebDevToolsFrontendImpl.h"
-
-#include "bindings/core/v8/ScriptController.h"
-#include "bindings/core/v8/V8BindingForCore.h"
-#include "bindings/core/v8/V8DevToolsHost.h"
-#include "core/exported/WebViewImpl.h"
-#include "core/frame/LocalFrame.h"
-#include "core/frame/WebLocalFrameImpl.h"
-#include "core/inspector/DevToolsHost.h"
-#include "core/page/Page.h"
-#include "public/platform/WebSecurityOrigin.h"
-#include "public/platform/WebString.h"
-#include "public/web/WebDevToolsFrontendClient.h"
-
-namespace blink {
-
-WebDevToolsFrontend* WebDevToolsFrontend::Create(
-    WebLocalFrame* frame,
-    WebDevToolsFrontendClient* client) {
-  return new WebDevToolsFrontendImpl(ToWebLocalFrameImpl(frame), client);
-}
-
-WebDevToolsFrontendImpl::WebDevToolsFrontendImpl(
-    WebLocalFrameImpl* web_frame,
-    WebDevToolsFrontendClient* client)
-    : web_frame_(web_frame), client_(client) {
-  web_frame_->SetDevToolsFrontend(this);
-  web_frame_->GetFrame()->GetPage()->SetDefaultPageScaleLimits(1.f, 1.f);
-}
-
-WebDevToolsFrontendImpl::~WebDevToolsFrontendImpl() {
-  web_frame_->SetDevToolsFrontend(nullptr);
-  if (devtools_host_)
-    devtools_host_->DisconnectClient();
-}
-
-void WebDevToolsFrontendImpl::DidClearWindowObject(WebLocalFrameImpl* frame) {
-  if (web_frame_ != frame)
-    return;
-  v8::Isolate* isolate = v8::Isolate::GetCurrent();
-  // Use higher limit for DevTools isolate so that it does not OOM when
-  // profiling large heaps.
-  isolate->IncreaseHeapLimitForDebugging();
-  ScriptState* script_state = ToScriptStateForMainWorld(web_frame_->GetFrame());
-  DCHECK(script_state);
-  ScriptState::Scope scope(script_state);
-
-  if (devtools_host_)
-    devtools_host_->DisconnectClient();
-  devtools_host_ = DevToolsHost::Create(this, web_frame_->GetFrame());
-  v8::Local<v8::Object> global = script_state->GetContext()->Global();
-  v8::Local<v8::Value> devtools_host_obj =
-      ToV8(devtools_host_.Get(), global, script_state->GetIsolate());
-  DCHECK(!devtools_host_obj.IsEmpty());
-  global->Set(V8AtomicString(isolate, "DevToolsHost"), devtools_host_obj);
-}
-
-void WebDevToolsFrontendImpl::SendMessageToEmbedder(const String& message) {
-  if (client_)
-    client_->SendMessageToEmbedder(message);
-}
-
-bool WebDevToolsFrontendImpl::IsUnderTest() {
-  return client_ ? client_->IsUnderTest() : false;
-}
-
-void WebDevToolsFrontendImpl::ShowContextMenu(
-    LocalFrame* target_frame,
-    float x,
-    float y,
-    ContextMenuProvider* menu_provider) {
-  WebLocalFrameImpl::FromFrame(target_frame)
-      ->ViewImpl()
-      ->ShowContextMenuAtPoint(x, y, menu_provider);
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/core/exported/WebDevToolsFrontendImpl.h b/third_party/WebKit/Source/core/exported/WebDevToolsFrontendImpl.h
deleted file mode 100644
index 1f229489..0000000
--- a/third_party/WebKit/Source/core/exported/WebDevToolsFrontendImpl.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2010 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef WebDevToolsFrontendImpl_h
-#define WebDevToolsFrontendImpl_h
-
-#include "base/macros.h"
-#include "core/CoreExport.h"
-#include "core/inspector/InspectorFrontendClient.h"
-#include "platform/heap/Handle.h"
-#include "platform/wtf/HashMap.h"
-#include "platform/wtf/text/WTFString.h"
-#include "public/web/WebDevToolsFrontend.h"
-
-namespace blink {
-
-class DevToolsHost;
-class WebLocalFrameImpl;
-
-class CORE_EXPORT WebDevToolsFrontendImpl final
-    : public WebDevToolsFrontend,
-      public InspectorFrontendClient {
- public:
-  WebDevToolsFrontendImpl(WebLocalFrameImpl*, WebDevToolsFrontendClient*);
-  ~WebDevToolsFrontendImpl() override;
-
-  void DidClearWindowObject(WebLocalFrameImpl*);
-
-  void SendMessageToEmbedder(const WTF::String&) override;
-
-  bool IsUnderTest() override;
-
-  void ShowContextMenu(LocalFrame*,
-                       float x,
-                       float y,
-                       ContextMenuProvider*) override;
-
- private:
-  Persistent<WebLocalFrameImpl> web_frame_;
-  WebDevToolsFrontendClient* client_;
-  Persistent<DevToolsHost> devtools_host_;
-
-  DISALLOW_COPY_AND_ASSIGN(WebDevToolsFrontendImpl);
-};
-
-}  // namespace blink
-
-#endif
diff --git a/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.cpp
index 9833489e..b0929025 100644
--- a/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.cpp
+++ b/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.cpp
@@ -1707,7 +1707,6 @@
       autofill_client_(nullptr),
       input_events_scale_factor_for_emulation_(1),
       interface_registry_(interface_registry),
-      web_dev_tools_frontend_(nullptr),
       input_method_controller_(*this),
       spell_check_panel_host_client_(nullptr),
       self_keep_alive_(this) {
diff --git a/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.h b/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.h
index 12949d1..ecac5142 100644
--- a/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.h
+++ b/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.h
@@ -60,7 +60,6 @@
 struct WebAssociatedURLLoaderOptions;
 class WebAutofillClient;
 class WebDevToolsAgentImpl;
-class WebDevToolsFrontendImpl;
 class WebFrameClient;
 class WebNode;
 class WebPerformance;
@@ -420,14 +419,6 @@
 
   void SetFrameWidget(WebFrameWidgetBase*);
 
-  // DevTools front-end bindings.
-  void SetDevToolsFrontend(WebDevToolsFrontendImpl* frontend) {
-    web_dev_tools_frontend_ = frontend;
-  }
-  WebDevToolsFrontendImpl* DevToolsFrontend() {
-    return web_dev_tools_frontend_;
-  }
-
   WebNode ContextMenuNode() const { return context_menu_node_.Get(); }
   void SetContextMenuNode(Node* node) { context_menu_node_ = node; }
   void ClearContextMenuNode() { context_menu_node_.Clear(); }
@@ -503,8 +494,6 @@
   // Borrowed pointers to Mojo objects.
   blink::InterfaceRegistry* interface_registry_;
 
-  WebDevToolsFrontendImpl* web_dev_tools_frontend_;
-
   Member<Node> context_menu_node_;
 
   WebInputMethodControllerImpl input_method_controller_;
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp
index 840343fc..97c3085 100644
--- a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp
+++ b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp
@@ -41,10 +41,10 @@
 // switch from idle to main thread only happens to a minority of toBlob calls
 #if !defined(OS_ANDROID)
 // Png image encoding on 4k by 4k canvas on Mac HDD takes 5.7+ seconds
-const double kIdleTaskCompleteTimeoutDelayMs = 6700.0;
+const double kIdleTaskCompleteTimeoutDelayMs = 10000.0;
 #else
 // Png image encoding on 4k by 4k canvas on Android One takes 9.0+ seconds
-const double kIdleTaskCompleteTimeoutDelayMs = 10000.0;
+const double kIdleTaskCompleteTimeoutDelayMs = 20000.0;
 #endif
 
 bool IsDeadlineNearOrPassed(double deadline_seconds) {
@@ -95,7 +95,7 @@
 // end of the list.
 enum ElapsedTimeHistogramType {
   kInitiateEncodingDelay,
-  kIdleEncodeDuration,
+  kCompleteEncodingDelay,
   kToBlobDuration,
   kNumberOfElapsedTimeHistogramTypes
 };
@@ -115,16 +115,16 @@
           ("Blink.Canvas.ToBlob.InitiateEncodingDelay.JPEG", 0, 10000000, 50));
       to_blob_jpeg_initiate_encoding_counter.Count(elapsed_time * 1000000.0);
     }
-  } else if (type == kIdleEncodeDuration) {
+  } else if (type == kCompleteEncodingDelay) {
     if (mime_type == CanvasAsyncBlobCreator::kMimeTypePng) {
       DEFINE_THREAD_SAFE_STATIC_LOCAL(
           CustomCountHistogram, to_blob_png_idle_encode_counter,
-          ("Blink.Canvas.ToBlob.IdleEncodeDuration.PNG", 0, 10000000, 50));
+          ("Blink.Canvas.ToBlob.CompleteEncodingDelay.PNG", 0, 10000000, 50));
       to_blob_png_idle_encode_counter.Count(elapsed_time * 1000000.0);
     } else if (mime_type == CanvasAsyncBlobCreator::kMimeTypeJpeg) {
       DEFINE_THREAD_SAFE_STATIC_LOCAL(
           CustomCountHistogram, to_blob_jpeg_idle_encode_counter,
-          ("Blink.Canvas.ToBlob.IdleEncodeDuration.JPEG", 0, 10000000, 50));
+          ("Blink.Canvas.ToBlob.CompleteEncodingDelay.JPEG", 0, 10000000, 50));
       to_blob_jpeg_idle_encode_counter.Count(elapsed_time * 1000000.0);
     }
   } else if (type == kToBlobDuration) {
@@ -184,7 +184,6 @@
       context_(context),
       mime_type_(mime_type),
       start_time_(start_time),
-      elapsed_time_(0),
       callback_(callback),
       script_promise_resolver_(resolver) {
   size_t rowBytes = size.Width() * 4;
@@ -263,7 +262,7 @@
 }
 
 void CanvasAsyncBlobCreator::ScheduleInitiateEncoding(double quality) {
-  schedule_initiate_start_time_ = WTF::MonotonicallyIncreasingTime();
+  schedule_idle_task_start_time_ = WTF::MonotonicallyIncreasingTime();
   Platform::Current()->CurrentThread()->Scheduler()->PostIdleTask(
       BLINK_FROM_HERE, WTF::Bind(&CanvasAsyncBlobCreator::InitiateEncoding,
                                  WrapPersistent(this), quality));
@@ -276,7 +275,7 @@
   }
   RecordElapsedTimeHistogram(
       kInitiateEncodingDelay, mime_type_,
-      WTF::MonotonicallyIncreasingTime() - schedule_initiate_start_time_);
+      WTF::MonotonicallyIncreasingTime() - schedule_idle_task_start_time_);
 
   DCHECK(idle_task_status_ == kIdleTaskNotStarted);
   idle_task_status_ = kIdleTaskStarted;
@@ -286,6 +285,8 @@
     return;
   }
 
+  // Re-use this time variable to collect data on complete encoding delay
+  schedule_idle_task_start_time_ = WTF::MonotonicallyIncreasingTime();
   IdleEncodeRows(deadline_seconds);
 }
 
@@ -294,11 +295,9 @@
     return;
   }
 
-  double start_time = WTF::MonotonicallyIncreasingTime();
   for (int y = num_rows_completed_; y < src_data_.height(); ++y) {
     if (IsDeadlineNearOrPassed(deadline_seconds)) {
       num_rows_completed_ = y;
-      elapsed_time_ += (WTF::MonotonicallyIncreasingTime() - start_time);
       Platform::Current()->CurrentThread()->Scheduler()->PostIdleTask(
           BLINK_FROM_HERE, WTF::Bind(&CanvasAsyncBlobCreator::IdleEncodeRows,
                                      WrapPersistent(this)));
@@ -314,8 +313,9 @@
   num_rows_completed_ = src_data_.height();
 
   idle_task_status_ = kIdleTaskCompleted;
-  elapsed_time_ += (WTF::MonotonicallyIncreasingTime() - start_time);
-  RecordElapsedTimeHistogram(kIdleEncodeDuration, mime_type_, elapsed_time_);
+  double elapsed_time =
+      WTF::MonotonicallyIncreasingTime() - schedule_idle_task_start_time_;
+  RecordElapsedTimeHistogram(kCompleteEncodingDelay, mime_type_, elapsed_time);
   if (IsDeadlineNearOrPassed(deadline_seconds)) {
     context_->GetTaskRunner(TaskType::kCanvasBlobSerialization)
         ->PostTask(BLINK_FROM_HERE,
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.h b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.h
index a37271c..6277b9a 100644
--- a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.h
+++ b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.h
@@ -107,9 +107,10 @@
 
   SkPixmap src_data_;
   const MimeType mime_type_;
+
+  // Chrome metrics use
   double start_time_;
-  double schedule_initiate_start_time_;
-  double elapsed_time_;
+  double schedule_idle_task_start_time_;
 
   ToBlobFunctionType function_type_;
 
diff --git a/third_party/WebKit/Source/core/inspector/DevToolsHost.cpp b/third_party/WebKit/Source/core/inspector/DevToolsHost.cpp
index 08ed4790..d35b0445 100644
--- a/third_party/WebKit/Source/core/inspector/DevToolsHost.cpp
+++ b/third_party/WebKit/Source/core/inspector/DevToolsHost.cpp
@@ -115,11 +115,10 @@
       frontend_frame_(frontend_frame),
       menu_provider_(nullptr) {}
 
-DevToolsHost::~DevToolsHost() {
-  DCHECK(!client_);
-}
+DevToolsHost::~DevToolsHost() {}
 
 void DevToolsHost::Trace(blink::Visitor* visitor) {
+  visitor->Trace(client_);
   visitor->Trace(frontend_frame_);
   visitor->Trace(menu_provider_);
   ScriptWrappable::Trace(visitor);
diff --git a/third_party/WebKit/Source/core/inspector/DevToolsHost.h b/third_party/WebKit/Source/core/inspector/DevToolsHost.h
index 969f46bdb..02e07b6 100644
--- a/third_party/WebKit/Source/core/inspector/DevToolsHost.h
+++ b/third_party/WebKit/Source/core/inspector/DevToolsHost.h
@@ -84,7 +84,7 @@
   DevToolsHost(InspectorFrontendClient*, LocalFrame* frontend_frame);
   void EvaluateScript(const String&);
 
-  InspectorFrontendClient* client_;
+  Member<InspectorFrontendClient> client_;
   Member<LocalFrame> frontend_frame_;
   Member<FrontendMenuProvider> menu_provider_;
 };
diff --git a/third_party/WebKit/Source/core/inspector/InspectorFrontendClient.h b/third_party/WebKit/Source/core/inspector/InspectorFrontendClient.h
index b6dcdd4..5d3e63e2 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorFrontendClient.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorFrontendClient.h
@@ -39,7 +39,7 @@
 class ContextMenuProvider;
 class LocalFrame;
 
-class InspectorFrontendClient {
+class InspectorFrontendClient : public GarbageCollectedMixin {
  public:
   virtual ~InspectorFrontendClient() {}
 
diff --git a/third_party/WebKit/Source/modules/ModulesInitializer.h b/third_party/WebKit/Source/modules/ModulesInitializer.h
index 7febcca..288db55 100644
--- a/third_party/WebKit/Source/modules/ModulesInitializer.h
+++ b/third_party/WebKit/Source/modules/ModulesInitializer.h
@@ -17,6 +17,8 @@
 
  protected:
   void InitLocalFrame(LocalFrame&) const override;
+  void OnClearWindowObjectInMainWorld(Document&,
+                                      const Settings&) const override;
 
  private:
   void InstallSupplements(LocalFrame&) const override;
@@ -29,8 +31,6 @@
                                  InspectorDOMAgent*,
                                  InspectedFrames*,
                                  Page*) const override;
-  void OnClearWindowObjectInMainWorld(Document&,
-                                      const Settings&) const override;
   std::unique_ptr<WebMediaPlayer> CreateWebMediaPlayer(
       WebFrameClient*,
       HTMLMediaElement&,
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn
index 4ed2ad4..837a121 100644
--- a/third_party/WebKit/Source/platform/BUILD.gn
+++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -223,6 +223,7 @@
   visibility = []  # Allow re-assignment of list.
   visibility = [
     "//components/pdf/common:interfaces_blink",
+    "//services/device/public/interfaces:interfaces_blink",
     "//third_party/WebKit/*",
     "//url/mojo:url_mojom_origin_blink",
     "//url/mojo:url_mojom_gurl_blink",
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceLoadScheduler.cpp b/third_party/WebKit/Source/platform/loader/fetch/ResourceLoadScheduler.cpp
index 727133ef..e5284df 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceLoadScheduler.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceLoadScheduler.cpp
@@ -38,6 +38,19 @@
 // Bucket count for metrics.
 constexpr int32_t kReportBucketCount = 25;
 
+constexpr char kRendererSideResourceScheduler[] =
+    "RendererSideResourceScheduler";
+
+// These values are copied from resource_scheduler.cc, but the meaning is a bit
+// different because ResourceScheduler counts the running delayable requests
+// while ResourceLoadScheduler counts all the running requests.
+constexpr size_t kTightLimitForRendererSideResourceScheduler = 1u;
+constexpr size_t kLimitForRendererSideResourceScheduler = 10u;
+
+constexpr char kTightLimitForRendererSideResourceSchedulerName[] =
+    "tight_limit";
+constexpr char kLimitForRendererSideResourceSchedulerName[] = "limit";
+
 // Represents a resource load circumstance, e.g. from main frame vs sub-frames,
 // or on throttled state vs on not-throttled state.
 // Used to report histograms. Do not reorder or insert new items.
@@ -54,14 +67,15 @@
   return static_cast<base::HistogramBase::Sample>(circumstance);
 }
 
-uint32_t GetFieldTrialUint32Param(const char* name, uint32_t default_param) {
+uint32_t GetFieldTrialUint32Param(const char* trial_name,
+                                  const char* parameter_name,
+                                  uint32_t default_param) {
   std::map<std::string, std::string> trial_params;
-  bool result =
-      base::GetFieldTrialParams(kResourceLoadSchedulerTrial, &trial_params);
+  bool result = base::GetFieldTrialParams(trial_name, &trial_params);
   if (!result)
     return default_param;
 
-  const auto& found = trial_params.find(name);
+  const auto& found = trial_params.find(parameter_name);
   if (found == trial_params.end())
     return default_param;
 
@@ -75,16 +89,17 @@
 uint32_t GetOutstandingThrottledLimit(FetchContext* context) {
   DCHECK(context);
 
-  uint32_t main_frame_limit =
-      GetFieldTrialUint32Param(kOutstandingLimitForBackgroundMainFrameName,
-                               kOutstandingLimitForBackgroundFrameDefault);
+  uint32_t main_frame_limit = GetFieldTrialUint32Param(
+      kResourceLoadSchedulerTrial, kOutstandingLimitForBackgroundMainFrameName,
+      kOutstandingLimitForBackgroundFrameDefault);
   if (context->IsMainFrame())
     return main_frame_limit;
 
   // We do not have a fixed default limit for sub-frames, but use the limit for
   // the main frame so that it works as how previous versions that haven't
   // consider sub-frames' specific limit work.
-  return GetFieldTrialUint32Param(kOutstandingLimitForBackgroundSubFrameName,
+  return GetFieldTrialUint32Param(kResourceLoadSchedulerTrial,
+                                  kOutstandingLimitForBackgroundSubFrameName,
                                   main_frame_limit);
 }
 
@@ -331,15 +346,26 @@
   traffic_monitor_ = std::make_unique<ResourceLoadScheduler::TrafficMonitor>(
       context_->IsMainFrame());
 
-  if (!RuntimeEnabledFeatures::ResourceLoadSchedulerEnabled())
+  if (!RuntimeEnabledFeatures::ResourceLoadSchedulerEnabled() &&
+      !Platform::Current()->IsRendererSideResourceSchedulerEnabled()) {
     return;
+  }
 
   auto* scheduler = context->GetFrameScheduler();
   if (!scheduler)
     return;
 
-  if (Platform::Current()->IsRendererSideResourceSchedulerEnabled())
+  if (Platform::Current()->IsRendererSideResourceSchedulerEnabled()) {
     policy_ = context->InitialLoadThrottlingPolicy();
+    outstanding_limit_ =
+        GetFieldTrialUint32Param(kRendererSideResourceScheduler,
+                                 kLimitForRendererSideResourceSchedulerName,
+                                 kLimitForRendererSideResourceScheduler);
+    tight_outstanding_limit_ = GetFieldTrialUint32Param(
+        kRendererSideResourceScheduler,
+        kTightLimitForRendererSideResourceSchedulerName,
+        kTightLimitForRendererSideResourceScheduler);
+  }
 
   is_enabled_ = true;
   scheduler->AddThrottlingObserver(WebFrameScheduler::ObserverType::kLoader,
@@ -617,6 +643,10 @@
         has_enough_running_requets) {
       break;
     }
+    if (IsThrottablePriority(pending_requests_.begin()->priority) &&
+        has_enough_running_requets) {
+      break;
+    }
 
     ClientId id = pending_requests_.begin()->client_id;
     pending_requests_.erase(pending_requests_.begin());
diff --git a/third_party/WebKit/public/BUILD.gn b/third_party/WebKit/public/BUILD.gn
index 4a3d2f3..7a854fd 100644
--- a/third_party/WebKit/public/BUILD.gn
+++ b/third_party/WebKit/public/BUILD.gn
@@ -493,8 +493,6 @@
     "web/WebDateTimeSuggestion.h",
     "web/WebDevToolsAgent.h",
     "web/WebDevToolsAgentClient.h",
-    "web/WebDevToolsFrontend.h",
-    "web/WebDevToolsFrontendClient.h",
     "web/WebDeviceEmulationParams.h",
     "web/WebDocument.h",
     "web/WebDocumentLoader.h",
@@ -808,6 +806,7 @@
     "platform/reporting.mojom",
     "platform/site_engagement.mojom",
     "web/console_message.mojom",
+    "web/devtools_frontend.mojom",
     "web/selection_menu_behavior.mojom",
     "web/shared_worker_creation_context_type.mojom",
     "web/window_features.mojom",
diff --git a/third_party/WebKit/public/platform/InterfaceRegistry.h b/third_party/WebKit/public/platform/InterfaceRegistry.h
index 5725979..c041e2c 100644
--- a/third_party/WebKit/public/platform/InterfaceRegistry.h
+++ b/third_party/WebKit/public/platform/InterfaceRegistry.h
@@ -69,9 +69,9 @@
           factory) {
     AddAssociatedInterface(
         Interface::Name_,
-        ConvertToBaseCallback(WTF::Bind(
+        WTF::BindRepeating(
             &InterfaceRegistry::ForwardToAssociatedInterfaceFactory<Interface>,
-            std::move(factory))));
+            std::move(factory)));
   }
 
  private:
diff --git a/third_party/WebKit/public/web/WebDevToolsFrontend.h b/third_party/WebKit/public/web/WebDevToolsFrontend.h
deleted file mode 100644
index 77c33dd..0000000
--- a/third_party/WebKit/public/web/WebDevToolsFrontend.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef WebDevToolsFrontend_h
-#define WebDevToolsFrontend_h
-
-#include "public/platform/WebCommon.h"
-
-namespace blink {
-
-class WebDevToolsFrontendClient;
-class WebLocalFrame;
-
-// WebDevToolsFrontend represents DevTools client sitting in the Glue. It
-// provides direct and delegate Apis to the host.
-class WebDevToolsFrontend {
- public:
-  BLINK_EXPORT static WebDevToolsFrontend* Create(WebLocalFrame*,
-                                                  WebDevToolsFrontendClient*);
-
-  virtual ~WebDevToolsFrontend() {}
-};
-
-}  // namespace blink
-
-#endif
diff --git a/third_party/WebKit/public/web/WebDevToolsFrontendClient.h b/third_party/WebKit/public/web/WebDevToolsFrontendClient.h
deleted file mode 100644
index 7d6df9feb..0000000
--- a/third_party/WebKit/public/web/WebDevToolsFrontendClient.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef WebDevToolsFrontendClient_h
-#define WebDevToolsFrontendClient_h
-
-namespace blink {
-
-class WebString;
-
-class WebDevToolsFrontendClient {
- public:
-  WebDevToolsFrontendClient() {}
-
-  virtual void SendMessageToEmbedder(const WebString&) {}
-
-  virtual bool IsUnderTest() { return false; }
-
- protected:
-  virtual ~WebDevToolsFrontendClient() {}
-};
-
-}  // namespace blink
-
-#endif
diff --git a/third_party/WebKit/public/web/devtools_frontend.mojom b/third_party/WebKit/public/web/devtools_frontend.mojom
new file mode 100644
index 0000000..46f4827
--- /dev/null
+++ b/third_party/WebKit/public/web/devtools_frontend.mojom
@@ -0,0 +1,34 @@
+// 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.
+
+module blink.mojom;
+
+// Provides extra capabilities required for DevTools frontend to function.
+// This includes communication channel from/to inspected target which implements
+// remote debugging protocol. Protocol messages go through browser process.
+//
+// Instances of this interface must be associated with navigation-related
+// interface, since we should setup DevToolsFrontend before the navigation
+// commits in the frame.
+interface DevToolsFrontend {
+  // Sets up a main frame as a DevTools frontend. This exposes DevToolsHost
+  // object (see DevToolsHost.idl for details). The |api_script| is executed
+  // on each navigation in the frame before the DevTools frontend starts
+  // loading. It makes use of DevToolsHost to expose embedder capabilities to
+  // DevTools (e.g. connection to the inspected target).
+  SetupDevToolsFrontend(string api_script,
+                        associated DevToolsFrontendHost host);
+
+  // Sets up a child frame to expose DevTools extension API by executing script
+  // |extension_api| on each navigation in the frame. This script provides
+  // required capabilities for DevTools extensions to function, implementing
+  // chrome.devtools extension API.
+  SetupDevToolsExtensionAPI(string extension_api);
+};
+
+// Provides embedder functionality to a frame serving as DevTools frontend.
+interface DevToolsFrontendHost {
+  // Sends a message to DevTools frontend embedder.
+  DispatchEmbedderMessage(string message);
+};
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 4708f28d..ef326f86 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -24482,6 +24482,7 @@
   <int value="-1940291343" label="SpeculativeResourcePrefetching:enabled"/>
   <int value="-1939016096"
       label="OmniboxUIExperimentHideSuggestionUrlTrivialSubdomains:enabled"/>
+  <int value="-1939003674" label="NetworkServiceInProcess:disabled"/>
   <int value="-1938263248" label="enable-extension-info-dialog"/>
   <int value="-1937077699" label="http-form-warning"/>
   <int value="-1933425042" label="OfflinePreviews:enabled"/>
@@ -25935,6 +25936,7 @@
   <int value="2005614493" label="tab-management-experiment-type-dill"/>
   <int value="2014331873" label="NTPDownloadSuggestions:disabled"/>
   <int value="2014629801" label="view-passwords:disabled"/>
+  <int value="2015547864" label="NetworkServiceInProcess:enabled"/>
   <int value="2020107447" label="AndroidPayIntegrationV1:enabled"/>
   <int value="2032558514"
       label="RemoveUsageOfDeprecatedGaiaSigninEndpoint:enabled"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 49581f64..f44fa8ba 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -6429,13 +6429,17 @@
   <summary>Time spent on 2D canvas putImageData API call.</summary>
 </histogram>
 
-<histogram name="Blink.Canvas.ToBlob.IdleEncodeDuration" units="microseconds">
+<histogram name="Blink.Canvas.ToBlob.CompleteEncodingDelay"
+    units="microseconds">
   <owner>junov@chromium.org</owner>
   <owner>xlai@chromium.org</owner>
   <summary>
-    This metric measures the total time spent on encoding all the rows of an
-    image (jpeg or png), as part of a canvas.toBlob API call. Encoding occurs
-    during one or more idle periods on the main thread.
+    This metric measures the total time spent on completing encoding all the
+    rows of an image (jpeg or png), as part of a canvas.toBlob API call.
+    Encoding occurs during one or more idle periods on the main thread and the
+    waiting time of the next idle period is included in the measurement. If the
+    code has swtiched to force encoding path, we will not measure the delay in
+    this metric.
 
     This metric is useful in helping us adjust the IdleTaskCompleteTimeoutDelay
     in canvas.toBlob. When the encoding idle task is delayed for longer than
@@ -6449,6 +6453,20 @@
   </summary>
 </histogram>
 
+<histogram name="Blink.Canvas.ToBlob.IdleEncodeDuration" units="microseconds">
+  <obsolete>
+    Replaced with Blink.Canvas.ToBlob.CompleteEncodingDelay in 2017/12.
+  </obsolete>
+  <owner>junov@chromium.org</owner>
+  <owner>xlai@chromium.org</owner>
+  <summary>
+    This metric measures the total time spent on encoding all the rows of an
+    image (jpeg or png), excluding the waiting time of next idle periods. This
+    is part of a canvas.toBlob API call. Encoding occurs during one or more idle
+    periods on the main thread.
+  </summary>
+</histogram>
+
 <histogram name="Blink.Canvas.ToBlob.IdleTaskStatus" enum="IdleTaskStatus">
   <owner>junov@chromium.org</owner>
   <owner>xlai@chromium.org</owner>
@@ -99406,7 +99424,12 @@
 <histogram_suffixes name="BlinkCanvasToBlobIdleEncodAndDelayType" separator=".">
   <suffix name="JPEG"/>
   <suffix name="PNG"/>
-  <affected-histogram name="Blink.Canvas.ToBlob.IdleEncodeDuration"/>
+  <affected-histogram name="Blink.Canvas.ToBlob.CompleteEncodingDelay"/>
+  <affected-histogram name="Blink.Canvas.ToBlob.IdleEncodeDuration">
+    <obsolete>
+      Replaced with Blink.Canvas.ToBlob.CompleteEncodingDelay in 2017/12.
+    </obsolete>
+  </affected-histogram>
   <affected-histogram name="Blink.Canvas.ToBlob.InitiateEncodingDelay"/>
 </histogram_suffixes>
 
diff --git a/ui/aura/test/aura_test_helper.cc b/ui/aura/test/aura_test_helper.cc
index 07ac3ce..dec50b8b 100644
--- a/ui/aura/test/aura_test_helper.cc
+++ b/ui/aura/test/aura_test_helper.cc
@@ -31,7 +31,6 @@
 #include "ui/base/ime/input_method_factory.h"
 #include "ui/base/ime/input_method_initializer.h"
 #include "ui/base/platform_window_defaults.h"
-#include "ui/base/ui_base_switches.h"
 #include "ui/compositor/compositor.h"
 #include "ui/compositor/layer_animator.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
@@ -121,10 +120,6 @@
   capture_client_ = std::make_unique<client::DefaultCaptureClient>();
   const Env::Mode env_mode =
       (mode_ == Mode::LOCAL) ? Env::Mode::LOCAL : Env::Mode::MUS;
-  if (env_mode == Env::Mode::MUS) {
-    base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-        switches::kMus, switches::kMusHostVizValue);
-  }
 
   if (mode_ == Mode::MUS_CREATE_WINDOW_TREE_CLIENT)
     InitWindowTreeClient();
diff --git a/ui/base/models/table_model.cc b/ui/base/models/table_model.cc
index d98cdb2..144ba862c 100644
--- a/ui/base/models/table_model.cc
+++ b/ui/base/models/table_model.cc
@@ -50,28 +50,6 @@
   return base::string16();
 }
 
-bool TableModel::ShouldIndent(int row) {
-  return false;
-}
-
-bool TableModel::HasGroups() {
-  return false;
-}
-
-TableModel::Groups TableModel::GetGroups() {
-  // If you override HasGroups to return true, you must override this as
-  // well.
-  NOTREACHED();
-  return std::vector<Group>();
-}
-
-int TableModel::GetGroupID(int row) {
-  // If you override HasGroups to return true, you must override this as
-  // well.
-  NOTREACHED();
-  return 0;
-}
-
 int TableModel::CompareValues(int row1, int row2, int column_id) {
   DCHECK(row1 >= 0 && row1 < RowCount() &&
          row2 >= 0 && row2 < RowCount());
diff --git a/ui/base/models/table_model.h b/ui/base/models/table_model.h
index c7172f4..110ae3c 100644
--- a/ui/base/models/table_model.h
+++ b/ui/base/models/table_model.h
@@ -22,16 +22,6 @@
 // The model driving the TableView.
 class UI_BASE_EXPORT TableModel {
  public:
-  // See HasGroups, get GetGroupID for details as to how this is used.
-  struct Group {
-    // The title text for the group.
-    base::string16 title;
-
-    // Unique id for the group.
-    int id;
-  };
-  typedef std::vector<Group> Groups;
-
   // Number of rows in the model.
   virtual int RowCount() = 0;
 
@@ -49,25 +39,6 @@
   // column zero.
   virtual base::string16 GetTooltip(int row);
 
-  // If true, this row should be indented.
-  virtual bool ShouldIndent(int row);
-
-  // Returns true if the TableView has groups. Groups provide a way to visually
-  // delineate the rows in a table view. When groups are enabled table view
-  // shows a visual separator for each group, followed by all the rows in
-  // the group.
-  //
-  // On win2k a visual separator is not rendered for the group headers.
-  virtual bool HasGroups();
-
-  // Returns the groups.
-  // This is only used if HasGroups returns true.
-  virtual Groups GetGroups();
-
-  // Returns the group id of the specified row.
-  // This is only used if HasGroups returns true.
-  virtual int GetGroupID(int row);
-
   // Sets the observer for the model. The TableView should NOT take ownership
   // of the observer.
   virtual void SetObserver(TableModelObserver* observer) = 0;
diff --git a/ui/compositor/test/in_process_context_provider.cc b/ui/compositor/test/in_process_context_provider.cc
index 12292c6..73ac986 100644
--- a/ui/compositor/test/in_process_context_provider.cc
+++ b/ui/compositor/test/in_process_context_provider.cc
@@ -98,7 +98,8 @@
       !window_, /* is_offscreen */
       window_, (shared_context_ ? shared_context_->context_.get() : nullptr),
       attribs_, gpu::SharedMemoryLimits(), gpu_memory_buffer_manager_,
-      image_factory_, base::ThreadTaskRunnerHandle::Get());
+      image_factory_, nullptr /* gpu_channel_manager_delegate */,
+      base::ThreadTaskRunnerHandle::Get());
 
   if (bind_result_ != gpu::ContextResult::kSuccess)
     return bind_result_;
diff --git a/ui/gfx/win/rendering_window_manager.cc b/ui/gfx/win/rendering_window_manager.cc
index a0528ecf..4f2cbfb7 100644
--- a/ui/gfx/win/rendering_window_manager.cc
+++ b/ui/gfx/win/rendering_window_manager.cc
@@ -4,7 +4,10 @@
 
 #include "ui/gfx/win/rendering_window_manager.h"
 
+#include "base/callback.h"
 #include "base/memory/singleton.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/task_scheduler/task_traits.h"
 
 namespace gfx {
 
@@ -16,11 +19,11 @@
 void RenderingWindowManager::RegisterParent(HWND parent) {
   base::AutoLock lock(lock_);
 
-  info_[parent] = nullptr;
+  info_.emplace(parent, EmeddingInfo());
 }
 
-bool RenderingWindowManager::RegisterChild(HWND parent, HWND child_window) {
-  if (!child_window)
+bool RenderingWindowManager::RegisterChild(HWND parent, HWND child) {
+  if (!child)
     return false;
 
   base::AutoLock lock(lock_);
@@ -28,10 +31,22 @@
   auto it = info_.find(parent);
   if (it == info_.end())
     return false;
-  if (it->second)
+
+  EmeddingInfo& info = it->second;
+  if (info.child)
     return false;
 
-  info_[parent] = child_window;
+  info.child = child;
+
+  // DoSetParentOnChild() was already called for |parent|. Call ::SetParent()
+  // now but from a worker thread instead of the IO thread. The ::SetParent()
+  // call could block the IO thread waiting on the UI thread and deadlock.
+  if (info.call_set_parent) {
+    base::PostTaskWithTraits(
+        FROM_HERE, {base::TaskPriority::USER_BLOCKING},
+        base::BindOnce(base::IgnoreResult(&::SetParent), child, parent));
+  }
+
   return true;
 }
 
@@ -43,9 +58,17 @@
     auto it = info_.find(parent);
     if (it == info_.end())
       return;
-    if (!it->second)
+
+    EmeddingInfo& info = it->second;
+
+    DCHECK(!info.call_set_parent);
+    info.call_set_parent = true;
+
+    // Call ::SetParent() once RegisterChild() is called.
+    if (!info.child)
       return;
-    child = it->second;
+
+    child = info.child;
   }
 
   ::SetParent(child, parent);
@@ -61,7 +84,7 @@
   auto it = info_.find(parent);
   if (it == info_.end())
     return false;
-  return !!it->second && ::IsWindow(it->second);
+  return !!it->second.child && ::IsWindow(it->second.child);
 }
 
 RenderingWindowManager::RenderingWindowManager() {}
diff --git a/ui/gfx/win/rendering_window_manager.h b/ui/gfx/win/rendering_window_manager.h
index bbb74ac..454e9dd 100644
--- a/ui/gfx/win/rendering_window_manager.h
+++ b/ui/gfx/win/rendering_window_manager.h
@@ -7,8 +7,7 @@
 
 #include <windows.h>
 
-#include <map>
-
+#include "base/containers/flat_map.h"
 #include "base/synchronization/lock.h"
 #include "ui/gfx/gfx_export.h"
 
@@ -34,11 +33,19 @@
  private:
   friend struct base::DefaultSingletonTraits<RenderingWindowManager>;
 
+  struct EmeddingInfo {
+    // The child window.
+    HWND child = nullptr;
+
+    // SetParent() should be called for child window.
+    bool call_set_parent = false;
+  };
+
   RenderingWindowManager();
   ~RenderingWindowManager();
 
   base::Lock lock_;
-  std::map<HWND, HWND> info_;
+  base::flat_map<HWND, EmeddingInfo> info_;
 
   DISALLOW_COPY_AND_ASSIGN(RenderingWindowManager);
 };
diff --git a/ui/gl/init/create_gr_gl_interface.cc b/ui/gl/init/create_gr_gl_interface.cc
index c48be07..e7b1c6e 100644
--- a/ui/gl/init/create_gr_gl_interface.cc
+++ b/ui/gl/init/create_gr_gl_interface.cc
@@ -87,6 +87,7 @@
   functions->fBindAttribLocation = gl->glBindAttribLocationFn;
   functions->fBindBuffer = gl->glBindBufferFn;
   functions->fBindFragDataLocation = gl->glBindFragDataLocationFn;
+  functions->fBindUniformLocation = gl->glBindUniformLocationCHROMIUMFn;
   functions->fBeginQuery = gl->glBeginQueryFn;
   functions->fBindTexture = gl->glBindTextureFn;