diff --git a/BUILD.gn b/BUILD.gn
index 1f7a397..c8e2bae 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -183,8 +183,8 @@
       "//storage//browser:storage_unittests",
       "//third_party/WebKit/Source/platform:blink_platform_unittests",
       "//third_party/WebKit/Source/platform/heap:blink_heap_unittests",
+      "//third_party/WebKit/Source/platform/wtf:wtf_unittests",
       "//third_party/WebKit/Source/web:webkit_unit_tests",
-      "//third_party/WebKit/Source/wtf:wtf_unittests",
       "//third_party/angle/src/tests:angle_end2end_tests",
       "//third_party/angle/src/tests:angle_unittests",
       "//third_party/angle/src/tests:angle_white_box_tests",
diff --git a/cc/resources/video_resource_updater.cc b/cc/resources/video_resource_updater.cc
index 2ad91ae..fa01b03 100644
--- a/cc/resources/video_resource_updater.cc
+++ b/cc/resources/video_resource_updater.cc
@@ -21,6 +21,7 @@
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "media/base/video_frame.h"
 #include "media/renderers/skcanvas_video_renderer.h"
+#include "media/video/half_float_maker.h"
 #include "third_party/khronos/GLES2/gl2.h"
 #include "third_party/khronos/GLES2/gl2ext.h"
 #include "third_party/libyuv/include/libyuv.h"
@@ -298,89 +299,6 @@
   return gfx::Size(plane_width, plane_height);
 }
 
-namespace {
-// By OR-ing with 0x3800, 10-bit numbers become half-floats in the
-// range [0.5..1) and 9-bit numbers get the range [0.5..0.75).
-//
-// Half-floats are evaluated as:
-// float value = pow(2.0, exponent - 25) * (0x400 + fraction);
-//
-// In our case the exponent is 14 (since we or with 0x3800) and
-// pow(2.0, 14-25) * 0x400 evaluates to 0.5 (our offset) and
-// pow(2.0, 14-25) * fraction is [0..0.49951171875] for 10-bit and
-// [0..0.24951171875] for 9-bit.
-//
-// https://en.wikipedia.org/wiki/Half-precision_floating-point_format
-class HalfFloatMaker_xor : public VideoResourceUpdater::HalfFloatMaker {
- public:
-  explicit HalfFloatMaker_xor(int bits_per_channel)
-      : bits_per_channel_(bits_per_channel) {}
-  float Offset() const override { return 0.5; }
-  float Multiplier() const override {
-    int max_input_value = (1 << bits_per_channel_) - 1;
-    // 2 << 11 = 2048 would be 1.0 with our exponent.
-    return 2048.0 / max_input_value;
-  }
-  void MakeHalfFloats(const uint16_t* src, size_t num, uint16_t* dst) override {
-    // Micro-benchmarking indicates that the compiler does
-    // a good enough job of optimizing this loop that trying
-    // to manually operate on one uint64 at a time is not
-    // actually helpful.
-    // Note to future optimizers: Benchmark your optimizations!
-    for (size_t i = 0; i < num; i++)
-      dst[i] = src[i] | 0x3800;
-  }
-
- private:
-  int bits_per_channel_;
-};
-
-class HalfFloatMaker_libyuv : public VideoResourceUpdater::HalfFloatMaker {
- public:
-  explicit HalfFloatMaker_libyuv(int bits_per_channel) {
-    int max_value = (1 << bits_per_channel) - 1;
-    // For less than 15 bits, we can give libyuv a multiplier of
-    // 1.0, which is faster on some platforms. If bits is 16 or larger,
-    // a multiplier of 1.0 would cause overflows. However, a multiplier
-    // of 1/max_value would cause subnormal floats, which perform
-    // very poorly on some platforms.
-    if (bits_per_channel <= 15) {
-      libyuv_multiplier_ = 1.0f;
-    } else {
-      // This multiplier makes sure that we avoid subnormal values.
-      libyuv_multiplier_ = 1.0f / 4096.0f;
-    }
-    resource_multiplier_ = 1.0f / libyuv_multiplier_ / max_value;
-  }
-  float Offset() const override { return 0.0f; }
-  float Multiplier() const override { return resource_multiplier_; }
-  void MakeHalfFloats(const uint16_t* src, size_t num, uint16_t* dst) override {
-    // Source and dest stride can be zero since we're only copying
-    // one row at a time.
-    int stride = 0;
-    int rows = 1;
-    libyuv::HalfFloatPlane(src, stride, dst, stride, libyuv_multiplier_, num,
-                           rows);
-  }
-
- private:
-  float libyuv_multiplier_;
-  float resource_multiplier_;
-};
-
-}  // namespace
-
-std::unique_ptr<VideoResourceUpdater::HalfFloatMaker>
-VideoResourceUpdater::NewHalfFloatMaker(int bits_per_channel) {
-  if (bits_per_channel < 11) {
-    return std::unique_ptr<VideoResourceUpdater::HalfFloatMaker>(
-        new HalfFloatMaker_xor(bits_per_channel));
-  } else {
-    return std::unique_ptr<VideoResourceUpdater::HalfFloatMaker>(
-        new HalfFloatMaker_libyuv(bits_per_channel));
-  }
-}
-
 VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes(
     scoped_refptr<media::VideoFrame> video_frame) {
   TRACE_EVENT0("cc", "VideoResourceUpdater::CreateForSoftwarePlanes");
@@ -518,10 +436,11 @@
     return external_resources;
   }
 
-  std::unique_ptr<HalfFloatMaker> half_float_maker;
+  std::unique_ptr<media::HalfFloatMaker> half_float_maker;
   if (resource_provider_->YuvResourceFormat(bits_per_channel) ==
       LUMINANCE_F16) {
-    half_float_maker = NewHalfFloatMaker(bits_per_channel);
+    half_float_maker =
+        media::HalfFloatMaker::NewHalfFloatMaker(bits_per_channel);
     external_resources.offset = half_float_maker->Offset();
     external_resources.multiplier = half_float_maker->Multiplier();
   }
@@ -533,7 +452,7 @@
               resource_provider_->YuvResourceFormat(bits_per_channel));
 
     if (!plane_resource.Matches(video_frame->unique_id(), i)) {
-      // TODO(hubbe): Move all conversion (and upload?) code to media/.
+      // TODO(hubbe): Move upload code to media/.
       // We need to transfer data from |video_frame| to the plane resource.
       // TODO(reveman): Can use GpuMemoryBuffers here to improve performance.
 
diff --git a/cc/resources/video_resource_updater.h b/cc/resources/video_resource_updater.h
index 7cc2c81..603b4a3 100644
--- a/cc/resources/video_resource_updater.h
+++ b/cc/resources/video_resource_updater.h
@@ -80,28 +80,6 @@
   VideoFrameExternalResources CreateExternalResourcesFromVideoFrame(
       scoped_refptr<media::VideoFrame> video_frame);
 
-  // Base class for converting short integers to half-floats.
-  // TODO(hubbe): Move this to media/.
-  class HalfFloatMaker {
-   public:
-    // Convert an array of short integers into an array of half-floats.
-    // |src| is an array of integers in range 0 .. 2^{bits_per_channel} - 1
-    // |num| is number of entries in input and output array.
-    // The numbers stored in |dst| will be half floats in range 0.0..1.0
-    virtual void MakeHalfFloats(const uint16_t* src,
-                                size_t num,
-                                uint16_t* dst) = 0;
-    // The half-floats made needs by this class will be in the range
-    // [Offset() .. Offset() + 1.0/Multiplier]. So if you want results
-    // in the 0-1 range, you need to do:
-    //   (half_float - Offset()) * Multiplier()
-    // to each returned value.
-    virtual float Offset() const = 0;
-    virtual float Multiplier() const = 0;
-  };
-
-  static std::unique_ptr<HalfFloatMaker> NewHalfFloatMaker(
-      int bits_per_channel);
 
  private:
   class PlaneResource {
diff --git a/cc/resources/video_resource_updater_unittest.cc b/cc/resources/video_resource_updater_unittest.cc
index 4b54fbe7..3c7874e4 100644
--- a/cc/resources/video_resource_updater_unittest.cc
+++ b/cc/resources/video_resource_updater_unittest.cc
@@ -519,62 +519,5 @@
   EXPECT_FALSE(context3d_->WasImmutableTextureCreated());
 }
 
-namespace {
-
-// Convert an IEEE 754 half-float to a double value
-// that we can do math on.
-double FromHalfFloat(uint16_t half_float) {
-  if (!half_float)
-    return 0.0;
-  int sign = (half_float & 0x8000) ? -1 : 1;
-  int exponent = (half_float >> 10) & 0x1F;
-  int fraction = half_float & 0x3FF;
-  if (exponent == 0) {
-    return pow(2.0, -24.0) * fraction;
-  } else if (exponent == 0x1F) {
-    return sign * 1000000000000.0;
-  } else {
-    return pow(2.0, exponent - 25) * (0x400 + fraction);
-  }
-}
-
-}  // namespace
-
-TEST_F(VideoResourceUpdaterTest, MakeHalfFloatTest) {
-  unsigned short integers[1 << 16];
-  unsigned short half_floats[1 << 16];
-  for (int bits = 9; bits <= 16; bits++) {
-    std::unique_ptr<VideoResourceUpdater::HalfFloatMaker> half_float_maker;
-    half_float_maker = VideoResourceUpdater::NewHalfFloatMaker(bits);
-    int num_values = 1 << bits;
-    for (int i = 0; i < num_values; i++)
-      integers[i] = i;
-
-    half_float_maker->MakeHalfFloats(integers, num_values, half_floats);
-    // Multiplier to converting integers to 0.0..1.0 range.
-    double multiplier = 1.0 / (num_values - 1);
-
-    for (int i = 0; i < num_values; i++) {
-      // This value is in range 0..1
-      float value = integers[i] * multiplier;
-      // Reverse the effect of offset and multiplier to get the expected
-      // output value from the half-float converter.
-      float expected_value =
-          value / half_float_maker->Multiplier() + half_float_maker->Offset();
-      EXPECT_EQ(integers[i], i);
-
-      // We expect the result to be within +/- one least-significant bit.
-      // Within the range we care about, half-floats values and
-      // their representation both sort in the same order, so we
-      // can just add one to get the next bigger half-float.
-      float expected_precision =
-          FromHalfFloat(half_floats[i] + 1) - FromHalfFloat(half_floats[i]);
-      EXPECT_NEAR(FromHalfFloat(half_floats[i]), expected_value,
-                  expected_precision)
-          << "i = " << i << " bits = " << bits;
-    }
-  }
-}
-
 }  // namespace
 }  // namespace cc
diff --git a/chrome/browser/resources/md_bookmarks/compiled_resources2.gyp b/chrome/browser/resources/md_bookmarks/compiled_resources2.gyp
index 263e0ac3..7ddb170 100644
--- a/chrome/browser/resources/md_bookmarks/compiled_resources2.gyp
+++ b/chrome/browser/resources/md_bookmarks/compiled_resources2.gyp
@@ -40,6 +40,7 @@
       'target_name': 'edit_dialog',
       'dependencies': [
         '<(DEPTH)/third_party/polymer/v1_0/components-chromium/iron-a11y-keys-behavior/compiled_resources2.gyp:iron-a11y-keys-behavior-extracted',
+        '<(DEPTH)/third_party/polymer/v1_0/components-chromium/paper-input/compiled_resources2.gyp:paper-input-extracted',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
         '<(EXTERNS_GYP):chrome_extensions',
diff --git a/chrome/browser/resources/md_bookmarks/edit_dialog.html b/chrome/browser/resources/md_bookmarks/edit_dialog.html
index 0808848..b2f23a3 100644
--- a/chrome/browser/resources/md_bookmarks/edit_dialog.html
+++ b/chrome/browser/resources/md_bookmarks/edit_dialog.html
@@ -18,9 +18,12 @@
             autofocus>
         </paper-input>
         <paper-input always-float-label id="url"
+            type="url"
             label="$i18n{editDialogUrlInput}"
+            error-message="$i18n{editDialogInvalidUrl}"
             value="{{urlValue_}}"
-            hidden$="[[isFolder_]]">
+            hidden$="[[isFolder_]]"
+            required>
         </paper-input>
       </div>
       <div class="button-container">
diff --git a/chrome/browser/resources/md_bookmarks/edit_dialog.js b/chrome/browser/resources/md_bookmarks/edit_dialog.js
index 6f7bccdd..6c3d635 100644
--- a/chrome/browser/resources/md_bookmarks/edit_dialog.js
+++ b/chrome/browser/resources/md_bookmarks/edit_dialog.js
@@ -33,8 +33,10 @@
     this.isFolder_ = !editItem.url;
 
     this.titleValue_ = editItem.title;
-    if (!this.isFolder_)
+    if (!this.isFolder_) {
+      this.$.url.invalid = false;
       this.urlValue_ = assert(editItem.url);
+    }
 
     this.$.dialog.showModal();
   },
@@ -49,12 +51,37 @@
         isFolder ? 'renameFolderTitle' : 'editBookmarkTitle');
   },
 
+  /**
+   * Validates the value of the URL field, returning true if it is a valid URL.
+   * May modify the value by prepending 'http://' in order to make it valid.
+   * @return {boolean}
+   * @private
+   */
+  validateUrl_: function() {
+    var urlInput = /** @type {PaperInputElement} */ (this.$.url);
+    var originalValue = this.urlValue_;
+
+    if (urlInput.validate())
+      return true;
+
+    this.urlValue_ = 'http://' + originalValue;
+
+    if (urlInput.validate())
+      return true;
+
+    this.urlValue_ = originalValue;
+    return false;
+  },
+
   /** @private */
   onSaveButtonTap_: function() {
-    // TODO(tsergeant): Verify values.
     var edit = {'title': this.titleValue_};
-    if (!this.isFolder_)
+    if (!this.isFolder_) {
+      if (!this.validateUrl_())
+        return;
+
       edit['url'] = this.urlValue_;
+    }
 
     chrome.bookmarks.update(this.editItem_.id, edit);
     this.$.dialog.close();
diff --git a/chrome/browser/ui/webui/md_bookmarks/md_bookmarks_ui.cc b/chrome/browser/ui/webui/md_bookmarks/md_bookmarks_ui.cc
index 620ed65..c5059be 100644
--- a/chrome/browser/ui/webui/md_bookmarks/md_bookmarks_ui.cc
+++ b/chrome/browser/ui/webui/md_bookmarks/md_bookmarks_ui.cc
@@ -36,6 +36,8 @@
   AddLocalizedString(source, "clearSearch",
                      IDS_MD_BOOKMARK_MANAGER_CLEAR_SEARCH);
   AddLocalizedString(source, "editBookmarkTitle", IDS_BOOKMARK_EDITOR_TITLE);
+  AddLocalizedString(source, "editDialogInvalidUrl",
+                     IDS_BOOKMARK_MANAGER_INVALID_URL);
   AddLocalizedString(source, "editDialogNameInput",
                      IDS_BOOKMARK_MANAGER_NAME_INPUT_PLACE_HOLDER);
   AddLocalizedString(source, "editDialogUrlInput",
diff --git a/chrome/test/data/webui/md_bookmarks/edit_dialog_test.js b/chrome/test/data/webui/md_bookmarks/edit_dialog_test.js
index 3eb9a2d..f433c9c 100644
--- a/chrome/test/data/webui/md_bookmarks/edit_dialog_test.js
+++ b/chrome/test/data/webui/md_bookmarks/edit_dialog_test.js
@@ -35,7 +35,7 @@
 
   test('editing passes the correct details to the update', function() {
     // Editing an item without changing anything.
-    var item = createItem('1', {url: 'www.website.com', title: 'website'});
+    var item = createItem('1', {url: 'http://website.com', title: 'website'});
     dialog.showEditDialog(item);
 
     MockInteractions.tap(dialog.$.saveButton);
@@ -63,4 +63,34 @@
     MockInteractions.pressEnter(dialog.$.url);
     assertFalse(dialog.$.dialog.open);
   });
+
+  test('validates urls correctly', function() {
+    dialog.urlValue_ = 'http://www.example.com';
+    assertTrue(dialog.validateUrl_());
+
+    dialog.urlValue_ = 'https://a@example.com:8080';
+    assertTrue(dialog.validateUrl_());
+
+    dialog.urlValue_ = 'example.com';
+    assertTrue(dialog.validateUrl_());
+    assertEquals('http://example.com', dialog.urlValue_);
+
+    dialog.urlValue_ = '';
+    assertFalse(dialog.validateUrl_());
+
+    dialog.urlValue_ = '~~~example.com~~~';
+    assertFalse(dialog.validateUrl_());
+  });
+
+  test('doesn\'t save when URL is invalid', function() {
+    var item = createItem('0');
+    dialog.showEditDialog(item);
+
+    dialog.urlValue_ = '';
+
+    MockInteractions.tap(dialog.$.saveButton);
+
+    assertTrue(dialog.$.url.invalid);
+    assertTrue(dialog.$.dialog.open);
+  });
 });
diff --git a/components/ntp_snippets/remote/fetch.py b/components/ntp_snippets/remote/fetch.py
new file mode 100755
index 0000000..199afb8
--- /dev/null
+++ b/components/ntp_snippets/remote/fetch.py
@@ -0,0 +1,228 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# 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.
+
+"""Fetches articles from the server.
+
+Examples:
+    $ fetch.py                        # unauthenticated, no experiments
+    $ fetch.py --short                # abbreviate instead of dumping JSON
+    $ fetch.py --signed-in -x3313279  # authenticated, results from Google Now
+
+If getting signed-in results, authenticates with OAuth2 and stores the
+credentials at ~/.zineauth.
+"""
+
+from __future__ import absolute_import, division, print_function, unicode_literals
+
+import argparse
+import base64
+import datetime
+import json
+import os
+import textwrap
+import oauth2client.client
+import oauth2client.file
+import oauth2client.tools
+import requests
+import sys
+
+
+API_KEY_FILE = os.path.join(
+    os.path.dirname(__file__),
+    "../../../google_apis/internal/google_chrome_api_keys.h")
+API_SCOPE = "https://www.googleapis.com/auth/chrome-content-suggestions"
+API_HOSTS = {
+    "prod": "https://chromecontentsuggestions-pa.googleapis.com",
+    "staging": "https://staging-chromecontentsuggestions-pa.googleapis.com",
+    "alpha": "https://alpha-chromecontentsuggestions-pa.sandbox.googleapis.com",
+}
+API_PATH = "/v1/suggestions/fetch"
+
+
+def main():
+  parser = argparse.ArgumentParser(
+      description="fetch articles from server",
+      parents=[oauth2client.tools.argparser])
+  parser.add_argument("-c", "--component",
+                      default="prod", choices=["prod", "staging", "alpha"],
+                      help="component to fetch from (default: prod)")
+  parser.add_argument("-x", "--experiment", action="append", type=int,
+                      help="include an experiment ID")
+  parser.add_argument("--api-key", type=str,
+                      help="API key to use for unauthenticated requests"
+                      " (default: use official key)")
+  parser.add_argument("-s", "--signed-in", action="store_true",
+                      help="sign in and issue authenticated request")
+  parser.add_argument("--client", metavar="ID,SECRET", type=str,
+                      help="client project to use for authenticated requests"
+                      " (default: use official project ID")
+  parser.add_argument("--short", action="store_true",
+                      help="print results in abbreviated form")
+  args = parser.parse_args()
+
+  r = PostRequest(args)
+  j = {}
+  try:
+    j = r.json()
+  except ValueError:
+    print(r.text)
+    sys.exit(1)
+  if j.get("error"):
+    print(r.text)
+    sys.exit(1)
+  if args.short:
+    PrintShortResponse(j)
+    return
+  print(r.text)
+  if r.status_code != 200:
+    sys.exit(1)
+
+
+def GetApiKeyFile():
+  return API_KEY_FILE
+
+
+def GetAPIDefs():
+  """Parses the internal file with API keys and returns a dict."""
+  with open(GetApiKeyFile()) as f:
+    lines = f.readlines()
+  defs = {}
+  next_name = None
+  for line in lines:
+    if next_name:
+      defs[next_name] = json.loads(line)
+      next_name = None
+    elif line.startswith("#define"):
+      try:
+        _, name, value = line.split()
+      except ValueError:
+        continue
+      if value == "\\":
+        next_name = name
+      else:
+        defs[name] = json.loads(value)
+  return defs
+
+
+def GetAPIKey():
+  return GetAPIDefs()["GOOGLE_API_KEY"]
+
+
+def GetOAuthClient():
+  defs = GetAPIDefs()
+  return defs["GOOGLE_CLIENT_ID_MAIN"], defs["GOOGLE_CLIENT_SECRET_MAIN"]
+
+
+def EncodeExperiments(experiments):
+  """Turn a list of experiment IDs into an X-Client-Data header value.
+
+  Encodes all the IDs as a protobuf (tag 1, varint) and base64 encodes the
+  result.
+  """
+  binary = b""
+  for exp in experiments:
+    binary += b"\x08"
+    while True:
+      byte = (exp & 0x7f)
+      exp >>= 7
+      if exp:
+        binary += chr(0x80 | byte)
+      else:
+        binary += chr(byte)
+        break
+  return base64.b64encode(binary)
+
+
+def AbbreviateDuration(duration):
+  """Turn a datetime.timedelta into a short string like "10h 14m"."""
+  w = duration.days // 7
+  d = duration.days % 7
+  h = duration.seconds // 3600
+  m = (duration.seconds % 3600) // 60
+  s = duration.seconds % 60
+  us = duration.microseconds
+  if w:
+    return "%dw %dd" % (w, d)
+  elif d:
+    return "%dd %dh" % (d, h)
+  elif h:
+    return "%dh %dm" % (h, m)
+  elif m:
+    return "%dm %ds" % (m, s)
+  elif s:
+    return "%ds" % s
+  elif us:
+    return "<1s"
+  else:
+    return "0s"
+
+
+def PostRequest(args):
+  url = API_HOSTS[args.component] + API_PATH
+  headers = {}
+
+  if args.experiment:
+    headers["X-Client-Data"] = EncodeExperiments(args.experiment)
+
+  if args.signed_in:
+    if args.client:
+      client_id, client_secret = args.client.split(",")
+    else:
+      client_id, client_secret = GetOAuthClient()
+    Authenticate(args, headers, client_id, client_secret)
+  else:
+    if args.api_key:
+      api_key = args.api_key
+    else:
+      api_key = GetAPIKey()
+    url += "?key=" + api_key
+
+  return requests.post(url, headers=headers)
+
+
+def Authenticate(args, headers, client_id, client_secret):
+  storage = oauth2client.file.Storage(os.path.expanduser("~/.zineauth"))
+  creds = storage.get()
+  if not creds or creds.invalid or creds.access_token_expired:
+    flow = oauth2client.client.OAuth2WebServerFlow(
+        client_id=client_id, client_secret=client_secret,
+        scope=API_SCOPE)
+    oauth2client.tools.run_flow(flow, storage, args)
+    creds = storage.get()
+  creds.apply(headers)
+
+
+def PrintShortResponse(r):
+  now = datetime.datetime.now()
+  for category in r.json()["categories"]:
+    print("%s: " % category["localizedTitle"])
+    for suggestion in category["suggestions"]:
+      attribution = suggestion["attribution"]
+      title = suggestion["title"]
+      full_url = suggestion["fullPageUrl"]
+      amp_url = suggestion.get("ampUrl")
+      creation_time = suggestion["creationTime"]
+
+      if len(title) > 40:
+        title = textwrap.wrap(title, 40)[0] + "…"
+      creation_time = ParseDateTime(creation_time)
+      age = AbbreviateDuration(now - creation_time)
+
+      print("  “%s” (%s, %s ago)" % (title, attribution, age))
+      print("    " + (amp_url or full_url))
+    if category["allowFetchingMoreResults"]:
+      print("  [More]")
+
+
+def ParseDateTime(creation_time):
+  try:
+    return datetime.datetime.strptime(creation_time, "%Y-%m-%dT%H:%M:%SZ")
+  except ValueError:
+    return datetime.datetime.strptime(creation_time, "%Y-%m-%dT%H:%M:%S.%fZ")
+
+
+if __name__ == "__main__":
+  main()
diff --git a/components/ntp_snippets/remote/remote_suggestions_fetcher.cc b/components/ntp_snippets/remote/remote_suggestions_fetcher.cc
index 080e06c..8bd852c 100644
--- a/components/ntp_snippets/remote/remote_suggestions_fetcher.cc
+++ b/components/ntp_snippets/remote/remote_suggestions_fetcher.cc
@@ -24,6 +24,7 @@
 #include "components/ntp_snippets/ntp_snippets_constants.h"
 #include "components/ntp_snippets/remote/request_params.h"
 #include "components/ntp_snippets/user_classifier.h"
+#include "components/signin/core/browser/access_token_fetcher.h"
 #include "components/signin/core/browser/signin_manager.h"
 #include "components/signin/core/browser/signin_manager_base.h"
 #include "components/strings/grit/components_strings.h"
@@ -243,8 +244,7 @@
     const GURL& api_endpoint,
     const std::string& api_key,
     const UserClassifier* user_classifier)
-    : OAuth2TokenService::Consumer("ntp_snippets"),
-      signin_manager_(signin_manager),
+    : signin_manager_(signin_manager),
       token_service_(token_service),
       url_request_context_getter_(std::move(url_request_context_getter)),
       language_model_(language_model),
@@ -254,11 +254,7 @@
       clock_(new base::DefaultClock()),
       user_classifier_(user_classifier) {}
 
-RemoteSuggestionsFetcher::~RemoteSuggestionsFetcher() {
-  if (waiting_for_refresh_token_) {
-    token_service_->RemoveObserver(this);
-  }
-}
+RemoteSuggestionsFetcher::~RemoteSuggestionsFetcher() = default;
 
 void RemoteSuggestionsFetcher::FetchSnippets(
     const RequestParams& params,
@@ -282,20 +278,10 @@
       .SetUrlRequestContextGetter(url_request_context_getter_)
       .SetUserClassifier(*user_classifier_);
 
-  if (signin_manager_->IsAuthenticated()) {
+  if (signin_manager_->IsAuthenticated() || signin_manager_->AuthInProgress()) {
     // Signed-in: get OAuth token --> fetch suggestions.
-    oauth_token_retried_ = false;
     pending_requests_.emplace(std::move(builder), std::move(callback));
     StartTokenRequest();
-  } else if (signin_manager_->AuthInProgress()) {
-    // Currently signing in: wait for auth to finish (the refresh token) -->
-    //     get OAuth token --> fetch suggestions.
-    pending_requests_.emplace(std::move(builder), std::move(callback));
-    if (!waiting_for_refresh_token_) {
-      // Wait until we get a refresh token.
-      waiting_for_refresh_token_ = true;
-      token_service_->AddObserver(this);
-    }
   } else {
     // Not signed in: fetch suggestions (without authentication).
     FetchSnippetsNonAuthenticated(std::move(builder), std::move(callback));
@@ -321,11 +307,10 @@
 void RemoteSuggestionsFetcher::FetchSnippetsAuthenticated(
     JsonRequest::Builder builder,
     SnippetsAvailableCallback callback,
-    const std::string& account_id,
     const std::string& oauth_access_token) {
   // TODO(jkrcal, treib): Add unit-tests for authenticated fetches.
   builder.SetUrl(fetch_url_)
-      .SetAuthentication(account_id,
+      .SetAuthentication(signin_manager_->GetAuthenticatedAccountId(),
                          base::StringPrintf(kAuthorizationRequestHeaderFormat,
                                             oauth_access_token.c_str()));
   StartRequest(std::move(builder), std::move(callback));
@@ -342,23 +327,33 @@
 }
 
 void RemoteSuggestionsFetcher::StartTokenRequest() {
-  OAuth2TokenService::ScopeSet scopes;
-  scopes.insert(kContentSuggestionsApiScope);
-  oauth_request_ = token_service_->StartRequest(
-      signin_manager_->GetAuthenticatedAccountId(), scopes, this);
+  // If there is already an ongoing token request, just wait for that.
+  if (token_fetcher_) {
+    return;
+  }
+
+  OAuth2TokenService::ScopeSet scopes{kContentSuggestionsApiScope};
+  token_fetcher_ = base::MakeUnique<AccessTokenFetcher>(
+      "ntp_snippets", signin_manager_, token_service_, scopes,
+      base::BindOnce(&RemoteSuggestionsFetcher::AccessTokenFetchFinished,
+                     base::Unretained(this)));
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// OAuth2TokenService::Consumer overrides
-void RemoteSuggestionsFetcher::OnGetTokenSuccess(
-    const OAuth2TokenService::Request* request,
-    const std::string& access_token,
-    const base::Time& expiration_time) {
-  // Delete the request after we leave this method.
-  std::unique_ptr<OAuth2TokenService::Request> oauth_request(
-      std::move(oauth_request_));
-  DCHECK_EQ(oauth_request.get(), request)
-      << "Got tokens from some previous request";
+void RemoteSuggestionsFetcher::AccessTokenFetchFinished(
+    const GoogleServiceAuthError& error,
+    const std::string& access_token) {
+  // Delete the fetcher only after we leave this method (which is called from
+  // the fetcher itself).
+  DCHECK(token_fetcher_);
+  std::unique_ptr<AccessTokenFetcher> token_fetcher_deleter(
+      std::move(token_fetcher_));
+
+  if (error.state() != GoogleServiceAuthError::NONE) {
+    AccessTokenError(error);
+    return;
+  }
+
+  DCHECK(!access_token.empty());
 
   while (!pending_requests_.empty()) {
     std::pair<JsonRequest::Builder, SnippetsAvailableCallback>
@@ -366,25 +361,16 @@
     pending_requests_.pop();
     FetchSnippetsAuthenticated(std::move(builder_and_callback.first),
                                std::move(builder_and_callback.second),
-                               oauth_request->GetAccountId(), access_token);
+                               access_token);
   }
 }
 
-void RemoteSuggestionsFetcher::OnGetTokenFailure(
-    const OAuth2TokenService::Request* request,
+void RemoteSuggestionsFetcher::AccessTokenError(
     const GoogleServiceAuthError& error) {
-  oauth_request_.reset();
-
-  if (!oauth_token_retried_ &&
-      error.state() == GoogleServiceAuthError::State::REQUEST_CANCELED) {
-    // The request (especially on startup) can get reset by loading the refresh
-    // token - do it one more time.
-    oauth_token_retried_ = true;
-    StartTokenRequest();
-    return;
-  }
+  DCHECK_NE(error.state(), GoogleServiceAuthError::NONE);
 
   DLOG(ERROR) << "Unable to get token: " << error.ToString();
+
   while (!pending_requests_.empty()) {
     std::pair<JsonRequest::Builder, SnippetsAvailableCallback>
         builder_and_callback = std::move(pending_requests_.front());
@@ -398,21 +384,6 @@
   }
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// OAuth2TokenService::Observer overrides
-void RemoteSuggestionsFetcher::OnRefreshTokenAvailable(
-    const std::string& account_id) {
-  // Only react on tokens for the account the user has signed in with.
-  if (account_id != signin_manager_->GetAuthenticatedAccountId()) {
-    return;
-  }
-
-  token_service_->RemoveObserver(this);
-  waiting_for_refresh_token_ = false;
-  oauth_token_retried_ = false;
-  StartTokenRequest();
-}
-
 void RemoteSuggestionsFetcher::JsonRequestDone(
     std::unique_ptr<JsonRequest> request,
     SnippetsAvailableCallback callback,
diff --git a/components/ntp_snippets/remote/remote_suggestions_fetcher.h b/components/ntp_snippets/remote/remote_suggestions_fetcher.h
index f767f1cf..ffe7fd9 100644
--- a/components/ntp_snippets/remote/remote_suggestions_fetcher.h
+++ b/components/ntp_snippets/remote/remote_suggestions_fetcher.h
@@ -25,6 +25,8 @@
 #include "components/version_info/version_info.h"
 #include "net/url_request/url_request_context_getter.h"
 
+class AccessTokenFetcher;
+class OAuth2TokenService;
 class PrefService;
 class SigninManagerBase;
 
@@ -60,8 +62,7 @@
 // TODO(fhorschig): Untangle cyclic dependencies by introducing a
 // RemoteSuggestionsFetcherInterface. (Would be good for mock implementations,
 // too!)
-class RemoteSuggestionsFetcher : public OAuth2TokenService::Consumer,
-                                 public OAuth2TokenService::Observer {
+class RemoteSuggestionsFetcher {
  public:
   struct FetchedCategory {
     Category category;
@@ -90,7 +91,7 @@
       const GURL& api_endpoint,
       const std::string& api_key,
       const UserClassifier* user_classifier);
-  ~RemoteSuggestionsFetcher() override;
+  ~RemoteSuggestionsFetcher();
 
   // Initiates a fetch from the server. When done (successfully or not), calls
   // the callback.
@@ -135,22 +136,15 @@
                                      SnippetsAvailableCallback callback);
   void FetchSnippetsAuthenticated(internal::JsonRequest::Builder builder,
                                   SnippetsAvailableCallback callback,
-                                  const std::string& account_id,
                                   const std::string& oauth_access_token);
   void StartRequest(internal::JsonRequest::Builder builder,
                     SnippetsAvailableCallback callback);
 
   void StartTokenRequest();
 
-  // OAuth2TokenService::Consumer overrides:
-  void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
-                         const std::string& access_token,
-                         const base::Time& expiration_time) override;
-  void OnGetTokenFailure(const OAuth2TokenService::Request* request,
-                         const GoogleServiceAuthError& error) override;
-
-  // OAuth2TokenService::Observer overrides:
-  void OnRefreshTokenAvailable(const std::string& account_id) override;
+  void AccessTokenFetchFinished(const GoogleServiceAuthError& error,
+                                const std::string& access_token);
+  void AccessTokenError(const GoogleServiceAuthError& error);
 
   void JsonRequestDone(std::unique_ptr<internal::JsonRequest> request,
                        SnippetsAvailableCallback callback,
@@ -169,11 +163,8 @@
   // Authentication for signed-in users.
   SigninManagerBase* signin_manager_;
   OAuth2TokenService* token_service_;
-  std::unique_ptr<OAuth2TokenService::Request> oauth_request_;
-  bool waiting_for_refresh_token_ = false;
 
-  // When a token request gets canceled, we want to retry once.
-  bool oauth_token_retried_ = false;
+  std::unique_ptr<AccessTokenFetcher> token_fetcher_;
 
   // Holds the URL request context.
   scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
diff --git a/components/ntp_snippets/remote/remote_suggestions_fetcher_unittest.cc b/components/ntp_snippets/remote/remote_suggestions_fetcher_unittest.cc
index 77b57ec..246372e 100644
--- a/components/ntp_snippets/remote/remote_suggestions_fetcher_unittest.cc
+++ b/components/ntp_snippets/remote/remote_suggestions_fetcher_unittest.cc
@@ -399,9 +399,11 @@
             GURL(kTestChromeContentSuggestionsSignedOutUrl)) {}
 };
 
-// TODO(jkrcal): Add unit-tests for the "authentication in progress" case as it
-// requires more changes (instead FakeSigninManagerBase use FakeSigninManager
-// which does not exist on ChromeOS). crbug.com/688310
+// TODO(jkrcal): Investigate whether the "authentication in progress" case can
+// ever happen (see discussion on https://codereview.chromium.org/2582573002),
+// and if so, add unit-tests for it. This will require more changes (instead of
+// FakeSigninManagerBase use FakeSigninManager which does not exist on
+// ChromeOS). crbug.com/688310
 class RemoteSuggestionsSignedInFetcherTest
     : public RemoteSuggestionsFetcherTestBase {
  public:
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index a40982f..a35245b 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -77,7 +77,7 @@
     "//device/screen_orientation/public/interfaces",
     "//device/vr",
     "//device/vr:features",
-    "//device/wake_lock",
+    "//device/wake_lock/public/interfaces",
     "//google_apis",
     "//gpu",
     "//gpu/command_buffer/client:gles2_implementation",
@@ -336,6 +336,8 @@
     "background_fetch/background_fetch_job_data.h",
     "background_fetch/background_fetch_job_info.cc",
     "background_fetch/background_fetch_job_info.h",
+    "background_fetch/background_fetch_registration_id.cc",
+    "background_fetch/background_fetch_registration_id.h",
     "background_fetch/background_fetch_request_info.cc",
     "background_fetch/background_fetch_request_info.h",
     "background_fetch/background_fetch_service_impl.cc",
@@ -1406,6 +1408,8 @@
     "user_metrics.cc",
     "utility_process_host_impl.cc",
     "utility_process_host_impl.h",
+    "wake_lock/wake_lock_context_host.cc",
+    "wake_lock/wake_lock_context_host.h",
     "web_contents/aura/gesture_nav_simple.cc",
     "web_contents/aura/gesture_nav_simple.h",
     "web_contents/aura/overscroll_navigation_overlay.cc",
diff --git a/content/browser/DEPS b/content/browser/DEPS
index b35c11e..32403d420 100644
--- a/content/browser/DEPS
+++ b/content/browser/DEPS
@@ -24,7 +24,7 @@
   "+device/screen_orientation/public/interfaces",
   "+device/sensors",
   "+device/vr",  # For WebVR API
-  "+device/wake_lock",
+  "+device/wake_lock/public/interfaces",
   # This can only be used on POSIX, in particular it mustn't be used on Windows
   # in the browser DLL.
   "+gin/v8_initializer.h",
diff --git a/content/browser/background_fetch/background_fetch_data_manager.cc b/content/browser/background_fetch/background_fetch_data_manager.cc
index f47bac8d..b4d60f165 100644
--- a/content/browser/background_fetch/background_fetch_data_manager.cc
+++ b/content/browser/background_fetch/background_fetch_data_manager.cc
@@ -23,9 +23,13 @@
 BackgroundFetchDataManager::CreateRequest(
     std::unique_ptr<BackgroundFetchJobInfo> job_info,
     BackgroundFetchRequestInfos request_infos) {
-  JobIdentifier id(job_info->service_worker_registration_id(), job_info->tag());
+  BackgroundFetchRegistrationId registration_id(
+      job_info->service_worker_registration_id(), job_info->origin(),
+      job_info->tag());
+
   // Ensure that this is not a duplicate request.
-  if (service_worker_tag_map_.find(id) != service_worker_tag_map_.end()) {
+  if (known_registrations_.find(registration_id) !=
+      known_registrations_.end()) {
     DVLOG(1) << "Origin " << job_info->origin()
              << " has already created a batch request with tag "
              << job_info->tag();
@@ -36,7 +40,7 @@
   // Add the request to our maps and return a JobData to track the individual
   // files in the request.
   const std::string job_guid = job_info->guid();
-  service_worker_tag_map_[id] = job_guid;
+  known_registrations_.insert(std::move(registration_id));
   WriteJobToStorage(std::move(job_info), std::move(request_infos));
   // TODO(harkness): Remove data when the job is complete.
 
diff --git a/content/browser/background_fetch/background_fetch_data_manager.h b/content/browser/background_fetch/background_fetch_data_manager.h
index 4dd3a868..a093da2d 100644
--- a/content/browser/background_fetch/background_fetch_data_manager.h
+++ b/content/browser/background_fetch/background_fetch_data_manager.h
@@ -5,14 +5,15 @@
 #ifndef CONTENT_BROWSER_BACKGROUND_FETCH_BACKGROUND_FETCH_DATA_MANAGER_H_
 #define CONTENT_BROWSER_BACKGROUND_FETCH_BACKGROUND_FETCH_DATA_MANAGER_H_
 
-#include <map>
 #include <memory>
+#include <set>
 #include <string>
 #include <unordered_map>
 
 #include "base/macros.h"
 #include "content/browser/background_fetch/background_fetch_job_data.h"
 #include "content/browser/background_fetch/background_fetch_job_info.h"
+#include "content/browser/background_fetch/background_fetch_registration_id.h"
 #include "content/common/content_export.h"
 #include "url/origin.h"
 
@@ -47,9 +48,8 @@
   // DataManager is guaranteed to be destructed before the Context.
   BackgroundFetchContext* background_fetch_context_;
 
-  // Map from <sw_registration_id, tag> to the job_guid for that tag.
-  using JobIdentifier = std::pair<int64_t, std::string>;
-  std::map<JobIdentifier, std::string> service_worker_tag_map_;
+  // Set of known background fetch registration ids.
+  std::set<BackgroundFetchRegistrationId> known_registrations_;
 
   // Temporary map to hold data which will be written to storage.
   // Map from job_guid to JobInfo.
diff --git a/content/browser/background_fetch/background_fetch_event_dispatcher.cc b/content/browser/background_fetch/background_fetch_event_dispatcher.cc
index 41cb2c1..291a19d 100644
--- a/content/browser/background_fetch/background_fetch_event_dispatcher.cc
+++ b/content/browser/background_fetch/background_fetch_event_dispatcher.cc
@@ -8,6 +8,7 @@
 #include "base/callback.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/strings/stringprintf.h"
+#include "content/browser/background_fetch/background_fetch_registration_id.h"
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/browser/service_worker/service_worker_registration.h"
 #include "content/browser/service_worker/service_worker_version.h"
@@ -69,17 +70,15 @@
 BackgroundFetchEventDispatcher::~BackgroundFetchEventDispatcher() = default;
 
 void BackgroundFetchEventDispatcher::DispatchBackgroundFetchAbortEvent(
-    int64_t service_worker_registration_id,
-    const GURL& origin,
-    const std::string& tag,
+    const BackgroundFetchRegistrationId& registration_id,
     base::Closure finished_closure) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   LoadServiceWorkerRegistrationForDispatch(
-      ServiceWorkerMetrics::EventType::BACKGROUND_FETCH_ABORT,
-      service_worker_registration_id, origin, std::move(finished_closure),
+      registration_id, ServiceWorkerMetrics::EventType::BACKGROUND_FETCH_ABORT,
+      std::move(finished_closure),
       base::Bind(
           &BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchAbortEvent,
-          tag));
+          registration_id.tag()));
 }
 
 void BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchAbortEvent(
@@ -92,18 +91,16 @@
 }
 
 void BackgroundFetchEventDispatcher::DispatchBackgroundFetchClickEvent(
-    int64_t service_worker_registration_id,
-    const GURL& origin,
-    const std::string& tag,
+    const BackgroundFetchRegistrationId& registration_id,
     mojom::BackgroundFetchState state,
     base::Closure finished_closure) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   LoadServiceWorkerRegistrationForDispatch(
-      ServiceWorkerMetrics::EventType::BACKGROUND_FETCH_CLICK,
-      service_worker_registration_id, origin, std::move(finished_closure),
+      registration_id, ServiceWorkerMetrics::EventType::BACKGROUND_FETCH_CLICK,
+      std::move(finished_closure),
       base::Bind(
           &BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchClickEvent,
-          tag, state));
+          registration_id.tag(), state));
 }
 
 void BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchClickEvent(
@@ -118,18 +115,16 @@
 }
 
 void BackgroundFetchEventDispatcher::DispatchBackgroundFetchFailEvent(
-    int64_t service_worker_registration_id,
-    const GURL& origin,
-    const std::string& tag,
+    const BackgroundFetchRegistrationId& registration_id,
     const std::vector<BackgroundFetchSettledFetch>& fetches,
     base::Closure finished_closure) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   LoadServiceWorkerRegistrationForDispatch(
-      ServiceWorkerMetrics::EventType::BACKGROUND_FETCH_FAIL,
-      service_worker_registration_id, origin, std::move(finished_closure),
+      registration_id, ServiceWorkerMetrics::EventType::BACKGROUND_FETCH_FAIL,
+      std::move(finished_closure),
       base::Bind(
           &BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchFailEvent,
-          tag, fetches));
+          registration_id.tag(), fetches));
 }
 
 void BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchFailEvent(
@@ -144,18 +139,16 @@
 }
 
 void BackgroundFetchEventDispatcher::DispatchBackgroundFetchedEvent(
-    int64_t service_worker_registration_id,
-    const GURL& origin,
-    const std::string& tag,
+    const BackgroundFetchRegistrationId& registration_id,
     const std::vector<BackgroundFetchSettledFetch>& fetches,
     base::Closure finished_closure) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   LoadServiceWorkerRegistrationForDispatch(
-      ServiceWorkerMetrics::EventType::BACKGROUND_FETCHED,
-      service_worker_registration_id, origin, std::move(finished_closure),
+      registration_id, ServiceWorkerMetrics::EventType::BACKGROUND_FETCHED,
+      std::move(finished_closure),
       base::Bind(
           &BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchedEvent,
-          tag, fetches));
+          registration_id.tag(), fetches));
 }
 
 void BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchedEvent(
@@ -170,13 +163,13 @@
 }
 
 void BackgroundFetchEventDispatcher::LoadServiceWorkerRegistrationForDispatch(
+    const BackgroundFetchRegistrationId& registration_id,
     ServiceWorkerMetrics::EventType event,
-    int64_t service_worker_registration_id,
-    const GURL& origin,
     base::Closure finished_closure,
     ServiceWorkerLoadedCallback loaded_callback) {
   service_worker_context_->FindReadyRegistrationForId(
-      service_worker_registration_id, origin,
+      registration_id.service_worker_registration_id(),
+      registration_id.origin().GetURL(),
       base::Bind(&BackgroundFetchEventDispatcher::StartActiveWorkerForDispatch,
                  event, std::move(finished_closure),
                  std::move(loaded_callback)));
diff --git a/content/browser/background_fetch/background_fetch_event_dispatcher.h b/content/browser/background_fetch/background_fetch_event_dispatcher.h
index 24a5933d..9d781ef 100644
--- a/content/browser/background_fetch/background_fetch_event_dispatcher.h
+++ b/content/browser/background_fetch/background_fetch_event_dispatcher.h
@@ -17,6 +17,7 @@
 
 namespace content {
 
+class BackgroundFetchRegistrationId;
 struct BackgroundFetchSettledFetch;
 class ServiceWorkerContextWrapper;
 class ServiceWorkerRegistration;
@@ -42,35 +43,29 @@
 
   // Dispatches the `backgroundfetchabort` event, which indicates that an active
   // background fetch was aborted by the user or another external event.
-  void DispatchBackgroundFetchAbortEvent(int64_t service_worker_registration_id,
-                                         const GURL& origin,
-                                         const std::string& tag,
-                                         base::Closure finished_closure);
+  void DispatchBackgroundFetchAbortEvent(
+      const BackgroundFetchRegistrationId& registration_id,
+      base::Closure finished_closure);
 
   // Dispatches the `backgroundfetchclick` event, which indicates that the user
   // interface displayed for an active background fetch was activated.
-  void DispatchBackgroundFetchClickEvent(int64_t service_worker_registration_id,
-                                         const GURL& origin,
-                                         const std::string& tag,
-                                         mojom::BackgroundFetchState state,
-                                         base::Closure finished_closure);
+  void DispatchBackgroundFetchClickEvent(
+      const BackgroundFetchRegistrationId& registration_id,
+      mojom::BackgroundFetchState state,
+      base::Closure finished_closure);
 
   // Dispatches the `backgroundfetchfail` event, which indicates that a
   // background fetch has finished with one or more failed fetches. The request-
   // response pairs are included.
   void DispatchBackgroundFetchFailEvent(
-      int64_t service_worker_registration_id,
-      const GURL& origin,
-      const std::string& tag,
+      const BackgroundFetchRegistrationId& registration_id,
       const std::vector<BackgroundFetchSettledFetch>& fetches,
       base::Closure finished_closure);
 
   // Dispatches the `backgroundfetched` event, which indicates that a background
   // fetch has successfully completed. The request-response pairs are included.
   void DispatchBackgroundFetchedEvent(
-      int64_t service_worker_registration_id,
-      const GURL& origin,
-      const std::string& tag,
+      const BackgroundFetchRegistrationId& registration_id,
       const std::vector<BackgroundFetchSettledFetch>& fetches,
       base::Closure finished_closure);
 
@@ -81,13 +76,12 @@
   // Phase at which the dispatching process finished. Used for UMA.
   enum class DispatchPhase { FINDING, STARTING, DISPATCHING };
 
-  // Loads the Service Worker identified by |service_worker_registration_id| and
+  // Loads the Service Worker identified included in the |registration_id| and
   // ensures that there is an activated version. Will invoke |finished_closure|,
   // log UMA and abort on error, or invoke |loaded_callback| on success.
   void LoadServiceWorkerRegistrationForDispatch(
+      const BackgroundFetchRegistrationId& registration_id,
       ServiceWorkerMetrics::EventType event,
-      int64_t service_worker_registration_id,
-      const GURL& origin,
       base::Closure finished_closure,
       ServiceWorkerLoadedCallback loaded_callback);
 
diff --git a/content/browser/background_fetch/background_fetch_event_dispatcher_unittest.cc b/content/browser/background_fetch/background_fetch_event_dispatcher_unittest.cc
index a061f73..007110e 100644
--- a/content/browser/background_fetch/background_fetch_event_dispatcher_unittest.cc
+++ b/content/browser/background_fetch/background_fetch_event_dispatcher_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/optional.h"
 #include "base/run_loop.h"
 #include "base/test/histogram_tester.h"
+#include "content/browser/background_fetch/background_fetch_registration_id.h"
 #include "content/browser/service_worker/embedded_worker_test_helper.h"
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/common/background_fetch/background_fetch_types.h"
@@ -190,6 +191,9 @@
     return service_worker_registration;
   }
 
+  // Helper function for getting an url::Origin object with the example origin.
+  url::Origin origin() const { return url::Origin(GURL(kExampleOrigin)); }
+
   BackgroundFetchEmbeddedWorkerTestHelper* test_helpers() {
     return &embedded_worker_test_helper_;
   }
@@ -236,11 +240,11 @@
 };
 
 TEST_F(BackgroundFetchEventDispatcherTest, DispatchInvalidRegistration) {
-  GURL origin(kExampleOrigin);
+  BackgroundFetchRegistrationId invalid_registration_id(
+      9042 /* random invalid id */, origin(), kExampleTag);
 
   base::RunLoop run_loop;
-  dispatcher()->DispatchBackgroundFetchAbortEvent(9042 /* random invalid Id */,
-                                                  origin, kExampleTag,
+  dispatcher()->DispatchBackgroundFetchAbortEvent(invalid_registration_id,
                                                   run_loop.QuitClosure());
 
   run_loop.Run();
@@ -258,13 +262,13 @@
   ASSERT_TRUE(service_worker_registration);
   ASSERT_TRUE(service_worker_registration->active_version());
 
-  GURL origin(kExampleOrigin);
+  BackgroundFetchRegistrationId registration_id(
+      service_worker_registration->id(), origin(), kExampleTag);
 
   {
     base::RunLoop run_loop;
-    dispatcher()->DispatchBackgroundFetchAbortEvent(
-        service_worker_registration->id(), origin, kExampleTag,
-        run_loop.QuitClosure());
+    dispatcher()->DispatchBackgroundFetchAbortEvent(registration_id,
+                                                    run_loop.QuitClosure());
 
     run_loop.Run();
   }
@@ -278,11 +282,13 @@
 
   test_helpers()->set_fail_abort_event(true);
 
+  BackgroundFetchRegistrationId second_registration_id(
+      service_worker_registration->id(), origin(), kExampleTag2);
+
   {
     base::RunLoop run_loop;
-    dispatcher()->DispatchBackgroundFetchAbortEvent(
-        service_worker_registration->id(), origin, kExampleTag2,
-        run_loop.QuitClosure());
+    dispatcher()->DispatchBackgroundFetchAbortEvent(second_registration_id,
+                                                    run_loop.QuitClosure());
 
     run_loop.Run();
   }
@@ -306,13 +312,14 @@
   ASSERT_TRUE(service_worker_registration);
   ASSERT_TRUE(service_worker_registration->active_version());
 
-  GURL origin(kExampleOrigin);
+  BackgroundFetchRegistrationId registration_id(
+      service_worker_registration->id(), origin(), kExampleTag);
 
   {
     base::RunLoop run_loop;
     dispatcher()->DispatchBackgroundFetchClickEvent(
-        service_worker_registration->id(), origin, kExampleTag,
-        mojom::BackgroundFetchState::PENDING, run_loop.QuitClosure());
+        registration_id, mojom::BackgroundFetchState::PENDING,
+        run_loop.QuitClosure());
 
     run_loop.Run();
   }
@@ -329,11 +336,14 @@
 
   test_helpers()->set_fail_click_event(true);
 
+  BackgroundFetchRegistrationId second_registration_id(
+      service_worker_registration->id(), origin(), kExampleTag2);
+
   {
     base::RunLoop run_loop;
     dispatcher()->DispatchBackgroundFetchClickEvent(
-        service_worker_registration->id(), origin, kExampleTag2,
-        mojom::BackgroundFetchState::SUCCEEDED, run_loop.QuitClosure());
+        second_registration_id, mojom::BackgroundFetchState::SUCCEEDED,
+        run_loop.QuitClosure());
 
     run_loop.Run();
   }
@@ -361,16 +371,16 @@
   ASSERT_TRUE(service_worker_registration);
   ASSERT_TRUE(service_worker_registration->active_version());
 
-  GURL origin(kExampleOrigin);
+  BackgroundFetchRegistrationId registration_id(
+      service_worker_registration->id(), origin(), kExampleTag);
 
   std::vector<BackgroundFetchSettledFetch> fetches;
   fetches.push_back(BackgroundFetchSettledFetch());
 
   {
     base::RunLoop run_loop;
-    dispatcher()->DispatchBackgroundFetchFailEvent(
-        service_worker_registration->id(), origin, kExampleTag, fetches,
-        run_loop.QuitClosure());
+    dispatcher()->DispatchBackgroundFetchFailEvent(registration_id, fetches,
+                                                   run_loop.QuitClosure());
 
     run_loop.Run();
   }
@@ -389,11 +399,13 @@
 
   test_helpers()->set_fail_fail_event(true);
 
+  BackgroundFetchRegistrationId second_registration_id(
+      service_worker_registration->id(), origin(), kExampleTag2);
+
   {
     base::RunLoop run_loop;
     dispatcher()->DispatchBackgroundFetchFailEvent(
-        service_worker_registration->id(), origin, kExampleTag2, fetches,
-        run_loop.QuitClosure());
+        second_registration_id, fetches, run_loop.QuitClosure());
 
     run_loop.Run();
   }
@@ -420,16 +432,16 @@
   ASSERT_TRUE(service_worker_registration);
   ASSERT_TRUE(service_worker_registration->active_version());
 
-  GURL origin(kExampleOrigin);
+  BackgroundFetchRegistrationId registration_id(
+      service_worker_registration->id(), origin(), kExampleTag);
 
   std::vector<BackgroundFetchSettledFetch> fetches;
   fetches.push_back(BackgroundFetchSettledFetch());
 
   {
     base::RunLoop run_loop;
-    dispatcher()->DispatchBackgroundFetchedEvent(
-        service_worker_registration->id(), origin, kExampleTag, fetches,
-        run_loop.QuitClosure());
+    dispatcher()->DispatchBackgroundFetchedEvent(registration_id, fetches,
+                                                 run_loop.QuitClosure());
 
     run_loop.Run();
   }
@@ -448,11 +460,13 @@
 
   test_helpers()->set_fail_fetched_event(true);
 
+  BackgroundFetchRegistrationId second_registration_id(
+      service_worker_registration->id(), origin(), kExampleTag2);
+
   {
     base::RunLoop run_loop;
     dispatcher()->DispatchBackgroundFetchedEvent(
-        service_worker_registration->id(), origin, kExampleTag2, fetches,
-        run_loop.QuitClosure());
+        second_registration_id, fetches, run_loop.QuitClosure());
 
     run_loop.Run();
   }
diff --git a/content/browser/background_fetch/background_fetch_registration_id.cc b/content/browser/background_fetch/background_fetch_registration_id.cc
new file mode 100644
index 0000000..46d6c679
--- /dev/null
+++ b/content/browser/background_fetch/background_fetch_registration_id.cc
@@ -0,0 +1,41 @@
+// 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 "content/browser/background_fetch/background_fetch_registration_id.h"
+
+namespace content {
+
+BackgroundFetchRegistrationId::BackgroundFetchRegistrationId(
+    int64_t service_worker_registration_id,
+    const url::Origin& origin,
+    const std::string& tag)
+    : service_worker_registration_id_(service_worker_registration_id),
+      origin_(origin),
+      tag_(tag) {}
+
+BackgroundFetchRegistrationId::BackgroundFetchRegistrationId(
+    BackgroundFetchRegistrationId&& other) = default;
+
+BackgroundFetchRegistrationId::~BackgroundFetchRegistrationId() = default;
+
+bool BackgroundFetchRegistrationId::operator==(
+    const BackgroundFetchRegistrationId& other) const {
+  return other.service_worker_registration_id_ ==
+             service_worker_registration_id_ &&
+         other.origin_ == origin_ && other.tag_ == tag_;
+}
+
+bool BackgroundFetchRegistrationId::operator!=(
+    const BackgroundFetchRegistrationId& other) const {
+  return !(*this == other);
+}
+
+bool BackgroundFetchRegistrationId::operator<(
+    const BackgroundFetchRegistrationId& other) const {
+  return service_worker_registration_id_ <
+             other.service_worker_registration_id_ ||
+         origin_ < other.origin_ || tag_ < other.tag_;
+}
+
+}  // namespace content
diff --git a/content/browser/background_fetch/background_fetch_registration_id.h b/content/browser/background_fetch/background_fetch_registration_id.h
new file mode 100644
index 0000000..b47f8f5
--- /dev/null
+++ b/content/browser/background_fetch/background_fetch_registration_id.h
@@ -0,0 +1,51 @@
+// 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 CONTENT_BROWSER_BACKGROUND_FETCH_BACKGROUND_FETCH_REGISTRATION_ID_H_
+#define CONTENT_BROWSER_BACKGROUND_FETCH_BACKGROUND_FETCH_REGISTRATION_ID_H_
+
+#include <stdint.h>
+#include <string>
+
+#include "base/macros.h"
+#include "content/common/content_export.h"
+#include "url/origin.h"
+
+namespace content {
+
+// The Background Fetch registration id corresponds to the information required
+// to uniquely identify a Background Fetch registration in scope of a profile.
+class CONTENT_EXPORT BackgroundFetchRegistrationId {
+ public:
+  BackgroundFetchRegistrationId(int64_t service_worker_registration_id,
+                                const url::Origin& origin,
+                                const std::string& tag);
+  BackgroundFetchRegistrationId(BackgroundFetchRegistrationId&& other);
+  ~BackgroundFetchRegistrationId();
+
+  // Returns whether the |other| registration id are identical or different.
+  bool operator==(const BackgroundFetchRegistrationId& other) const;
+  bool operator!=(const BackgroundFetchRegistrationId& other) const;
+
+  // Enables this type to be used in an std::map and std::set.
+  // TODO(peter): Delete this when we switch away from using maps.
+  bool operator<(const BackgroundFetchRegistrationId& other) const;
+
+  int64_t service_worker_registration_id() const {
+    return service_worker_registration_id_;
+  }
+  const url::Origin& origin() const { return origin_; }
+  const std::string& tag() const { return tag_; }
+
+ private:
+  int64_t service_worker_registration_id_;
+  url::Origin origin_;
+  std::string tag_;
+
+  DISALLOW_COPY_AND_ASSIGN(BackgroundFetchRegistrationId);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_BACKGROUND_FETCH_BACKGROUND_FETCH_REGISTRATION_ID_H_
diff --git a/content/browser/frame_host/render_frame_host_delegate.cc b/content/browser/frame_host/render_frame_host_delegate.cc
index 8d75514..4d0a8ea5 100644
--- a/content/browser/frame_host/render_frame_host_delegate.cc
+++ b/content/browser/frame_host/render_frame_host_delegate.cc
@@ -77,7 +77,7 @@
   return nullptr;
 }
 
-device::WakeLockServiceContext*
+device::mojom::WakeLockContext*
 RenderFrameHostDelegate::GetWakeLockServiceContext() {
   return nullptr;
 }
diff --git a/content/browser/frame_host/render_frame_host_delegate.h b/content/browser/frame_host/render_frame_host_delegate.h
index e00b771..197b64b4 100644
--- a/content/browser/frame_host/render_frame_host_delegate.h
+++ b/content/browser/frame_host/render_frame_host_delegate.h
@@ -38,7 +38,10 @@
 
 namespace device {
 class GeolocationServiceContext;
-class WakeLockServiceContext;
+
+namespace mojom {
+class WakeLockContext;
+}
 }
 
 namespace gfx {
@@ -192,7 +195,7 @@
   virtual device::GeolocationServiceContext* GetGeolocationServiceContext();
 
   // Gets the WakeLockServiceContext associated with this delegate.
-  virtual device::WakeLockServiceContext* GetWakeLockServiceContext();
+  virtual device::mojom::WakeLockContext* GetWakeLockServiceContext();
 
   // Notification that the frame wants to go into fullscreen mode.
   // |origin| represents the origin of the frame that requests fullscreen.
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 1043df3..b04daf76b 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -98,7 +98,8 @@
 #include "device/generic_sensor/sensor_provider_impl.h"
 #include "device/geolocation/geolocation_service_context.h"
 #include "device/vr/features.h"
-#include "device/wake_lock/wake_lock_service_context.h"
+#include "device/wake_lock/public/interfaces/wake_lock_context.mojom.h"
+#include "device/wake_lock/public/interfaces/wake_lock_service.mojom.h"
 #include "media/base/media_switches.h"
 #include "media/media_features.h"
 #include "media/mojo/interfaces/media_service.mojom.h"
@@ -2440,14 +2441,14 @@
                    base::Unretained(geolocation_service_context)));
   }
 
-  device::WakeLockServiceContext* wake_lock_service_context =
+  device::mojom::WakeLockContext* wake_lock_service_context =
       delegate_ ? delegate_->GetWakeLockServiceContext() : nullptr;
   if (wake_lock_service_context) {
     // WakeLockServiceContext is owned by WebContentsImpl so it will outlive
     // this RenderFrameHostImpl, hence a raw pointer can be bound to service
     // factory callback.
     GetInterfaceRegistry()->AddInterface<device::mojom::WakeLockService>(
-        base::Bind(&device::WakeLockServiceContext::CreateService,
+        base::Bind(&device::mojom::WakeLockContext::GetWakeLock,
                    base::Unretained(wake_lock_service_context)));
   }
 
diff --git a/content/browser/service_manager/service_manager_context.cc b/content/browser/service_manager/service_manager_context.cc
index bc49cfb2..caa9424 100644
--- a/content/browser/service_manager/service_manager_context.cc
+++ b/content/browser/service_manager/service_manager_context.cc
@@ -19,6 +19,7 @@
 #include "content/browser/child_process_launcher.h"
 #include "content/browser/gpu/gpu_process_host.h"
 #include "content/browser/service_manager/merge_dictionary.h"
+#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/public/browser/browser_thread.h"
@@ -284,10 +285,20 @@
 
 
   ServiceInfo device_info;
+#if defined(OS_ANDROID)
+  // See the comments on wake_lock_context_host.h for details on this
+  // callback.
+  device_info.factory =
+      base::Bind(&device::CreateDeviceService,
+                 BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE),
+                 BrowserThread::GetTaskRunnerForThread(BrowserThread::IO),
+                 base::Bind(&WakeLockContextHost::GetNativeViewForContext));
+#else
   device_info.factory =
       base::Bind(&device::CreateDeviceService,
                  BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE),
                  BrowserThread::GetTaskRunnerForThread(BrowserThread::IO));
+#endif
   device_info.task_runner = base::ThreadTaskRunnerHandle::Get();
   packaged_services_connection_->AddEmbeddedService(device::mojom::kServiceName,
                                                     device_info);
diff --git a/content/browser/wake_lock/wake_lock_browsertest.cc b/content/browser/wake_lock/wake_lock_browsertest.cc
index c86ad7b..fee42cae 100644
--- a/content/browser/wake_lock/wake_lock_browsertest.cc
+++ b/content/browser/wake_lock/wake_lock_browsertest.cc
@@ -12,7 +12,6 @@
 #include "content/public/test/test_utils.h"
 #include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test_utils_internal.h"
-#include "device/wake_lock/wake_lock_service_context.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 
@@ -22,6 +21,11 @@
 
 const char kBlinkWakeLockFeature[] = "WakeLock";
 
+void OnHasWakeLock(bool* out, bool has_wakelock) {
+  *out = has_wakelock;
+  base::MessageLoop::current()->QuitNow();
+}
+
 }  // namespace
 
 class WakeLockTest : public ContentBrowserTest {
@@ -62,12 +66,18 @@
     return GetNestedFrameNode()->current_frame_host();
   }
 
-  device::WakeLockServiceContext* GetWakeLockServiceContext() {
+  device::mojom::WakeLockContext* GetWakeLockServiceContext() {
     return GetWebContentsImpl()->GetWakeLockServiceContext();
   }
 
   bool HasWakeLock() {
-    return GetWakeLockServiceContext()->HasWakeLockForTests();
+    bool has_wakelock = false;
+    base::RunLoop run_loop;
+
+    GetWakeLockServiceContext()->HasWakeLockForTests(
+        base::Bind(&OnHasWakeLock, &has_wakelock));
+    run_loop.Run();
+    return has_wakelock;
   }
 
   void WaitForPossibleUpdate() {
diff --git a/content/browser/wake_lock/wake_lock_context_host.cc b/content/browser/wake_lock/wake_lock_context_host.cc
new file mode 100644
index 0000000..7376d05
--- /dev/null
+++ b/content/browser/wake_lock/wake_lock_context_host.cc
@@ -0,0 +1,60 @@
+// 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 "content/browser/wake_lock/wake_lock_context_host.h"
+
+#include "base/atomic_sequence_num.h"
+#include "base/lazy_instance.h"
+#include "content/public/common/service_manager_connection.h"
+#include "device/wake_lock/public/interfaces/wake_lock_context_provider.mojom.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "services/device/public/interfaces/constants.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
+
+namespace content {
+
+namespace {
+
+base::StaticAtomicSequenceNumber g_unique_id;
+
+base::LazyInstance<std::map<int, WakeLockContextHost*>>::Leaky
+    g_id_to_context_host = LAZY_INSTANCE_INITIALIZER;
+
+WakeLockContextHost* ContextHostFromId(int id) {
+  auto it = g_id_to_context_host.Get().find(id);
+  return it != g_id_to_context_host.Get().end() ? it->second : nullptr;
+}
+
+}  // namespace
+
+WakeLockContextHost::WakeLockContextHost(WebContents* web_contents)
+    : id_(g_unique_id.GetNext()), web_contents_(web_contents) {
+  g_id_to_context_host.Get()[id_] = this;
+
+  // Connect to a WakeLockContext, associating it with |id_| (note that in some
+  // testing contexts, the service manager connection isn't initialized).
+  if (ServiceManagerConnection::GetForProcess()) {
+    service_manager::Connector* connector =
+        ServiceManagerConnection::GetForProcess()->GetConnector();
+    DCHECK(connector);
+    device::mojom::WakeLockContextProviderPtr context_provider;
+    connector->BindInterface(device::mojom::kServiceName,
+                             mojo::MakeRequest(&context_provider));
+    context_provider->GetContext(id_, mojo::MakeRequest(&wake_lock_context_));
+  }
+}
+
+WakeLockContextHost::~WakeLockContextHost() {
+  g_id_to_context_host.Get().erase(id_);
+}
+
+// static
+gfx::NativeView WakeLockContextHost::GetNativeViewForContext(int context_id) {
+  WakeLockContextHost* context_host = ContextHostFromId(context_id);
+  if (context_host)
+    return context_host->web_contents_->GetNativeView();
+  return nullptr;
+}
+
+}  // namespace content
diff --git a/content/browser/wake_lock/wake_lock_context_host.h b/content/browser/wake_lock/wake_lock_context_host.h
new file mode 100644
index 0000000..30bfe5d
--- /dev/null
+++ b/content/browser/wake_lock/wake_lock_context_host.h
@@ -0,0 +1,48 @@
+// 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 CONTENT_BROWSER_WAKE_LOCK_WAKE_LOCK_CONTEXT_HOST_H_
+#define CONTENT_BROWSER_WAKE_LOCK_WAKE_LOCK_CONTEXT_HOST_H_
+
+#include "content/public/browser/web_contents.h"
+#include "device/wake_lock/public/interfaces/wake_lock_context.mojom.h"
+#include "device/wake_lock/public/interfaces/wake_lock_context_provider.mojom.h"
+#include "ui/gfx/native_widget_types.h"
+
+namespace content {
+
+// On Android, WakeLockContext requires the NativeView associated with the
+// context in order to lock the screen. WakeLockContextHost provides this
+// functionality by mapping WakeLockContext IDs to the WebContents associated
+// with those IDs.
+class WakeLockContextHost {
+ public:
+  explicit WakeLockContextHost(WebContents* web_contents);
+  ~WakeLockContextHost();
+
+  // This callback is passed into the DeviceService constructor in order to
+  // enable WakeLockContext to map a context ID to a Native View as necessary.
+  static gfx::NativeView GetNativeViewForContext(int context_id);
+
+  // Returns the WakeLockContext* to which this instance is connected.
+  device::mojom::WakeLockContext* GetWakeLockContext() {
+    return wake_lock_context_.get();
+  }
+
+ private:
+  // This instance's ID.
+  int id_;
+
+  // The WebContents that owns this instance.
+  WebContents* web_contents_;
+
+  // The WakeLockContext instance that is connected to this instance.
+  device::mojom::WakeLockContextPtr wake_lock_context_;
+
+  DISALLOW_COPY_AND_ASSIGN(WakeLockContextHost);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_WAKE_LOCK_WAKE_LOCK_CONTEXT_HOST_H_
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index d3765ab9..445cf50 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -126,7 +126,6 @@
 #include "content/public/common/web_preferences.h"
 #include "device/geolocation/geolocation_service_context.h"
 #include "device/nfc/nfc.mojom.h"
-#include "device/wake_lock/wake_lock_service_context.h"
 #include "net/base/url_util.h"
 #include "net/http/http_cache.h"
 #include "net/http/http_transaction_factory.h"
@@ -481,10 +480,9 @@
 #if BUILDFLAG(ENABLE_PLUGINS)
   pepper_playback_observer_.reset(new PepperPlaybackObserver(this));
 #endif
+
+  wake_lock_context_host_.reset(new WakeLockContextHost(this));
   loader_io_thread_notifier_.reset(new LoaderIOThreadNotifier(this));
-  wake_lock_service_context_.reset(new device::WakeLockServiceContext(
-      BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE),
-      base::Bind(&WebContentsImpl::GetNativeView, base::Unretained(this))));
   host_zoom_map_observer_.reset(new HostZoomMapObserver(this));
 }
 
@@ -2485,8 +2483,8 @@
   return geolocation_service_context_.get();
 }
 
-device::WakeLockServiceContext* WebContentsImpl::GetWakeLockServiceContext() {
-  return wake_lock_service_context_.get();
+device::mojom::WakeLockContext* WebContentsImpl::GetWakeLockServiceContext() {
+  return wake_lock_context_host_->GetWakeLockContext();
 }
 
 void WebContentsImpl::OnShowValidationMessage(
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 89c134f8..e475a18 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -31,6 +31,7 @@
 #include "content/browser/renderer_host/render_view_host_delegate.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_delegate.h"
+#include "content/browser/wake_lock/wake_lock_context_host.h"
 #include "content/common/accessibility_mode.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/color_chooser.h"
@@ -43,6 +44,7 @@
 #include "content/public/common/renderer_preferences.h"
 #include "content/public/common/resource_type.h"
 #include "content/public/common/three_d_api_types.h"
+#include "device/wake_lock/public/interfaces/wake_lock_context.mojom.h"
 #include "net/base/load_states.h"
 #include "net/http/http_response_headers.h"
 #include "ppapi/features/features.h"
@@ -78,7 +80,6 @@
 class SiteInstance;
 class TestWebContents;
 class TextInputManager;
-class WakeLockServiceContext;
 class WebContentsAudioMuter;
 class WebContentsDelegate;
 class WebContentsImpl;
@@ -488,7 +489,7 @@
       RenderFrameHost* render_frame_host,
       int browser_plugin_instance_id) override;
   device::GeolocationServiceContext* GetGeolocationServiceContext() override;
-  device::WakeLockServiceContext* GetWakeLockServiceContext() override;
+  device::mojom::WakeLockContext* GetWakeLockServiceContext() override;
   void EnterFullscreenMode(const GURL& origin) override;
   void ExitFullscreenMode(bool will_cause_resize) override;
   bool ShouldRouteMessageEvent(
@@ -1473,7 +1474,7 @@
   std::unique_ptr<device::GeolocationServiceContext>
       geolocation_service_context_;
 
-  std::unique_ptr<device::WakeLockServiceContext> wake_lock_service_context_;
+  std::unique_ptr<WakeLockContextHost> wake_lock_context_host_;
 
   std::unique_ptr<ScreenOrientationProvider> screen_orientation_provider_;
 
diff --git a/content/browser/webrtc/webrtc_audio_debug_recordings_browsertest.cc b/content/browser/webrtc/webrtc_audio_debug_recordings_browsertest.cc
index 4129ac8e7..ed6b0b05 100644
--- a/content/browser/webrtc/webrtc_audio_debug_recordings_browsertest.cc
+++ b/content/browser/webrtc/webrtc_audio_debug_recordings_browsertest.cc
@@ -186,9 +186,11 @@
 
 #if defined(OS_ANDROID) && defined(ADDRESS_SANITIZER)
 // Renderer crashes under Android ASAN: https://crbug.com/408496.
-#define MAYBE_CallWithAudioDebugRecordingsEnabledThenDisabled DISABLED_CallWithAudioDebugRecordingsEnabledThenDisabled
+#define MAYBE_CallWithAudioDebugRecordingsEnabledThenDisabled \
+  DISABLED_CallWithAudioDebugRecordingsEnabledThenDisabled
 #else
-#define MAYBE_CallWithAudioDebugRecordingsEnabledThenDisabled CallWithAudioDebugRecordingsEnabledThenDisabled
+#define MAYBE_CallWithAudioDebugRecordingsEnabledThenDisabled \
+  CallWithAudioDebugRecordingsEnabledThenDisabled
 #endif
 
 // As above, but enable and disable recordings before starting a call. No files
@@ -231,12 +233,21 @@
   base::ThreadRestrictions::SetIOAllowed(prev_io_allowed);
 }
 
+#if defined(OS_ANDROID) && defined(ADDRESS_SANITIZER)
 // Renderer crashes under Android ASAN: https://crbug.com/408496.
+#define MAYBE_TwoCallsWithAudioDebugRecordings \
+  DISABLED_TwoCallsWithAudioDebugRecordings
+#elif defined(OS_ANDROID)
 // Renderer crashes on Android M. https://crbug.com/535728.
-// TODO(grunell): Re-enable on all but Android. See conditions for the above two
-// tests.
+#define MAYBE_TwoCallsWithAudioDebugRecordings \
+  DISABLED_TwoCallsWithAudioDebugRecordings
+#else
+#define MAYBE_TwoCallsWithAudioDebugRecordings TwoCallsWithAudioDebugRecordings
+#endif
+
+// Same test as CallWithAudioDebugRecordings, but does two parallel calls.
 IN_PROC_BROWSER_TEST_F(WebRtcAudioDebugRecordingsBrowserTest,
-                       DISABLED_TwoCallsWithAudioDebugRecordings) {
+                       MAYBE_TwoCallsWithAudioDebugRecordings) {
   if (!media::AudioManager::Get()->HasAudioOutputDevices()) {
     LOG(INFO) << "Missing output devices: skipping test...";
     return;
diff --git a/content/public/app/mojo/content_browser_manifest.json b/content/public/app/mojo/content_browser_manifest.json
index c31412e..bce66119 100644
--- a/content/public/app/mojo/content_browser_manifest.json
+++ b/content/public/app/mojo/content_browser_manifest.json
@@ -55,6 +55,7 @@
         "content_renderer": [ "browser" ],
         "content_utility": [ "browser" ],
         "data_decoder": [ "image_decoder" ],
+        "device": [ "device:wake_lock" ],
         "file": [ "file:filesystem", "file:leveldb" ],
         "media": [ "media:media" ],
         "ui": [ "display_output_protection" ],
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 22dc425..09467ff 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -747,7 +747,7 @@
     "//device/screen_orientation/public/interfaces",
     "//device/sensors",
     "//device/sensors/public/cpp:full",
-    "//device/wake_lock",
+    "//device/wake_lock/public/interfaces",
     "//gin",
     "//gpu",
     "//gpu/ipc/host",
diff --git a/device/BUILD.gn b/device/BUILD.gn
index 08cb74dc..eba54e2 100644
--- a/device/BUILD.gn
+++ b/device/BUILD.gn
@@ -76,7 +76,6 @@
     "test/run_all_unittests.cc",
     "u2f/u2f_apdu_unittest.cc",
     "u2f/u2f_message_unittest.cc",
-    "wake_lock/wake_lock_service_context_unittest.cc",
   ]
 
   deps = [
diff --git a/device/gamepad/gamepad_provider_unittest.cc b/device/gamepad/gamepad_provider_unittest.cc
index b60dbf8..ad84543 100644
--- a/device/gamepad/gamepad_provider_unittest.cc
+++ b/device/gamepad/gamepad_provider_unittest.cc
@@ -70,7 +70,8 @@
   DISALLOW_COPY_AND_ASSIGN(GamepadProviderTest);
 };
 
-TEST_F(GamepadProviderTest, PollingAccess) {
+// Test is flaky. crbug.com/705367
+TEST_F(GamepadProviderTest, DISABLED_PollingAccess) {
   WebGamepads test_data;
   memset(&test_data, 0, sizeof(WebGamepads));
   test_data.items[0].connected = true;
diff --git a/device/wake_lock/BUILD.gn b/device/wake_lock/BUILD.gn
index 3ba8339..99febb8b 100644
--- a/device/wake_lock/BUILD.gn
+++ b/device/wake_lock/BUILD.gn
@@ -4,6 +4,8 @@
 
 source_set("wake_lock") {
   sources = [
+    "wake_lock_context_provider.cc",
+    "wake_lock_context_provider.h",
     "wake_lock_service_context.cc",
     "wake_lock_service_context.h",
     "wake_lock_service_impl.cc",
diff --git a/device/wake_lock/public/interfaces/BUILD.gn b/device/wake_lock/public/interfaces/BUILD.gn
index 7d246c8..9e5bb01 100644
--- a/device/wake_lock/public/interfaces/BUILD.gn
+++ b/device/wake_lock/public/interfaces/BUILD.gn
@@ -6,6 +6,8 @@
 
 mojom("interfaces") {
   sources = [
+    "wake_lock_context.mojom",
+    "wake_lock_context_provider.mojom",
     "wake_lock_service.mojom",
   ]
 }
diff --git a/device/wake_lock/public/interfaces/README.md b/device/wake_lock/public/interfaces/README.md
new file mode 100644
index 0000000..ee4679af
--- /dev/null
+++ b/device/wake_lock/public/interfaces/README.md
@@ -0,0 +1,19 @@
+Provides the ability to block the device / display from sleeping.
+
+On Android, the implementation is inherently coupled to the NativeView
+associated with the context of the requestor due to system APIs. To handle
+this coupling, the Wake Lock usage model on Android is as follows:
+
+(1) The embedder passes in a callback at Device Service construction that
+enables the Wake Lock implementation to map (embedder-specific) context IDs to
+NativeViews.
+(2) For a given embedder-specific context, a trusted client
+connects to the WakeLockContextProvider interface and gets a
+WakeLockContext instance that is associated with that context.
+(3) That trusted client then forwards requests to bind wake locks from
+untrusted clients that are made within that context, with the Wake Lock
+implementation using the callback from (1) as necessary to obtain the
+NativeView associated with that context.
+
+On other platforms, the usage model is similar but the callback is not
+necessary/employed.
diff --git a/device/wake_lock/public/interfaces/wake_lock_context.mojom b/device/wake_lock/public/interfaces/wake_lock_context.mojom
new file mode 100644
index 0000000..24cd02f
--- /dev/null
+++ b/device/wake_lock/public/interfaces/wake_lock_context.mojom
@@ -0,0 +1,17 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module device.mojom;
+
+import "device/wake_lock/public/interfaces/wake_lock_service.mojom";
+
+// Context in which WakeLockService instances operate.
+interface WakeLockContext {
+  // Gets a WakeLockService within this context.
+  GetWakeLock(WakeLockService& wake_lock);
+
+  // Test-only method that returns whethere a wake lock is currently active
+  // within this context.
+  HasWakeLockForTests() => (bool result);
+};
diff --git a/device/wake_lock/public/interfaces/wake_lock_context_provider.mojom b/device/wake_lock/public/interfaces/wake_lock_context_provider.mojom
new file mode 100644
index 0000000..442cf6d
--- /dev/null
+++ b/device/wake_lock/public/interfaces/wake_lock_context_provider.mojom
@@ -0,0 +1,15 @@
+// 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.
+
+module device.mojom;
+
+import "device/wake_lock/public/interfaces/wake_lock_context.mojom";
+
+interface WakeLockContextProvider {
+
+  // Gets a WakeLockContext that is associated with |context_id|. |context_id|
+  // is used to obtain the NativeView associated with the relevant context on
+  // Android (see WakeLockContextCallback).
+  GetContext(int32 context_id, WakeLockContext& context);
+};
diff --git a/device/wake_lock/wake_lock_context_provider.cc b/device/wake_lock/wake_lock_context_provider.cc
new file mode 100644
index 0000000..289b1c64
--- /dev/null
+++ b/device/wake_lock/wake_lock_context_provider.cc
@@ -0,0 +1,40 @@
+// 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 "device/wake_lock/wake_lock_context_provider.h"
+
+#include <utility>
+
+#include "mojo/public/cpp/bindings/strong_binding.h"
+
+namespace device {
+
+// static
+void WakeLockContextProvider::Create(
+    mojom::WakeLockContextProviderRequest request,
+    scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,
+    const WakeLockContextCallback& native_view_getter) {
+  mojo::MakeStrongBinding(base::MakeUnique<WakeLockContextProvider>(
+                              std::move(file_task_runner), native_view_getter),
+                          std::move(request));
+}
+
+WakeLockContextProvider::WakeLockContextProvider(
+    scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,
+    const WakeLockContextCallback& native_view_getter)
+    : file_task_runner_(std::move(file_task_runner)),
+      native_view_getter_(native_view_getter) {}
+
+WakeLockContextProvider::~WakeLockContextProvider() {}
+
+void WakeLockContextProvider::GetContext(
+    int context_id,
+    mojo::InterfaceRequest<mojom::WakeLockContext> request) {
+  // WakeLockServiceContext owns itself (see the comment on
+  // wake_lock_service_context.h).
+  new WakeLockServiceContext(std::move(request), context_id, file_task_runner_,
+                             native_view_getter_);
+}
+
+}  // namespace device
diff --git a/device/wake_lock/wake_lock_context_provider.h b/device/wake_lock/wake_lock_context_provider.h
new file mode 100644
index 0000000..9909a08
--- /dev/null
+++ b/device/wake_lock/wake_lock_context_provider.h
@@ -0,0 +1,44 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_WAKE_LOCK_WAKE_LOCK_CONTEXT_PROVIDER_H_
+#define DEVICE_WAKE_LOCK_WAKE_LOCK_CONTEXT_PROVIDER_H_
+
+#include "base/sequenced_task_runner.h"
+#include "device/wake_lock/public/interfaces/wake_lock_context.mojom.h"
+#include "device/wake_lock/public/interfaces/wake_lock_context_provider.mojom.h"
+#include "device/wake_lock/wake_lock_service_context.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "ui/gfx/native_widget_types.h"
+
+namespace device {
+
+// Serves requests for WakeLockContext connections.
+class WakeLockContextProvider : public mojom::WakeLockContextProvider {
+ public:
+  WakeLockContextProvider(
+      scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,
+      const WakeLockContextCallback& native_view_getter);
+  ~WakeLockContextProvider() override;
+
+  static void Create(
+      mojom::WakeLockContextProviderRequest request,
+      scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,
+      const WakeLockContextCallback& native_view_getter);
+
+  // mojom::WakeLockContextProvider:
+  void GetContext(
+      int context_id,
+      mojo::InterfaceRequest<mojom::WakeLockContext> request) override;
+
+ private:
+  scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
+  WakeLockContextCallback native_view_getter_;
+
+  DISALLOW_COPY_AND_ASSIGN(WakeLockContextProvider);
+};
+
+}  // namespace device
+
+#endif  // DEVICE_WAKE_LOCK_WAKE_LOCK_CONTEXT_PROVIDER_H_
diff --git a/device/wake_lock/wake_lock_service_context.cc b/device/wake_lock/wake_lock_service_context.cc
index d30f8cd..b56680f 100644
--- a/device/wake_lock/wake_lock_service_context.cc
+++ b/device/wake_lock/wake_lock_service_context.cc
@@ -11,26 +11,36 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "device/power_save_blocker/power_save_blocker.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
 
 namespace device {
 
 WakeLockServiceContext::WakeLockServiceContext(
+    mojom::WakeLockContextRequest request,
+    int context_id,
     scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,
-    base::Callback<gfx::NativeView()> native_view_getter)
+    const WakeLockContextCallback& native_view_getter)
     : main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
-      file_task_runner_(file_task_runner),
+      file_task_runner_(std::move(file_task_runner)),
       num_lock_requests_(0),
+#if defined(OS_ANDROID)
+      context_id_(context_id),
       native_view_getter_(native_view_getter),
-      weak_factory_(this) {}
+#endif
+      context_binding_(this, std::move(request)),
+      context_binding_encountered_error_(false) {
+  context_binding_.set_connection_error_handler(base::Bind(
+      &WakeLockServiceContext::OnContextBindingError, base::Unretained(this)));
+  wake_lock_bindings_.set_connection_error_handler(
+      base::Bind(&WakeLockServiceContext::DestroyIfNoLongerNeeded,
+                 base::Unretained(this)));
+}
 
 WakeLockServiceContext::~WakeLockServiceContext() {}
 
-void WakeLockServiceContext::CreateService(
+void WakeLockServiceContext::GetWakeLock(
     mojo::InterfaceRequest<mojom::WakeLockService> request) {
-  mojo::MakeStrongBinding(
-      base::MakeUnique<WakeLockServiceImpl>(weak_factory_.GetWeakPtr()),
-      std::move(request));
+  wake_lock_bindings_.AddBinding(base::MakeUnique<WakeLockServiceImpl>(this),
+                                 std::move(request));
 }
 
 void WakeLockServiceContext::RequestWakeLock() {
@@ -45,8 +55,9 @@
   UpdateWakeLock();
 }
 
-bool WakeLockServiceContext::HasWakeLockForTests() const {
-  return !!wake_lock_;
+void WakeLockServiceContext::HasWakeLockForTests(
+    const HasWakeLockForTestsCallback& callback) {
+  callback.Run(!!wake_lock_);
 }
 
 void WakeLockServiceContext::CreateWakeLock() {
@@ -57,7 +68,7 @@
       main_task_runner_, file_task_runner_));
 
 #if defined(OS_ANDROID)
-  gfx::NativeView native_view = native_view_getter_.Run();
+  gfx::NativeView native_view = native_view_getter_.Run(context_id_);
   if (native_view) {
     wake_lock_.get()->InitDisplaySleepBlocker(native_view);
   }
@@ -80,4 +91,18 @@
   }
 }
 
+void WakeLockServiceContext::OnContextBindingError() {
+  context_binding_encountered_error_ = true;
+  DestroyIfNoLongerNeeded();
+}
+
+void WakeLockServiceContext::DestroyIfNoLongerNeeded() {
+  if (context_binding_encountered_error_ && wake_lock_bindings_.empty()) {
+    // Delete this instance once there are no more live connections to it.
+    // However, ensure that this instance stays alive throughout the destructor
+    // of a WakeLockServiceImpl instance that might be triggering this callback.
+    base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
+  }
+}
+
 }  // namespace device
diff --git a/device/wake_lock/wake_lock_service_context.h b/device/wake_lock/wake_lock_service_context.h
index 01e7ebe..0baa1a7 100644
--- a/device/wake_lock/wake_lock_service_context.h
+++ b/device/wake_lock/wake_lock_service_context.h
@@ -12,25 +12,47 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
 #include "base/sequenced_task_runner.h"
+#include "device/wake_lock/public/interfaces/wake_lock_context.mojom.h"
 #include "device/wake_lock/wake_lock_service_impl.h"
+#include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/bindings/strong_binding_set.h"
 #include "ui/gfx/native_widget_types.h"
 
 namespace device {
 
 class PowerSaveBlocker;
 
-class WakeLockServiceContext {
+// Callback that maps a context ID to the NativeView associated with
+// that context. This callback is provided to the Device Service by its
+// embedder.
+using WakeLockContextCallback = base::Callback<gfx::NativeView(int)>;
+
+// Serves requests for WakeLockService connections within a given context.
+
+// Note that the lifetime model of WakeLockContext is somewhat complex: It must
+// stay alive as long as either
+// (1) Its Mojo connection is still valid (as the client might make future
+// GetWakeLock() calls) OR
+// (2) There are still live WakeLock instances that it has instantiated (since
+// they call into it when they receive Mojo requests from *their* clients).
+// Consequently, WakeLockContext monitors the state of the connections described
+// in (1) and (2), dying only when *all* of those connections go away.
+class WakeLockServiceContext : public mojom::WakeLockContext {
  public:
   WakeLockServiceContext(
+      mojom::WakeLockContextRequest request,
+      int context_id,
       scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,
-      base::Callback<gfx::NativeView()> native_view_getter);
-  ~WakeLockServiceContext();
+      const WakeLockContextCallback& native_view_getter);
+  ~WakeLockServiceContext() override;
 
-  // Creates a WakeLockServiceImpl that is strongly bound to |request|.
-  void CreateService(mojo::InterfaceRequest<mojom::WakeLockService> request);
+  // mojom::WakeLockContext:
+  void GetWakeLock(
+      mojo::InterfaceRequest<mojom::WakeLockService> request) override;
+  void HasWakeLockForTests(
+      const HasWakeLockForTestsCallback& callback) override;
 
   // Requests wake lock.
   void RequestWakeLock();
@@ -38,13 +60,14 @@
   // Cancels pending wake lock request.
   void CancelWakeLock();
 
-  // Used by tests.
-  bool HasWakeLockForTests() const;
-
  private:
   void CreateWakeLock();
   void RemoveWakeLock();
   void UpdateWakeLock();
+  void OnContextBindingError();
+
+  // Checks whether this instance is still needed, and if not, destroys it.
+  void DestroyIfNoLongerNeeded();
 
   scoped_refptr<base::SequencedTaskRunner> main_task_runner_;
   scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
@@ -53,9 +76,16 @@
 
   // The actual power save blocker for screen.
   std::unique_ptr<PowerSaveBlocker> wake_lock_;
-  base::Callback<gfx::NativeView()> native_view_getter_;
 
-  base::WeakPtrFactory<WakeLockServiceContext> weak_factory_;
+#if defined(OS_ANDROID)
+  int context_id_;
+  WakeLockContextCallback native_view_getter_;
+#endif
+
+  mojo::Binding<mojom::WakeLockContext> context_binding_;
+  bool context_binding_encountered_error_;
+
+  mojo::StrongBindingSet<mojom::WakeLockService> wake_lock_bindings_;
 
   DISALLOW_COPY_AND_ASSIGN(WakeLockServiceContext);
 };
diff --git a/device/wake_lock/wake_lock_service_context_unittest.cc b/device/wake_lock/wake_lock_service_context_unittest.cc
deleted file mode 100644
index 8b7f6d1..0000000
--- a/device/wake_lock/wake_lock_service_context_unittest.cc
+++ /dev/null
@@ -1,64 +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 "device/wake_lock/wake_lock_service_context.h"
-
-#include <memory>
-
-#include "base/message_loop/message_loop.h"
-#include "base/process/kill.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace device {
-
-class WakeLockServiceContextTest : public testing::Test {
- public:
-  WakeLockServiceContextTest()
-      : wake_lock_service_context_(
-            base::ThreadTaskRunnerHandle::Get(),
-            base::Bind(&WakeLockServiceContextTest::GetNativeView,
-                       base::Unretained(this))) {}
-
- protected:
-  void RequestWakeLock() { GetWakeLockServiceContext()->RequestWakeLock(); }
-
-  void CancelWakeLock() { GetWakeLockServiceContext()->CancelWakeLock(); }
-
-  WakeLockServiceContext* GetWakeLockServiceContext() {
-    return &wake_lock_service_context_;
-  }
-
-  bool HasWakeLock() {
-    return GetWakeLockServiceContext()->HasWakeLockForTests();
-  }
-
- private:
-  gfx::NativeView GetNativeView() { return nullptr; }
-
-  base::MessageLoop message_loop_;
-  WakeLockServiceContext wake_lock_service_context_;
-};
-
-TEST_F(WakeLockServiceContextTest, NoLockInitially) {
-  EXPECT_FALSE(HasWakeLock());
-}
-
-TEST_F(WakeLockServiceContextTest, LockUnlock) {
-  ASSERT_TRUE(GetWakeLockServiceContext());
-
-  // Request wake lock.
-  RequestWakeLock();
-
-  // Should set the blocker.
-  EXPECT_TRUE(HasWakeLock());
-
-  // Remove wake lock request.
-  CancelWakeLock();
-
-  // Should remove the blocker.
-  EXPECT_FALSE(HasWakeLock());
-}
-
-}  // namespace device
diff --git a/device/wake_lock/wake_lock_service_impl.cc b/device/wake_lock/wake_lock_service_impl.cc
index 34bcca25..ae998aa6 100644
--- a/device/wake_lock/wake_lock_service_impl.cc
+++ b/device/wake_lock/wake_lock_service_impl.cc
@@ -10,8 +10,7 @@
 
 namespace device {
 
-WakeLockServiceImpl::WakeLockServiceImpl(
-    base::WeakPtr<WakeLockServiceContext> context)
+WakeLockServiceImpl::WakeLockServiceImpl(WakeLockServiceContext* context)
     : context_(context), wake_lock_request_outstanding_(false) {}
 
 WakeLockServiceImpl::~WakeLockServiceImpl() {
@@ -19,7 +18,7 @@
 }
 
 void WakeLockServiceImpl::RequestWakeLock() {
-  if (!context_ || wake_lock_request_outstanding_)
+  if (wake_lock_request_outstanding_)
     return;
 
   wake_lock_request_outstanding_ = true;
@@ -27,7 +26,7 @@
 }
 
 void WakeLockServiceImpl::CancelWakeLock() {
-  if (!context_ || !wake_lock_request_outstanding_)
+  if (!wake_lock_request_outstanding_)
     return;
 
   wake_lock_request_outstanding_ = false;
diff --git a/device/wake_lock/wake_lock_service_impl.h b/device/wake_lock/wake_lock_service_impl.h
index 87a9b00..c66ec8d1a 100644
--- a/device/wake_lock/wake_lock_service_impl.h
+++ b/device/wake_lock/wake_lock_service_impl.h
@@ -6,7 +6,6 @@
 #define DEVICE_WAKE_LOCK_WAKE_LOCK_SERVICE_IMPL_H_
 
 #include "base/macros.h"
-#include "base/memory/weak_ptr.h"
 #include "device/wake_lock/public/interfaces/wake_lock_service.mojom.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
 
@@ -16,7 +15,7 @@
 
 class WakeLockServiceImpl : public mojom::WakeLockService {
  public:
-  explicit WakeLockServiceImpl(base::WeakPtr<WakeLockServiceContext> context);
+  explicit WakeLockServiceImpl(WakeLockServiceContext* context);
   ~WakeLockServiceImpl() override;
 
   // WakeLockSevice implementation.
@@ -24,7 +23,8 @@
   void CancelWakeLock() override;
 
  private:
-  base::WeakPtr<WakeLockServiceContext> context_;
+  // Will outlive this instance.
+  WakeLockServiceContext* context_;
   bool wake_lock_request_outstanding_;
 
   DISALLOW_COPY_AND_ASSIGN(WakeLockServiceImpl);
diff --git a/media/BUILD.gn b/media/BUILD.gn
index 3f96b8b..71cfeb4 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -250,6 +250,8 @@
     "video/gpu_memory_buffer_video_frame_pool.h",
     "video/h264_poc.cc",
     "video/h264_poc.h",
+    "video/half_float_maker.cc",
+    "video/half_float_maker.h",
     "video/jpeg_decode_accelerator.cc",
     "video/jpeg_decode_accelerator.h",
     "video/picture.cc",
@@ -587,6 +589,7 @@
     "renderers/video_renderer_impl_unittest.cc",
     "video/gpu_memory_buffer_video_frame_pool_unittest.cc",
     "video/h264_poc_unittest.cc",
+    "video/half_float_maker_unittest.cc",
   ]
 
   data = [
diff --git a/media/test/data/test-25fps.vp8.md5 b/media/test/data/test-25fps.vp8.md5
index 0739b86..1a138846 100644
--- a/media/test/data/test-25fps.vp8.md5
+++ b/media/test/data/test-25fps.vp8.md5
@@ -8,6 +8,8 @@
 bea8039e6921d930bb1c86185f62b1b0
 # Intel - VA_FILTER_SCALING_DEFAULT
 32a3c4257dac03df92a5c7593ee7e31f
+# Intel - go2001
+5e06153339e8f83f4d8f76331f54423d
 
 # TODO(llandwerlin): Remove the following hash when the libva-intel-driver
 # is updated.
diff --git a/media/video/half_float_maker.cc b/media/video/half_float_maker.cc
new file mode 100644
index 0000000..49c56883
--- /dev/null
+++ b/media/video/half_float_maker.cc
@@ -0,0 +1,91 @@
+// Copyright (c) 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 "media/video/half_float_maker.h"
+#include "third_party/libyuv/include/libyuv.h"
+
+namespace media {
+
+// By OR-ing with 0x3800, 10-bit numbers become half-floats in the
+// range [0.5..1) and 9-bit numbers get the range [0.5..0.75).
+//
+// Half-floats are evaluated as:
+// float value = pow(2.0, exponent - 25) * (0x400 + fraction);
+//
+// In our case the exponent is 14 (since we or with 0x3800) and
+// pow(2.0, 14-25) * 0x400 evaluates to 0.5 (our offset) and
+// pow(2.0, 14-25) * fraction is [0..0.49951171875] for 10-bit and
+// [0..0.24951171875] for 9-bit.
+//
+// https://en.wikipedia.org/wiki/Half-precision_floating-point_format
+class HalfFloatMaker_xor : public HalfFloatMaker {
+ public:
+  explicit HalfFloatMaker_xor(int bits_per_channel)
+      : bits_per_channel_(bits_per_channel) {}
+  float Offset() const override { return 0.5; }
+  float Multiplier() const override {
+    int max_input_value = (1 << bits_per_channel_) - 1;
+    // 2 << 11 = 2048 would be 1.0 with our exponent.
+    return 2048.0 / max_input_value;
+  }
+  void MakeHalfFloats(const uint16_t* src, size_t num, uint16_t* dst) override {
+    // Micro-benchmarking indicates that the compiler does
+    // a good enough job of optimizing this loop that trying
+    // to manually operate on one uint64 at a time is not
+    // actually helpful.
+    // Note to future optimizers: Benchmark your optimizations!
+    for (size_t i = 0; i < num; i++)
+      dst[i] = src[i] | 0x3800;
+  }
+
+ private:
+  int bits_per_channel_;
+};
+
+// Convert plane of 16 bit shorts to half floats using libyuv.
+class HalfFloatMaker_libyuv : public HalfFloatMaker {
+ public:
+  explicit HalfFloatMaker_libyuv(int bits_per_channel) {
+    int max_value = (1 << bits_per_channel) - 1;
+    // For less than 15 bits, we can give libyuv a multiplier of
+    // 1.0, which is faster on some platforms. If bits is 16 or larger,
+    // a multiplier of 1.0 would cause overflows. However, a multiplier
+    // of 1/max_value would cause subnormal floats, which perform
+    // very poorly on some platforms.
+    if (bits_per_channel <= 15) {
+      libyuv_multiplier_ = 1.0f;
+    } else {
+      // This multiplier makes sure that we avoid subnormal values.
+      libyuv_multiplier_ = 1.0f / 4096.0f;
+    }
+    resource_multiplier_ = 1.0f / libyuv_multiplier_ / max_value;
+  }
+  float Offset() const override { return 0.0f; }
+  float Multiplier() const override { return resource_multiplier_; }
+  void MakeHalfFloats(const uint16_t* src, size_t num, uint16_t* dst) override {
+    // Source and dest stride can be zero since we're only copying
+    // one row at a time.
+    int stride = 0;
+    int rows = 1;
+    libyuv::HalfFloatPlane(src, stride, dst, stride, libyuv_multiplier_, num,
+                           rows);
+  }
+
+ private:
+  float libyuv_multiplier_;
+  float resource_multiplier_;
+};
+
+std::unique_ptr<HalfFloatMaker> HalfFloatMaker::NewHalfFloatMaker(
+    int bits_per_channel) {
+  if (bits_per_channel < 11) {
+    return std::unique_ptr<HalfFloatMaker>(
+        new HalfFloatMaker_xor(bits_per_channel));
+  } else {
+    return std::unique_ptr<HalfFloatMaker>(
+        new HalfFloatMaker_libyuv(bits_per_channel));
+  }
+}
+
+}  // namespace media
diff --git a/media/video/half_float_maker.h b/media/video/half_float_maker.h
new file mode 100644
index 0000000..08ec6817
--- /dev/null
+++ b/media/video/half_float_maker.h
@@ -0,0 +1,38 @@
+// 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 MEDIA_VIDEO_HALF_FLOAT_MAKER_H_
+#define MEDIA_VIDEO_HALF_FLOAT_MAKER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <memory>
+
+#include "media/base/media_export.h"
+
+namespace media {
+
+class MEDIA_EXPORT HalfFloatMaker {
+ public:
+  // Convert an array of short integers into an array of half-floats.
+  // |src| is an array of integers in range 0 .. 2^{bits_per_channel} - 1
+  // |num| is number of entries in input and output array.
+  // The numbers stored in |dst| will be half floats in range 0.0..1.0
+  virtual void MakeHalfFloats(const uint16_t* src,
+                              size_t num,
+                              uint16_t* dst) = 0;
+  // The half-floats made needs by this class will be in the range
+  // [Offset() .. Offset() + 1.0/Multiplier]. So if you want results
+  // in the 0-1 range, you need to do:
+  //   (half_float - Offset()) * Multiplier()
+  // to each returned value.
+  virtual float Offset() const = 0;
+  virtual float Multiplier() const = 0;
+  // Below is a factory method which can be used to create halffloatmaker.
+  static std::unique_ptr<HalfFloatMaker> NewHalfFloatMaker(
+      int bits_per_channel);
+};
+
+}  // namespace media
+#endif  // MEDIA_VIDEO_HALF_FLOAT_MAKER_H_
diff --git a/media/video/half_float_maker_unittest.cc b/media/video/half_float_maker_unittest.cc
new file mode 100644
index 0000000..2b089ee
--- /dev/null
+++ b/media/video/half_float_maker_unittest.cc
@@ -0,0 +1,67 @@
+// 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 <math.h>
+
+#include "media/video/half_float_maker.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media {
+
+class HalfFloatMakerTest : public testing::Test {};
+
+// Convert an IEEE 754 half-float to a double value
+// that we can do math on.
+double FromHalfFloat(uint16_t half_float) {
+  if (!half_float)
+    return 0.0;
+  int sign = (half_float & 0x8000) ? -1 : 1;
+  int exponent = (half_float >> 10) & 0x1F;
+  int fraction = half_float & 0x3FF;
+  if (exponent == 0) {
+    return pow(2.0, -24.0) * fraction;
+  } else if (exponent == 0x1F) {
+    return sign * 1000000000000.0;
+  } else {
+    return pow(2.0, exponent - 25) * (0x400 + fraction);
+  }
+}
+
+TEST_F(HalfFloatMakerTest, MakeHalfFloatTest) {
+  unsigned short integers[1 << 16];
+  unsigned short half_floats[1 << 16];
+  for (int bits = 9; bits <= 16; bits++) {
+    std::unique_ptr<media::HalfFloatMaker> half_float_maker;
+    half_float_maker = media::HalfFloatMaker::NewHalfFloatMaker(bits);
+    int num_values = 1 << bits;
+    for (int i = 0; i < num_values; i++)
+      integers[i] = i;
+
+    half_float_maker->MakeHalfFloats(integers, num_values, half_floats);
+    // Multiplier to converting integers to 0.0..1.0 range.
+    double multiplier = 1.0 / (num_values - 1);
+
+    for (int i = 0; i < num_values; i++) {
+      // This value is in range 0..1
+      float value = integers[i] * multiplier;
+      // Reverse the effect of offset and multiplier to get the expected
+      // output value from the half-float converter.
+      float expected_value =
+          value / half_float_maker->Multiplier() + half_float_maker->Offset();
+      EXPECT_EQ(integers[i], i);
+
+      // We expect the result to be within +/- one least-significant bit.
+      // Within the range we care about, half-floats values and
+      // their representation both sort in the same order, so we
+      // can just add one to get the next bigger half-float.
+      float expected_precision =
+          FromHalfFloat(half_floats[i] + 1) - FromHalfFloat(half_floats[i]);
+      EXPECT_NEAR(FromHalfFloat(half_floats[i]), expected_value,
+                  expected_precision)
+          << "i = " << i << " bits = " << bits;
+    }
+  }
+}
+
+}  // namespace media
diff --git a/mojo/public/js/new_bindings/base.js b/mojo/public/js/new_bindings/base.js
index 4c86fb1..c147ec6 100644
--- a/mojo/public/js/new_bindings/base.js
+++ b/mojo/public/js/new_bindings/base.js
@@ -11,53 +11,10 @@
 var mojoBindings = {};
 mojoBindings.internal = {};
 mojoBindings.internal.global = this;
-mojoBindings.config = {
-  // Whether to automatically load mojom dependencies.
-  // For example, if foo.mojom imports bar.mojom, |autoLoadMojomDeps| set to
-  // true means that loading foo.mojom.js will insert a <script> tag to load
-  // bar.mojom.js, if it hasn't been loaded.
-  //
-  // The URL of bar.mojom.js is determined by the relative path of bar.mojom
-  // (relative to the position of foo.mojom at build time) and the URL of
-  // foo.mojom.js. For exmple, if at build time the two mojom files are
-  // located at:
-  //   a/b/c/foo.mojom
-  //   a/b/d/bar.mojom
-  // and the URL of foo.mojom.js is:
-  //   http://example.org/scripts/b/c/foo.mojom.js
-  // then the URL of bar.mojom.js will be:
-  //   http://example.org/scripts/b/d/bar.mojom.js
-  //
-  // If you would like bar.mojom.js to live at a different location, you need
-  // to turn off |autoLoadMojomDeps| before loading foo.mojom.js, and manually
-  // load bar.mojom.js yourself. Similarly, you need to turn off the option if
-  // you merge bar.mojom.js and foo.mojom.js into a single file.
-  //
-  // Performance tip: Avoid loading the same mojom.js file multiple times.
-  // Assume that |autoLoadMojomDeps| is set to true:
-  // <!-- No duplicate loading; recommended. -->
-  // <script src="http://example.org/scripts/b/c/foo.mojom.js"></script>
-  //
-  // <!-- No duplicate loading, although unnecessary. -->
-  // <script src="http://example.org/scripts/b/d/bar.mojom.js"></script>
-  // <script src="http://example.org/scripts/b/c/foo.mojom.js"></script>
-  //
-  // <!-- Load bar.mojom.js twice; should be avoided. -->
-  // <script src="http://example.org/scripts/b/c/foo.mojom.js"></script>
-  // <script src="http://example.org/scripts/b/d/bar.mojom.js"></script>
-  autoLoadMojomDeps: true
-};
 
 (function() {
   var internal = mojoBindings.internal;
 
-  var LoadState = {
-    PENDING_LOAD: 1,
-    LOADED: 2
-  };
-
-  var mojomRegistry = new Map();
-
   function exposeNamespace(namespace) {
     var current = internal.global;
     var parts = namespace.split('.');
@@ -72,40 +29,5 @@
     return current;
   }
 
-  function isMojomPendingLoad(id) {
-    return mojomRegistry.get(id) === LoadState.PENDING_LOAD;
-  }
-
-  function isMojomLoaded(id) {
-    return mojomRegistry.get(id) === LoadState.LOADED;
-  }
-
-  function markMojomPendingLoad(id) {
-    if (isMojomLoaded(id)) {
-      throw new Error('The following mojom file has been loaded: ' + id);
-    }
-
-    mojomRegistry.set(id, LoadState.PENDING_LOAD);
-  }
-
-  function markMojomLoaded(id) {
-    mojomRegistry.set(id, LoadState.LOADED);
-  }
-
-  function loadMojomIfNecessary(id, url) {
-    if (mojomRegistry.has(id)) {
-      return;
-    }
-
-    markMojomPendingLoad(id);
-    internal.global.document.write('<script type="text/javascript" src="' +
-                                   url + '"></script>');
-  }
-
   internal.exposeNamespace = exposeNamespace;
-  internal.isMojomPendingLoad = isMojomPendingLoad;
-  internal.isMojomLoaded = isMojomLoaded;
-  internal.markMojomPendingLoad = markMojomPendingLoad;
-  internal.markMojomLoaded = markMojomLoaded;
-  internal.loadMojomIfNecessary = loadMojomIfNecessary;
 })();
diff --git a/mojo/public/tools/bindings/generators/js_templates/module.amd.tmpl b/mojo/public/tools/bindings/generators/js_templates/module.amd.tmpl
index f04ee99..cf349765 100644
--- a/mojo/public/tools/bindings/generators/js_templates/module.amd.tmpl
+++ b/mojo/public/tools/bindings/generators/js_templates/module.amd.tmpl
@@ -4,32 +4,16 @@
 
 {%- if use_new_js_bindings %}
 
-'use strict';
+"use strict";
 
 (function() {
-  var mojomId = '{{module.path}}';
-  if (mojoBindings.internal.isMojomLoaded(mojomId)) {
-    console.warn('The following mojom is loaded multiple times: ' + mojomId);
-    return;
-  }
-  mojoBindings.internal.markMojomLoaded(mojomId);
-
   // TODO(yzshen): Define these aliases to minimize the differences between the
   // old/new modes. Remove them when the old mode goes away.
   var bindings = mojoBindings;
   var codec = mojoBindings.internal;
   var validator = mojoBindings.internal;
-
 {%-   for import in imports %}
-  var {{import.unique_name}} =
-      mojoBindings.internal.exposeNamespace('{{import.module.namespace}}');
-  if (mojoBindings.config.autoLoadMojomDeps) {
-    mojoBindings.internal.loadMojomIfNecessary(
-        '{{import.module.path}}',
-        new URL(
-            '{{import.module|get_relative_path(module)}}.js',
-            document.currentScript.src).href);
-  }
+  var {{import.unique_name}} = {{import.module.namespace}};
 {%-   endfor %}
 
 {% include "module_definition.tmpl" %}
@@ -61,4 +45,4 @@
   return exports;
 });
 
-{%- endif %}
+{%- endif %}
\ No newline at end of file
diff --git a/mojo/public/tools/bindings/generators/mojom_js_generator.py b/mojo/public/tools/bindings/generators/mojom_js_generator.py
index ab9635e..6184f6d 100644
--- a/mojo/public/tools/bindings/generators/mojom_js_generator.py
+++ b/mojo/public/tools/bindings/generators/mojom_js_generator.py
@@ -7,7 +7,6 @@
 import mojom.generate.generator as generator
 import mojom.generate.module as mojom
 import mojom.generate.pack as pack
-import os
 from mojom.generate.template_expander import UseJinja
 
 _kind_to_javascript_default_value = {
@@ -325,9 +324,6 @@
 def IsEnumField(field):
   return mojom.IsEnumKind(field.kind)
 
-def GetRelativePath(module, base_module):
-  return os.path.relpath(module.path, os.path.dirname(base_module.path))
-
 
 class Generator(generator.Generator):
 
@@ -352,7 +348,6 @@
     "is_union_field": IsUnionField,
     "js_type": JavaScriptType,
     "payload_size": JavaScriptPayloadSize,
-    "get_relative_path": GetRelativePath,
     "stylize_method": generator.StudlyCapsToCamel,
     "union_decode_snippet": JavaScriptUnionDecodeSnippet,
     "union_encode_snippet": JavaScriptUnionEncodeSnippet,
diff --git a/services/device/BUILD.gn b/services/device/BUILD.gn
index b6c558e..de1ecce 100644
--- a/services/device/BUILD.gn
+++ b/services/device/BUILD.gn
@@ -21,11 +21,13 @@
     "//device/battery:mojo_bindings",
     "//device/sensors",
     "//device/vibration:mojo_bindings",
+    "//device/wake_lock",
     "//services/device/fingerprint",
     "//services/device/power_monitor",
     "//services/device/screen_orientation",
     "//services/device/time_zone_monitor",
     "//services/service_manager/public/cpp",
+    "//ui/gfx",
   ]
 
   if (is_android) {
diff --git a/services/device/DEPS b/services/device/DEPS
index 4d38b23c..6383a3f 100644
--- a/services/device/DEPS
+++ b/services/device/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
   "+device",
   "+jni",
+  "+ui/gfx/native_widget_types.h",
 ]
diff --git a/services/device/device_service.cc b/services/device/device_service.cc
index f804ba03..a0aae54d 100644
--- a/services/device/device_service.cc
+++ b/services/device/device_service.cc
@@ -4,6 +4,8 @@
 
 #include "services/device/device_service.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/weak_ptr.h"
@@ -13,6 +15,7 @@
 #include "device/battery/battery_monitor_impl.h"
 #include "device/battery/battery_status_service.h"
 #include "device/sensors/device_sensor_host.h"
+#include "device/wake_lock/wake_lock_context_provider.h"
 #include "mojo/public/cpp/system/message_pipe.h"
 #include "services/device/fingerprint/fingerprint.h"
 #include "services/device/power_monitor/power_monitor_message_broadcaster.h"
@@ -20,6 +23,7 @@
 #include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/interface_registry.h"
 #include "services/service_manager/public/cpp/service_info.h"
+#include "ui/gfx/native_widget_types.h"
 
 #if defined(OS_ANDROID)
 #include "base/android/context_utils.h"
@@ -33,30 +37,45 @@
 
 namespace device {
 
+#if defined(OS_ANDROID)
 std::unique_ptr<service_manager::Service> CreateDeviceService(
     scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,
-    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) {
-#if defined(OS_ANDROID)
+    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
+    const WakeLockContextCallback& wake_lock_context_callback) {
   if (!EnsureJniRegistered()) {
     DLOG(ERROR) << "Failed to register JNI for Device Service";
     return nullptr;
   }
-#endif
 
   return base::MakeUnique<DeviceService>(std::move(file_task_runner),
+                                         std::move(io_task_runner),
+                                         wake_lock_context_callback);
+}
+#else
+std::unique_ptr<service_manager::Service> CreateDeviceService(
+    scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,
+    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) {
+  return base::MakeUnique<DeviceService>(std::move(file_task_runner),
                                          std::move(io_task_runner));
 }
+#endif
 
+#if defined(OS_ANDROID)
+DeviceService::DeviceService(
+    scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,
+    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
+    const WakeLockContextCallback& wake_lock_context_callback)
+    : java_interface_provider_initialized_(false),
+      file_task_runner_(std::move(file_task_runner)),
+      io_task_runner_(std::move(io_task_runner)),
+      wake_lock_context_callback_(wake_lock_context_callback) {}
+#else
 DeviceService::DeviceService(
     scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,
     scoped_refptr<base::SingleThreadTaskRunner> io_task_runner)
-    :
-#if defined(OS_ANDROID)
-      java_interface_provider_initialized_(false),
+    : file_task_runner_(std::move(file_task_runner)),
+      io_task_runner_(std::move(io_task_runner)) {}
 #endif
-      file_task_runner_(std::move(file_task_runner)),
-      io_task_runner_(std::move(io_task_runner)) {
-}
 
 DeviceService::~DeviceService() {
 #if !defined(OS_ANDROID)
@@ -76,6 +95,7 @@
   registry->AddInterface<mojom::PowerMonitor>(this);
   registry->AddInterface<mojom::ScreenOrientationListener>(this);
   registry->AddInterface<mojom::TimeZoneMonitor>(this);
+  registry->AddInterface<mojom::WakeLockContextProvider>(this);
 
 #if defined(OS_ANDROID)
   registry->AddInterface(
@@ -201,6 +221,12 @@
   time_zone_monitor_->Bind(std::move(request));
 }
 
+void DeviceService::Create(const service_manager::Identity& remote_identity,
+                           mojom::WakeLockContextProviderRequest request) {
+  WakeLockContextProvider::Create(std::move(request), file_task_runner_,
+                                  wake_lock_context_callback_);
+}
+
 #if defined(OS_ANDROID)
 service_manager::InterfaceProvider* DeviceService::GetJavaInterfaceProvider() {
   if (!java_interface_provider_initialized_) {
diff --git a/services/device/device_service.h b/services/device/device_service.h
index 756c57f..c4ed1276 100644
--- a/services/device/device_service.h
+++ b/services/device/device_service.h
@@ -12,6 +12,8 @@
 #include "device/sensors/public/interfaces/motion.mojom.h"
 #include "device/sensors/public/interfaces/orientation.mojom.h"
 #include "device/vibration/vibration_manager.mojom.h"
+#include "device/wake_lock/public/interfaces/wake_lock_context_provider.mojom.h"
+#include "device/wake_lock/wake_lock_service_context.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "services/device/public/interfaces/fingerprint.mojom.h"
 #include "services/device/public/interfaces/power_monitor.mojom.h"
@@ -29,9 +31,16 @@
 class PowerMonitorMessageBroadcaster;
 class TimeZoneMonitor;
 
+#if defined(OS_ANDROID)
+std::unique_ptr<service_manager::Service> CreateDeviceService(
+    scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,
+    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
+    const WakeLockContextCallback& wake_lock_context_callback);
+#else
 std::unique_ptr<service_manager::Service> CreateDeviceService(
     scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,
     scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
+#endif
 
 class DeviceService
     : public service_manager::Service,
@@ -50,10 +59,17 @@
       public service_manager::InterfaceFactory<mojom::PowerMonitor>,
       public service_manager::InterfaceFactory<
           mojom::ScreenOrientationListener>,
-      public service_manager::InterfaceFactory<mojom::TimeZoneMonitor> {
+      public service_manager::InterfaceFactory<mojom::TimeZoneMonitor>,
+      public service_manager::InterfaceFactory<mojom::WakeLockContextProvider> {
  public:
+#if defined(OS_ANDROID)
+  DeviceService(scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,
+                scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
+                const WakeLockContextCallback& wake_lock_context_callback);
+#else
   DeviceService(scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,
                 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
+#endif
   ~DeviceService() override;
 
  private:
@@ -103,6 +119,10 @@
   void Create(const service_manager::Identity& remote_identity,
               mojom::TimeZoneMonitorRequest request) override;
 
+  // InterfaceFactory<mojom::WakeLockContextProvider>:
+  void Create(const service_manager::Identity& remote_identity,
+              mojom::WakeLockContextProviderRequest request) override;
+
   std::unique_ptr<PowerMonitorMessageBroadcaster>
       power_monitor_message_broadcaster_;
   std::unique_ptr<TimeZoneMonitor> time_zone_monitor_;
@@ -120,6 +140,8 @@
   scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
   scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
 
+  WakeLockContextCallback wake_lock_context_callback_;
+
   DISALLOW_COPY_AND_ASSIGN(DeviceService);
 };
 
diff --git a/services/device/manifest.json b/services/device/manifest.json
index 13e86bc8..f4c6d963 100644
--- a/services/device/manifest.json
+++ b/services/device/manifest.json
@@ -15,7 +15,8 @@
           "device::mojom::OrientationSensor"
         ],
         "device:time_zone_monitor": [ "device::mojom::TimeZoneMonitor" ],
-        "device:vibration": [ "device::mojom::VibrationManager" ]
+        "device:vibration": [ "device::mojom::VibrationManager" ],
+        "device:wake_lock": [ "device::mojom::WakeLockContextProvider" ]
       },
       "requires": {
         "service_manager": [ "service_manager:all_users" ]
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index 55813f1f..6ddffa818 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -1095,7 +1095,7 @@
     "type": "windowed_test_launcher",
   },
   "wtf_unittests": {
-    "label": "//third_party/WebKit/Source/wtf:wtf_unittests",
+    "label": "//third_party/WebKit/Source/platform/wtf:wtf_unittests",
     "type": "console_test_launcher",
   },
 }
diff --git a/testing/libfuzzer/fuzzers/BUILD.gn b/testing/libfuzzer/fuzzers/BUILD.gn
index f550f52..217e08b 100644
--- a/testing/libfuzzer/fuzzers/BUILD.gn
+++ b/testing/libfuzzer/fuzzers/BUILD.gn
@@ -8,7 +8,7 @@
 import("//media/media_options.gni")
 import("//testing/libfuzzer/fuzzer_test.gni")
 
-# root BUILD depenends on this target. Needed for package discovery
+# root BUILD depends on this target. Needed for package discovery
 group("fuzzers") {
 }
 
@@ -113,6 +113,17 @@
   ]
 }
 
+fuzzer_test("template_url_parser_fuzzer") {
+  sources = [
+    "template_url_parser_fuzzer.cc",
+  ]
+  deps = [
+    "//components/search_engines:search_engines",
+  ]
+  dict = "dicts/xml.dict"
+  libfuzzer_options = [ "max_len=4096" ]
+}
+
 fuzzer_test("url_parse_fuzzer") {
   sources = [
     "url_parse_fuzzer.cc",
diff --git a/testing/libfuzzer/fuzzers/template_url_parser_fuzzer.cc b/testing/libfuzzer/fuzzers/template_url_parser_fuzzer.cc
new file mode 100644
index 0000000..4d1b762
--- /dev/null
+++ b/testing/libfuzzer/fuzzers/template_url_parser_fuzzer.cc
@@ -0,0 +1,44 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <random>
+#include <string>
+
+#include "components/search_engines/search_terms_data.h"
+#include "components/search_engines/template_url.h"
+#include "components/search_engines/template_url_parser.h"
+
+class PseudoRandomFilter : public TemplateURLParser::ParameterFilter {
+ public:
+  PseudoRandomFilter(uint32_t seed) : generator_(seed), pool_(0, 1) {}
+  ~PseudoRandomFilter() override = default;
+
+  bool KeepParameter(const std::string&, const std::string&) override {
+    return pool_(generator_);
+  }
+
+ private:
+  std::mt19937 generator_;
+  std::uniform_int_distribution<uint8_t> pool_;
+};
+
+struct FuzzerFixedParams {
+  uint32_t seed_;
+};
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  if (size < sizeof(FuzzerFixedParams)) {
+    return 0;
+  }
+  const FuzzerFixedParams* params =
+      reinterpret_cast<const FuzzerFixedParams*>(data);
+  size -= sizeof(FuzzerFixedParams);
+  const char* char_data = reinterpret_cast<const char*>(params + 1);
+  PseudoRandomFilter filter(params->seed_);
+  TemplateURLParser::Parse(SearchTermsData(), char_data, size, &filter);
+  return 0;
+}
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/cross-origin-preflight-timeout.html b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/cross-origin-preflight-timeout.html
new file mode 100644
index 0000000..923ea56
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/cross-origin-preflight-timeout.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+async_test(t => {
+    const url = 'http://localhost:8000/xmlhttprequest/resources/access-control-allow-with-delay.php';
+    const xhr = new XMLHttpRequest();
+    xhr.open('GET', url);
+    xhr.setRequestHeader('foo', 'bar');
+    xhr.timeout = 1500;
+    xhr.ontimeout = t.step_func_done(() => {
+      assert_equals(xhr.readyState, 4);
+      });
+    xhr.onload = t.unreached_func('load event fired');
+    xhr.send();
+  }, 'CORS preflight and the actual request should use the same timer');
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/resources/access-control-allow-with-delay.php b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/resources/access-control-allow-with-delay.php
new file mode 100644
index 0000000..a8438f7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/resources/access-control-allow-with-delay.php
@@ -0,0 +1,8 @@
+<?php
+    sleep(1);
+    header("Content-Type: text/plain");
+    header("Cache-Control: no-store");
+    header("Access-Control-Allow-Origin: *");
+    header("Access-Control-Allow-Headers: foo");
+?>
+
diff --git a/third_party/WebKit/LayoutTests/mojo/module-loading-manual-deps-loading.html b/third_party/WebKit/LayoutTests/mojo/module-loading-manual-deps-loading.html
deleted file mode 100644
index 74dad2d2..0000000
--- a/third_party/WebKit/LayoutTests/mojo/module-loading-manual-deps-loading.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!DOCTYPE html>
-<title>Mojo JavaScript bindings module loading tests (manual mojom deps loading)</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="file:///gen/mojo/public/js/mojo_bindings.js"></script>
-<script>
-  mojoBindings.config.autoLoadMojomDeps = false;
-</script>
-<script src="file:///gen/mojo/public/interfaces/bindings/tests/echo.mojom.js"></script>
-<script src="file:///gen/mojo/public/interfaces/bindings/tests/echo_import.mojom.js"></script>
-<script>
-
-promise_test(async () => {
-  function EchoImpl() {}
-  EchoImpl.prototype.echoPoint = function(point) {
-    return Promise.resolve({result: point});
-  };
-
-  var echoServicePtr = new test.echo.mojom.EchoPtr();
-  var echoServiceBinding = new mojoBindings.Binding(
-      test.echo.mojom.Echo,
-      new EchoImpl(),
-      mojoBindings.makeRequest(echoServicePtr));
-  var result = (await echoServicePtr.echoPoint({x: 1, y: 2})).result;
-  assert_equals(1, result.x);
-  assert_equals(2, result.y);
-}, 'Basics');
-
-</script>
diff --git a/third_party/WebKit/LayoutTests/mojo/module-loading.html b/third_party/WebKit/LayoutTests/mojo/module-loading.html
index 52eebeb5..6ebd60e 100644
--- a/third_party/WebKit/LayoutTests/mojo/module-loading.html
+++ b/third_party/WebKit/LayoutTests/mojo/module-loading.html
@@ -3,6 +3,7 @@
 <script src="../resources/testharness.js"></script>
 <script src="../resources/testharnessreport.js"></script>
 <script src="file:///gen/mojo/public/js/mojo_bindings.js"></script>
+<script src="file:///gen/mojo/public/interfaces/bindings/tests/echo_import.mojom.js"></script>
 <script src="file:///gen/mojo/public/interfaces/bindings/tests/echo.mojom.js"></script>
 <script>
 
diff --git a/third_party/WebKit/Source/core/dom/Node.h b/third_party/WebKit/Source/core/dom/Node.h
index e80329ba..939c833 100644
--- a/third_party/WebKit/Source/core/dom/Node.h
+++ b/third_party/WebKit/Source/core/dom/Node.h
@@ -965,14 +965,6 @@
          childNeedsStyleRecalc();
 }
 
-inline bool isTreeScopeRoot(const Node* node) {
-  return !node || node->isDocumentNode() || node->isShadowRoot();
-}
-
-inline bool isTreeScopeRoot(const Node& node) {
-  return node.isDocumentNode() || node.isShadowRoot();
-}
-
 // See the comment at the declaration of ScriptWrappable::fromNode in
 // bindings/core/v8/ScriptWrappable.h about why this method is defined here.
 inline ScriptWrappable* ScriptWrappable::fromNode(Node* node) {
diff --git a/third_party/WebKit/Source/core/dom/SelectorQuery.cpp b/third_party/WebKit/Source/core/dom/SelectorQuery.cpp
index c3b21eaf..a8c7576e 100644
--- a/third_party/WebKit/Source/core/dom/SelectorQuery.cpp
+++ b/third_party/WebKit/Source/core/dom/SelectorQuery.cpp
@@ -250,8 +250,7 @@
       Element* element =
           rootNode.containingTreeScope().getElementById(selector->value());
       ContainerNode* adjustedNode = &rootNode;
-      if (element &&
-          (isTreeScopeRoot(rootNode) || element->isDescendantOf(&rootNode)))
+      if (element && element->isDescendantOf(&rootNode))
         adjustedNode = element;
       else if (!element || isRightmostSelector)
         adjustedNode = nullptr;
@@ -509,7 +508,7 @@
       const HeapVector<Member<Element>>& elements =
           rootNode.treeScope().getAllElementsById(idToMatch);
       for (const auto& element : elements) {
-        if (!(isTreeScopeRoot(rootNode) || element->isDescendantOf(&rootNode)))
+        if (!element->isDescendantOf(&rootNode))
           continue;
         if (selectorMatches(selector, *element, rootNode)) {
           SelectorQueryTrait::appendElement(output, *element);
@@ -520,8 +519,9 @@
       return;
     }
     Element* element = rootNode.treeScope().getElementById(idToMatch);
-    if (!element ||
-        !(isTreeScopeRoot(rootNode) || element->isDescendantOf(&rootNode)))
+    if (!element)
+      return;
+    if (!element->isDescendantOf(&rootNode))
       return;
     if (selectorMatches(selector, *element, rootNode))
       SelectorQueryTrait::appendElement(output, *element);
diff --git a/third_party/WebKit/Source/core/editing/DOMSelection.cpp b/third_party/WebKit/Source/core/editing/DOMSelection.cpp
index 1c73eeed..fd59dce 100644
--- a/third_party/WebKit/Source/core/editing/DOMSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/DOMSelection.cpp
@@ -540,15 +540,16 @@
 }
 
 Range* DOMSelection::createRangeFromSelectionEditor() const {
-  Position anchor = blink::anchorPosition(visibleSelection());
+  const VisibleSelection& selection = visibleSelection();
+  const Position& anchor = blink::anchorPosition(selection);
   if (isSelectionOfDocument() && !anchor.anchorNode()->isInShadowTree())
-    return frame()->selection().firstRange();
+    return createRange(firstEphemeralRangeOf(selection));
 
-  Node* node = shadowAdjustedNode(anchor);
+  Node* const node = shadowAdjustedNode(anchor);
   if (!node)  // crbug.com/595100
     return nullptr;
-  Position focus = focusPosition(visibleSelection());
-  if (!visibleSelection().isBaseFirst()) {
+  const Position& focus = focusPosition(selection);
+  if (!selection.isBaseFirst()) {
     return Range::create(*anchor.document(), shadowAdjustedNode(focus),
                          shadowAdjustedOffset(focus), node,
                          shadowAdjustedOffset(anchor));
diff --git a/third_party/WebKit/Source/core/editing/EditingUtilities.cpp b/third_party/WebKit/Source/core/editing/EditingUtilities.cpp
index 736d889..8c1b3c1 100644
--- a/third_party/WebKit/Source/core/editing/EditingUtilities.cpp
+++ b/third_party/WebKit/Source/core/editing/EditingUtilities.cpp
@@ -104,7 +104,7 @@
 
 }  // namespace
 
-static bool needsLayoutTreeUpdate(const Node& node) {
+bool needsLayoutTreeUpdate(const Node& node) {
   const Document& document = node.document();
   if (document.needsLayoutTreeUpdate())
     return true;
@@ -1970,36 +1970,6 @@
   return createVisiblePosition(range.startPosition());
 }
 
-// Determines whether a node is inside a range or visibly starts and ends at the
-// boundaries of the range. Call this function to determine whether a node is
-// visibly fit inside selectedRange
-bool isNodeVisiblyContainedWithin(Node& node, const Range& selectedRange) {
-  DCHECK(!needsLayoutTreeUpdate(node));
-  DocumentLifecycle::DisallowTransitionScope disallowTransition(
-      node.document().lifecycle());
-
-  if (selectedRange.isNodeFullyContained(node))
-    return true;
-
-  bool startIsVisuallySame =
-      visiblePositionBeforeNode(node).deepEquivalent() ==
-      createVisiblePosition(selectedRange.startPosition()).deepEquivalent();
-  if (startIsVisuallySame &&
-      comparePositions(Position::inParentAfterNode(node),
-                       selectedRange.endPosition()) < 0)
-    return true;
-
-  bool endIsVisuallySame =
-      visiblePositionAfterNode(node).deepEquivalent() ==
-      createVisiblePosition(selectedRange.endPosition()).deepEquivalent();
-  if (endIsVisuallySame &&
-      comparePositions(selectedRange.startPosition(),
-                       Position::inParentBeforeNode(node)) < 0)
-    return true;
-
-  return startIsVisuallySame && endIsVisuallySame;
-}
-
 bool isRenderedAsNonInlineTableImageOrHR(const Node* node) {
   if (!node)
     return false;
diff --git a/third_party/WebKit/Source/core/editing/EditingUtilities.h b/third_party/WebKit/Source/core/editing/EditingUtilities.h
index b4505d04..567aeaa 100644
--- a/third_party/WebKit/Source/core/editing/EditingUtilities.h
+++ b/third_party/WebKit/Source/core/editing/EditingUtilities.h
@@ -63,10 +63,10 @@
 class HTMLElement;
 class HTMLSpanElement;
 class Node;
-class Range;
 
 // This file contains a set of helper functions used by the editing commands
 
+bool needsLayoutTreeUpdate(const Node&);
 CORE_EXPORT bool needsLayoutTreeUpdate(const Position&);
 CORE_EXPORT bool needsLayoutTreeUpdate(const PositionInFlatTree&);
 
@@ -185,7 +185,6 @@
 bool isListItem(const Node*);
 bool isPresentationalHTMLElement(const Node*);
 bool isNodeRendered(const Node&);
-bool isNodeVisiblyContainedWithin(Node&, const Range&);
 bool isRenderedAsNonInlineTableImageOrHR(const Node*);
 // Returns true if specified nodes are elements, have identical tag names,
 // have identical attributes, and are editable.
diff --git a/third_party/WebKit/Source/core/editing/FrameSelection.cpp b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
index 6645c43..54c4879 100644
--- a/third_party/WebKit/Source/core/editing/FrameSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
@@ -665,10 +665,6 @@
   return true;
 }
 
-Range* FrameSelection::firstRange() const {
-  return m_selectionEditor->firstRange();
-}
-
 void FrameSelection::notifyAccessibilityForSelectionChange() {
   if (selectionInDOMTree().isNone())
     return;
diff --git a/third_party/WebKit/Source/core/editing/FrameSelection.h b/third_party/WebKit/Source/core/editing/FrameSelection.h
index 27227ac..aaa88fad 100644
--- a/third_party/WebKit/Source/core/editing/FrameSelection.h
+++ b/third_party/WebKit/Source/core/editing/FrameSelection.h
@@ -180,11 +180,6 @@
   const SelectionInDOMTree& selectionInDOMTree() const;
   bool isDirectional() const { return selectionInDOMTree().isDirectional(); }
 
-  // If this FrameSelection has a logical range which is still valid, this
-  // function return its clone. Otherwise, the return value from underlying
-  // VisibleSelection's firstRange() is returned.
-  Range* firstRange() const;
-
   void documentAttached(Document*);
 
   void didLayout();
diff --git a/third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp b/third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp
index d566ff0..e32a97a4 100644
--- a/third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp
+++ b/third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp
@@ -56,7 +56,7 @@
   return text;
 }
 
-TEST_F(FrameSelectionTest, FirstRange) {
+TEST_F(FrameSelectionTest, FirstEphemeralRangeOf) {
   setBodyContent("<div id=sample>0123456789</div>abc");
   Element* const sample = document().getElementById("sample");
   Node* const text = sample->firstChild();
@@ -66,10 +66,11 @@
   sample->setAttribute(HTMLNames::styleAttr, "display:none");
   // Move |VisibleSelection| before "abc".
   updateAllLifecyclePhases();
-  Range* const range = selection().firstRange();
-  EXPECT_EQ(Position(sample->nextSibling(), 0), range->startPosition())
+  const EphemeralRange& range =
+      firstEphemeralRangeOf(selection().computeVisibleSelectionInDOMTree());
+  EXPECT_EQ(Position(sample->nextSibling(), 0), range.startPosition())
       << "firstRagne() should return current selection value";
-  EXPECT_EQ(Position(sample->nextSibling(), 0), range->endPosition());
+  EXPECT_EQ(Position(sample->nextSibling(), 0), range.endPosition());
 }
 
 TEST_F(FrameSelectionTest, SetValidSelection) {
diff --git a/third_party/WebKit/Source/core/editing/GranularityStrategy.cpp b/third_party/WebKit/Source/core/editing/GranularityStrategy.cpp
index 0b09b8b9..11b0593 100644
--- a/third_party/WebKit/Source/core/editing/GranularityStrategy.cpp
+++ b/third_party/WebKit/Source/core/editing/GranularityStrategy.cpp
@@ -69,8 +69,8 @@
       visiblePositionForContentsPoint(extentPoint, frame);
   const VisibleSelection& selection =
       frame->selection().computeVisibleSelectionInDOMTreeDeprecated();
-  if (selection.visibleBase().deepEquivalent() ==
-      extentPosition.deepEquivalent())
+  if (extentPosition.isNull() || selection.visibleBase().deepEquivalent() ==
+                                     extentPosition.deepEquivalent())
     return selection.asSelection();
   return SelectionInDOMTree::Builder()
       .collapse(selection.base())
@@ -127,6 +127,8 @@
 
   VisiblePosition newOffsetExtentPosition =
       visiblePositionForContentsPoint(newOffsetExtentPoint, frame);
+  if (newOffsetExtentPosition.isNull())
+    return selection.asSelection();
   IntPoint newOffsetLocation = positionLocation(newOffsetExtentPosition);
 
   // Reset the offset in case of a vertical change in the location (could be
diff --git a/third_party/WebKit/Source/core/editing/GranularityStrategyTest.cpp b/third_party/WebKit/Source/core/editing/GranularityStrategyTest.cpp
index 3291f0c..7a14419 100644
--- a/third_party/WebKit/Source/core/editing/GranularityStrategyTest.cpp
+++ b/third_party/WebKit/Source/core/editing/GranularityStrategyTest.cpp
@@ -40,6 +40,7 @@
 
   DummyPageHolder& dummyPageHolder() const { return *m_dummyPageHolder; }
   Document& document() const;
+  LocalFrame& frame() const { return m_dummyPageHolder->frame(); }
   void setSelection(const VisibleSelection&);
   FrameSelection& selection() const;
   Text* appendTextNode(const String& data);
@@ -708,4 +709,69 @@
   EXPECT_EQ_SELECTED_TEXT("mnopqr iiin");
 }
 
+// For http://crbug.com/704529
+TEST_F(GranularityStrategyTest, UpdateExtentWithNullPositionForCharacter) {
+  dummyPageHolder().frame().settings()->setSelectionStrategy(
+      SelectionStrategy::Character);
+  document().body()->setInnerHTML("<div id=host></div><div id=sample>ab</div>");
+  // Simulate VIDEO element which has a RANGE as slider of video time.
+  Element* const host = document().getElementById("host");
+  ShadowRoot* const shadowRoot =
+      host->createShadowRootInternal(ShadowRootType::Open, ASSERT_NO_EXCEPTION);
+  shadowRoot->setInnerHTML("<input type=range>");
+  Element* const sample = document().getElementById("sample");
+  document().updateStyleAndLayout();
+  const SelectionInDOMTree& selectionInDOMTree =
+      SelectionInDOMTree::Builder()
+          .collapse(Position(sample->firstChild(), 2))
+          .setIsDirectional(true)
+          .setIsHandleVisible(true)
+          .build();
+  selection().setSelection(selectionInDOMTree);
+
+  // Since, it is not obvious that |visiblePositionForContentsPoint()| returns
+  // null position, we verify here.
+  ASSERT_EQ(Position(),
+            visiblePositionForContentsPoint(IntPoint(0, 0), &frame())
+                .deepEquivalent())
+      << "This test requires null position.";
+
+  // Point to RANGE inside shadow root to get null position from
+  // |visiblePositionForContentsPoint()|.
+  selection().moveRangeSelectionExtent(IntPoint(0, 0));
+  EXPECT_EQ(selectionInDOMTree, selection().selectionInDOMTree());
+}
+
+// For http://crbug.com/704529
+TEST_F(GranularityStrategyTest, UpdateExtentWithNullPositionForDirectional) {
+  document().body()->setInnerHTML("<div id=host></div><div id=sample>ab</div>");
+  // Simulate VIDEO element which has a RANGE as slider of video time.
+  Element* const host = document().getElementById("host");
+  ShadowRoot* const shadowRoot =
+      host->createShadowRootInternal(ShadowRootType::Open, ASSERT_NO_EXCEPTION);
+  shadowRoot->setInnerHTML("<input type=range>");
+  Element* const sample = document().getElementById("sample");
+  document().updateStyleAndLayout();
+  const SelectionInDOMTree& selectionInDOMTree =
+      SelectionInDOMTree::Builder()
+          .collapse(Position(sample->firstChild(), 2))
+          .setIsDirectional(true)
+          .setIsHandleVisible(true)
+          .build();
+  selection().setSelection(selectionInDOMTree);
+
+  // Since, it is not obvious that |visiblePositionForContentsPoint()| returns
+  // null position, we verify here.
+  ASSERT_EQ(Position(),
+            visiblePositionForContentsPoint(IntPoint(0, 0), &frame())
+                .deepEquivalent())
+      << "This test requires null position.";
+
+  // Point to RANGE inside shadow root to get null position from
+  // |visiblePositionForContentsPoint()|.
+  selection().moveRangeSelectionExtent(IntPoint(0, 0));
+
+  EXPECT_EQ(selectionInDOMTree, selection().selectionInDOMTree());
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/SelectionEditor.cpp b/third_party/WebKit/Source/core/editing/SelectionEditor.cpp
index 615c5d7..778bbd76 100644
--- a/third_party/WebKit/Source/core/editing/SelectionEditor.cpp
+++ b/third_party/WebKit/Source/core/editing/SelectionEditor.cpp
@@ -348,10 +348,6 @@
   didFinishTextChange(newBase, newExtent);
 }
 
-Range* SelectionEditor::firstRange() const {
-  return createRange(firstEphemeralRangeOf(computeVisibleSelectionInDOMTree()));
-}
-
 bool SelectionEditor::shouldAlwaysUseDirectionalSelection() const {
   return frame()->editor().behavior().shouldConsiderSelectionAsDirectional();
 }
diff --git a/third_party/WebKit/Source/core/editing/SelectionEditor.h b/third_party/WebKit/Source/core/editing/SelectionEditor.h
index 322b3b4..bd4af3a 100644
--- a/third_party/WebKit/Source/core/editing/SelectionEditor.h
+++ b/third_party/WebKit/Source/core/editing/SelectionEditor.h
@@ -61,11 +61,6 @@
 
   void documentAttached(Document*);
 
-  // If this FrameSelection has a logical range which is still valid, this
-  // function return its clone. Otherwise, the return value from underlying
-  // |VisibleSelection|'s |firstRange()| is returned.
-  Range* firstRange() const;
-
   // There functions are exposed for |FrameSelection|.
   void cacheRangeOfDocument(Range*);
   Range* documentCachedRange() const;
diff --git a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp
index ec63558..30d2a360 100644
--- a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp
@@ -1963,6 +1963,37 @@
   m_endingSelection = parent->m_endingSelection;
 }
 
+// Determines whether a node is inside a range or visibly starts and ends at the
+// boundaries of the range. Call this function to determine whether a node is
+// visibly fit inside selectedRange
+bool CompositeEditCommand::isNodeVisiblyContainedWithin(
+    Node& node,
+    const Range& selectedRange) {
+  DCHECK(!needsLayoutTreeUpdate(node));
+  DocumentLifecycle::DisallowTransitionScope disallowTransition(
+      node.document().lifecycle());
+
+  if (selectedRange.isNodeFullyContained(node))
+    return true;
+
+  bool startIsVisuallySame =
+      visiblePositionBeforeNode(node).deepEquivalent() ==
+      createVisiblePosition(selectedRange.startPosition()).deepEquivalent();
+  if (startIsVisuallySame && comparePositions(Position::inParentAfterNode(node),
+                                              selectedRange.endPosition()) < 0)
+    return true;
+
+  bool endIsVisuallySame =
+      visiblePositionAfterNode(node).deepEquivalent() ==
+      createVisiblePosition(selectedRange.endPosition()).deepEquivalent();
+  if (endIsVisuallySame &&
+      comparePositions(selectedRange.startPosition(),
+                       Position::inParentBeforeNode(node)) < 0)
+    return true;
+
+  return startIsVisuallySame && endIsVisuallySame;
+}
+
 DEFINE_TRACE(CompositeEditCommand) {
   visitor->trace(m_commands);
   visitor->trace(m_startingSelection);
diff --git a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.h b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.h
index 7a2642b..d4d1f9b 100644
--- a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.h
+++ b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.h
@@ -221,6 +221,8 @@
 
   Node* splitTreeToNode(Node*, Node*, bool splitAncestor = false);
 
+  static bool isNodeVisiblyContainedWithin(Node&, const Range&);
+
   HeapVector<Member<EditCommand>> m_commands;
 
  private:
diff --git a/third_party/WebKit/Source/core/html/HTMLFormControlElement.cpp b/third_party/WebKit/Source/core/html/HTMLFormControlElement.cpp
index f0e9aa5a..8046e82e 100644
--- a/third_party/WebKit/Source/core/html/HTMLFormControlElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLFormControlElement.cpp
@@ -584,9 +584,6 @@
     pseudoStateChanged(CSSSelector::PseudoInvalid);
   }
 
-  pseudoStateChanged(CSSSelector::PseudoInRange);
-  pseudoStateChanged(CSSSelector::PseudoOutOfRange);
-
   // Updates only if this control already has a validation message.
   if (isValidationMessageVisible()) {
     // Calls updateVisibleValidationMessage() even if m_isValid is not
diff --git a/third_party/WebKit/Source/core/html/HTMLInputElement.cpp b/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
index 6ef98db..aa2e7b46 100644
--- a/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
@@ -726,6 +726,7 @@
     setNeedsValidityCheck();
     m_valueAttributeWasUpdatedAfterParsing = !m_parsingInProgress;
     m_inputType->warnIfValueIsInvalidAndElementIsVisible(value);
+    m_inputType->inRangeChanged();
     m_inputTypeView->valueAttributeChanged();
   } else if (name == checkedAttr) {
     // Another radio button in the same group might be checked by state
@@ -770,11 +771,13 @@
   } else if (name == minAttr) {
     m_inputTypeView->minOrMaxAttributeChanged();
     m_inputType->sanitizeValueInResponseToMinOrMaxAttributeChange();
+    m_inputType->inRangeChanged();
     setNeedsValidityCheck();
     UseCounter::count(document(), UseCounter::MinAttribute);
   } else if (name == maxAttr) {
     m_inputTypeView->minOrMaxAttributeChanged();
     m_inputType->sanitizeValueInResponseToMinOrMaxAttributeChange();
+    m_inputType->inRangeChanged();
     setNeedsValidityCheck();
     UseCounter::count(document(), UseCounter::MaxAttribute);
   } else if (name == multipleAttr) {
@@ -1099,10 +1102,7 @@
   m_nonAttributeValue = sanitizedValue;
   m_hasDirtyValue = true;
   setNeedsValidityCheck();
-  if (m_inputType->isSteppable()) {
-    pseudoStateChanged(CSSSelector::PseudoInRange);
-    pseudoStateChanged(CSSSelector::PseudoOutOfRange);
-  }
+  m_inputType->inRangeChanged();
 }
 
 void HTMLInputElement::setNonDirtyValue(const String& newValue) {
diff --git a/third_party/WebKit/Source/core/html/forms/InputType.cpp b/third_party/WebKit/Source/core/html/forms/InputType.cpp
index 8aa3a4a..6fcf15a 100644
--- a/third_party/WebKit/Source/core/html/forms/InputType.cpp
+++ b/third_party/WebKit/Source/core/html/forms/InputType.cpp
@@ -297,6 +297,13 @@
           numericValue > stepRange.maximum());
 }
 
+void InputType::inRangeChanged() const {
+  if (isSteppable()) {
+    element().pseudoStateChanged(CSSSelector::PseudoInRange);
+    element().pseudoStateChanged(CSSSelector::PseudoOutOfRange);
+  }
+}
+
 bool InputType::stepMismatch(const String& value) const {
   if (!isSteppable())
     return false;
diff --git a/third_party/WebKit/Source/core/html/forms/InputType.h b/third_party/WebKit/Source/core/html/forms/InputType.h
index af9283a..be26ce1 100644
--- a/third_party/WebKit/Source/core/html/forms/InputType.h
+++ b/third_party/WebKit/Source/core/html/forms/InputType.h
@@ -130,6 +130,7 @@
   bool rangeOverflow(const String&) const;
   bool isInRange(const String&) const;
   bool isOutOfRange(const String&) const;
+  void inRangeChanged() const;
   virtual Decimal defaultValueForStepUp() const;
   double minimum() const;
   double maximum() const;
diff --git a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
index 06461184..b2a432e 100644
--- a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
@@ -900,9 +900,6 @@
   DCHECK(m_fallbackRequestForServiceWorker.isNull());
 
   if (!m_actualRequest.isNull()) {
-    // FIXME: Timeout should be applied to whole fetch, not for each of
-    // preflight and actual request.
-    m_timeoutTimer.stop();
     DCHECK(!m_sameOriginRequest);
     DCHECK_EQ(m_options.crossOriginRequestPolicy, UseAccessControl);
     loadActualRequest();
@@ -988,7 +985,9 @@
   if (!m_actualRequest.isNull())
     resourceLoaderOptions.dataBufferingPolicy = BufferData;
 
-  if (m_options.timeoutMilliseconds > 0) {
+  // The timer can be active if this is the actual request of a
+  // CORS-with-preflight request.
+  if (m_options.timeoutMilliseconds > 0 && !m_timeoutTimer.isActive()) {
     m_timeoutTimer.startOneShot(m_options.timeoutMilliseconds / 1000.0,
                                 BLINK_FROM_HERE);
   }
diff --git a/third_party/WebKit/Source/modules/beacon/OWNERS b/third_party/WebKit/Source/modules/beacon/OWNERS
new file mode 100644
index 0000000..48a3882
--- /dev/null
+++ b/third_party/WebKit/Source/modules/beacon/OWNERS
@@ -0,0 +1,5 @@
+sigbjornf@opera.com
+tyoshino@chromium.org
+
+# TEAM: blink-network-dev@chromium.org
+# COMPONENT: Blink>Network
diff --git a/third_party/WebKit/Source/wtf/ASCIICTypeTest.cpp b/third_party/WebKit/Source/platform/wtf/ASCIICTypeTest.cpp
similarity index 91%
rename from third_party/WebKit/Source/wtf/ASCIICTypeTest.cpp
rename to third_party/WebKit/Source/platform/wtf/ASCIICTypeTest.cpp
index 55d123d6..0bca42c8 100644
--- a/third_party/WebKit/Source/wtf/ASCIICTypeTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/ASCIICTypeTest.cpp
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "wtf/ASCIICType.h"
+#include "platform/wtf/ASCIICType.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/third_party/WebKit/Source/wtf/AssertionsTest.cpp b/third_party/WebKit/Source/platform/wtf/AssertionsTest.cpp
similarity index 95%
rename from third_party/WebKit/Source/wtf/AssertionsTest.cpp
rename to third_party/WebKit/Source/platform/wtf/AssertionsTest.cpp
index a15d47c..3e5fbfd 100644
--- a/third_party/WebKit/Source/wtf/AssertionsTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/AssertionsTest.cpp
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "wtf/Assertions.h"
+#include "platform/wtf/Assertions.h"
 
+#include "platform/wtf/text/StringBuilder.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "wtf/text/StringBuilder.h"
 #include <stdio.h>
 
 namespace WTF {
diff --git a/third_party/WebKit/Source/platform/wtf/BUILD.gn b/third_party/WebKit/Source/platform/wtf/BUILD.gn
index 3d133651..57617d31 100644
--- a/third_party/WebKit/Source/platform/wtf/BUILD.gn
+++ b/third_party/WebKit/Source/platform/wtf/BUILD.gn
@@ -20,14 +20,16 @@
 #
 # When we finish moving all the files, "platform_wtf" target will take over
 # the role of "wtf".
-#
-# TODO(yutak): Set up platform_wtf_unittests in the similar manner.
 
 assert(!is_ios)
 
+import("//testing/test.gni")
 import("//third_party/WebKit/Source/config.gni")
 
-visibility = [ "//third_party/WebKit/Source/wtf/*" ]
+visibility = [
+  ":*",
+  "//third_party/WebKit/Source/wtf/*",
+]
 
 config("wtf_config") {
   if (is_win) {
@@ -57,7 +59,7 @@
   }
 }
 
-source_set("platform_wtf") {
+component("platform_wtf") {
   sources = [
     "ASCIICType.cpp",
     "ASCIICType.h",
@@ -330,3 +332,68 @@
     configs += [ "//build/config/compiler:no_symbols" ]
   }
 }
+
+test("wtf_unittests") {
+  visibility = []  # Allow re-assignment of list.
+  visibility = [ "*" ]
+
+  sources = [
+    "ASCIICTypeTest.cpp",
+    "AssertionsTest.cpp",
+    "DequeTest.cpp",
+    "FunctionalTest.cpp",
+    "HashMapTest.cpp",
+    "HashSetTest.cpp",
+    "ListHashSetTest.cpp",
+    "MathExtrasTest.cpp",
+    "OptionalTest.cpp",
+    "PassRefPtrTest.cpp",
+    "RefPtrTest.cpp",
+    "StringExtrasTest.cpp",
+    "StringHasherTest.cpp",
+    "TimeTest.cpp",
+    "TreeNodeTest.cpp",
+    "TypeTraitsTest.cpp",
+    "VectorTest.cpp",
+    "dtoa_test.cpp",
+    "testing/RunAllTests.cpp",
+    "text/AtomicStringTest.cpp",
+    "text/CStringTest.cpp",
+    "text/IntegerToStringConversionTest.cpp",
+    "text/StringBufferTest.cpp",
+    "text/StringBuilderTest.cpp",
+    "text/StringImplTest.cpp",
+    "text/StringOperatorsTest.cpp",
+    "text/StringToNumberTest.cpp",
+    "text/StringViewTest.cpp",
+    "text/TextCodecICUTest.cpp",
+    "text/TextCodecLatin1Test.cpp",
+    "text/TextCodecReplacementTest.cpp",
+    "text/TextCodecTest.cpp",
+    "text/TextCodecUTF8Test.cpp",
+    "text/TextCodecUserDefinedTest.cpp",
+    "text/TextEncodingTest.cpp",
+    "text/WTFStringTest.cpp",
+    "typed_arrays/ArrayBufferBuilderTest.cpp",
+  ]
+
+  # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+
+  if (is_win) {
+    cflags = [ "/wd4068" ]  # Unknown pragma.
+  }
+
+  configs += [
+    "//third_party/WebKit/Source:config",
+    "//third_party/WebKit/Source:blink_pch",
+  ]
+
+  deps = [
+    ":platform_wtf",
+    "//base",
+    "//base/test:test_support",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+}
diff --git a/third_party/WebKit/Source/wtf/DequeTest.cpp b/third_party/WebKit/Source/platform/wtf/DequeTest.cpp
similarity index 99%
rename from third_party/WebKit/Source/wtf/DequeTest.cpp
rename to third_party/WebKit/Source/platform/wtf/DequeTest.cpp
index d4e2655..fe65902 100644
--- a/third_party/WebKit/Source/wtf/DequeTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/DequeTest.cpp
@@ -23,11 +23,11 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "wtf/Deque.h"
+#include "platform/wtf/Deque.h"
 
+#include "platform/wtf/HashSet.h"
+#include "platform/wtf/PtrUtil.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "wtf/HashSet.h"
-#include "wtf/PtrUtil.h"
 #include <memory>
 
 namespace WTF {
diff --git a/third_party/WebKit/Source/wtf/FunctionalTest.cpp b/third_party/WebKit/Source/platform/wtf/FunctionalTest.cpp
similarity index 99%
rename from third_party/WebKit/Source/wtf/FunctionalTest.cpp
rename to third_party/WebKit/Source/platform/wtf/FunctionalTest.cpp
index 30dc236..e5b1fa9e 100644
--- a/third_party/WebKit/Source/wtf/FunctionalTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/FunctionalTest.cpp
@@ -23,11 +23,11 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "wtf/Functional.h"
+#include "platform/wtf/Functional.h"
 
+#include "platform/wtf/RefCounted.h"
+#include "platform/wtf/WeakPtr.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "wtf/RefCounted.h"
-#include "wtf/WeakPtr.h"
 #include <utility>
 
 namespace WTF {
diff --git a/third_party/WebKit/Source/wtf/HashMapTest.cpp b/third_party/WebKit/Source/platform/wtf/HashMapTest.cpp
similarity index 98%
rename from third_party/WebKit/Source/wtf/HashMapTest.cpp
rename to third_party/WebKit/Source/platform/wtf/HashMapTest.cpp
index fb556ef..83b8fc8 100644
--- a/third_party/WebKit/Source/wtf/HashMapTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/HashMapTest.cpp
@@ -23,13 +23,13 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "wtf/HashMap.h"
+#include "platform/wtf/HashMap.h"
 
+#include "platform/wtf/PassRefPtr.h"
+#include "platform/wtf/PtrUtil.h"
+#include "platform/wtf/RefCounted.h"
+#include "platform/wtf/Vector.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "wtf/PassRefPtr.h"
-#include "wtf/PtrUtil.h"
-#include "wtf/RefCounted.h"
-#include "wtf/Vector.h"
 #include <memory>
 
 namespace WTF {
diff --git a/third_party/WebKit/Source/wtf/HashSetTest.cpp b/third_party/WebKit/Source/platform/wtf/HashSetTest.cpp
similarity index 98%
rename from third_party/WebKit/Source/wtf/HashSetTest.cpp
rename to third_party/WebKit/Source/platform/wtf/HashSetTest.cpp
index 4d6e77c..62ad787 100644
--- a/third_party/WebKit/Source/wtf/HashSetTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/HashSetTest.cpp
@@ -23,11 +23,11 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "wtf/HashSet.h"
+#include "platform/wtf/HashSet.h"
 
+#include "platform/wtf/PtrUtil.h"
+#include "platform/wtf/RefCounted.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "wtf/PtrUtil.h"
-#include "wtf/RefCounted.h"
 #include <memory>
 
 namespace WTF {
diff --git a/third_party/WebKit/Source/wtf/ListHashSetTest.cpp b/third_party/WebKit/Source/platform/wtf/ListHashSetTest.cpp
similarity index 98%
rename from third_party/WebKit/Source/wtf/ListHashSetTest.cpp
rename to third_party/WebKit/Source/platform/wtf/ListHashSetTest.cpp
index 59f5cfe..2839ca6 100644
--- a/third_party/WebKit/Source/wtf/ListHashSetTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/ListHashSetTest.cpp
@@ -23,14 +23,14 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "wtf/ListHashSet.h"
+#include "platform/wtf/ListHashSet.h"
 
+#include "platform/wtf/LinkedHashSet.h"
+#include "platform/wtf/PassRefPtr.h"
+#include "platform/wtf/PtrUtil.h"
+#include "platform/wtf/RefCounted.h"
+#include "platform/wtf/RefPtr.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "wtf/LinkedHashSet.h"
-#include "wtf/PassRefPtr.h"
-#include "wtf/PtrUtil.h"
-#include "wtf/RefCounted.h"
-#include "wtf/RefPtr.h"
 #include <memory>
 #include <type_traits>
 
diff --git a/third_party/WebKit/Source/wtf/MathExtrasTest.cpp b/third_party/WebKit/Source/platform/wtf/MathExtrasTest.cpp
similarity index 99%
rename from third_party/WebKit/Source/wtf/MathExtrasTest.cpp
rename to third_party/WebKit/Source/platform/wtf/MathExtrasTest.cpp
index 0ab26cd..3fe79b4 100644
--- a/third_party/WebKit/Source/wtf/MathExtrasTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/MathExtrasTest.cpp
@@ -23,7 +23,7 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "wtf/MathExtras.h"
+#include "platform/wtf/MathExtras.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/third_party/WebKit/Source/wtf/OptionalTest.cpp b/third_party/WebKit/Source/platform/wtf/OptionalTest.cpp
similarity index 96%
rename from third_party/WebKit/Source/wtf/OptionalTest.cpp
rename to third_party/WebKit/Source/platform/wtf/OptionalTest.cpp
index 68335458..7630f54 100644
--- a/third_party/WebKit/Source/wtf/OptionalTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/OptionalTest.cpp
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "wtf/Optional.h"
+#include "platform/wtf/Optional.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/third_party/WebKit/Source/wtf/PassRefPtrTest.cpp b/third_party/WebKit/Source/platform/wtf/PassRefPtrTest.cpp
similarity index 90%
rename from third_party/WebKit/Source/wtf/PassRefPtrTest.cpp
rename to third_party/WebKit/Source/platform/wtf/PassRefPtrTest.cpp
index e9126636..c089f95 100644
--- a/third_party/WebKit/Source/wtf/PassRefPtrTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/PassRefPtrTest.cpp
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "wtf/PassRefPtr.h"
+#include "platform/wtf/PassRefPtr.h"
 
+#include "platform/wtf/RefCounted.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "wtf/RefCounted.h"
 
 namespace WTF {
 
diff --git a/third_party/WebKit/Source/wtf/RefPtrTest.cpp b/third_party/WebKit/Source/platform/wtf/RefPtrTest.cpp
similarity index 91%
rename from third_party/WebKit/Source/wtf/RefPtrTest.cpp
rename to third_party/WebKit/Source/platform/wtf/RefPtrTest.cpp
index 9e0975a..1615f1e 100644
--- a/third_party/WebKit/Source/wtf/RefPtrTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/RefPtrTest.cpp
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "wtf/RefPtr.h"
+#include "platform/wtf/RefPtr.h"
 
+#include "platform/wtf/RefCounted.h"
+#include "platform/wtf/text/StringImpl.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "wtf/RefCounted.h"
-#include "wtf/text/StringImpl.h"
 
 namespace WTF {
 
diff --git a/third_party/WebKit/Source/wtf/StringExtrasTest.cpp b/third_party/WebKit/Source/platform/wtf/StringExtrasTest.cpp
similarity index 97%
rename from third_party/WebKit/Source/wtf/StringExtrasTest.cpp
rename to third_party/WebKit/Source/platform/wtf/StringExtrasTest.cpp
index ab32cf5..bc399c68 100644
--- a/third_party/WebKit/Source/wtf/StringExtrasTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/StringExtrasTest.cpp
@@ -23,11 +23,11 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "wtf/StringExtras.h"
+#include "platform/wtf/StringExtras.h"
 
+#include "platform/wtf/text/CString.h"
+#include "platform/wtf/text/WTFString.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "wtf/text/CString.h"
-#include "wtf/text/WTFString.h"
 #include <limits>
 
 namespace WTF {
diff --git a/third_party/WebKit/Source/wtf/StringHasherTest.cpp b/third_party/WebKit/Source/platform/wtf/StringHasherTest.cpp
similarity index 99%
rename from third_party/WebKit/Source/wtf/StringHasherTest.cpp
rename to third_party/WebKit/Source/platform/wtf/StringHasherTest.cpp
index 8cf8ea2..7882e27 100644
--- a/third_party/WebKit/Source/wtf/StringHasherTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/StringHasherTest.cpp
@@ -23,7 +23,7 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "wtf/StringHasher.h"
+#include "platform/wtf/StringHasher.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/third_party/WebKit/Source/wtf/TimeTest.cpp b/third_party/WebKit/Source/platform/wtf/TimeTest.cpp
similarity index 95%
rename from third_party/WebKit/Source/wtf/TimeTest.cpp
rename to third_party/WebKit/Source/platform/wtf/TimeTest.cpp
index f39176c..140495c 100644
--- a/third_party/WebKit/Source/wtf/TimeTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/TimeTest.cpp
@@ -1,4 +1,4 @@
-#include "wtf/Time.h"
+#include "platform/wtf/Time.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/third_party/WebKit/Source/wtf/TreeNodeTest.cpp b/third_party/WebKit/Source/platform/wtf/TreeNodeTest.cpp
similarity index 97%
rename from third_party/WebKit/Source/wtf/TreeNodeTest.cpp
rename to third_party/WebKit/Source/platform/wtf/TreeNodeTest.cpp
index 18421f25..855d651 100644
--- a/third_party/WebKit/Source/wtf/TreeNodeTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/TreeNodeTest.cpp
@@ -23,12 +23,12 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "wtf/TreeNode.h"
+#include "platform/wtf/TreeNode.h"
 
+#include "platform/wtf/PassRefPtr.h"
+#include "platform/wtf/RefCounted.h"
+#include "platform/wtf/RefPtr.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "wtf/PassRefPtr.h"
-#include "wtf/RefCounted.h"
-#include "wtf/RefPtr.h"
 
 namespace WTF {
 
diff --git a/third_party/WebKit/Source/wtf/TypeTraitsTest.cpp b/third_party/WebKit/Source/platform/wtf/TypeTraitsTest.cpp
similarity index 98%
rename from third_party/WebKit/Source/wtf/TypeTraitsTest.cpp
rename to third_party/WebKit/Source/platform/wtf/TypeTraitsTest.cpp
index f3f972d5..43e38ea 100644
--- a/third_party/WebKit/Source/wtf/TypeTraitsTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/TypeTraitsTest.cpp
@@ -19,9 +19,9 @@
  *
  */
 
-#include "wtf/TypeTraits.h"
+#include "platform/wtf/TypeTraits.h"
 
-#include "wtf/Noncopyable.h"
+#include "platform/wtf/Noncopyable.h"
 
 // No gtest tests; only static_assert checks.
 
diff --git a/third_party/WebKit/Source/wtf/VectorTest.cpp b/third_party/WebKit/Source/platform/wtf/VectorTest.cpp
similarity index 98%
rename from third_party/WebKit/Source/wtf/VectorTest.cpp
rename to third_party/WebKit/Source/platform/wtf/VectorTest.cpp
index 6089962..049d97a 100644
--- a/third_party/WebKit/Source/wtf/VectorTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/VectorTest.cpp
@@ -23,13 +23,13 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "wtf/Vector.h"
+#include "platform/wtf/Vector.h"
 
+#include "platform/wtf/HashSet.h"
+#include "platform/wtf/Optional.h"
+#include "platform/wtf/PtrUtil.h"
+#include "platform/wtf/text/WTFString.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "wtf/HashSet.h"
-#include "wtf/Optional.h"
-#include "wtf/PtrUtil.h"
-#include "wtf/text/WTFString.h"
 #include <memory>
 
 namespace WTF {
diff --git a/third_party/WebKit/Source/wtf/dtoa_test.cpp b/third_party/WebKit/Source/platform/wtf/dtoa_test.cpp
similarity index 97%
rename from third_party/WebKit/Source/wtf/dtoa_test.cpp
rename to third_party/WebKit/Source/platform/wtf/dtoa_test.cpp
index 64d3f35..7b0f092 100644
--- a/third_party/WebKit/Source/wtf/dtoa_test.cpp
+++ b/third_party/WebKit/Source/platform/wtf/dtoa_test.cpp
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "wtf/dtoa.h"
+#include "platform/wtf/dtoa.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/third_party/WebKit/Source/wtf/testing/RunAllTests.cpp b/third_party/WebKit/Source/platform/wtf/testing/RunAllTests.cpp
similarity index 89%
rename from third_party/WebKit/Source/wtf/testing/RunAllTests.cpp
rename to third_party/WebKit/Source/platform/wtf/testing/RunAllTests.cpp
index 1d23af7..307211cb7 100644
--- a/third_party/WebKit/Source/wtf/testing/RunAllTests.cpp
+++ b/third_party/WebKit/Source/platform/wtf/testing/RunAllTests.cpp
@@ -28,11 +28,11 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "wtf/CryptographicallyRandomNumber.h"
-#include "wtf/CurrentTime.h"
-#include "wtf/WTF.h"
-#include "wtf/allocator/Partitions.h"
-#include <base/test/test_suite.h>
+#include "base/test/test_suite.h"
+#include "platform/wtf/CryptographicallyRandomNumber.h"
+#include "platform/wtf/CurrentTime.h"
+#include "platform/wtf/WTF.h"
+#include "platform/wtf/allocator/Partitions.h"
 #include <string.h>
 
 static double dummyCurrentTime() {
diff --git a/third_party/WebKit/Source/wtf/text/AtomicStringTest.cpp b/third_party/WebKit/Source/platform/wtf/text/AtomicStringTest.cpp
similarity index 98%
rename from third_party/WebKit/Source/wtf/text/AtomicStringTest.cpp
rename to third_party/WebKit/Source/platform/wtf/text/AtomicStringTest.cpp
index 7e3ef3b..d07f404 100644
--- a/third_party/WebKit/Source/wtf/text/AtomicStringTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/text/AtomicStringTest.cpp
@@ -28,7 +28,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "wtf/text/AtomicString.h"
+#include "platform/wtf/text/AtomicString.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/third_party/WebKit/Source/wtf/text/CStringTest.cpp b/third_party/WebKit/Source/platform/wtf/text/CStringTest.cpp
similarity index 99%
rename from third_party/WebKit/Source/wtf/text/CStringTest.cpp
rename to third_party/WebKit/Source/platform/wtf/text/CStringTest.cpp
index 6a365f2..96fb189 100644
--- a/third_party/WebKit/Source/wtf/text/CStringTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/text/CStringTest.cpp
@@ -23,7 +23,7 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "wtf/text/CString.h"
+#include "platform/wtf/text/CString.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include <sstream>
diff --git a/third_party/WebKit/Source/wtf/text/IntegerToStringConversionTest.cpp b/third_party/WebKit/Source/platform/wtf/text/IntegerToStringConversionTest.cpp
similarity index 82%
rename from third_party/WebKit/Source/wtf/text/IntegerToStringConversionTest.cpp
rename to third_party/WebKit/Source/platform/wtf/text/IntegerToStringConversionTest.cpp
index 7ec4910c..409a3f2 100644
--- a/third_party/WebKit/Source/wtf/text/IntegerToStringConversionTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/text/IntegerToStringConversionTest.cpp
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "wtf/text/IntegerToStringConversion.h"
+#include "platform/wtf/text/IntegerToStringConversion.h"
 
+#include "platform/wtf/text/StringView.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "wtf/text/StringView.h"
 
 namespace WTF {
 
diff --git a/third_party/WebKit/Source/wtf/text/StringBufferTest.cpp b/third_party/WebKit/Source/platform/wtf/text/StringBufferTest.cpp
similarity index 94%
rename from third_party/WebKit/Source/wtf/text/StringBufferTest.cpp
rename to third_party/WebKit/Source/platform/wtf/text/StringBufferTest.cpp
index 1d22521..61148d8 100644
--- a/third_party/WebKit/Source/wtf/text/StringBufferTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/text/StringBufferTest.cpp
@@ -4,7 +4,7 @@
  * found in the LICENSE file.
  */
 
-#include "wtf/text/StringBuffer.h"
+#include "platform/wtf/text/StringBuffer.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/third_party/WebKit/Source/wtf/text/StringBuilderTest.cpp b/third_party/WebKit/Source/platform/wtf/text/StringBuilderTest.cpp
similarity index 97%
rename from third_party/WebKit/Source/wtf/text/StringBuilderTest.cpp
rename to third_party/WebKit/Source/platform/wtf/text/StringBuilderTest.cpp
index acaee22..524a8c14 100644
--- a/third_party/WebKit/Source/wtf/text/StringBuilderTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/text/StringBuilderTest.cpp
@@ -29,13 +29,13 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "wtf/text/StringBuilder.h"
+#include "platform/wtf/text/StringBuilder.h"
 
+#include "platform/wtf/Assertions.h"
+#include "platform/wtf/text/CString.h"
+#include "platform/wtf/text/CharacterNames.h"
+#include "platform/wtf/text/WTFString.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "wtf/Assertions.h"
-#include "wtf/text/CString.h"
-#include "wtf/text/CharacterNames.h"
-#include "wtf/text/WTFString.h"
 
 namespace WTF {
 
diff --git a/third_party/WebKit/Source/wtf/text/StringImplTest.cpp b/third_party/WebKit/Source/platform/wtf/text/StringImplTest.cpp
similarity index 98%
rename from third_party/WebKit/Source/wtf/text/StringImplTest.cpp
rename to third_party/WebKit/Source/platform/wtf/text/StringImplTest.cpp
index 8e8835a..09bc5e7 100644
--- a/third_party/WebKit/Source/wtf/text/StringImplTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/text/StringImplTest.cpp
@@ -23,10 +23,10 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "wtf/text/StringImpl.h"
+#include "platform/wtf/text/StringImpl.h"
 
+#include "platform/wtf/text/WTFString.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "wtf/text/WTFString.h"
 
 namespace WTF {
 
diff --git a/third_party/WebKit/Source/wtf/text/StringOperatorsTest.cpp b/third_party/WebKit/Source/platform/wtf/text/StringOperatorsTest.cpp
similarity index 99%
rename from third_party/WebKit/Source/wtf/text/StringOperatorsTest.cpp
rename to third_party/WebKit/Source/platform/wtf/text/StringOperatorsTest.cpp
index 2b8859df..29501e20 100644
--- a/third_party/WebKit/Source/wtf/text/StringOperatorsTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/text/StringOperatorsTest.cpp
@@ -27,8 +27,8 @@
 
 static int wtfStringCopyCount;
 
+#include "platform/wtf/text/WTFString.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "wtf/text/WTFString.h"
 
 namespace WTF {
 
diff --git a/third_party/WebKit/Source/wtf/text/StringToNumberTest.cpp b/third_party/WebKit/Source/platform/wtf/text/StringToNumberTest.cpp
similarity index 98%
rename from third_party/WebKit/Source/wtf/text/StringToNumberTest.cpp
rename to third_party/WebKit/Source/platform/wtf/text/StringToNumberTest.cpp
index 429147c..7eb7717d 100644
--- a/third_party/WebKit/Source/wtf/text/StringToNumberTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/text/StringToNumberTest.cpp
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "wtf/text/StringToNumber.h"
+#include "platform/wtf/text/StringToNumber.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include <cstring>
diff --git a/third_party/WebKit/Source/wtf/text/StringViewTest.cpp b/third_party/WebKit/Source/platform/wtf/text/StringViewTest.cpp
similarity index 98%
rename from third_party/WebKit/Source/wtf/text/StringViewTest.cpp
rename to third_party/WebKit/Source/platform/wtf/text/StringViewTest.cpp
index 7c41186..8e25a0d5 100644
--- a/third_party/WebKit/Source/wtf/text/StringViewTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/text/StringViewTest.cpp
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "wtf/text/StringView.h"
+#include "platform/wtf/text/StringView.h"
 
+#include "platform/wtf/text/AtomicString.h"
+#include "platform/wtf/text/StringImpl.h"
+#include "platform/wtf/text/WTFString.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "wtf/text/AtomicString.h"
-#include "wtf/text/StringImpl.h"
-#include "wtf/text/WTFString.h"
 
 namespace WTF {
 
diff --git a/third_party/WebKit/Source/wtf/text/TextCodecICUTest.cpp b/third_party/WebKit/Source/platform/wtf/text/TextCodecICUTest.cpp
similarity index 93%
rename from third_party/WebKit/Source/wtf/text/TextCodecICUTest.cpp
rename to third_party/WebKit/Source/platform/wtf/text/TextCodecICUTest.cpp
index c1aef93..3469902 100644
--- a/third_party/WebKit/Source/wtf/text/TextCodecICUTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/text/TextCodecICUTest.cpp
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "wtf/text/TextCodecICU.h"
+#include "platform/wtf/text/TextCodecICU.h"
 
+#include "platform/wtf/Vector.h"
+#include "platform/wtf/text/CharacterNames.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "wtf/Vector.h"
-#include "wtf/text/CharacterNames.h"
 
 namespace WTF {
 
diff --git a/third_party/WebKit/Source/wtf/text/TextCodecLatin1Test.cpp b/third_party/WebKit/Source/platform/wtf/text/TextCodecLatin1Test.cpp
similarity index 84%
rename from third_party/WebKit/Source/wtf/text/TextCodecLatin1Test.cpp
rename to third_party/WebKit/Source/platform/wtf/text/TextCodecLatin1Test.cpp
index 71fb8d1..a68d389 100644
--- a/third_party/WebKit/Source/wtf/text/TextCodecLatin1Test.cpp
+++ b/third_party/WebKit/Source/platform/wtf/text/TextCodecLatin1Test.cpp
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "wtf/text/TextCodecLatin1.h"
+#include "platform/wtf/text/TextCodecLatin1.h"
 
+#include "platform/wtf/text/CString.h"
+#include "platform/wtf/text/TextCodec.h"
+#include "platform/wtf/text/TextEncoding.h"
+#include "platform/wtf/text/TextEncodingRegistry.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "wtf/text/CString.h"
-#include "wtf/text/TextCodec.h"
-#include "wtf/text/TextEncoding.h"
-#include "wtf/text/TextEncodingRegistry.h"
 #include <memory>
 
 TEST(TextCodecLatin1Test, QuestionMarksAndSurrogates) {
diff --git a/third_party/WebKit/Source/wtf/text/TextCodecReplacementTest.cpp b/third_party/WebKit/Source/platform/wtf/text/TextCodecReplacementTest.cpp
similarity index 85%
rename from third_party/WebKit/Source/wtf/text/TextCodecReplacementTest.cpp
rename to third_party/WebKit/Source/platform/wtf/text/TextCodecReplacementTest.cpp
index 06084273..8a441f9 100644
--- a/third_party/WebKit/Source/wtf/text/TextCodecReplacementTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/text/TextCodecReplacementTest.cpp
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "wtf/text/TextCodecReplacement.h"
+#include "platform/wtf/text/TextCodecReplacement.h"
 
+#include "platform/wtf/text/CString.h"
+#include "platform/wtf/text/TextCodec.h"
+#include "platform/wtf/text/TextEncoding.h"
+#include "platform/wtf/text/TextEncodingRegistry.h"
+#include "platform/wtf/text/WTFString.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "wtf/text/CString.h"
-#include "wtf/text/TextCodec.h"
-#include "wtf/text/TextEncoding.h"
-#include "wtf/text/TextEncodingRegistry.h"
-#include "wtf/text/WTFString.h"
 #include <memory>
 
 namespace WTF {
diff --git a/third_party/WebKit/Source/wtf/text/TextCodecTest.cpp b/third_party/WebKit/Source/platform/wtf/text/TextCodecTest.cpp
similarity index 98%
rename from third_party/WebKit/Source/wtf/text/TextCodecTest.cpp
rename to third_party/WebKit/Source/platform/wtf/text/TextCodecTest.cpp
index bb6c139..cebf585a 100644
--- a/third_party/WebKit/Source/wtf/text/TextCodecTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/text/TextCodecTest.cpp
@@ -28,7 +28,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "wtf/text/TextCodec.h"
+#include "platform/wtf/text/TextCodec.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/third_party/WebKit/Source/wtf/text/TextCodecUTF8Test.cpp b/third_party/WebKit/Source/platform/wtf/text/TextCodecUTF8Test.cpp
similarity index 92%
rename from third_party/WebKit/Source/wtf/text/TextCodecUTF8Test.cpp
rename to third_party/WebKit/Source/platform/wtf/text/TextCodecUTF8Test.cpp
index 18ab423..5bbd9f0 100644
--- a/third_party/WebKit/Source/wtf/text/TextCodecUTF8Test.cpp
+++ b/third_party/WebKit/Source/platform/wtf/text/TextCodecUTF8Test.cpp
@@ -28,13 +28,13 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "wtf/text/TextCodecUTF8.h"
+#include "platform/wtf/text/TextCodecUTF8.h"
 
+#include "platform/wtf/text/TextCodec.h"
+#include "platform/wtf/text/TextEncoding.h"
+#include "platform/wtf/text/TextEncodingRegistry.h"
+#include "platform/wtf/text/WTFString.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "wtf/text/TextCodec.h"
-#include "wtf/text/TextEncoding.h"
-#include "wtf/text/TextEncodingRegistry.h"
-#include "wtf/text/WTFString.h"
 #include <memory>
 
 namespace WTF {
diff --git a/third_party/WebKit/Source/wtf/text/TextCodecUserDefinedTest.cpp b/third_party/WebKit/Source/platform/wtf/text/TextCodecUserDefinedTest.cpp
similarity index 87%
rename from third_party/WebKit/Source/wtf/text/TextCodecUserDefinedTest.cpp
rename to third_party/WebKit/Source/platform/wtf/text/TextCodecUserDefinedTest.cpp
index 9442ab5..22cd289 100644
--- a/third_party/WebKit/Source/wtf/text/TextCodecUserDefinedTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/text/TextCodecUserDefinedTest.cpp
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "wtf/text/TextCodecUserDefined.h"
+#include "platform/wtf/text/TextCodecUserDefined.h"
 
+#include "platform/wtf/text/CString.h"
+#include "platform/wtf/text/TextCodec.h"
+#include "platform/wtf/text/TextEncoding.h"
+#include "platform/wtf/text/TextEncodingRegistry.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "wtf/text/CString.h"
-#include "wtf/text/TextCodec.h"
-#include "wtf/text/TextEncoding.h"
-#include "wtf/text/TextEncodingRegistry.h"
 #include <memory>
 
 TEST(TextCodecUserDefinedTest, QuestionMarksAndSurrogates) {
diff --git a/third_party/WebKit/Source/wtf/text/TextEncodingTest.cpp b/third_party/WebKit/Source/platform/wtf/text/TextEncodingTest.cpp
similarity index 98%
rename from third_party/WebKit/Source/wtf/text/TextEncodingTest.cpp
rename to third_party/WebKit/Source/platform/wtf/text/TextEncodingTest.cpp
index 9191eaf..49e15a1d 100644
--- a/third_party/WebKit/Source/wtf/text/TextEncodingTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/text/TextEncodingTest.cpp
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "wtf/text/TextEncoding.h"
+#include "platform/wtf/text/TextEncoding.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/third_party/WebKit/Source/wtf/text/WTFStringTest.cpp b/third_party/WebKit/Source/platform/wtf/text/WTFStringTest.cpp
similarity index 99%
rename from third_party/WebKit/Source/wtf/text/WTFStringTest.cpp
rename to third_party/WebKit/Source/platform/wtf/text/WTFStringTest.cpp
index 081384c1..ec3715e 100644
--- a/third_party/WebKit/Source/wtf/text/WTFStringTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/text/WTFStringTest.cpp
@@ -23,11 +23,11 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "wtf/text/WTFString.h"
+#include "platform/wtf/text/WTFString.h"
 
+#include "platform/wtf/MathExtras.h"
+#include "platform/wtf/text/CString.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "wtf/MathExtras.h"
-#include "wtf/text/CString.h"
 #include <limits>
 
 namespace WTF {
diff --git a/third_party/WebKit/Source/wtf/typed_arrays/ArrayBufferBuilderTest.cpp b/third_party/WebKit/Source/platform/wtf/typed_arrays/ArrayBufferBuilderTest.cpp
similarity index 98%
rename from third_party/WebKit/Source/wtf/typed_arrays/ArrayBufferBuilderTest.cpp
rename to third_party/WebKit/Source/platform/wtf/typed_arrays/ArrayBufferBuilderTest.cpp
index 8d75c73..d1914af 100644
--- a/third_party/WebKit/Source/wtf/typed_arrays/ArrayBufferBuilderTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/typed_arrays/ArrayBufferBuilderTest.cpp
@@ -28,10 +28,10 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "wtf/typed_arrays/ArrayBufferBuilder.h"
+#include "platform/wtf/typed_arrays/ArrayBufferBuilder.h"
 
+#include "platform/wtf/Assertions.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "wtf/Assertions.h"
 #include <limits.h>
 #include <string.h>
 
diff --git a/third_party/WebKit/Source/wtf/BUILD.gn b/third_party/WebKit/Source/wtf/BUILD.gn
index 634b9d8..f8621d67 100644
--- a/third_party/WebKit/Source/wtf/BUILD.gn
+++ b/third_party/WebKit/Source/wtf/BUILD.gn
@@ -204,68 +204,3 @@
     configs += [ "//build/config/compiler:no_symbols" ]
   }
 }
-
-test("wtf_unittests") {
-  visibility = []  # Allow re-assignment of list.
-  visibility = [ "*" ]
-
-  sources = [
-    "ASCIICTypeTest.cpp",
-    "AssertionsTest.cpp",
-    "DequeTest.cpp",
-    "FunctionalTest.cpp",
-    "HashMapTest.cpp",
-    "HashSetTest.cpp",
-    "ListHashSetTest.cpp",
-    "MathExtrasTest.cpp",
-    "OptionalTest.cpp",
-    "PassRefPtrTest.cpp",
-    "RefPtrTest.cpp",
-    "StringExtrasTest.cpp",
-    "StringHasherTest.cpp",
-    "TimeTest.cpp",
-    "TreeNodeTest.cpp",
-    "TypeTraitsTest.cpp",
-    "VectorTest.cpp",
-    "dtoa_test.cpp",
-    "testing/RunAllTests.cpp",
-    "text/AtomicStringTest.cpp",
-    "text/CStringTest.cpp",
-    "text/IntegerToStringConversionTest.cpp",
-    "text/StringBufferTest.cpp",
-    "text/StringBuilderTest.cpp",
-    "text/StringImplTest.cpp",
-    "text/StringOperatorsTest.cpp",
-    "text/StringToNumberTest.cpp",
-    "text/StringViewTest.cpp",
-    "text/TextCodecICUTest.cpp",
-    "text/TextCodecLatin1Test.cpp",
-    "text/TextCodecReplacementTest.cpp",
-    "text/TextCodecTest.cpp",
-    "text/TextCodecUTF8Test.cpp",
-    "text/TextCodecUserDefinedTest.cpp",
-    "text/TextEncodingTest.cpp",
-    "text/WTFStringTest.cpp",
-    "typed_arrays/ArrayBufferBuilderTest.cpp",
-  ]
-
-  # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
-  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
-
-  if (is_win) {
-    cflags = [ "/wd4068" ]  # Unknown pragma.
-  }
-
-  configs += [
-    "//third_party/WebKit/Source:config",
-    "//third_party/WebKit/Source:blink_pch",
-  ]
-
-  deps = [
-    ":wtf",
-    "//base",
-    "//base/test:test_support",
-    "//testing/gmock",
-    "//testing/gtest",
-  ]
-}
diff --git a/third_party/WebKit/public/BUILD.gn b/third_party/WebKit/public/BUILD.gn
index 7c1d81fd..cfaa3d6 100644
--- a/third_party/WebKit/public/BUILD.gn
+++ b/third_party/WebKit/public/BUILD.gn
@@ -40,9 +40,9 @@
     "//third_party/WebKit/Source/modules",
     "//third_party/WebKit/Source/platform:blink_platform_unittests",
     "//third_party/WebKit/Source/platform/heap:blink_heap_unittests",
+    "//third_party/WebKit/Source/platform/wtf:wtf_unittests",
     "//third_party/WebKit/Source/web",
     "//third_party/WebKit/Source/web:webkit_unit_tests",
-    "//third_party/WebKit/Source/wtf:wtf_unittests",
   ]
 }