diff --git a/DEPS b/DEPS
index 28c1c95..75bddad 100644
--- a/DEPS
+++ b/DEPS
@@ -39,11 +39,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'fcff08c8301b1ca08eee20911d0df5fb9db41156',
+  'skia_revision': 'a7627dc5cc2bf5d9a95d883d20c40d477ecadadf',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '205085f926d00f4ea6e756bf251c54313d61e9d8',
+  'v8_revision': 'e6b4ab5c3268efc45d13e06b7758670934f93fc5',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -87,7 +87,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling NaCl
   # and whatever else without interference from each other.
-  'nacl_revision': '0f5756e09816dba8fc189ae75a55cd96fd5edeac',
+  'nacl_revision': 'f3dcedcdb5cf72890166b9618005331bd2666e84',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling dEQP
   # and whatever else without interference from each other.
@@ -217,7 +217,7 @@
    Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067',
 
   'src/third_party/webrtc':
-    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'c8b569e0a7ad0b369e15f0197b3a558699ec8efa', # commit position 10494
+    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '7ad9e661f8a035d49d049ccdb87c77ae8ecdfa35', # commit position 10537
 
   'src/third_party/openmax_dl':
     Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' +  Var('openmax_dl_revision'),
@@ -540,13 +540,15 @@
   },
   {
     # This downloads SDK extras and puts them in the
-    # third_party/android_tools/sdk/extras directory on the bots. Developers
-    # need to manually install these packages and accept the ToS.
+    # third_party/android_tools/sdk/extras directory.
     'name': 'sdkextras',
     'pattern': '.',
     # When adding a new sdk extras package to download, add the package
     # directory and zip file to .gitignore in third_party/android_tools.
-    'action': ['python', 'src/build/download_sdk_extras.py'],
+    'action': ['python',
+               'src/build/android/play_services/update.py',
+               'download'
+    ],
   },
   {
     # Downloads the current stable linux sysroot to build/linux/ if needed.
diff --git a/android_webview/browser/net/android_stream_reader_url_request_job.cc b/android_webview/browser/net/android_stream_reader_url_request_job.cc
index c1bbea8..dc288faa5 100644
--- a/android_webview/browser/net/android_stream_reader_url_request_job.cc
+++ b/android_webview/browser/net/android_stream_reader_url_request_job.cc
@@ -21,7 +21,6 @@
 #include "content/public/browser/browser_thread.h"
 #include "net/base/io_buffer.h"
 #include "net/base/mime_util.h"
-#include "net/base/net_errors.h"
 #include "net/base/net_util.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_response_info.h"
@@ -90,6 +89,7 @@
     net::NetworkDelegate* network_delegate,
     scoped_ptr<Delegate> delegate)
     : URLRequestJob(request, network_delegate),
+      range_parse_result_(net::OK),
       delegate_(delegate.Pass()),
       weak_factory_(this) {
   DCHECK(delegate_);
@@ -101,6 +101,7 @@
     scoped_ptr<DelegateObtainer> delegate_obtainer,
     bool)
     : URLRequestJob(request, network_delegate),
+      range_parse_result_(net::OK),
       delegate_obtainer_(delegate_obtainer.Pass()),
       weak_factory_(this) {
   DCHECK(delegate_obtainer_);
@@ -141,7 +142,10 @@
         base::Bind(&AndroidStreamReaderURLRequestJob::DelegateObtained,
                    weak_factory_.GetWeakPtr()));
   } else {
-    DoStart();
+    // Run DoStart asynchronously to avoid re-entering the delegate.
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&AndroidStreamReaderURLRequestJob::DoStart,
+                              weak_factory_.GetWeakPtr()));
   }
 }
 
@@ -202,60 +206,40 @@
     set_expected_content_size(result);
     HeadersComplete(kHTTPOk, kHTTPOkText);
   } else {
-    NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
+    NotifyStartError(
+        net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
   }
 }
 
 void AndroidStreamReaderURLRequestJob::OnReaderReadCompleted(int result) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  // The URLRequest API contract requires that:
-  // * NotifyDone be called once, to set the status code, indicate the job is
-  //   finished (there will be no further IO),
-  // * NotifyReadComplete be called if false is returned from ReadRawData to
-  //   indicate that the IOBuffer will not be used by the job anymore.
-  // There might be multiple calls to ReadRawData (and thus multiple calls to
-  // NotifyReadComplete), which is why NotifyDone is called only on errors
-  // (result < 0) and end of data (result == 0).
-  if (result == 0) {
-    NotifyDone(net::URLRequestStatus());
-  } else if (result < 0) {
-    NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
-  } else {
-    // Clear the IO_PENDING status.
-    SetStatus(net::URLRequestStatus());
-  }
-  NotifyReadComplete(result);
+
+  ReadRawDataComplete(result);
 }
 
 base::TaskRunner* AndroidStreamReaderURLRequestJob::GetWorkerThreadRunner() {
   return static_cast<base::TaskRunner*>(BrowserThread::GetBlockingPool());
 }
 
-bool AndroidStreamReaderURLRequestJob::ReadRawData(net::IOBuffer* dest,
-                                                   int dest_size,
-                                                   int* bytes_read) {
+int AndroidStreamReaderURLRequestJob::ReadRawData(net::IOBuffer* dest,
+                                                  int dest_size) {
   DCHECK(thread_checker_.CalledOnValidThread());
   if (!input_stream_reader_wrapper_.get()) {
     // This will happen if opening the InputStream fails in which case the
     // error is communicated by setting the HTTP response status header rather
     // than failing the request during the header fetch phase.
-    *bytes_read = 0;
-    return true;
+    return 0;
   }
 
   PostTaskAndReplyWithResult(
-      GetWorkerThreadRunner(),
-      FROM_HERE,
+      GetWorkerThreadRunner(), FROM_HERE,
       base::Bind(&InputStreamReaderWrapper::ReadRawData,
-                 input_stream_reader_wrapper_,
-                 make_scoped_refptr(dest),
+                 input_stream_reader_wrapper_, make_scoped_refptr(dest),
                  dest_size),
       base::Bind(&AndroidStreamReaderURLRequestJob::OnReaderReadCompleted,
                  weak_factory_.GetWeakPtr()));
 
-  SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING,
-                                  net::ERR_IO_PENDING));
-  return false;
+  return net::ERR_IO_PENDING;
 }
 
 bool AndroidStreamReaderURLRequestJob::GetMimeType(
@@ -305,6 +289,11 @@
 
 void AndroidStreamReaderURLRequestJob::DoStart() {
   DCHECK(thread_checker_.CalledOnValidThread());
+  if (range_parse_result_ != net::OK) {
+    NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED,
+                                           range_parse_result_));
+    return;
+  }
   // Start reading asynchronously so that all error reporting and data
   // callbacks happen as they would for network requests.
   SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING,
@@ -385,19 +374,18 @@
     const net::HttpRequestHeaders& headers) {
   std::string range_header;
   if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) {
-    // We only extract the "Range" header so that we know how many bytes in the
-    // stream to skip and how many to read after that.
+    // This job only cares about the Range header so that we know how many bytes
+    // in the stream to skip and how many to read after that. Note that
+    // validation is deferred to DoStart(), because NotifyStartError() is not
+    // legal to call since the job has not started.
     std::vector<net::HttpByteRange> ranges;
     if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) {
-      if (ranges.size() == 1) {
+      if (ranges.size() == 1)
         byte_range_ = ranges[0];
-      } else {
-        // We don't support multiple range requests in one single URL request,
-        // because we need to do multipart encoding here.
-        NotifyDone(net::URLRequestStatus(
-            net::URLRequestStatus::FAILED,
-            net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
-      }
+    } else {
+      // We don't support multiple range requests in one single URL request,
+      // because we need to do multipart encoding here.
+      range_parse_result_ = net::ERR_REQUEST_RANGE_NOT_SATISFIABLE;
     }
   }
 }
diff --git a/android_webview/browser/net/android_stream_reader_url_request_job.h b/android_webview/browser/net/android_stream_reader_url_request_job.h
index e21d7655..645be13 100644
--- a/android_webview/browser/net/android_stream_reader_url_request_job.h
+++ b/android_webview/browser/net/android_stream_reader_url_request_job.h
@@ -15,6 +15,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread_checker.h"
+#include "net/base/net_errors.h"
 #include "net/http/http_byte_range.h"
 #include "net/url_request/url_request_job.h"
 
@@ -96,7 +97,7 @@
   // URLRequestJob:
   void Start() override;
   void Kill() override;
-  bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override;
+  int ReadRawData(net::IOBuffer* buf, int buf_size) override;
   void SetExtraRequestHeaders(const net::HttpRequestHeaders& headers) override;
   bool GetMimeType(std::string* mime_type) const override;
   bool GetCharset(std::string* charset) override;
@@ -131,6 +132,7 @@
   void OnReaderReadCompleted(int bytes_read);
 
   net::HttpByteRange byte_range_;
+  net::Error range_parse_result_;
   scoped_ptr<net::HttpResponseInfo> response_info_;
   scoped_ptr<Delegate> delegate_;
   scoped_ptr<DelegateObtainer> delegate_obtainer_;
diff --git a/base/base_export.h b/base/base_export.h
index 723b38a6..cf7ebd7 100644
--- a/base/base_export.h
+++ b/base/base_export.h
@@ -10,25 +10,20 @@
 
 #if defined(BASE_IMPLEMENTATION)
 #define BASE_EXPORT __declspec(dllexport)
-#define BASE_EXPORT_PRIVATE __declspec(dllexport)
 #else
 #define BASE_EXPORT __declspec(dllimport)
-#define BASE_EXPORT_PRIVATE __declspec(dllimport)
 #endif  // defined(BASE_IMPLEMENTATION)
 
 #else  // defined(WIN32)
 #if defined(BASE_IMPLEMENTATION)
 #define BASE_EXPORT __attribute__((visibility("default")))
-#define BASE_EXPORT_PRIVATE __attribute__((visibility("default")))
 #else
 #define BASE_EXPORT
-#define BASE_EXPORT_PRIVATE
 #endif  // defined(BASE_IMPLEMENTATION)
 #endif
 
 #else  // defined(COMPONENT_BUILD)
 #define BASE_EXPORT
-#define BASE_EXPORT_PRIVATE
 #endif
 
 #endif  // BASE_BASE_EXPORT_H_
diff --git a/base/json/json_parser.h b/base/json/json_parser.h
index 4e23beb..ac1ad85 100644
--- a/base/json/json_parser.h
+++ b/base/json/json_parser.h
@@ -40,7 +40,7 @@
 // of a token, such that the next iteration of the parser will be at the byte
 // immediately following the token, which would likely be the first byte of the
 // next token.
-class BASE_EXPORT_PRIVATE JSONParser {
+class BASE_EXPORT JSONParser {
  public:
   explicit JSONParser(int options);
   ~JSONParser();
diff --git a/base/metrics/bucket_ranges.h b/base/metrics/bucket_ranges.h
index 6ea5849..eb330f4 100644
--- a/base/metrics/bucket_ranges.h
+++ b/base/metrics/bucket_ranges.h
@@ -71,7 +71,7 @@
 
 //////////////////////////////////////////////////////////////////////////////
 // Expose only for test.
-BASE_EXPORT_PRIVATE extern const uint32 kCrcTable[256];
+BASE_EXPORT extern const uint32 kCrcTable[256];
 
 }  // namespace base
 
diff --git a/base/metrics/histogram.h b/base/metrics/histogram.h
index 1f6e2a1..15e0ec2 100644
--- a/base/metrics/histogram.h
+++ b/base/metrics/histogram.h
@@ -224,7 +224,7 @@
   friend class StatisticsRecorder;  // To allow it to delete duplicates.
   friend class StatisticsRecorderTest;
 
-  friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+  friend BASE_EXPORT HistogramBase* DeserializeHistogramInfo(
       base::PickleIterator* iter);
   static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
 
@@ -349,7 +349,7 @@
   bool PrintEmptyBucket(size_t index) const override;
 
  private:
-  friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+  friend BASE_EXPORT HistogramBase* DeserializeHistogramInfo(
       base::PickleIterator* iter);
   static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
 
@@ -379,7 +379,7 @@
  private:
   BooleanHistogram(const std::string& name, const BucketRanges* ranges);
 
-  friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+  friend BASE_EXPORT HistogramBase* DeserializeHistogramInfo(
       base::PickleIterator* iter);
   static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
 
@@ -427,7 +427,7 @@
   double GetBucketSize(Count current, size_t i) const override;
 
  private:
-  friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+  friend BASE_EXPORT HistogramBase* DeserializeHistogramInfo(
       base::PickleIterator* iter);
   static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
 
diff --git a/base/metrics/histogram_base.h b/base/metrics/histogram_base.h
index 304e3e03..669d4ba 100644
--- a/base/metrics/histogram_base.h
+++ b/base/metrics/histogram_base.h
@@ -43,8 +43,7 @@
 
 // Create or find existing histogram that matches the pickled info.
 // Returns NULL if the pickled data has problems.
-BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
-    base::PickleIterator* iter);
+BASE_EXPORT HistogramBase* DeserializeHistogramInfo(base::PickleIterator* iter);
 
 ////////////////////////////////////////////////////////////////////////////////
 
diff --git a/base/metrics/sample_map.h b/base/metrics/sample_map.h
index 952d34a1..d1d7cd6 100644
--- a/base/metrics/sample_map.h
+++ b/base/metrics/sample_map.h
@@ -17,7 +17,7 @@
 
 namespace base {
 
-class BASE_EXPORT_PRIVATE SampleMap : public HistogramSamples {
+class BASE_EXPORT SampleMap : public HistogramSamples {
  public:
   SampleMap();
   ~SampleMap() override;
@@ -40,7 +40,7 @@
   DISALLOW_COPY_AND_ASSIGN(SampleMap);
 };
 
-class BASE_EXPORT_PRIVATE SampleMapIterator : public SampleCountIterator {
+class BASE_EXPORT SampleMapIterator : public SampleCountIterator {
  public:
   typedef std::map<HistogramBase::Sample, HistogramBase::Count>
       SampleToCountMap;
diff --git a/base/metrics/sample_vector.h b/base/metrics/sample_vector.h
index 55f9b96..8cb2ab9 100644
--- a/base/metrics/sample_vector.h
+++ b/base/metrics/sample_vector.h
@@ -20,7 +20,7 @@
 
 class BucketRanges;
 
-class BASE_EXPORT_PRIVATE SampleVector : public HistogramSamples {
+class BASE_EXPORT SampleVector : public HistogramSamples {
  public:
   explicit SampleVector(const BucketRanges* bucket_ranges);
   ~SampleVector() override;
@@ -53,7 +53,7 @@
   DISALLOW_COPY_AND_ASSIGN(SampleVector);
 };
 
-class BASE_EXPORT_PRIVATE SampleVectorIterator : public SampleCountIterator {
+class BASE_EXPORT SampleVectorIterator : public SampleCountIterator {
  public:
   SampleVectorIterator(const std::vector<HistogramBase::AtomicCount>* counts,
                        const BucketRanges* bucket_ranges);
diff --git a/base/metrics/sparse_histogram.h b/base/metrics/sparse_histogram.h
index 3abd080..241d975 100644
--- a/base/metrics/sparse_histogram.h
+++ b/base/metrics/sparse_histogram.h
@@ -28,7 +28,7 @@
 
 class HistogramSamples;
 
-class BASE_EXPORT_PRIVATE SparseHistogram : public HistogramBase {
+class BASE_EXPORT SparseHistogram : public HistogramBase {
  public:
   // If there's one with same name, return the existing one. If not, create a
   // new one.
@@ -57,7 +57,7 @@
   // Clients should always use FactoryGet to create SparseHistogram.
   explicit SparseHistogram(const std::string& name);
 
-  friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+  friend BASE_EXPORT HistogramBase* DeserializeHistogramInfo(
       base::PickleIterator* iter);
   static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
 
diff --git a/base/trace_event/memory_profiler_allocation_register.cc b/base/trace_event/memory_profiler_allocation_register.cc
index 662e86f..4421c0a 100644
--- a/base/trace_event/memory_profiler_allocation_register.cc
+++ b/base/trace_event/memory_profiler_allocation_register.cc
@@ -4,6 +4,8 @@
 
 #include "base/trace_event/memory_profiler_allocation_register.h"
 
+#include "base/trace_event/trace_event_memory_overhead.h"
+
 namespace base {
 namespace trace_event {
 
@@ -162,5 +164,19 @@
   return static_cast<uint32_t>(h) & kNumBucketsMask;
 }
 
+void AllocationRegister::EstimateTraceMemoryOverhead(
+    TraceEventMemoryOverhead* overhead) const {
+  // Estimate memory overhead by counting all of the cells that have ever been
+  // touched. Don't report mmapped memory as allocated, because it has not been
+  // allocated by malloc.
+  size_t allocated = sizeof(AllocationRegister);
+  size_t resident = sizeof(AllocationRegister)
+                    // Include size of touched cells (size of |*cells_|).
+                    + sizeof(Cell) * next_unused_cell_
+                    // Size of |*buckets_|.
+                    + sizeof(CellIndex) * kNumBuckets;
+  overhead->Add("AllocationRegister", allocated, resident);
+}
+
 }  // namespace trace_event
 }  // namespace base
diff --git a/base/trace_event/memory_profiler_allocation_register.h b/base/trace_event/memory_profiler_allocation_register.h
index db8eb03..8eb4a9d5 100644
--- a/base/trace_event/memory_profiler_allocation_register.h
+++ b/base/trace_event/memory_profiler_allocation_register.h
@@ -13,6 +13,8 @@
 namespace base {
 namespace trace_event {
 
+class TraceEventMemoryOverhead;
+
 // The allocation register keeps track of all allocations that have not been
 // freed. It is a memory map-backed hash table that stores size and context
 // indexed by address. The hash table is tailored specifically for this use
@@ -72,6 +74,9 @@
   ConstIterator begin() const;
   ConstIterator end() const;
 
+  // Estimates memory overhead including |sizeof(AllocationRegister)|.
+  void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead) const;
+
  private:
   friend class AllocationRegisterTest;
   using CellIndex = uint32_t;
diff --git a/build/android/OWNERS b/build/android/OWNERS
index dd3fe44..09f8997 100644
--- a/build/android/OWNERS
+++ b/build/android/OWNERS
@@ -2,4 +2,5 @@
 klundberg@chromium.org
 mikecase@chromium.org
 pasko@chromium.org
-rnephew@chromium.org
\ No newline at end of file
+perezju@chromium.org
+rnephew@chromium.org
diff --git a/build/android/devil/android/device_blacklist.py b/build/android/devil/android/device_blacklist.py
index cf72ecb..a38da15 100644
--- a/build/android/devil/android/device_blacklist.py
+++ b/build/android/devil/android/device_blacklist.py
@@ -33,7 +33,12 @@
         return dict()
 
       with open(self._path, 'r') as f:
-        return json.load(f)
+        blacklist = json.load(f)
+      if not isinstance(blacklist, dict):
+        logging.warning('Ignoring %s: %s (a dict was expected instead)',
+                        self._path, blacklist)
+        blacklist = dict()
+      return blacklist
 
   def Write(self, blacklist):
     """Writes the provided blacklist to the blacklist file.
@@ -71,4 +76,3 @@
     with self._blacklist_lock:
       if os.path.exists(self._path):
         os.remove(self._path)
-
diff --git a/build/android/gyp/javac.py b/build/android/gyp/javac.py
index f1965811..a818ff85 100755
--- a/build/android/gyp/javac.py
+++ b/build/android/gyp/javac.py
@@ -238,11 +238,21 @@
       if md5_check.PRINT_EXPLANATIONS:
         stdout_filter = None
 
-      build_utils.CheckOutput(
+      attempt_build = lambda: build_utils.CheckOutput(
           cmd,
           print_stdout=options.chromium_code,
           stdout_filter=stdout_filter,
           stderr_filter=ColorJavacOutput)
+      try:
+        attempt_build()
+      except build_utils.CalledProcessError as e:
+        # Work-around for a bug in jmake (http://crbug.com/551449).
+        if 'project database corrupted' not in e.output:
+          raise
+        print ('Applying work-around for jmake project database corrupted '
+               '(http://crbug.com/551449).')
+        os.unlink(pdb_path)
+        attempt_build()
 
     if options.main_class or options.manifest_entry:
       entries = []
diff --git a/build/android/tombstones.py b/build/android/tombstones.py
index c961d75..f1108dd36 100755
--- a/build/android/tombstones.py
+++ b/build/android/tombstones.py
@@ -35,11 +35,14 @@
     Tuples of (tombstone filename, date time of file on device).
   """
   try:
+    if not device.PathExists('/data/tombstones', timeout=60, retries=3):
+      return
+    # TODO(perezju): Introduce a DeviceUtils.Ls() method (crbug.com/552376).
     lines = device.RunShellCommand(
         ['ls', '-a', '-l', '/data/tombstones'],
         as_root=True, check_return=True, env=_TZ_UTC, timeout=60)
     for line in lines:
-      if 'tombstone' in line and not 'No such file or directory' in line:
+      if 'tombstone' in line:
         details = line.split()
         t = datetime.datetime.strptime(details[-3] + ' ' + details[-2],
                                        '%Y-%m-%d %H:%M')
diff --git a/build/android_sdk_extras.json b/build/android_sdk_extras.json
deleted file mode 100644
index 2735e2f..0000000
--- a/build/android_sdk_extras.json
+++ /dev/null
@@ -1,9 +0,0 @@
-[
-  {
-    "dir_name": "google",
-    "version": "26.0.0",
-    "zip": "google_google_play_services_26.0.0.zip",
-    "package": "google_play_services",
-    "package_id": "extra-google-google_play_services"
-  }
-]
diff --git a/build/check_sdk_extras_version.py b/build/check_sdk_extras_version.py
index 9b2f10d..3f2e62b3 100755
--- a/build/check_sdk_extras_version.py
+++ b/build/check_sdk_extras_version.py
@@ -5,127 +5,6 @@
 
 '''Checks the status of an Android SDK package.
 
-Verifies the given package has been installed from the Android SDK Manager and
-that its version is at least the minimum version required by the project
-configuration.
+TODO(dgn) replaced by a direct update mechanism: http://crbug.com/541727
+This file is now a placeholder until removal after 2 sided patches.
 '''
-
-import argparse
-import json
-import os
-import re
-import sys
-
-
-COLORAMA_ROOT = os.path.join(os.path.dirname(__file__),
-                 os.pardir, 'third_party', 'colorama', 'src')
-
-sys.path.append(COLORAMA_ROOT)
-import colorama
-
-
-UDPATE_SCRIPT_PATH = 'build/install-android-sdks.sh'
-
-SDK_EXTRAS_JSON_FILE = os.path.join(os.path.dirname(__file__),
-                                    'android_sdk_extras.json')
-
-PACKAGE_VERSION_PATTERN = r'^Pkg\.Revision=(?P<version>\d+).*$'
-
-PKG_NOT_FOUND_MSG = ('Error while checking Android SDK extras versions. '
-                     'Could not find the "{package_id}" package in '
-                     '{checked_location}. Please run {script} to download it.')
-UPDATE_NEEDED_MSG = ('Error while checking Android SDK extras versions. '
-                     'Version {minimum_version} or greater is required for the '
-                     'package "{package_id}". Version {actual_version} found. '
-                     'Please run {script} to update it.')
-REQUIRED_VERSION_ERROR_MSG = ('Error while checking Android SDK extras '
-                              'versions. '
-                              'Could not retrieve the required version for '
-                              'package "{package_id}".')
-
-
-def main():
-  parser = argparse.ArgumentParser(description=__doc__)
-  parser.add_argument('--package-id',
-                      help=('id of the package to check for. The list of '
-                            'available packages and their ids can be obtained '
-                            'by running '
-                            'third_party/android_tools/sdk/tools/android list '
-                            'sdk --extended'))
-  parser.add_argument('--package-location',
-                      help='path to the package\'s expected install location.',
-                      metavar='DIR')
-  parser.add_argument('--stamp',
-                      help=('if specified, a stamp file will be created at the '
-                            'provided location.'),
-                      metavar='FILE')
-
-  args = parser.parse_args()
-
-  if not ShouldSkipVersionCheck():
-    minimum_version = GetRequiredMinimumVersion(args.package_id)
-    CheckPackageVersion(args.package_id, args.package_location, minimum_version)
-
-  # Create the stamp file.
-  if args.stamp:
-    with open(args.stamp, 'a'):
-      os.utime(args.stamp, None)
-
-  sys.exit(0)
-
-def ExitError(msg):
-  sys.exit(colorama.Fore.MAGENTA + colorama.Style.BRIGHT + msg +
-           colorama.Style.RESET_ALL)
-
-
-def GetRequiredMinimumVersion(package_id):
-  with open(SDK_EXTRAS_JSON_FILE, 'r') as json_file:
-    packages = json.load(json_file)
-
-  for package in packages:
-    if package['package_id'] == package_id:
-      return int(package['version'].split('.')[0])
-
-  ExitError(REQUIRED_VERSION_ERROR_MSG.format(package_id=package_id))
-
-
-def CheckPackageVersion(pkg_id, location, minimum_version):
-  version_file_path = os.path.join(location, 'source.properties')
-  # Extracts the version of the package described by the property file. We only
-  # care about the major version number here.
-  version_pattern = re.compile(PACKAGE_VERSION_PATTERN, re.MULTILINE)
-
-  if not os.path.isfile(version_file_path):
-    ExitError(PKG_NOT_FOUND_MSG.format(
-      package_id=pkg_id,
-      checked_location=location,
-      script=UDPATE_SCRIPT_PATH))
-
-  with open(version_file_path, 'r') as f:
-    match = version_pattern.search(f.read())
-
-    if not match:
-      ExitError(PKG_NOT_FOUND_MSG.format(
-        package_id=pkg_id,
-        checked_location=location,
-        script=UDPATE_SCRIPT_PATH))
-
-    pkg_version = int(match.group('version'))
-    if pkg_version < minimum_version:
-      ExitError(UPDATE_NEEDED_MSG.format(
-        package_id=pkg_id,
-        minimum_version=minimum_version,
-        actual_version=pkg_version,
-        script=UDPATE_SCRIPT_PATH))
-
-  # Everything looks ok, print nothing.
-
-def ShouldSkipVersionCheck():
-  '''
-  Bots should not run the version check, since they download the sdk extras
-  in a different way.
-  '''
-  return bool(os.environ.get('CHROME_HEADLESS'))
-
-if __name__ == '__main__':
-  main()
diff --git a/build/common.gypi b/build/common.gypi
index 780f43d..67fc8e5 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -644,9 +644,6 @@
       # Supervised users are enabled by default.
       'enable_supervised_users%': 1,
 
-      # Platform sends memory pressure signals natively.
-      'native_memory_pressure_signals%': 0,
-
       'enable_mdns%' : 0,
       'enable_service_discovery%': 0,
       'enable_hangout_services_extension%': 0,
@@ -812,7 +809,6 @@
           'remoting%': 0,
           'arm_neon%': 0,
           'arm_neon_optional%': 1,
-          'native_memory_pressure_signals%': 1,
           'enable_basic_printing%': 1,
           'enable_print_preview%': 0,
           'enable_task_manager%':0,
@@ -833,10 +829,6 @@
           'proprietary_codecs%': 0,
         }],
 
-        ['OS=="mac" or OS=="ios"', {
-          'native_memory_pressure_signals%': 1,
-        }],
-
         # Enable autofill dialog when not on iOS.
         ['OS!="ios"', {
           'enable_autofill_dialog%': 1,
@@ -1233,7 +1225,6 @@
     'google_default_client_id%': '<(google_default_client_id)',
     'google_default_client_secret%': '<(google_default_client_secret)',
     'enable_supervised_users%': '<(enable_supervised_users)',
-    'native_memory_pressure_signals%': '<(native_memory_pressure_signals)',
     'enable_mdns%' : '<(enable_mdns)',
     'enable_service_discovery%' : '<(enable_service_discovery)',
     'enable_hangout_services_extension%' : '<(enable_hangout_services_extension)',
@@ -2761,9 +2752,6 @@
       ['enable_topchrome_md==1', {
         'defines': ['ENABLE_TOPCHROME_MD=1'],
       }],
-      ['native_memory_pressure_signals==1', {
-        'defines': ['SYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE'],
-      }],
       ['use_udev==1', {
         'defines': ['USE_UDEV'],
       }],
diff --git a/build/download_sdk_extras.py b/build/download_sdk_extras.py
deleted file mode 100755
index 7c3a678..0000000
--- a/build/download_sdk_extras.py
+++ /dev/null
@@ -1,99 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Script to download sdk/extras packages on the bots from google storage.
-
-The script expects arguments that specify zips file in the google storage
-bucket named: <dir in SDK extras>_<package name>_<version>.zip. The file will
-be extracted in the android_tools/sdk/extras directory on the test bots. This
-script will not do anything for developers.
-
-TODO(navabi): Move this script (crbug.com/459819).
-"""
-
-import find_depot_tools
-import json
-import os
-import shutil
-import subprocess
-import sys
-import zipfile
-
-SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
-CHROME_SRC = os.path.abspath(os.path.join(SCRIPT_DIR, os.pardir))
-sys.path.insert(0, os.path.join(SCRIPT_DIR, 'android'))
-
-from pylib import constants
-
-DEPOT_PATH = find_depot_tools.add_depot_tools_to_path()
-GSUTIL_PATH = os.path.join(DEPOT_PATH, 'gsutil.py')
-SDK_EXTRAS_BUCKET = 'gs://chrome-sdk-extras'
-SDK_EXTRAS_PATH = os.path.join(constants.ANDROID_SDK_ROOT, 'extras')
-SDK_EXTRAS_JSON_FILE = os.path.join(os.path.dirname(__file__),
-                                    'android_sdk_extras.json')
-
-
-def clean_and_extract(dir_name, package_name, zip_file):
-  local_dir = '%s/%s/%s' % (SDK_EXTRAS_PATH, dir_name, package_name)
-  if os.path.exists(local_dir):
-    shutil.rmtree(local_dir)
-  local_zip = '%s/%s' % (SDK_EXTRAS_PATH, zip_file)
-  with zipfile.ZipFile(local_zip) as z:
-    z.extractall(path=SDK_EXTRAS_PATH)
-
-
-def download_package_if_needed(remote_file, local_file):
-  """Download a file from GCS.
-
-  Returns:
-    success (bool): True if the download succeeded, False otherwise.
-  """
-  if not os.path.exists(local_file):
-    try:
-      subprocess.check_call(['python', GSUTIL_PATH, '--force-version', '4.7',
-                             'cp', remote_file, local_file])
-    except subprocess.CalledProcessError:
-      print ('WARNING: Failed to download SDK packages. If this bot compiles '
-             'for Android, it may have errors.')
-      return False
-  return True
-
-def main():
-  if not os.environ.get('CHROME_HEADLESS'):
-    # This is not a buildbot checkout.
-    return 0
-  # Update the android_sdk_extras.json file to update downloaded packages.
-  with open(SDK_EXTRAS_JSON_FILE) as json_file:
-    packages = json.load(json_file)
-  for package in packages:
-    local_zip = '%s/%s' % (SDK_EXTRAS_PATH, package['zip'])
-    package_zip = '%s/%s' % (SDK_EXTRAS_BUCKET, package['zip'])
-    for attempt in xrange(2):
-      print '(%d) Downloading package %s' % (attempt + 1, package['zip'])
-      if not download_package_if_needed(package_zip, local_zip):
-        # Ignore errors when download failed to keep the corresponding build
-        # step green. The error we're ignoring here is essentially
-        # 'permission denied', because we're using the presence or absence of
-        # credentials on a build machine as the way to mark android builders.
-        # See crbug.com/460463 for more context.
-        return 0
-      try:
-        # Always clean dir and extract zip to ensure correct contents.
-        clean_and_extract(package['dir_name'],
-                          package['package'],
-                          package['zip'])
-        break
-      except zipfile.BadZipfile:
-        print 'Failed unpacking zip file. Deleting and retrying...'
-        os.remove(local_zip)
-
-    else:
-      print ('WARNING: Failed to unpack SDK packages. If this bot compiles '
-             'for Android, it may have errors.')
-      return 1
-
-
-if __name__ == '__main__':
-  sys.exit(main())
diff --git a/build/get_sdk_extras_packages.py b/build/get_sdk_extras_packages.py
deleted file mode 100755
index a90b8a8..0000000
--- a/build/get_sdk_extras_packages.py
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import json
-import os
-import sys
-
-SDK_EXTRAS_JSON_FILE = os.path.join(os.path.dirname(__file__),
-                                    'android_sdk_extras.json')
-
-def main():
-  with open(SDK_EXTRAS_JSON_FILE) as json_file:
-    packages = json.load(json_file)
-
-  out = []
-  for package in packages:
-    out.append(package['package_id'])
-
-  print ','.join(out)
-
-if __name__ == '__main__':
-  sys.exit(main())
diff --git a/build/install-android-sdks.sh b/build/install-android-sdks.sh
deleted file mode 100755
index 1119b7d7..0000000
--- a/build/install-android-sdks.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash -e
-
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# Script to install SDKs needed to build chromium on android.
-# See http://code.google.com/p/chromium/wiki/AndroidBuildInstructions
-
-echo 'checking for sdk packages install'
-# Use absolute path to call 'android' so script can be run from any directory.
-cwd=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
-# Get the SDK extras packages to install from the DEPS file 'sdkextras' hook.
-packages="$(python ${cwd}/get_sdk_extras_packages.py)"
-if [[ -n "${packages}" ]]; then
-  ${cwd}/../third_party/android_tools/sdk/tools/android update sdk --no-ui \
-      --filter ${packages}
-fi
-
-echo "install-android-sdks.sh complete."
diff --git a/build/install-build-deps-android.sh b/build/install-build-deps-android.sh
index cf87381..9c3692c7 100755
--- a/build/install-build-deps-android.sh
+++ b/build/install-build-deps-android.sh
@@ -13,11 +13,10 @@
 # past the curses-based dialog press TAB <ret> TAB <ret> to agree.
 
 args="$@"
+
+# TODO(dgn) remove this this argument from calls (http://crbug.com/541727)
 if test "$1" = "--skip-sdk-packages"; then
-  skip_inst_sdk_packages=1
   args="${@:2}"
-else
-  skip_inst_sdk_packages=0
 fi
 
 if ! uname -m | egrep -q "i686|x86_64"; then
@@ -92,9 +91,4 @@
   fi
 fi
 
-# Install SDK packages for android
-if test "$skip_inst_sdk_packages" != 1; then
-  "$(dirname "${BASH_SOURCE[0]}")/install-android-sdks.sh"
-fi
-
 echo "install-build-deps-android.sh complete."
diff --git a/build/linux/unbundle/remove_bundled_libraries.py b/build/linux/unbundle/remove_bundled_libraries.py
index 69e76f5..1cf2841b 100755
--- a/build/linux/unbundle/remove_bundled_libraries.py
+++ b/build/linux/unbundle/remove_bundled_libraries.py
@@ -68,6 +68,10 @@
       if f.endswith('.gyp') or f.endswith('.gypi'):
         continue
 
+      # Same about GN files.
+      if f.endswith('.gn') or f.endswith('.gni'):
+        continue
+
       # Deleting .isolate files leads to gyp failures. They are usually
       # not used by a distro build anyway.
       # See http://www.chromium.org/developers/testing/isolated-testing
diff --git a/build/secondary/third_party/android_tools/BUILD.gn b/build/secondary/third_party/android_tools/BUILD.gn
index 710b7d7a..c849d035 100644
--- a/build/secondary/third_party/android_tools/BUILD.gn
+++ b/build/secondary/third_party/android_tools/BUILD.gn
@@ -93,9 +93,6 @@
   v14_skip = true
   resource_dirs = [ "$android_sdk_root/extras/google/google_play_services/libproject/google-play-services_lib/res" ]
   custom_package = "com.google.android.gms"
-  deps = [
-    ":check_sdk_extras_version",
-  ]
 }
 android_java_prebuilt("google_play_services_default_java") {
   deps = [
@@ -106,34 +103,9 @@
   ]
   proguard_preprocess = true
   proguard_config = "//third_party/android_tools/proguard.flags"
-
-  # TODO(dgn) deps should not complain about having a custom action here
-  # Currently, there is no guarantee that the data_deps actions will complete before the current one runs
-  data_deps = [
-    ":check_sdk_extras_version",
-  ]
   jar_path = "$android_sdk_root/extras/google/google_play_services/libproject/google-play-services_lib/libs/google-play-services.jar"
 }
 
-action("check_sdk_extras_version") {
-  script = "//build/check_sdk_extras_version.py"
-  args = [
-    "--package-id",
-    "extra-google-google_play_services",
-    "--package-location",
-    rebase_path("$android_sdk_root/extras/google/google_play_services"),
-    "--stamp",
-    rebase_path("$target_gen_dir/checked_sdk_extras_version.stamp"),
-  ]
-  inputs = [
-    "//build/android_sdk_extras.json",
-    "$android_sdk_root/extras/google/google_play_services/source.properties",
-  ]
-  outputs = [
-    "$target_gen_dir/checked_sdk_extras_version.stamp",
-  ]
-}
-
 # TODO(jbudorick): Remove this once net_java_test_support no longer needs it.
 android_java_prebuilt("legacy_http_javalib") {
   jar_path = "$android_sdk/optional/org.apache.http.legacy.jar"
diff --git a/cc/quads/draw_polygon_unittest.cc b/cc/quads/draw_polygon_unittest.cc
index 27cfed4..517e131 100644
--- a/cc/quads/draw_polygon_unittest.cc
+++ b/cc/quads/draw_polygon_unittest.cc
@@ -50,7 +50,7 @@
   CREATE_NEW_DRAW_POLYGON(
       polygon_b, vertices_b, gfx::Vector3dF(-1.0f, 0.0f, 0.0f), 1);
 
-  EXPECT_EQ(DrawPolygon::SideCompare(polygon_b, polygon_a), BSP_FRONT);
+  EXPECT_EQ(BSP_FRONT, DrawPolygon::SideCompare(polygon_b, polygon_a));
 }
 
 // One quad is resting against another, but doesn't cross its plane so no split
@@ -72,7 +72,7 @@
   CREATE_NEW_DRAW_POLYGON(
       polygon_b, vertices_b, gfx::Vector3dF(-1.0f, 0.0f, 0.0f), 1);
 
-  EXPECT_EQ(DrawPolygon::SideCompare(polygon_b, polygon_a), BSP_BACK);
+  EXPECT_EQ(BSP_BACK, DrawPolygon::SideCompare(polygon_b, polygon_a));
 }
 
 // One quad intersects another and becomes two pieces.
@@ -93,13 +93,13 @@
   CREATE_NEW_DRAW_POLYGON(
       polygon_b, vertices_b, gfx::Vector3dF(-1.0f, 0.0f, 0.0f), 1);
 
-  EXPECT_EQ(DrawPolygon::SideCompare(polygon_b, polygon_a), BSP_SPLIT);
+  EXPECT_EQ(BSP_SPLIT, DrawPolygon::SideCompare(polygon_b, polygon_a));
 
   scoped_ptr<DrawPolygon> front_polygon;
   scoped_ptr<DrawPolygon> back_polygon;
   polygon_b.Split(polygon_a, &front_polygon, &back_polygon);
-  EXPECT_EQ(DrawPolygon::SideCompare(*front_polygon, polygon_a), BSP_FRONT);
-  EXPECT_EQ(DrawPolygon::SideCompare(*back_polygon, polygon_a), BSP_BACK);
+  EXPECT_EQ(BSP_FRONT, DrawPolygon::SideCompare(*front_polygon, polygon_a));
+  EXPECT_EQ(BSP_BACK, DrawPolygon::SideCompare(*back_polygon, polygon_a));
 
   std::vector<gfx::Point3F> test_points_a;
   test_points_a.push_back(gfx::Point3F(5.0f, 0.0f, 0.0f));
@@ -114,8 +114,8 @@
   ValidatePoints(*(front_polygon.get()), test_points_a);
   ValidatePoints(*(back_polygon.get()), test_points_b);
 
-  EXPECT_EQ(front_polygon->points().size(), 4u);
-  EXPECT_EQ(back_polygon->points().size(), 4u);
+  EXPECT_EQ(4u, front_polygon->points().size());
+  EXPECT_EQ(4u, back_polygon->points().size());
 }
 
 // In this test we cut the corner of a quad so that it creates a triangle and
@@ -137,16 +137,16 @@
   CREATE_NEW_DRAW_POLYGON(
       polygon_b, vertices_b, gfx::Vector3dF(0.707107f, 0.0f, -0.707107f), 1);
 
-  EXPECT_EQ(DrawPolygon::SideCompare(polygon_a, polygon_b), BSP_SPLIT);
+  EXPECT_EQ(BSP_SPLIT, DrawPolygon::SideCompare(polygon_a, polygon_b));
 
   scoped_ptr<DrawPolygon> front_polygon;
   scoped_ptr<DrawPolygon> back_polygon;
   polygon_a.Split(polygon_b, &front_polygon, &back_polygon);
-  EXPECT_EQ(DrawPolygon::SideCompare(*front_polygon, polygon_b), BSP_FRONT);
-  EXPECT_EQ(DrawPolygon::SideCompare(*back_polygon, polygon_b), BSP_BACK);
+  EXPECT_EQ(BSP_FRONT, DrawPolygon::SideCompare(*front_polygon, polygon_b));
+  EXPECT_EQ(BSP_BACK, DrawPolygon::SideCompare(*back_polygon, polygon_b));
 
-  EXPECT_EQ(front_polygon->points().size(), 3u);
-  EXPECT_EQ(back_polygon->points().size(), 5u);
+  EXPECT_EQ(3u, front_polygon->points().size());
+  EXPECT_EQ(5u, back_polygon->points().size());
 
   std::vector<gfx::Point3F> test_points_a;
   test_points_a.push_back(gfx::Point3F(10.0f, 0.0f, 9.0f));
diff --git a/cc/resources/video_resource_updater.cc b/cc/resources/video_resource_updater.cc
index 1adfe0e..4936dae 100644
--- a/cc/resources/video_resource_updater.cc
+++ b/cc/resources/video_resource_updater.cc
@@ -75,13 +75,14 @@
                       const gpu::SyncToken& sync_token)
       : gl_(gl), sync_token_(sync_token) {}
   ~SyncTokenClientImpl() override {}
-  uint32 InsertSyncPoint() override {
+  void GenerateSyncToken(gpu::SyncToken* sync_token) override {
     if (sync_token_.HasData()) {
-      DCHECK_EQ(gpu::CommandBufferNamespace::OLD_SYNC_POINTS,
-                sync_token_.namespace_id());
-      return static_cast<uint32>(sync_token_.release_count());
+      *sync_token = sync_token_;
+    } else {
+      const uint64_t fence_sync = gl_->InsertFenceSyncCHROMIUM();
+      gl_->ShallowFlushCHROMIUM();
+      gl_->GenSyncTokenCHROMIUM(fence_sync, sync_token->GetData());
     }
-    return gl_->InsertSyncPointCHROMIUM();
   }
   void WaitSyncToken(const gpu::SyncToken& sync_token) override {
     if (sync_token.HasData()) {
diff --git a/cc/test/test_gpu_memory_buffer_manager.cc b/cc/test/test_gpu_memory_buffer_manager.cc
index 352a75c..ed5e713 100644
--- a/cc/test/test_gpu_memory_buffer_manager.cc
+++ b/cc/test/test_gpu_memory_buffer_manager.cc
@@ -114,9 +114,8 @@
   return reinterpret_cast<gfx::GpuMemoryBuffer*>(buffer);
 }
 
-void TestGpuMemoryBufferManager::SetDestructionSyncPoint(
+void TestGpuMemoryBufferManager::SetDestructionSyncToken(
     gfx::GpuMemoryBuffer* buffer,
-    uint32 sync_point) {
-}
+    const gpu::SyncToken& sync_token) {}
 
 }  // namespace cc
diff --git a/cc/test/test_gpu_memory_buffer_manager.h b/cc/test/test_gpu_memory_buffer_manager.h
index a3720bf..85f642cb 100644
--- a/cc/test/test_gpu_memory_buffer_manager.h
+++ b/cc/test/test_gpu_memory_buffer_manager.h
@@ -25,8 +25,8 @@
       gfx::BufferFormat format) override;
   gfx::GpuMemoryBuffer* GpuMemoryBufferFromClientBuffer(
       ClientBuffer buffer) override;
-  void SetDestructionSyncPoint(gfx::GpuMemoryBuffer* buffer,
-                               uint32 sync_point) override;
+  void SetDestructionSyncToken(gfx::GpuMemoryBuffer* buffer,
+                               const gpu::SyncToken& sync_token) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(TestGpuMemoryBufferManager);
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index efe187c7..9ba7401 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -12812,12 +12812,6 @@
         <message name="IDS_SHOW_DOWNLOADS_MAC" desc="The Mac menu item to show downloads in the window menu.">
           Downloads
         </message>
-        <message name="IDS_WINDOW_AUDIO_PLAYING_MAC" desc="The emoji to append to the title of a window showing audio is playing.">
-          <ph name="TAB_TITLE">$1<ex>The Title of the Tab</ex></ph> (audio)
-        </message>
-        <message name="IDS_WINDOW_AUDIO_MUTING_MAC" desc="The emoji to append to the title of a window showing audio is muting.">
-          <ph name="TAB_TITLE">$1<ex>The Title of the Tab</ex></ph> (muted)
-        </message>
         <message name="IDS_SHOW_EXTENSIONS_MAC" desc="The Mac menu item to show extensions in the window menu.">
           Extensions
         </message>
diff --git a/chrome/browser/android/background_sync_launcher_android.cc b/chrome/browser/android/background_sync_launcher_android.cc
index 7d9c2e3..db5278a 100644
--- a/chrome/browser/android/background_sync_launcher_android.cc
+++ b/chrome/browser/android/background_sync_launcher_android.cc
@@ -23,32 +23,20 @@
 
 // static
 void BackgroundSyncLauncherAndroid::LaunchBrowserWhenNextOnline(
-    const content::BackgroundSyncManager* registrant,
     bool launch_when_next_online) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  Get()->LaunchBrowserWhenNextOnlineImpl(registrant, launch_when_next_online);
+  Get()->LaunchBrowserWhenNextOnlineImpl(launch_when_next_online);
 }
 
 void BackgroundSyncLauncherAndroid::LaunchBrowserWhenNextOnlineImpl(
-    const content::BackgroundSyncManager* registrant,
     bool launch_when_next_online) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  bool was_launching = !launch_when_next_online_registrants_.empty();
-
-  if (launch_when_next_online)
-    launch_when_next_online_registrants_.insert(registrant);
-  else
-    launch_when_next_online_registrants_.erase(registrant);
-
-  bool now_launching = !launch_when_next_online_registrants_.empty();
-  if (was_launching != now_launching) {
-    JNIEnv* env = base::android::AttachCurrentThread();
-    Java_BackgroundSyncLauncher_launchBrowserWhenNextOnlineIfStopped(
-        env, java_launcher_.obj(), base::android::GetApplicationContext(),
-        now_launching);
-  }
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Java_BackgroundSyncLauncher_launchBrowserWhenNextOnlineIfStopped(
+      env, java_launcher_.obj(), base::android::GetApplicationContext(),
+      launch_when_next_online);
 }
 
 // static
diff --git a/chrome/browser/android/background_sync_launcher_android.h b/chrome/browser/android/background_sync_launcher_android.h
index ced3422..1f23d75 100644
--- a/chrome/browser/android/background_sync_launcher_android.h
+++ b/chrome/browser/android/background_sync_launcher_android.h
@@ -25,15 +25,7 @@
  public:
   static BackgroundSyncLauncherAndroid* Get();
 
-  // Register the |registrant|'s interest (or disinterest) in starting the
-  // browser the next time the device goes online after the browser has closed.
-  // |registrant| is used to count the number of interested objects and is not
-  // accessed, therefore it is okay for |registrant| to be deleted before this
-  // class. Interest is reset the next time the BackgroundSyncLauncherAndroid is
-  // created (browser restart). The caller can remove interest in launching the
-  // browser by calling with |launch_when_next_online| set to false.
   static void LaunchBrowserWhenNextOnline(
-      const content::BackgroundSyncManager* registrant,
       bool launch_when_next_online);
 
   static bool RegisterLauncher(JNIEnv* env);
@@ -46,11 +38,8 @@
   ~BackgroundSyncLauncherAndroid();
 
   void LaunchBrowserWhenNextOnlineImpl(
-      const content::BackgroundSyncManager* registrant,
       bool launch_when_next_online);
 
-  std::set<const content::BackgroundSyncManager*>
-      launch_when_next_online_registrants_;
   base::android::ScopedJavaGlobalRef<jobject> java_launcher_;
   DISALLOW_COPY_AND_ASSIGN(BackgroundSyncLauncherAndroid);
 };
diff --git a/chrome/browser/background_sync/background_sync_controller_impl.cc b/chrome/browser/background_sync/background_sync_controller_impl.cc
index 7412edd..e60bf88 100644
--- a/chrome/browser/background_sync/background_sync_controller_impl.cc
+++ b/chrome/browser/background_sync/background_sync_controller_impl.cc
@@ -33,12 +33,15 @@
       GetRapporService(), "BackgroundSync.Register.Origin", origin);
 }
 
-#if defined(OS_ANDROID)
-void BackgroundSyncControllerImpl::LaunchBrowserWhenNextOnline(
-    const content::BackgroundSyncManager* registrant,
-    bool launch_when_next_online) {
+void BackgroundSyncControllerImpl::RunInBackground(bool enabled) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  BackgroundSyncLauncherAndroid::LaunchBrowserWhenNextOnline(
-      registrant, launch_when_next_online);
-}
+
+  if (profile_->IsOffTheRecord())
+    return;
+#if defined(OS_ANDROID)
+  BackgroundSyncLauncherAndroid::LaunchBrowserWhenNextOnline(enabled);
+#else
+// TODO(jkarlin): Use BackgroundModeManager to enter background mode. See
+// https://crbug.com/484201.
 #endif
+}
diff --git a/chrome/browser/background_sync/background_sync_controller_impl.h b/chrome/browser/background_sync/background_sync_controller_impl.h
index 0126149..88f032d9 100644
--- a/chrome/browser/background_sync/background_sync_controller_impl.h
+++ b/chrome/browser/background_sync/background_sync_controller_impl.h
@@ -24,12 +24,7 @@
 
   // content::BackgroundSyncController overrides.
   void NotifyBackgroundSyncRegistered(const GURL& origin) override;
-
-#if defined(OS_ANDROID)
-  void LaunchBrowserWhenNextOnline(
-      const content::BackgroundSyncManager* registrant,
-      bool launch_when_next_online) override;
-#endif
+  void RunInBackground(bool enabled) override;
 
  protected:
   // Virtual for testing.
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 7d218e7..7eb4155 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -130,6 +130,7 @@
         <include name="IDR_MD_DOWNLOADS_CONSTANTS_JS" file="resources\md_downloads\constants.js" type="BINDATA" />
         <include name="IDR_MD_DOWNLOADS_CRISPER_JS" file="resources\md_downloads\crisper.js" flattenhtml="true" type="BINDATA" />
         <include name="IDR_MD_DOWNLOADS_DOWNLOADS_JS" file="resources\md_downloads\downloads.js" type="BINDATA" />
+        <include name="IDR_MD_DOWNLOADS_I18N_HTML" file="resources\md_downloads\i18n.html" type="BINDATA" />
         <include name="IDR_MD_DOWNLOADS_ITEM_CSS" file="resources\md_downloads\item.css" type="BINDATA" flattenhtml="true" />
         <include name="IDR_MD_DOWNLOADS_ITEM_HTML" file="resources\md_downloads\item.html" type="BINDATA" />
         <include name="IDR_MD_DOWNLOADS_ITEM_JS" file="resources\md_downloads\item.js" type="BINDATA" />
@@ -137,7 +138,6 @@
         <include name="IDR_MD_DOWNLOADS_MANAGER_HTML" file="resources\md_downloads\manager.html" type="BINDATA" />
         <include name="IDR_MD_DOWNLOADS_MANAGER_JS" file="resources\md_downloads\manager.js" type="BINDATA" />
         <include name="IDR_MD_DOWNLOADS_SHARED_STYLE_CSS" file="resources\md_downloads\shared_style.css" type="BINDATA" />
-        <include name="IDR_MD_DOWNLOADS_STRINGS_HTML" file="resources\md_downloads\strings.html" type="BINDATA" />
         <include name="IDR_MD_DOWNLOADS_TOOLBAR_CSS" file="resources\md_downloads\toolbar.css" type="BINDATA" />
         <include name="IDR_MD_DOWNLOADS_TOOLBAR_HTML" file="resources\md_downloads\toolbar.html" type="BINDATA" />
         <include name="IDR_MD_DOWNLOADS_TOOLBAR_JS" file="resources\md_downloads\toolbar.js" type="BINDATA" />
diff --git a/chrome/browser/chromeos/fileapi/external_file_url_request_job.cc b/chrome/browser/chromeos/fileapi/external_file_url_request_job.cc
index 2132113..4abe494 100644
--- a/chrome/browser/chromeos/fileapi/external_file_url_request_job.cc
+++ b/chrome/browser/chromeos/fileapi/external_file_url_request_job.cc
@@ -10,6 +10,7 @@
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
 #include "chrome/browser/chromeos/fileapi/external_file_url_util.h"
@@ -19,7 +20,6 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/common/url_constants.h"
-#include "net/base/net_errors.h"
 #include "net/http/http_byte_range.h"
 #include "net/http/http_request_headers.h"
 #include "net/http/http_response_info.h"
@@ -163,32 +163,48 @@
     net::NetworkDelegate* network_delegate)
     : net::URLRequestJob(request, network_delegate),
       profile_id_(profile_id),
+      range_parse_result_(net::OK),
       remaining_bytes_(0),
-      weak_ptr_factory_(this) {
-}
+      weak_ptr_factory_(this) {}
 
 void ExternalFileURLRequestJob::SetExtraRequestHeaders(
     const net::HttpRequestHeaders& headers) {
   std::string range_header;
   if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) {
-    // Note: We only support single range requests.
+    // Currently this job only cares about the Range header, and only supports
+    // single range requests. Note that validation is deferred to Start,
+    // because NotifyStartError is not legal to call since the job has not
+    // started.
     std::vector<net::HttpByteRange> ranges;
     if (net::HttpUtil::ParseRangeHeader(range_header, &ranges) &&
         ranges.size() == 1) {
       byte_range_ = ranges[0];
     } else {
-      // Failed to parse Range: header, so notify the error.
-      NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
-                                       net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
+      range_parse_result_ = net::ERR_REQUEST_RANGE_NOT_SATISFIABLE;
     }
   }
 }
 
 void ExternalFileURLRequestJob::Start() {
+  // Post a task to invoke StartAsync asynchronously to avoid re-entering the
+  // delegate, because NotifyStartError is not legal to call synchronously in
+  // Start().
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&ExternalFileURLRequestJob::StartAsync,
+                            weak_ptr_factory_.GetWeakPtr()));
+}
+
+void ExternalFileURLRequestJob::StartAsync() {
   DVLOG(1) << "Starting request";
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(!stream_reader_);
 
+  if (range_parse_result_ != net::OK) {
+    NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED,
+                                           range_parse_result_));
+    return;
+  }
+
   // We only support GET request.
   if (request()->method() != "GET") {
     LOG(WARNING) << "Failed to start request: " << request()->method()
@@ -326,38 +342,23 @@
   return true;
 }
 
-bool ExternalFileURLRequestJob::ReadRawData(net::IOBuffer* buf,
-                                            int buf_size,
-                                            int* bytes_read) {
+int ExternalFileURLRequestJob::ReadRawData(net::IOBuffer* buf, int buf_size) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(stream_reader_);
 
-  if (remaining_bytes_ == 0) {
-    *bytes_read = 0;
-    return true;
-  }
+  if (remaining_bytes_ == 0)
+    return 0;
 
   const int result = stream_reader_->Read(
-      buf,
-      std::min<int64>(buf_size, remaining_bytes_),
+      buf, std::min<int64>(buf_size, remaining_bytes_),
       base::Bind(&ExternalFileURLRequestJob::OnReadCompleted,
                  weak_ptr_factory_.GetWeakPtr()));
 
-  if (result == net::ERR_IO_PENDING) {
-    // The data is not yet available.
-    SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
-    return false;
-  }
-  if (result < 0) {
-    // An error occurs.
-    NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
-    return false;
-  }
+  if (result < 0)
+    return result;
 
-  // Reading has been finished immediately.
-  *bytes_read = result;
   remaining_bytes_ -= result;
-  return true;
+  return result;
 }
 
 ExternalFileURLRequestJob::~ExternalFileURLRequestJob() {
@@ -366,15 +367,10 @@
 void ExternalFileURLRequestJob::OnReadCompleted(int read_result) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
-  if (read_result < 0) {
-    DCHECK_NE(read_result, net::ERR_IO_PENDING);
-    NotifyDone(
-        net::URLRequestStatus(net::URLRequestStatus::FAILED, read_result));
-  }
+  if (read_result > 0)
+    remaining_bytes_ -= read_result;
 
-  remaining_bytes_ -= read_result;
-  SetStatus(net::URLRequestStatus());  // Clear the IO_PENDING status.
-  NotifyReadComplete(read_result);
+  ReadRawDataComplete(read_result);
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/fileapi/external_file_url_request_job.h b/chrome/browser/chromeos/fileapi/external_file_url_request_job.h
index a026e43..dff3379b 100644
--- a/chrome/browser/chromeos/fileapi/external_file_url_request_job.h
+++ b/chrome/browser/chromeos/fileapi/external_file_url_request_job.h
@@ -63,12 +63,17 @@
   void Kill() override;
   bool GetMimeType(std::string* mime_type) const override;
   bool IsRedirectResponse(GURL* location, int* http_status_code) override;
-  bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override;
+  int ReadRawData(net::IOBuffer* buf, int buf_size) override;
 
  protected:
   ~ExternalFileURLRequestJob() override;
 
  private:
+  // Helper method to start the job. Should be called asynchronously because
+  // NotifyStartError() is not legal to call synchronously in
+  // URLRequestJob::Start().
+  void StartAsync();
+
   // Called from an internal helper class defined in drive_url_request_job.cc,
   // which is running on the UI thread.
   void OnHelperResultObtained(
@@ -91,6 +96,7 @@
   void* const profile_id_;
 
   // The range of the file to be returned.
+  net::Error range_parse_result_;
   net::HttpByteRange byte_range_;
   int64 remaining_bytes_;
 
diff --git a/chrome/browser/extensions/api/dial/dial_service.cc b/chrome/browser/extensions/api/dial/dial_service.cc
index d704ffe..54fbfe0 100644
--- a/chrome/browser/extensions/api/dial/dial_service.cc
+++ b/chrome/browser/extensions/api/dial/dial_service.cc
@@ -21,11 +21,11 @@
 #include "chrome/browser/extensions/api/dial/dial_device_data.h"
 #include "components/version_info/version_info.h"
 #include "content/public/browser/browser_thread.h"
+#include "net/base/address_family.h"
 #include "net/base/completion_callback.h"
 #include "net/base/io_buffer.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/base/network_interfaces.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_util.h"
diff --git a/chrome/browser/extensions/extension_service_test_base.h b/chrome/browser/extensions/extension_service_test_base.h
index 0cb4778..e59e854 100644
--- a/chrome/browser/extensions/extension_service_test_base.h
+++ b/chrome/browser/extensions/extension_service_test_base.h
@@ -72,7 +72,8 @@
   ExtensionServiceInitParams CreateDefaultInitParams();
 
   // Initialize an ExtensionService according to the given |params|.
-  void InitializeExtensionService(const ExtensionServiceInitParams& params);
+  virtual void InitializeExtensionService(
+      const ExtensionServiceInitParams& params);
 
   // Initialize an empty ExtensionService using the default init params.
   void InitializeEmptyExtensionService();
diff --git a/chrome/browser/extensions/extension_service_test_with_install.cc b/chrome/browser/extensions/extension_service_test_with_install.cc
index ab0120e..7f6e37f8 100644
--- a/chrome/browser/extensions/extension_service_test_with_install.cc
+++ b/chrome/browser/extensions/extension_service_test_with_install.cc
@@ -9,7 +9,6 @@
 #include "chrome/browser/extensions/crx_installer.h"
 #include "chrome/browser/extensions/extension_creator.h"
 #include "chrome/browser/extensions/extension_error_reporter.h"
-#include "chrome/browser/profiles/profile.h"
 #include "content/public/browser/notification_service.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/notification_types.h"
@@ -43,23 +42,18 @@
       unloaded_reason_(UnloadedExtensionInfo::REASON_UNDEFINED),
       expected_extensions_count_(0),
       override_external_install_prompt_(
-          FeatureSwitch::prompt_for_external_extensions(),
-          false) {
-  // TODO(treib,devlin): This should use ExtensionRegistryObserver instead.
-  registrar_.Add(this,
-                 extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
-                 content::NotificationService::AllSources());
-  registrar_.Add(this,
-                 extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED,
-                 content::NotificationService::AllSources());
-  registrar_.Add(
-      this,
-      extensions::NOTIFICATION_EXTENSION_WILL_BE_INSTALLED_DEPRECATED,
-      content::NotificationService::AllSources());
-}
+          FeatureSwitch::prompt_for_external_extensions(), false),
+      registry_observer_(this) {}
 
 ExtensionServiceTestWithInstall::~ExtensionServiceTestWithInstall() {}
 
+void ExtensionServiceTestWithInstall::InitializeExtensionService(
+    const ExtensionServiceInitParams& params) {
+  ExtensionServiceTestBase::InitializeExtensionService(params);
+
+  registry_observer_.Add(registry());
+}
+
 // static
 std::vector<base::string16> ExtensionServiceTestWithInstall::GetErrors() {
   const std::vector<base::string16>* errors =
@@ -201,7 +195,7 @@
     InstallState install_state,
     const std::string& expected_old_name) {
   std::vector<base::string16> errors = GetErrors();
-  const Extension* extension = NULL;
+  const Extension* extension = nullptr;
   if (install_state != INSTALL_FAILED) {
     if (install_state == INSTALL_NEW)
       ++expected_extensions_count_;
@@ -239,7 +233,7 @@
     EXPECT_EQ(1u, errors.size()) << path.value();
   }
 
-  installed_ = NULL;
+  installed_ = nullptr;
   was_update_ = false;
   old_name_ = "";
   loaded_.clear();
@@ -278,7 +272,7 @@
       previous_enabled_extension_count +
       registry()->disabled_extensions().size();
 
-  extensions::CrxInstaller* installer = NULL;
+  extensions::CrxInstaller* installer = nullptr;
   content::WindowedNotificationObserver observer(
       extensions::NOTIFICATION_CRX_INSTALLER_DONE,
       base::Bind(&IsCrxInstallerDone, &installer));
@@ -341,10 +335,8 @@
         service(), id, extensions::UNINSTALL_REASON_FOR_TESTING));
   } else {
     EXPECT_TRUE(service()->UninstallExtension(
-        id,
-        extensions::UNINSTALL_REASON_FOR_TESTING,
-        base::Bind(&base::DoNothing),
-        NULL));
+        id, extensions::UNINSTALL_REASON_FOR_TESTING,
+        base::Bind(&base::DoNothing), nullptr));
   }
   --expected_extensions_count_;
 
@@ -379,49 +371,39 @@
   service()->TrackTerminatedExtensionForTest(extension);
 }
 
-void ExtensionServiceTestWithInstall::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  switch (type) {
-    case extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED: {
-      const Extension* extension =
-          content::Details<const Extension>(details).ptr();
-      loaded_.push_back(make_scoped_refptr(extension));
-      // The tests rely on the errors being in a certain order, which can vary
-      // depending on how filesystem iteration works.
-      std::stable_sort(loaded_.begin(), loaded_.end(), ExtensionsOrder());
-      break;
-    }
+void ExtensionServiceTestWithInstall::OnExtensionLoaded(
+    content::BrowserContext* browser_context,
+    const Extension* extension) {
+  loaded_.push_back(make_scoped_refptr(extension));
+  // The tests rely on the errors being in a certain order, which can vary
+  // depending on how filesystem iteration works.
+  std::stable_sort(loaded_.begin(), loaded_.end(), ExtensionsOrder());
+}
 
-    case extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED: {
-      UnloadedExtensionInfo* unloaded_info =
-          content::Details<UnloadedExtensionInfo>(details).ptr();
-      const Extension* e = unloaded_info->extension;
-      unloaded_id_ = e->id();
-      unloaded_reason_ = unloaded_info->reason;
-      extensions::ExtensionList::iterator i =
-          std::find(loaded_.begin(), loaded_.end(), e);
+void ExtensionServiceTestWithInstall::OnExtensionUnloaded(
+    content::BrowserContext* browser_context,
+    const Extension* extension,
+    UnloadedExtensionInfo::Reason reason) {
+  unloaded_id_ = extension->id();
+  unloaded_reason_ = reason;
+  extensions::ExtensionList::iterator i =
+      std::find(loaded_.begin(), loaded_.end(), extension);
       // TODO(erikkay) fix so this can be an assert.  Right now the tests
       // are manually calling clear() on loaded_, so this isn't doable.
       if (i == loaded_.end())
         return;
       loaded_.erase(i);
-      break;
-    }
-    case extensions::NOTIFICATION_EXTENSION_WILL_BE_INSTALLED_DEPRECATED: {
-      const extensions::InstalledExtensionInfo* installed_info =
-          content::Details<const extensions::InstalledExtensionInfo>(details)
-              .ptr();
-      installed_ = installed_info->extension;
-      was_update_ = installed_info->is_update;
-      old_name_ = installed_info->old_name;
-      break;
-    }
+}
 
-    default:
-      DCHECK(false);
-  }
+void ExtensionServiceTestWithInstall::OnExtensionWillBeInstalled(
+    content::BrowserContext* browser_context,
+    const Extension* extension,
+    bool is_update,
+    bool from_ephemeral,
+    const std::string& old_name) {
+  installed_ = extension;
+  was_update_ = is_update;
+  old_name_ = old_name;
 }
 
 // Create a CrxInstaller and install the CRX file.
diff --git a/chrome/browser/extensions/extension_service_test_with_install.h b/chrome/browser/extensions/extension_service_test_with_install.h
index cfafca28..b9bb169 100644
--- a/chrome/browser/extensions/extension_service_test_with_install.h
+++ b/chrome/browser/extensions/extension_service_test_with_install.h
@@ -7,25 +7,33 @@
 
 #include <string>
 
-#include "base/files/file_path.h"
 #include "base/macros.h"
+#include "base/scoped_observer.h"
 #include "chrome/browser/extensions/extension_service_test_base.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
+#include "extensions/browser/extension_registry_observer.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/feature_switch.h"
 
+namespace base {
+class FilePath;
+}
+
 namespace extensions {
 
+class ExtensionRegistry;
+
 // An enhancement of ExtensionServiceTestBase that provides helpers to install,
 // update, and uninstall extensions.
 class ExtensionServiceTestWithInstall : public ExtensionServiceTestBase,
-                                        public content::NotificationObserver {
+                                        public ExtensionRegistryObserver {
  public:
   ExtensionServiceTestWithInstall();
   ~ExtensionServiceTestWithInstall() override;
 
  protected:
+  void InitializeExtensionService(
+      const ExtensionServiceInitParams& params) override;
+
   static std::vector<base::string16> GetErrors();
 
   void PackCRX(const base::FilePath& dir_path,
@@ -105,6 +113,18 @@
 
   void TerminateExtension(const std::string& id);
 
+  // ExtensionRegistryObserver:
+  void OnExtensionLoaded(content::BrowserContext* browser_context,
+                         const Extension* extension) override;
+  void OnExtensionUnloaded(content::BrowserContext* browser_context,
+                           const Extension* extension,
+                           UnloadedExtensionInfo::Reason reason) override;
+  void OnExtensionWillBeInstalled(content::BrowserContext* browser_context,
+                                  const Extension* extension,
+                                  bool is_update,
+                                  bool from_ephemeral,
+                                  const std::string& old_name) override;
+
   // TODO(treib,devlin): Make these private and add accessors as needed.
   extensions::ExtensionList loaded_;
   const Extension* installed_;
@@ -114,17 +134,15 @@
   UnloadedExtensionInfo::Reason unloaded_reason_;
 
  private:
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
-
   void InstallCRXInternal(const base::FilePath& crx_path, int creation_flags);
 
-  content::NotificationRegistrar registrar_;
   size_t expected_extensions_count_;
 
   FeatureSwitch::ScopedOverride override_external_install_prompt_;
 
+  ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver>
+      registry_observer_;
+
   DISALLOW_COPY_AND_ASSIGN(ExtensionServiceTestWithInstall);
 };
 
diff --git a/chrome/browser/local_discovery/privet_traffic_detector.cc b/chrome/browser/local_discovery/privet_traffic_detector.cc
index 2b76f01..e02f64c 100644
--- a/chrome/browser/local_discovery/privet_traffic_detector.cc
+++ b/chrome/browser/local_discovery/privet_traffic_detector.cc
@@ -9,7 +9,6 @@
 #include "base/single_thread_task_runner.h"
 #include "base/sys_byteorder.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/base/network_interfaces.h"
 #include "net/dns/dns_protocol.h"
 #include "net/dns/dns_response.h"
diff --git a/chrome/browser/password_manager/password_store_mac.cc b/chrome/browser/password_manager/password_store_mac.cc
index 45daca3e..1ad1dd6 100644
--- a/chrome/browser/password_manager/password_store_mac.cc
+++ b/chrome/browser/password_manager/password_store_mac.cc
@@ -1257,12 +1257,12 @@
     login_metadata_db_->stats_table().RemoveRow(origin_domain);
 }
 
-scoped_ptr<password_manager::InteractionsStats>
+ScopedVector<password_manager::InteractionsStats>
 PasswordStoreMac::GetSiteStatsImpl(const GURL& origin_domain) {
   DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
   return login_metadata_db_
-             ? login_metadata_db_->stats_table().GetRow(origin_domain)
-             : scoped_ptr<password_manager::InteractionsStats>();
+             ? login_metadata_db_->stats_table().GetRows(origin_domain)
+             : ScopedVector<password_manager::InteractionsStats>();
 }
 
 bool PasswordStoreMac::AddToKeychainIfNecessary(const PasswordForm& form) {
diff --git a/chrome/browser/password_manager/password_store_mac.h b/chrome/browser/password_manager/password_store_mac.h
index c8571466..1d2f4bf 100644
--- a/chrome/browser/password_manager/password_store_mac.h
+++ b/chrome/browser/password_manager/password_store_mac.h
@@ -93,7 +93,7 @@
   void AddSiteStatsImpl(
       const password_manager::InteractionsStats& stats) override;
   void RemoveSiteStatsImpl(const GURL& origin_domain) override;
-  scoped_ptr<password_manager::InteractionsStats> GetSiteStatsImpl(
+  ScopedVector<password_manager::InteractionsStats> GetSiteStatsImpl(
       const GURL& origin_domain) override;
 
   // Adds the given form to the Keychain if it's something we want to store
diff --git a/chrome/browser/password_manager/password_store_proxy_mac.cc b/chrome/browser/password_manager/password_store_proxy_mac.cc
index 3ed1a3f..ad34546 100644
--- a/chrome/browser/password_manager/password_store_proxy_mac.cc
+++ b/chrome/browser/password_manager/password_store_proxy_mac.cc
@@ -203,7 +203,7 @@
   GetBackend()->RemoveSiteStatsImpl(origin_domain);
 }
 
-scoped_ptr<password_manager::InteractionsStats>
+ScopedVector<password_manager::InteractionsStats>
 PasswordStoreProxyMac::GetSiteStatsImpl(const GURL& origin_domain) {
   return GetBackend()->GetSiteStatsImpl(origin_domain);
 }
diff --git a/chrome/browser/password_manager/password_store_proxy_mac.h b/chrome/browser/password_manager/password_store_proxy_mac.h
index 38bf539..2556af5 100644
--- a/chrome/browser/password_manager/password_store_proxy_mac.h
+++ b/chrome/browser/password_manager/password_store_proxy_mac.h
@@ -90,7 +90,7 @@
   void AddSiteStatsImpl(
       const password_manager::InteractionsStats& stats) override;
   void RemoveSiteStatsImpl(const GURL& origin_domain) override;
-  scoped_ptr<password_manager::InteractionsStats> GetSiteStatsImpl(
+  ScopedVector<password_manager::InteractionsStats> GetSiteStatsImpl(
       const GURL& origin_domain) override;
 
   scoped_refptr<PasswordStoreMac> password_store_mac_;
diff --git a/chrome/browser/resources/chromeos/chromevox/chromevox.gni b/chrome/browser/resources/chromeos/chromevox/chromevox.gni
index fa68a6af..6a36df8d 100644
--- a/chrome/browser/resources/chromeos/chromevox/chromevox.gni
+++ b/chrome/browser/resources/chromeos/chromevox/chromevox.gni
@@ -125,10 +125,13 @@
   "cvox2/background/automation_predicate.js",
   "cvox2/background/automation_util.js",
   "cvox2/background/background.js",
+  "cvox2/background/base_automation_handler.js",
   "cvox2/background/cursors.js",
+  "cvox2/background/desktop_automation_handler.js",
   "cvox2/background/earcon_engine.js",
   "cvox2/background/next_earcons.js",
   "cvox2/background/output.js",
+  "cvox2/background/tabs_automation_handler.js",
   "extensions/searchvox/abstract_result.js",
   "extensions/searchvox/constants.js",
   "extensions/searchvox/context_menu.js",
diff --git a/chrome/browser/resources/chromeos/chromevox/chromevox/background/tabs_api_handler.js b/chrome/browser/resources/chromeos/chromevox/chromevox/background/tabs_api_handler.js
index b776438..6fbbedc4 100644
--- a/chrome/browser/resources/chromeos/chromevox/chromevox/background/tabs_api_handler.js
+++ b/chrome/browser/resources/chromeos/chromevox/chromevox/background/tabs_api_handler.js
@@ -9,6 +9,7 @@
 
 goog.provide('cvox.TabsApiHandler');
 
+goog.require('TabsAutomationHandler');
 goog.require('cvox.AbstractEarcons');
 goog.require('cvox.AbstractTts');
 goog.require('cvox.BrailleInterface');
@@ -52,6 +53,7 @@
     cvox.ChromeVox.braille.write(
         cvox.NavBraille.fromText(this.msg_('chrome_tab_created')));
     cvox.ChromeVox.earcons.playEarcon(cvox.Earcon.OBJECT_OPEN);
+    this.refreshAutomationHandler_(tab.id);
   },
 
   /**
@@ -109,6 +111,7 @@
         this.lastActiveTabLoaded_ = true;
         cvox.ChromeVox.earcons.playEarcon(cvox.Earcon.PAGE_FINISH_LOADING);
       }
+      this.refreshAutomationHandler_(tabId);
     }.bind(this));
   },
 
@@ -135,7 +138,25 @@
         cvox.ChromeVox.braille.write(
             cvox.NavBraille.fromText(this.msg_(msgId, [title])));
         cvox.ChromeVox.earcons.playEarcon(cvox.Earcon.OBJECT_SELECT);
+        this.refreshAutomationHandler_(tab.id);
       }.bind(this));
     }.bind(this));
+  },
+
+  /**
+   * Installs a new automation handler for the given tab.
+   * @param {number} tabId
+   * @private
+   */
+  refreshAutomationHandler_: function(tabId) {
+    if (!cvox.ChromeVox.isMac)
+      return;
+
+    chrome.automation.getTree(tabId, function(node) {
+      if (this.handler_)
+        this.handler_.unregister();
+
+      this.handler_ = new TabsAutomationHandler(node);
+    }.bind(this));
   }
 };
diff --git a/chrome/browser/resources/chromeos/chromevox/common/chrome_extension_externs.js b/chrome/browser/resources/chromeos/chromevox/common/chrome_extension_externs.js
index 6ba315b3..eaa2d1b 100644
--- a/chrome/browser/resources/chromeos/chromevox/common/chrome_extension_externs.js
+++ b/chrome/browser/resources/chromeos/chromevox/common/chrome_extension_externs.js
@@ -289,7 +289,7 @@
 /**
  * Get the automation tree for the whole desktop which consists of all on screen
  * views. Note this API is currently only supported on Chrome OS.
- * @param {function(chrome.automation.AutomationNode):void} callback
+ * @param {function(!chrome.automation.AutomationNode):void} callback
  *     Called when the <code>AutomationNode</code> for the page is available.
  */
 chrome.automation.getDesktop = function(callback) {};
@@ -445,7 +445,7 @@
 
 /**
  * @param {chrome.automation.EventType} eventType
- * @param {function(chrome.automation.AutomationNode) : void} callback
+ * @param {function(!chrome.automation.AutomationEvent) : void} callback
  * @param {boolean} capture
  */
 chrome.automation.AutomationNode.prototype.removeEventListener =
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_util.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_util.js
index 4c71aba..e907c0c 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_util.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_util.js
@@ -270,7 +270,7 @@
     case RoleType.toolbar:
       return node.root.role == RoleType.desktop;
     case RoleType.rootWebArea:
-      return node.parent.root.role == RoleType.desktop;
+      return !!(node.parent && node.parent.root.role == RoleType.desktop);
     default:
       return false;
   }
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
index 1a68453..abe9f8a 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
@@ -8,6 +8,7 @@
  */
 
 goog.provide('Background');
+goog.provide('ChromeVoxMode');
 goog.provide('global');
 
 goog.require('AutomationPredicate');
@@ -33,7 +34,7 @@
  * All possible modes ChromeVox can run.
  * @enum {string}
  */
-var ChromeVoxMode = {
+ChromeVoxMode = {
   CLASSIC: 'classic',
   COMPAT: 'compat',
   NEXT: 'next',
@@ -80,28 +81,6 @@
       this[func] = this[func].bind(this);
   }
 
-  /**
-   * Maps an automation event to its listener.
-   * @type {!Object<EventType, function(Object) : void>}
-   */
-  this.listeners_ = {
-    alert: this.onAlert,
-    focus: this.onFocus,
-    hover: this.onEventDefault,
-    loadComplete: this.onLoadComplete,
-    menuStart: this.onEventDefault,
-    menuEnd: this.onEventDefault,
-    textChanged: this.onTextOrTextSelectionChanged,
-    textSelectionChanged: this.onTextOrTextSelectionChanged,
-    valueChanged: this.onValueChanged
-  };
-
-  /**
-   * The object that speaks changes to an editable text field.
-   * @type {?cvox.ChromeVoxEditableTextBase}
-   */
-  this.editableTextHandler_ = null;
-
   chrome.automation.getDesktop(this.onGotDesktop);
 
   // Handle messages directed to the Next background page.
@@ -156,29 +135,28 @@
     this.setChromeVoxMode(ChromeVoxMode.FORCE_NEXT);
   },
 
+  get mode() {
+    return this.mode_;
+  },
+
+  get currentRange() {
+    return this.currentRange_;
+  },
+
+  set currentRange(value) {
+    if (!value)
+      return;
+
+    this.currentRange_ = value;
+  },
+
   /**
    * Handles all setup once a new automation tree appears.
    * @param {chrome.automation.AutomationNode} desktop
    */
   onGotDesktop: function(desktop) {
-    // Register all automation event listeners.
-    for (var eventType in this.listeners_)
-      desktop.addEventListener(eventType, this.listeners_[eventType], true);
-
     // Register a tree change observer.
     chrome.automation.addTreeChangeObserver(this.onTreeChange);
-
-    // The focused state gets set on the containing webView node.
-    var webView = desktop.find({role: RoleType.webView,
-                                state: {focused: true}});
-    if (webView) {
-      var root = webView.find({role: RoleType.rootWebArea});
-      if (root) {
-        this.onLoadComplete(
-            {target: root,
-             type: chrome.automation.EventType.loadComplete});
-      }
-    }
   },
 
   /**
@@ -475,199 +453,21 @@
   },
 
   /**
-   * Provides all feedback once ChromeVox's focus changes.
-   * @param {Object} evt
+   * Refreshes the current mode based on a url.
+   * @param {string} url
    */
-  onEventDefault: function(evt) {
-    var node = evt.target;
-
-    if (!node)
-      return;
-
-    var prevRange = this.currentRange_;
-
-    this.currentRange_ = cursors.Range.fromNode(node);
-
-    // Check to see if we've crossed roots. Continue if we've crossed roots or
-    // are not within web content.
-    if (node.root.role == 'desktop' ||
-        !prevRange ||
-        prevRange.start.node.root != node.root)
-      this.setupChromeVoxVariants_(node.root.docUrl || '');
-
-    // Don't process nodes inside of web content if ChromeVox Next is inactive.
-    if (node.root.role != RoleType.desktop &&
-        this.mode_ === ChromeVoxMode.CLASSIC) {
-      chrome.accessibilityPrivate.setFocusRing([]);
-      return;
+  refreshMode: function(url) {
+    var mode = this.mode_;
+    if (mode != ChromeVoxMode.FORCE_NEXT) {
+      if (this.isWhitelistedForNext_(url))
+        mode = ChromeVoxMode.NEXT;
+      else if (this.isBlacklistedForClassic_(url))
+        mode = ChromeVoxMode.COMPAT;
+      else
+        mode = ChromeVoxMode.CLASSIC;
     }
 
-    // Don't output if focused node hasn't changed.
-    if (prevRange &&
-        evt.type == 'focus' &&
-        this.currentRange_.equals(prevRange))
-      return;
-
-    new Output().withSpeechAndBraille(
-            this.currentRange_, prevRange, evt.type)
-        .go();
-  },
-
-  /**
-   * Makes an announcement without changing focus.
-   * @param {Object} evt
-   */
-  onAlert: function(evt) {
-    var node = evt.target;
-    if (!node)
-      return;
-
-    // Don't process nodes inside of web content if ChromeVox Next is inactive.
-    if (node.root.role != RoleType.desktop &&
-        this.mode_ === ChromeVoxMode.CLASSIC) {
-      return;
-    }
-
-    var range = cursors.Range.fromNode(node);
-
-    new Output().withSpeechAndBraille(range, null, evt.type).go();
-  },
-
-  /**
-   * Provides all feedback once a focus event fires.
-   * @param {Object} evt
-   */
-  onFocus: function(evt) {
-    // Invalidate any previous editable text handler state.
-    this.editableTextHandler_ = null;
-
-    var node = evt.target;
-
-    // Discard focus events on embeddedObject nodes.
-    if (node.role == RoleType.embeddedObject)
-      return;
-
-    // It almost never makes sense to place focus directly on a rootWebArea.
-    if (node.role == RoleType.rootWebArea) {
-      // Discard focus events for root web areas when focus was previously
-      // placed on a descendant.
-      if (this.currentRange_.start.node.root == node)
-        return;
-
-      // Discard focused root nodes without focused state set.
-      if (!node.state.focused)
-        return;
-
-      // Try to find a focusable descendant.
-      node = node.find({state: {focused: true}}) || node;
-    }
-
-    if (evt.target.state.editable)
-      this.createEditableTextHandlerIfNeeded_(evt.target);
-
-    this.onEventDefault({target: node, type: 'focus'});
-  },
-
-  /**
-   * Provides all feedback once a load complete event fires.
-   * @param {Object} evt
-   */
-  onLoadComplete: function(evt) {
-    this.setupChromeVoxVariants_(evt.target.docUrl);
-
-    // Don't process nodes inside of web content if ChromeVox Next is inactive.
-    if (evt.target.root.role != RoleType.desktop &&
-        this.mode_ === ChromeVoxMode.CLASSIC)
-      return;
-
-    // If initial focus was already placed on this page (e.g. if a user starts
-    // tabbing before load complete), then don't move ChromeVox's position on
-    // the page.
-    if (this.currentRange_ &&
-        this.currentRange_.start.node.role != RoleType.rootWebArea &&
-        this.currentRange_.start.node.root.docUrl == evt.target.docUrl)
-      return;
-
-    var root = evt.target;
-    var webView = root;
-    while (webView && webView.role != RoleType.webView)
-      webView = webView.parent;
-
-    if (!webView || !webView.state.focused)
-      return;
-
-    var node = AutomationUtil.findNodePost(root,
-        Dir.FORWARD,
-        AutomationPredicate.leaf);
-
-    if (node)
-      this.currentRange_ = cursors.Range.fromNode(node);
-
-    if (this.currentRange_)
-      new Output().withSpeechAndBraille(
-              this.currentRange_, null, evt.type)
-          .go();
-  },
-
-  /**
-   * Provides all feedback once a text selection change event fires.
-   * @param {Object} evt
-   */
-  onTextOrTextSelectionChanged: function(evt) {
-    if (!evt.target.state.editable)
-      return;
-
-    // Don't process nodes inside of web content if ChromeVox Next is inactive.
-    if (evt.target.root.role != RoleType.desktop &&
-        this.mode_ === ChromeVoxMode.CLASSIC)
-      return;
-
-    if (!evt.target.state.focused)
-      return;
-
-    if (evt.target.role != RoleType.textField)
-      return;
-
-    if (!this.currentRange_) {
-      this.onEventDefault(evt);
-      this.currentRange_ = cursors.Range.fromNode(evt.target);
-    }
-
-    this.createEditableTextHandlerIfNeeded_(evt.target);
-
-    var textChangeEvent = new cvox.TextChangeEvent(
-        evt.target.value,
-        evt.target.textSelStart,
-        evt.target.textSelEnd,
-        true);  // triggered by user
-
-    this.editableTextHandler_.changed(textChangeEvent);
-
-    new Output().withBraille(
-            this.currentRange_, null, evt.type)
-        .go();
-  },
-
-  /**
-   * Provides all feedback once a value changed event fires.
-   * @param {Object} evt
-   */
-  onValueChanged: function(evt) {
-    // Don't process nodes inside of web content if ChromeVox Next is inactive.
-    if (evt.target.root.role != RoleType.desktop &&
-        this.mode_ === ChromeVoxMode.CLASSIC)
-      return;
-
-    if (!evt.target.state.focused)
-      return;
-
-    // Value change events fire on web text fields and text areas when pressing
-    // enter; suppress them.
-    if (!this.currentRange_ ||
-        evt.target.role != RoleType.textField) {
-      this.onEventDefault(evt);
-      this.currentRange_ = cursors.Range.fromNode(evt.target);
-    }
+    this.setChromeVoxMode(mode);
   },
 
   /**
@@ -745,25 +545,6 @@
   },
 
   /**
-   * Setup ChromeVox variants.
-   * @param {string} url
-   * @private
-   */
-  setupChromeVoxVariants_: function(url) {
-    var mode = this.mode_;
-    if (mode != ChromeVoxMode.FORCE_NEXT) {
-      if (this.isWhitelistedForNext_(url))
-        mode = ChromeVoxMode.NEXT;
-      else if (this.isBlacklistedForClassic_(url))
-        mode = ChromeVoxMode.COMPAT;
-      else
-        mode = ChromeVoxMode.CLASSIC;
-    }
-
-    this.setChromeVoxMode(mode);
-  },
-
-  /**
    * Disables classic ChromeVox in current web content.
    */
   disableClassicChromeVox_: function() {
@@ -785,6 +566,16 @@
     else
       cvox.ChromeVoxKbHandler.handlerKeyMap = cvox.KeyMap.fromNext();
 
+    if (mode == ChromeVoxMode.CLASSIC) {
+      if (chrome.commands &&
+          chrome.commands.onCommand.hasListener(this.onGotCommand))
+        chrome.commands.onCommand.removeListener(this.onGotCommand);
+    } else {
+      if (chrome.commands &&
+          !chrome.commands.onCommand.hasListener(this.onGotCommand))
+        chrome.commands.onCommand.addListener(this.onGotCommand);
+    }
+
     chrome.tabs.query({active: true}, function(tabs) {
       if (mode === ChromeVoxMode.CLASSIC) {
         // Generally, we don't want to inject classic content scripts as it is
@@ -833,30 +624,6 @@
       var start = text.getSpanStart(selectionSpan);
       actionNode.setSelection(position - start, position - start);
     }
-  },
-
-  /**
-   * Create an editable text handler for the given node if needed.
-   * @param {Object} node
-   */
-  createEditableTextHandlerIfNeeded_: function(node) {
-    if (!this.editableTextHandler_ || node != this.currentRange_.start.node) {
-      var start = node.textSelStart;
-      var end = node.textSelEnd;
-      if (start > end) {
-        var tempOffset = end;
-        end = start;
-        start = tempOffset;
-      }
-
-      this.editableTextHandler_ =
-          new cvox.ChromeVoxEditableTextBase(
-              node.value,
-              start,
-              end,
-              node.state.protected,
-              cvox.ChromeVox.tts);
-    }
   }
 };
 
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
index ae084c8..27bb3af 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
@@ -378,11 +378,12 @@
     */},
     function(rootNode) {
       var assertExists = this.newCallback(function (evt) {
-        assertNotNullNorUndefined(global.backgroundObj.editableTextHandler_);
+        assertNotNullNorUndefined(
+            global.desktopAutomationHandler.editableTextHandler_);
         evt.stopPropagation();
       });
       var assertDoesntExist = this.newCallback(function (evt) {
-        assertTrue(!global.backgroundObj.editableTextHandler_);
+        assertTrue(!global.desktopAutomationHandler.editableTextHandler_);
         evt.stopPropagation();
       });
 
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/base_automation_handler.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/base_automation_handler.js
new file mode 100644
index 0000000..7888428
--- /dev/null
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/base_automation_handler.js
@@ -0,0 +1,140 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview Basic facillities to handle events from a single automation
+ * node.
+ */
+
+goog.provide('BaseAutomationHandler');
+
+goog.scope(function() {
+var AutomationEvent = chrome.automation.AutomationEvent;
+var AutomationNode = chrome.automation.AutomationNode;
+var EventType = chrome.automation.EventType;
+
+/**
+ * @param {!AutomationNode} node
+ * @constructor
+ */
+BaseAutomationHandler = function(node) {
+  /**
+   * @type {!AutomationNode}
+   */
+  this.node_ = node;
+
+  /**
+   * Maps an automation event to its listener.
+   * @type {!Object<EventType, function(Object) : void>}
+   */
+  this.listenerMap_ = {
+    alert: this.onAlert,
+    focus: this.onFocus,
+    hover: this.onEventDefault,
+    loadComplete: this.onLoadComplete,
+    menuStart: this.onEventDefault,
+    menuEnd: this.onEventDefault,
+    textChanged: this.onTextOrTextSelectionChanged,
+    textSelectionChanged: this.onTextOrTextSelectionChanged,
+    valueChanged: this.onValueChanged
+  };
+
+  /** @type {boolean} @private */
+  this.isRegistered_ = false;
+
+  /** @type {!Object<string, function(AutomationEvent): void>} @private */
+  this.listeners_ = {};
+
+  this.register_();
+};
+
+BaseAutomationHandler.prototype = {
+  /**
+   * Registers event listeners. Can be called repeatedly without duplicate
+   * listeners.
+   * @private
+   */
+  register_: function() {
+    for (var eventType in this.listenerMap_) {
+      var listener =
+          this.makeListener_(this.listenerMap_[eventType].bind(this));
+      this.node_.addEventListener(eventType, listener, true);
+      this.listeners_[eventType] = listener;
+    }
+
+    this.isRegistered_ = true;
+  },
+
+  /**
+   * Unregisters listeners.
+   */
+  unregister: function() {
+    if (!this.isRegistered_)
+      throw new Error('Not registered on node ' + this.node_.toString());
+
+    for (var eventType in this.listenerMap_) {
+      this.node_.removeEventListener(
+          eventType, this.listeners_[eventType], true);
+    }
+
+    this.isRegistered_ = false;
+  },
+
+  /**
+   * @return {!function(AutomationEvent): void}
+   * @private
+   */
+  makeListener_: function(callback) {
+    return function(evt) {
+      if (this.willHandleEvent_(evt))
+        return;
+      callback(evt);
+      this.didHandleEvent_(evt);
+    }.bind(this);
+  },
+
+  /**
+   * Called before the event |evt| is handled.
+   * @return {boolean} True to skip processing this event.
+   * @protected
+   */
+  willHandleEvent_: function(evt) {
+    return false;
+  },
+
+  /**
+    * Called after the event |evt| is handled.
+   * @protected
+   */
+  didHandleEvent_: function(evt) {
+  },
+
+  /**
+   * @param {Object} evt
+   */
+  onAlert: function(evt) {},
+
+  /**
+   * @param {Object} evt
+   */
+  onFocus: function(evt) {},
+
+  /**
+   * @param {Object} evt
+   */
+  onLoadComplete: function(evt) {},
+  onEventDefault: function(evt) {},
+
+  /**
+   * @param {Object} evt
+   */
+  onTextOrTextSelectionChanged: function(evt) {},
+
+  /**
+   * @param {Object} evt
+   */
+  onValueChanged: function(evt) {}
+};
+
+});  // goog.scope
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/desktop_automation_handler.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/desktop_automation_handler.js
new file mode 100644
index 0000000..0cb5812
--- /dev/null
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/desktop_automation_handler.js
@@ -0,0 +1,287 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview Handles automation from a desktop automation node.
+ */
+
+goog.provide('DesktopAutomationHandler');
+
+goog.require('Background');
+goog.require('BaseAutomationHandler');
+
+goog.scope(function() {
+var AutomationEvent = chrome.automation.AutomationEvent;
+var AutomationNode = chrome.automation.AutomationNode;
+var Dir = AutomationUtil.Dir;
+var RoleType = chrome.automation.RoleType;
+
+/**
+ * @param {!AutomationNode} node
+ * @constructor
+ * @extends {BaseAutomationHandler}
+ */
+DesktopAutomationHandler = function(node) {
+  BaseAutomationHandler.call(this, node);
+
+  /**
+   * The object that speaks changes to an editable text field.
+   * @type {?cvox.ChromeVoxEditableTextBase}
+   */
+  this.editableTextHandler_ = null;
+
+  // The focused state gets set on the containing webView node.
+  var webView = node.find({role: RoleType.webView, state: {focused: true}});
+  if (webView) {
+    var root = webView.find({role: RoleType.rootWebArea});
+    if (root) {
+      this.onLoadComplete(
+          {target: root,
+           type: chrome.automation.EventType.loadComplete});
+    }
+  }
+};
+
+DesktopAutomationHandler.prototype = {
+  __proto__: BaseAutomationHandler.prototype,
+
+  /**
+   * Provides all feedback once ChromeVox's focus changes.
+   * @param {Object} evt
+   */
+  onEventDefault: function(evt) {
+    var node = evt.target;
+
+    if (!node)
+      return;
+
+    var prevRange = global.backgroundObj.currentRange;
+
+    global.backgroundObj.currentRange = cursors.Range.fromNode(node);
+
+    // Check to see if we've crossed roots. Continue if we've crossed roots or
+    // are not within web content.
+    if (node.root.role == 'desktop' ||
+        !prevRange ||
+        prevRange.start.node.root != node.root)
+      global.backgroundObj.refreshMode(node.root.docUrl || '');
+
+    // Don't process nodes inside of web content if ChromeVox Next is inactive.
+    if (node.root.role != RoleType.desktop &&
+        global.backgroundObj.mode === ChromeVoxMode.CLASSIC) {
+      chrome.accessibilityPrivate.setFocusRing([]);
+      return;
+    }
+
+    // Don't output if focused node hasn't changed.
+    if (prevRange &&
+        evt.type == 'focus' &&
+        global.backgroundObj.currentRange.equals(prevRange))
+      return;
+
+    new Output().withSpeechAndBraille(
+            global.backgroundObj.currentRange, prevRange, evt.type)
+        .go();
+  },
+
+  /**
+   * Makes an announcement without changing focus.
+   * @param {Object} evt
+   */
+  onAlert: function(evt) {
+    var node = evt.target;
+    if (!node)
+      return;
+
+    // Don't process nodes inside of web content if ChromeVox Next is inactive.
+    if (node.root.role != RoleType.desktop &&
+        global.backgroundObj.mode === ChromeVoxMode.CLASSIC) {
+      return;
+    }
+
+    var range = cursors.Range.fromNode(node);
+
+    new Output().withSpeechAndBraille(range, null, evt.type).go();
+  },
+
+  /**
+   * Provides all feedback once a focus event fires.
+   * @param {Object} evt
+   */
+  onFocus: function(evt) {
+    // Invalidate any previous editable text handler state.
+    this.editableTextHandler_ = null;
+
+    var node = evt.target;
+
+    // Discard focus events on embeddedObject nodes.
+    if (node.role == RoleType.embeddedObject)
+      return;
+
+    // It almost never makes sense to place focus directly on a rootWebArea.
+    if (node.role == RoleType.rootWebArea) {
+      // Discard focus events for root web areas when focus was previously
+      // placed on a descendant.
+      if (global.backgroundObj.currentRange.start.node.root == node)
+        return;
+
+      // Discard focused root nodes without focused state set.
+      if (!node.state.focused)
+        return;
+
+      // Try to find a focusable descendant.
+      node = node.find({state: {focused: true}}) || node;
+    }
+
+    if (evt.target.state.editable)
+      this.createEditableTextHandlerIfNeeded_(evt.target);
+
+    this.onEventDefault({target: node, type: 'focus'});
+  },
+
+  /**
+   * Provides all feedback once a load complete event fires.
+   * @param {Object} evt
+   */
+  onLoadComplete: function(evt) {
+    global.backgroundObj.refreshMode(evt.target.docUrl);
+
+    // Don't process nodes inside of web content if ChromeVox Next is inactive.
+    if (evt.target.root.role != RoleType.desktop &&
+        global.backgroundObj.mode === ChromeVoxMode.CLASSIC)
+      return;
+
+    // If initial focus was already placed on this page (e.g. if a user starts
+    // tabbing before load complete), then don't move ChromeVox's position on
+    // the page.
+    if (global.backgroundObj.currentRange &&
+        global.backgroundObj.currentRange.start.node.role !=
+            RoleType.rootWebArea &&
+        global.backgroundObj.currentRange.start.node.root.docUrl ==
+            evt.target.docUrl)
+      return;
+
+    var root = evt.target;
+    var webView = root;
+    while (webView && webView.role != RoleType.webView)
+      webView = webView.parent;
+
+    if (!webView || !webView.state.focused)
+      return;
+
+    var node = AutomationUtil.findNodePost(root,
+        Dir.FORWARD,
+        AutomationPredicate.leaf);
+
+    if (node)
+      global.backgroundObj.currentRange = cursors.Range.fromNode(node);
+
+    if (global.backgroundObj.currentRange)
+      new Output().withSpeechAndBraille(
+              global.backgroundObj.currentRange, null, evt.type)
+          .go();
+  },
+
+  /**
+   * Provides all feedback once a text selection change event fires.
+   * @param {Object} evt
+   */
+  onTextOrTextSelectionChanged: function(evt) {
+    if (!evt.target.state.editable)
+      return;
+
+    // Don't process nodes inside of web content if ChromeVox Next is inactive.
+    if (evt.target.root.role != RoleType.desktop &&
+        global.backgroundObj.mode === ChromeVoxMode.CLASSIC)
+      return;
+
+    if (!evt.target.state.focused)
+      return;
+
+    if (evt.target.role != RoleType.textField)
+      return;
+
+    if (!global.backgroundObj.currentRange) {
+      this.onEventDefault(evt);
+      global.backgroundObj.currentRange = cursors.Range.fromNode(evt.target);
+    }
+
+    this.createEditableTextHandlerIfNeeded_(evt.target);
+
+    var textChangeEvent = new cvox.TextChangeEvent(
+        evt.target.value,
+        evt.target.textSelStart,
+        evt.target.textSelEnd,
+        true);  // triggered by user
+
+    this.editableTextHandler_.changed(textChangeEvent);
+
+    new Output().withBraille(
+            global.backgroundObj.currentRange, null, evt.type)
+        .go();
+  },
+
+  /**
+   * Provides all feedback once a value changed event fires.
+   * @param {Object} evt
+   */
+  onValueChanged: function(evt) {
+    // Don't process nodes inside of web content if ChromeVox Next is inactive.
+    if (evt.target.root.role != RoleType.desktop &&
+        global.backgroundObj.mode === ChromeVoxMode.CLASSIC)
+      return;
+
+    if (!evt.target.state.focused)
+      return;
+
+    // Value change events fire on web text fields and text areas when pressing
+    // enter; suppress them.
+    if (!global.backgroundObj.currentRange ||
+        evt.target.role != RoleType.textField) {
+      this.onEventDefault(evt);
+      global.backgroundObj.currentRange = cursors.Range.fromNode(evt.target);
+    }
+  },
+
+  /**
+   * Create an editable text handler for the given node if needed.
+   * @param {Object} node
+   */
+  createEditableTextHandlerIfNeeded_: function(node) {
+    if (!this.editableTextHandler_ ||
+        node != global.backgroundObj.currentRange.start.node) {
+      var start = node.textSelStart;
+      var end = node.textSelEnd;
+      if (start > end) {
+        var tempOffset = end;
+        end = start;
+        start = tempOffset;
+      }
+
+      this.editableTextHandler_ =
+          new cvox.ChromeVoxEditableTextBase(
+              node.value,
+              start,
+              end,
+              node.state.protected,
+              cvox.ChromeVox.tts);
+    }
+  }
+};
+
+/**
+ * Initializes global state for DesktopAutomationHandler.
+ * @private
+ */
+DesktopAutomationHandler.init_ = function() {
+  if (cvox.ChromeVox.isMac)
+    return;
+  chrome.automation.getDesktop(function(desktop) {
+    global.desktopAutomationHandler = new DesktopAutomationHandler(desktop);
+  });
+};
+
+DesktopAutomationHandler.init_();
+
+});  // goog.scope
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/tabs_automation_handler.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/tabs_automation_handler.js
new file mode 100644
index 0000000..fef2f0a3
--- /dev/null
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/tabs_automation_handler.js
@@ -0,0 +1,27 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview Handles automation from a tabs automation node.
+ */
+
+goog.provide('TabsAutomationHandler');
+
+goog.require('DesktopAutomationHandler');
+
+/**
+ * @param {!chrome.automation.AutomationNode} node
+ * @constructor
+ * @extends {DesktopAutomationHandler}
+ */
+TabsAutomationHandler = function(node) {
+  DesktopAutomationHandler.call(this, node);
+};
+
+TabsAutomationHandler.prototype = {
+  /** @override */
+  didHandleEvent_: function(evt) {
+    evt.stopPropagation();
+  }
+};
diff --git a/chrome/browser/resources/chromeos/chromevox/generate_manifest.gypi b/chrome/browser/resources/chromeos/chromevox/generate_manifest.gypi
index 758a73e..7b9bdd1 100644
--- a/chrome/browser/resources/chromeos/chromevox/generate_manifest.gypi
+++ b/chrome/browser/resources/chromeos/chromevox/generate_manifest.gypi
@@ -14,14 +14,12 @@
 #
 # is_guest_manifest: 1 or 0; generates a manifest usable while in guest
 # mode.
-# is_chromevox_classic: 1 or 0; generates a manifest for ChromeVox Classic.
 # chromevox_compress_js: 1 or 0; whether the javascript is compressed.
 
 {
   'variables': {
     'generate_manifest_script_path': 'tools/generate_manifest.py',
     'is_guest_manifest%': 0,
-    'is_chromevox_classic%': 0,
   },
   'includes': [
     '../../../../../build/util/version.gypi',
@@ -42,7 +40,6 @@
         '<(generate_manifest_script_path)',
         '--is_guest_manifest=<(is_guest_manifest)',
         '--key=<(chromevox_extension_key)',
-        '--is_chromevox_classic=<(is_chromevox_classic)',
         '--is_js_compressed=<(chromevox_compress_js)',
         '--set_version=<(version_full)',
         '--output_manifest=<(output_manifest_path)',
diff --git a/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2 b/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2
index 2995377..ec3777e 100644
--- a/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2
+++ b/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2
@@ -59,242 +59,36 @@
     "desktop": true
   },
   "commands": {
-{% if is_chromevox_classic == '0' %}
     "nextElement": {
       "description": "__MSG_CHROMEVOX_NEXT_OBJECT__",
       "suggested_key": {
-        "chromeos": "Search+Right"
+        "default": "Alt+Shift+Right"
       }
     },
     "previousElement": {
       "description": "__MSG_CHROMEVOX_PREVIOUS_OBJECT__",
       "suggested_key": {
-        "chromeos": "Search+Left"
-      }
-    },
-    "nextCharacter": {
-      "description": "__MSG_CHROMEVOX_NEXT_CHARACTER__",
-      "suggested_key": {
-        "chromeos": "Search+Shift+Right"
-      }
-    },
-    "previousCharacter": {
-      "description": "__MSG_CHROMEVOX_PREVIOUS_CHARACTER__",
-      "suggested_key": {
-        "chromeos": "Search+Shift+Left"
-      }
-    },
-    "nextWord": {
-      "description": "__MSG_CHROMEVOX_NEXT_WORD__",
-      "suggested_key": {
-        "chromeos": "Search+Ctrl+Shift+Right"
-      }
-    },
-    "previousWord": {
-      "description": "__MSG_CHROMEVOX_PREVIOUS_WORD__",
-      "suggested_key": {
-        "chromeos": "Search+Ctrl+Shift+Left"
-      }
-    },
-    "nextLine": {
-      "description": "__MSG_CHROMEVOX_NEXT_LINE__",
-      "suggested_key": {
-        "chromeos": "Search+Down"
-      }
-    },
-    "previousLine": {
-      "description": "__MSG_CHROMEVOX_PREVIOUS_LINE__",
-      "suggested_key": {
-        "chromeos": "Search+Up"
-      }
-    },
-    "nextButton": {
-      "description": "__MSG_CHROMEVOX_NEXT_BUTTON__",
-      "suggested_key": {
-        "chromeos": "Search+B"
-      }
-    },
-    "previousButton": {
-      "description": "__MSG_CHROMEVOX_PREVIOUS_BUTTON__",
-      "suggested_key": {
-        "chromeos": "Search+Shift+B"
-      }
-    },
-    "nextCheckBox": {
-      "description": "__MSG_CHROMEVOX_NEXT_CHECKBOX__",
-      "suggested_key": {
-        "chromeos": "Search+X"
-      }
-    },
-    "previousCheckBox": {
-      "description": "__MSG_CHROMEVOX_PREVIOUS_CHECKBOX__",
-      "suggested_key": {
-        "chromeos": "Search+Shift+X"
-      }
-    },
-    "nextComboBox": {
-      "description": "__MSG_CHROMEVOX_NEXT_COMBO_BOX__",
-      "suggested_key": {
-        "chromeos": "Search+C"
-      }
-    },
-    "previousComboBox": {
-      "description": "__MSG_CHROMEVOX_PREVIOUS_COMBO_BOX__",
-      "suggested_key": {
-        "chromeos": "Search+Shift+C"
-      }
-    },
-    "nextEditText": {
-      "description": "__MSG_CHROMEVOX_NEXT_EDIT_TEXT__",
-      "suggested_key": {
-        "chromeos": "Search+E"
-      }
-    },
-    "previousEditText": {
-      "description": "__MSG_CHROMEVOX_PREVIOUS_EDIT_TEXT__",
-      "suggested_key": {
-        "chromeos": "Search+Shift+E"
-      }
-    },
-    "nextFormField": {
-      "description": "__MSG_CHROMEVOX_NEXT_FORM_FIELD__",
-      "suggested_key": {
-        "chromeos": "Search+F"
-      }
-    },
-    "previousFormField": {
-      "description": "__MSG_CHROMEVOX_PREVIOUS_FORM_FIELD__",
-      "suggested_key": {
-        "chromeos": "Search+Shift+F"
-      }
-    },
-    "nextHeading": {
-      "description": "__MSG_CHROMEVOX_NEXT_HEADING__",
-      "suggested_key": {
-        "chromeos": "Search+H"
-      }
-    },
-    "previousHeading": {
-      "description": "__MSG_CHROMEVOX_PREVIOUS_HEADING__",
-      "suggested_key": {
-        "chromeos": "Search+Shift+H"
-      }
-    },
-    "compatPreviousLine": {
-      "description": "__MSG_CHROMEVOX_PREVIOUS_HEADING__",
-      "suggested_key": {
-        "chromeos": "Search+Shift+Up"
-      }
-    },
-    "compatNextLine": {
-      "description": "__MSG_CHROMEVOX_PREVIOUS_HEADING__",
-      "suggested_key": {
-        "chromeos": "Search+Shift+Down"
-      }
-    },
-    "sequencePrefixPrevious": {
-      "description": "Sequence prefix",
-      "suggested_key": {
-        "chromeos": "Search+Shift+P"
-      }
-    },
-    "sequencePrefixNext": {
-      "description": "Sequence prefix",
-      "suggested_key": {
-        "chromeos": "Search+Shift+N"
-      }
-    },
-    "nextLink": {
-      "description": "__MSG_CHROMEVOX_NEXT_LINK__",
-      "suggested_key": {
-        "chromeos": "Search+L"
-      }
-    },
-    "previousLink": {
-      "description": "__MSG_CHROMEVOX_PREVIOUS_LINK__",
-      "suggested_key": {
-        "chromeos": "Search+Shift+L"
-      }
-    },
-    "nextTable": {
-      "description": "__MSG_CHROMEVOX_NEXT_TABLE__",
-      "suggested_key": {
-        "chromeos": "Search+T"
-      }
-    },
-    "previousTable": {
-      "description": "__MSG_CHROMEVOX_PREVIOUS_TABLE__",
-      "suggested_key": {
-        "chromeos": "Search+Shift+T"
-      }
-    },
-    "nextVisitedLink": {
-      "description": "__MSG_CHROMEVOX_NEXT_VISITED_LINK__",
-      "suggested_key": {
-        "chromeos": "Search+V"
-      }
-    },
-    "previousVisitedLink": {
-      "description": "__MSG_CHROMEVOX_PREVIOUS_VISITED_LINK__",
-      "suggested_key": {
-        "chromeos": "Search+Shift+V"
-      }
-    },
-    "goToBeginning": {
-      "description": "__MSG_CHROMEVOX_JUMP_TO_TOP__",
-      "suggested_key": {
-        "chromeos": "Search+Ctrl+Left"
-      }
-    },
-    "goToEnd": {
-      "description": "__MSG_CHROMEVOX_JUMP_TO_BOTTOM__",
-      "suggested_key": {
-        "chromeos": "Search+Ctrl+Right"
+        "default": "Alt+Shift+Left"
       }
     },
     "doDefault": {
       "description": "__MSG_CHROMEVOX_PERFORM_DEFAULT_ACTION__",
       "suggested_key": {
-        "chromeos": "Search+Space"
-      }
-    },
-    "compatDoDefault": {
-      "description": "__MSG_CHROMEVOX_PERFORM_DEFAULT_ACTION__",
-      "suggested_key": {
-        "chromeos": "Search+Shift+Space"
+        "default": "Alt+Shift+Space"
       }
     },
     "toggleChromeVoxVersion": {
       "description": "__MSG_CHROMEVOX_TOGGLE_CHROMEVOX__",
       "suggested_key": {
-        "chromeos": "Search+Shift+Q"
+        "default": "Alt+Shift+Q"
       }
     },
     "continuousRead": {
       "description": "__MSG_CHROMEVOX_READ_FROM_HERE__",
       "suggested_key": {
-        "chromeos": "Search+R"
-      }
-    },
-    "compatContinuousRead": {
-      "description": "__MSG_CHROMEVOX_READ_FROM_HERE__",
-      "suggested_key": {
-        "chromeos": "Search+Shift+R"
-      }
-    },
-    "sequencePrefixOpen": {
-      "description": "Sequence prefix",
-      "suggested_key": {
-        "chromeos": "Search+Shift+O"
-      }
-    },
-    "showContextMenu": {
-      "description": "__MSG_CHROMEVOX_SHOW_CONTEXT_MENU__",
-      "suggested_key": {
-        "chromeos": "Search+Ctrl+Space"
+        "default": "Alt+Shift+R"
       }
     }
-{% endif %}
   },
   "options_page": "chromevox/background/options.html",
   "default_locale": "en"
diff --git a/chrome/browser/resources/chromeos/chromevox/tools/generate_manifest.py b/chrome/browser/resources/chromeos/chromevox/tools/generate_manifest.py
index c3a2a4c..03dd0b7 100755
--- a/chrome/browser/resources/chromeos/chromevox/tools/generate_manifest.py
+++ b/chrome/browser/resources/chromeos/chromevox/tools/generate_manifest.py
@@ -54,9 +54,6 @@
       '--is_guest_manifest', default='0', action='store', metavar='NUM',
       help='Whether to generate a guest mode capable manifest')
   parser.add_option(
-      '--is_chromevox_classic', default='0', action='store', metavar='NUM',
-      help='Whether to generate a ChromeVox Classic manifest')
-  parser.add_option(
       '--is_js_compressed', default='1', action='store', metavar='NUM',
       help='Whether compressed JavaScript files are used')
   parser.add_option(
diff --git a/chrome/browser/resources/chromeos/chromevox/tools/publish_webstore_extension.py b/chrome/browser/resources/chromeos/chromevox/tools/publish_webstore_extension.py
index fe8af1e..91cfbd6 100755
--- a/chrome/browser/resources/chromeos/chromevox/tools/publish_webstore_extension.py
+++ b/chrome/browser/resources/chromeos/chromevox/tools/publish_webstore_extension.py
@@ -69,7 +69,6 @@
   in_file_name = os.path.join(_SCRIPT_DIR, os.path.pardir,
                               'manifest.json.jinja2')
   context = {
-    'is_chromevox_classic': '1',
     'is_guest_manifest': '0',
     'is_js_compressed': '1',
     'set_version': GetVersion()
diff --git a/chrome/browser/resources/md_downloads/action_service.html b/chrome/browser/resources/md_downloads/action_service.html
index 1adb058..4fe25fe3 100644
--- a/chrome/browser/resources/md_downloads/action_service.html
+++ b/chrome/browser/resources/md_downloads/action_service.html
@@ -1,4 +1,4 @@
 <link rel="import" href="chrome://resources/html/assert.html">
 <link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="chrome://resources/html/load_time_data.html">
+<link rel="import" href="chrome://downloads/i18n.html">
 <script src="chrome://downloads/action_service.js"></script>
diff --git a/chrome/browser/resources/md_downloads/downloads.html b/chrome/browser/resources/md_downloads/downloads.html
index 501ce428..36d6480 100644
--- a/chrome/browser/resources/md_downloads/downloads.html
+++ b/chrome/browser/resources/md_downloads/downloads.html
@@ -33,9 +33,7 @@
   <command id="undo-command" shortcut="Ctrl-U+005A"><!-- Ctrl+Z -->
 </if>
   <link rel="import" href="chrome://resources/html/polymer_config.html">
-  <link rel="import" href="chrome://resources/html/load_time_data.html">
-  <link rel="import" href="chrome://downloads/strings.html">
-  <link rel="import" href="chrome://resources/html/i18n_template.html">
+  <link rel="import" href="chrome://downloads/i18n.html">
   <link rel="import" href="chrome://downloads/manager.html">
   <script src="chrome://downloads/downloads.js"></script>
 </body>
diff --git a/chrome/browser/resources/md_downloads/i18n.html b/chrome/browser/resources/md_downloads/i18n.html
new file mode 100644
index 0000000..9d4bf792
--- /dev/null
+++ b/chrome/browser/resources/md_downloads/i18n.html
@@ -0,0 +1,3 @@
+<script src="chrome://resources/js/load_time_data.js"></script>
+<script src="chrome://downloads/strings.js"></script>
+<script src="chrome://resources/js/i18n_template.js"></script>
diff --git a/chrome/browser/resources/md_downloads/item.html b/chrome/browser/resources/md_downloads/item.html
index 7837490..84b2b2c 100644
--- a/chrome/browser/resources/md_downloads/item.html
+++ b/chrome/browser/resources/md_downloads/item.html
@@ -1,6 +1,5 @@
 <link rel="import" href="chrome://resources/html/action_link.html">
 <link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="chrome://resources/html/load_time_data.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-icons.html">
@@ -9,6 +8,7 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-progress/paper-progress.html">
 <link rel="import" href="chrome://downloads/action_service.html">
 <link rel="import" href="chrome://downloads/constants.html">
+<link rel="import" href="chrome://downloads/i18n.html">
 
 <dom-module id="inky-text-button">
   <template><content></content></template>
diff --git a/chrome/browser/resources/md_downloads/manager.html b/chrome/browser/resources/md_downloads/manager.html
index b696a31..3f1e233 100644
--- a/chrome/browser/resources/md_downloads/manager.html
+++ b/chrome/browser/resources/md_downloads/manager.html
@@ -1,22 +1,16 @@
 <link rel="import" href="chrome://resources/html/cr.html">
 <link rel="import" href="chrome://resources/html/cr/ui.html">
 <link rel="import" href="chrome://resources/html/cr/ui/command.html">
-<link rel="import" href="chrome://resources/html/load_time_data.html">
 <link rel="import" href="chrome://resources/html/util.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-header-panel/paper-header-panel.html">
 <link rel="import" href="chrome://downloads/action_service.html">
 <link rel="import" href="chrome://downloads/constants.html">
+<link rel="import" href="chrome://downloads/i18n.html">
 <link rel="import" href="chrome://downloads/item.html">
 <link rel="import" href="chrome://downloads/toolbar.html">
 
-<!-- Must be after load_time_data.html. -->
-<link rel="import" href="chrome://downloads/strings.html">
-
-<!-- Must be after strings.html. -->
-<link rel="import" href="chrome://resources/html/i18n_template.html">
-
 <dom-module id="downloads-manager">
   <template>
     <paper-header-panel id="panel" class="loading">
diff --git a/chrome/browser/resources/md_downloads/strings.html b/chrome/browser/resources/md_downloads/strings.html
deleted file mode 100644
index ecbe002..0000000
--- a/chrome/browser/resources/md_downloads/strings.html
+++ /dev/null
@@ -1,2 +0,0 @@
-<link rel="import" href="chrome://resources/html/load_time_data.html">
-<script src="chrome://downloads/strings.js"></script>
diff --git a/chrome/browser/resources/md_downloads/toolbar.html b/chrome/browser/resources/md_downloads/toolbar.html
index 334caea..abfd12e 100644
--- a/chrome/browser/resources/md_downloads/toolbar.html
+++ b/chrome/browser/resources/md_downloads/toolbar.html
@@ -9,6 +9,7 @@
 <link rel="import" href="chrome://resources/html/assert.html">
 <link rel="import" href="chrome://resources/html/cr.html">
 <link rel="import" href="chrome://resources/html/util.html">
+<link rel="import" href="chrome://downloads/i18n.html">
 
 <dom-module id="downloads-toolbar">
   <template>
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.h b/chrome/browser/ui/cocoa/browser_window_cocoa.h
index 966f2f1..cf08dd5 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa.h
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa.h
@@ -13,7 +13,6 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/exclusive_access/exclusive_access_context.h"
 #include "chrome/browser/ui/search/search_model_observer.h"
-#include "chrome/browser/ui/tabs/tab_utils.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "ui/base/ui_base_types.h"
 
@@ -181,20 +180,9 @@
   // Adds the given FindBar cocoa controller to this browser window.
   void AddFindBar(FindBarCocoaController* find_bar_cocoa_controller);
 
-  // Update window media state to show if one of the tabs within the window is
-  // playing an audio/video or even if it's playing something but it's muted.
-  void UpdateMediaState(TabMediaState media_state);
-
   // Returns the cocoa-world BrowserWindowController
   BrowserWindowController* cocoa_controller() { return controller_; }
 
-  // Returns window title based on the active tab title and window media state.
-  NSString* WindowTitle();
-
-  // Returns current media state, determined by the media state of tabs, set by
-  // UpdateMediaState.
-  TabMediaState media_state() { return media_state_; }
-
  protected:
   void DestroyBrowser() override;
 
@@ -206,11 +194,6 @@
   base::scoped_nsobject<NSString> pending_window_title_;
   ui::WindowShowState initial_show_state_;
   NSInteger attention_request_id_;  // identifier from requestUserAttention
-
-  // Preserves window media state to show appropriate icon in the window title
-  // which can be audio playing, muting or none (determined by media state of
-  // tabs.
-  TabMediaState media_state_;
 };
 
 #endif  // CHROME_BROWSER_UI_COCOA_BROWSER_WINDOW_COCOA_H_
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.mm b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
index 2e52d63b..3b3606a3 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa.mm
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
@@ -297,23 +297,13 @@
 }
 
 void BrowserWindowCocoa::UpdateTitleBar() {
-  NSString* newTitle = WindowTitle();
+  NSString* newTitle =
+      base::SysUTF16ToNSString(browser_->GetWindowTitleForCurrentTab());
 
-  pending_window_title_.reset([BrowserWindowUtils
-      scheduleReplaceOldTitle:pending_window_title_.get()
-                 withNewTitle:newTitle
-                    forWindow:window()]);
-}
-
-NSString* BrowserWindowCocoa::WindowTitle() {
-  if (media_state_ == TAB_MEDIA_STATE_AUDIO_PLAYING) {
-    return l10n_util::GetNSStringF(IDS_WINDOW_AUDIO_PLAYING_MAC,
-                                   browser_->GetWindowTitleForCurrentTab());
-  } else if (media_state_ == TAB_MEDIA_STATE_AUDIO_MUTING) {
-    return l10n_util::GetNSStringF(IDS_WINDOW_AUDIO_MUTING_MAC,
-                                   browser_->GetWindowTitleForCurrentTab());
-  }
-  return base::SysUTF16ToNSString(browser_->GetWindowTitleForCurrentTab());
+  pending_window_title_.reset(
+      [BrowserWindowUtils scheduleReplaceOldTitle:pending_window_title_.get()
+                                     withNewTitle:newTitle
+                                        forWindow:window()]);
 }
 
 void BrowserWindowCocoa::BookmarkBarStateChanged(
@@ -552,11 +542,6 @@
   [controller_ addFindBar:find_bar_cocoa_controller];
 }
 
-void BrowserWindowCocoa::UpdateMediaState(TabMediaState media_state) {
-  media_state_ = media_state;
-  UpdateTitleBar();
-}
-
 void BrowserWindowCocoa::ShowUpdateChromeDialog() {
   restart_browser::RequestRestart(window());
 }
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa_unittest.mm b/chrome/browser/ui/cocoa/browser_window_cocoa_unittest.mm
index 1802bf7..3ff2a87 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa_unittest.mm
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa_unittest.mm
@@ -11,13 +11,11 @@
 #import "chrome/browser/ui/cocoa/browser_window_cocoa.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
-#include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/notification_details.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
 #import "third_party/ocmock/gtest_support.h"
-#include "ui/base/l10n/l10n_util_mac.h"
 
 // Main test class.
 class BrowserWindowCocoaTest : public CocoaProfileTest {
@@ -50,30 +48,6 @@
   EXPECT_EQ(before, bwc->IsBookmarkBarVisible());
 }
 
-TEST_F(BrowserWindowCocoaTest, TestWindowTitle) {
-  scoped_ptr<BrowserWindowCocoa> bwc(
-      new BrowserWindowCocoa(browser(), controller_));
-  NSString* playing_emoji =
-      l10n_util::GetNSStringF(IDS_WINDOW_AUDIO_PLAYING_MAC, base::string16());
-  NSString* muting_emoji =
-      l10n_util::GetNSStringF(IDS_WINDOW_AUDIO_MUTING_MAC, base::string16());
-  EXPECT_EQ([bwc->WindowTitle() rangeOfString:playing_emoji].location,
-            NSNotFound);
-  EXPECT_EQ([bwc->WindowTitle() rangeOfString:muting_emoji].location,
-            NSNotFound);
-  bwc->UpdateMediaState(TAB_MEDIA_STATE_AUDIO_PLAYING);
-  EXPECT_NE([bwc->WindowTitle() rangeOfString:playing_emoji].location,
-            NSNotFound);
-  bwc->UpdateMediaState(TAB_MEDIA_STATE_AUDIO_MUTING);
-  EXPECT_NE([bwc->WindowTitle() rangeOfString:muting_emoji].location,
-            NSNotFound);
-  bwc->UpdateMediaState(TAB_MEDIA_STATE_NONE);
-  EXPECT_EQ([bwc->WindowTitle() rangeOfString:playing_emoji].location,
-            NSNotFound);
-  EXPECT_EQ([bwc->WindowTitle() rangeOfString:muting_emoji].location,
-            NSNotFound);
-}
-
 // Test that IsMaximized() returns false when the browser window goes from
 // maximized to minimized state - http://crbug/452976.
 TEST_F(BrowserWindowCocoaTest, TestMinimizeState) {
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.h b/chrome/browser/ui/cocoa/browser_window_controller.h
index bba57ad..e438e18b 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.h
+++ b/chrome/browser/ui/cocoa/browser_window_controller.h
@@ -15,7 +15,6 @@
 #include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/translate/chrome_translate_client.h"
-#include "chrome/browser/ui/tabs/tab_utils.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.h"
 #import "chrome/browser/ui/cocoa/exclusive_access_bubble_window_controller.h"
@@ -376,13 +375,6 @@
 - (void)executeExtensionCommand:(const std::string&)extension_id
                         command:(const extensions::Command&)command;
 
-// To set whether the window has a tab playing audio or muted audio playing.
-- (void)setMediaState:(TabMediaState)mediaState;
-
-// Returns current media state, determined by the media state of tabs, set by
-// UpdateMediaState.
-- (TabMediaState)mediaState;
-
 @end  // @interface BrowserWindowController
 
 
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm
index 401d2d3..12e4f0b 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller.mm
@@ -1907,15 +1907,6 @@
                                                  command.accelerator());
 }
 
-- (void)setMediaState:(TabMediaState)mediaState {
-  static_cast<BrowserWindowCocoa*>([self browserWindow])
-      ->UpdateMediaState(mediaState);
-}
-
-- (TabMediaState)mediaState {
-  return static_cast<BrowserWindowCocoa*>([self browserWindow])->media_state();
-}
-
 @end  // @implementation BrowserWindowController
 
 @implementation BrowserWindowController(Fullscreen)
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.h b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.h
index 0f1cc332..b51e69a8 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.h
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.h
@@ -13,7 +13,6 @@
 #import "chrome/browser/ui/cocoa/tabs/tab_controller_target.h"
 #import "chrome/browser/ui/cocoa/url_drop_target.h"
 #include "chrome/browser/ui/tabs/hover_tab_selector.h"
-#include "chrome/browser/ui/tabs/tab_utils.h"
 
 @class CrTrackingArea;
 @class CustomWindowControlsView;
@@ -272,20 +271,6 @@
 // Removes custom traffic light buttons from the tab strip. Idempotent.
 - (void)removeCustomWindowControls;
 
-// Gets the tab and the media state to check whether the window
-// media state should be updated or not. If the tab media state is
-// AUDIO_PLAYING, the window media state should be set to AUDIO_PLAYING.
-// If the tab media state is AUDIO_MUTING, this method would check if the
-// window has no other tab with state AUDIO_PLAYING, then the window
-// media state will be set to AUDIO_MUTING. If the tab media state is NONE,
-// this method checks if the window has no playing or muting tab, then window
-// media state will be set as NONE.
-- (void)updateWindowMediaState:(TabMediaState)mediaState
-                            on:(content::WebContents*)changed;
-
-// Returns the media state associated with the contents.
-- (TabMediaState)mediaStateForContents:(content::WebContents*)contents;
-
 @end
 
 @interface TabStripController(TestingAPI)
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
index a163bfa..816aa1b3 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
@@ -45,6 +45,7 @@
 #include "chrome/browser/ui/tabs/tab_menu_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h"
+#include "chrome/browser/ui/tabs/tab_utils.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/metrics/proto/omnibox_event.pb.h"
@@ -251,9 +252,6 @@
 - (void)setNewTabButtonHoverState:(BOOL)showHover;
 - (void)themeDidChangeNotification:(NSNotification*)notification;
 - (void)setNewTabImages;
-- (BOOL)isAnyOtherTab:(content::WebContents*)selected
-            withState:(TabMediaState)state;
-
 @end
 
 // A simple view class that contains the traffic light buttons. This class
@@ -1280,7 +1278,7 @@
   [tab setTitle:base::SysUTF16ToNSString(title)];
 
   const base::string16& toolTip = chrome::AssembleTabTooltipText(
-      title, [self mediaStateForContents:contents]);
+      title, chrome::GetTabMediaStateForContents(contents));
   [tab setToolTip:base::SysUTF16ToNSString(toolTip)];
 }
 
@@ -1633,10 +1631,7 @@
     }
   }
 
-  TabMediaState mediaState = [self mediaStateForContents:contents];
-
-  [self updateWindowMediaState:mediaState on:contents];
-  [tabController setMediaState:mediaState];
+  [tabController setMediaState:chrome::GetTabMediaStateForContents(contents)];
 
   [tabController updateVisibility];
 }
@@ -2301,57 +2296,6 @@
   [customWindowControls_ setMouseInside:NO];
 }
 
-// Gets the tab and the media state to check whether the window
-// media state should be updated or not. If the tab media state is
-// AUDIO_PLAYING, the window media state should be set to AUDIO_PLAYING.
-// If the tab media state is AUDIO_MUTING, this method would check if the
-// window has no other tab with state AUDIO_PLAYING, then the window
-// media state will be set to AUDIO_MUTING. If the tab media state is NONE,
-// this method checks if the window has no playing or muting tab, then window
-// media state will be set as NONE.
-- (void)updateWindowMediaState:(TabMediaState)mediaState
-                            on:(content::WebContents*)selected {
-  NSWindow* window = [tabStripView_ window];
-  BrowserWindowController* windowController =
-      [BrowserWindowController browserWindowControllerForWindow:window];
-  if (mediaState == TAB_MEDIA_STATE_NONE) {
-    if (![self isAnyOtherTab:selected
-                   withState:TAB_MEDIA_STATE_AUDIO_PLAYING] &&
-        ![self isAnyOtherTab:selected withState:TAB_MEDIA_STATE_AUDIO_MUTING]) {
-      [windowController setMediaState:TAB_MEDIA_STATE_NONE];
-    } else if ([self isAnyOtherTab:selected
-                         withState:TAB_MEDIA_STATE_AUDIO_MUTING]) {
-      [windowController setMediaState:TAB_MEDIA_STATE_AUDIO_MUTING];
-    }
-  } else if (mediaState == TAB_MEDIA_STATE_AUDIO_MUTING) {
-    if (![self isAnyOtherTab:selected withState:TAB_MEDIA_STATE_AUDIO_PLAYING])
-      [windowController setMediaState:TAB_MEDIA_STATE_AUDIO_MUTING];
-  } else {
-    [windowController setMediaState:mediaState];
-  }
-}
-
-// Checks if tabs (excluding selected) has media state equals to the second
-// parameter. It returns YES when it finds the first tab with the criterion.
-- (BOOL)isAnyOtherTab:(content::WebContents*)selected
-            withState:(TabMediaState)state {
-  const int existingTabCount = tabStripModel_->count();
-  for (int i = 0; i < existingTabCount; ++i) {
-    content::WebContents* currentContents = tabStripModel_->GetWebContentsAt(i);
-    if (selected == currentContents)
-      continue;
-    TabMediaState currentMediaStateForContents =
-        [self mediaStateForContents:currentContents];
-    if (currentMediaStateForContents == state)
-      return YES;
-  }
-  return NO;
-}
-
-- (TabMediaState)mediaStateForContents:(content::WebContents*)contents {
-  return chrome::GetTabMediaStateForContents(contents);
-}
-
 - (void)themeDidChangeNotification:(NSNotification*)notification {
   [self setNewTabImages];
 }
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_controller_unittest.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_controller_unittest.mm
index a691ac46..cfe3a71 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_controller_unittest.mm
@@ -9,7 +9,6 @@
 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
 #include "chrome/browser/media/media_stream_capture_indicator.h"
 #include "chrome/browser/ui/browser_window.h"
-#import "chrome/browser/ui/cocoa/browser_window_controller.h"
 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
 #import "chrome/browser/ui/cocoa/new_tab_button.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_controller.h"
@@ -30,25 +29,6 @@
 using content::SiteInstance;
 using content::WebContents;
 
-@interface TabStripControllerForMediaTesting : TabStripController {
-  // Keeps media state of tabs in browser for testing purpose.
-  std::map<content::WebContents*, TabMediaState> contents_media_state_maps;
-}
-@end
-
-@implementation TabStripControllerForMediaTesting
-// Returns the media state of each tab from the map we are keeping.
-- (TabMediaState)mediaStateForContents:(content::WebContents*)contents {
-  return contents_media_state_maps[contents];
-}
-
-- (void)setMediaStateForContents:(content::WebContents*)contents
-                  withMediaState:(TabMediaState)media_state {
-  contents_media_state_maps[contents] = media_state;
-}
-
-@end
-
 @interface TestTabStripControllerDelegate
     : NSObject<TabStripControllerDelegate> {
 }
@@ -122,8 +102,7 @@
     NSRect switch_frame = NSMakeRect(0, 0, content_frame.size.width, 500);
     base::scoped_nsobject<NSView> switch_view(
         [[NSView alloc] initWithFrame:switch_frame]);
-    switch_view_ = switch_view;
-    [parent addSubview:switch_view_.get()];
+    [parent addSubview:switch_view.get()];
 
     // Create the tab strip view. It's expected to have a child button in it
     // already as the "new tab" button so create that too.
@@ -156,17 +135,6 @@
     CocoaProfileTest::TearDown();
   }
 
-  // Return a derived TabStripController.
-  TabStripControllerForMediaTesting* InitTabStripControllerForMediaTesting() {
-    TabStripControllerForMediaTesting* c =
-        [[TabStripControllerForMediaTesting alloc]
-            initWithView:static_cast<TabStripView*>(tab_strip_.get())
-              switchView:switch_view_.get()
-                 browser:browser()
-                delegate:controller_delegate_.get()];
-    return c;
-  }
-
   TabView* CreateTab() {
     SiteInstance* instance = SiteInstance::Create(profile());
     WebContents* web_contents = WebContents::Create(
@@ -194,7 +162,6 @@
   base::scoped_nsobject<TestTabStripControllerDelegate> controller_delegate_;
   base::scoped_nsobject<TabStripController> controller_;
   base::scoped_nsobject<TabStripView> tab_strip_;
-  base::scoped_nsobject<NSView> switch_view_;
 };
 
 // Test adding and removing tabs and making sure that views get added to
@@ -382,87 +349,4 @@
   EXPECT_EQ(tab1, value);
 }
 
-TEST_F(TabStripControllerTest, CorrectWindowFromUpdateWindowMediaState) {
-  controller_.reset(InitTabStripControllerForMediaTesting());
-  NSWindow* window = [tab_strip_ window];
-  BrowserWindowController* window_controller =
-      [BrowserWindowController browserWindowControllerForWindow:window];
-  TabStripControllerForMediaTesting* tabStripControllerForTesting =
-      static_cast<TabStripControllerForMediaTesting*>(controller_);
-
-  TabView* const tab1 = CreateTab();
-  TabView* const tab2 = CreateTab();
-
-  // tab2 should be the selected one.
-  EXPECT_FALSE([tab1 controller].selected);
-  EXPECT_TRUE([tab2 controller].selected);
-  WebContents* const contents_at_tab1 = model_->GetActiveWebContents();
-
-  [tabStripControllerForTesting
-      setMediaStateForContents:contents_at_tab1
-                withMediaState:TAB_MEDIA_STATE_AUDIO_PLAYING];
-  // Make sure the overriden from base controller correctly handles media
-  // status of tabs.
-  EXPECT_EQ(TAB_MEDIA_STATE_AUDIO_PLAYING,
-            [controller_ mediaStateForContents:contents_at_tab1]);
-  [controller_ updateWindowMediaState:TAB_MEDIA_STATE_AUDIO_PLAYING
-                                   on:contents_at_tab1];
-  // Because we have one tab playing, and the other one's media state is none,
-  // window media state should be AUDIO_PLAYING.
-  EXPECT_EQ(TAB_MEDIA_STATE_AUDIO_PLAYING, [window_controller mediaState]);
-
-  model_->ActivateTabAt(0, false);
-  // tab1 should be the selected one now.
-  EXPECT_TRUE([tab1 controller].selected);
-  EXPECT_FALSE([tab2 controller].selected);
-  WebContents* const contents_at_tab0 = model_->GetActiveWebContents();
-
-  [tabStripControllerForTesting
-      setMediaStateForContents:contents_at_tab0
-                withMediaState:TAB_MEDIA_STATE_AUDIO_MUTING];
-  [controller_ updateWindowMediaState:TAB_MEDIA_STATE_AUDIO_MUTING
-                                   on:contents_at_tab0];
-  // We have two tabs. One is playing and the other one is muting. The window
-  // media state should be still AUDIO_PLAYING.
-  EXPECT_EQ(TAB_MEDIA_STATE_AUDIO_PLAYING, [window_controller mediaState]);
-
-  [tabStripControllerForTesting
-      setMediaStateForContents:contents_at_tab1
-                withMediaState:TAB_MEDIA_STATE_AUDIO_MUTING];
-  [controller_ updateWindowMediaState:TAB_MEDIA_STATE_AUDIO_MUTING
-                                   on:contents_at_tab1];
-  // Now both tabs are muting, the window media state should be AUDIO_MUTING.
-  EXPECT_EQ(TAB_MEDIA_STATE_AUDIO_MUTING, [window_controller mediaState]);
-
-  [tabStripControllerForTesting
-      setMediaStateForContents:contents_at_tab0
-                withMediaState:TAB_MEDIA_STATE_AUDIO_PLAYING];
-  [controller_ updateWindowMediaState:TAB_MEDIA_STATE_AUDIO_PLAYING
-                                   on:contents_at_tab0];
-  // Among those tabs which were muting, one is started playing, the window
-  // media state should be playing.
-  EXPECT_EQ(TAB_MEDIA_STATE_AUDIO_PLAYING, [window_controller mediaState]);
-
-  // Mute it again for further testing.
-  [tabStripControllerForTesting
-      setMediaStateForContents:contents_at_tab0
-                withMediaState:TAB_MEDIA_STATE_AUDIO_MUTING];
-  [controller_ updateWindowMediaState:TAB_MEDIA_STATE_AUDIO_MUTING
-                                   on:contents_at_tab0];
-
-  [tabStripControllerForTesting setMediaStateForContents:contents_at_tab1
-                                          withMediaState:TAB_MEDIA_STATE_NONE];
-  [controller_ updateWindowMediaState:TAB_MEDIA_STATE_NONE on:contents_at_tab1];
-  // One of the tabs is muting, the other one is none. So window media state
-  // should be MUTING.
-  EXPECT_EQ(TAB_MEDIA_STATE_AUDIO_MUTING, [window_controller mediaState]);
-
-  [tabStripControllerForTesting setMediaStateForContents:contents_at_tab0
-                                          withMediaState:TAB_MEDIA_STATE_NONE];
-  [controller_ updateWindowMediaState:TAB_MEDIA_STATE_NONE on:contents_at_tab0];
-  // Neither of tabs playing nor muting, so the window media state should be
-  // NONE.
-  EXPECT_EQ(TAB_MEDIA_STATE_NONE, [window_controller mediaState]);
-}
-
 }  // namespace
diff --git a/chrome/browser/ui/views/location_bar/save_credit_card_icon_view.cc b/chrome/browser/ui/views/autofill/save_card_icon_view.cc
similarity index 73%
rename from chrome/browser/ui/views/location_bar/save_credit_card_icon_view.cc
rename to chrome/browser/ui/views/autofill/save_card_icon_view.cc
index 06c2dce..878b6e0f 100644
--- a/chrome/browser/ui/views/location_bar/save_credit_card_icon_view.cc
+++ b/chrome/browser/ui/views/autofill/save_card_icon_view.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/views/location_bar/save_credit_card_icon_view.h"
+#include "chrome/browser/ui/views/autofill/save_card_icon_view.h"
 
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/ui/autofill/save_card_bubble_controller_impl.h"
@@ -14,8 +14,10 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/vector_icons_public.h"
 
-SaveCreditCardIconView::SaveCreditCardIconView(CommandUpdater* command_updater,
-                                               Browser* browser)
+namespace autofill {
+
+SaveCardIconView::SaveCardIconView(CommandUpdater* command_updater,
+                                   Browser* browser)
     : BubbleIconView(command_updater, IDC_SAVE_CREDIT_CARD_FOR_PAGE),
       browser_(browser) {
   set_id(VIEW_ID_SAVE_CREDIT_CARD_BUTTON);
@@ -23,16 +25,16 @@
   SetToggled(false);
 }
 
-SaveCreditCardIconView::~SaveCreditCardIconView() {}
+SaveCardIconView::~SaveCardIconView() {}
 
-void SaveCreditCardIconView::SetToggled(bool on) {
+void SaveCardIconView::SetToggled(bool on) {
   SetActiveInternal(on);
 }
 
-void SaveCreditCardIconView::OnExecuting(
+void SaveCardIconView::OnExecuting(
     BubbleIconView::ExecuteSource execute_source) {}
 
-views::BubbleDelegateView* SaveCreditCardIconView::GetBubble() const {
+views::BubbleDelegateView* SaveCardIconView::GetBubble() const {
   if (!browser_)
     return nullptr;
   content::WebContents* web_contents =
@@ -48,6 +50,8 @@
       controller->save_card_bubble_view());
 }
 
-gfx::VectorIconId SaveCreditCardIconView::GetVectorIcon() const {
+gfx::VectorIconId SaveCardIconView::GetVectorIcon() const {
   return gfx::VectorIconId::AUTOFILL;
 }
+
+}  // namespace autofill
diff --git a/chrome/browser/ui/views/autofill/save_card_icon_view.h b/chrome/browser/ui/views/autofill/save_card_icon_view.h
new file mode 100644
index 0000000..527c0f76
--- /dev/null
+++ b/chrome/browser/ui/views/autofill/save_card_icon_view.h
@@ -0,0 +1,42 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_AUTOFILL_SAVE_CARD_ICON_VIEW_H_
+#define CHROME_BROWSER_UI_VIEWS_AUTOFILL_SAVE_CARD_ICON_VIEW_H_
+
+#include "base/macros.h"
+#include "chrome/browser/ui/views/location_bar/bubble_icon_view.h"
+
+class Browser;
+class CommandUpdater;
+
+namespace autofill {
+
+// The location bar icon to show the Save Credit Card bubble where the user can
+// choose to save the credit card info to use again later without re-entering
+// it.
+class SaveCardIconView : public BubbleIconView {
+ public:
+  explicit SaveCardIconView(CommandUpdater* command_updater, Browser* browser);
+  ~SaveCardIconView() override;
+
+  // Toggles the icon on or off.
+  void SetToggled(bool on);
+
+ protected:
+  // BubbleIconView:
+  void OnExecuting(BubbleIconView::ExecuteSource execute_source) override;
+  views::BubbleDelegateView* GetBubble() const override;
+  gfx::VectorIconId GetVectorIcon() const override;
+
+ private:
+  // May be nullptr.
+  Browser* browser_;
+
+  DISALLOW_COPY_AND_ASSIGN(SaveCardIconView);
+};
+
+}  // namespace autofill
+
+#endif  // CHROME_BROWSER_UI_VIEWS_AUTOFILL_SAVE_CARD_ICON_VIEW_H_
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc
index c2c44caa..4eee58e1 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -36,6 +36,7 @@
 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/views/autofill/save_card_icon_view.h"
 #include "chrome/browser/ui/views/browser_dialogs.h"
 #include "chrome/browser/ui/views/layout_constants.h"
 #include "chrome/browser/ui/views/location_bar/background_with_1_px_border.h"
@@ -47,15 +48,14 @@
 #include "chrome/browser/ui/views/location_bar/open_pdf_in_reader_view.h"
 #include "chrome/browser/ui/views/location_bar/page_action_image_view.h"
 #include "chrome/browser/ui/views/location_bar/page_action_with_badge_view.h"
-#include "chrome/browser/ui/views/location_bar/save_credit_card_icon_view.h"
 #include "chrome/browser/ui/views/location_bar/selected_keyword_view.h"
 #include "chrome/browser/ui/views/location_bar/star_view.h"
-#include "chrome/browser/ui/views/location_bar/translate_icon_view.h"
 #include "chrome/browser/ui/views/location_bar/zoom_bubble_view.h"
 #include "chrome/browser/ui/views/location_bar/zoom_view.h"
 #include "chrome/browser/ui/views/passwords/manage_passwords_bubble_view.h"
 #include "chrome/browser/ui/views/passwords/manage_passwords_icon_views.h"
 #include "chrome/browser/ui/views/translate/translate_bubble_view.h"
+#include "chrome/browser/ui/views/translate/translate_icon_view.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/bookmarks/common/bookmark_pref_names.h"
 #include "components/favicon/content/content_favicon_driver.h"
@@ -315,7 +315,7 @@
   AddChildView(manage_passwords_icon_view_);
 
   save_credit_card_icon_view_ =
-      new SaveCreditCardIconView(command_updater(), browser_);
+      new autofill::SaveCardIconView(command_updater(), browser_);
   save_credit_card_icon_view_->SetVisible(false);
   AddChildView(save_credit_card_icon_view_);
 
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.h b/chrome/browser/ui/views/location_bar/location_bar_view.h
index 015923f..9d4d1bc 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.h
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.h
@@ -44,13 +44,16 @@
 class PageActionWithBadgeView;
 class PageActionImageView;
 class Profile;
-class SaveCreditCardIconView;
 class SelectedKeywordView;
 class StarView;
 class TemplateURLService;
 class TranslateIconView;
 class ZoomView;
 
+namespace autofill {
+class SaveCardIconView;
+}
+
 namespace views {
 class BubbleDelegateView;
 class ImageButton;
@@ -177,7 +180,7 @@
   StarView* star_view() { return star_view_; }
 
   // The save credit card icon. It may not be visible.
-  SaveCreditCardIconView* save_credit_card_icon_view() {
+  autofill::SaveCardIconView* save_credit_card_icon_view() {
     return save_credit_card_icon_view_;
   }
 
@@ -463,7 +466,7 @@
   PageActionViews page_action_views_;
 
   // The save credit card icon.
-  SaveCreditCardIconView* save_credit_card_icon_view_;
+  autofill::SaveCardIconView* save_credit_card_icon_view_;
 
   // The icon for Translate.
   TranslateIconView* translate_icon_view_;
diff --git a/chrome/browser/ui/views/location_bar/save_credit_card_icon_view.h b/chrome/browser/ui/views/location_bar/save_credit_card_icon_view.h
deleted file mode 100644
index 4da388e7..0000000
--- a/chrome/browser/ui/views/location_bar/save_credit_card_icon_view.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_SAVE_CREDIT_CARD_ICON_VIEW_H_
-#define CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_SAVE_CREDIT_CARD_ICON_VIEW_H_
-
-#include "base/macros.h"
-#include "chrome/browser/ui/views/location_bar/bubble_icon_view.h"
-
-class Browser;
-class CommandUpdater;
-
-// The icon to show the Save Credit Card bubble where the user can choose to
-// save the credit card info to use again later without re-entering it.
-class SaveCreditCardIconView : public BubbleIconView {
- public:
-  explicit SaveCreditCardIconView(CommandUpdater* command_updater,
-                                  Browser* browser);
-  ~SaveCreditCardIconView() override;
-
-  // Toggles the icon on or off.
-  void SetToggled(bool on);
-
- protected:
-  // BubbleIconView:
-  void OnExecuting(BubbleIconView::ExecuteSource execute_source) override;
-  views::BubbleDelegateView* GetBubble() const override;
-  gfx::VectorIconId GetVectorIcon() const override;
-
- private:
-  // May be nullptr.
-  Browser* browser_;
-
-  DISALLOW_COPY_AND_ASSIGN(SaveCreditCardIconView);
-};
-
-#endif  // CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_SAVE_CREDIT_CARD_ICON_VIEW_H_
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc
index 106a799..21b4d611 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -28,14 +28,13 @@
 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/views/autofill/save_card_icon_view.h"
 #include "chrome/browser/ui/views/extensions/extension_popup.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/layout_constants.h"
 #include "chrome/browser/ui/views/location_bar/page_action_image_view.h"
 #include "chrome/browser/ui/views/location_bar/page_action_with_badge_view.h"
-#include "chrome/browser/ui/views/location_bar/save_credit_card_icon_view.h"
 #include "chrome/browser/ui/views/location_bar/star_view.h"
-#include "chrome/browser/ui/views/location_bar/translate_icon_view.h"
 #include "chrome/browser/ui/views/outdated_upgrade_bubble_view.h"
 #include "chrome/browser/ui/views/toolbar/app_menu_button.h"
 #include "chrome/browser/ui/views/toolbar/back_button.h"
@@ -43,6 +42,7 @@
 #include "chrome/browser/ui/views/toolbar/home_button.h"
 #include "chrome/browser/ui/views/toolbar/reload_button.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_button.h"
+#include "chrome/browser/ui/views/translate/translate_icon_view.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/chromium_strings.h"
diff --git a/chrome/browser/ui/views/location_bar/translate_icon_view.cc b/chrome/browser/ui/views/translate/translate_icon_view.cc
similarity index 87%
rename from chrome/browser/ui/views/location_bar/translate_icon_view.cc
rename to chrome/browser/ui/views/translate/translate_icon_view.cc
index df8a633..c4acdca 100644
--- a/chrome/browser/ui/views/location_bar/translate_icon_view.cc
+++ b/chrome/browser/ui/views/translate/translate_icon_view.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/views/location_bar/translate_icon_view.h"
+#include "chrome/browser/ui/views/translate/translate_icon_view.h"
 
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app/chrome_command_ids.h"
@@ -21,16 +21,14 @@
   SetTooltipText(l10n_util::GetStringUTF16(IDS_TOOLTIP_TRANSLATE));
 }
 
-TranslateIconView::~TranslateIconView() {
-}
+TranslateIconView::~TranslateIconView() {}
 
 void TranslateIconView::SetToggled(bool on) {
   SetActiveInternal(on);
 }
 
 void TranslateIconView::OnExecuting(
-  BubbleIconView::ExecuteSource execute_source) {
-}
+    BubbleIconView::ExecuteSource execute_source) {}
 
 views::BubbleDelegateView* TranslateIconView::GetBubble() const {
   return TranslateBubbleView::GetCurrentBubble();
diff --git a/chrome/browser/ui/views/location_bar/translate_icon_view.h b/chrome/browser/ui/views/translate/translate_icon_view.h
similarity index 70%
rename from chrome/browser/ui/views/location_bar/translate_icon_view.h
rename to chrome/browser/ui/views/translate/translate_icon_view.h
index 947bb7b..f981c4a 100644
--- a/chrome/browser/ui/views/location_bar/translate_icon_view.h
+++ b/chrome/browser/ui/views/translate/translate_icon_view.h
@@ -2,15 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_TRANSLATE_ICON_VIEW_H_
-#define CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_TRANSLATE_ICON_VIEW_H_
+#ifndef CHROME_BROWSER_UI_VIEWS_TRANSLATE_TRANSLATE_ICON_VIEW_H_
+#define CHROME_BROWSER_UI_VIEWS_TRANSLATE_TRANSLATE_ICON_VIEW_H_
 
+#include "base/macros.h"
 #include "chrome/browser/ui/views/location_bar/bubble_icon_view.h"
 
 class CommandUpdater;
 
-// The icon to show the Translate bubble where the user can have the page
-// tarnslated.
+// The location bar icon to show the Translate bubble where the user can have
+// the page translated.
 class TranslateIconView : public BubbleIconView {
  public:
   explicit TranslateIconView(CommandUpdater* command_updater);
@@ -29,4 +30,4 @@
   DISALLOW_COPY_AND_ASSIGN(TranslateIconView);
 };
 
-#endif  // CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_TRANSLATE_ICON_VIEW_H_
+#endif  // CHROME_BROWSER_UI_VIEWS_TRANSLATE_TRANSLATE_ICON_VIEW_H_
diff --git a/chrome/browser/ui/webui/md_downloads/md_downloads_ui.cc b/chrome/browser/ui/webui/md_downloads/md_downloads_ui.cc
index 9003ff3..ecda4cc 100644
--- a/chrome/browser/ui/webui/md_downloads/md_downloads_ui.cc
+++ b/chrome/browser/ui/webui/md_downloads/md_downloads_ui.cc
@@ -111,6 +111,7 @@
   source->AddResourcePath("crisper.js", IDR_MD_DOWNLOADS_CRISPER_JS);
   source->AddResourcePath("dev.html", IDR_MD_DOWNLOADS_DOWNLOADS_HTML);
   source->AddResourcePath("downloads.js", IDR_MD_DOWNLOADS_DOWNLOADS_JS);
+  source->AddResourcePath("i18n.html", IDR_MD_DOWNLOADS_I18N_HTML);
   source->AddResourcePath("item.css", IDR_MD_DOWNLOADS_ITEM_CSS);
   source->AddResourcePath("item.html", IDR_MD_DOWNLOADS_ITEM_HTML);
   source->AddResourcePath("item.js", IDR_MD_DOWNLOADS_ITEM_JS);
@@ -119,7 +120,6 @@
   source->AddResourcePath("manager.js", IDR_MD_DOWNLOADS_MANAGER_JS);
   source->AddResourcePath("shared_style.css",
                           IDR_MD_DOWNLOADS_SHARED_STYLE_CSS);
-  source->AddResourcePath("strings.html", IDR_MD_DOWNLOADS_STRINGS_HTML);
   source->AddResourcePath("toolbar.css", IDR_MD_DOWNLOADS_TOOLBAR_CSS);
   source->AddResourcePath("toolbar.html", IDR_MD_DOWNLOADS_TOOLBAR_HTML);
   source->AddResourcePath("toolbar.js", IDR_MD_DOWNLOADS_TOOLBAR_JS);
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index 974897d..3f58812 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -2112,6 +2112,8 @@
       'browser/ui/views/autofill/password_generation_popup_view_views.h',
       'browser/ui/views/autofill/save_card_bubble_views.cc',
       'browser/ui/views/autofill/save_card_bubble_views.h',
+      'browser/ui/views/autofill/save_card_icon_view.cc',
+      'browser/ui/views/autofill/save_card_icon_view.h',
       'browser/ui/views/autofill/tooltip_icon.cc',
       'browser/ui/views/autofill/tooltip_icon.h',
       'browser/ui/views/bar_control_button.cc',
@@ -2294,14 +2296,10 @@
       'browser/ui/views/location_bar/page_action_with_badge_view.h',
       'browser/ui/views/location_bar/page_info_helper.cc',
       'browser/ui/views/location_bar/page_info_helper.h',
-      'browser/ui/views/location_bar/save_credit_card_icon_view.cc',
-      'browser/ui/views/location_bar/save_credit_card_icon_view.h',
       'browser/ui/views/location_bar/selected_keyword_view.cc',
       'browser/ui/views/location_bar/selected_keyword_view.h',
       'browser/ui/views/location_bar/star_view.cc',
       'browser/ui/views/location_bar/star_view.h',
-      'browser/ui/views/location_bar/translate_icon_view.cc',
-      'browser/ui/views/location_bar/translate_icon_view.h',
       'browser/ui/views/location_bar/zoom_bubble_view.cc',
       'browser/ui/views/location_bar/zoom_bubble_view.h',
       'browser/ui/views/location_bar/zoom_view.cc',
@@ -2428,6 +2426,8 @@
       'browser/ui/views/touch_uma/touch_uma.h',
       'browser/ui/views/translate/translate_bubble_view.cc',
       'browser/ui/views/translate/translate_bubble_view.h',
+      'browser/ui/views/translate/translate_icon_view.cc',
+      'browser/ui/views/translate/translate_icon_view.h',
       'browser/ui/views/update_recommended_message_box.cc',
       'browser/ui/views/update_recommended_message_box.h',
       'browser/ui/views/validation_message_bubble_delegate.cc',
diff --git a/chrome/common/crash_keys.cc b/chrome/common/crash_keys.cc
index 414b3f60..06e262f 100644
--- a/chrome/common/crash_keys.cc
+++ b/chrome/common/crash_keys.cc
@@ -146,19 +146,6 @@
     { kBug464926CrashKey, kSmallSize },
     { kViewCount, kSmallSize },
     { kZeroEncodeDetails, kSmallSize },
-
-    // Temporary for http://crbug.com/369661
-    { "pageid", kSmallSize },
-    { "navuniqueid", kSmallSize },
-    { "oldindex", kSmallSize },
-    { "newindex", kSmallSize },
-    { "lastcommittedindex", kSmallSize },
-    { "oldurl", kLargeSize },
-    { "newurl", kLargeSize },
-    { "updatedvalue", kLargeSize },
-    { "oldvalue", kLargeSize },
-    { "newvalue", kLargeSize },
-    // End http://crbug.com/369661
   };
 
   // This dynamic set of keys is used for sets of key value pairs when gathering
diff --git a/chrome/common/net/x509_certificate_model_openssl.cc b/chrome/common/net/x509_certificate_model_openssl.cc
index b9f2039..7a7c8366 100644
--- a/chrome/common/net/x509_certificate_model_openssl.cc
+++ b/chrome/common/net/x509_certificate_model_openssl.cc
@@ -21,6 +21,7 @@
 #include "crypto/openssl_bio_string.h"
 #include "crypto/openssl_util.h"
 #include "crypto/scoped_openssl_types.h"
+#include "net/base/address_family.h"
 #include "net/base/net_util.h"
 #include "net/cert/x509_util_openssl.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc
index e5193d4..286695b 100644
--- a/chrome/installer/setup/setup_main.cc
+++ b/chrome/installer/setup/setup_main.cc
@@ -829,7 +829,6 @@
   const bool system_install = installer_state->system_install();
   installer::InstallStatus install_status = installer::UNKNOWN_STATUS;
   installer::ArchiveType archive_type = installer::UNKNOWN_ARCHIVE_TYPE;
-  bool delegated_to_existing = false;
   installer_state->UpdateStage(installer::PRECONDITIONS);
   // The stage provides more fine-grained information than -multifail, so remove
   // the -multifail suffix from the Google Update "ap" value.
@@ -840,7 +839,7 @@
     VLOG(1) << "Installing to " << installer_state->target_path().value();
     install_status = InstallProductsHelper(
         original_state, setup_exe, cmd_line, prefs, *installer_state,
-        installer_directory, &archive_type, &delegated_to_existing);
+        installer_directory, &archive_type);
   } else {
     // CheckPreInstallConditions must set the status on failure.
     DCHECK_NE(install_status, installer::UNKNOWN_STATUS);
@@ -860,11 +859,6 @@
     }
   }
 
-  // Early exit if this setup.exe delegated to another, since that one would
-  // have taken care of UpdateInstallStatus and UpdateStage.
-  if (delegated_to_existing)
-    return install_status;
-
   const Products& products = installer_state->products();
   for (Products::const_iterator it = products.begin(); it < products.end();
        ++it) {
@@ -1408,10 +1402,8 @@
                                     const MasterPreferences& prefs,
                                     const InstallerState& installer_state,
                                     base::FilePath* installer_directory,
-                                    ArchiveType* archive_type,
-                                    bool* delegated_to_existing) {
+                                    ArchiveType* archive_type) {
   DCHECK(archive_type);
-  DCHECK(delegated_to_existing);
   const bool system_install = installer_state.system_install();
   InstallStatus install_status = UNKNOWN_STATUS;
 
@@ -1506,26 +1498,6 @@
     VLOG(1) << "version to install: " << installer_version->GetString();
     bool proceed_with_installation = true;
 
-    if (installer_state.operation() == InstallerState::MULTI_INSTALL) {
-      // This is a new install of a multi-install product. Rather than give up
-      // in case a higher version of the binaries (including a single-install
-      // of Chrome, which can safely be migrated to multi-install by way of
-      // CheckMultiInstallConditions) is already installed, delegate to the
-      // installed setup.exe to install the product at hand.
-      base::FilePath existing_setup_exe;
-      if (GetExistingHigherInstaller(original_state, system_install,
-                                     *installer_version, &existing_setup_exe)) {
-        VLOG(1) << "Deferring to existing installer.";
-        installer_state.UpdateStage(DEFERRING_TO_HIGHER_VERSION);
-        if (DeferToExistingInstall(existing_setup_exe, cmd_line,
-                                   installer_state, temp_path.path(),
-                                   &install_status)) {
-          *delegated_to_existing = true;
-          return install_status;
-        }
-      }
-    }
-
     uint32 higher_products = 0;
     COMPILE_ASSERT(
         sizeof(higher_products) * 8 > BrowserDistribution::NUM_TYPES,
diff --git a/chrome/installer/setup/setup_main.h b/chrome/installer/setup/setup_main.h
index 5bcf457f..b6ec002 100644
--- a/chrome/installer/setup/setup_main.h
+++ b/chrome/installer/setup/setup_main.h
@@ -31,8 +31,7 @@
                                     const MasterPreferences& prefs,
                                     const InstallerState& installer_state,
                                     base::FilePath* installer_directory,
-                                    ArchiveType* archive_type,
-                                    bool* delegated_to_existing);
+                                    ArchiveType* archive_type);
 
 }  // namespace installer
 
diff --git a/chrome/installer/setup/setup_util.cc b/chrome/installer/setup/setup_util.cc
index 6ac6a3c..0ad1b45 100644
--- a/chrome/installer/setup/setup_util.cc
+++ b/chrome/installer/setup/setup_util.cc
@@ -19,9 +19,6 @@
 #include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/numerics/safe_conversions.h"
-#include "base/process/kill.h"
-#include "base/process/launch.h"
-#include "base/process/process_handle.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/version.h"
@@ -29,13 +26,10 @@
 #include "base/win/windows_version.h"
 #include "chrome/installer/setup/setup_constants.h"
 #include "chrome/installer/util/app_registration_data.h"
-#include "chrome/installer/util/copy_tree_work_item.h"
 #include "chrome/installer/util/google_update_constants.h"
 #include "chrome/installer/util/installation_state.h"
 #include "chrome/installer/util/installer_state.h"
-#include "chrome/installer/util/master_preferences.h"
 #include "chrome/installer/util/util_constants.h"
-#include "chrome/installer/util/work_item.h"
 #include "courgette/courgette.h"
 #include "courgette/third_party/bsdiff.h"
 #include "third_party/bspatch/mbspatch.h"
@@ -44,53 +38,6 @@
 
 namespace {
 
-// Launches |setup_exe| with |command_line|, save --install-archive and its
-// value if present. Returns false if the process failed to launch. Otherwise,
-// waits indefinitely for it to exit and populates |exit_code| as expected. On
-// the off chance that waiting itself fails, |exit_code| is set to
-// WAIT_FOR_EXISTING_FAILED.
-bool LaunchAndWaitForExistingInstall(const base::FilePath& setup_exe,
-                                     const base::CommandLine& command_line,
-                                     int* exit_code) {
-  DCHECK(exit_code);
-  base::CommandLine new_cl(setup_exe);
-
-  // Copy over all switches but --install-archive.
-  base::CommandLine::SwitchMap switches(command_line.GetSwitches());
-  switches.erase(switches::kInstallArchive);
-  for (base::CommandLine::SwitchMap::const_iterator i = switches.begin();
-       i != switches.end(); ++i) {
-    if (i->second.empty())
-      new_cl.AppendSwitch(i->first);
-    else
-      new_cl.AppendSwitchNative(i->first, i->second);
-  }
-
-  // Copy over all arguments.
-  base::CommandLine::StringVector args(command_line.GetArgs());
-  for (base::CommandLine::StringVector::const_iterator i = args.begin();
-       i != args.end(); ++i) {
-    new_cl.AppendArgNative(*i);
-  }
-
-  // Launch the process and wait for it to exit.
-  VLOG(1) << "Launching existing installer with command: "
-          << new_cl.GetCommandLineString();
-  base::Process process = base::LaunchProcess(new_cl, base::LaunchOptions());
-  if (!process.IsValid()) {
-    PLOG(ERROR) << "Failed to launch existing installer with command: "
-                << new_cl.GetCommandLineString();
-    return false;
-  }
-  if (!process.WaitForExit(exit_code)) {
-    PLOG(DFATAL) << "Failed to get exit code from existing installer";
-    *exit_code = WAIT_FOR_EXISTING_FAILED;
-  } else {
-    VLOG(1) << "Existing installer returned exit code " << *exit_code;
-  }
-  return true;
-}
-
 // Returns true if product |type| cam be meaningfully installed without the
 // --multi-install flag.
 bool SupportsSingleInstall(BrowserDistribution::Type type) {
@@ -265,65 +212,6 @@
   return ok != FALSE;
 }
 
-bool GetExistingHigherInstaller(
-    const InstallationState& original_state,
-    bool system_install,
-    const Version& installer_version,
-    base::FilePath* setup_exe) {
-  DCHECK(setup_exe);
-  bool trying_single_browser = false;
-  const ProductState* existing_state =
-      original_state.GetProductState(system_install,
-                                     BrowserDistribution::CHROME_BINARIES);
-  if (!existing_state) {
-    // The binaries aren't installed, but perhaps a single-install Chrome is.
-    trying_single_browser = true;
-    existing_state =
-        original_state.GetProductState(system_install,
-                                       BrowserDistribution::CHROME_BROWSER);
-  }
-
-  if (!existing_state ||
-      existing_state->version().CompareTo(installer_version) <= 0) {
-    return false;
-  }
-
-  *setup_exe = existing_state->GetSetupPath();
-
-  VLOG_IF(1, !setup_exe->empty()) << "Found a higher version of "
-      << (trying_single_browser ? "single-install Chrome."
-          : "multi-install Chrome binaries.");
-
-  return !setup_exe->empty();
-}
-
-bool DeferToExistingInstall(const base::FilePath& setup_exe,
-                            const base::CommandLine& command_line,
-                            const InstallerState& installer_state,
-                            const base::FilePath& temp_path,
-                            InstallStatus* install_status) {
-  // Copy a master_preferences file if there is one.
-  base::FilePath prefs_source_path(command_line.GetSwitchValueNative(
-      switches::kInstallerData));
-  base::FilePath prefs_dest_path(installer_state.target_path().AppendASCII(
-      kDefaultMasterPrefs));
-  scoped_ptr<WorkItem> copy_prefs(WorkItem::CreateCopyTreeWorkItem(
-      prefs_source_path, prefs_dest_path, temp_path, WorkItem::ALWAYS,
-      base::FilePath()));
-  // There's nothing to rollback if the copy fails, so punt if so.
-  if (!copy_prefs->Do())
-    copy_prefs.reset();
-
-  int exit_code = 0;
-  if (!LaunchAndWaitForExistingInstall(setup_exe, command_line, &exit_code)) {
-    if (copy_prefs)
-      copy_prefs->Rollback();
-    return false;
-  }
-  *install_status = static_cast<InstallStatus>(exit_code);
-  return true;
-}
-
 // There are 4 disjoint cases => return values {false,true}:
 // (1) Product is being uninstalled => false.
 // (2) Product is being installed => true.
diff --git a/chrome/installer/setup/setup_util.h b/chrome/installer/setup/setup_util.h
index 8dc9c60..631887ab 100644
--- a/chrome/installer/setup/setup_util.h
+++ b/chrome/installer/setup/setup_util.h
@@ -70,25 +70,6 @@
 bool DeleteFileFromTempProcess(const base::FilePath& path,
                                uint32 delay_before_delete_ms);
 
-// Returns true and populates |setup_exe| with the path to an existing product
-// installer if one is found that is newer than the currently running installer
-// (|installer_version|).
-bool GetExistingHigherInstaller(const InstallationState& original_state,
-                                bool system_install,
-                                const base::Version& installer_version,
-                                base::FilePath* setup_exe);
-
-// Invokes the pre-existing |setup_exe| to handle the current operation (as
-// dictated by |command_line|). An installerdata file, if specified, is first
-// unconditionally copied into place so that it will be in effect in case the
-// invoked |setup_exe| runs the newly installed product prior to exiting.
-// Returns true if |setup_exe| was launched, false otherwise.
-bool DeferToExistingInstall(const base::FilePath& setup_exe,
-                            const base::CommandLine& command_line,
-                            const InstallerState& installer_state,
-                            const base::FilePath& temp_path,
-                            InstallStatus* install_status);
-
 // Returns true if the product |type| will be installed after the current
 // setup.exe instance have carried out installation / uninstallation, at
 // the level specified by |installer_state|.
diff --git a/chrome/installer/util/install_util.cc b/chrome/installer/util/install_util.cc
index 727d847..fe7d589 100644
--- a/chrome/installer/util/install_util.cc
+++ b/chrome/installer/util/install_util.cc
@@ -61,7 +61,6 @@
 const wchar_t kStageUnpacking[] = L"unpacking";
 const wchar_t kStageUpdatingChannels[] = L"updating_channels";
 const wchar_t kStageCreatingVisualManifest[] = L"creating_visual_manifest";
-const wchar_t kStageDeferringToHigherVersion[] = L"deferring_to_higher_version";
 const wchar_t kStageUninstallingBinaries[] = L"uninstalling_binaries";
 const wchar_t kStageUninstallingChromeFrame[] = L"uninstalling_chrome_frame";
 
@@ -84,7 +83,7 @@
   kStageFinishing,
   kStageConfiguringAutoLaunch,
   kStageCreatingVisualManifest,
-  kStageDeferringToHigherVersion,
+  nullptr,      // Deprecated with InstallerStage(18) in util_constants.h.
   kStageUninstallingBinaries,
   kStageUninstallingChromeFrame,
 };
diff --git a/chrome/installer/util/util_constants.h b/chrome/installer/util/util_constants.h
index 389da42..20742f19 100644
--- a/chrome/installer/util/util_constants.h
+++ b/chrome/installer/util/util_constants.h
@@ -73,7 +73,7 @@
   // INSTALL_OF_GOOGLE_UPDATE_FAILED = 46,
   INVALID_STATE_FOR_OPTION = 47,  // A non-install option was called with an
                                   // invalid installer state.
-  WAIT_FOR_EXISTING_FAILED = 48,  // OS error waiting for existing setup.exe.
+  // WAIT_FOR_EXISTING_FAILED = 48,
   PATCH_INVALID_ARGUMENTS = 49,  // The arguments of --patch were missing or
                                  // they were invalid for any reason.
   DIFF_PATCH_SOURCE_MISSING = 50,  // No previous version archive found for
@@ -102,28 +102,28 @@
 // values to the end (before NUM_STAGES) and update the compile assert below
 // to assert on the last value added.
 enum InstallerStage {
-  NO_STAGE,                    // 0: No stage to report.
-  PRECONDITIONS,               // 1: Evaluating pre-install conditions.
-  UNCOMPRESSING,               // 2: Uncompressing chrome.packed.7z.
-  ENSEMBLE_PATCHING,           // 3: Patching chrome.7z using courgette.
-  BINARY_PATCHING,             // 4: Patching chrome.7z using bspatch.
-  UNPACKING,                   // 5: Unpacking chrome.7z.
-  BUILDING,                    // 6: Building the install work item list.
-  EXECUTING,                   // 7: Executing the install work item list.
-  ROLLINGBACK,                 // 8: Rolling-back the install work item list.
-  REFRESHING_POLICY,           // 9: Refreshing the elevation policy.
-  UPDATING_CHANNELS,           // 10: Updating channel information.
-  COPYING_PREFERENCES_FILE,    // 11: Copying preferences file.
-  CREATING_SHORTCUTS,          // 12: Creating shortcuts.
-  REGISTERING_CHROME,          // 13: Performing Chrome registration.
-  REMOVING_OLD_VERSIONS,       // 14: Deleting old version directories.
-  FINISHING,                   // 15: Finishing the install.
-  CONFIGURE_AUTO_LAUNCH,       // 16: Configuring Chrome to auto-launch.
-  CREATING_VISUAL_MANIFEST,    // 17: Creating VisualElementsManifest.xml
-  DEFERRING_TO_HIGHER_VERSION,  // 18: Deferring to an installed higher version.
-  UNINSTALLING_BINARIES,       // 19: Uninstalling unused binaries.
-  UNINSTALLING_CHROME_FRAME,   // 20: Uninstalling multi-install Chrome Frame.
-  NUM_STAGES                   // 21: The number of stages.
+  NO_STAGE = 0,                    // No stage to report.
+  PRECONDITIONS = 1,               // Evaluating pre-install conditions.
+  UNCOMPRESSING = 2,               // Uncompressing chrome.packed.7z.
+  ENSEMBLE_PATCHING = 3,           // Patching chrome.7z using courgette.
+  BINARY_PATCHING = 4,             // Patching chrome.7z using bspatch.
+  UNPACKING = 5,                   // Unpacking chrome.7z.
+  BUILDING = 6,                    // Building the install work item list.
+  EXECUTING = 7,                   // Executing the install work item list.
+  ROLLINGBACK = 8,                 // Rolling-back the install work item list.
+  REFRESHING_POLICY = 9,           // Refreshing the elevation policy.
+  UPDATING_CHANNELS = 10,          // Updating channel information.
+  COPYING_PREFERENCES_FILE = 11,   // Copying preferences file.
+  CREATING_SHORTCUTS = 12,         // Creating shortcuts.
+  REGISTERING_CHROME = 13,         // Performing Chrome registration.
+  REMOVING_OLD_VERSIONS = 14,      // Deleting old version directories.
+  FINISHING = 15,                  // Finishing the install.
+  CONFIGURE_AUTO_LAUNCH = 16,      // Configuring Chrome to auto-launch.
+  CREATING_VISUAL_MANIFEST = 17,   // Creating VisualElementsManifest.xml
+  // DEFERRING_TO_HIGHER_VERSION = 18,
+  UNINSTALLING_BINARIES = 19,      // Uninstalling unused binaries.
+  UNINSTALLING_CHROME_FRAME = 20,  // Uninstalling multi-install Chrome Frame.
+  NUM_STAGES                       // The number of stages.
 };
 
 // When we start reporting the numerical values from the enum, the order
diff --git a/chrome/third_party/mozilla_security_manager/nsNSSCertHelper.cpp b/chrome/third_party/mozilla_security_manager/nsNSSCertHelper.cpp
index b1507ff..7fdd628 100644
--- a/chrome/third_party/mozilla_security_manager/nsNSSCertHelper.cpp
+++ b/chrome/third_party/mozilla_security_manager/nsNSSCertHelper.cpp
@@ -53,8 +53,9 @@
 #include "chrome/common/net/x509_certificate_model.h"
 #include "crypto/scoped_nss_types.h"
 #include "chrome/grit/generated_resources.h"
+#include "net/base/address_family.h"
+#include "net/base/ip_address_number.h"
 #include "net/base/ip_endpoint.h"
-#include "net/base/net_util.h"
 #include "ui/base/l10n/l10n_util.h"
 
 #if !defined(CERTDB_TERMINAL_RECORD)
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 77025fc..cb34a370 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -313,7 +313,6 @@
     "//components/compression:unit_tests",
     "//components/content_settings/core/common",
     "//components/data_usage/core:unit_tests",
-    "//components/data_use_measurement/content:unit_tests",
     "//components/google/core/browser:unit_tests",
     "//components/net_log:unit_tests",
     "//components/search:unit_tests",
@@ -333,6 +332,7 @@
   if (!is_ios) {
     deps += [
       "//components/certificate_transparency:unit_tests",
+      "//components/data_use_measurement/content:unit_tests",
       "//components/enhanced_bookmarks:unit_tests",
       "//components/error_page/renderer:unit_tests",
       "//components/guest_view/browser:unit_tests",
diff --git a/components/autofill/content/browser/content_autofill_driver_factory.cc b/components/autofill/content/browser/content_autofill_driver_factory.cc
index 565c58b..d19bd574 100644
--- a/components/autofill/content/browser/content_autofill_driver_factory.cc
+++ b/components/autofill/content/browser/content_autofill_driver_factory.cc
@@ -57,7 +57,11 @@
                  base::Unretained(this)));
 }
 
-ContentAutofillDriverFactory::~ContentAutofillDriverFactory() {}
+ContentAutofillDriverFactory::~ContentAutofillDriverFactory() {
+  STLDeleteContainerPairSecondPointers(frame_driver_map_.begin(),
+                                       frame_driver_map_.end());
+  frame_driver_map_.clear();
+}
 
 ContentAutofillDriver* ContentAutofillDriverFactory::DriverForFrame(
     content::RenderFrameHost* render_frame_host) {
@@ -68,19 +72,19 @@
 bool ContentAutofillDriverFactory::OnMessageReceived(
     const IPC::Message& message,
     content::RenderFrameHost* render_frame_host) {
-  return frame_driver_map_.find(render_frame_host)
-      ->second->HandleMessage(message);
+  return frame_driver_map_[render_frame_host]->HandleMessage(message);
 }
 
 void ContentAutofillDriverFactory::RenderFrameCreated(
     content::RenderFrameHost* render_frame_host) {
   // RenderFrameCreated is called more than once for the main frame.
-  if (!ContainsKey(frame_driver_map_, render_frame_host))
+  if (!frame_driver_map_[render_frame_host])
     CreateDriverForFrame(render_frame_host);
 }
 
 void ContentAutofillDriverFactory::RenderFrameDeleted(
     content::RenderFrameHost* render_frame_host) {
+  delete frame_driver_map_[render_frame_host];
   frame_driver_map_.erase(render_frame_host);
 }
 
@@ -88,7 +92,7 @@
     content::RenderFrameHost* rfh,
     const content::LoadCommittedDetails& details,
     const content::FrameNavigateParams& params) {
-  frame_driver_map_.find(rfh)->second->DidNavigateFrame(details, params);
+  frame_driver_map_[rfh]->DidNavigateFrame(details, params);
 }
 
 void ContentAutofillDriverFactory::NavigationEntryCommitted(
@@ -102,11 +106,9 @@
 
 void ContentAutofillDriverFactory::CreateDriverForFrame(
     content::RenderFrameHost* render_frame_host) {
-  DCHECK(!ContainsKey(frame_driver_map_, render_frame_host));
-  frame_driver_map_.set(
-      render_frame_host,
-      make_scoped_ptr(new ContentAutofillDriver(
-          render_frame_host, client_, app_locale_, enable_download_manager_)));
+  DCHECK(!frame_driver_map_[render_frame_host]);
+  frame_driver_map_[render_frame_host] = new ContentAutofillDriver(
+      render_frame_host, client_, app_locale_, enable_download_manager_);
 }
 
 }  // namespace autofill
diff --git a/components/autofill/content/browser/content_autofill_driver_factory.h b/components/autofill/content/browser/content_autofill_driver_factory.h
index 95f8df6..c0b1aa1 100644
--- a/components/autofill/content/browser/content_autofill_driver_factory.h
+++ b/components/autofill/content/browser/content_autofill_driver_factory.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/containers/scoped_ptr_map.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/supports_user_data.h"
 #include "components/autofill/content/browser/request_autocomplete_manager.h"
@@ -75,8 +74,7 @@
   std::string app_locale_;
   AutofillManager::AutofillDownloadManagerState enable_download_manager_;
 
-  base::ScopedPtrMap<content::RenderFrameHost*,
-                     scoped_ptr<ContentAutofillDriver>> frame_driver_map_;
+  std::map<content::RenderFrameHost*, ContentAutofillDriver*> frame_driver_map_;
 };
 
 }  // namespace autofill
diff --git a/components/components_tests.gyp b/components/components_tests.gyp
index 11ab790..198e0765 100644
--- a/components/components_tests.gyp
+++ b/components/components_tests.gyp
@@ -429,6 +429,7 @@
       'password_manager/core/browser/facet_manager_unittest.cc',
       'password_manager/core/browser/import/csv_reader_unittest.cc',
       'password_manager/core/browser/log_router_unittest.cc',
+      'password_manager/core/browser/login_database_ios_unittest.cc',
       'password_manager/core/browser/login_database_unittest.cc',
       'password_manager/core/browser/login_model_unittest.cc',
       'password_manager/core/browser/mock_affiliated_match_helper.cc',
diff --git a/components/cronet.gypi b/components/cronet.gypi
index e4bed68..71d2794 100644
--- a/components/cronet.gypi
+++ b/components/cronet.gypi
@@ -11,7 +11,6 @@
           'target_name': 'cronet_jni_headers',
           'type': 'none',
           'sources': [
-            'cronet/android/java/src/org/chromium/net/CronetHistogramManager.java',
             'cronet/android/java/src/org/chromium/net/CronetLibraryLoader.java',
             'cronet/android/java/src/org/chromium/net/CronetUploadDataStream.java',
             'cronet/android/java/src/org/chromium/net/CronetUrlRequest.java',
@@ -247,7 +246,6 @@
               '**/ChromiumUrlRequestError.java',
               '**/ChromiumUrlRequestFactory.java',
               '**/ChromiumUrlRequestPriority.java',
-              '**/CronetHistogramManager.java',
               '**/CronetResponseInfo.java',
               '**/CronetLibraryLoader.java',
               '**/CronetUploadDataStream.java',
diff --git a/components/cronet/android/api/src/org/chromium/net/CronetEngine.java b/components/cronet/android/api/src/org/chromium/net/CronetEngine.java
index 29fd3f01..e6f3161 100644
--- a/components/cronet/android/api/src/org/chromium/net/CronetEngine.java
+++ b/components/cronet/android/api/src/org/chromium/net/CronetEngine.java
@@ -486,6 +486,30 @@
     public abstract void stopNetLog();
 
     /**
+     * Returns differences in metrics collected by Cronet since the last call to
+     * {@link #getGlobalMetricsDeltas}.
+     * <p>
+     * Cronet collects these metrics globally. This means deltas returned by
+     * {@code getGlobalMetricsDeltas()} will include measurements of requests
+     * processed by other {@link CronetEngine} instances. Since this function
+     * returns differences in metrics collected since the last call, and these
+     * metrics are collected globally, a call to any {@code CronetEngine}
+     * instance's {@code getGlobalMetricsDeltas()} method will affect the deltas
+     * returned by any other {@code CronetEngine} instance's
+     * {@code getGlobalMetricsDeltas()}.
+     * <p>
+     * Cronet starts collecting these metrics after the first call to
+     * {@code getGlobalMetricsDeltras()}, so the first call returns no
+     * useful data as no metrics have yet been collected.
+     *
+     * @return differences in metrics collected by Cronet, since the last call
+     *         to {@code getGlobalMetricsDeltas()}, serialized as a
+     *         <a href=https://developers.google.com/protocol-buffers>protobuf
+     *         </a>.
+     */
+    public abstract byte[] getGlobalMetricsDeltas();
+
+    /**
      * Enables the network quality estimator, which collects and reports
      * measurements of round trip time (RTT) and downstream throughput at
      * various layers of the network stack. After enabling the estimator,
diff --git a/components/cronet/android/api/src/org/chromium/net/HistogramManager.java b/components/cronet/android/api/src/org/chromium/net/HistogramManager.java
deleted file mode 100644
index 63bc673..0000000
--- a/components/cronet/android/api/src/org/chromium/net/HistogramManager.java
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.net;
-
-import java.lang.reflect.Constructor;
-
-/**
- * Controls user metrics analysis (UMA) histograms.
- */
-public abstract class HistogramManager {
-    private static final String CRONET_HISTOGRAM_MANAGER =
-            "org.chromium.net.CronetHistogramManager";
-
-    // Don't expose public constructor. Use createHistogramManager() instead.
-    HistogramManager() {}
-
-    /**
-     * Get histogram deltas serialized as
-     * <a href=https://developers.google.com/protocol-buffers>protobuf</a>.
-     */
-    public abstract byte[] getHistogramDeltas();
-
-    /**
-     * Creates Histogram Manager if native library is loaded, returns {@code null} if not.
-     */
-    public static HistogramManager createHistogramManager() {
-        HistogramManager histogramManager = null;
-        try {
-            Class<? extends HistogramManager> histogramManagerClass =
-                    HistogramManager.class.getClassLoader()
-                            .loadClass(CRONET_HISTOGRAM_MANAGER)
-                            .asSubclass(HistogramManager.class);
-            Constructor<? extends HistogramManager> constructor =
-                    histogramManagerClass.getConstructor();
-            histogramManager = constructor.newInstance();
-        } catch (ClassNotFoundException e) {
-            // Leave as null.
-        } catch (Exception e) {
-            throw new IllegalStateException(
-                    "Cannot instantiate: " + CRONET_HISTOGRAM_MANAGER,
-                    e);
-        }
-        return histogramManager;
-    }
-}
diff --git a/components/cronet/android/cronet_histogram_manager.cc b/components/cronet/android/cronet_histogram_manager.cc
deleted file mode 100644
index ca7c3f0..0000000
--- a/components/cronet/android/cronet_histogram_manager.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/cronet/android/cronet_histogram_manager.h"
-
-#include <string>
-#include <vector>
-
-#include "base/android/jni_array.h"
-#include "base/metrics/statistics_recorder.h"
-#include "components/cronet/histogram_manager.h"
-
-#include "jni/CronetHistogramManager_jni.h"
-
-namespace cronet {
-
-// Explicitly register static JNI functions.
-bool CronetHistogramManagerRegisterJni(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
-static void EnsureInitialized(JNIEnv* env,
-                              const JavaParamRef<jobject>& jcaller) {
-  base::StatisticsRecorder::Initialize();
-}
-
-static ScopedJavaLocalRef<jbyteArray> GetHistogramDeltas(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& jcaller) {
-  std::vector<uint8> data;
-  if (!HistogramManager::GetInstance()->GetDeltas(&data))
-    return ScopedJavaLocalRef<jbyteArray>();
-  return base::android::ToJavaByteArray(env, &data[0], data.size());
-}
-
-}  // namespace cronet
diff --git a/components/cronet/android/cronet_histogram_manager.h b/components/cronet/android/cronet_histogram_manager.h
deleted file mode 100644
index 1d298e1..0000000
--- a/components/cronet/android/cronet_histogram_manager.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_CRONET_ANDROID_CRONET_HISTOGRAM_MANAGER_H_
-#define COMPONENTS_CRONET_ANDROID_CRONET_HISTOGRAM_MANAGER_H_
-
-#include <jni.h>
-
-namespace cronet {
-
-bool CronetHistogramManagerRegisterJni(JNIEnv* env);
-
-}  // namespace cronet
-
-#endif  // COMPONENTS_CRONET_ANDROID_CRONET_HISTOGRAM_MANAGER_H_
diff --git a/components/cronet/android/cronet_library_loader.cc b/components/cronet/android/cronet_library_loader.cc
index d0021a83..fec9360 100644
--- a/components/cronet/android/cronet_library_loader.cc
+++ b/components/cronet/android/cronet_library_loader.cc
@@ -17,7 +17,6 @@
 #include "base/message_loop/message_loop.h"
 #include "components/cronet/android/chromium_url_request.h"
 #include "components/cronet/android/chromium_url_request_context.h"
-#include "components/cronet/android/cronet_histogram_manager.h"
 #include "components/cronet/android/cronet_upload_data_stream_adapter.h"
 #include "components/cronet/android/cronet_url_request_adapter.h"
 #include "components/cronet/android/cronet_url_request_context_adapter.h"
@@ -41,7 +40,6 @@
     {"BaseAndroid", base::android::RegisterJni},
     {"ChromiumUrlRequest", ChromiumUrlRequestRegisterJni},
     {"ChromiumUrlRequestContext", ChromiumUrlRequestContextRegisterJni},
-    {"CronetHistogramManager", CronetHistogramManagerRegisterJni},
     {"CronetLibraryLoader", RegisterNativesImpl},
     {"CronetUploadDataStreamAdapter", CronetUploadDataStreamAdapterRegisterJni},
     {"CronetUrlRequestAdapter", CronetUrlRequestAdapterRegisterJni},
diff --git a/components/cronet/android/cronet_url_request_context_adapter.cc b/components/cronet/android/cronet_url_request_context_adapter.cc
index 37a18ce..67dad4e 100644
--- a/components/cronet/android/cronet_url_request_context_adapter.cc
+++ b/components/cronet/android/cronet_url_request_context_adapter.cc
@@ -7,6 +7,7 @@
 #include <map>
 
 #include "base/android/jni_android.h"
+#include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
 #include "base/bind.h"
 #include "base/files/file_util.h"
@@ -14,6 +15,7 @@
 #include "base/logging.h"
 #include "base/memory/scoped_vector.h"
 #include "base/message_loop/message_loop.h"
+#include "base/metrics/statistics_recorder.h"
 #include "base/prefs/pref_filter.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
@@ -21,6 +23,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/time/time.h"
 #include "base/values.h"
+#include "components/cronet/histogram_manager.h"
 #include "components/cronet/url_request_context_config.h"
 #include "jni/CronetUrlRequestContext_jni.h"
 #include "net/base/external_estimate_provider.h"
@@ -538,4 +541,14 @@
   return old_log_level;
 }
 
+static ScopedJavaLocalRef<jbyteArray> GetHistogramDeltas(
+    JNIEnv* env,
+    const JavaParamRef<jclass>& jcaller) {
+  base::StatisticsRecorder::Initialize();
+  std::vector<uint8> data;
+  if (!HistogramManager::GetInstance()->GetDeltas(&data))
+    return ScopedJavaLocalRef<jbyteArray>();
+  return base::android::ToJavaByteArray(env, &data[0], data.size());
+}
+
 }  // namespace cronet
diff --git a/components/cronet/android/java/src/org/chromium/net/CronetHistogramManager.java b/components/cronet/android/java/src/org/chromium/net/CronetHistogramManager.java
deleted file mode 100644
index 702f98ee..0000000
--- a/components/cronet/android/java/src/org/chromium/net/CronetHistogramManager.java
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.net;
-
-import org.chromium.base.annotations.JNINamespace;
-
-/**
- * The implementation of {@link HistogramManager}. Controls UMA histograms.
- */
-@JNINamespace("cronet")
-final class CronetHistogramManager extends HistogramManager {
-    public CronetHistogramManager() {
-        nativeEnsureInitialized();
-    }
-
-    @Override
-    public byte[] getHistogramDeltas() {
-        return nativeGetHistogramDeltas();
-    }
-
-    private native byte[] nativeGetHistogramDeltas();
-
-    private native void nativeEnsureInitialized();
-}
diff --git a/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java b/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java
index 6a315f7..227bd41 100644
--- a/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java
+++ b/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java
@@ -179,6 +179,13 @@
         }
     }
 
+    // This method is intentionally non-static to ensure Cronet native library
+    // is loaded by class constructor.
+    @Override
+    public byte[] getGlobalMetricsDeltas() {
+        return nativeGetHistogramDeltas();
+    }
+
     @Override
     public void enableNetworkQualityEstimator(Executor executor) {
         enableNetworkQualityEstimatorForTesting(false, false, executor);
@@ -397,6 +404,8 @@
 
     private static native int nativeSetMinLogLevel(int loggingLevel);
 
+    private static native byte[] nativeGetHistogramDeltas();
+
     @NativeClassQualifiedName("CronetURLRequestContextAdapter")
     private native void nativeDestroy(long nativePtr);
 
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
index 9b023ac7f..1132c069 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
@@ -18,6 +18,7 @@
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileReader;
+import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.NoSuchElementException;
 import java.util.concurrent.Executor;
@@ -773,4 +774,21 @@
         secondEngine.shutdown();
         thirdEngine.shutdown();
     }
+
+    @SmallTest
+    @Feature({"Cronet"})
+    public void testGetGlobalMetricsDeltas() throws Exception {
+        mTestFramework = startCronetTestFramework();
+
+        byte delta1[] = mTestFramework.mCronetEngine.getGlobalMetricsDeltas();
+
+        TestUrlRequestCallback callback = new TestUrlRequestCallback();
+        UrlRequest.Builder builder = new UrlRequest.Builder(
+                TEST_URL, callback, callback.getExecutor(), mTestFramework.mCronetEngine);
+        builder.build().start();
+        callback.blockForDone();
+        byte delta2[] = mTestFramework.mCronetEngine.getGlobalMetricsDeltas();
+        assertTrue(delta2.length != 0);
+        assertFalse(Arrays.equals(delta1, delta2));
+    }
 }
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/HistogramManagerTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/HistogramManagerTest.java
deleted file mode 100644
index 2dd53062..0000000
--- a/components/cronet/android/test/javatests/src/org/chromium/net/HistogramManagerTest.java
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.net;
-
-import android.test.suitebuilder.annotation.SmallTest;
-
-import org.chromium.base.test.util.Feature;
-
-import java.util.Arrays;
-
-/**
- * Test HistogramManager.
- */
-public class HistogramManagerTest extends CronetTestBase {
-    // URLs used for tests.
-    private static final String TEST_URL = "http://127.0.0.1:8000";
-
-    CronetTestFramework mTestFramework;
-
-    @SmallTest
-    @Feature({"Cronet"})
-    public void testHistogramManager() throws Exception {
-        mTestFramework = startCronetTestFramework();
-        byte delta1[] = mTestFramework.mHistogramManager.getHistogramDeltas();
-
-        TestUrlRequestCallback callback = new TestUrlRequestCallback();
-        UrlRequest.Builder builder = new UrlRequest.Builder(
-                TEST_URL, callback, callback.getExecutor(), mTestFramework.mCronetEngine);
-        builder.build().start();
-        callback.blockForDone();
-        byte delta2[] = mTestFramework.mHistogramManager.getHistogramDeltas();
-        assertTrue(delta2.length != 0);
-        assertFalse(Arrays.equals(delta1, delta2));
-    }
-}
diff --git a/components/cronet/android/test/src/org/chromium/net/CronetTestFramework.java b/components/cronet/android/test/src/org/chromium/net/CronetTestFramework.java
index 530c1dd..fbee5f92 100644
--- a/components/cronet/android/test/src/org/chromium/net/CronetTestFramework.java
+++ b/components/cronet/android/test/src/org/chromium/net/CronetTestFramework.java
@@ -66,7 +66,6 @@
     public URLStreamHandlerFactory mStreamHandlerFactory;
     public CronetEngine mCronetEngine;
     @SuppressWarnings("deprecation") HttpUrlRequestFactory mRequestFactory;
-    @SuppressFBWarnings("URF_UNREAD_FIELD") HistogramManager mHistogramManager;
 
     private final String[] mCommandLine;
     private final Context mContext;
@@ -129,7 +128,8 @@
             mStreamHandlerFactory = mCronetEngine.createURLStreamHandlerFactory();
         }
 
-        mHistogramManager = HistogramManager.createHistogramManager();
+        // Start collecting metrics.
+        mCronetEngine.getGlobalMetricsDeltas();
 
         if (LIBRARY_INIT_CRONET_ONLY.equals(initString)) {
             return;
diff --git a/components/cronet/cronet_static.gypi b/components/cronet/cronet_static.gypi
index f2dce0d1..cf62a0a 100644
--- a/components/cronet/cronet_static.gypi
+++ b/components/cronet/cronet_static.gypi
@@ -21,8 +21,6 @@
     'android/chromium_url_request_context.h',
     'android/chromium_url_request_error_list.h',
     'android/chromium_url_request_priority_list.h',
-    'android/cronet_histogram_manager.cc',
-    'android/cronet_histogram_manager.h',
     'android/cronet_in_memory_pref_store.cc',
     'android/cronet_in_memory_pref_store.h',
     'android/cronet_library_loader.cc',
diff --git a/components/devtools_service/BUILD.gn b/components/devtools_service/BUILD.gn
index 26ca66eb..67eccf5 100644
--- a/components/devtools_service/BUILD.gn
+++ b/components/devtools_service/BUILD.gn
@@ -4,10 +4,6 @@
 
 import("//mojo/public/mojo_application.gni")
 
-# We don't support building mojo apps in the component build.
-# Currently this app is used by Mandoline only.
-assert(!is_component_build)
-
 source_set("lib") {
   sources = [
     "devtools_agent_host.cc",
diff --git a/components/filesystem/BUILD.gn b/components/filesystem/BUILD.gn
index 028f02fc..3159f2f 100644
--- a/components/filesystem/BUILD.gn
+++ b/components/filesystem/BUILD.gn
@@ -40,7 +40,7 @@
     "//mojo/application/public/cpp",
     "//mojo/common",
     "//mojo/environment:chromium",
-    "//mojo/platform_handle",
+    "//mojo/platform_handle:for_shared_library",
     "//third_party/mojo/src/mojo/public/cpp/bindings",
     "//third_party/mojo/src/mojo/public/cpp/system",
   ]
@@ -62,7 +62,7 @@
     "//base",
     "//components/filesystem/public/interfaces",
     "//mojo/application/public/cpp:test_support",
-    "//mojo/platform_handle",
+    "//mojo/platform_handle:for_shared_library",
     "//third_party/mojo/src/mojo/public/cpp/bindings",
   ]
 
diff --git a/components/font_service/public/cpp/BUILD.gn b/components/font_service/public/cpp/BUILD.gn
index 31458096..52359b7 100644
--- a/components/font_service/public/cpp/BUILD.gn
+++ b/components/font_service/public/cpp/BUILD.gn
@@ -19,7 +19,7 @@
     "//mojo/application/public/interfaces",
     "//mojo/common",
     "//mojo/message_pump",
-    "//mojo/platform_handle:defs",
+    "//mojo/platform_handle",
     "//skia",
     "//third_party/mojo/src/mojo/public/cpp/bindings",
     "//third_party/mojo/src/mojo/public/cpp/system",
diff --git a/components/html_viewer/BUILD.gn b/components/html_viewer/BUILD.gn
index b1ed623..4fc54ed 100644
--- a/components/html_viewer/BUILD.gn
+++ b/components/html_viewer/BUILD.gn
@@ -39,10 +39,12 @@
     "$root_gen_dir/blink/public/resources/blink_image_resources_100_percent.pak",
     "$root_gen_dir/blink/public/resources/blink_resources.pak",
     "$root_gen_dir/components/html_viewer/html_viewer_resources.pak",
-    "$root_gen_dir/ui/resources/ui_resources_100_percent.pak",
     "$root_gen_dir/ui/strings/app_locale_settings_en-US.pak",
     "$root_gen_dir/ui/strings/ui_strings_en-US.pak",
   ]
+  if (!is_component_build) {
+    sources += [ "$root_gen_dir/ui/resources/ui_resources_100_percent.pak" ]
+  }
   output = "$root_out_dir/html_viewer.pak"
   deps = [
     ":copy_html_viewer_resources",
@@ -171,6 +173,7 @@
     "//media",
     "//media/blink",
     "//media/mojo",
+    "//media:shared_memory_support",
     "//mojo/application/public/cpp",
     "//mojo/application/public/interfaces",
     "//mojo/common",
@@ -238,7 +241,6 @@
     ":pak",
     "//base",
     "//mojo/application/public/cpp:sources",
-    "//third_party/mojo/src/mojo/public/c/system:for_shared_library",
   ]
   resources = [ "$root_out_dir/html_viewer.pak" ]
 
diff --git a/components/html_viewer/blink_platform_impl.cc b/components/html_viewer/blink_platform_impl.cc
index b8eb54f..f7a13723 100644
--- a/components/html_viewer/blink_platform_impl.cc
+++ b/components/html_viewer/blink_platform_impl.cc
@@ -75,8 +75,7 @@
     : global_state_(global_state),
       app_(app),
       main_thread_task_runner_(renderer_scheduler->DefaultTaskRunner()),
-      main_thread_(new scheduler::WebThreadImplForRendererScheduler(
-          renderer_scheduler)) {
+      main_thread_(renderer_scheduler->CreateMainThread()) {
   if (app) {
     mojo::URLRequestPtr request(mojo::URLRequest::New());
     request->url = mojo::String::From("mojo:network_service");
diff --git a/components/html_viewer/blink_platform_impl.h b/components/html_viewer/blink_platform_impl.h
index 267674a..a0ceae4 100644
--- a/components/html_viewer/blink_platform_impl.h
+++ b/components/html_viewer/blink_platform_impl.h
@@ -104,7 +104,7 @@
   GlobalState* global_state_;
   mojo::ApplicationImpl* app_;
   scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
-  scoped_ptr<scheduler::WebThreadImplForRendererScheduler> main_thread_;
+  scoped_ptr<blink::WebThread> main_thread_;
   base::ThreadLocalStorage::Slot current_thread_slot_;
   cc_blink::WebCompositorSupportImpl compositor_support_;
   WebThemeEngineImpl theme_engine_;
diff --git a/components/html_viewer/global_state.cc b/components/html_viewer/global_state.cc
index 37e5c49..a0bb8be 100644
--- a/components/html_viewer/global_state.cc
+++ b/components/html_viewer/global_state.cc
@@ -143,28 +143,34 @@
       0u);
 #endif
   blink::initialize(blink_platform_.get());
-  base::i18n::InitializeICUWithFileDescriptor(
-      resource_loader_.GetICUFile().TakePlatformFile(),
-      base::MemoryMappedFile::Region::kWholeFile);
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  base::File pak_file = resource_loader_.ReleaseFile(kResourceResourcesPak);
 
-  ui::RegisterPathProvider();
+  bool initialize_icu_and_ui = true;
+#if defined(COMPONENT_BUILD)
+  if (command_line->HasSwitch("single-process"))
+    initialize_icu_and_ui = false;
+#endif
+  if (initialize_icu_and_ui) {
+    base::i18n::InitializeICUWithFileDescriptor(
+        resource_loader_.GetICUFile().TakePlatformFile(),
+        base::MemoryMappedFile::Region::kWholeFile);
+    ui::RegisterPathProvider();
+    base::File pak_file_2 = pak_file.Duplicate();
+    ui::ResourceBundle::InitSharedInstanceWithPakFileRegion(
+      pak_file_2.Pass(), base::MemoryMappedFile::Region::kWholeFile);
+  }
 
   mojo::logging::InitLogging();
 
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-
   if (command_line->HasSwitch(kDisableEncryptedMedia))
     blink::WebRuntimeFeatures::enableEncryptedMedia(false);
 
   blink_settings_->Init();
 
-  base::File pak_file = resource_loader_.ReleaseFile(kResourceResourcesPak);
-  base::File pak_file_2 = pak_file.Duplicate();
-  ui::ResourceBundle::InitSharedInstanceWithPakFileRegion(
-      pak_file.Pass(), base::MemoryMappedFile::Region::kWholeFile);
   // TODO(sky): why is this always using 100?
   ui::ResourceBundle::GetSharedInstance().AddDataPackFromFile(
-      pak_file_2.Pass(), ui::SCALE_FACTOR_100P);
+      pak_file.Pass(), ui::SCALE_FACTOR_100P);
 
   compositor_thread_.Start();
 
diff --git a/components/html_viewer/web_layer_tree_view_impl.cc b/components/html_viewer/web_layer_tree_view_impl.cc
index c5e9850..92e10b6 100644
--- a/components/html_viewer/web_layer_tree_view_impl.cc
+++ b/components/html_viewer/web_layer_tree_view_impl.cc
@@ -15,6 +15,7 @@
 #include "components/mus/public/cpp/window.h"
 #include "mojo/converters/surfaces/surfaces_type_converters.h"
 #include "third_party/WebKit/public/web/WebWidget.h"
+#include "third_party/mojo/src/mojo/public/c/gles2/gles2.h"
 #include "ui/gfx/buffer_types.h"
 
 namespace html_viewer {
diff --git a/components/invalidation/impl/gcm_network_channel.h b/components/invalidation/impl/gcm_network_channel.h
index 511088c..a68e35b3 100644
--- a/components/invalidation/impl/gcm_network_channel.h
+++ b/components/invalidation/impl/gcm_network_channel.h
@@ -46,7 +46,7 @@
 
 // GCMNetworkChannel is an implementation of SyncNetworkChannel that routes
 // messages through GCMService.
-class INVALIDATION_EXPORT_PRIVATE GCMNetworkChannel
+class INVALIDATION_EXPORT GCMNetworkChannel
     : public SyncNetworkChannel,
       public net::URLFetcherDelegate,
       public net::NetworkChangeNotifier::NetworkChangeObserver,
diff --git a/components/invalidation/impl/invalidation_notifier.h b/components/invalidation/impl/invalidation_notifier.h
index db53e92..17e27ce 100644
--- a/components/invalidation/impl/invalidation_notifier.h
+++ b/components/invalidation/impl/invalidation_notifier.h
@@ -34,7 +34,7 @@
 namespace syncer {
 
 // This class must live on the IO thread.
-class INVALIDATION_EXPORT_PRIVATE InvalidationNotifier
+class INVALIDATION_EXPORT InvalidationNotifier
     : public Invalidator,
       public SyncInvalidationListener::Delegate,
       public base::NonThreadSafe {
diff --git a/components/invalidation/impl/non_blocking_invalidator.h b/components/invalidation/impl/non_blocking_invalidator.h
index 22e7f4ee..23d535af 100644
--- a/components/invalidation/impl/non_blocking_invalidator.h
+++ b/components/invalidation/impl/non_blocking_invalidator.h
@@ -36,7 +36,7 @@
 typedef base::Callback<scoped_ptr<SyncNetworkChannel>(void)>
     NetworkChannelCreator;
 
-class INVALIDATION_EXPORT_PRIVATE NonBlockingInvalidator
+class INVALIDATION_EXPORT NonBlockingInvalidator
     : public Invalidator,
       public InvalidationStateTracker {
  public:
diff --git a/components/invalidation/impl/p2p_invalidator.h b/components/invalidation/impl/p2p_invalidator.h
index b7bc462..c8ae1b5 100644
--- a/components/invalidation/impl/p2p_invalidator.h
+++ b/components/invalidation/impl/p2p_invalidator.h
@@ -43,16 +43,16 @@
   LAST_NOTIFICATION_TARGET = NOTIFY_ALL
 };
 
-INVALIDATION_EXPORT_PRIVATE std::string P2PNotificationTargetToString(
+INVALIDATION_EXPORT std::string P2PNotificationTargetToString(
     P2PNotificationTarget target);
 
 // If |target_str| can't be parsed, assumes NOTIFY_SELF.
-INVALIDATION_EXPORT_PRIVATE P2PNotificationTarget
+INVALIDATION_EXPORT P2PNotificationTarget
 P2PNotificationTargetFromString(const std::string& target_str);
 
 // Helper notification data class that can be serialized to and
 // deserialized from a string.
-class INVALIDATION_EXPORT_PRIVATE P2PNotificationData {
+class INVALIDATION_EXPORT P2PNotificationData {
  public:
   // Initializes with an empty sender ID, target set to NOTIFY_SELF,
   // and empty changed types.
@@ -85,7 +85,7 @@
   ObjectIdInvalidationMap invalidation_map_;
 };
 
-class INVALIDATION_EXPORT_PRIVATE P2PInvalidator
+class INVALIDATION_EXPORT P2PInvalidator
     : public Invalidator,
       public NON_EXPORTED_BASE(notifier::PushClientObserver) {
  public:
diff --git a/components/invalidation/impl/push_client_channel.h b/components/invalidation/impl/push_client_channel.h
index 85a2fd3..d47cc49 100644
--- a/components/invalidation/impl/push_client_channel.h
+++ b/components/invalidation/impl/push_client_channel.h
@@ -22,7 +22,7 @@
 
 // A PushClientChannel is an implementation of NetworkChannel that
 // routes messages through a PushClient.
-class INVALIDATION_EXPORT_PRIVATE PushClientChannel
+class INVALIDATION_EXPORT PushClientChannel
     : public SyncNetworkChannel,
       public NON_EXPORTED_BASE(notifier::PushClientObserver) {
  public:
diff --git a/components/invalidation/impl/registration_manager.h b/components/invalidation/impl/registration_manager.h
index 3e6913f..0a3a9434 100644
--- a/components/invalidation/impl/registration_manager.h
+++ b/components/invalidation/impl/registration_manager.h
@@ -32,8 +32,7 @@
 // implementations include the syncer thread (both versions) and XMPP
 // retries.  The most sophisticated one is URLRequestThrottler; making
 // that generic should work for everyone.
-class INVALIDATION_EXPORT_PRIVATE RegistrationManager
-    : public base::NonThreadSafe {
+class INVALIDATION_EXPORT RegistrationManager : public base::NonThreadSafe {
  public:
   // Constants for exponential backoff (used by tests).
   static const int kInitialRegistrationDelaySeconds;
diff --git a/components/invalidation/impl/state_writer.h b/components/invalidation/impl/state_writer.h
index cb02c41..269098e 100644
--- a/components/invalidation/impl/state_writer.h
+++ b/components/invalidation/impl/state_writer.h
@@ -13,7 +13,7 @@
 
 namespace syncer {
 
-class INVALIDATION_EXPORT_PRIVATE StateWriter {
+class INVALIDATION_EXPORT StateWriter {
  public:
   virtual ~StateWriter() {}
 
diff --git a/components/invalidation/impl/sync_invalidation_listener.h b/components/invalidation/impl/sync_invalidation_listener.h
index 697c1a7..ad93cad3 100644
--- a/components/invalidation/impl/sync_invalidation_listener.h
+++ b/components/invalidation/impl/sync_invalidation_listener.h
@@ -40,7 +40,7 @@
 
 // SyncInvalidationListener is not thread-safe and lives on the sync
 // thread.
-class INVALIDATION_EXPORT_PRIVATE SyncInvalidationListener
+class INVALIDATION_EXPORT SyncInvalidationListener
     : public NON_EXPORTED_BASE(invalidation::InvalidationListener),
       public StateWriter,
       public SyncNetworkChannel::Observer,
@@ -54,7 +54,7 @@
       const invalidation::string&,
       invalidation::InvalidationListener*)> CreateInvalidationClientCallback;
 
-  class INVALIDATION_EXPORT_PRIVATE Delegate {
+  class INVALIDATION_EXPORT Delegate {
    public:
     virtual ~Delegate();
 
diff --git a/components/invalidation/impl/sync_system_resources.h b/components/invalidation/impl/sync_system_resources.h
index 5a6e8c93..5b4d119 100644
--- a/components/invalidation/impl/sync_system_resources.h
+++ b/components/invalidation/impl/sync_system_resources.h
@@ -85,7 +85,7 @@
 //  - notifying observers about network channel state change
 // Implementation of particular network protocol should implement
 // SendMessage and call NotifyStateChange and DeliverIncomingMessage.
-class INVALIDATION_EXPORT_PRIVATE SyncNetworkChannel
+class INVALIDATION_EXPORT SyncNetworkChannel
     : public NON_EXPORTED_BASE(invalidation::NetworkChannel) {
  public:
   class Observer {
@@ -213,7 +213,7 @@
   std::string cached_state_;
 };
 
-class INVALIDATION_EXPORT_PRIVATE SyncSystemResources
+class INVALIDATION_EXPORT SyncSystemResources
     : public NON_EXPORTED_BASE(invalidation::SystemResources) {
  public:
   SyncSystemResources(SyncNetworkChannel* sync_network_channel,
diff --git a/components/invalidation/public/invalidation_export.h b/components/invalidation/public/invalidation_export.h
index f41a06bb..8b41308 100644
--- a/components/invalidation/public/invalidation_export.h
+++ b/components/invalidation/public/invalidation_export.h
@@ -16,6 +16,5 @@
 // For now, we provide dummy definitions of these tags.
 
 #define INVALIDATION_EXPORT
-#define INVALIDATION_EXPORT_PRIVATE
 
 #endif  // COMPONENTS_INVALIDATION_PUBLIC_INVALIDATION_EXPORT_H_
diff --git a/components/mus/BUILD.gn b/components/mus/BUILD.gn
index 2466dea6..7001e29 100644
--- a/components/mus/BUILD.gn
+++ b/components/mus/BUILD.gn
@@ -83,4 +83,11 @@
     "//ui/platform_window:platform_impls",
     "//ui/platform_window:platform_window",
   ]
+
+  if (use_x11) {
+    public_configs = [ "//build/config/linux:x11" ]
+    public_deps = [
+      "//ui/events/platform/x11",
+    ]
+  }
 }
diff --git a/components/mus/example/window_type_launcher/BUILD.gn b/components/mus/example/window_type_launcher/BUILD.gn
index bdf6224..e1b2e2a 100644
--- a/components/mus/example/window_type_launcher/BUILD.gn
+++ b/components/mus/example/window_type_launcher/BUILD.gn
@@ -20,6 +20,7 @@
   deps = [
     ":window_type_launcher_resources",
     "//base",
+    "//base:base_static",
     "//mojo/application/public/cpp",
     "//mojo/application/public/interfaces",
     "//mojo/common:common_base",
@@ -29,7 +30,7 @@
     "//mojo/runner/child:lib",
     "//mojo/runner:init",
     "//skia",
-    "//third_party/mojo/src/mojo/edk/embedder",
+    "//third_party/mojo/src/mojo/edk/system",
     "//third_party/mojo/src/mojo/public/cpp/bindings",
     "//ui/aura",
     "//ui/gfx",
diff --git a/components/mus/gles2/BUILD.gn b/components/mus/gles2/BUILD.gn
index 9c0929f..e39037d23 100644
--- a/components/mus/gles2/BUILD.gn
+++ b/components/mus/gles2/BUILD.gn
@@ -34,8 +34,9 @@
     "//base",
     "//components/mus/public/interfaces",
     "//gpu/command_buffer/client",
+    "//gpu/command_buffer/common:gles2_utils",
     "//gpu/command_buffer/service",
-    "//gpu/config:config_sources",
+    "//gpu/config:config",
     "//mojo/converters/geometry",
     "//third_party/mojo/src/mojo/public/cpp/bindings",
     "//ui/mojo/geometry:interfaces",
@@ -45,9 +46,9 @@
   ]
 
   if (is_android) {
-    deps += [ "//mojo/platform_handle:defs" ]
+    deps += [ "//mojo/platform_handle:platform_handle_impl" ]
   } else {
-    deps += [ "//mojo/platform_handle" ]
+    deps += [ "//mojo/platform_handle:for_shared_library" ]
   }
 
   include_dirs = [ "../.." ]
@@ -73,7 +74,7 @@
     "//components/mus/public/interfaces",
     "//gpu/command_buffer/common",
     "//gpu/command_buffer/client",
-    "//gpu/config:config_sources",
+    "//gpu/config:config",
     "//third_party/mojo/src/mojo/public/cpp/bindings",
     "//third_party/mojo/src/mojo/public/cpp/system",
     "//ui/gfx",
diff --git a/components/mus/gles2/mojo_gpu_memory_buffer_manager.cc b/components/mus/gles2/mojo_gpu_memory_buffer_manager.cc
index 5de16a5..1f5c0845 100644
--- a/components/mus/gles2/mojo_gpu_memory_buffer_manager.cc
+++ b/components/mus/gles2/mojo_gpu_memory_buffer_manager.cc
@@ -35,9 +35,9 @@
   return MojoGpuMemoryBufferImpl::FromClientBuffer(buffer);
 }
 
-void MojoGpuMemoryBufferManager::SetDestructionSyncPoint(
+void MojoGpuMemoryBufferManager::SetDestructionSyncToken(
     gfx::GpuMemoryBuffer* buffer,
-    uint32 sync_point) {
+    const gpu::SyncToken& sync_token) {
   NOTIMPLEMENTED();
 }
 
diff --git a/components/mus/gles2/mojo_gpu_memory_buffer_manager.h b/components/mus/gles2/mojo_gpu_memory_buffer_manager.h
index b44c84c..6d4e235 100644
--- a/components/mus/gles2/mojo_gpu_memory_buffer_manager.h
+++ b/components/mus/gles2/mojo_gpu_memory_buffer_manager.h
@@ -25,8 +25,8 @@
       gfx::BufferFormat format) override;
   gfx::GpuMemoryBuffer* GpuMemoryBufferFromClientBuffer(
       ClientBuffer buffer) override;
-  void SetDestructionSyncPoint(gfx::GpuMemoryBuffer* buffer,
-                               uint32 sync_point) override;
+  void SetDestructionSyncToken(gfx::GpuMemoryBuffer* buffer,
+                               const gpu::SyncToken& sync_token) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MojoGpuMemoryBufferManager);
diff --git a/components/mus/public/cpp/BUILD.gn b/components/mus/public/cpp/BUILD.gn
index f4deb64..69712a0d 100644
--- a/components/mus/public/cpp/BUILD.gn
+++ b/components/mus/public/cpp/BUILD.gn
@@ -2,10 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//third_party/mojo/src/mojo/public/mojo_sdk.gni")
-
-mojo_sdk_source_set("cpp") {
-  restrict_external_deps = false
+source_set("cpp") {
   sources = [
     "context_provider.h",
     "event_matcher.h",
@@ -55,18 +52,13 @@
     "//mojo/converters/surfaces",
     "//mojo/gles2:headers",
     "//mojo/gpu:mojo_gles2_implementation",
+    "//third_party/mojo/src/mojo/public/cpp/bindings:bindings",
     "//third_party/mojo/src/mojo/public/cpp/environment",
     "//third_party/mojo/src/mojo/public/cpp/system",
     "//ui/gfx/geometry",
     "//ui/mojo/geometry:interfaces",
   ]
 
-  mojo_sdk_deps = [
-    "mojo/public/c/gles2:headers",
-    "mojo/public/cpp/bindings:bindings",
-    "mojo/public/cpp/system",
-  ]
-
   data_deps = [
     "//components/mus",
   ]
diff --git a/components/mus/public/cpp/context_provider.h b/components/mus/public/cpp/context_provider.h
index 12c77fdc..18aa1375 100644
--- a/components/mus/public/cpp/context_provider.h
+++ b/components/mus/public/cpp/context_provider.h
@@ -9,7 +9,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/synchronization/lock.h"
 #include "cc/output/context_provider.h"
-#include "third_party/mojo/src/mojo/public/c/gles2/gles2.h"
+#include "third_party/mojo/src/mojo/public/c/gles2/gles2_types.h"
 #include "third_party/mojo/src/mojo/public/cpp/system/core.h"
 
 namespace mus {
diff --git a/components/mus/public/cpp/tests/BUILD.gn b/components/mus/public/cpp/tests/BUILD.gn
index ac9fa94..9787e49 100644
--- a/components/mus/public/cpp/tests/BUILD.gn
+++ b/components/mus/public/cpp/tests/BUILD.gn
@@ -49,7 +49,7 @@
     "//components/mus/public/cpp",
     "//mojo/application/public/cpp",
     "//mojo/gles2",
-    "//mojo/runner:platform_handle",
+    "//mojo/platform_handle:platform_handle_impl",
     "//testing/gtest",
     "//third_party/mojo/src/mojo/public/cpp/system",
     "//third_party/mojo/src/mojo/edk/system",
diff --git a/components/password_manager.gypi b/components/password_manager.gypi
index 8db288e8..6e941e5 100644
--- a/components/password_manager.gypi
+++ b/components/password_manager.gypi
@@ -68,6 +68,7 @@
         'password_manager/core/browser/log_router.h',
         'password_manager/core/browser/login_database.cc',
         'password_manager/core/browser/login_database.h',
+        'password_manager/core/browser/login_database_ios.cc',
         'password_manager/core/browser/login_database_mac.cc',
         'password_manager/core/browser/login_database_posix.cc',
         'password_manager/core/browser/login_database_win.cc',
@@ -125,10 +126,13 @@
         'password_manager/core/browser/webdata/password_web_data_service_win.h',
       ],
       'conditions': [
+        ['OS=="ios"', {
+          'sources!': [
+            'password_manager/core/browser/login_database_posix.cc',
+          ],
+        }],
         ['OS=="mac"', {
           'sources!': [
-            # TODO(blundell): Provide the iOS login DB implementation and then
-            # also exclude the POSIX one from iOS. http://crbug.com/341429
             'password_manager/core/browser/login_database_posix.cc',
           ],
         }],
diff --git a/components/password_manager/core/browser/login_database.cc b/components/password_manager/core/browser/login_database.cc
index f241b00..b816f62 100644
--- a/components/password_manager/core/browser/login_database.cc
+++ b/components/password_manager/core/browser/login_database.cc
@@ -13,6 +13,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/sparse_histogram.h"
 #include "base/pickle.h"
+#include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/time/time.h"
@@ -32,7 +33,7 @@
 namespace password_manager {
 
 // The current version number of the login database schema.
-const int kCurrentVersionNumber = 15;
+const int kCurrentVersionNumber = 16;
 // The oldest version of the schema such that a legacy Chrome client using that
 // version can still read/write the current database.
 const int kCompatibleVersionNumber = 14;
@@ -419,13 +420,7 @@
     db_.Close();
     return false;
   }
-
-  if (!stats_table_.Init(&db_)) {
-    LogDatabaseInitError(INIT_STATS_ERROR);
-    LOG(ERROR) << "Unable to initialize the stats table.";
-    db_.Close();
-    return false;
-  }
+  stats_table_.Init(&db_);
 
   // If the file on disk is an older database version, bring it up to date.
   if (meta_table_.GetVersionNumber() < kCurrentVersionNumber &&
@@ -440,6 +435,13 @@
     return false;
   }
 
+  if (!stats_table_.CreateTableIfNecessary()) {
+    LogDatabaseInitError(INIT_STATS_ERROR);
+    LOG(ERROR) << "Unable to create the stats table.";
+    db_.Close();
+    return false;
+  }
+
   if (!transaction.Commit()) {
     LogDatabaseInitError(COMMIT_TRANSACTION_ERROR);
     LOG(ERROR) << "Unable to commit a transaction.";
@@ -606,7 +608,11 @@
       // through an otherwise no-op migration process that will, however, now
       // correctly set the 'compatible version number'. Previously, it was
       // always being set to (and forever left at) version 1.
-      // Fall through.
+      meta_table_.SetCompatibleVersionNumber(kCompatibleVersionNumber);
+    case 15:
+      // Recreate the statistics.
+      if (!stats_table_.MigrateToVersion(16))
+        return false;
 
     // -------------------------------------------------------------------------
     // DO NOT FORGET to update |kCompatibleVersionNumber| if you add a migration
@@ -617,7 +623,6 @@
     case kCurrentVersionNumber:
       // Already up to date.
       meta_table_.SetVersionNumber(kCurrentVersionNumber);
-      meta_table_.SetCompatibleVersionNumber(kCompatibleVersionNumber);
       return true;
     default:
       NOTREACHED();
@@ -878,6 +883,9 @@
           &encrypted_password) != ENCRYPTION_RESULT_SUCCESS)
     return PasswordStoreChangeList();
 
+#if defined(OS_IOS)
+  DeleteEncryptedPassword(form);
+#endif
   // Replacement is necessary to deal with updating imported credentials. See
   // crbug.com/349138 for details.
   sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE,
@@ -947,6 +955,9 @@
     // credentials.
     return false;
   }
+#if defined(OS_IOS)
+  DeleteEncryptedPassword(form);
+#endif
   // Remove a login by UNIQUE-constrained fields.
   sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE,
                                           "DELETE FROM logins WHERE "
@@ -968,6 +979,15 @@
 
 bool LoginDatabase::RemoveLoginsCreatedBetween(base::Time delete_begin,
                                                base::Time delete_end) {
+#if defined(OS_IOS)
+  ScopedVector<autofill::PasswordForm> forms;
+  if (GetLoginsCreatedBetween(delete_begin, delete_end, &forms)) {
+    for (size_t i = 0; i < forms.size(); i++) {
+      DeleteEncryptedPassword(*forms[i]);
+    }
+  }
+#endif
+
   sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE,
       "DELETE FROM logins WHERE "
       "date_created >= ? AND date_created < ?"));
@@ -1207,6 +1227,32 @@
   return Init();
 }
 
+std::string LoginDatabase::GetEncryptedPassword(
+    const autofill::PasswordForm& form) const {
+  sql::Statement s(
+      db_.GetCachedStatement(SQL_FROM_HERE,
+                             "SELECT password_value FROM logins WHERE "
+                             "origin_url = ? AND "
+                             "username_element = ? AND "
+                             "username_value = ? AND "
+                             "password_element = ? AND "
+                             "submit_element = ? AND "
+                             "signon_realm = ? "));
+
+  s.BindString(0, form.origin.spec());
+  s.BindString16(1, form.username_element);
+  s.BindString16(2, form.username_value);
+  s.BindString16(3, form.password_element);
+  s.BindString16(4, form.submit_element);
+  s.BindString(5, form.signon_realm);
+
+  std::string encrypted_password;
+  if (s.Step()) {
+    s.ColumnBlobAsString(0, &encrypted_password);
+  }
+  return encrypted_password;
+}
+
 // static
 bool LoginDatabase::StatementToForms(
     sql::Statement* statement,
diff --git a/components/password_manager/core/browser/login_database.h b/components/password_manager/core/browser/login_database.h
index 304fd96..b032d53 100644
--- a/components/password_manager/core/browser/login_database.h
+++ b/components/password_manager/core/browser/login_database.h
@@ -20,6 +20,10 @@
 #include "sql/connection.h"
 #include "sql/meta_table.h"
 
+#if defined(OS_IOS)
+#include "base/gtest_prod_util.h"
+#endif
+
 namespace password_manager {
 
 extern const int kCurrentVersionNumber;
@@ -110,11 +114,24 @@
   // whether further use of this login database will succeed is unspecified.
   bool DeleteAndRecreateDatabaseFile();
 
+  // Returns the encrypted password value for the specified |form|.  Returns an
+  // empty string if the row for this |form| is not found.
+  std::string GetEncryptedPassword(const autofill::PasswordForm& form) const;
+
   StatisticsTable& stats_table() { return stats_table_; }
 
   void set_clear_password_values(bool val) { clear_password_values_ = val; }
 
  private:
+#if defined(OS_IOS)
+  friend class LoginDatabaseIOSTest;
+  FRIEND_TEST_ALL_PREFIXES(LoginDatabaseIOSTest, KeychainStorage);
+
+  // On iOS, removes the keychain item that is used to store the
+  // encrypted password for the supplied |form|.
+  void DeleteEncryptedPassword(const autofill::PasswordForm& form);
+#endif
+
   // Result values for encryption/decryption actions.
   enum EncryptionResult {
     // Success.
diff --git a/components/password_manager/core/browser/login_database_ios.cc b/components/password_manager/core/browser/login_database_ios.cc
new file mode 100644
index 0000000..cbd34555
--- /dev/null
+++ b/components/password_manager/core/browser/login_database_ios.cc
@@ -0,0 +1,134 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/password_manager/core/browser/login_database.h"
+
+#import <Security/Security.h>
+
+#include "base/base64.h"
+#include "base/logging.h"
+#include "base/mac/mac_logging.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/sparse_histogram.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+
+using base::ScopedCFTypeRef;
+using autofill::PasswordForm;
+
+namespace password_manager {
+
+// On iOS, the LoginDatabase uses Keychain API to store passwords. The
+// "encrypted" version of the password is a unique ID (UUID) that is
+// stored as an attribute along with the password in the keychain.
+// A side effect of this approach is that the same password saved multiple
+// times will have different "encrypted" values.
+
+// TODO(ios): Use |Encryptor| to encrypt the login database. b/6976257
+
+LoginDatabase::EncryptionResult LoginDatabase::EncryptedString(
+    const base::string16& plain_text,
+    std::string* cipher_text) {
+  if (plain_text.size() == 0) {
+    *cipher_text = std::string();
+    return ENCRYPTION_RESULT_SUCCESS;
+  }
+
+  ScopedCFTypeRef<CFUUIDRef> uuid(CFUUIDCreate(NULL));
+  ScopedCFTypeRef<CFStringRef> item_ref(CFUUIDCreateString(NULL, uuid));
+  ScopedCFTypeRef<CFMutableDictionaryRef> attributes(
+      CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
+                                &kCFTypeDictionaryValueCallBacks));
+  CFDictionarySetValue(attributes, kSecClass, kSecClassGenericPassword);
+
+  // It does not matter which attribute we use to identify the keychain
+  // item as long as it uniquely identifies it. We are arbitrarily choosing the
+  // |kSecAttrAccount| attribute for this purpose.
+  CFDictionarySetValue(attributes, kSecAttrAccount, item_ref);
+  std::string plain_text_utf8 = UTF16ToUTF8(plain_text);
+  ScopedCFTypeRef<CFDataRef> data(
+      CFDataCreate(NULL, reinterpret_cast<const UInt8*>(plain_text_utf8.data()),
+                   plain_text_utf8.size()));
+  CFDictionarySetValue(attributes, kSecValueData, data);
+
+  // Only allow access when the device has been unlocked.
+  CFDictionarySetValue(attributes, kSecAttrAccessible,
+                       kSecAttrAccessibleWhenUnlocked);
+
+  OSStatus status = SecItemAdd(attributes, NULL);
+  if (status != errSecSuccess) {
+    NOTREACHED() << "Unable to save password in keychain: " << status;
+    if (status == errSecDuplicateItem || status == errSecDecode)
+      return ENCRYPTION_RESULT_ITEM_FAILURE;
+    else
+      return ENCRYPTION_RESULT_SERVICE_FAILURE;
+  }
+
+  *cipher_text = base::SysCFStringRefToUTF8(item_ref);
+  return ENCRYPTION_RESULT_SUCCESS;
+}
+
+LoginDatabase::EncryptionResult LoginDatabase::DecryptedString(
+    const std::string& cipher_text,
+    base::string16* plain_text) {
+  if (cipher_text.size() == 0) {
+    *plain_text = base::string16();
+    return ENCRYPTION_RESULT_SUCCESS;
+  }
+
+  ScopedCFTypeRef<CFStringRef> item_ref(
+      base::SysUTF8ToCFStringRef(cipher_text));
+  ScopedCFTypeRef<CFMutableDictionaryRef> query(
+      CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
+                                &kCFTypeDictionaryValueCallBacks));
+  CFDictionarySetValue(query, kSecClass, kSecClassGenericPassword);
+
+  // We are using the account attribute to store item references.
+  CFDictionarySetValue(query, kSecAttrAccount, item_ref);
+  CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue);
+
+  CFDataRef data;
+  OSStatus status = SecItemCopyMatching(query, (CFTypeRef*)&data);
+  if (status != errSecSuccess) {
+    OSSTATUS_LOG(INFO, status) << "Failed to retrieve password from keychain";
+    if (status == errSecItemNotFound || status == errSecDecode)
+      return ENCRYPTION_RESULT_ITEM_FAILURE;
+    else
+      return ENCRYPTION_RESULT_SERVICE_FAILURE;
+  }
+
+  const size_t size = CFDataGetLength(data);
+  scoped_ptr<UInt8[]> buffer(new UInt8[size]);
+  CFDataGetBytes(data, CFRangeMake(0, size), buffer.get());
+  CFRelease(data);
+
+  *plain_text = base::UTF8ToUTF16(
+      std::string(static_cast<char*>(static_cast<void*>(buffer.get())),
+                  static_cast<size_t>(size)));
+  return ENCRYPTION_RESULT_SUCCESS;
+}
+
+void LoginDatabase::DeleteEncryptedPassword(const PasswordForm& form) {
+  std::string cipher_text = GetEncryptedPassword(form);
+  if (cipher_text.size() == 0)
+    return;
+
+  ScopedCFTypeRef<CFStringRef> item_ref(
+      base::SysUTF8ToCFStringRef(cipher_text));
+  ScopedCFTypeRef<CFMutableDictionaryRef> query(
+      CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
+                                &kCFTypeDictionaryValueCallBacks));
+  CFDictionarySetValue(query, kSecClass, kSecClassGenericPassword);
+
+  // We are using the account attribute to store item references.
+  CFDictionarySetValue(query, kSecAttrAccount, item_ref);
+
+  OSStatus status = SecItemDelete(query);
+  if (status != errSecSuccess && status != errSecItemNotFound) {
+    NOTREACHED() << "Unable to remove password from keychain: " << status;
+  }
+}
+
+}  // namespace password_manager
diff --git a/components/password_manager/core/browser/login_database_ios_unittest.cc b/components/password_manager/core/browser/login_database_ios_unittest.cc
new file mode 100644
index 0000000..06b6442
--- /dev/null
+++ b/components/password_manager/core/browser/login_database_ios_unittest.cc
@@ -0,0 +1,187 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/password_manager/core/browser/login_database.h"
+
+#include <Security/Security.h>
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/ios/ios_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/macros.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/common/password_form.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+using base::ScopedCFTypeRef;
+using autofill::PasswordForm;
+
+namespace password_manager {
+
+class LoginDatabaseIOSTest : public PlatformTest {
+ public:
+  void SetUp() override {
+    ClearKeychain();
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    base::FilePath login_db_path =
+        temp_dir_.path().AppendASCII("temp_login.db");
+    login_db_.reset(new password_manager::LoginDatabase(login_db_path));
+    login_db_->Init();
+  }
+
+  void TearDown() override { ClearKeychain(); }
+
+  // Removes all passwords from the keychain.  Since the unit test
+  // executable does not share the keychain with anything else on iOS, clearing
+  // the keychain will not affect any other applications.
+  void ClearKeychain();
+
+  // Returns the number of items in the keychain.
+  size_t GetKeychainSize();
+
+ protected:
+  base::ScopedTempDir temp_dir_;
+  scoped_ptr<LoginDatabase> login_db_;
+};
+
+void LoginDatabaseIOSTest::ClearKeychain() {
+  const void* queryKeys[] = {kSecClass};
+  const void* queryValues[] = {kSecClassGenericPassword};
+  ScopedCFTypeRef<CFDictionaryRef> query(CFDictionaryCreate(
+      NULL, queryKeys, queryValues, arraysize(queryKeys),
+      &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
+  OSStatus status = SecItemDelete(query);
+  // iOS7 returns an error of |errSecItemNotFound| if you try to clear an empty
+  // keychain.
+  ASSERT_TRUE(status == errSecSuccess || status == errSecItemNotFound);
+}
+
+size_t LoginDatabaseIOSTest::GetKeychainSize() {
+  // Verify that the keychain now contains exactly one item.
+  ScopedCFTypeRef<CFMutableDictionaryRef> query(
+      CFDictionaryCreateMutable(NULL, 4, &kCFTypeDictionaryKeyCallBacks,
+                                &kCFTypeDictionaryValueCallBacks));
+  CFDictionarySetValue(query, kSecClass, kSecClassGenericPassword);
+  CFDictionarySetValue(query, kSecReturnAttributes, kCFBooleanTrue);
+  CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll);
+  CFDictionarySetValue(query, kSecAttrAccessible,
+                       kSecAttrAccessibleWhenUnlocked);
+
+  CFTypeRef result;
+  OSStatus status = SecItemCopyMatching(query, &result);
+  if (status == errSecItemNotFound)
+    return 0;
+
+  EXPECT_EQ(errSecSuccess, status);
+  size_t size = CFArrayGetCount((CFArrayRef)result);
+  CFRelease(result);
+  return size;
+}
+
+TEST_F(LoginDatabaseIOSTest, KeychainStorage) {
+  base::string16 test_passwords[] = {
+      base::ASCIIToUTF16("foo"), base::ASCIIToUTF16("bar"),
+      base::WideToUTF16(L"\u043F\u0430\u0440\u043E\u043B\u044C"),
+      base::string16(),
+  };
+
+  for (unsigned int i = 0; i < arraysize(test_passwords); i++) {
+    std::string encrypted;
+    EXPECT_EQ(LoginDatabase::ENCRYPTION_RESULT_SUCCESS,
+              login_db_->EncryptedString(test_passwords[i], &encrypted));
+    base::string16 decrypted;
+    EXPECT_EQ(LoginDatabase::ENCRYPTION_RESULT_SUCCESS,
+              login_db_->DecryptedString(encrypted, &decrypted));
+    EXPECT_STREQ(UTF16ToUTF8(test_passwords[i]).c_str(),
+                 UTF16ToUTF8(decrypted).c_str());
+  }
+}
+
+TEST_F(LoginDatabaseIOSTest, UpdateLogin) {
+  PasswordForm form;
+  form.origin = GURL("http://0.com");
+  form.signon_realm = "http://www.example.com";
+  form.action = GURL("http://www.example.com/action");
+  form.password_element = base::ASCIIToUTF16("pwd");
+  form.password_value = base::ASCIIToUTF16("example");
+
+  ignore_result(login_db_->AddLogin(form));
+
+  form.password_value = base::ASCIIToUTF16("secret");
+
+  password_manager::PasswordStoreChangeList changes =
+      login_db_->UpdateLogin(form);
+  ASSERT_EQ(1u, changes.size());
+
+  form.password_value = base::string16();
+
+  ScopedVector<PasswordForm> forms;
+  EXPECT_TRUE(login_db_->GetLogins(form, &forms));
+
+  ASSERT_EQ(1U, forms.size());
+  EXPECT_STREQ("secret", UTF16ToUTF8(forms[0]->password_value).c_str());
+  ASSERT_EQ(1U, GetKeychainSize());
+}
+
+TEST_F(LoginDatabaseIOSTest, RemoveLogin) {
+  PasswordForm form;
+  form.signon_realm = "www.example.com";
+  form.action = GURL("www.example.com/action");
+  form.password_element = base::ASCIIToUTF16("pwd");
+  form.password_value = base::ASCIIToUTF16("example");
+
+  ignore_result(login_db_->AddLogin(form));
+
+  ignore_result(login_db_->RemoveLogin(form));
+
+  ScopedVector<PasswordForm> forms;
+  EXPECT_TRUE(login_db_->GetLogins(form, &forms));
+
+  ASSERT_EQ(0U, forms.size());
+  ASSERT_EQ(0U, GetKeychainSize());
+}
+
+TEST_F(LoginDatabaseIOSTest, RemoveLoginsCreatedBetween) {
+  PasswordForm forms[3];
+  forms[0].origin = GURL("http://0.com");
+  forms[0].signon_realm = "http://www.example.com";
+  forms[0].username_element = base::ASCIIToUTF16("login0");
+  forms[0].date_created = base::Time::FromDoubleT(100);
+  forms[0].password_value = base::ASCIIToUTF16("pass0");
+
+  forms[1].origin = GURL("http://1.com");
+  forms[1].signon_realm = "http://www.example.com";
+  forms[1].username_element = base::ASCIIToUTF16("login1");
+  forms[1].date_created = base::Time::FromDoubleT(200);
+  forms[1].password_value = base::ASCIIToUTF16("pass1");
+
+  forms[2].origin = GURL("http://2.com");
+  forms[2].signon_realm = "http://www.example.com";
+  forms[2].username_element = base::ASCIIToUTF16("login2");
+  forms[2].date_created = base::Time::FromDoubleT(300);
+  forms[2].password_value = base::ASCIIToUTF16("pass2");
+
+  for (size_t i = 0; i < arraysize(forms); i++) {
+    ignore_result(login_db_->AddLogin(forms[i]));
+  }
+
+  login_db_->RemoveLoginsCreatedBetween(base::Time::FromDoubleT(150),
+                                        base::Time::FromDoubleT(250));
+
+  PasswordForm form;
+  form.signon_realm = "http://www.example.com";
+  ScopedVector<PasswordForm> logins;
+  EXPECT_TRUE(login_db_->GetLogins(form, &logins));
+
+  ASSERT_EQ(2U, logins.size());
+  ASSERT_EQ(2U, GetKeychainSize());
+
+  EXPECT_STREQ("login0", UTF16ToUTF8(logins[0]->username_element).c_str());
+  EXPECT_STREQ("pass0", UTF16ToUTF8(logins[0]->password_value).c_str());
+  EXPECT_STREQ("login2", UTF16ToUTF8(logins[1]->username_element).c_str());
+  EXPECT_STREQ("pass2", UTF16ToUTF8(logins[1]->password_value).c_str());
+}
+
+}  // namespace password_manager
diff --git a/components/password_manager/core/browser/login_database_unittest.cc b/components/password_manager/core/browser/login_database_unittest.cc
index 00a1e06..a0bf235f 100644
--- a/components/password_manager/core/browser/login_database_unittest.cc
+++ b/components/password_manager/core/browser/login_database_unittest.cc
@@ -1521,7 +1521,7 @@
 
 INSTANTIATE_TEST_CASE_P(MigrationToVCurrent,
                         LoginDatabaseMigrationTest,
-                        testing::Range(1, kCurrentVersionNumber));
+                        testing::Range(1, kCurrentVersionNumber + 1));
 INSTANTIATE_TEST_CASE_P(MigrationToVCurrent,
                         LoginDatabaseMigrationTestV9,
                         testing::Values(9));
diff --git a/components/password_manager/core/browser/mock_password_store.h b/components/password_manager/core/browser/mock_password_store.h
index 60beb7a..1127a3c 100644
--- a/components/password_manager/core/browser/mock_password_store.h
+++ b/components/password_manager/core/browser/mock_password_store.h
@@ -49,9 +49,9 @@
   MOCK_METHOD1(NotifyLoginsChanged, void(const PasswordStoreChangeList&));
   void AddSiteStatsImpl(const InteractionsStats& stats) override {}
   void RemoveSiteStatsImpl(const GURL& origin_domain) override {}
-  scoped_ptr<InteractionsStats> GetSiteStatsImpl(
+  ScopedVector<InteractionsStats> GetSiteStatsImpl(
       const GURL& origin_domain) override {
-    return scoped_ptr<InteractionsStats>();
+    return ScopedVector<InteractionsStats>();
   }
 
   PasswordStoreSync* GetSyncInterface() { return this; }
diff --git a/components/password_manager/core/browser/password_store.cc b/components/password_manager/core/browser/password_store.cc
index 252916e..6a2c1877 100644
--- a/components/password_manager/core/browser/password_store.cc
+++ b/components/password_manager/core/browser/password_store.cc
@@ -62,7 +62,7 @@
 }
 
 void PasswordStore::GetLoginsRequest::NotifyWithSiteStatistics(
-    scoped_ptr<InteractionsStats> stats) {
+    ScopedVector<InteractionsStats> stats) {
   origin_task_runner_->PostTask(
       FROM_HERE, base::Bind(&PasswordStoreConsumer::OnGetSiteStatistics,
                             consumer_weak_, base::Passed(&stats)));
diff --git a/components/password_manager/core/browser/password_store.h b/components/password_manager/core/browser/password_store.h
index c0ef993..ec22f90 100644
--- a/components/password_manager/core/browser/password_store.h
+++ b/components/password_manager/core/browser/password_store.h
@@ -205,7 +205,7 @@
     void NotifyConsumerWithResults(
         ScopedVector<autofill::PasswordForm> results);
 
-    void NotifyWithSiteStatistics(scoped_ptr<InteractionsStats> stats);
+    void NotifyWithSiteStatistics(ScopedVector<InteractionsStats> stats);
 
     void set_ignore_logins_cutoff(base::Time cutoff) {
       ignore_logins_cutoff_ = cutoff;
@@ -283,7 +283,7 @@
   virtual void AddSiteStatsImpl(const InteractionsStats& stats) = 0;
   virtual void RemoveSiteStatsImpl(const GURL& origin_domain) = 0;
   // Returns a raw pointer so that InteractionsStats can be forward declared.
-  virtual scoped_ptr<InteractionsStats> GetSiteStatsImpl(
+  virtual ScopedVector<InteractionsStats> GetSiteStatsImpl(
       const GURL& origin_domain) WARN_UNUSED_RESULT = 0;
 
   // Log UMA stats for number of bulk deletions.
diff --git a/components/password_manager/core/browser/password_store_consumer.cc b/components/password_manager/core/browser/password_store_consumer.cc
index 8347f2b..1aa16c6 100644
--- a/components/password_manager/core/browser/password_store_consumer.cc
+++ b/components/password_manager/core/browser/password_store_consumer.cc
@@ -15,7 +15,6 @@
 }
 
 void PasswordStoreConsumer::OnGetSiteStatistics(
-    scoped_ptr<InteractionsStats> stats) {
-}
+    ScopedVector<InteractionsStats> stats) {}
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_store_consumer.h b/components/password_manager/core/browser/password_store_consumer.h
index b8934995..4ce40ba 100644
--- a/components/password_manager/core/browser/password_store_consumer.h
+++ b/components/password_manager/core/browser/password_store_consumer.h
@@ -32,7 +32,7 @@
   virtual void OnGetPasswordStoreResults(
       ScopedVector<autofill::PasswordForm> results) = 0;
 
-  virtual void OnGetSiteStatistics(scoped_ptr<InteractionsStats> stats);
+  virtual void OnGetSiteStatistics(ScopedVector<InteractionsStats> stats);
 
   // The base::CancelableTaskTracker can be used for cancelling the
   // tasks associated with the consumer.
diff --git a/components/password_manager/core/browser/password_store_default.cc b/components/password_manager/core/browser/password_store_default.cc
index 26599ce..89ca082 100644
--- a/components/password_manager/core/browser/password_store_default.cc
+++ b/components/password_manager/core/browser/password_store_default.cc
@@ -170,11 +170,11 @@
     login_db_->stats_table().RemoveRow(origin_domain);
 }
 
-scoped_ptr<InteractionsStats> PasswordStoreDefault::GetSiteStatsImpl(
+ScopedVector<InteractionsStats> PasswordStoreDefault::GetSiteStatsImpl(
     const GURL& origin_domain) {
   DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
-  return login_db_ ? login_db_->stats_table().GetRow(origin_domain)
-                   : scoped_ptr<InteractionsStats>();
+  return login_db_ ? login_db_->stats_table().GetRows(origin_domain)
+                   : ScopedVector<InteractionsStats>();
 }
 
 void PasswordStoreDefault::ResetLoginDB() {
diff --git a/components/password_manager/core/browser/password_store_default.h b/components/password_manager/core/browser/password_store_default.h
index f31be5f..b43c20e 100644
--- a/components/password_manager/core/browser/password_store_default.h
+++ b/components/password_manager/core/browser/password_store_default.h
@@ -65,7 +65,7 @@
       ScopedVector<autofill::PasswordForm>* forms) override;
   void AddSiteStatsImpl(const InteractionsStats& stats) override;
   void RemoveSiteStatsImpl(const GURL& origin_domain) override;
-  scoped_ptr<InteractionsStats> GetSiteStatsImpl(
+  ScopedVector<InteractionsStats> GetSiteStatsImpl(
       const GURL& origin_domain) override;
 
   inline bool DeleteAndRecreateDatabaseFile() {
diff --git a/components/password_manager/core/browser/statistics_table.cc b/components/password_manager/core/browser/statistics_table.cc
index 1246ee9..6cc4027 100644
--- a/components/password_manager/core/browser/statistics_table.cc
+++ b/components/password_manager/core/browser/statistics_table.cc
@@ -13,44 +13,60 @@
 // Convenience enum for interacting with SQL queries that use all the columns.
 enum LoginTableColumns {
   COLUMN_ORIGIN_DOMAIN = 0,
-  COLUMN_NOPES,
+  COLUMN_USERNAME,
   COLUMN_DISMISSALS,
   COLUMN_DATE,
 };
 
 }  // namespace
 
+InteractionsStats::InteractionsStats() = default;
+
 StatisticsTable::StatisticsTable() : db_(nullptr) {
 }
 
-StatisticsTable::~StatisticsTable() {
+StatisticsTable::~StatisticsTable() = default;
+
+void StatisticsTable::Init(sql::Connection* db) {
+  db_ = db;
 }
 
-bool StatisticsTable::Init(sql::Connection* db) {
-  db_ = db;
+bool StatisticsTable::CreateTableIfNecessary() {
   if (!db_->DoesTableExist("stats")) {
     const char query[] =
         "CREATE TABLE stats ("
-        "origin_domain VARCHAR NOT NULL PRIMARY KEY, "
-        "nopes_count INTEGER, "
+        "origin_domain VARCHAR NOT NULL, "
+        "username_value VARCHAR, "
         "dismissal_count INTEGER, "
-        "start_date INTEGER NOT NULL)";
+        "update_time INTEGER NOT NULL, "
+        "UNIQUE(origin_domain, username_value))";
     if (!db_->Execute(query))
       return false;
+    const char index[] = "CREATE INDEX stats_origin ON stats(origin_domain)";
+    if (!db_->Execute(index))
+      return false;
   }
   return true;
 }
 
+bool StatisticsTable::MigrateToVersion(int version) {
+  if (!db_->DoesTableExist("stats"))
+    return true;
+  if (version == 16)
+    return db_->Execute("DROP TABLE stats");
+  return true;
+}
+
 bool StatisticsTable::AddRow(const InteractionsStats& stats) {
   sql::Statement s(db_->GetCachedStatement(
       SQL_FROM_HERE,
       "INSERT OR REPLACE INTO stats "
-      "(origin_domain, nopes_count, dismissal_count, start_date) "
+      "(origin_domain, username_value, dismissal_count, update_time) "
       "VALUES (?, ?, ?, ?)"));
   s.BindString(COLUMN_ORIGIN_DOMAIN, stats.origin_domain.spec());
-  s.BindInt(COLUMN_NOPES, stats.nopes_count);
+  s.BindString16(COLUMN_USERNAME, stats.username_value);
   s.BindInt(COLUMN_DISMISSALS, stats.dismissal_count);
-  s.BindInt64(COLUMN_DATE, stats.start_date.ToInternalValue());
+  s.BindInt64(COLUMN_DATE, stats.update_time.ToInternalValue());
   return s.Run();
 }
 
@@ -62,22 +78,33 @@
   return s.Run();
 }
 
-scoped_ptr<InteractionsStats> StatisticsTable::GetRow(const GURL& domain) {
+ScopedVector<InteractionsStats> StatisticsTable::GetRows(const GURL& domain) {
   const char query[] =
-      "SELECT origin_domain, nopes_count, "
-      "dismissal_count, start_date FROM stats WHERE origin_domain == ?";
+      "SELECT origin_domain, username_value, "
+      "dismissal_count, update_time FROM stats WHERE origin_domain == ?";
   sql::Statement s(db_->GetCachedStatement(SQL_FROM_HERE, query));
   s.BindString(0, domain.spec());
-  if (s.Step()) {
-    scoped_ptr<InteractionsStats> stats(new InteractionsStats);
-    stats->origin_domain = GURL(s.ColumnString(COLUMN_ORIGIN_DOMAIN));
-    stats->nopes_count = s.ColumnInt(COLUMN_NOPES);
-    stats->dismissal_count = s.ColumnInt(COLUMN_DISMISSALS);
-    stats->start_date =
+  ScopedVector<InteractionsStats> result;
+  while (s.Step()) {
+    result.push_back(new InteractionsStats);
+    result.back()->origin_domain = GURL(s.ColumnString(COLUMN_ORIGIN_DOMAIN));
+    result.back()->username_value = s.ColumnString16(COLUMN_USERNAME);
+    result.back()->dismissal_count = s.ColumnInt(COLUMN_DISMISSALS);
+    result.back()->update_time =
         base::Time::FromInternalValue(s.ColumnInt64(COLUMN_DATE));
-    return stats.Pass();
   }
-  return scoped_ptr<InteractionsStats>();
+  return result.Pass();
+}
+
+bool StatisticsTable::RemoveStatsBetween(base::Time delete_begin,
+                                         base::Time delete_end) {
+  sql::Statement s(db_->GetCachedStatement(
+      SQL_FROM_HERE,
+      "DELETE FROM stats WHERE update_time >= ? AND update_time < ?"));
+  s.BindInt64(0, delete_begin.ToInternalValue());
+  s.BindInt64(1, delete_end.is_null() ? std::numeric_limits<int64>::max()
+                                      : delete_end.ToInternalValue());
+  return s.Run();
 }
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/statistics_table.h b/components/password_manager/core/browser/statistics_table.h
index d135309..9a48f1e 100644
--- a/components/password_manager/core/browser/statistics_table.h
+++ b/components/password_manager/core/browser/statistics_table.h
@@ -7,6 +7,7 @@
 
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
 #include "base/time/time.h"
 #include "url/gurl.h"
 
@@ -18,29 +19,40 @@
 
 // The statistics containing user interactions with a site.
 struct InteractionsStats {
+  InteractionsStats();
+
   // The domain of the site.
   GURL origin_domain;
 
-  // Number of times the user clicked "Don't save the password".
-  int nopes_count;
+  // The value of the username.
+  base::string16 username_value;
 
   // Number of times the user dismissed the bubble.
-  int dismissal_count;
+  int dismissal_count = 0;
 
-  // The beginning date of the measurements.
-  base::Time start_date;
+  // The date when the row was updated.
+  base::Time update_time;
 };
 
-// Represents 'stats' table in the Login Database.
+// Represents the 'stats' table in the Login Database.
 class StatisticsTable {
  public:
   StatisticsTable();
   ~StatisticsTable();
 
-  // Initializes |db_| and creates the statistics table if it doesn't exist.
-  bool Init(sql::Connection* db);
+  // Initializes |db_|.
+  void Init(sql::Connection* db);
 
-  // Adds or replaces the statistics about |stats.origin_domain|.
+  // Creates the statistics table if it doesn't exist.
+  bool CreateTableIfNecessary();
+
+  // Migrates this table to |version|. The current version should be less than
+  // |version|. Returns false if there was migration work to do and it failed,
+  // true otherwise.
+  bool MigrateToVersion(int version);
+
+  // Adds or replaces the statistics about |stats.origin_domain| and
+  // |stats.username_value|.
   bool AddRow(const InteractionsStats& stats);
 
   // Removes the statistics for |domain|. Returns true if the SQL completed
@@ -48,7 +60,11 @@
   bool RemoveRow(const GURL& domain);
 
   // Returns the statistics for |domain| if it exists.
-  scoped_ptr<InteractionsStats> GetRow(const GURL& domain);
+  ScopedVector<InteractionsStats> GetRows(const GURL& domain);
+
+  // Removes the statistics between the dates. Returns true if the SQL completed
+  // successfully.
+  bool RemoveStatsBetween(base::Time delete_begin, base::Time delete_end);
 
  private:
   sql::Connection* db_;
diff --git a/components/password_manager/core/browser/statistics_table_unittest.cc b/components/password_manager/core/browser/statistics_table_unittest.cc
index c3d28ff..f592e0a 100644
--- a/components/password_manager/core/browser/statistics_table_unittest.cc
+++ b/components/password_manager/core/browser/statistics_table_unittest.cc
@@ -5,20 +5,29 @@
 #include "components/password_manager/core/browser/statistics_table.h"
 
 #include "base/files/scoped_temp_dir.h"
+#include "base/strings/utf_string_conversions.h"
 #include "sql/connection.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace password_manager {
 namespace {
 
 const char kTestDomain[] = "http://google.com";
+const char kTestDomain2[] = "http://example.com";
+const char kUsername1[] = "user1";
+const char kUsername2[] = "user2";
 
-void CheckStatsAreEqual(const InteractionsStats& left,
-                        const InteractionsStats& right) {
-  EXPECT_EQ(left.origin_domain, right.origin_domain);
-  EXPECT_EQ(left.nopes_count, right.nopes_count);
-  EXPECT_EQ(left.dismissal_count, right.dismissal_count);
-  EXPECT_EQ(left.start_date, right.start_date);
+using ::testing::ElementsAre;
+using ::testing::IsEmpty;
+using ::testing::Pointee;
+using ::testing::UnorderedElementsAre;
+
+MATCHER_P(StatsIs, stats, "") {
+  return arg.origin_domain == stats.origin_domain &&
+         arg.username_value == stats.username_value &&
+         arg.dismissal_count == stats.dismissal_count &&
+         arg.update_time == stats.update_time;
 }
 
 class StatisticsTableTest : public testing::Test {
@@ -28,9 +37,9 @@
     ReloadDatabase();
 
     test_data_.origin_domain = GURL(kTestDomain);
-    test_data_.nopes_count = 5;
+    test_data_.username_value = base::ASCIIToUTF16(kUsername1);
     test_data_.dismissal_count = 10;
-    test_data_.start_date = base::Time::FromTimeT(1);
+    test_data_.update_time = base::Time::FromTimeT(1);
   }
 
   void ReloadDatabase() {
@@ -39,7 +48,8 @@
     connection_.reset(new sql::Connection);
     connection_->set_exclusive_locking();
     ASSERT_TRUE(connection_->Open(file));
-    ASSERT_TRUE(db_->Init(connection_.get()));
+    db_->Init(connection_.get());
+    ASSERT_TRUE(db_->CreateTableIfNecessary());
   }
 
   InteractionsStats& test_data() { return test_data_; }
@@ -54,37 +64,72 @@
 
 TEST_F(StatisticsTableTest, Sanity) {
   EXPECT_TRUE(db()->AddRow(test_data()));
-  scoped_ptr<InteractionsStats> stats = db()->GetRow(test_data().origin_domain);
-  ASSERT_TRUE(stats);
-  CheckStatsAreEqual(test_data(), *stats);
+  EXPECT_THAT(db()->GetRows(test_data().origin_domain),
+              ElementsAre(Pointee(StatsIs(test_data()))));
   EXPECT_TRUE(db()->RemoveRow(test_data().origin_domain));
-  EXPECT_FALSE(db()->GetRow(test_data().origin_domain));
+  EXPECT_THAT(db()->GetRows(test_data().origin_domain), IsEmpty());
 }
 
 TEST_F(StatisticsTableTest, Reload) {
   EXPECT_TRUE(db()->AddRow(test_data()));
-  EXPECT_TRUE(db()->GetRow(test_data().origin_domain));
 
   ReloadDatabase();
 
-  scoped_ptr<InteractionsStats> stats = db()->GetRow(test_data().origin_domain);
-  ASSERT_TRUE(stats);
-  CheckStatsAreEqual(test_data(), *stats);
+  EXPECT_THAT(db()->GetRows(test_data().origin_domain),
+              ElementsAre(Pointee(StatsIs(test_data()))));
 }
 
 TEST_F(StatisticsTableTest, DoubleOperation) {
   EXPECT_TRUE(db()->AddRow(test_data()));
-  test_data().nopes_count++;
+  test_data().dismissal_count++;
   EXPECT_TRUE(db()->AddRow(test_data()));
 
-  scoped_ptr<InteractionsStats> stats = db()->GetRow(test_data().origin_domain);
-  ASSERT_TRUE(stats);
-  CheckStatsAreEqual(test_data(), *stats);
+  EXPECT_THAT(db()->GetRows(test_data().origin_domain),
+              ElementsAre(Pointee(StatsIs(test_data()))));
 
   EXPECT_TRUE(db()->RemoveRow(test_data().origin_domain));
-  EXPECT_FALSE(db()->GetRow(test_data().origin_domain));
+  EXPECT_THAT(db()->GetRows(test_data().origin_domain), IsEmpty());
   EXPECT_TRUE(db()->RemoveRow(test_data().origin_domain));
-  EXPECT_FALSE(db()->GetRow(test_data().origin_domain));
+}
+
+TEST_F(StatisticsTableTest, DifferentUsernames) {
+  InteractionsStats stats1 = test_data();
+  InteractionsStats stats2 = test_data();
+  stats2.username_value = base::ASCIIToUTF16(kUsername2);
+
+  EXPECT_TRUE(db()->AddRow(stats1));
+  EXPECT_TRUE(db()->AddRow(stats2));
+  EXPECT_THAT(
+      db()->GetRows(test_data().origin_domain),
+      UnorderedElementsAre(Pointee(StatsIs(stats1)), Pointee(StatsIs(stats2))));
+  EXPECT_TRUE(db()->RemoveRow(test_data().origin_domain));
+  EXPECT_THAT(db()->GetRows(test_data().origin_domain), IsEmpty());
+}
+
+TEST_F(StatisticsTableTest, RemoveBetween) {
+  InteractionsStats stats1 = test_data();
+  stats1.update_time = base::Time::FromTimeT(1);
+  InteractionsStats stats2 = test_data();
+  stats2.update_time = base::Time::FromTimeT(2);
+  stats2.origin_domain = GURL(kTestDomain2);
+
+  EXPECT_TRUE(db()->AddRow(stats1));
+  EXPECT_TRUE(db()->AddRow(stats2));
+  EXPECT_THAT(db()->GetRows(stats1.origin_domain),
+              ElementsAre(Pointee(StatsIs(stats1))));
+  EXPECT_THAT(db()->GetRows(stats2.origin_domain),
+              ElementsAre(Pointee(StatsIs(stats2))));
+
+  // Remove the first one only.
+  EXPECT_TRUE(db()->RemoveStatsBetween(base::Time(), base::Time::FromTimeT(2)));
+  EXPECT_THAT(db()->GetRows(stats1.origin_domain), IsEmpty());
+  EXPECT_THAT(db()->GetRows(stats2.origin_domain),
+              ElementsAre(Pointee(StatsIs(stats2))));
+
+  // Remove the second one only.
+  EXPECT_TRUE(db()->RemoveStatsBetween(base::Time::FromTimeT(2), base::Time()));
+  EXPECT_THAT(db()->GetRows(stats1.origin_domain), IsEmpty());
+  EXPECT_THAT(db()->GetRows(stats2.origin_domain), IsEmpty());
 }
 
 }  // namespace
diff --git a/components/password_manager/core/browser/test_password_store.cc b/components/password_manager/core/browser/test_password_store.cc
index fd3285a..776a869 100644
--- a/components/password_manager/core/browser/test_password_store.cc
+++ b/components/password_manager/core/browser/test_password_store.cc
@@ -127,9 +127,9 @@
 void TestPasswordStore::RemoveSiteStatsImpl(const GURL& origin_domain) {
 }
 
-scoped_ptr<InteractionsStats> TestPasswordStore::GetSiteStatsImpl(
+ScopedVector<InteractionsStats> TestPasswordStore::GetSiteStatsImpl(
     const GURL& origin_domain) {
-  return scoped_ptr<InteractionsStats>();
+  return ScopedVector<InteractionsStats>();
 }
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/test_password_store.h b/components/password_manager/core/browser/test_password_store.h
index 079997f5c..826ed0e 100644
--- a/components/password_manager/core/browser/test_password_store.h
+++ b/components/password_manager/core/browser/test_password_store.h
@@ -62,7 +62,7 @@
       ScopedVector<autofill::PasswordForm>* forms) override;
   void AddSiteStatsImpl(const InteractionsStats& stats) override;
   void RemoveSiteStatsImpl(const GURL& origin_domain) override;
-  scoped_ptr<InteractionsStats> GetSiteStatsImpl(
+  ScopedVector<InteractionsStats> GetSiteStatsImpl(
       const GURL& origin_domain) override;
 
  private:
diff --git a/components/pdf_viewer/BUILD.gn b/components/pdf_viewer/BUILD.gn
index bb8f5e6..4ec5149 100644
--- a/components/pdf_viewer/BUILD.gn
+++ b/components/pdf_viewer/BUILD.gn
@@ -15,8 +15,6 @@
     "//base",
     "//components/mus/public/interfaces",
     "//components/mus/public/cpp",
-    "//components/resource_provider/public/cpp",
-    "//components/resource_provider/public/interfaces",
     "//components/web_view/public/interfaces",
     "//gpu",
     "//mojo/application/public/cpp",
@@ -24,7 +22,6 @@
     "//mojo/common:common_base",
     "//mojo/converters/input_events",
     "//mojo/converters/surfaces",
-    "//mojo/platform_handle",
     "//mojo/services/network/public/cpp",
     "//mojo/services/network/public/interfaces",
     "//mojo/services/tracing/public/cpp",
diff --git a/components/resource_provider/BUILD.gn b/components/resource_provider/BUILD.gn
index 9985579b..5d26584 100644
--- a/components/resource_provider/BUILD.gn
+++ b/components/resource_provider/BUILD.gn
@@ -36,6 +36,7 @@
       "//build/config/sanitizers:deps",
       "//components/resource_provider/public/interfaces",
       "//mojo/environment:chromium",
+      "//mojo/platform_handle:for_shared_library",
       "//third_party/mojo/src/mojo/public/c/system:for_shared_library",
       "//url",
     ]
@@ -97,7 +98,6 @@
     "//components/resource_provider/public/interfaces",
     "//mojo/application/public/cpp",
     "//mojo/common:common_base",
-    "//mojo/platform_handle",
     "//url",
   ]
 }
@@ -113,6 +113,7 @@
     "//base/test:test_config",
     "//components/resource_provider/public/interfaces",
     "//mojo/environment:chromium",
+    "//mojo/platform_handle:for_shared_library",
     "//testing/gtest",
     "//third_party/mojo/src/mojo/edk/test:run_all_unittests",
     "//url",
@@ -138,7 +139,6 @@
     "//components/resource_provider/public/cpp",
     "//components/resource_provider/public/interfaces",
     "//mojo/application/public/cpp:test_support",
-    "//mojo/platform_handle",
   ]
 
   data_deps = [
diff --git a/components/resource_provider/file_utils.cc b/components/resource_provider/file_utils.cc
index 54bdd905..5aeccdf 100644
--- a/components/resource_provider/file_utils.cc
+++ b/components/resource_provider/file_utils.cc
@@ -8,7 +8,6 @@
 #include "base/path_service.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
-#include "url/gurl.h"
 
 namespace resource_provider {
 namespace {
@@ -27,18 +26,30 @@
 
 }  // namespace
 
-base::FilePath GetPathForApplicationUrl(const GURL& application_url) {
-  if (application_url.scheme() != "mojo" && application_url.scheme() != "exe")
+base::FilePath GetPathForApplicationUrl(const std::string& application_url) {
+// We don't want to use GURL because it can behave differently depending on
+  // whether mojo:// has been registered as a standard scheme or not. Also, we
+  // can get mojo:foo or mojo://foo urls here.
+  std::string path = application_url;
+  if (!base::StartsWith(path, "mojo:", base::CompareCase::INSENSITIVE_ASCII) &&
+      !base::StartsWith(path, "exe:", base::CompareCase::INSENSITIVE_ASCII))
     return base::FilePath();
-
-  std::string path = application_url.path();
+  if (path.find('.') != std::string::npos)
+    return base::FilePath();
+  if (base::StartsWith(path, "mojo:", base::CompareCase::INSENSITIVE_ASCII))
+    path.erase(path.begin(), path.begin() + 5);
+  else
+    path.erase(path.begin(), path.begin() + 4);
   base::TrimString(path, "/", &path);
+  size_t end_of_name = path.find('/');
+  if (end_of_name != std::string::npos)
+    path.erase(path.begin() + end_of_name, path.end());
 
   // TODO(beng): I'm adding this because there is a collision between the
   //             executable name in the exe dir and the resource package dir on
   //             non-Windows systems. Arbitrary exes should probably load their
   //             resources themselves rather than use resource provider.
-  if (application_url.SchemeIs("exe"))
+  if (base::StartsWith(path, "exe:", base::CompareCase::INSENSITIVE_ASCII))
     path += "_res";
 
   if (!IsPathNameValid(path))
diff --git a/components/resource_provider/file_utils.h b/components/resource_provider/file_utils.h
index 7ddf947..9f5ce62 100644
--- a/components/resource_provider/file_utils.h
+++ b/components/resource_provider/file_utils.h
@@ -7,8 +7,6 @@
 
 #include <string>
 
-class GURL;
-
 namespace base {
 class FilePath;
 }
@@ -17,7 +15,7 @@
 
 // Returns the path to the resources for |application_url|, or an empty
 // path if |application_url| is not valid.
-base::FilePath GetPathForApplicationUrl(const GURL& application_url);
+base::FilePath GetPathForApplicationUrl(const std::string& application_url);
 
 // Returns the path to the specified resource. |app_path| was previously
 // obtained by way of GetPathForApplicationUrl().
diff --git a/components/resource_provider/file_utils_unittest.cc b/components/resource_provider/file_utils_unittest.cc
index 96de984..0e33fe1 100644
--- a/components/resource_provider/file_utils_unittest.cc
+++ b/components/resource_provider/file_utils_unittest.cc
@@ -26,8 +26,8 @@
   };
 
   for (size_t i = 0; i < arraysize(invalid_cases); ++i) {
-    const GURL url(invalid_cases[i].url);
-    base::FilePath resulting_path(GetPathForApplicationUrl(url));
+    base::FilePath resulting_path(GetPathForApplicationUrl(
+        invalid_cases[i].url));
     EXPECT_TRUE(resulting_path.empty()) << "i=" << i
                                         << " input=" << invalid_cases[i].url
                                         << " result=" << resulting_path.value();
@@ -50,7 +50,7 @@
       {"bar//baz/"},
   };
 
-  const base::FilePath app_path(GetPathForApplicationUrl(GURL("mojo:test")));
+  const base::FilePath app_path(GetPathForApplicationUrl("mojo:test"));
   ASSERT_FALSE(app_path.empty());
 
   for (size_t i = 0; i < arraysize(invalid_cases); ++i) {
@@ -63,7 +63,7 @@
 }
 
 TEST(FileUtilsTest, ValidPaths) {
-  const base::FilePath app_path(GetPathForApplicationUrl(GURL("mojo:test")));
+  const base::FilePath app_path(GetPathForApplicationUrl("mojo:test"));
   ASSERT_FALSE(app_path.empty());
 
   // Trivial single path element.
diff --git a/components/resource_provider/public/cpp/BUILD.gn b/components/resource_provider/public/cpp/BUILD.gn
index 8cfa313..5d21378 100644
--- a/components/resource_provider/public/cpp/BUILD.gn
+++ b/components/resource_provider/public/cpp/BUILD.gn
@@ -14,6 +14,7 @@
     "//mojo/application/public/cpp",
     "//mojo/application/public/interfaces",
     "//mojo/common",
+    "//mojo/platform_handle:for_shared_library",
     "//third_party/mojo/src/mojo/public/cpp/bindings",
     "//third_party/mojo/src/mojo/public/cpp/system",
   ]
diff --git a/components/resource_provider/resource_provider_app.cc b/components/resource_provider/resource_provider_app.cc
index b835b208a..c7cd6fae 100644
--- a/components/resource_provider/resource_provider_app.cc
+++ b/components/resource_provider/resource_provider_app.cc
@@ -25,7 +25,7 @@
 bool ResourceProviderApp::ConfigureIncomingConnection(
     mojo::ApplicationConnection* connection) {
   const base::FilePath app_path(
-      GetPathForApplicationUrl(GURL(connection->GetRemoteApplicationURL())));
+      GetPathForApplicationUrl(connection->GetRemoteApplicationURL()));
   if (app_path.empty())
     return false;  // The specified app has no resources.
 
@@ -37,7 +37,7 @@
     mojo::ApplicationConnection* connection,
     mojo::InterfaceRequest<ResourceProvider> request) {
   const base::FilePath app_path(
-      GetPathForApplicationUrl(GURL(connection->GetRemoteApplicationURL())));
+      GetPathForApplicationUrl(connection->GetRemoteApplicationURL()));
   // We validated path at ConfigureIncomingConnection() time, so it should still
   // be valid.
   CHECK(!app_path.empty());
diff --git a/components/resource_provider/resource_provider_impl.cc b/components/resource_provider/resource_provider_impl.cc
index c93c3e2..3f14e76 100644
--- a/components/resource_provider/resource_provider_impl.cc
+++ b/components/resource_provider/resource_provider_impl.cc
@@ -70,7 +70,7 @@
 
 void ResourceProviderImpl::GetICUHandle(const GetICUHandleCallback& callback) {
   const base::FilePath resource_app_path(
-      GetPathForApplicationUrl(GURL(resource_provider_app_url_)));
+      GetPathForApplicationUrl(resource_provider_app_url_));
   mojo::ScopedHandle handle = GetHandleForPath(
       GetPathForResourceNamed(resource_app_path, kResourceIcudtl));
   callback.Run(handle.Pass());
diff --git a/components/scheduler/renderer/renderer_scheduler.h b/components/scheduler/renderer/renderer_scheduler.h
index 5f7b0a5..ef6621a 100644
--- a/components/scheduler/renderer/renderer_scheduler.h
+++ b/components/scheduler/renderer/renderer_scheduler.h
@@ -16,6 +16,10 @@
 struct BeginFrameArgs;
 }
 
+namespace blink {
+class WebThread;
+}
+
 namespace scheduler {
 
 class RenderWidgetSchedulingState;
@@ -43,6 +47,9 @@
   };
   static const char* UseCaseToString(UseCase use_case);
 
+  // Creates a WebThread implementation for the renderer main thread.
+  virtual scoped_ptr<blink::WebThread> CreateMainThread() = 0;
+
   // Returns the loading task runner.  This queue is intended for tasks related
   // to resource dispatch, foreground HTML parsing, etc...
   virtual scoped_refptr<base::SingleThreadTaskRunner> LoadingTaskRunner() = 0;
diff --git a/components/scheduler/renderer/renderer_scheduler_impl.cc b/components/scheduler/renderer/renderer_scheduler_impl.cc
index e06e47a..0ee5481d 100644
--- a/components/scheduler/renderer/renderer_scheduler_impl.cc
+++ b/components/scheduler/renderer/renderer_scheduler_impl.cc
@@ -13,6 +13,7 @@
 #include "components/scheduler/base/task_queue_impl.h"
 #include "components/scheduler/base/task_queue_selector.h"
 #include "components/scheduler/child/scheduler_tqm_delegate.h"
+#include "components/scheduler/renderer/webthread_impl_for_renderer_scheduler.h"
 
 namespace scheduler {
 namespace {
@@ -145,6 +146,10 @@
   MainThreadOnly().was_shutdown = true;
 }
 
+scoped_ptr<blink::WebThread> RendererSchedulerImpl::CreateMainThread() {
+  return make_scoped_ptr(new WebThreadImplForRendererScheduler(this)).Pass();
+}
+
 scoped_refptr<TaskQueue> RendererSchedulerImpl::DefaultTaskRunner() {
   return helper_.DefaultTaskRunner();
 }
diff --git a/components/scheduler/renderer/renderer_scheduler_impl.h b/components/scheduler/renderer/renderer_scheduler_impl.h
index cf86ab7..6fb097a1 100644
--- a/components/scheduler/renderer/renderer_scheduler_impl.h
+++ b/components/scheduler/renderer/renderer_scheduler_impl.h
@@ -37,6 +37,7 @@
   ~RendererSchedulerImpl() override;
 
   // RendererScheduler implementation:
+  scoped_ptr<blink::WebThread> CreateMainThread() override;
   scoped_refptr<TaskQueue> DefaultTaskRunner() override;
   scoped_refptr<SingleThreadIdleTaskRunner> IdleTaskRunner() override;
   scoped_refptr<base::SingleThreadTaskRunner> CompositorTaskRunner() override;
diff --git a/components/scheduler/renderer/renderer_web_scheduler_impl.cc b/components/scheduler/renderer/renderer_web_scheduler_impl.cc
index 6e702e4d..922b1bdc 100644
--- a/components/scheduler/renderer/renderer_web_scheduler_impl.cc
+++ b/components/scheduler/renderer/renderer_web_scheduler_impl.cc
@@ -5,20 +5,19 @@
 #include "components/scheduler/renderer/renderer_web_scheduler_impl.h"
 
 #include "components/scheduler/base/task_queue.h"
-#include "components/scheduler/renderer/renderer_scheduler.h"
+#include "components/scheduler/renderer/renderer_scheduler_impl.h"
 #include "components/scheduler/renderer/web_view_scheduler_impl.h"
 #include "third_party/WebKit/public/platform/WebPassOwnPtr.h"
 
 namespace scheduler {
 
 RendererWebSchedulerImpl::RendererWebSchedulerImpl(
-    RendererScheduler* renderer_scheduler)
+    RendererSchedulerImpl* renderer_scheduler)
     : WebSchedulerImpl(renderer_scheduler,
                        renderer_scheduler->IdleTaskRunner(),
                        renderer_scheduler->LoadingTaskRunner(),
                        renderer_scheduler->TimerTaskRunner()),
-      renderer_scheduler_(renderer_scheduler) {
-}
+      renderer_scheduler_(renderer_scheduler) {}
 
 RendererWebSchedulerImpl::~RendererWebSchedulerImpl() {
 }
diff --git a/components/scheduler/renderer/renderer_web_scheduler_impl.h b/components/scheduler/renderer/renderer_web_scheduler_impl.h
index 98faf4f..acab082 100644
--- a/components/scheduler/renderer/renderer_web_scheduler_impl.h
+++ b/components/scheduler/renderer/renderer_web_scheduler_impl.h
@@ -9,11 +9,11 @@
 
 namespace scheduler {
 
-class RendererScheduler;
+class RendererSchedulerImpl;
 
 class SCHEDULER_EXPORT RendererWebSchedulerImpl : public WebSchedulerImpl {
  public:
-  explicit RendererWebSchedulerImpl(RendererScheduler* child_scheduler);
+  explicit RendererWebSchedulerImpl(RendererSchedulerImpl* renderer_scheduler);
 
   ~RendererWebSchedulerImpl() override;
 
@@ -27,7 +27,7 @@
   void onNavigationStarted() override;
 
  private:
-  RendererScheduler* renderer_scheduler_;  // NOT OWNED
+  RendererSchedulerImpl* renderer_scheduler_;  // NOT OWNED
 };
 
 }  // namespace scheduler
diff --git a/components/scheduler/renderer/web_frame_scheduler_impl.cc b/components/scheduler/renderer/web_frame_scheduler_impl.cc
index c4204cc8..15e4a7d 100644
--- a/components/scheduler/renderer/web_frame_scheduler_impl.cc
+++ b/components/scheduler/renderer/web_frame_scheduler_impl.cc
@@ -5,16 +5,16 @@
 #include "components/scheduler/renderer/web_frame_scheduler_impl.h"
 
 #include "components/scheduler/child/web_task_runner_impl.h"
-#include "components/scheduler/renderer/renderer_scheduler.h"
+#include "components/scheduler/renderer/renderer_scheduler_impl.h"
 #include "components/scheduler/renderer/web_view_scheduler_impl.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 
 namespace scheduler {
 
 WebFrameSchedulerImpl::WebFrameSchedulerImpl(
-    RendererScheduler* render_scheduler,
+    RendererSchedulerImpl* renderer_scheduler,
     WebViewSchedulerImpl* parent_web_view_scheduler)
-    : render_scheduler_(render_scheduler),
+    : renderer_scheduler_(renderer_scheduler),
       parent_web_view_scheduler_(parent_web_view_scheduler),
       visible_(true) {}
 
@@ -41,7 +41,7 @@
 blink::WebTaskRunner* WebFrameSchedulerImpl::loadingTaskRunner() {
   if (!loading_web_task_runner_) {
     loading_task_queue_ =
-        render_scheduler_->NewLoadingTaskRunner("frame_loading_tq");
+        renderer_scheduler_->NewLoadingTaskRunner("frame_loading_tq");
     loading_web_task_runner_.reset(new WebTaskRunnerImpl(loading_task_queue_));
   }
   return loading_web_task_runner_.get();
@@ -49,7 +49,8 @@
 
 blink::WebTaskRunner* WebFrameSchedulerImpl::timerTaskRunner() {
   if (!timer_web_task_runner_) {
-    timer_task_queue_ = render_scheduler_->NewTimerTaskRunner("frame_timer_tq");
+    timer_task_queue_ =
+        renderer_scheduler_->NewTimerTaskRunner("frame_timer_tq");
     timer_web_task_runner_.reset(new WebTaskRunnerImpl(timer_task_queue_));
   }
   return timer_web_task_runner_.get();
diff --git a/components/scheduler/renderer/web_frame_scheduler_impl.h b/components/scheduler/renderer/web_frame_scheduler_impl.h
index e8a3eba..eb14bc0 100644
--- a/components/scheduler/renderer/web_frame_scheduler_impl.h
+++ b/components/scheduler/renderer/web_frame_scheduler_impl.h
@@ -18,14 +18,14 @@
 
 namespace scheduler {
 
-class RendererScheduler;
+class RendererSchedulerImpl;
 class TaskQueue;
 class WebTaskRunnerImpl;
 class WebViewSchedulerImpl;
 
 class SCHEDULER_EXPORT WebFrameSchedulerImpl : public blink::WebFrameScheduler {
  public:
-  WebFrameSchedulerImpl(RendererScheduler* render_scheduler,
+  WebFrameSchedulerImpl(RendererSchedulerImpl* renderer_scheduler,
                         WebViewSchedulerImpl* parent_web_view_scheduler);
 
   ~WebFrameSchedulerImpl() override;
@@ -45,7 +45,7 @@
   scoped_refptr<TaskQueue> timer_task_queue_;
   scoped_ptr<WebTaskRunnerImpl> loading_web_task_runner_;
   scoped_ptr<WebTaskRunnerImpl> timer_web_task_runner_;
-  RendererScheduler* render_scheduler_;              // NOT OWNED
+  RendererSchedulerImpl* renderer_scheduler_;        // NOT OWNED
   WebViewSchedulerImpl* parent_web_view_scheduler_;  // NOT OWNED
   blink::WebSecurityOrigin origin_;
   bool visible_;
diff --git a/components/scheduler/renderer/web_view_scheduler_impl.cc b/components/scheduler/renderer/web_view_scheduler_impl.cc
index 2bb36a4e..28bc216 100644
--- a/components/scheduler/renderer/web_view_scheduler_impl.cc
+++ b/components/scheduler/renderer/web_view_scheduler_impl.cc
@@ -12,7 +12,7 @@
 
 WebViewSchedulerImpl::WebViewSchedulerImpl(
     blink::WebView* web_view,
-    RendererScheduler* renderer_scheduler)
+    RendererSchedulerImpl* renderer_scheduler)
     : web_view_(web_view),
       renderer_scheduler_(renderer_scheduler),
       background_(false) {}
diff --git a/components/scheduler/renderer/web_view_scheduler_impl.h b/components/scheduler/renderer/web_view_scheduler_impl.h
index 7ec84d86..647d6d9 100644
--- a/components/scheduler/renderer/web_view_scheduler_impl.h
+++ b/components/scheduler/renderer/web_view_scheduler_impl.h
@@ -21,13 +21,13 @@
 
 namespace scheduler {
 
-class RendererScheduler;
+class RendererSchedulerImpl;
 class WebFrameSchedulerImpl;
 
 class SCHEDULER_EXPORT WebViewSchedulerImpl : public blink::WebViewScheduler {
  public:
-  explicit WebViewSchedulerImpl(blink::WebView* web_view,
-                                RendererScheduler* render_scheduler);
+  WebViewSchedulerImpl(blink::WebView* web_view,
+                       RendererSchedulerImpl* renderer_scheduler);
 
   ~WebViewSchedulerImpl() override;
 
@@ -45,7 +45,7 @@
 
   std::set<WebFrameSchedulerImpl*> frame_schedulers_;
   blink::WebView* web_view_;
-  RendererScheduler* renderer_scheduler_;
+  RendererSchedulerImpl* renderer_scheduler_;
   bool background_;
 
   DISALLOW_COPY_AND_ASSIGN(WebViewSchedulerImpl);
diff --git a/components/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc b/components/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc
index cd725b0ef..f59e714c 100644
--- a/components/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc
+++ b/components/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc
@@ -6,14 +6,14 @@
 
 #include "components/scheduler/base/task_queue.h"
 #include "components/scheduler/child/web_task_runner_impl.h"
-#include "components/scheduler/renderer/renderer_scheduler.h"
+#include "components/scheduler/renderer/renderer_scheduler_impl.h"
 #include "components/scheduler/renderer/renderer_web_scheduler_impl.h"
 #include "third_party/WebKit/public/platform/WebTraceLocation.h"
 
 namespace scheduler {
 
 WebThreadImplForRendererScheduler::WebThreadImplForRendererScheduler(
-    RendererScheduler* scheduler)
+    RendererSchedulerImpl* scheduler)
     : web_scheduler_(new RendererWebSchedulerImpl(scheduler)),
       task_runner_(scheduler->DefaultTaskRunner()),
       idle_task_runner_(scheduler->IdleTaskRunner()),
diff --git a/components/scheduler/renderer/webthread_impl_for_renderer_scheduler.h b/components/scheduler/renderer/webthread_impl_for_renderer_scheduler.h
index 0c54c467..3befa1c 100644
--- a/components/scheduler/renderer/webthread_impl_for_renderer_scheduler.h
+++ b/components/scheduler/renderer/webthread_impl_for_renderer_scheduler.h
@@ -13,14 +13,14 @@
 };
 
 namespace scheduler {
-class RendererScheduler;
+class RendererSchedulerImpl;
 class WebSchedulerImpl;
 class WebTaskRunnerImpl;
 
 class SCHEDULER_EXPORT WebThreadImplForRendererScheduler
     : public WebThreadBase {
  public:
-  explicit WebThreadImplForRendererScheduler(RendererScheduler* scheduler);
+  explicit WebThreadImplForRendererScheduler(RendererSchedulerImpl* scheduler);
   ~WebThreadImplForRendererScheduler() override;
 
   // blink::WebThread implementation.
@@ -41,7 +41,7 @@
   scoped_ptr<WebSchedulerImpl> web_scheduler_;
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
   scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_;
-  RendererScheduler* scheduler_;  // Not owned.
+  RendererSchedulerImpl* scheduler_;  // Not owned.
   blink::PlatformThreadId thread_id_;
   scoped_ptr<WebTaskRunnerImpl> web_task_runner_;
 };
diff --git a/components/scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc b/components/scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc
index 2f6d0b8..52f4ee85 100644
--- a/components/scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc
+++ b/components/scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc
@@ -41,7 +41,7 @@
             &message_loop_,
             make_scoped_ptr(new TestTimeSource(clock_.get())))),
         default_task_runner_(scheduler_.DefaultTaskRunner()),
-        thread_(&scheduler_) {}
+        thread_(scheduler_.CreateMainThread()) {}
 
   ~WebThreadImplForRendererSchedulerTest() override {}
 
@@ -57,14 +57,14 @@
   scoped_ptr<base::SimpleTestTickClock> clock_;
   RendererSchedulerImpl scheduler_;
   scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_;
-  WebThreadImplForRendererScheduler thread_;
+  scoped_ptr<blink::WebThread> thread_;
 
   DISALLOW_COPY_AND_ASSIGN(WebThreadImplForRendererSchedulerTest);
 };
 
 TEST_F(WebThreadImplForRendererSchedulerTest, TestTaskObserver) {
   MockTaskObserver observer;
-  thread_.addTaskObserver(&observer);
+  thread_->addTaskObserver(&observer);
   scoped_ptr<MockTask> task(new MockTask());
 
   {
@@ -74,14 +74,14 @@
     EXPECT_CALL(observer, didProcessTask());
   }
 
-  thread_.taskRunner()->postTask(blink::WebTraceLocation(), task.release());
+  thread_->taskRunner()->postTask(blink::WebTraceLocation(), task.release());
   message_loop_.RunUntilIdle();
-  thread_.removeTaskObserver(&observer);
+  thread_->removeTaskObserver(&observer);
 }
 
 TEST_F(WebThreadImplForRendererSchedulerTest, TestWorkBatchWithOneTask) {
   MockTaskObserver observer;
-  thread_.addTaskObserver(&observer);
+  thread_->addTaskObserver(&observer);
   scoped_ptr<MockTask> task(new MockTask());
 
   SetWorkBatchSizeForTesting(kWorkBatchSize);
@@ -92,14 +92,14 @@
     EXPECT_CALL(observer, didProcessTask());
   }
 
-  thread_.taskRunner()->postTask(blink::WebTraceLocation(), task.release());
+  thread_->taskRunner()->postTask(blink::WebTraceLocation(), task.release());
   message_loop_.RunUntilIdle();
-  thread_.removeTaskObserver(&observer);
+  thread_->removeTaskObserver(&observer);
 }
 
 TEST_F(WebThreadImplForRendererSchedulerTest, TestWorkBatchWithTwoTasks) {
   MockTaskObserver observer;
-  thread_.addTaskObserver(&observer);
+  thread_->addTaskObserver(&observer);
   scoped_ptr<MockTask> task1(new MockTask());
   scoped_ptr<MockTask> task2(new MockTask());
 
@@ -115,15 +115,15 @@
     EXPECT_CALL(observer, didProcessTask());
   }
 
-  thread_.taskRunner()->postTask(blink::WebTraceLocation(), task1.release());
-  thread_.taskRunner()->postTask(blink::WebTraceLocation(), task2.release());
+  thread_->taskRunner()->postTask(blink::WebTraceLocation(), task1.release());
+  thread_->taskRunner()->postTask(blink::WebTraceLocation(), task2.release());
   message_loop_.RunUntilIdle();
-  thread_.removeTaskObserver(&observer);
+  thread_->removeTaskObserver(&observer);
 }
 
 TEST_F(WebThreadImplForRendererSchedulerTest, TestWorkBatchWithThreeTasks) {
   MockTaskObserver observer;
-  thread_.addTaskObserver(&observer);
+  thread_->addTaskObserver(&observer);
   scoped_ptr<MockTask> task1(new MockTask());
   scoped_ptr<MockTask> task2(new MockTask());
   scoped_ptr<MockTask> task3(new MockTask());
@@ -144,11 +144,11 @@
     EXPECT_CALL(observer, didProcessTask());
   }
 
-  thread_.taskRunner()->postTask(blink::WebTraceLocation(), task1.release());
-  thread_.taskRunner()->postTask(blink::WebTraceLocation(), task2.release());
-  thread_.taskRunner()->postTask(blink::WebTraceLocation(), task3.release());
+  thread_->taskRunner()->postTask(blink::WebTraceLocation(), task1.release());
+  thread_->taskRunner()->postTask(blink::WebTraceLocation(), task2.release());
+  thread_->taskRunner()->postTask(blink::WebTraceLocation(), task3.release());
   message_loop_.RunUntilIdle();
-  thread_.removeTaskObserver(&observer);
+  thread_->removeTaskObserver(&observer);
 }
 
 class ExitRunLoopTask : public blink::WebTaskRunner::Task {
@@ -173,7 +173,7 @@
 
 TEST_F(WebThreadImplForRendererSchedulerTest, TestNestedRunLoop) {
   MockTaskObserver observer;
-  thread_.addTaskObserver(&observer);
+  thread_->addTaskObserver(&observer);
 
   {
     testing::InSequence sequence;
@@ -191,9 +191,9 @@
 
   message_loop_.task_runner()->PostTask(
       FROM_HERE, base::Bind(&EnterRunLoop, base::Unretained(&message_loop_),
-                            base::Unretained(&thread_)));
+                            base::Unretained(thread_.get())));
   message_loop_.RunUntilIdle();
-  thread_.removeTaskObserver(&observer);
+  thread_->removeTaskObserver(&observer);
 }
 
 }  // namespace scheduler
diff --git a/components/sessions/content/content_serialized_navigation_driver.h b/components/sessions/content/content_serialized_navigation_driver.h
index dafaee2..c0911d7 100644
--- a/components/sessions/content/content_serialized_navigation_driver.h
+++ b/components/sessions/content/content_serialized_navigation_driver.h
@@ -17,7 +17,7 @@
 
 // Provides an implementation of SerializedNavigationDriver that is backed by
 // content classes.
-class SESSIONS_EXPORT_PRIVATE ContentSerializedNavigationDriver
+class SESSIONS_EXPORT ContentSerializedNavigationDriver
     : public SerializedNavigationDriver {
  public:
   ~ContentSerializedNavigationDriver() override;
diff --git a/components/sessions/core/serialized_navigation_driver.h b/components/sessions/core/serialized_navigation_driver.h
index 767394ca..5fc261e 100644
--- a/components/sessions/core/serialized_navigation_driver.h
+++ b/components/sessions/core/serialized_navigation_driver.h
@@ -16,7 +16,7 @@
 // The SerializedNavigationDriver interface allows SerializedNavigationEntry to
 // obtain information from a singleton driver object. A concrete implementation
 // must be provided by the driver on each platform.
-class SESSIONS_EXPORT_PRIVATE SerializedNavigationDriver {
+class SESSIONS_EXPORT SerializedNavigationDriver {
  public:
   virtual ~SerializedNavigationDriver() {}
 
diff --git a/components/sessions/core/sessions_export.h b/components/sessions/core/sessions_export.h
index 4ba194d..cd5ade48 100644
--- a/components/sessions/core/sessions_export.h
+++ b/components/sessions/core/sessions_export.h
@@ -10,25 +10,20 @@
 
 #if defined(SESSIONS_IMPLEMENTATION)
 #define SESSIONS_EXPORT __declspec(dllexport)
-#define SESSIONS_EXPORT_PRIVATE __declspec(dllexport)
 #else
 #define SESSIONS_EXPORT __declspec(dllimport)
-#define SESSIONS_EXPORT_PRIVATE __declspec(dllimport)
 #endif  // defined(SESSIONS_IMPLEMENTATION)
 
 #else  // defined(WIN32)
 #if defined(SESSIONS_IMPLEMENTATION)
 #define SESSIONS_EXPORT __attribute__((visibility("default")))
-#define SESSIONS_EXPORT_PRIVATE __attribute__((visibility("default")))
 #else
 #define SESSIONS_EXPORT
-#define SESSIONS_EXPORT_PRIVATE
 #endif
 #endif
 
 #else  // defined(COMPONENT_BUILD)
 #define SESSIONS_EXPORT
-#define SESSIONS_EXPORT_PRIVATE
 #endif
 
 #endif  // COMPONENTS_SESSIONS_CORE_SESSIONS_EXPORT_H_
diff --git a/components/test/data/password_manager/login_db_v12.sql b/components/test/data/password_manager/login_db_v12.sql
index 9530fb5a..c25cb0e 100644
--- a/components/test/data/password_manager/login_db_v12.sql
+++ b/components/test/data/password_manager/login_db_v12.sql
@@ -79,4 +79,9 @@
 0  /* generation_upload_status */
 );
 CREATE INDEX logins_signon ON logins (signon_realm);
+CREATE TABLE stats (
+origin_domain VARCHAR NOT NULL PRIMARY KEY, 
+nopes_count INTEGER,
+dismissal_count INTEGER, 
+start_date INTEGER NOT NULL);
 COMMIT;
diff --git a/components/test/data/password_manager/login_db_v13.sql b/components/test/data/password_manager/login_db_v13.sql
index 451c3e4d..c71773f 100644
--- a/components/test/data/password_manager/login_db_v13.sql
+++ b/components/test/data/password_manager/login_db_v13.sql
@@ -79,4 +79,9 @@
 0  /* generation_upload_status */
 );
 CREATE INDEX logins_signon ON logins (signon_realm);
+CREATE TABLE stats (
+origin_domain VARCHAR NOT NULL PRIMARY KEY, 
+nopes_count INTEGER,
+dismissal_count INTEGER, 
+start_date INTEGER NOT NULL);
 COMMIT;
diff --git a/components/test/data/password_manager/login_db_v14.sql b/components/test/data/password_manager/login_db_v14.sql
index 063260f1..cdf4b31 100644
--- a/components/test/data/password_manager/login_db_v14.sql
+++ b/components/test/data/password_manager/login_db_v14.sql
@@ -79,4 +79,9 @@
 0  /* generation_upload_status */
 );
 CREATE INDEX logins_signon ON logins (signon_realm);
+CREATE TABLE stats (
+origin_domain VARCHAR NOT NULL PRIMARY KEY, 
+nopes_count INTEGER,
+dismissal_count INTEGER, 
+start_date INTEGER NOT NULL);
 COMMIT;
diff --git a/components/test/data/password_manager/login_db_v15.sql b/components/test/data/password_manager/login_db_v15.sql
new file mode 100644
index 0000000..9e3af8f
--- /dev/null
+++ b/components/test/data/password_manager/login_db_v15.sql
@@ -0,0 +1,87 @@
+PRAGMA foreign_keys=OFF;
+BEGIN TRANSACTION;
+CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR);
+INSERT INTO "meta" VALUES('last_compatible_version','14');
+INSERT INTO "meta" VALUES('version','15');
+CREATE TABLE logins (
+origin_url VARCHAR NOT NULL,
+action_url VARCHAR,
+username_element VARCHAR,
+username_value VARCHAR,
+password_element VARCHAR,
+password_value BLOB,
+submit_element VARCHAR,
+signon_realm VARCHAR NOT NULL,
+ssl_valid INTEGER NOT NULL,
+preferred INTEGER NOT NULL,
+date_created INTEGER NOT NULL,
+blacklisted_by_user INTEGER NOT NULL,
+scheme INTEGER NOT NULL,
+password_type INTEGER,
+possible_usernames BLOB,
+times_used INTEGER,
+form_data BLOB,
+date_synced INTEGER,
+display_name VARCHAR,
+icon_url VARCHAR,
+federation_url VARCHAR,
+skip_zero_click INTEGER,
+generation_upload_status INTEGER,
+UNIQUE (origin_url, username_element, username_value, password_element, signon_realm));
+INSERT INTO "logins" VALUES(
+'https://accounts.google.com/ServiceLogin', /* origin_url */
+'https://accounts.google.com/ServiceLoginAuth', /* action_url */
+'Email', /* username_element */
+'theerikchen', /* username_value */
+'Passwd', /* password_element */
+X'', /* password_value */
+'', /* submit_element */
+'https://accounts.google.com/', /* signon_realm */
+1, /* ssl_valid */
+1, /* preferred */
+13047429345000000, /* date_created */
+0, /* blacklisted_by_user */
+0, /* scheme */
+0, /* password_type */
+X'00000000', /* possible_usernames */
+1, /* times_used */
+X'18000000020000000000000000000000000000000000000000000000', /* form_data */
+0, /* date_synced */
+'', /* display_name */
+'', /* icon_url */
+'', /* federation_url */
+0,  /* skip_zero_click */
+0  /* generation_upload_status */
+);
+INSERT INTO "logins" VALUES(
+'https://accounts.google.com/ServiceLogin', /* origin_url */
+'https://accounts.google.com/ServiceLoginAuth', /* action_url */
+'Email', /* username_element */
+'theerikchen2', /* username_value */
+'Passwd', /* password_element */
+X'', /* password_value */
+'non-empty', /* submit_element */
+'https://accounts.google.com/', /* signon_realm */
+1, /* ssl_valid */
+1, /* preferred */
+13047423600000000, /* date_created */
+0, /* blacklisted_by_user */
+0, /* scheme */
+0, /* password_type */
+X'00000000', /* possible_usernames */
+1, /* times_used */
+X'18000000020000000000000000000000000000000000000000000000', /* form_data */
+0, /* date_synced */
+'', /* display_name */
+'https://www.google.com/icon', /* icon_url */
+'', /* federation_url */
+0,  /* skip_zero_click */
+0  /* generation_upload_status */
+);
+CREATE INDEX logins_signon ON logins (signon_realm);
+CREATE TABLE stats (
+origin_domain VARCHAR NOT NULL PRIMARY KEY,
+nopes_count INTEGER,
+dismissal_count INTEGER,
+start_date INTEGER NOT NULL);
+COMMIT;
diff --git a/components/test/data/password_manager/login_db_v16.sql b/components/test/data/password_manager/login_db_v16.sql
new file mode 100644
index 0000000..e52bd253
--- /dev/null
+++ b/components/test/data/password_manager/login_db_v16.sql
@@ -0,0 +1,89 @@
+PRAGMA foreign_keys=OFF;
+BEGIN TRANSACTION;
+CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR);
+INSERT INTO "meta" VALUES('last_compatible_version','14');
+INSERT INTO "meta" VALUES('version','15');
+CREATE TABLE logins (
+origin_url VARCHAR NOT NULL,
+action_url VARCHAR,
+username_element VARCHAR,
+username_value VARCHAR,
+password_element VARCHAR,
+password_value BLOB,
+submit_element VARCHAR,
+signon_realm VARCHAR NOT NULL,
+ssl_valid INTEGER NOT NULL,
+preferred INTEGER NOT NULL,
+date_created INTEGER NOT NULL,
+blacklisted_by_user INTEGER NOT NULL,
+scheme INTEGER NOT NULL,
+password_type INTEGER,
+possible_usernames BLOB,
+times_used INTEGER,
+form_data BLOB,
+date_synced INTEGER,
+display_name VARCHAR,
+icon_url VARCHAR,
+federation_url VARCHAR,
+skip_zero_click INTEGER,
+generation_upload_status INTEGER,
+UNIQUE (origin_url, username_element, username_value, password_element, signon_realm));
+INSERT INTO "logins" VALUES(
+'https://accounts.google.com/ServiceLogin', /* origin_url */
+'https://accounts.google.com/ServiceLoginAuth', /* action_url */
+'Email', /* username_element */
+'theerikchen', /* username_value */
+'Passwd', /* password_element */
+X'', /* password_value */
+'', /* submit_element */
+'https://accounts.google.com/', /* signon_realm */
+1, /* ssl_valid */
+1, /* preferred */
+13047429345000000, /* date_created */
+0, /* blacklisted_by_user */
+0, /* scheme */
+0, /* password_type */
+X'00000000', /* possible_usernames */
+1, /* times_used */
+X'18000000020000000000000000000000000000000000000000000000', /* form_data */
+0, /* date_synced */
+'', /* display_name */
+'', /* icon_url */
+'', /* federation_url */
+0,  /* skip_zero_click */
+0  /* generation_upload_status */
+);
+INSERT INTO "logins" VALUES(
+'https://accounts.google.com/ServiceLogin', /* origin_url */
+'https://accounts.google.com/ServiceLoginAuth', /* action_url */
+'Email', /* username_element */
+'theerikchen2', /* username_value */
+'Passwd', /* password_element */
+X'', /* password_value */
+'non-empty', /* submit_element */
+'https://accounts.google.com/', /* signon_realm */
+1, /* ssl_valid */
+1, /* preferred */
+13047423600000000, /* date_created */
+0, /* blacklisted_by_user */
+0, /* scheme */
+0, /* password_type */
+X'00000000', /* possible_usernames */
+1, /* times_used */
+X'18000000020000000000000000000000000000000000000000000000', /* form_data */
+0, /* date_synced */
+'', /* display_name */
+'https://www.google.com/icon', /* icon_url */
+'', /* federation_url */
+0,  /* skip_zero_click */
+0  /* generation_upload_status */
+);
+CREATE INDEX logins_signon ON logins (signon_realm);
+CREATE TABLE stats (
+origin_domain VARCHAR NOT NULL,
+username_value VARCHAR,
+dismissal_count INTEGER,
+update_time INTEGER NOT NULL,
+UNIQUE(origin_domain, username_value));
+CREATE INDEX stats_origin ON stats(origin_domain);
+COMMIT;
diff --git a/content/browser/android/url_request_content_job.cc b/content/browser/android/url_request_content_job.cc
index 594e89f3..1bcbf210 100644
--- a/content/browser/android/url_request_content_job.cc
+++ b/content/browser/android/url_request_content_job.cc
@@ -11,7 +11,6 @@
 #include "base/task_runner.h"
 #include "net/base/file_stream.h"
 #include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
 #include "net/http/http_util.h"
 #include "net/url_request/url_request_error_job.h"
 #include "url/gurl.h"
@@ -34,6 +33,7 @@
       content_path_(content_path),
       stream_(new net::FileStream(content_task_runner)),
       content_task_runner_(content_task_runner),
+      range_parse_result_(net::OK),
       remaining_bytes_(0),
       io_pending_(false),
       weak_ptr_factory_(this) {}
@@ -56,44 +56,28 @@
   net::URLRequestJob::Kill();
 }
 
-bool URLRequestContentJob::ReadRawData(net::IOBuffer* dest,
-                                       int dest_size,
-                                       int* bytes_read) {
+int URLRequestContentJob::ReadRawData(net::IOBuffer* dest, int dest_size) {
   DCHECK_GT(dest_size, 0);
-  DCHECK(bytes_read);
   DCHECK_GE(remaining_bytes_, 0);
 
   if (remaining_bytes_ < dest_size)
-    dest_size = static_cast<int>(remaining_bytes_);
+    dest_size = remaining_bytes_;
 
   // If we should copy zero bytes because |remaining_bytes_| is zero, short
   // circuit here.
-  if (!dest_size) {
-    *bytes_read = 0;
-    return true;
-  }
+  if (!dest_size)
+    return 0;
 
-  int rv = stream_->Read(dest,
-                         dest_size,
+  int rv = stream_->Read(dest, dest_size,
                          base::Bind(&URLRequestContentJob::DidRead,
-                                    weak_ptr_factory_.GetWeakPtr(),
-                                    make_scoped_refptr(dest)));
-  if (rv >= 0) {
-    // Data is immediately available.
-    *bytes_read = rv;
-    remaining_bytes_ -= rv;
-    DCHECK_GE(remaining_bytes_, 0);
-    return true;
-  }
-
-  // Otherwise, a read error occured.  We may just need to wait...
+                                    weak_ptr_factory_.GetWeakPtr()));
   if (rv == net::ERR_IO_PENDING) {
     io_pending_ = true;
-    SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
-  } else {
-    NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, rv));
+  } else if (rv > 0) {
+    remaining_bytes_ -= rv;
   }
-  return false;
+  DCHECK_GE(remaining_bytes_, 0);
+  return rv;
 }
 
 bool URLRequestContentJob::IsRedirectResponse(GURL* location,
@@ -116,16 +100,16 @@
   if (!headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header))
     return;
 
-  // We only care about "Range" header here.
+  // Currently this job only cares about the Range header. Note that validation
+  // is deferred to DidOpen(), because NotifyStartError is not legal to call
+  // since the job has not started.
   std::vector<net::HttpByteRange> ranges;
   if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) {
     if (ranges.size() == 1) {
       byte_range_ = ranges[0];
     } else {
       // We don't support multiple range requests.
-      NotifyDone(net::URLRequestStatus(
-          net::URLRequestStatus::FAILED,
-          net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
+      range_parse_result_ = net::ERR_REQUEST_RANGE_NOT_SATISFIABLE;
     }
   }
 }
@@ -162,13 +146,20 @@
 
 void URLRequestContentJob::DidOpen(int result) {
   if (result != net::OK) {
-    NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
+    NotifyStartError(
+        net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
+    return;
+  }
+
+  if (range_parse_result_ != net::OK) {
+    NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED,
+                                           range_parse_result_));
     return;
   }
 
   if (!byte_range_.ComputeBounds(meta_info_.content_size)) {
-    NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
-                                     net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
+    NotifyStartError(net::URLRequestStatus(
+        net::URLRequestStatus::FAILED, net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
     return;
   }
 
@@ -195,8 +186,8 @@
 
 void URLRequestContentJob::DidSeek(int64 result) {
   if (result != byte_range_.first_byte_position()) {
-    NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
-                                     net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
+    NotifyStartError(net::URLRequestStatus(
+        net::URLRequestStatus::FAILED, net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
     return;
   }
 
@@ -204,24 +195,16 @@
   NotifyHeadersComplete();
 }
 
-void URLRequestContentJob::DidRead(
-    scoped_refptr<net::IOBuffer> buf, int result) {
+void URLRequestContentJob::DidRead(int result) {
+  DCHECK(io_pending_);
+  io_pending_ = false;
+
   if (result > 0) {
-    SetStatus(net::URLRequestStatus());  // Clear the IO_PENDING status
     remaining_bytes_ -= result;
     DCHECK_GE(remaining_bytes_, 0);
   }
 
-  DCHECK(io_pending_);
-  io_pending_ = false;
-
-  if (result == 0) {
-    NotifyDone(net::URLRequestStatus());
-  } else if (result < 0) {
-    NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
-  }
-
-  NotifyReadComplete(result);
+  ReadRawDataComplete(result);
 }
 
 }  // namespace content
diff --git a/content/browser/android/url_request_content_job.h b/content/browser/android/url_request_content_job.h
index 5d3d9336..dad9fbfc 100644
--- a/content/browser/android/url_request_content_job.h
+++ b/content/browser/android/url_request_content_job.h
@@ -12,6 +12,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "content/common/content_export.h"
+#include "net/base/net_errors.h"
 #include "net/http/http_byte_range.h"
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_job.h"
@@ -42,7 +43,7 @@
   // net::URLRequestJob:
   void Start() override;
   void Kill() override;
-  bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override;
+  int ReadRawData(net::IOBuffer* buf, int buf_size) override;
   bool IsRedirectResponse(GURL* location, int* http_status_code) override;
   bool GetMimeType(std::string* mime_type) const override;
   void SetExtraRequestHeaders(const net::HttpRequestHeaders& headers) override;
@@ -79,7 +80,7 @@
   void DidSeek(int64 result);
 
   // Callback after data is asynchronously read from the content URI into |buf|.
-  void DidRead(scoped_refptr<net::IOBuffer> buf, int result);
+  void DidRead(int result);
 
   // The full path of the content URI.
   base::FilePath content_path_;
@@ -89,6 +90,7 @@
   const scoped_refptr<base::TaskRunner> content_task_runner_;
 
   net::HttpByteRange byte_range_;
+  net::Error range_parse_result_;
   int64 remaining_bytes_;
 
   bool io_pending_;
diff --git a/content/browser/appcache/appcache_url_request_job.cc b/content/browser/appcache/appcache_url_request_job.cc
index 5b06e6e8..de924a1 100644
--- a/content/browser/appcache/appcache_url_request_job.cc
+++ b/content/browser/appcache/appcache_url_request_job.cc
@@ -341,7 +341,6 @@
 void AppCacheURLRequestJob::OnReadComplete(int result) {
   DCHECK(is_delivering_appcache_response());
   if (result == 0) {
-    NotifyDone(net::URLRequestStatus());
     AppCacheHistograms::CountResponseRetrieval(
         true, is_main_resource_, manifest_url_.GetOrigin());
   } else if (result < 0) {
@@ -349,13 +348,10 @@
       storage_->service()->CheckAppCacheResponse(manifest_url_, cache_id_,
                                                  entry_.response_id());
     }
-    NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
     AppCacheHistograms::CountResponseRetrieval(
         false, is_main_resource_, manifest_url_.GetOrigin());
-  } else {
-    SetStatus(net::URLRequestStatus());  // Clear the IO_PENDING status
   }
-  NotifyReadComplete(result);
+  ReadRawDataComplete(result);
 }
 
 // net::URLRequestJob overrides ------------------------------------------------
@@ -424,17 +420,14 @@
   return http_info()->headers->response_code();
 }
 
-bool AppCacheURLRequestJob::ReadRawData(net::IOBuffer* buf, int buf_size,
-                                        int *bytes_read) {
+int AppCacheURLRequestJob::ReadRawData(net::IOBuffer* buf, int buf_size) {
   DCHECK(is_delivering_appcache_response());
   DCHECK_NE(buf_size, 0);
-  DCHECK(bytes_read);
   DCHECK(!reader_->IsReadPending());
-  reader_->ReadData(
-      buf, buf_size, base::Bind(&AppCacheURLRequestJob::OnReadComplete,
-                                base::Unretained(this)));
-  SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
-  return false;
+  reader_->ReadData(buf, buf_size,
+                    base::Bind(&AppCacheURLRequestJob::OnReadComplete,
+                               base::Unretained(this)));
+  return net::ERR_IO_PENDING;
 }
 
 void AppCacheURLRequestJob::SetExtraRequestHeaders(
diff --git a/content/browser/appcache/appcache_url_request_job.h b/content/browser/appcache/appcache_url_request_job.h
index 95a3e18..8f51e7b 100644
--- a/content/browser/appcache/appcache_url_request_job.h
+++ b/content/browser/appcache/appcache_url_request_job.h
@@ -148,7 +148,7 @@
   net::LoadState GetLoadState() const override;
   bool GetCharset(std::string* charset) override;
   void GetResponseInfo(net::HttpResponseInfo* info) override;
-  bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override;
+  int ReadRawData(net::IOBuffer* buf, int buf_size) override;
 
   // Sets extra request headers for Job types that support request headers.
   // This is how we get informed of range-requests.
diff --git a/content/browser/background_sync/background_sync_manager.cc b/content/browser/background_sync/background_sync_manager.cc
index 5624239..df3fcb6 100644
--- a/content/browser/background_sync/background_sync_manager.cc
+++ b/content/browser/background_sync/background_sync_manager.cc
@@ -91,6 +91,18 @@
   background_sync_controller->NotifyBackgroundSyncRegistered(origin);
 }
 
+void RunInBackgroundOnUIThread(
+    const scoped_refptr<ServiceWorkerContextWrapper>& sw_context_wrapper,
+    bool enabled) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  BackgroundSyncController* background_sync_controller =
+      GetBackgroundSyncControllerOnUIThread(sw_context_wrapper);
+  if (background_sync_controller) {
+    background_sync_controller->RunInBackground(enabled);
+  }
+}
+
 }  // namespace
 
 BackgroundSyncManager::BackgroundSyncRegistrations::
@@ -973,7 +985,6 @@
 }
 
 void BackgroundSyncManager::SchedulePendingRegistrations() {
-#if defined(OS_ANDROID)
   bool keep_browser_alive_for_one_shot = false;
 
   for (const auto& sw_id_and_registrations : active_registrations_) {
@@ -994,26 +1005,8 @@
 
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
-      base::Bind(&BackgroundSyncManager::SchedulePendingRegistrationsOnUIThread,
-                 base::Unretained(this), keep_browser_alive_for_one_shot));
-
-#else
-// TODO(jkarlin): Toggle Chrome's background mode.
-#endif
-}
-
-void BackgroundSyncManager::SchedulePendingRegistrationsOnUIThread(
-    bool keep_browser_alive_for_one_shot) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  BackgroundSyncController* background_sync_controller =
-      GetBackgroundSyncControllerOnUIThread(service_worker_context_);
-  if (background_sync_controller) {
-    // TODO(jkarlin): Use the context's path instead of the 'this' pointer as an
-    // identifier. See crbug.com/489705.
-    background_sync_controller->LaunchBrowserWhenNextOnline(
-        this, keep_browser_alive_for_one_shot);
-  }
+      base::Bind(RunInBackgroundOnUIThread, service_worker_context_,
+                 keep_browser_alive_for_one_shot));
 }
 
 void BackgroundSyncManager::FireReadyEvents() {
@@ -1058,7 +1051,7 @@
 
   // If there are no registrations currently ready, then just run |callback|.
   // Otherwise, fire them all, and record the result when done.
-  if (sw_id_and_keys_to_fire.size() == 0) {
+  if (sw_id_and_keys_to_fire.empty()) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
                                                   base::Bind(callback));
   } else {
diff --git a/content/browser/background_sync/background_sync_manager.h b/content/browser/background_sync/background_sync_manager.h
index ff6994e..236f832 100644
--- a/content/browser/background_sync/background_sync_manager.h
+++ b/content/browser/background_sync/background_sync_manager.h
@@ -274,10 +274,9 @@
   // seen (on Android the browser is instead woken up the next time it goes
   // online). For periodic syncs this means creating an alarm.
   void SchedulePendingRegistrations();
-  void SchedulePendingRegistrationsOnUIThread(
-      bool keep_browser_alive_for_one_shot);
 
-  // FireReadyEvents and callbacks
+  // FireReadyEvents scans the list of available events and fires those that are
+  // ready to fire. For those that can't yet be fired, wakeup alarms are set.
   void FireReadyEvents();
   void FireReadyEventsImpl(const base::Closure& callback);
   void FireReadyEventsDidFindRegistration(
diff --git a/content/browser/background_sync/background_sync_manager_unittest.cc b/content/browser/background_sync/background_sync_manager_unittest.cc
index de8a37c..0cc7152 100644
--- a/content/browser/background_sync/background_sync_manager_unittest.cc
+++ b/content/browser/background_sync/background_sync_manager_unittest.cc
@@ -22,6 +22,9 @@
 #include "content/browser/service_worker/service_worker_context_core.h"
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/browser/service_worker/service_worker_storage.h"
+#include "content/browser/storage_partition_impl.h"
+#include "content/public/browser/background_sync_controller.h"
+#include "content/public/test/test_browser_context.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "net/base/network_change_notifier.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -34,7 +37,6 @@
 const char kPattern2[] = "https://example.com/b";
 const char kScript1[] = "https://example.com/a/script.js";
 const char kScript2[] = "https://example.com/b/script.js";
-const int kRenderProcessId = 99;
 const int kProviderId1 = 1;
 const int kProviderId2 = 2;
 
@@ -109,6 +111,35 @@
   bool test_on_battery_power_ = false;
 };
 
+class CountingBackgroundSyncController : public BackgroundSyncController {
+ public:
+  CountingBackgroundSyncController() = default;
+
+  // BackgroundSyncController Overrides
+  void NotifyBackgroundSyncRegistered(const GURL& origin) override {
+    registration_count_ += 1;
+    registration_origin_ = origin;
+  }
+  void RunInBackground(bool enabled) override {
+    run_in_background_count_ += 1;
+    run_in_background_enabled_ = enabled;
+  }
+
+  int registration_count() const { return registration_count_; }
+  GURL registration_origin() const { return registration_origin_; }
+  int run_in_background_count() const { return run_in_background_count_; }
+  bool run_in_background_enabled() const { return run_in_background_enabled_; }
+
+ private:
+  int registration_count_ = 0;
+  GURL registration_origin_;
+
+  int run_in_background_count_ = 0;
+  bool run_in_background_enabled_ = true;
+
+  DISALLOW_COPY_AND_ASSIGN(CountingBackgroundSyncController);
+};
+
 }  // namespace
 
 // A BackgroundSyncManager that can simulate delaying and corrupting the backend
@@ -221,6 +252,7 @@
       : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
         network_change_notifier_(net::NetworkChangeNotifier::CreateMock()),
         test_background_sync_manager_(nullptr),
+        counting_controller_(nullptr),
         callback_status_(BACKGROUND_SYNC_STATUS_OK),
         callback_sw_status_code_(SERVICE_WORKER_OK),
         sync_events_called_(0) {
@@ -239,8 +271,19 @@
     // Don't let the tests be confused by the real-world device connectivity
     BackgroundSyncNetworkObserver::SetIgnoreNetworkChangeNotifierForTests(true);
 
-    helper_.reset(
-        new EmbeddedWorkerTestHelper(base::FilePath(), kRenderProcessId));
+    // TODO(jkarlin): Create a new object with all of the necessary SW calls
+    // so that we can inject test versions instead of bringing up all of this
+    // extra SW stuff.
+    helper_.reset(new EmbeddedWorkerTestHelper(base::FilePath()));
+
+    // Create a StoragePartition with the correct BrowserContext so that the
+    // BackgroundSyncManager can find the BrowserContext through it.
+    storage_partition_impl_.reset(new StoragePartitionImpl(
+        helper_->browser_context(), base::FilePath(), nullptr, nullptr, nullptr,
+        nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+        nullptr, nullptr, nullptr, nullptr));
+    helper_->context_wrapper()->set_storage_partition(
+        storage_partition_impl_.get());
 
     power_monitor_source_ = new TestPowerSource();
     // power_monitor_ takes ownership of power_monitor_source.
@@ -251,6 +294,12 @@
 
     SetupBackgroundSyncManager();
 
+    scoped_ptr<CountingBackgroundSyncController> background_sync_controller(
+        new CountingBackgroundSyncController());
+    counting_controller_ = background_sync_controller.get();
+    helper_->browser_context()->SetBackgroundSyncController(
+        background_sync_controller.Pass());
+
     // Wait for storage to finish initializing before registering service
     // workers.
     base::RunLoop().RunUntilIdle();
@@ -281,13 +330,14 @@
 
     // Register window clients for the service workers
     ServiceWorkerProviderHost* host_1 = new ServiceWorkerProviderHost(
-        kRenderProcessId, MSG_ROUTING_NONE /* render_frame_id */, kProviderId1,
+        helper_->mock_render_process_id(),
+        MSG_ROUTING_NONE /* render_frame_id */, kProviderId1,
         SERVICE_WORKER_PROVIDER_FOR_WINDOW, helper_->context()->AsWeakPtr(),
         nullptr);
     host_1->SetDocumentUrl(GURL(kPattern1));
 
     ServiceWorkerProviderHost* host_2 = new ServiceWorkerProviderHost(
-        kRenderProcessId /* dummy render proces id */,
+        helper_->mock_render_process_id(),
         MSG_ROUTING_NONE /* render_frame_id */, kProviderId2,
         SERVICE_WORKER_PROVIDER_FOR_WINDOW, helper_->context()->AsWeakPtr(),
         nullptr);
@@ -311,7 +361,8 @@
   }
 
   void RemoveWindowClients() {
-    helper_->context()->RemoveAllProviderHostsForProcess(kRenderProcessId);
+    helper_->context()->RemoveAllProviderHostsForProcess(
+        helper_->mock_render_process_id());
   }
 
   void SetNetwork(net::NetworkChangeNotifier::ConnectionType connection_type) {
@@ -562,7 +613,9 @@
   scoped_ptr<base::PowerMonitor> power_monitor_;
   scoped_ptr<EmbeddedWorkerTestHelper> helper_;
   scoped_ptr<BackgroundSyncManager> background_sync_manager_;
+  scoped_ptr<StoragePartitionImpl> storage_partition_impl_;
   TestBackgroundSyncManager* test_background_sync_manager_;
+  CountingBackgroundSyncController* counting_controller_;
 
   int64 sw_registration_id_1_;
   int64 sw_registration_id_2_;
@@ -1688,9 +1741,9 @@
 TEST_F(BackgroundSyncManagerTest, RegisterWithClientWindowForWrongOrigin) {
   RemoveWindowClients();
   ServiceWorkerProviderHost* host = new ServiceWorkerProviderHost(
-      kRenderProcessId, MSG_ROUTING_NONE /* render_frame_id */, kProviderId1,
-      SERVICE_WORKER_PROVIDER_FOR_WINDOW, helper_->context()->AsWeakPtr(),
-      nullptr);
+      helper_->mock_render_process_id(), MSG_ROUTING_NONE /* render_frame_id */,
+      kProviderId1, SERVICE_WORKER_PROVIDER_FOR_WINDOW,
+      helper_->context()->AsWeakPtr(), nullptr);
   host->SetDocumentUrl(GURL("http://example.com:9999"));
   helper_->context()->AddProviderHost(make_scoped_ptr(host));
   EXPECT_FALSE(Register(sync_options_1_));
@@ -1741,4 +1794,40 @@
   EXPECT_EQ(BACKGROUND_SYNC_STATUS_STORAGE_ERROR, callback_status_);
 }
 
+TEST_F(BackgroundSyncManagerTest, NotifyBackgroundSyncRegistered) {
+  // Verify that the BackgroundSyncController is informed of registrations.
+  EXPECT_EQ(0, counting_controller_->registration_count());
+  EXPECT_TRUE(Register(sync_options_1_));
+  EXPECT_EQ(1, counting_controller_->registration_count());
+  EXPECT_EQ(GURL(kPattern1).GetOrigin().spec(),
+            counting_controller_->registration_origin().spec());
+}
+
+TEST_F(BackgroundSyncManagerTest, WakeBrowserCalled) {
+  InitDelayedSyncEventTest();
+
+  // The BackgroundSyncManager should declare in initialization
+  // that it doesn't need to be woken up since it has no registrations.
+  EXPECT_LT(0, counting_controller_->run_in_background_count());
+  EXPECT_FALSE(counting_controller_->run_in_background_enabled());
+
+  SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
+  EXPECT_FALSE(counting_controller_->run_in_background_enabled());
+
+  // Register a one-shot but it can't fire due to lack of network, wake up is
+  // required.
+  Register(sync_options_1_);
+  EXPECT_TRUE(counting_controller_->run_in_background_enabled());
+
+  // Start the event but it will pause mid-sync due to
+  // InitDelayedSyncEventTest() above.
+  SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);
+  EXPECT_FALSE(counting_controller_->run_in_background_enabled());
+
+  // Finish the sync.
+  sync_fired_callback_.Run(SERVICE_WORKER_OK);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(counting_controller_->run_in_background_enabled());
+}
+
 }  // namespace content
diff --git a/content/browser/background_sync/background_sync_service_impl_unittest.cc b/content/browser/background_sync/background_sync_service_impl_unittest.cc
index 8ffded0..916c4cb 100644
--- a/content/browser/background_sync/background_sync_service_impl_unittest.cc
+++ b/content/browser/background_sync/background_sync_service_impl_unittest.cc
@@ -26,7 +26,6 @@
 
 const char kServiceWorkerPattern[] = "https://example.com/a";
 const char kServiceWorkerScript[] = "https://example.com/a/script.js";
-const int kRenderProcessId = 99;
 const int kProviderId = 1;
 
 // Callbacks from SetUp methods
@@ -133,7 +132,7 @@
   // SetUp helper methods
   void CreateTestHelper() {
     embedded_worker_helper_.reset(
-        new EmbeddedWorkerTestHelper(base::FilePath(), kRenderProcessId));
+        new EmbeddedWorkerTestHelper(base::FilePath()));
   }
 
   void CreateBackgroundSyncContext() {
@@ -175,7 +174,8 @@
 
     // Register window client for the service worker
     ServiceWorkerProviderHost* provider_host = new ServiceWorkerProviderHost(
-        kRenderProcessId, MSG_ROUTING_NONE /* render_frame_id */, kProviderId,
+        embedded_worker_helper_->mock_render_process_id(),
+        MSG_ROUTING_NONE /* render_frame_id */, kProviderId,
         SERVICE_WORKER_PROVIDER_FOR_WINDOW,
         embedded_worker_helper_->context()->AsWeakPtr(), nullptr);
     provider_host->SetDocumentUrl(GURL(kServiceWorkerPattern));
@@ -185,7 +185,7 @@
 
   void RemoveWindowClient() {
     embedded_worker_helper_->context()->RemoveAllProviderHostsForProcess(
-        kRenderProcessId);
+        embedded_worker_helper_->mock_render_process_id());
   }
 
   void CreateBackgroundSyncServiceImpl() {
diff --git a/content/browser/fileapi/file_writer_delegate_unittest.cc b/content/browser/fileapi/file_writer_delegate_unittest.cc
index c9bcfbb7..9eb73b1 100644
--- a/content/browser/fileapi/file_writer_delegate_unittest.cc
+++ b/content/browser/fileapi/file_writer_delegate_unittest.cc
@@ -184,17 +184,15 @@
         base::Bind(&FileWriterDelegateTestJob::NotifyHeadersComplete, this));
   }
 
-  bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override {
+  int ReadRawData(net::IOBuffer* buf, int buf_size) override {
     if (remaining_bytes_ < buf_size)
-      buf_size = static_cast<int>(remaining_bytes_);
+      buf_size = remaining_bytes_;
 
     for (int i = 0; i < buf_size; ++i)
       buf->data()[i] = content_[cursor_++];
     remaining_bytes_ -= buf_size;
 
-    SetStatus(net::URLRequestStatus());
-    *bytes_read = buf_size;
-    return true;
+    return buf_size;
   }
 
   int GetResponseCode() const override { return 200; }
diff --git a/content/browser/geolocation/osx_wifi.h b/content/browser/geolocation/osx_wifi.h
deleted file mode 100644
index cef998b..0000000
--- a/content/browser/geolocation/osx_wifi.h
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// The remainder of this file is copied from the Gears project:
-// http://code.google.com/p/gears/source/browse/trunk/gears/geolocation/osx_wifi.h
-
-// The contents of this file are taken from Apple80211.h from the iStumbler
-// project (http://www.istumbler.net). This project is released under the BSD
-// license with the following restrictions.
-//
-// Copyright (c) 02006, Alf Watt (alf@istumbler.net). All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions
-// are met:
-//
-// * Redistributions of source code must retain the above copyright
-//   notice, this list of conditions and the following disclaimer.
-//
-// * Redistributions in binary form must reproduce the above copyright
-//   notice, this list of conditions and the following disclaimer in the
-//   documentation and/or other materials provided with the distribution.
-//
-// * Neither the name of iStumbler nor the names of its contributors may be
-//   used to endorse or promote products derived from this software without
-//   specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
-// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
-// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// This is the reverse engineered header for the Apple80211 private framework.
-// The framework can be found at
-// /System/Library/PrivateFrameworks/Apple80211.framework.
-
-#ifndef CONTENT_BROWSER_GEOLOCATION_OSX_WIFI_H_
-#define CONTENT_BROWSER_GEOLOCATION_OSX_WIFI_H_
-
-#include <CoreFoundation/CoreFoundation.h>
-
-extern "C" {
-
-typedef SInt32 WIErr;
-
-// A WirelessContext should be created using WirelessAttach
-// before any other Wireless functions are called. WirelessDetach
-// is used to dispose of a WirelessContext.
-struct WirelessContext;
-
-// WirelessAttach
-//
-// This should be called before all other wireless functions.
-typedef WIErr (*WirelessAttachFunction)(WirelessContext** outContext,
-                                        const UInt32);
-
-// WirelessDetach
-//
-// This should be called after all other wireless functions.
-typedef WIErr (*WirelessDetachFunction)(WirelessContext* inContext);
-
-typedef UInt16 WINetworkInfoFlags;
-
-struct WirelessNetworkInfo
-{
-  UInt16 channel;            // Channel for the network.
-  SInt16 noise;              // Noise for the network. 0 for Adhoc.
-  SInt16 signal;             // Signal strength of the network. 0 for Adhoc.
-  UInt8 macAddress[6];       // MAC address of the wireless access point.
-  UInt16 beaconInterval;     // Beacon interval in milliseconds
-  WINetworkInfoFlags flags;  // Flags for the network
-  UInt16 nameLen;
-  SInt8 name[32];
-};
-
-// WirelessScanSplit
-//
-// WirelessScanSplit scans for available wireless networks. It will allocate 2
-// CFArrays to store a list of managed and adhoc networks. The arrays hold
-// CFData objects which contain WirelessNetworkInfo structures.
-//
-// Note: An adhoc network created on the computer the scan is running on will
-// not be found. WirelessGetInfo can be used to find info about a local adhoc
-// network.
-//
-// If stripDups != 0 only one bases tation for each SSID will be returned.
-typedef WIErr (*WirelessScanSplitFunction)(WirelessContext* inContext,
-                                           CFArrayRef* apList,
-                                           CFArrayRef* adhocList,
-                                           const UInt32 stripDups);
-
-}  // extern "C"
-
-#endif  // CONTENT_BROWSER_GEOLOCATION_OSX_WIFI_H_
diff --git a/content/browser/geolocation/wifi_data_provider_mac.cc b/content/browser/geolocation/wifi_data_provider_mac.cc
index da541872..ac5a484 100644
--- a/content/browser/geolocation/wifi_data_provider_mac.cc
+++ b/content/browser/geolocation/wifi_data_provider_mac.cc
@@ -2,18 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// For OSX 10.5 we use the system API function WirelessScanSplit. This function
-// is not documented or included in the SDK, so we use a reverse-engineered
-// header, osx_wifi_.h. This file is taken from the iStumbler project
-// (http://www.istumbler.net).
-
 #include "content/browser/geolocation/wifi_data_provider_mac.h"
 
-#include <dlfcn.h>
-#include <stdio.h>
-
-#include "base/strings/utf_string_conversions.h"
-#include "content/browser/geolocation/osx_wifi.h"
 #include "content/browser/geolocation/wifi_data_provider_common.h"
 #include "content/browser/geolocation/wifi_data_provider_manager.h"
 
@@ -24,139 +14,6 @@
 const int kNoChangePollingInterval = 300000;  // 5 mins
 const int kTwoNoChangePollingInterval = 600000;  // 10 mins
 const int kNoWifiPollingIntervalMilliseconds = 20 * 1000; // 20s
-
-// Provides the wifi API binding for use when running on OSX 10.5 machines using
-// the Apple80211 framework.
-class Apple80211Api : public WifiDataProviderCommon::WlanApiInterface {
- public:
-  Apple80211Api();
-  ~Apple80211Api() override;
-
-  // Must be called before any other interface method. Will return false if the
-  // Apple80211 framework cannot be initialized (e.g. running on post-10.5 OSX),
-  // in which case no other method may be called.
-  bool Init();
-
-  // WlanApiInterface
-  bool GetAccessPointData(WifiData::AccessPointDataSet* data) override;
-
- private:
-  // Handle, context and function pointers for Apple80211 library.
-  void* apple_80211_library_;
-  WirelessContext* wifi_context_;
-  WirelessAttachFunction WirelessAttach_function_;
-  WirelessScanSplitFunction WirelessScanSplit_function_;
-  WirelessDetachFunction WirelessDetach_function_;
-
-  WifiData wifi_data_;
-
-  DISALLOW_COPY_AND_ASSIGN(Apple80211Api);
-};
-
-Apple80211Api::Apple80211Api()
-    : apple_80211_library_(NULL), wifi_context_(NULL),
-      WirelessAttach_function_(NULL), WirelessScanSplit_function_(NULL),
-      WirelessDetach_function_(NULL) {
-}
-
-Apple80211Api::~Apple80211Api() {
-  if (WirelessDetach_function_)
-    (*WirelessDetach_function_)(wifi_context_);
-  dlclose(apple_80211_library_);
-}
-
-bool Apple80211Api::Init() {
-  DVLOG(1) << "Apple80211Api::Init";
-  apple_80211_library_ = dlopen(
-      "/System/Library/PrivateFrameworks/Apple80211.framework/Apple80211",
-      RTLD_LAZY);
-  if (!apple_80211_library_) {
-    DLOG(WARNING) << "Could not open Apple80211 library";
-    return false;
-  }
-  WirelessAttach_function_ = reinterpret_cast<WirelessAttachFunction>(
-      dlsym(apple_80211_library_, "WirelessAttach"));
-  WirelessScanSplit_function_ = reinterpret_cast<WirelessScanSplitFunction>(
-      dlsym(apple_80211_library_, "WirelessScanSplit"));
-  WirelessDetach_function_ = reinterpret_cast<WirelessDetachFunction>(
-      dlsym(apple_80211_library_, "WirelessDetach"));
-  DCHECK(WirelessAttach_function_);
-  DCHECK(WirelessScanSplit_function_);
-  DCHECK(WirelessDetach_function_);
-
-  if (!WirelessAttach_function_ || !WirelessScanSplit_function_ ||
-      !WirelessDetach_function_) {
-    DLOG(WARNING) << "Symbol error. Attach: " << !!WirelessAttach_function_
-        << " Split: " << !!WirelessScanSplit_function_
-        << " Detach: " << !!WirelessDetach_function_;
-    return false;
-  }
-
-  WIErr err = (*WirelessAttach_function_)(&wifi_context_, 0);
-  if (err != noErr) {
-    DLOG(WARNING) << "Error attaching: " << err;
-    return false;
-  }
-  return true;
-}
-
-bool Apple80211Api::GetAccessPointData(WifiData::AccessPointDataSet* data) {
-  DVLOG(1) << "Apple80211Api::GetAccessPointData";
-  DCHECK(data);
-  DCHECK(WirelessScanSplit_function_);
-  CFArrayRef managed_access_points = NULL;
-  CFArrayRef adhoc_access_points = NULL;
-  // Arrays returned here are owned by the caller.
-  WIErr err = (*WirelessScanSplit_function_)(wifi_context_,
-                                             &managed_access_points,
-                                             &adhoc_access_points,
-                                             0);
-  if (err != noErr) {
-    DLOG(WARNING) << "Error spliting scan: " << err;
-    return false;
-  }
-
-  if (managed_access_points == NULL) {
-    DLOG(WARNING) << "managed_access_points == NULL";
-    return false;
-  }
-
-  int num_access_points = CFArrayGetCount(managed_access_points);
-  DVLOG(1) << "Found " << num_access_points << " managed access points";
-  for (int i = 0; i < num_access_points; ++i) {
-    const WirelessNetworkInfo* access_point_info =
-        reinterpret_cast<const WirelessNetworkInfo*>(
-        CFDataGetBytePtr(
-        reinterpret_cast<const CFDataRef>(
-        CFArrayGetValueAtIndex(managed_access_points, i))));
-
-    // Currently we get only MAC address, signal strength, channel
-    // signal-to-noise and SSID
-    AccessPointData access_point_data;
-    access_point_data.mac_address =
-        MacAddressAsString16(access_point_info->macAddress);
-    // WirelessNetworkInfo::signal appears to be signal strength in dBm.
-    access_point_data.radio_signal_strength = access_point_info->signal;
-    access_point_data.channel = access_point_info->channel;
-    // WirelessNetworkInfo::noise appears to be noise floor in dBm.
-    access_point_data.signal_to_noise = access_point_info->signal -
-                                        access_point_info->noise;
-    if (!base::UTF8ToUTF16(reinterpret_cast<const char*>(
-                               access_point_info->name),
-                           access_point_info->nameLen,
-                           &access_point_data.ssid)) {
-      access_point_data.ssid.clear();
-    }
-    data->insert(access_point_data);
-  }
-
-  if (managed_access_points)
-    CFRelease(managed_access_points);
-  if (adhoc_access_points)
-    CFRelease(adhoc_access_points);
-
-  return true;
-}
 }  // namespace
 
 // static
@@ -171,17 +28,10 @@
 }
 
 WifiDataProviderMac::WlanApiInterface* WifiDataProviderMac::NewWlanApi() {
-  // Try and find a API binding that works: first try the officially supported
-  // CoreWLAN API, and if this fails (e.g. on OSX 10.5) fall back to the reverse
-  // engineered Apple80211 API.
   WifiDataProviderMac::WlanApiInterface* core_wlan_api = NewCoreWlanApi();
   if (core_wlan_api)
     return core_wlan_api;
 
-  scoped_ptr<Apple80211Api> wlan_api(new Apple80211Api);
-  if (wlan_api->Init())
-    return wlan_api.release();
-
   DVLOG(1) << "WifiDataProviderMac : failed to initialize any wlan api";
   return NULL;
 }
diff --git a/content/browser/gpu/browser_gpu_memory_buffer_manager.cc b/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
index fa61b00a..b7f36b6 100644
--- a/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
+++ b/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
@@ -67,9 +67,9 @@
 void GpuMemoryBufferDeleted(
     scoped_refptr<base::SingleThreadTaskRunner> destruction_task_runner,
     const GpuMemoryBufferImpl::DestructionCallback& destruction_callback,
-    uint32 sync_point) {
+    const gpu::SyncToken& sync_token) {
   destruction_task_runner->PostTask(
-      FROM_HERE, base::Bind(destruction_callback, sync_point));
+      FROM_HERE, base::Bind(destruction_callback, sync_token));
 }
 
 bool IsNativeGpuMemoryBufferFactoryConfigurationSupported(
@@ -342,11 +342,11 @@
   return GpuMemoryBufferImpl::FromClientBuffer(buffer);
 }
 
-void BrowserGpuMemoryBufferManager::SetDestructionSyncPoint(
+void BrowserGpuMemoryBufferManager::SetDestructionSyncToken(
     gfx::GpuMemoryBuffer* buffer,
-    uint32 sync_point) {
+    const gpu::SyncToken& sync_token) {
   static_cast<GpuMemoryBufferImpl*>(buffer)
-      ->set_destruction_sync_point(sync_point);
+      ->set_destruction_sync_token(sync_token);
 }
 
 bool BrowserGpuMemoryBufferManager::OnMemoryDump(
@@ -395,10 +395,10 @@
     gfx::GpuMemoryBufferId id,
     base::ProcessHandle child_process_handle,
     int child_client_id,
-    uint32 sync_point) {
+    const gpu::SyncToken& sync_token) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
-  DestroyGpuMemoryBufferOnIO(id, child_client_id, sync_point);
+  DestroyGpuMemoryBufferOnIO(id, child_client_id, sync_token);
 }
 
 void BrowserGpuMemoryBufferManager::ProcessRemoved(
@@ -419,7 +419,7 @@
 
     GpuProcessHost* host = GpuProcessHost::FromID(buffer.second.gpu_host_id);
     if (host)
-      host->DestroyGpuMemoryBuffer(buffer.first, client_id, 0);
+      host->DestroyGpuMemoryBuffer(buffer.first, client_id, gpu::SyncToken());
   }
 
   clients_.erase(client_it);
@@ -654,7 +654,7 @@
     if (!handle.is_null()) {
       GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id);
       if (host)
-        host->DestroyGpuMemoryBuffer(handle.id, client_id, 0);
+        host->DestroyGpuMemoryBuffer(handle.id, client_id, gpu::SyncToken());
     }
     callback.Run(gfx::GpuMemoryBufferHandle());
     return;
@@ -706,7 +706,7 @@
 void BrowserGpuMemoryBufferManager::DestroyGpuMemoryBufferOnIO(
     gfx::GpuMemoryBufferId id,
     int client_id,
-    uint32 sync_point) {
+    const gpu::SyncToken& sync_token) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(clients_.find(client_id) != clients_.end());
 
@@ -727,7 +727,7 @@
 
   GpuProcessHost* host = GpuProcessHost::FromID(buffer_it->second.gpu_host_id);
   if (host)
-    host->DestroyGpuMemoryBuffer(id, client_id, sync_point);
+    host->DestroyGpuMemoryBuffer(id, client_id, sync_token);
 
   buffers.erase(buffer_it);
 }
diff --git a/content/browser/gpu/browser_gpu_memory_buffer_manager.h b/content/browser/gpu/browser_gpu_memory_buffer_manager.h
index 9cb9c43b..09c8f73 100644
--- a/content/browser/gpu/browser_gpu_memory_buffer_manager.h
+++ b/content/browser/gpu/browser_gpu_memory_buffer_manager.h
@@ -65,8 +65,8 @@
       gfx::BufferFormat format) override;
   gfx::GpuMemoryBuffer* GpuMemoryBufferFromClientBuffer(
       ClientBuffer buffer) override;
-  void SetDestructionSyncPoint(gfx::GpuMemoryBuffer* buffer,
-                               uint32 sync_point) override;
+  void SetDestructionSyncToken(gfx::GpuMemoryBuffer* buffer,
+                               const gpu::SyncToken& sync_token) override;
 
   // Overridden from base::trace_event::MemoryDumpProvider:
   bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
@@ -90,7 +90,7 @@
       gfx::GpuMemoryBufferId id,
       base::ProcessHandle child_process_handle,
       int child_client_id,
-      uint32 sync_point);
+      const gpu::SyncToken& sync_token);
   void ProcessRemoved(base::ProcessHandle process_handle, int client_id);
 
   bool IsNativeGpuMemoryBufferConfiguration(gfx::BufferFormat format,
@@ -164,7 +164,7 @@
                                   const gfx::GpuMemoryBufferHandle& handle);
   void DestroyGpuMemoryBufferOnIO(gfx::GpuMemoryBufferId id,
                                   int client_id,
-                                  uint32 sync_point);
+                                  const gpu::SyncToken& sync_token);
 
   uint64_t ClientIdToTracingProcessId(int client_id) const;
 
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 9edf3ab..a3b56cc 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -766,12 +766,12 @@
 
 void GpuProcessHost::DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
                                             int client_id,
-                                            int sync_point) {
+                                            const gpu::SyncToken& sync_token) {
   TRACE_EVENT0("gpu", "GpuProcessHost::DestroyGpuMemoryBuffer");
 
   DCHECK(CalledOnValidThread());
 
-  Send(new GpuMsg_DestroyGpuMemoryBuffer(id, client_id, sync_point));
+  Send(new GpuMsg_DestroyGpuMemoryBuffer(id, client_id, sync_token));
 }
 
 void GpuProcessHost::OnInitialized(bool result, const gpu::GPUInfo& gpu_info) {
diff --git a/content/browser/gpu/gpu_process_host.h b/content/browser/gpu/gpu_process_host.h
index 83e3410..245e330 100644
--- a/content/browser/gpu/gpu_process_host.h
+++ b/content/browser/gpu/gpu_process_host.h
@@ -40,6 +40,10 @@
 struct ChannelHandle;
 }
 
+namespace gpu {
+struct SyncToken;
+}
+
 namespace content {
 class BrowserChildProcessHostImpl;
 class GpuMainThread;
@@ -148,7 +152,7 @@
   // Tells the GPU process to destroy GPU memory buffer.
   void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
                               int client_id,
-                              int sync_point);
+                              const gpu::SyncToken& sync_token);
 
   // What kind of GPU process, e.g. sandboxed or unsandboxed.
   GpuProcessKind kind();
diff --git a/content/browser/net/view_http_cache_job_factory.cc b/content/browser/net/view_http_cache_job_factory.cc
index 6b46b618..3f9570eed 100644
--- a/content/browser/net/view_http_cache_job_factory.cc
+++ b/content/browser/net/view_http_cache_job_factory.cc
@@ -10,6 +10,7 @@
 #include "base/compiler_specific.h"
 #include "base/location.h"
 #include "base/memory/weak_ptr.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/thread_task_runner_handle.h"
@@ -44,8 +45,8 @@
   bool GetCharset(std::string* charset) override {
     return core_->GetCharset(charset);
   }
-  bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override {
-    return core_->ReadRawData(buf, buf_size, bytes_read);
+  int ReadRawData(net::IOBuffer* buf, int buf_size) override {
+    return core_->ReadRawData(buf, buf_size);
   }
 
  private:
@@ -65,7 +66,7 @@
 
     bool GetMimeType(std::string* mime_type) const;
     bool GetCharset(std::string* charset);
-    bool ReadRawData(net::IOBuffer* buf, int buf_size, int *bytes_read);
+    int ReadRawData(net::IOBuffer* buf, int buf_size);
 
    private:
     friend class base::RefCounted<Core>;
@@ -164,17 +165,13 @@
   return true;
 }
 
-bool ViewHttpCacheJob::Core::ReadRawData(net::IOBuffer* buf,
-                                         int buf_size,
-                                         int* bytes_read) {
-  DCHECK(bytes_read);
-  int remaining = static_cast<int>(data_.size()) - data_offset_;
+int ViewHttpCacheJob::Core::ReadRawData(net::IOBuffer* buf, int buf_size) {
+  int remaining = base::checked_cast<int>(data_.size()) - data_offset_;
   if (buf_size > remaining)
     buf_size = remaining;
   memcpy(buf->data(), data_.data() + data_offset_, buf_size);
   data_offset_ += buf_size;
-  *bytes_read = buf_size;
-  return true;
+  return buf_size;
 }
 
 void ViewHttpCacheJob::Core::OnIOComplete(int result) {
diff --git a/content/browser/renderer_host/media/video_capture_controller.cc b/content/browser/renderer_host/media/video_capture_controller.cc
index 50f3a5f7..01a7772 100644
--- a/content/browser/renderer_host/media/video_capture_controller.cc
+++ b/content/browser/renderer_host/media/video_capture_controller.cc
@@ -45,7 +45,9 @@
  public:
   explicit SyncTokenClientImpl(GLHelper* gl_helper) : gl_helper_(gl_helper) {}
   ~SyncTokenClientImpl() override {}
-  uint32 InsertSyncPoint() override { return gl_helper_->InsertSyncPoint(); }
+  void GenerateSyncToken(gpu::SyncToken* sync_token) override {
+    gl_helper_->GenerateSyncToken(sync_token);
+  }
   void WaitSyncToken(const gpu::SyncToken& sync_token) override {
     gl_helper_->WaitSyncToken(sync_token);
   }
diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc
index 8861e37..9feac401 100644
--- a/content/browser/renderer_host/render_message_filter.cc
+++ b/content/browser/renderer_host/render_message_filter.cc
@@ -687,11 +687,11 @@
 
 void RenderMessageFilter::OnDeletedGpuMemoryBuffer(
     gfx::GpuMemoryBufferId id,
-    uint32 sync_point) {
+    const gpu::SyncToken& sync_token) {
   DCHECK(BrowserGpuMemoryBufferManager::current());
 
   BrowserGpuMemoryBufferManager::current()->ChildProcessDeletedGpuMemoryBuffer(
-      id, PeerHandle(), render_process_id_, sync_point);
+      id, PeerHandle(), render_process_id_, sync_token);
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/render_message_filter.h b/content/browser/renderer_host/render_message_filter.h
index 2fdf7f6..da1f387 100644
--- a/content/browser/renderer_host/render_message_filter.h
+++ b/content/browser/renderer_host/render_message_filter.h
@@ -59,6 +59,10 @@
 struct GpuMemoryBufferHandle;
 }
 
+namespace gpu {
+struct SyncToken;
+}
+
 namespace media {
 class AudioManager;
 struct MediaLogEvent;
@@ -210,7 +214,7 @@
   void GpuMemoryBufferAllocated(IPC::Message* reply,
                                 const gfx::GpuMemoryBufferHandle& handle);
   void OnDeletedGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
-                                uint32 sync_point);
+                                const gpu::SyncToken& sync_token);
 
   // Cached resource request dispatcher host, guaranteed to be non-null. We do
   // not own it; it is managed by the BrowserProcess, which has a wider scope
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index ef80f9e..29a96ae 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -626,7 +626,6 @@
                           const gfx::Range& range);
   void OnSelectionBoundsChanged(
       const ViewHostMsg_SelectionBounds_Params& params);
-  void OnSnapshot(bool success, const SkBitmap& bitmap);
 
   // Called (either immediately or asynchronously) after we're done with our
   // BackingStore and can send an ACK to the renderer so it can paint onto it
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index 77ea388..882e985 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -80,6 +80,7 @@
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/color_profile.h"
 #include "ui/gfx/display.h"
+#include "ui/gfx/geometry/dip_util.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/geometry/size_conversions.h"
 #include "ui/gfx/screen.h"
@@ -475,6 +476,7 @@
       is_guest_view_hack_(is_guest_view_hack),
       begin_frame_observer_proxy_(this),
       set_focus_on_mouse_down_(false),
+      device_scale_factor_(0.0f),
       weak_ptr_factory_(this) {
   if (!is_guest_view_hack_)
     host_->SetView(this);
@@ -524,6 +526,13 @@
   window_->Init(ui::LAYER_SOLID_COLOR);
   window_->SetName("RenderWidgetHostViewAura");
   window_->layer()->SetColor(background_color_);
+
+  if (parent_view)
+    parent_view->AddChild(GetNativeView());
+
+  const gfx::Display display =
+      gfx::Screen::GetScreenFor(window_)->GetDisplayNearestWindow(window_);
+  device_scale_factor_ = display.device_scale_factor();
 }
 
 void RenderWidgetHostViewAura::InitAsPopup(
@@ -572,6 +581,10 @@
     window_->SetCapture();
 
   event_filter_for_popup_exit_.reset(new EventFilterForPopupExit(this));
+
+  const gfx::Display display =
+      gfx::Screen::GetScreenFor(window_)->GetDisplayNearestWindow(window_);
+  device_scale_factor_ = display.device_scale_factor();
 }
 
 void RenderWidgetHostViewAura::InitAsFullscreen(
@@ -600,6 +613,10 @@
   aura::client::ParentWindowWithContext(window_, parent, bounds);
   Show();
   Focus();
+
+  const gfx::Display display =
+      gfx::Screen::GetScreenFor(window_)->GetDisplayNearestWindow(window_);
+  device_scale_factor_ = display.device_scale_factor();
 }
 
 RenderWidgetHost* RenderWidgetHostViewAura::GetRenderWidgetHost() const {
@@ -1883,6 +1900,7 @@
 
   UpdateScreenInfo(window_);
 
+  device_scale_factor_ = device_scale_factor;
   const gfx::Display display = gfx::Screen::GetScreenFor(window_)->
       GetDisplayNearestWindow(window_);
   DCHECK_EQ(device_scale_factor, display.device_scale_factor());
@@ -2174,8 +2192,17 @@
 uint32_t RenderWidgetHostViewAura::SurfaceIdNamespaceAtPoint(
     const gfx::Point& point,
     gfx::Point* transformed_point) {
-  cc::SurfaceId id =
-      delegated_frame_host_->SurfaceIdAtPoint(point, transformed_point);
+  DCHECK(device_scale_factor_ != 0.0f);
+
+  // The surface hittest happens in device pixels, so we need to convert the
+  // |point| from DIPs to pixels before hittesting.
+  gfx::Point point_in_pixels =
+      gfx::ConvertPointToPixel(device_scale_factor_, point);
+  cc::SurfaceId id = delegated_frame_host_->SurfaceIdAtPoint(point_in_pixels,
+                                                             transformed_point);
+  *transformed_point =
+      gfx::ConvertPointToDIP(device_scale_factor_, *transformed_point);
+
   // It is possible that the renderer has not yet produced a surface, in which
   // case we return our current namespace.
   if (id.is_null())
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h
index 5bc45b66..d5c7e9e4 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -667,6 +667,8 @@
   // the current view has focus. Defaults to false.
   bool set_focus_on_mouse_down_;
 
+  float device_scale_factor_;
+
   base::WeakPtrFactory<RenderWidgetHostViewAura> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAura);
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm
index b349033..a938f7d 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -1593,8 +1593,16 @@
 uint32_t RenderWidgetHostViewMac::SurfaceIdNamespaceAtPoint(
     const gfx::Point& point,
     gfx::Point* transformed_point) {
-  cc::SurfaceId id =
-      delegated_frame_host_->SurfaceIdAtPoint(point, transformed_point);
+  // The surface hittest happens in device pixels, so we need to convert the
+  // |point| from DIPs to pixels before hittesting.
+  float scale_factor = gfx::Screen::GetScreenFor(cocoa_view_)
+                           ->GetDisplayNearestWindow(cocoa_view_)
+                           .device_scale_factor();
+  gfx::Point point_in_pixels = gfx::ConvertPointToPixel(scale_factor, point);
+  cc::SurfaceId id = delegated_frame_host_->SurfaceIdAtPoint(point_in_pixels,
+                                                             transformed_point);
+  *transformed_point = gfx::ConvertPointToDIP(scale_factor, *transformed_point);
+
   // It is possible that the renderer has not yet produced a surface, in which
   // case we return our current namespace.
   if (id.is_null())
diff --git a/content/browser/service_worker/embedded_worker_test_helper.cc b/content/browser/service_worker/embedded_worker_test_helper.cc
index 0a2ed59..5cbc11aa 100644
--- a/content/browser/service_worker/embedded_worker_test_helper.cc
+++ b/content/browser/service_worker/embedded_worker_test_helper.cc
@@ -70,7 +70,7 @@
     const base::FilePath& user_data_directory)
     : browser_context_(new TestBrowserContext),
       render_process_host_(new MockRenderProcessHost(browser_context_.get())),
-      wrapper_(new ServiceWorkerContextWrapper(nullptr)),
+      wrapper_(new ServiceWorkerContextWrapper(browser_context_.get())),
       next_thread_id_(0),
       mock_render_process_id_(render_process_host_->GetID()),
       weak_factory_(this) {
diff --git a/content/browser/service_worker/embedded_worker_test_helper.h b/content/browser/service_worker/embedded_worker_test_helper.h
index edd27a9..d713905 100644
--- a/content/browser/service_worker/embedded_worker_test_helper.h
+++ b/content/browser/service_worker/embedded_worker_test_helper.h
@@ -84,6 +84,8 @@
     return render_process_host_.get();
   }
 
+  TestBrowserContext* browser_context() { return browser_context_.get(); }
+
  protected:
   // Called when StartWorker, StopWorker and SendMessageToWorker message
   // is sent to the embedded worker. Override if necessary. By default
diff --git a/content/browser/service_worker/service_worker_read_from_cache_job.cc b/content/browser/service_worker/service_worker_read_from_cache_job.cc
index 062d475..6aa92af8 100644
--- a/content/browser/service_worker/service_worker_read_from_cache_job.cc
+++ b/content/browser/service_worker/service_worker_read_from_cache_job.cc
@@ -41,27 +41,9 @@
 }
 
 void ServiceWorkerReadFromCacheJob::Start() {
-  TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
-                           "ServiceWorkerReadFromCacheJob::ReadInfo",
-                           this,
-                           "URL", request_->url().spec());
-  if (!context_) {
-    NotifyStartError(net::URLRequestStatus(
-        net::URLRequestStatus::FAILED, net::ERR_FAILED));
-    return;
-  }
-
-  // Create a response reader and start reading the headers,
-  // we'll continue when thats done.
-  if (is_main_script())
-    version_->embedded_worker()->OnScriptReadStarted();
-  reader_ = context_->storage()->CreateResponseReader(resource_id_);
-  http_info_io_buffer_ = new HttpResponseInfoIOBuffer;
-  reader_->ReadInfo(
-      http_info_io_buffer_.get(),
-      base::Bind(&ServiceWorkerReadFromCacheJob::OnReadInfoComplete,
-                 weak_factory_.GetWeakPtr()));
-  SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&ServiceWorkerReadFromCacheJob::StartAsync,
+                            weak_factory_.GetWeakPtr()));
 }
 
 void ServiceWorkerReadFromCacheJob::Kill() {
@@ -123,22 +105,42 @@
     range_requested_ = ranges[0];
 }
 
-bool ServiceWorkerReadFromCacheJob::ReadRawData(
-    net::IOBuffer* buf,
-    int buf_size,
-    int *bytes_read) {
+int ServiceWorkerReadFromCacheJob::ReadRawData(net::IOBuffer* buf,
+                                               int buf_size) {
   DCHECK_NE(buf_size, 0);
-  DCHECK(bytes_read);
   DCHECK(!reader_->IsReadPending());
   TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
                            "ServiceWorkerReadFromCacheJob::ReadRawData",
                            this,
                            "URL", request_->url().spec());
-  reader_->ReadData(
-      buf, buf_size, base::Bind(&ServiceWorkerReadFromCacheJob::OnReadComplete,
-                                weak_factory_.GetWeakPtr()));
+  reader_->ReadData(buf, buf_size,
+                    base::Bind(&ServiceWorkerReadFromCacheJob::OnReadComplete,
+                               weak_factory_.GetWeakPtr()));
+  return net::ERR_IO_PENDING;
+}
+
+void ServiceWorkerReadFromCacheJob::StartAsync() {
+  TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
+                           "ServiceWorkerReadFromCacheJob::ReadInfo", this,
+                           "URL", request_->url().spec());
+  if (!context_) {
+    // NotifyStartError is not safe to call synchronously in Start.
+    NotifyStartError(
+        net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED));
+    return;
+  }
+
+  // Create a response reader and start reading the headers,
+  // we'll continue when thats done.
+  if (is_main_script())
+    version_->embedded_worker()->OnScriptReadStarted();
+  reader_ = context_->storage()->CreateResponseReader(resource_id_);
+  http_info_io_buffer_ = new HttpResponseInfoIOBuffer;
+  reader_->ReadInfo(
+      http_info_io_buffer_.get(),
+      base::Bind(&ServiceWorkerReadFromCacheJob::OnReadInfoComplete,
+                 weak_factory_.GetWeakPtr()));
   SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
-  return false;
 }
 
 const net::HttpResponseInfo* ServiceWorkerReadFromCacheJob::http_info() const {
@@ -156,6 +158,8 @@
     ServiceWorkerMetrics::CountReadResponseResult(
         ServiceWorkerMetrics::READ_HEADERS_ERROR);
     Done(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
+    NotifyStartError(
+        net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
     return;
   }
   DCHECK_GE(result, 0);
@@ -209,23 +213,22 @@
   }
   if (is_main_script())
     version_->embedded_worker()->OnScriptReadFinished();
-  NotifyDone(status);
 }
 
 void ServiceWorkerReadFromCacheJob::OnReadComplete(int result) {
   ServiceWorkerMetrics::ReadResponseResult check_result;
-  if (result == 0) {
+
+  if (result >= 0) {
     check_result = ServiceWorkerMetrics::READ_OK;
-    Done(net::URLRequestStatus());
-  } else if (result < 0) {
+    if (result == 0)
+      Done(net::URLRequestStatus());
+  } else {
     check_result = ServiceWorkerMetrics::READ_DATA_ERROR;
     Done(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
-  } else {
-    check_result = ServiceWorkerMetrics::READ_OK;
-    SetStatus(net::URLRequestStatus());  // Clear the IO_PENDING status
   }
+
   ServiceWorkerMetrics::CountReadResponseResult(check_result);
-  NotifyReadComplete(result);
+  ReadRawDataComplete(result);
   TRACE_EVENT_ASYNC_END1("ServiceWorker",
                          "ServiceWorkerReadFromCacheJob::ReadRawData",
                          this,
diff --git a/content/browser/service_worker/service_worker_read_from_cache_job.h b/content/browser/service_worker/service_worker_read_from_cache_job.h
index fccde7a..a62893d 100644
--- a/content/browser/service_worker/service_worker_read_from_cache_job.h
+++ b/content/browser/service_worker/service_worker_read_from_cache_job.h
@@ -51,13 +51,14 @@
   void GetResponseInfo(net::HttpResponseInfo* info) override;
   int GetResponseCode() const override;
   void SetExtraRequestHeaders(const net::HttpRequestHeaders& headers) override;
-  bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override;
+  int ReadRawData(net::IOBuffer* buf, int buf_size) override;
 
   // Reader completion callbacks.
   void OnReadInfoComplete(int result);
   void OnReadComplete(int result);
 
   // Helpers
+  void StartAsync();
   const net::HttpResponseInfo* http_info() const;
   bool is_range_request() const { return range_requested_.IsValid(); }
   void SetupRangeResponse(int response_data_size);
diff --git a/content/browser/service_worker/service_worker_url_request_job.cc b/content/browser/service_worker/service_worker_url_request_job.cc
index 2572c93..7e7c699 100644
--- a/content/browser/service_worker/service_worker_url_request_job.cc
+++ b/content/browser/service_worker/service_worker_url_request_job.cc
@@ -203,49 +203,44 @@
     byte_range_ = ranges[0];
 }
 
-bool ServiceWorkerURLRequestJob::ReadRawData(
-    net::IOBuffer* buf, int buf_size, int *bytes_read) {
+int ServiceWorkerURLRequestJob::ReadRawData(net::IOBuffer* buf, int buf_size) {
   DCHECK(buf);
   DCHECK_GE(buf_size, 0);
-  DCHECK(bytes_read);
   DCHECK(waiting_stream_url_.is_empty());
+
+  int bytes_read = 0;
+
   if (stream_.get()) {
-    switch (stream_->ReadRawData(buf, buf_size, bytes_read)) {
+    switch (stream_->ReadRawData(buf, buf_size, &bytes_read)) {
       case Stream::STREAM_HAS_DATA:
-        DCHECK_GT(*bytes_read, 0);
-        return true;
+        DCHECK_GT(bytes_read, 0);
+        return bytes_read;
       case Stream::STREAM_COMPLETE:
-        DCHECK(!*bytes_read);
+        DCHECK_EQ(0, bytes_read);
         RecordResult(ServiceWorkerMetrics::REQUEST_JOB_STREAM_RESPONSE);
-        return true;
+        return 0;
       case Stream::STREAM_EMPTY:
         stream_pending_buffer_ = buf;
         stream_pending_buffer_size_ = buf_size;
-        SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
-        return false;
+        return net::ERR_IO_PENDING;
       case Stream::STREAM_ABORTED:
         // Handle this as connection reset.
         RecordResult(ServiceWorkerMetrics::REQUEST_JOB_ERROR_STREAM_ABORTED);
-        NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
-                                         net::ERR_CONNECTION_RESET));
-        return false;
+        return net::ERR_CONNECTION_RESET;
     }
     NOTREACHED();
-    return false;
+    return net::ERR_FAILED;
   }
 
-  if (!blob_request_) {
-    *bytes_read = 0;
-    return true;
-  }
-  blob_request_->Read(buf, buf_size, bytes_read);
+  if (!blob_request_)
+    return 0;
+  blob_request_->Read(buf, buf_size, &bytes_read);
   net::URLRequestStatus status = blob_request_->status();
-  SetStatus(status);
-  if (status.is_io_pending())
-    return false;
-  if (status.is_success() && *bytes_read == 0)
+  if (status.status() != net::URLRequestStatus::SUCCESS)
+    return status.error();
+  if (bytes_read == 0)
     RecordResult(ServiceWorkerMetrics::REQUEST_JOB_BLOB_RESPONSE);
-  return status.is_success();
+  return bytes_read;
 }
 
 // TODO(falken): Refactor Blob and Stream specific handling to separate classes.
@@ -291,29 +286,18 @@
 
 void ServiceWorkerURLRequestJob::OnReadCompleted(net::URLRequest* request,
                                                  int bytes_read) {
-  SetStatus(request->status());
   if (!request->status().is_success()) {
     RecordResult(ServiceWorkerMetrics::REQUEST_JOB_ERROR_BLOB_READ);
-    NotifyDone(request->status());
-    return;
-  }
-
-  if (bytes_read == 0) {
-    // Protect because NotifyReadComplete() can destroy |this|.
-    scoped_refptr<ServiceWorkerURLRequestJob> protect(this);
+  } else if (bytes_read == 0) {
     RecordResult(ServiceWorkerMetrics::REQUEST_JOB_BLOB_RESPONSE);
-    NotifyReadComplete(bytes_read);
-    NotifyDone(request->status());
-    return;
   }
-  NotifyReadComplete(bytes_read);
+  net::URLRequestStatus status = request->status();
+  ReadRawDataComplete(status.is_success() ? bytes_read : status.error());
 }
 
 // Overrides for Stream reading -----------------------------------------------
 
 void ServiceWorkerURLRequestJob::OnDataAvailable(Stream* stream) {
-  // Clear the IO_PENDING status.
-  SetStatus(net::URLRequestStatus());
   // Do nothing if stream_pending_buffer_ is empty, i.e. there's no ReadRawData
   // operation waiting for IO completion.
   if (!stream_pending_buffer_.get())
@@ -322,15 +306,15 @@
   // stream_pending_buffer_ is set to the IOBuffer instance provided to
   // ReadRawData() by URLRequestJob.
 
-  int bytes_read = 0;
-  switch (stream_->ReadRawData(
-      stream_pending_buffer_.get(), stream_pending_buffer_size_, &bytes_read)) {
+  int result = 0;
+  switch (stream_->ReadRawData(stream_pending_buffer_.get(),
+                               stream_pending_buffer_size_, &result)) {
     case Stream::STREAM_HAS_DATA:
-      DCHECK_GT(bytes_read, 0);
+      DCHECK_GT(result, 0);
       break;
     case Stream::STREAM_COMPLETE:
       // Calling NotifyReadComplete with 0 signals completion.
-      DCHECK(!bytes_read);
+      DCHECK(!result);
       RecordResult(ServiceWorkerMetrics::REQUEST_JOB_STREAM_RESPONSE);
       break;
     case Stream::STREAM_EMPTY:
@@ -338,9 +322,8 @@
       break;
     case Stream::STREAM_ABORTED:
       // Handle this as connection reset.
+      result = net::ERR_CONNECTION_RESET;
       RecordResult(ServiceWorkerMetrics::REQUEST_JOB_ERROR_STREAM_ABORTED);
-      NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
-                                       net::ERR_CONNECTION_RESET));
       break;
   }
 
@@ -348,7 +331,7 @@
   // safe for the observer to read.
   stream_pending_buffer_ = nullptr;
   stream_pending_buffer_size_ = 0;
-  NotifyReadComplete(bytes_read);
+  ReadRawDataComplete(result);
 }
 
 void ServiceWorkerURLRequestJob::OnStreamRegistered(Stream* stream) {
@@ -644,7 +627,7 @@
   // error.
   if (response.status_code == 0) {
     RecordStatusZeroResponseError(response.error);
-    NotifyDone(
+    NotifyStartError(
         net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED));
     return;
   }
diff --git a/content/browser/service_worker/service_worker_url_request_job.h b/content/browser/service_worker/service_worker_url_request_job.h
index 4815c0b..2a50c94 100644
--- a/content/browser/service_worker/service_worker_url_request_job.h
+++ b/content/browser/service_worker/service_worker_url_request_job.h
@@ -87,7 +87,7 @@
   void GetLoadTimingInfo(net::LoadTimingInfo* load_timing_info) const override;
   int GetResponseCode() const override;
   void SetExtraRequestHeaders(const net::HttpRequestHeaders& headers) override;
-  bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override;
+  int ReadRawData(net::IOBuffer* buf, int buf_size) override;
 
   // net::URLRequest::Delegate overrides that read the blob from the
   // ServiceWorkerFetchResponse.
diff --git a/content/browser/service_worker/service_worker_write_to_cache_job.cc b/content/browser/service_worker/service_worker_write_to_cache_job.cc
index 27d545e5..0cc9f88 100644
--- a/content/browser/service_worker/service_worker_write_to_cache_job.cc
+++ b/content/browser/service_worker/service_worker_write_to_cache_job.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
 #include "content/browser/service_worker/service_worker_cache_writer.h"
 #include "content/browser/service_worker/service_worker_context_core.h"
@@ -47,7 +48,7 @@
 // developers.
 // TODO(falken): Redesign this class so we don't have to fail at the network
 // stack layer just to cancel the update.
-const int kIdenticalScriptError = net::ERR_FILE_EXISTS;
+const net::Error kIdenticalScriptError = net::ERR_FILE_EXISTS;
 
 }  // namespace
 
@@ -79,13 +80,20 @@
 }
 
 void ServiceWorkerWriteToCacheJob::Start() {
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&ServiceWorkerWriteToCacheJob::StartAsync,
+                            weak_factory_.GetWeakPtr()));
+}
+
+void ServiceWorkerWriteToCacheJob::StartAsync() {
   TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
                            "ServiceWorkerWriteToCacheJob::ExecutingJob",
                            this,
                            "URL", request_->url().spec());
   if (!context_) {
-    NotifyStartError(net::URLRequestStatus(
-        net::URLRequestStatus::FAILED, net::ERR_FAILED));
+    // NotifyStartError is not safe to call synchronously in Start().
+    NotifyStartError(
+        net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED));
     return;
   }
 
@@ -108,8 +116,9 @@
   has_been_killed_ = true;
   net_request_.reset();
   if (did_notify_started_) {
-    NotifyFinishedCaching(net::URLRequestStatus::FromError(net::ERR_ABORTED),
-                          kKilledError);
+    net::Error error = NotifyFinishedCaching(
+        net::URLRequestStatus::FromError(net::ERR_ABORTED), kKilledError);
+    DCHECK_EQ(net::ERR_ABORTED, error);
   }
   writer_.reset();
   context_.reset();
@@ -156,40 +165,20 @@
   net_request_->SetExtraRequestHeaders(headers);
 }
 
-bool ServiceWorkerWriteToCacheJob::ReadRawData(net::IOBuffer* buf,
-                                               int buf_size,
-                                               int* bytes_read) {
-  net::URLRequestStatus status = ReadNetData(buf, buf_size, bytes_read);
-  SetStatus(status);
+int ServiceWorkerWriteToCacheJob::ReadRawData(net::IOBuffer* buf,
+                                              int buf_size) {
+  int bytes_read = 0;
+  net::URLRequestStatus status = ReadNetData(buf, buf_size, &bytes_read);
   if (status.is_io_pending())
-    return false;
+    return net::ERR_IO_PENDING;
 
   if (!status.is_success()) {
-    NotifyDoneHelper(status, kFetchScriptError);
-    return false;
+    net::Error error = NotifyFinishedCaching(status, kFetchScriptError);
+    DCHECK_EQ(status.error(), error);
+    return error;
   }
 
-  HandleNetData(*bytes_read);
-  status = GetStatus();
-
-  // Synchronous EOFs that do not replace the incumbent entry are considered
-  // failures. Since normally the URLRequestJob's status would be set by
-  // ReadNetData or HandleNetData, this code has to manually fix up the status
-  // to match the failure this function is about to return.
-  if (status.status() == net::URLRequestStatus::SUCCESS &&
-      *bytes_read == 0 && !cache_writer_->did_replace()) {
-    status = net::URLRequestStatus::FromError(kIdenticalScriptError);
-  }
-
-  if (!status.is_success()) {
-    NotifyDoneHelper(status, "");
-    return false;
-  }
-
-  // Since URLRequestStatus::is_success() means "SUCCESS or IO_PENDING", but the
-  // contract of this function is "return true for synchronous successes only",
-  // it is important to test against SUCCESS explicitly here.
-  return status.status() == net::URLRequestStatus::SUCCESS;
+  return HandleNetData(bytes_read);
 }
 
 const net::HttpResponseInfo* ServiceWorkerWriteToCacheJob::http_info() const {
@@ -244,9 +233,9 @@
   TRACE_EVENT0("ServiceWorker",
                "ServiceWorkerWriteToCacheJob::OnReceivedRedirect");
   // Script resources can't redirect.
-  NotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
-                                         net::ERR_UNSAFE_REDIRECT),
-                   kRedirectError);
+  NotifyStartErrorHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
+                                               net::ERR_UNSAFE_REDIRECT),
+                         kRedirectError);
 }
 
 void ServiceWorkerWriteToCacheJob::OnAuthRequired(
@@ -256,7 +245,7 @@
   TRACE_EVENT0("ServiceWorker",
                "ServiceWorkerWriteToCacheJob::OnAuthRequired");
   // TODO(michaeln): Pass this thru to our jobs client.
-  NotifyDoneHelper(
+  NotifyStartErrorHelper(
       net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED),
       kClientAuthenticationError);
 }
@@ -269,7 +258,7 @@
                "ServiceWorkerWriteToCacheJob::OnCertificateRequested");
   // TODO(michaeln): Pass this thru to our jobs client.
   // see NotifyCertificateRequested.
-  NotifyDoneHelper(
+  NotifyStartErrorHelper(
       net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED),
       kClientAuthenticationError);
 }
@@ -283,9 +272,9 @@
                "ServiceWorkerWriteToCacheJob::OnSSLCertificateError");
   // TODO(michaeln): Pass this thru to our jobs client,
   // see NotifySSLCertificateError.
-  NotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
-                                         net::ERR_INSECURE_RESPONSE),
-                   kSSLError);
+  NotifyStartErrorHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
+                                               net::ERR_INSECURE_RESPONSE),
+                         kSSLError);
 }
 
 void ServiceWorkerWriteToCacheJob::OnBeforeNetworkStart(
@@ -301,15 +290,15 @@
     net::URLRequest* request) {
   DCHECK_EQ(net_request_, request);
   if (!request->status().is_success()) {
-    NotifyDoneHelper(request->status(), kFetchScriptError);
+    NotifyStartErrorHelper(request->status(), kFetchScriptError);
     return;
   }
   if (request->GetResponseCode() / 100 != 2) {
     std::string error_message =
         base::StringPrintf(kBadHTTPResponseError, request->GetResponseCode());
-    NotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
-                                           net::ERR_INVALID_RESPONSE),
-                     error_message);
+    NotifyStartErrorHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
+                                                 net::ERR_INVALID_RESPONSE),
+                           error_message);
     // TODO(michaeln): Instead of error'ing immediately, send the net
     // response to our consumer, just don't cache it?
     return;
@@ -320,9 +309,10 @@
     const net::HttpNetworkSession::Params* session_params =
         request->context()->GetNetworkSessionParams();
     if (!session_params || !session_params->ignore_certificate_errors) {
-      NotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
-                                             net::ERR_INSECURE_RESPONSE),
-                       kSSLError);
+      NotifyStartErrorHelper(
+          net::URLRequestStatus(net::URLRequestStatus::FAILED,
+                                net::ERR_INSECURE_RESPONSE),
+          kSSLError);
       return;
     }
   }
@@ -337,9 +327,10 @@
           mime_type.empty()
               ? kNoMIMEError
               : base::StringPrintf(kBadMIMEError, mime_type.c_str());
-      NotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
-                                             net::ERR_INSECURE_RESPONSE),
-                       error_message);
+      NotifyStartErrorHelper(
+          net::URLRequestStatus(net::URLRequestStatus::FAILED,
+                                net::ERR_INSECURE_RESPONSE),
+          error_message);
       return;
     }
 
@@ -375,53 +366,31 @@
   NotifyHeadersComplete();
 }
 
-void ServiceWorkerWriteToCacheJob::HandleNetData(int bytes_read) {
-  io_buffer_bytes_ = bytes_read;
-  net::Error error = cache_writer_->MaybeWriteData(
-      io_buffer_.get(), bytes_read,
-      base::Bind(&ServiceWorkerWriteToCacheJob::OnWriteDataComplete,
-                 weak_factory_.GetWeakPtr()));
-  SetStatus(net::URLRequestStatus::FromError(error));
-
-  // In case of ERR_IO_PENDING, this logic is done in OnWriteDataComplete.
-  if (error != net::ERR_IO_PENDING && bytes_read == 0) {
-    NotifyFinishedCaching(net::URLRequestStatus::FromError(error),
-                          std::string());
-  }
-}
-
 void ServiceWorkerWriteToCacheJob::OnWriteDataComplete(net::Error error) {
   SetStatus(net::URLRequestStatus::FromError(error));
   DCHECK_NE(net::ERR_IO_PENDING, error);
-  if (io_buffer_bytes_ == 0) {
-    NotifyDoneHelper(net::URLRequestStatus::FromError(error), std::string());
-  }
-  NotifyReadComplete(error == net::OK ? io_buffer_bytes_ : error);
+  if (io_buffer_bytes_ == 0)
+    error = NotifyFinishedCaching(net::URLRequestStatus::FromError(error), "");
+  ReadRawDataComplete(error == net::OK ? io_buffer_bytes_ : error);
 }
 
-void ServiceWorkerWriteToCacheJob::OnReadCompleted(
-    net::URLRequest* request,
-    int bytes_read) {
+void ServiceWorkerWriteToCacheJob::OnReadCompleted(net::URLRequest* request,
+                                                   int result) {
   DCHECK_EQ(net_request_, request);
-  if (bytes_read < 0) {
+  DCHECK_NE(result, net::ERR_IO_PENDING);
+
+  if (result < 0) {
     DCHECK(!request->status().is_success());
-    NotifyDoneHelper(request->status(), kFetchScriptError);
+    result = NotifyFinishedCaching(request->status(), kFetchScriptError);
+  } else {
+    result = HandleNetData(result);
+  }
+
+  // ReadRawDataComplete will be called in OnWriteDataComplete, so return early.
+  if (result == net::ERR_IO_PENDING)
     return;
-  }
-  HandleNetData(bytes_read);
-  // HandleNetData can cause status of this job to change. If the status changes
-  // to IO_PENDING, that means HandleNetData has pending IO, and
-  // NotifyReadComplete will be called later by the appropriate callback.
-  if (!GetStatus().is_io_pending()) {
-    int result = GetStatus().status() == net::URLRequestStatus::SUCCESS
-                     ? bytes_read
-                     : GetStatus().error();
-    // If bytes_read is 0, HandleNetData synchronously completed and this job is
-    // at EOF.
-    if (bytes_read == 0)
-      NotifyDoneHelper(GetStatus(), std::string());
-    NotifyReadComplete(result);
-  }
+
+  ReadRawDataComplete(result);
 }
 
 bool ServiceWorkerWriteToCacheJob::CheckPathRestriction(
@@ -435,43 +404,57 @@
   if (!ServiceWorkerUtils::IsPathRestrictionSatisfied(
           version_->scope(), url_,
           has_header ? &service_worker_allowed : nullptr, &error_message)) {
-    NotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
-                                           net::ERR_INSECURE_RESPONSE),
-                     error_message);
+    NotifyStartErrorHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
+                                                 net::ERR_INSECURE_RESPONSE),
+                           error_message);
     return false;
   }
   return true;
 }
 
-void ServiceWorkerWriteToCacheJob::NotifyDoneHelper(
+int ServiceWorkerWriteToCacheJob::HandleNetData(int bytes_read) {
+  io_buffer_bytes_ = bytes_read;
+  net::Error error = cache_writer_->MaybeWriteData(
+      io_buffer_.get(), bytes_read,
+      base::Bind(&ServiceWorkerWriteToCacheJob::OnWriteDataComplete,
+                 weak_factory_.GetWeakPtr()));
+
+  // In case of ERR_IO_PENDING, this logic is done in OnWriteDataComplete.
+  if (error != net::ERR_IO_PENDING && bytes_read == 0) {
+    error = NotifyFinishedCaching(net::URLRequestStatus::FromError(error),
+                                  std::string());
+  }
+  return error == net::OK ? bytes_read : error;
+}
+
+void ServiceWorkerWriteToCacheJob::NotifyStartErrorHelper(
     const net::URLRequestStatus& status,
     const std::string& status_message) {
   DCHECK(!status.is_io_pending());
 
-  // Note that NotifyFinishedCaching has logic in it to detect the special case
-  // mentioned below as well.
-  NotifyFinishedCaching(status, status_message);
+  net::Error error = NotifyFinishedCaching(status, status_message);
+  // The special case mentioned in NotifyFinishedCaching about script being
+  // identical does not apply here, since the entire body needs to be read
+  // before this is relevant.
+  DCHECK_EQ(status.error(), error);
 
   net::URLRequestStatus reported_status = status;
   std::string reported_status_message = status_message;
 
-  // A strange special case: requests that successfully fetch the entire
-  // ServiceWorker and write it back, but which did not replace the incumbent
-  // script because the new script was identical, are considered to have failed.
-  if (status.is_success() && !cache_writer_->did_replace()) {
-    reported_status = net::URLRequestStatus::FromError(kIdenticalScriptError);
-    reported_status_message = "";
-  }
-
   SetStatus(reported_status);
-  NotifyDone(reported_status);
+  NotifyStartError(reported_status);
 }
 
-void ServiceWorkerWriteToCacheJob::NotifyFinishedCaching(
+net::Error ServiceWorkerWriteToCacheJob::NotifyFinishedCaching(
     net::URLRequestStatus status,
     const std::string& status_message) {
+  net::Error result = static_cast<net::Error>(status.error());
   if (did_notify_finished_)
-    return;
+    return result;
+
+  int size = -1;
+  if (status.is_success())
+    size = cache_writer_->bytes_written();
 
   // If all the calls to MaybeWriteHeaders/MaybeWriteData succeeded, but the
   // incumbent entry wasn't actually replaced because the new entry was
@@ -479,17 +462,18 @@
   // exists.
   if (status.status() == net::URLRequestStatus::SUCCESS &&
       !cache_writer_->did_replace()) {
-    status = net::URLRequestStatus::FromError(kIdenticalScriptError);
+    result = kIdenticalScriptError;
+    status = net::URLRequestStatus::FromError(result);
     version_->SetStartWorkerStatusCode(SERVICE_WORKER_ERROR_EXISTS);
+    version_->script_cache_map()->NotifyFinishedCaching(url_, size, status,
+                                                        std::string());
+  } else {
+    version_->script_cache_map()->NotifyFinishedCaching(url_, size, status,
+                                                        status_message);
   }
 
-  int size = -1;
-  if (status.is_success())
-    size = cache_writer_->bytes_written();
-
-  version_->script_cache_map()->NotifyFinishedCaching(url_, size, status,
-                                                      status_message);
   did_notify_finished_ = true;
+  return result;
 }
 
 scoped_ptr<ServiceWorkerResponseReader>
diff --git a/content/browser/service_worker/service_worker_write_to_cache_job.h b/content/browser/service_worker/service_worker_write_to_cache_job.h
index 92272399..e614912 100644
--- a/content/browser/service_worker/service_worker_write_to_cache_job.h
+++ b/content/browser/service_worker/service_worker_write_to_cache_job.h
@@ -64,6 +64,7 @@
 
   // net::URLRequestJob overrides
   void Start() override;
+  void StartAsync();
   void Kill() override;
   net::LoadState GetLoadState() const override;
   bool GetCharset(std::string* charset) override;
@@ -71,7 +72,7 @@
   void GetResponseInfo(net::HttpResponseInfo* info) override;
   int GetResponseCode() const override;
   void SetExtraRequestHeaders(const net::HttpRequestHeaders& headers) override;
-  bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override;
+  int ReadRawData(net::IOBuffer* buf, int buf_size) override;
 
   const net::HttpResponseInfo* http_info() const;
 
@@ -109,18 +110,22 @@
   bool CheckPathRestriction(net::URLRequest* request);
 
   // Writes network data back to the script cache if needed, and notifies the
-  // script cache of fetch completion at EOF. This function might need to do
-  // asynchronous IO; if so, it signals this through setting the URLRequestJob's
-  // status to IO_PENDING. After this function returns, if the URLRequestJob
-  // isn't IO_PENDING, all of the data in |io_buffer_| has been written back to
-  // the script cache if necessary.
-  void HandleNetData(int bytes_read);
+  // script cache of fetch completion at EOF. This function returns
+  // net::IO_PENDING if the IO is to be completed asynchronously, returns a
+  // negative number that represents a corresponding net error code (other than
+  // net::IO_PENDING) if an error occurred, or returns a non-negative number
+  // that represents the number of network bytes read. If the return value is
+  // non-negative, all of the data in |io_buffer_| has been written back to the
+  // script cache if necessary.
+  int HandleNetData(int bytes_read);
 
-  void NotifyDoneHelper(const net::URLRequestStatus& status,
-                        const std::string& status_message);
+  void NotifyStartErrorHelper(const net::URLRequestStatus& status,
+                              const std::string& status_message);
 
-  void NotifyFinishedCaching(net::URLRequestStatus status,
-                             const std::string& status_message);
+  // Returns an error code that is passed in through |status| or a new one if an
+  // additional error is found.
+  net::Error NotifyFinishedCaching(net::URLRequestStatus status,
+                                   const std::string& status_message);
 
   scoped_ptr<ServiceWorkerResponseReader> CreateCacheResponseReader();
   scoped_ptr<ServiceWorkerResponseWriter> CreateCacheResponseWriter();
@@ -140,6 +145,7 @@
   bool has_been_killed_;
   bool did_notify_started_;
   bool did_notify_finished_;
+
   base::WeakPtrFactory<ServiceWorkerWriteToCacheJob> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerWriteToCacheJob);
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 582d90a7..51cd0d4 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -41,6 +41,7 @@
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
 #include "third_party/WebKit/public/web/WebSandboxFlags.h"
+#include "ui/gfx/switches.h"
 
 namespace content {
 
@@ -109,6 +110,149 @@
   rwh->ForwardMouseEvent(mouse_event);
 }
 
+class RenderWidgetHostMouseEventMonitor {
+ public:
+  explicit RenderWidgetHostMouseEventMonitor(RenderWidgetHost* host)
+      : host_(host), event_received_(false) {
+    host_->AddMouseEventCallback(
+        base::Bind(&RenderWidgetHostMouseEventMonitor::MouseEventCallback,
+                   base::Unretained(this)));
+  }
+  ~RenderWidgetHostMouseEventMonitor() {
+    host_->RemoveMouseEventCallback(
+        base::Bind(&RenderWidgetHostMouseEventMonitor::MouseEventCallback,
+                   base::Unretained(this)));
+  }
+  bool EventWasReceived() const { return event_received_; }
+  void ResetEventReceived() { event_received_ = false; }
+  const blink::WebMouseEvent& event() const { return event_; }
+
+ private:
+  bool MouseEventCallback(const blink::WebMouseEvent& event) {
+    event_received_ = true;
+    event_ = event;
+    return false;
+  }
+  RenderWidgetHost* host_;
+  bool event_received_;
+  blink::WebMouseEvent event_;
+
+  DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostMouseEventMonitor);
+};
+
+// Helper function that performs a surface hittest.
+void SurfaceHitTestTestHelper(
+    Shell* shell,
+    net::test_server::EmbeddedTestServer* embedded_test_server) {
+  if (!UseSurfacesEnabled())
+    return;
+
+  GURL main_url(embedded_test_server->GetURL(
+      "/frame_tree/page_with_positioned_frame.html"));
+  NavigateToURL(shell, main_url);
+
+  // It is safe to obtain the root frame tree node here, as it doesn't change.
+  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell->web_contents())
+                            ->GetFrameTree()
+                            ->root();
+  ASSERT_EQ(1U, root->child_count());
+
+  FrameTreeNode* child_node = root->child_at(0);
+  GURL site_url(embedded_test_server->GetURL("baz.com", "/title1.html"));
+  EXPECT_EQ(site_url, child_node->current_url());
+  EXPECT_NE(shell->web_contents()->GetSiteInstance(),
+            child_node->current_frame_host()->GetSiteInstance());
+
+  // Create listeners for mouse events.
+  RenderWidgetHostMouseEventMonitor main_frame_monitor(
+      root->current_frame_host()->GetRenderWidgetHost());
+  RenderWidgetHostMouseEventMonitor child_frame_monitor(
+      child_node->current_frame_host()->GetRenderWidgetHost());
+
+  RenderWidgetHostInputEventRouter* router =
+      static_cast<WebContentsImpl*>(shell->web_contents())
+          ->GetInputEventRouter();
+
+  RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>(
+      root->current_frame_host()->GetRenderWidgetHost()->GetView());
+  RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
+      child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+  // We need to wait for a compositor frame from the child frame, at which
+  // point its surface will be created.
+  while (rwhv_child->RendererFrameNumber() <= 0) {
+    // TODO(lazyboy): Find a better way to avoid sleeping like this. See
+    // http://crbug.com/405282 for details.
+    base::RunLoop run_loop;
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, run_loop.QuitClosure(),
+        base::TimeDelta::FromMilliseconds(10));
+    run_loop.Run();
+  }
+
+  uint32_t cur_render_frame_number = root_view->RendererFrameNumber();
+
+  // Target input event to child frame.
+  blink::WebMouseEvent child_event;
+  child_event.type = blink::WebInputEvent::MouseDown;
+  child_event.button = blink::WebPointerProperties::ButtonLeft;
+  child_event.x = 75;
+  child_event.y = 75;
+  child_event.clickCount = 1;
+  main_frame_monitor.ResetEventReceived();
+  child_frame_monitor.ResetEventReceived();
+  router->RouteMouseEvent(root_view, &child_event);
+
+  while (!child_frame_monitor.EventWasReceived()) {
+    // This is working around a big synchronization problem. It is very
+    // difficult to know if we have received a compositor frame from the
+    // main frame renderer *after* it received the child frame's surface
+    // ID. Hit testing won't work until this happens. So if the hit test
+    // fails then we wait for another frame to arrive and try again.
+    // TODO(kenrb): We need a better way to do all of this, possibly coming
+    // from http://crbug.com/405282.
+    while (root_view->RendererFrameNumber() <= cur_render_frame_number) {
+      base::RunLoop run_loop;
+      base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+          FROM_HERE, run_loop.QuitClosure(),
+          base::TimeDelta::FromMilliseconds(10));
+      run_loop.Run();
+    }
+    cur_render_frame_number = root_view->RendererFrameNumber();
+    child_event.type = blink::WebInputEvent::MouseDown;
+    child_event.button = blink::WebPointerProperties::ButtonLeft;
+    child_event.x = 75;
+    child_event.y = 75;
+    child_event.clickCount = 1;
+    main_frame_monitor.ResetEventReceived();
+    child_frame_monitor.ResetEventReceived();
+    router->RouteMouseEvent(root_view, &child_event);
+  }
+
+  EXPECT_TRUE(child_frame_monitor.EventWasReceived());
+  EXPECT_EQ(23, child_frame_monitor.event().x);
+  EXPECT_EQ(23, child_frame_monitor.event().y);
+  EXPECT_FALSE(main_frame_monitor.EventWasReceived());
+
+  child_frame_monitor.ResetEventReceived();
+  main_frame_monitor.ResetEventReceived();
+
+  // Target input event to main frame.
+  blink::WebMouseEvent main_event;
+  main_event.type = blink::WebInputEvent::MouseDown;
+  main_event.button = blink::WebPointerProperties::ButtonLeft;
+  main_event.x = 1;
+  main_event.y = 1;
+  main_event.clickCount = 1;
+  // Ladies and gentlemen, THIS is the main_event!
+  router->RouteMouseEvent(root_view, &main_event);
+
+  EXPECT_FALSE(child_frame_monitor.EventWasReceived());
+  EXPECT_TRUE(main_frame_monitor.EventWasReceived());
+  EXPECT_EQ(1, main_frame_monitor.event().x);
+  EXPECT_EQ(1, main_frame_monitor.event().y);
+}
+
 class RedirectNotificationObserver : public NotificationObserver {
  public:
   // Register to listen for notifications of the given type from either a
@@ -329,6 +473,23 @@
   SetupCrossSiteRedirector(embedded_test_server());
 }
 
+//
+// SitePerProcessHighDPIBrowserTest
+//
+
+
+class SitePerProcessHighDPIBrowserTest : public SitePerProcessBrowserTest {
+ public:
+  SitePerProcessHighDPIBrowserTest() {}
+
+ protected:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    SitePerProcessBrowserTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitchASCII(switches::kForceDeviceScaleFactor,
+                                    base::StringPrintf("2"));
+  }
+};
+
 // Ensure that navigating subframes in --site-per-process mode works and the
 // correct documents are committed.
 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteIframe) {
@@ -458,34 +619,6 @@
       DepictFrameTree(root));
 }
 
-class RenderWidgetHostMouseEventMonitor {
- public:
-  RenderWidgetHostMouseEventMonitor(RenderWidgetHost* host)
-      : host_(host), event_received(false) {
-    host_->AddMouseEventCallback(
-        base::Bind(&RenderWidgetHostMouseEventMonitor::MouseEventCallback,
-                   base::Unretained(this)));
-  }
-  ~RenderWidgetHostMouseEventMonitor() {
-    host_->RemoveMouseEventCallback(
-        base::Bind(&RenderWidgetHostMouseEventMonitor::MouseEventCallback,
-                   base::Unretained(this)));
-  }
-  bool EventWasReceived() { return event_received; }
-  void ResetEventReceived() { event_received = false; }
-  const blink::WebMouseEvent& event() const { return event_; }
-
- private:
-  bool MouseEventCallback(const blink::WebMouseEvent& event) {
-    event_received = true;
-    event_ = event;
-    return false;
-  }
-  RenderWidgetHost* host_;
-  bool event_received;
-  blink::WebMouseEvent event_;
-};
-
 // Test that mouse events are being routed to the correct RenderWidgetHostView
 // based on coordinates.
 #if defined(OS_ANDROID)
@@ -496,113 +629,21 @@
 #define MAYBE_SurfaceHitTestTest SurfaceHitTestTest
 #endif
 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, MAYBE_SurfaceHitTestTest) {
-  if (!UseSurfacesEnabled())
-    return;
+  SurfaceHitTestTestHelper(shell(), embedded_test_server());
+}
 
-  GURL main_url(embedded_test_server()->GetURL(
-      "/frame_tree/page_with_positioned_frame.html"));
-  NavigateToURL(shell(), main_url);
-
-  // It is safe to obtain the root frame tree node here, as it doesn't change.
-  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
-                            ->GetFrameTree()
-                            ->root();
-  ASSERT_EQ(1U, root->child_count());
-
-  FrameTreeNode* child_node = root->child_at(0);
-  GURL site_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
-  EXPECT_EQ(site_url, child_node->current_url());
-  EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
-            child_node->current_frame_host()->GetSiteInstance());
-
-  // Create listeners for mouse events.
-  RenderWidgetHostMouseEventMonitor main_frame_monitor(
-      root->current_frame_host()->GetRenderWidgetHost());
-  RenderWidgetHostMouseEventMonitor child_frame_monitor(
-      child_node->current_frame_host()->GetRenderWidgetHost());
-
-  RenderWidgetHostInputEventRouter* router =
-      static_cast<WebContentsImpl*>(shell()->web_contents())
-          ->GetInputEventRouter();
-
-  RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>(
-      root->current_frame_host()->GetRenderWidgetHost()->GetView());
-  RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
-      child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
-
-  // We need to wait for a compositor frame from the child frame, at which
-  // point its surface will be created.
-  while (rwhv_child->RendererFrameNumber() <= 0) {
-    // TODO(lazyboy): Find a better way to avoid sleeping like this. See
-    // http://crbug.com/405282 for details.
-    base::RunLoop run_loop;
-    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-        FROM_HERE, run_loop.QuitClosure(),
-        base::TimeDelta::FromMilliseconds(10));
-    run_loop.Run();
-  }
-
-  uint32_t cur_render_frame_number = root_view->RendererFrameNumber();
-
-  // Target input event to child frame.
-  blink::WebMouseEvent child_event;
-  child_event.type = blink::WebInputEvent::MouseDown;
-  child_event.button = blink::WebPointerProperties::ButtonLeft;
-  child_event.x = 75;
-  child_event.y = 75;
-  child_event.clickCount = 1;
-  main_frame_monitor.ResetEventReceived();
-  child_frame_monitor.ResetEventReceived();
-  router->RouteMouseEvent(root_view, &child_event);
-
-  while (!child_frame_monitor.EventWasReceived()) {
-    // This is working around a big synchronization problem. It is very
-    // difficult to know if we have received a compositor frame from the
-    // main frame renderer *after* it received the child frame's surface
-    // ID. Hit testing won't work until this happens. So if the hit test
-    // fails then we wait for another frame to arrive and try again.
-    // TODO(kenrb): We need a better way to do all of this, possibly coming
-    // from http://crbug.com/405282.
-    while (root_view->RendererFrameNumber() <= cur_render_frame_number) {
-      base::RunLoop run_loop;
-      base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-          FROM_HERE, run_loop.QuitClosure(),
-          base::TimeDelta::FromMilliseconds(10));
-      run_loop.Run();
-    }
-    cur_render_frame_number = root_view->RendererFrameNumber();
-    child_event.type = blink::WebInputEvent::MouseDown;
-    child_event.button = blink::WebPointerProperties::ButtonLeft;
-    child_event.x = 75;
-    child_event.y = 75;
-    child_event.clickCount = 1;
-    main_frame_monitor.ResetEventReceived();
-    child_frame_monitor.ResetEventReceived();
-    router->RouteMouseEvent(root_view, &child_event);
-  }
-
-  EXPECT_TRUE(child_frame_monitor.EventWasReceived());
-  EXPECT_EQ(23, child_frame_monitor.event().x);
-  EXPECT_EQ(23, child_frame_monitor.event().y);
-  EXPECT_FALSE(main_frame_monitor.EventWasReceived());
-
-  child_frame_monitor.ResetEventReceived();
-  main_frame_monitor.ResetEventReceived();
-
-  // Target input event to main frame.
-  blink::WebMouseEvent main_event;
-  main_event.type = blink::WebInputEvent::MouseDown;
-  main_event.button = blink::WebPointerProperties::ButtonLeft;
-  main_event.x = 1;
-  main_event.y = 1;
-  main_event.clickCount = 1;
-  // Ladies and gentlemen, THIS is the main_event!
-  router->RouteMouseEvent(root_view, &main_event);
-
-  EXPECT_FALSE(child_frame_monitor.EventWasReceived());
-  EXPECT_TRUE(main_frame_monitor.EventWasReceived());
-  EXPECT_EQ(1, main_frame_monitor.event().x);
-  EXPECT_EQ(1, main_frame_monitor.event().y);
+// Same test as above, but runs in high-dpi mode.
+#if defined(OS_ANDROID) || defined(OS_WIN)
+// Browser process hit testing is not implemented on Android.
+// https://crbug.com/491334
+// Windows is disabled because of https://crbug.com/545547.
+#define MAYBE_HighDPISurfaceHitTestTest DISABLED_SurfaceHitTestTest
+#else
+#define MAYBE_HighDPISurfaceHitTestTest SurfaceHitTestTest
+#endif
+IN_PROC_BROWSER_TEST_F(SitePerProcessHighDPIBrowserTest,
+                       MAYBE_HighDPISurfaceHitTestTest) {
+  SurfaceHitTestTestHelper(shell(), embedded_test_server());
 }
 
 // Tests OOPIF rendering by checking that the RWH of the iframe generates
diff --git a/content/browser/storage_partition_impl.h b/content/browser/storage_partition_impl.h
index 37ee1f8..2c08a7e 100644
--- a/content/browser/storage_partition_impl.h
+++ b/content/browser/storage_partition_impl.h
@@ -82,6 +82,7 @@
   struct QuotaManagedDataDeletionHelper;
 
  private:
+  friend class BackgroundSyncManagerTest;
   friend class StoragePartitionImplMap;
   FRIEND_TEST_ALL_PREFIXES(StoragePartitionShaderClearTest, ClearShaderCache);
   FRIEND_TEST_ALL_PREFIXES(StoragePartitionImplTest,
diff --git a/content/browser/streams/stream_url_request_job.cc b/content/browser/streams/stream_url_request_job.cc
index d2bce89..e26fe35 100644
--- a/content/browser/streams/stream_url_request_job.cc
+++ b/content/browser/streams/stream_url_request_job.cc
@@ -40,8 +40,6 @@
 }
 
 void StreamURLRequestJob::OnDataAvailable(Stream* stream) {
-  // Clear the IO_PENDING status.
-  SetStatus(net::URLRequestStatus());
   // Do nothing if pending_buffer_ is empty, i.e. there's no ReadRawData()
   // operation waiting for IO completion.
   if (!pending_buffer_.get())
@@ -50,24 +48,22 @@
   // pending_buffer_ is set to the IOBuffer instance provided to ReadRawData()
   // by URLRequestJob.
 
-  int bytes_read;
-  switch (stream_->ReadRawData(
-      pending_buffer_.get(), pending_buffer_size_, &bytes_read)) {
+  int result = 0;
+  switch (stream_->ReadRawData(pending_buffer_.get(), pending_buffer_size_,
+                               &result)) {
     case Stream::STREAM_HAS_DATA:
-      DCHECK_GT(bytes_read, 0);
+      DCHECK_GT(result, 0);
       break;
     case Stream::STREAM_COMPLETE:
-      // Ensure this. Calling NotifyReadComplete call with 0 signals
-      // completion.
-      bytes_read = 0;
+      // Ensure ReadRawData gives net::OK.
+      DCHECK_EQ(net::OK, result);
       break;
     case Stream::STREAM_EMPTY:
       NOTREACHED();
       break;
     case Stream::STREAM_ABORTED:
       // Handle this as connection reset.
-      NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
-                                       net::ERR_CONNECTION_RESET));
+      result = net::ERR_CONNECTION_RESET;
       break;
   }
 
@@ -76,8 +72,9 @@
   pending_buffer_ = NULL;
   pending_buffer_size_ = 0;
 
-  total_bytes_read_ += bytes_read;
-  NotifyReadComplete(bytes_read);
+  if (result > 0)
+    total_bytes_read_ += result;
+  ReadRawDataComplete(result);
 }
 
 // net::URLRequestJob methods.
@@ -94,43 +91,40 @@
   ClearStream();
 }
 
-bool StreamURLRequestJob::ReadRawData(net::IOBuffer* buf,
-                                      int buf_size,
-                                      int* bytes_read) {
+int StreamURLRequestJob::ReadRawData(net::IOBuffer* buf, int buf_size) {
+  // TODO(ellyjones): This is not right. The old code returned true here, but
+  // ReadRawData's old contract was to return true only for synchronous
+  // successes, which had the effect of treating all errors as synchronous EOFs.
+  // See https://crbug.com/508957
   if (request_failed_)
-    return true;
+    return 0;
 
   DCHECK(buf);
-  DCHECK(bytes_read);
   int to_read = buf_size;
   if (max_range_ && to_read) {
     if (to_read + total_bytes_read_ > max_range_)
       to_read = max_range_ - total_bytes_read_;
 
-    if (to_read <= 0) {
-      *bytes_read = 0;
-      return true;
-    }
+    if (to_read == 0)
+      return 0;
   }
 
-  switch (stream_->ReadRawData(buf, to_read, bytes_read)) {
+  int bytes_read = 0;
+  switch (stream_->ReadRawData(buf, to_read, &bytes_read)) {
     case Stream::STREAM_HAS_DATA:
     case Stream::STREAM_COMPLETE:
-      total_bytes_read_ += *bytes_read;
-      return true;
+      total_bytes_read_ += bytes_read;
+      return bytes_read;
     case Stream::STREAM_EMPTY:
       pending_buffer_ = buf;
       pending_buffer_size_ = to_read;
-      SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
-      return false;
+      return net::ERR_IO_PENDING;
     case Stream::STREAM_ABORTED:
       // Handle this as connection reset.
-      NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
-                                       net::ERR_CONNECTION_RESET));
-      return false;
+      return net::ERR_CONNECTION_RESET;
   }
   NOTREACHED();
-  return false;
+  return net::ERR_FAILED;
 }
 
 bool StreamURLRequestJob::GetMimeType(std::string* mime_type) const {
@@ -189,13 +183,8 @@
 void StreamURLRequestJob::NotifyFailure(int error_code) {
   request_failed_ = true;
 
-  // If we already return the headers on success, we can't change the headers
-  // now. Instead, we just error out.
-  if (headers_set_) {
-    NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
-                                     error_code));
-    return;
-  }
+  // This method can only be called before headers are set.
+  DCHECK(!headers_set_);
 
   // TODO(zork): Share these with BlobURLRequestJob.
   net::HttpStatusCode status_code = net::HTTP_INTERNAL_SERVER_ERROR;
diff --git a/content/browser/streams/stream_url_request_job.h b/content/browser/streams/stream_url_request_job.h
index 05c9551..f22311d 100644
--- a/content/browser/streams/stream_url_request_job.h
+++ b/content/browser/streams/stream_url_request_job.h
@@ -29,7 +29,7 @@
   // net::URLRequestJob methods.
   void Start() override;
   void Kill() override;
-  bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override;
+  int ReadRawData(net::IOBuffer* buf, int buf_size) override;
   bool GetMimeType(std::string* mime_type) const override;
   void GetResponseInfo(net::HttpResponseInfo* info) override;
   int GetResponseCode() const override;
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index e979525..41a6084 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -7,7 +7,6 @@
 #include <utility>
 
 #include "base/command_line.h"
-#include "base/debug/crash_logging.h"
 #include "base/lazy_instance.h"
 #include "base/location.h"
 #include "base/logging.h"
@@ -3899,37 +3898,14 @@
   RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>(rvh);
   NavigationEntryImpl* entry = controller_.GetEntryWithPageID(
       rvhi->GetSiteInstance(), page_id);
-
-  int nav_entry_id =
-      static_cast<RenderFrameHostImpl*>(rvhi->GetMainFrame())->nav_entry_id();
-  NavigationEntryImpl* new_entry =
-      controller_.GetEntryWithUniqueID(nav_entry_id);
-
-  base::debug::SetCrashKeyValue("pageid", base::IntToString(page_id));
-  base::debug::SetCrashKeyValue("navuniqueid", base::IntToString(nav_entry_id));
-  base::debug::SetCrashKeyValue(
-      "oldindex", base::IntToString(controller_.GetIndexOfEntry(entry)));
-  base::debug::SetCrashKeyValue(
-      "newindex", base::IntToString(controller_.GetIndexOfEntry(new_entry)));
-  base::debug::SetCrashKeyValue(
-      "lastcommittedindex",
-      base::IntToString(controller_.GetLastCommittedEntryIndex()));
-  base::debug::SetCrashKeyValue("oldurl",
-                                entry ? entry->GetURL().spec() : "-nullptr-");
-  base::debug::SetCrashKeyValue(
-      "newurl", new_entry ? new_entry->GetURL().spec() : "-nullptr-");
-  base::debug::SetCrashKeyValue(
-      "updatedvalue", page_state.GetTopLevelUrlStringTemporaryForBug369661());
-  base::debug::SetCrashKeyValue(
-      "oldvalue", entry ? entry->GetURL().spec() : "-nullptr-");
-  base::debug::SetCrashKeyValue(
-      "newvalue",
-      new_entry ? new_entry->GetURL().spec() : "-nullptr-");
-  CHECK_EQ(entry, new_entry);
-
   if (!entry)
     return;
 
+  NavigationEntryImpl* new_entry = controller_.GetEntryWithUniqueID(
+      static_cast<RenderFrameHostImpl*>(rvhi->GetMainFrame())->nav_entry_id());
+
+  DCHECK_EQ(entry, new_entry);
+
   if (page_state == entry->GetPageState())
     return;  // Nothing to update.
   entry->SetPageState(page_state);
@@ -4131,31 +4107,9 @@
   NavigationEntryImpl* entry = controller_.GetEntryWithPageID(
       render_frame_host->GetSiteInstance(), page_id);
 
-  int nav_entry_id =
-      static_cast<RenderFrameHostImpl*>(render_frame_host)->nav_entry_id();
-  NavigationEntryImpl* new_entry =
-      controller_.GetEntryWithUniqueID(nav_entry_id);
-
-  base::debug::SetCrashKeyValue("pageid", base::IntToString(page_id));
-  base::debug::SetCrashKeyValue("navuniqueid", base::IntToString(nav_entry_id));
-  base::debug::SetCrashKeyValue(
-      "oldindex", base::IntToString(controller_.GetIndexOfEntry(entry)));
-  base::debug::SetCrashKeyValue(
-      "newindex", base::IntToString(controller_.GetIndexOfEntry(new_entry)));
-  base::debug::SetCrashKeyValue(
-      "lastcommittedindex",
-      base::IntToString(controller_.GetLastCommittedEntryIndex()));
-  base::debug::SetCrashKeyValue("oldurl",
-                                entry ? entry->GetURL().spec() : "-nullptr-");
-  base::debug::SetCrashKeyValue(
-      "newurl", new_entry ? new_entry->GetURL().spec() : "-nullptr-");
-  base::debug::SetCrashKeyValue("updatedvalue", base::UTF16ToUTF8(title));
-  base::debug::SetCrashKeyValue(
-      "oldvalue", entry ? base::UTF16ToUTF8(entry->GetTitle()) : "-nullptr-");
-  base::debug::SetCrashKeyValue(
-      "newvalue",
-      new_entry ? base::UTF16ToUTF8(new_entry->GetTitle()) : "-nullptr-");
-  CHECK_EQ(entry, new_entry);
+  NavigationEntryImpl* new_entry = controller_.GetEntryWithUniqueID(
+      static_cast<RenderFrameHostImpl*>(render_frame_host)->nav_entry_id());
+  DCHECK_EQ(entry, new_entry);
 
   // We can handle title updates when we don't have an entry in
   // UpdateTitleForEntry, but only if the update is from the current RVH.
diff --git a/content/browser/web_contents/web_contents_view_aura.cc b/content/browser/web_contents/web_contents_view_aura.cc
index 28ee915d..3d0b9c7 100644
--- a/content/browser/web_contents/web_contents_view_aura.cc
+++ b/content/browser/web_contents/web_contents_view_aura.cc
@@ -886,8 +886,7 @@
 
   RenderWidgetHostViewAura* view =
       new RenderWidgetHostViewAura(render_widget_host, is_guest_view_hack);
-  view->InitAsChild(NULL);
-  GetNativeView()->AddChild(view->GetNativeView());
+  view->InitAsChild(GetNativeView());
 
   RenderWidgetHostImpl* host_impl =
       RenderWidgetHostImpl::From(render_widget_host);
diff --git a/content/browser/webui/url_data_manager_backend.cc b/content/browser/webui/url_data_manager_backend.cc
index ac346dd..485aff6 100644
--- a/content/browser/webui/url_data_manager_backend.cc
+++ b/content/browser/webui/url_data_manager_backend.cc
@@ -119,7 +119,7 @@
   // net::URLRequestJob implementation.
   void Start() override;
   void Kill() override;
-  bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override;
+  int ReadRawData(net::IOBuffer* buf, int buf_size) override;
   bool GetMimeType(std::string* mime_type) const override;
   int GetResponseCode() const override;
   void GetResponseInfo(net::HttpResponseInfo* info) override;
@@ -190,8 +190,9 @@
   bool RequiresUnsafeEval() const;
 
   // Do the actual copy from data_ (the data we're serving) into |buf|.
-  // Separate from ReadRawData so we can handle async I/O.
-  void CompleteRead(net::IOBuffer* buf, int buf_size, int* bytes_read);
+  // Separate from ReadRawData so we can handle async I/O. Returns the number of
+  // bytes read.
+  int CompleteRead(net::IOBuffer* buf, int buf_size);
 
   // The actual data we're serving.  NULL until it's been fetched.
   scoped_refptr<base::RefCountedMemory> data_;
@@ -336,22 +337,16 @@
 void URLRequestChromeJob::DataAvailable(base::RefCountedMemory* bytes) {
   TRACE_EVENT_ASYNC_END0("browser", "DataManager:Request", this);
   if (bytes) {
-    // The request completed, and we have all the data.
-    // Clear any IO pending status.
-    SetStatus(net::URLRequestStatus());
-
     data_ = bytes;
-    int bytes_read;
     if (pending_buf_.get()) {
       CHECK(pending_buf_->data());
-      CompleteRead(pending_buf_.get(), pending_buf_size_, &bytes_read);
+      int result = CompleteRead(pending_buf_.get(), pending_buf_size_);
       pending_buf_ = NULL;
-      NotifyReadComplete(bytes_read);
+      ReadRawDataComplete(result);
     }
   } else {
     // The request failed.
-    NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
-                                     net::ERR_FAILED));
+    ReadRawDataComplete(net::ERR_FAILED);
   }
 }
 
@@ -359,25 +354,21 @@
   return weak_factory_.GetWeakPtr();
 }
 
-bool URLRequestChromeJob::ReadRawData(net::IOBuffer* buf, int buf_size,
-                                      int* bytes_read) {
+int URLRequestChromeJob::ReadRawData(net::IOBuffer* buf, int buf_size) {
   if (!data_.get()) {
-    SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
     DCHECK(!pending_buf_.get());
     CHECK(buf->data());
     pending_buf_ = buf;
     pending_buf_size_ = buf_size;
-    return false;  // Tell the caller we're still waiting for data.
+    return net::ERR_IO_PENDING;
   }
 
   // Otherwise, the data is available.
-  CompleteRead(buf, buf_size, bytes_read);
-  return true;
+  return CompleteRead(buf, buf_size);
 }
 
-void URLRequestChromeJob::CompleteRead(net::IOBuffer* buf, int buf_size,
-                                       int* bytes_read) {
-  int remaining = static_cast<int>(data_->size()) - data_offset_;
+int URLRequestChromeJob::CompleteRead(net::IOBuffer* buf, int buf_size) {
+  int remaining = data_->size() - data_offset_;
   if (buf_size > remaining)
     buf_size = remaining;
   if (buf_size > 0) {
@@ -389,7 +380,7 @@
     memcpy(buf->data(), data_->front() + data_offset_, buf_size);
     data_offset_ += buf_size;
   }
-  *bytes_read = buf_size;
+  return buf_size;
 }
 
 void URLRequestChromeJob::CheckStoragePartitionMatches(
diff --git a/content/child/child_gpu_memory_buffer_manager.cc b/content/child/child_gpu_memory_buffer_manager.cc
index 6eaf229..c83ceea6 100644
--- a/content/child/child_gpu_memory_buffer_manager.cc
+++ b/content/child/child_gpu_memory_buffer_manager.cc
@@ -13,10 +13,10 @@
 
 void DeletedGpuMemoryBuffer(ThreadSafeSender* sender,
                             gfx::GpuMemoryBufferId id,
-                            uint32 sync_point) {
+                            const gpu::SyncToken& sync_token) {
   TRACE_EVENT0("renderer",
                "ChildGpuMemoryBufferManager::DeletedGpuMemoryBuffer");
-  sender->Send(new ChildProcessHostMsg_DeletedGpuMemoryBuffer(id, sync_point));
+  sender->Send(new ChildProcessHostMsg_DeletedGpuMemoryBuffer(id, sync_token));
 }
 
 }  // namespace
@@ -52,7 +52,8 @@
       handle, size, format, usage,
       base::Bind(&DeletedGpuMemoryBuffer, sender_, handle.id)));
   if (!buffer) {
-    sender_->Send(new ChildProcessHostMsg_DeletedGpuMemoryBuffer(handle.id, 0));
+    sender_->Send(new ChildProcessHostMsg_DeletedGpuMemoryBuffer(
+        handle.id, gpu::SyncToken()));
     return nullptr;
   }
 
@@ -74,11 +75,11 @@
   return GpuMemoryBufferImpl::FromClientBuffer(buffer);
 }
 
-void ChildGpuMemoryBufferManager::SetDestructionSyncPoint(
+void ChildGpuMemoryBufferManager::SetDestructionSyncToken(
     gfx::GpuMemoryBuffer* buffer,
-    uint32 sync_point) {
+    const gpu::SyncToken& sync_token) {
   static_cast<GpuMemoryBufferImpl*>(buffer)
-      ->set_destruction_sync_point(sync_point);
+      ->set_destruction_sync_token(sync_token);
 }
 
 }  // namespace content
diff --git a/content/child/child_gpu_memory_buffer_manager.h b/content/child/child_gpu_memory_buffer_manager.h
index 26258530..1cdb945 100644
--- a/content/child/child_gpu_memory_buffer_manager.h
+++ b/content/child/child_gpu_memory_buffer_manager.h
@@ -26,8 +26,8 @@
       gfx::BufferFormat format) override;
   gfx::GpuMemoryBuffer* GpuMemoryBufferFromClientBuffer(
       ClientBuffer buffer) override;
-  void SetDestructionSyncPoint(gfx::GpuMemoryBuffer* buffer,
-                               uint32 sync_point) override;
+  void SetDestructionSyncToken(gfx::GpuMemoryBuffer* buffer,
+                               const gpu::SyncToken& sync_token) override;
 
  private:
   scoped_refptr<ThreadSafeSender> sender_;
diff --git a/content/child/web_memory_dump_provider_adapter.cc b/content/child/web_memory_dump_provider_adapter.cc
index 6b33aac..8666fd09 100644
--- a/content/child/web_memory_dump_provider_adapter.cc
+++ b/content/child/web_memory_dump_provider_adapter.cc
@@ -10,6 +10,7 @@
 #include "base/trace_event/memory_profiler_heap_dump_writer.h"
 #include "base/trace_event/process_memory_dump.h"
 #include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/trace_event_memory_overhead.h"
 #include "content/child/web_process_memory_dump_impl.h"
 #include "third_party/WebKit/public/platform/WebMemoryDumpProvider.h"
 
@@ -74,14 +75,18 @@
       web_memory_dump_provider_->supportsHeapProfiling() &&
       g_heap_profiling_enabled) {
     HeapDumpWriter writer(pmd->session_state()->stack_frame_deduplicator());
+    TraceEventMemoryOverhead overhead;
 
     {
       AutoLock lock(g_allocation_register_lock.Get());
       for (const auto& alloc_size : *g_allocation_register)
         writer.InsertAllocation(alloc_size.context, alloc_size.size);
+
+      g_allocation_register->EstimateTraceMemoryOverhead(&overhead);
     }
 
     pmd->AddHeapDump("partition_alloc", writer.WriteHeapDump());
+    overhead.DumpInto("tracing/heap_profiler", pmd);
   }
 
   return web_memory_dump_provider_->onMemoryDump(level, &web_pmd_impl);
diff --git a/content/common/child_process_host_impl.cc b/content/common/child_process_host_impl.cc
index 707d644a..b7ce51b 100644
--- a/content/common/child_process_host_impl.cc
+++ b/content/common/child_process_host_impl.cc
@@ -317,7 +317,7 @@
 
 void ChildProcessHostImpl::OnDeletedGpuMemoryBuffer(
     gfx::GpuMemoryBufferId id,
-    uint32 sync_point) {
+    const gpu::SyncToken& sync_token) {
   // Note: Nothing to do here as ownership of shared memory backed
   // GpuMemoryBuffers is passed with IPC.
 }
diff --git a/content/common/child_process_host_impl.h b/content/common/child_process_host_impl.h
index d859323..f07e2a88 100644
--- a/content/common/child_process_host_impl.h
+++ b/content/common/child_process_host_impl.h
@@ -28,6 +28,10 @@
 class MessageFilter;
 }
 
+namespace gpu {
+struct SyncToken;
+}
+
 namespace content {
 class ChildProcessHostDelegate;
 
@@ -101,7 +105,7 @@
                                  gfx::BufferUsage usage,
                                  gfx::GpuMemoryBufferHandle* handle);
   void OnDeletedGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
-                                uint32 sync_point);
+                                const gpu::SyncToken& sync_token);
 
   ChildProcessHostDelegate* delegate_;
   base::Process peer_process_;
diff --git a/content/common/child_process_messages.h b/content/common/child_process_messages.h
index 7e78e87f..ec2a4bf 100644
--- a/content/common/child_process_messages.h
+++ b/content/common/child_process_messages.h
@@ -14,6 +14,7 @@
 #include "cc/resources/shared_bitmap_manager.h"
 #include "content/common/content_export.h"
 #include "content/common/host_discardable_shared_memory_manager.h"
+#include "gpu/command_buffer/common/sync_token.h"
 #include "ipc/ipc_message_macros.h"
 #include "ui/gfx/gpu_memory_buffer.h"
 #include "ui/gfx/ipc/gfx_param_traits.h"
@@ -210,7 +211,7 @@
 // Informs the browser that the child deleted a gpu memory buffer.
 IPC_MESSAGE_CONTROL2(ChildProcessHostMsg_DeletedGpuMemoryBuffer,
                      gfx::GpuMemoryBufferId,
-                     uint32 /* sync_point */)
+                     gpu::SyncToken /* sync_token */)
 
 // Asks the browser to create a block of discardable shared memory for the
 // child process.
diff --git a/content/common/gpu/client/command_buffer_proxy_impl.cc b/content/common/gpu/client/command_buffer_proxy_impl.cc
index c3c84192..b8785bc 100644
--- a/content/common/gpu/client/command_buffer_proxy_impl.cc
+++ b/content/common/gpu/client/command_buffer_proxy_impl.cc
@@ -400,7 +400,7 @@
 int32_t CommandBufferProxyImpl::CreateImage(ClientBuffer buffer,
                                             size_t width,
                                             size_t height,
-                                            unsigned internalformat) {
+                                            unsigned internal_format) {
   CheckLock();
   if (last_state_.error != gpu::error::kNoError)
     return -1;
@@ -416,29 +416,47 @@
   // This handle is owned by the GPU process and must be passed to it or it
   // will leak. In otherwords, do not early out on error between here and the
   // sending of the CreateImage IPC below.
-  bool requires_sync_point = false;
+  bool requires_sync_token = false;
   gfx::GpuMemoryBufferHandle handle =
       channel_->ShareGpuMemoryBufferToGpuProcess(gpu_memory_buffer->GetHandle(),
-                                                 &requires_sync_point);
+                                                 &requires_sync_token);
+
+  uint64_t image_fence_sync = 0;
+  if (requires_sync_token) {
+    image_fence_sync = GenerateFenceSyncRelease();
+
+    // Make sure fence syncs were flushed before CreateImage() was called.
+    DCHECK_LE(image_fence_sync - 1, flushed_fence_sync_release_);
+  }
 
   DCHECK(gpu::ImageFactory::IsGpuMemoryBufferFormatSupported(
       gpu_memory_buffer->GetFormat(), capabilities_));
   DCHECK(gpu::ImageFactory::IsImageSizeValidForGpuMemoryBufferFormat(
       gfx::Size(width, height), gpu_memory_buffer->GetFormat()));
   DCHECK(gpu::ImageFactory::IsImageFormatCompatibleWithGpuMemoryBufferFormat(
-      internalformat, gpu_memory_buffer->GetFormat()));
-  if (!Send(new GpuCommandBufferMsg_CreateImage(route_id_,
-                                                new_id,
-                                                handle,
-                                                gfx::Size(width, height),
-                                                gpu_memory_buffer->GetFormat(),
-                                                internalformat))) {
-    return -1;
-  }
+      internal_format, gpu_memory_buffer->GetFormat()));
 
-  if (requires_sync_point) {
-    gpu_memory_buffer_manager->SetDestructionSyncPoint(gpu_memory_buffer,
-                                                       InsertSyncPoint());
+  GpuCommandBufferMsg_CreateImage_Params params;
+  params.id = new_id;
+  params.gpu_memory_buffer = handle;
+  params.size = gfx::Size(width, height);
+  params.format = gpu_memory_buffer->GetFormat();
+  params.internal_format = internal_format;
+  params.image_release_count = image_fence_sync;
+
+  if (!Send(new GpuCommandBufferMsg_CreateImage(route_id_, params)))
+    return -1;
+
+  if (image_fence_sync) {
+    gpu::SyncToken sync_token(GetNamespaceID(), GetCommandBufferID(),
+                              image_fence_sync);
+
+    // Force a synchronous IPC to validate sync token.
+    channel_->ValidateFlushIDReachedServer(stream_id_, true);
+    sync_token.SetVerifyFlush();
+
+    gpu_memory_buffer_manager->SetDestructionSyncToken(gpu_memory_buffer,
+                                                       sync_token);
   }
 
   return new_id;
@@ -455,18 +473,18 @@
 int32_t CommandBufferProxyImpl::CreateGpuMemoryBufferImage(
     size_t width,
     size_t height,
-    unsigned internalformat,
+    unsigned internal_format,
     unsigned usage) {
   CheckLock();
   scoped_ptr<gfx::GpuMemoryBuffer> buffer(
       channel_->gpu_memory_buffer_manager()->AllocateGpuMemoryBuffer(
           gfx::Size(width, height),
-          gpu::ImageFactory::DefaultBufferFormatForImageFormat(internalformat),
+          gpu::ImageFactory::DefaultBufferFormatForImageFormat(internal_format),
           gfx::BufferUsage::SCANOUT));
   if (!buffer)
     return -1;
 
-  return CreateImage(buffer->AsClientBuffer(), width, height, internalformat);
+  return CreateImage(buffer->AsClientBuffer(), width, height, internal_format);
 }
 
 uint32 CommandBufferProxyImpl::CreateStreamTexture(uint32 texture_id) {
@@ -530,7 +548,8 @@
       return true;
 
     // Has not been validated, validate it now.
-    UpdateVerifiedReleases(channel_->ValidateFlushIDReachedServer(stream_id_));
+    UpdateVerifiedReleases(
+        channel_->ValidateFlushIDReachedServer(stream_id_, false));
     return release <= verified_fence_sync_release_;
   }
 
diff --git a/content/common/gpu/client/command_buffer_proxy_impl.h b/content/common/gpu/client/command_buffer_proxy_impl.h
index 39bc76b..5646cca 100644
--- a/content/common/gpu/client/command_buffer_proxy_impl.h
+++ b/content/common/gpu/client/command_buffer_proxy_impl.h
@@ -106,11 +106,11 @@
   int32 CreateImage(ClientBuffer buffer,
                     size_t width,
                     size_t height,
-                    unsigned internalformat) override;
+                    unsigned internal_format) override;
   void DestroyImage(int32 id) override;
   int32 CreateGpuMemoryBufferImage(size_t width,
                                    size_t height,
-                                   unsigned internalformat,
+                                   unsigned internal_format,
                                    unsigned usage) override;
   uint32 InsertSyncPoint() override;
   uint32_t InsertFutureSyncPoint() override;
diff --git a/content/common/gpu/client/gl_helper.cc b/content/common/gpu/client/gl_helper.cc
index 88c64994..33c9521c 100644
--- a/content/common/gpu/client/gl_helper.cc
+++ b/content/common/gpu/client/gl_helper.cc
@@ -954,6 +954,12 @@
 
 uint32 GLHelper::InsertSyncPoint() { return gl_->InsertSyncPointCHROMIUM(); }
 
+void GLHelper::GenerateSyncToken(gpu::SyncToken* sync_token) {
+  const uint64_t fence_sync = gl_->InsertFenceSyncCHROMIUM();
+  gl_->ShallowFlushCHROMIUM();
+  gl_->GenSyncTokenCHROMIUM(fence_sync, sync_token->GetData());
+}
+
 void GLHelper::WaitSyncToken(const gpu::SyncToken& sync_token) {
   gl_->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
 }
diff --git a/content/common/gpu/client/gl_helper.h b/content/common/gpu/client/gl_helper.h
index 828097d6..c8224d4 100644
--- a/content/common/gpu/client/gl_helper.h
+++ b/content/common/gpu/client/gl_helper.h
@@ -247,6 +247,9 @@
   // Insert a sync point into the GL command buffer.
   uint32 InsertSyncPoint();
 
+  // Inserts a fence sync, flushes, and generates a sync token.
+  void GenerateSyncToken(gpu::SyncToken* sync_token);
+
   // Wait for the sync token before executing further GL commands.
   void WaitSyncToken(const gpu::SyncToken& sync_token);
 
diff --git a/content/common/gpu/client/gpu_channel_host.cc b/content/common/gpu/client/gpu_channel_host.cc
index 30700df..8ff3ab854 100644
--- a/content/common/gpu/client/gpu_channel_host.cc
+++ b/content/common/gpu/client/gpu_channel_host.cc
@@ -398,7 +398,8 @@
   return next_stream_id_.GetNext();
 }
 
-uint32_t GpuChannelHost::ValidateFlushIDReachedServer(int32 stream_id) {
+uint32_t GpuChannelHost::ValidateFlushIDReachedServer(int32 stream_id,
+                                                      bool force_validate) {
   // Store what flush ids we will be validating for all streams.
   base::hash_map<int32, uint32_t> validate_flushes;
   uint32_t flushed_stream_flush_id = 0;
@@ -421,7 +422,7 @@
     }
   }
 
-  if (flushed_stream_flush_id == verified_stream_flush_id) {
+  if (!force_validate && flushed_stream_flush_id == verified_stream_flush_id) {
     // Current stream has no unverified flushes.
     return verified_stream_flush_id;
   }
diff --git a/content/common/gpu/client/gpu_channel_host.h b/content/common/gpu/client/gpu_channel_host.h
index a161a78..b5488ed9 100644
--- a/content/common/gpu/client/gpu_channel_host.h
+++ b/content/common/gpu/client/gpu_channel_host.h
@@ -190,7 +190,7 @@
   // If the validation fails (which can only happen upon context lost), the
   // highest validated flush id will not change. If no flush ID were ever
   // validated then it will return 0 (Note the lowest valid flush ID is 1).
-  uint32_t ValidateFlushIDReachedServer(int32 stream_id);
+  uint32_t ValidateFlushIDReachedServer(int32 stream_id, bool force_validate);
 
   // Returns the highest validated flush ID for a given stream.
   uint32_t GetHighestValidatedFlushID(int32 stream_id);
diff --git a/content/common/gpu/client/gpu_memory_buffer_impl.cc b/content/common/gpu/client/gpu_memory_buffer_impl.cc
index bfe4656..e900829f 100644
--- a/content/common/gpu/client/gpu_memory_buffer_impl.cc
+++ b/content/common/gpu/client/gpu_memory_buffer_impl.cc
@@ -29,12 +29,11 @@
       size_(size),
       format_(format),
       callback_(callback),
-      mapped_(false),
-      destruction_sync_point_(0) {}
+      mapped_(false) {}
 
 GpuMemoryBufferImpl::~GpuMemoryBufferImpl() {
   DCHECK(!mapped_);
-  callback_.Run(destruction_sync_point_);
+  callback_.Run(destruction_sync_token_);
 }
 
 // static
diff --git a/content/common/gpu/client/gpu_memory_buffer_impl.h b/content/common/gpu/client/gpu_memory_buffer_impl.h
index 44b528e8..a3ba3f5 100644
--- a/content/common/gpu/client/gpu_memory_buffer_impl.h
+++ b/content/common/gpu/client/gpu_memory_buffer_impl.h
@@ -8,6 +8,7 @@
 #include "base/callback.h"
 #include "base/memory/scoped_ptr.h"
 #include "content/common/content_export.h"
+#include "gpu/command_buffer/common/sync_token.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/gpu_memory_buffer.h"
 
@@ -16,7 +17,7 @@
 // Provides common implementation of a GPU memory buffer.
 class CONTENT_EXPORT GpuMemoryBufferImpl : public gfx::GpuMemoryBuffer {
  public:
-  typedef base::Callback<void(uint32 sync_point)> DestructionCallback;
+  typedef base::Callback<void(const gpu::SyncToken& sync)> DestructionCallback;
 
   ~GpuMemoryBufferImpl() override;
 
@@ -40,8 +41,8 @@
   gfx::GpuMemoryBufferId GetId() const override;
   ClientBuffer AsClientBuffer() override;
 
-  void set_destruction_sync_point(uint32 sync_point) {
-    destruction_sync_point_ = sync_point;
+  void set_destruction_sync_token(const gpu::SyncToken& sync_token) {
+    destruction_sync_token_ = sync_token;
   }
 
  protected:
@@ -55,7 +56,7 @@
   const gfx::BufferFormat format_;
   const DestructionCallback callback_;
   bool mapped_;
-  uint32 destruction_sync_point_;
+  gpu::SyncToken destruction_sync_token_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferImpl);
diff --git a/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory_unittest.cc b/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory_unittest.cc
index cce258b..251e16c 100644
--- a/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory_unittest.cc
+++ b/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory_unittest.cc
@@ -12,7 +12,7 @@
                               GpuMemoryBufferImplTest,
                               GpuMemoryBufferImplSharedMemory);
 
-void BufferDestroyed(bool* destroyed, uint32 sync_point) {
+void BufferDestroyed(bool* destroyed, const gpu::SyncToken& sync_token) {
   *destroyed = true;
 }
 
diff --git a/content/common/gpu/gpu_channel_manager.cc b/content/common/gpu/gpu_channel_manager.cc
index 4d9c4351..3f603a6 100644
--- a/content/common/gpu/gpu_channel_manager.cc
+++ b/content/common/gpu/gpu_channel_manager.cc
@@ -60,6 +60,7 @@
           this,
           GpuMemoryManager::kDefaultMaxSurfacesWithFrontbufferSoftLimit),
       sync_point_manager_(sync_point_manager),
+      sync_point_client_waiter_(new gpu::SyncPointClientWaiter),
       gpu_memory_buffer_factory_(gpu_memory_buffer_factory),
       weak_factory_(this) {
   DCHECK(task_runner);
@@ -227,17 +228,22 @@
 void GpuChannelManager::OnDestroyGpuMemoryBuffer(
     gfx::GpuMemoryBufferId id,
     int client_id,
-    int32 sync_point) {
-  if (!sync_point) {
-    DestroyGpuMemoryBuffer(id, client_id);
-  } else {
-    sync_point_manager()->AddSyncPointCallback(
-        sync_point,
-        base::Bind(&GpuChannelManager::DestroyGpuMemoryBuffer,
-                   base::Unretained(this),
-                   id,
-                   client_id));
+    const gpu::SyncToken& sync_token) {
+  if (sync_token.HasData()) {
+    scoped_refptr<gpu::SyncPointClientState> release_state =
+        sync_point_manager()->GetSyncPointClientState(
+            sync_token.namespace_id(), sync_token.command_buffer_id());
+    if (release_state) {
+      sync_point_client_waiter_->Wait(
+          release_state.get(), sync_token.release_count(),
+          base::Bind(&GpuChannelManager::DestroyGpuMemoryBuffer,
+                     base::Unretained(this), id, client_id));
+      return;
+    }
   }
+
+  // No sync token or invalid sync token, destroy immediately.
+  DestroyGpuMemoryBuffer(id, client_id);
 }
 
 void GpuChannelManager::OnUpdateValueState(
diff --git a/content/common/gpu/gpu_channel_manager.h b/content/common/gpu/gpu_channel_manager.h
index 19cec9d..c3e889a 100644
--- a/content/common/gpu/gpu_channel_manager.h
+++ b/content/common/gpu/gpu_channel_manager.h
@@ -34,7 +34,9 @@
 
 namespace gpu {
 class PreemptionFlag;
+class SyncPointClientWaiter;
 class SyncPointManager;
+struct SyncToken;
 union ValueState;
 namespace gles2 {
 class FramebufferCompletenessCache;
@@ -156,7 +158,7 @@
   void DestroyGpuMemoryBufferOnIO(gfx::GpuMemoryBufferId id, int client_id);
   void OnDestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
                                 int client_id,
-                                int32 sync_point);
+                                const gpu::SyncToken& sync_token);
 
   void OnUpdateValueState(int client_id,
                           unsigned int target,
@@ -182,6 +184,7 @@
   GpuMemoryManager gpu_memory_manager_;
   // SyncPointManager guaranteed to outlive running MessageLoop.
   gpu::SyncPointManager* sync_point_manager_;
+  scoped_ptr<gpu::SyncPointClientWaiter> sync_point_client_waiter_;
   scoped_ptr<gpu::gles2::ProgramCache> program_cache_;
   scoped_refptr<gpu::gles2::ShaderTranslatorCache> shader_translator_cache_;
   scoped_refptr<gpu::gles2::FramebufferCompletenessCache>
diff --git a/content/common/gpu/gpu_command_buffer_stub.cc b/content/common/gpu/gpu_command_buffer_stub.cc
index b82d715..a26854f 100644
--- a/content/common/gpu/gpu_command_buffer_stub.cc
+++ b/content/common/gpu/gpu_command_buffer_stub.cc
@@ -1107,12 +1107,15 @@
   scheduler_->SetScheduled(true);
 }
 
-void GpuCommandBufferStub::OnCreateImage(int32 id,
-                                         gfx::GpuMemoryBufferHandle handle,
-                                         gfx::Size size,
-                                         gfx::BufferFormat format,
-                                         uint32 internalformat) {
+void GpuCommandBufferStub::OnCreateImage(
+    const GpuCommandBufferMsg_CreateImage_Params& params) {
   TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnCreateImage");
+  const int32_t id = params.id;
+  const gfx::GpuMemoryBufferHandle& handle = params.gpu_memory_buffer;
+  const gfx::Size& size = params.size;
+  const gfx::BufferFormat& format = params.format;
+  const uint32_t internalformat = params.internal_format;
+  const uint64_t image_release_count = params.image_release_count;
 
   if (!decoder_)
     return;
@@ -1148,6 +1151,9 @@
     return;
 
   image_manager->AddImage(image.get(), id);
+  if (image_release_count) {
+    sync_point_client_->ReleaseFenceSync(image_release_count);
+  }
 }
 
 void GpuCommandBufferStub::OnDestroyImage(int32 id) {
diff --git a/content/common/gpu/gpu_command_buffer_stub.h b/content/common/gpu/gpu_command_buffer_stub.h
index 910cd91..0537c30 100644
--- a/content/common/gpu/gpu_command_buffer_stub.h
+++ b/content/common/gpu/gpu_command_buffer_stub.h
@@ -44,6 +44,8 @@
 }
 }
 
+struct GpuCommandBufferMsg_CreateImage_Params;
+
 namespace content {
 
 class GpuChannel;
@@ -214,11 +216,7 @@
                                 uint64_t command_buffer_id,
                                 uint64_t release);
 
-  void OnCreateImage(int32 id,
-                     gfx::GpuMemoryBufferHandle handle,
-                     gfx::Size size,
-                     gfx::BufferFormat format,
-                     uint32 internalformat);
+  void OnCreateImage(const GpuCommandBufferMsg_CreateImage_Params& params);
   void OnDestroyImage(int32 id);
   void OnCreateStreamTexture(uint32 texture_id,
                              int32 stream_id,
diff --git a/content/common/gpu/gpu_messages.h b/content/common/gpu/gpu_messages.h
index 949ecf9..a9c84a4 100644
--- a/content/common/gpu/gpu_messages.h
+++ b/content/common/gpu/gpu_messages.h
@@ -184,7 +184,16 @@
 IPC_STRUCT_END()
 #endif
 
-  IPC_STRUCT_TRAITS_BEGIN(gpu::DxDiagNode)
+IPC_STRUCT_BEGIN(GpuCommandBufferMsg_CreateImage_Params)
+  IPC_STRUCT_MEMBER(int32, id)
+  IPC_STRUCT_MEMBER(gfx::GpuMemoryBufferHandle, gpu_memory_buffer)
+  IPC_STRUCT_MEMBER(gfx::Size, size)
+  IPC_STRUCT_MEMBER(gfx::BufferFormat, format)
+  IPC_STRUCT_MEMBER(uint32, internal_format)
+  IPC_STRUCT_MEMBER(uint64, image_release_count)
+IPC_STRUCT_END()
+
+IPC_STRUCT_TRAITS_BEGIN(gpu::DxDiagNode)
   IPC_STRUCT_TRAITS_MEMBER(values)
   IPC_STRUCT_TRAITS_MEMBER(children)
 IPC_STRUCT_TRAITS_END()
@@ -331,8 +340,8 @@
 // Tells the GPU process to destroy buffer.
 IPC_MESSAGE_CONTROL3(GpuMsg_DestroyGpuMemoryBuffer,
                      gfx::GpuMemoryBufferId, /* id */
-                     int32, /* client_id */
-                     int32 /* sync_point */)
+                     int32,                  /* client_id */
+                     gpu::SyncToken /* sync_token */)
 
 // Create and initialize a hardware jpeg decoder using the specified route_id.
 // Created decoders should be freed with AcceleratedJpegDecoderMsg_Destroy when
@@ -652,12 +661,8 @@
 
 // Create an image from an existing gpu memory buffer. The id that can be
 // used to identify the image from a command buffer.
-IPC_MESSAGE_ROUTED5(GpuCommandBufferMsg_CreateImage,
-                    int32 /* id */,
-                    gfx::GpuMemoryBufferHandle /* gpu_memory_buffer */,
-                    gfx::Size /* size */,
-                    gfx::BufferFormat /* format */,
-                    uint32 /* internalformat */)
+IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_CreateImage,
+                    GpuCommandBufferMsg_CreateImage_Params /* params */)
 
 // Destroy a previously created image.
 IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_DestroyImage,
diff --git a/content/common/gpu/media/dxva_video_decode_accelerator.cc b/content/common/gpu/media/dxva_video_decode_accelerator.cc
index 1c999e31..33ac9a7 100644
--- a/content/common/gpu/media/dxva_video_decode_accelerator.cc
+++ b/content/common/gpu/media/dxva_video_decode_accelerator.cc
@@ -739,7 +739,7 @@
     present_params.BackBufferFormat = D3DFMT_UNKNOWN;
     present_params.BackBufferCount = 1;
     present_params.SwapEffect = D3DSWAPEFFECT_DISCARD;
-    present_params.hDeviceWindow = ::GetShellWindow();
+    present_params.hDeviceWindow = NULL;
     present_params.Windowed = TRUE;
     present_params.Flags = D3DPRESENTFLAG_VIDEO;
     present_params.FullScreen_RefreshRateInHz = 0;
@@ -747,7 +747,7 @@
 
     hr = d3d9_->CreateDeviceEx(D3DADAPTER_DEFAULT,
                                D3DDEVTYPE_HAL,
-                               ::GetShellWindow(),
+                               NULL,
                                D3DCREATE_FPU_PRESERVE |
                                D3DCREATE_HARDWARE_VERTEXPROCESSING |
                                D3DCREATE_DISABLE_PSGP_THREADING |
diff --git a/content/common/gpu/media/vaapi_jpeg_decode_accelerator.cc b/content/common/gpu/media/vaapi_jpeg_decode_accelerator.cc
index 9a5f394e..11ff91a9 100644
--- a/content/common/gpu/media/vaapi_jpeg_decode_accelerator.cc
+++ b/content/common/gpu/media/vaapi_jpeg_decode_accelerator.cc
@@ -21,7 +21,8 @@
 // UMA errors that the VaapiJpegDecodeAccelerator class reports.
 enum VAJDADecoderFailure {
   VAAPI_ERROR = 0,
-  VAJDA_DECODER_FAILURES_MAX,
+  // UMA requires that max must be greater than 1.
+  VAJDA_DECODER_FAILURES_MAX = 2,
 };
 
 static void ReportToUMA(VAJDADecoderFailure failure) {
diff --git a/content/common/gpu/media/vaapi_video_decode_accelerator.cc b/content/common/gpu/media/vaapi_video_decode_accelerator.cc
index d5b70aa..704f7f2 100644
--- a/content/common/gpu/media/vaapi_video_decode_accelerator.cc
+++ b/content/common/gpu/media/vaapi_video_decode_accelerator.cc
@@ -29,7 +29,8 @@
 // UMA errors that the VaapiVideoDecodeAccelerator class reports.
 enum VAVDADecoderFailure {
   VAAPI_ERROR = 0,
-  VAVDA_DECODER_FAILURES_MAX,
+  // UMA requires that max must be greater than 1.
+  VAVDA_DECODER_FAILURES_MAX = 2,
 };
 }
 
diff --git a/content/common/gpu/media/vaapi_video_encode_accelerator.cc b/content/common/gpu/media/vaapi_video_encode_accelerator.cc
index 1f9388e..9c078b2 100644
--- a/content/common/gpu/media/vaapi_video_encode_accelerator.cc
+++ b/content/common/gpu/media/vaapi_video_encode_accelerator.cc
@@ -67,7 +67,8 @@
 // UMA errors that the VaapiVideoEncodeAccelerator class reports.
 enum VAVEAEncoderFailure {
   VAAPI_ERROR = 0,
-  VAVEA_ENCODER_FAILURES_MAX,
+  // UMA requires that max must be greater than 1.
+  VAVEA_ENCODER_FAILURES_MAX = 2,
 };
 
 }
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index 6969d21..3ee12f48 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -821,7 +821,6 @@
       'browser/geolocation/network_location_provider.h',
       'browser/geolocation/network_location_request.cc',
       'browser/geolocation/network_location_request.h',
-      'browser/geolocation/osx_wifi.h',
       'browser/geolocation/wifi_data.cc',
       'browser/geolocation/wifi_data.h',
       'browser/geolocation/wifi_data_provider.cc',
diff --git a/content/public/android/javatests/src/org/chromium/content/common/CleanupReferenceTest.java b/content/public/android/javatests/src/org/chromium/content/common/CleanupReferenceTest.java
index dc61afc0..602d2f6 100644
--- a/content/public/android/javatests/src/org/chromium/content/common/CleanupReferenceTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/common/CleanupReferenceTest.java
@@ -91,6 +91,9 @@
         instances = null;
         // Ensure compiler / instrumentation does not strip out the assignment.
         assertTrue(instances == null);
+        // Calling sObjectCount.get() before collectGarbage() seems to be required for the objects
+        // to be GC'ed only when building using GN.
+        assertTrue(sObjectCount.get() != -1);
         collectGarbage();
         assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
diff --git a/content/public/browser/background_sync_controller.h b/content/public/browser/background_sync_controller.h
index fccaf4443..72ebef1 100644
--- a/content/public/browser/background_sync_controller.h
+++ b/content/public/browser/background_sync_controller.h
@@ -22,14 +22,14 @@
   // registered a background sync event.
   virtual void NotifyBackgroundSyncRegistered(const GURL& origin) {}
 
-  // Register the |registrant|'s interest (or disinterest) in starting the
-  // browser the next time the device goes online after the browser has closed.
-  // This only needs to be implemented by browsers; WebView and other embedders
-  // which should not have their application relaunched by Background Sync can
-  // use the default implentation.
-  virtual void LaunchBrowserWhenNextOnline(
-      const BackgroundSyncManager* registrant,
-      bool launch_when_next_online) {}
+  // If |enabled|, ensures that the browser is running when the device next goes
+  // online. The behavior is platform dependent:
+  // * Android: Registers a GCM task which verifies that the browser is running
+  // the next time the device goes online. If it's not, it starts it.
+  //
+  // * Other Platforms: (UNIMPLEMENTED) Keeps the browser alive via
+  // BackgroundModeManager until called with |enabled| = false.
+  virtual void RunInBackground(bool enabled) {}
 };
 
 }  // namespace content
diff --git a/content/public/common/page_state.cc b/content/public/common/page_state.cc
index 6174a845..9d100d3 100644
--- a/content/public/common/page_state.cc
+++ b/content/public/common/page_state.cc
@@ -5,7 +5,6 @@
 #include "content/public/common/page_state.h"
 
 #include "base/files/file_path.h"
-#include "base/logging.h"
 #include "base/strings/utf_string_conversions.h"
 #include "content/common/page_state_serialization.h"
 
@@ -120,15 +119,6 @@
   return data_;
 }
 
-std::string PageState::GetTopLevelUrlStringTemporaryForBug369661() const {
-  ExplodedPageState state;
-  CHECK(DecodePageState(data_, &state));
-
-  base::NullableString16& url_string = state.top.url_string;
-  CHECK(!url_string.is_null());
-  return base::UTF16ToUTF8(url_string.string());
-}
-
 std::vector<base::FilePath> PageState::GetReferencedFiles() const {
   std::vector<base::FilePath> results;
 
diff --git a/content/public/common/page_state.h b/content/public/common/page_state.h
index 78782a2..c38f961 100644
--- a/content/public/common/page_state.h
+++ b/content/public/common/page_state.h
@@ -40,7 +40,6 @@
   bool IsValid() const;
   bool Equals(const PageState& page_state) const;
   const std::string& ToEncodedData() const;
-  std::string GetTopLevelUrlStringTemporaryForBug369661() const;
 
   std::vector<base::FilePath> GetReferencedFiles() const;
   PageState RemovePasswordData() const;
diff --git a/content/public/test/test_browser_context.cc b/content/public/test/test_browser_context.cc
index dd038b6..c1c139ce 100644
--- a/content/public/test/test_browser_context.cc
+++ b/content/public/test/test_browser_context.cc
@@ -6,6 +6,7 @@
 
 #include "base/files/file_path.h"
 #include "base/test/null_task_runner.h"
+#include "content/public/browser/background_sync_controller.h"
 #include "content/public/test/mock_resource_context.h"
 #include "content/test/mock_ssl_host_state_delegate.h"
 #include "net/url_request/url_request_context.h"
@@ -56,6 +57,11 @@
   special_storage_policy_ = policy;
 }
 
+void TestBrowserContext::SetBackgroundSyncController(
+    scoped_ptr<BackgroundSyncController> controller) {
+  background_sync_controller_ = controller.Pass();
+}
+
 base::FilePath TestBrowserContext::GetPath() const {
   return browser_context_dir_.path();
 }
@@ -135,7 +141,7 @@
 }
 
 BackgroundSyncController* TestBrowserContext::GetBackgroundSyncController() {
-  return nullptr;
+  return background_sync_controller_.get();
 }
 
 }  // namespace content
diff --git a/content/public/test/test_browser_context.h b/content/public/test/test_browser_context.h
index cb50825..55501644 100644
--- a/content/public/test/test_browser_context.h
+++ b/content/public/test/test_browser_context.h
@@ -27,6 +27,8 @@
   base::FilePath TakePath();
 
   void SetSpecialStoragePolicy(storage::SpecialStoragePolicy* policy);
+  void SetBackgroundSyncController(
+      scoped_ptr<BackgroundSyncController> controller);
 
   base::FilePath GetPath() const override;
   scoped_ptr<ZoomLevelDelegate> CreateZoomLevelDelegate(
@@ -56,6 +58,7 @@
   scoped_ptr<MockResourceContext> resource_context_;
   scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy_;
   scoped_ptr<MockSSLHostStateDelegate> ssl_host_state_delegate_;
+  scoped_ptr<BackgroundSyncController> background_sync_controller_;
 
   DISALLOW_COPY_AND_ASSIGN(TestBrowserContext);
 };
diff --git a/content/renderer/media/android/webmediaplayer_android.cc b/content/renderer/media/android/webmediaplayer_android.cc
index e732515..ceecc08 100644
--- a/content/renderer/media/android/webmediaplayer_android.cc
+++ b/content/renderer/media/android/webmediaplayer_android.cc
@@ -136,11 +136,10 @@
       blink::WebGraphicsContext3D* web_graphics_context)
       : web_graphics_context_(web_graphics_context) {}
   ~SyncTokenClientImpl() override {}
-  uint32 InsertSyncPoint() override {
-    gpu::SyncToken sync_token;
-    if (!web_graphics_context_->insertSyncPoint(sync_token.GetData()))
-      return 0;
-    return static_cast<uint32>(sync_token.release_count());
+  void GenerateSyncToken(gpu::SyncToken* sync_token) override {
+    if (!web_graphics_context_->insertSyncPoint(sync_token->GetData())) {
+      sync_token->Clear();
+    }
   }
   void WaitSyncToken(const gpu::SyncToken& sync_token) override {
     web_graphics_context_->waitSyncToken(sync_token.GetConstData());
diff --git a/content/renderer/media/video_capture_impl.cc b/content/renderer/media/video_capture_impl.cc
index 8d09c20..1e99fd8 100644
--- a/content/renderer/media/video_capture_impl.cc
+++ b/content/renderer/media/video_capture_impl.cc
@@ -100,7 +100,7 @@
       buffer->Unmap();
   }
 
-  void DestroyGpuMemoryBuffer(uint32 sync_point) {}
+  void DestroyGpuMemoryBuffer(const gpu::SyncToken& sync_token) {}
 
   const std::vector<gfx::GpuMemoryBufferHandle> handles_;
   const gfx::Size size_;
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index 7e75ee9..1fa92f3d 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -233,8 +233,7 @@
 RendererBlinkPlatformImpl::RendererBlinkPlatformImpl(
     scheduler::RendererScheduler* renderer_scheduler)
     : BlinkPlatformImpl(renderer_scheduler->DefaultTaskRunner()),
-      main_thread_(
-          new scheduler::WebThreadImplForRendererScheduler(renderer_scheduler)),
+      main_thread_(renderer_scheduler->CreateMainThread()),
       clipboard_delegate_(new RendererClipboardDelegate),
       clipboard_(new WebClipboardImpl(clipboard_delegate_.get())),
       mime_registry_(new RendererBlinkPlatformImpl::MimeRegistry),
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h
index d9279741..247b97ce 100644
--- a/content/renderer/renderer_blink_platform_impl.h
+++ b/content/renderer/renderer_blink_platform_impl.h
@@ -223,7 +223,7 @@
   void SendFakeDeviceEventDataForTesting(blink::WebPlatformEventType type);
   device::VibrationManagerPtr& GetConnectedVibrationManagerService();
 
-  scoped_ptr<scheduler::WebThreadImplForRendererScheduler> main_thread_;
+  scoped_ptr<blink::WebThread> main_thread_;
 
   scoped_ptr<RendererClipboardDelegate> clipboard_delegate_;
   scoped_ptr<WebClipboardImpl> clipboard_;
diff --git a/content/test/fake_renderer_scheduler.cc b/content/test/fake_renderer_scheduler.cc
index f0ae6c7..a12f257 100644
--- a/content/test/fake_renderer_scheduler.cc
+++ b/content/test/fake_renderer_scheduler.cc
@@ -4,6 +4,8 @@
 
 #include "content/test/fake_renderer_scheduler.h"
 
+#include "third_party/WebKit/public/platform/WebThread.h"
+
 namespace content {
 
 FakeRendererScheduler::FakeRendererScheduler() {
@@ -12,6 +14,10 @@
 FakeRendererScheduler::~FakeRendererScheduler() {
 }
 
+scoped_ptr<blink::WebThread> FakeRendererScheduler::CreateMainThread() {
+  return nullptr;
+}
+
 scoped_refptr<scheduler::TaskQueue> FakeRendererScheduler::DefaultTaskRunner() {
   return nullptr;
 }
diff --git a/content/test/fake_renderer_scheduler.h b/content/test/fake_renderer_scheduler.h
index 4367f3f1..73d8c1a8 100644
--- a/content/test/fake_renderer_scheduler.h
+++ b/content/test/fake_renderer_scheduler.h
@@ -15,6 +15,7 @@
   ~FakeRendererScheduler() override;
 
   // RendererScheduler implementation.
+  scoped_ptr<blink::WebThread> CreateMainThread() override;
   scoped_refptr<scheduler::TaskQueue> DefaultTaskRunner() override;
   scoped_refptr<base::SingleThreadTaskRunner> CompositorTaskRunner() override;
   scoped_refptr<base::SingleThreadTaskRunner> LoadingTaskRunner() override;
diff --git a/content/test/gpu_memory_buffer_impl_test_template.h b/content/test/gpu_memory_buffer_impl_test_template.h
index a91589f..73cce9e9 100644
--- a/content/test/gpu_memory_buffer_impl_test_template.h
+++ b/content/test/gpu_memory_buffer_impl_test_template.h
@@ -32,7 +32,7 @@
  private:
   void FreeGpuMemoryBuffer(const base::Closure& free_callback,
                            bool* destroyed,
-                           uint32 sync_point) {
+                           const gpu::SyncToken& sync_token) {
     free_callback.Run();
     if (destroyed)
       *destroyed = true;
diff --git a/content/test/net/url_request_abort_on_end_job.cc b/content/test/net/url_request_abort_on_end_job.cc
index f7ff5a9..6d237a8 100644
--- a/content/test/net/url_request_abort_on_end_job.cc
+++ b/content/test/net/url_request_abort_on_end_job.cc
@@ -8,6 +8,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/location.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/thread_task_runner_handle.h"
@@ -111,20 +112,16 @@
                             weak_factory_.GetWeakPtr()));
 }
 
-bool URLRequestAbortOnEndJob::ReadRawData(net::IOBuffer* buf,
-                                          const int max_bytes,
-                                          int* bytes_read) {
+int URLRequestAbortOnEndJob::ReadRawData(net::IOBuffer* buf, int max_bytes) {
   if (!sent_data_) {
-    *bytes_read = std::min(size_t(max_bytes), sizeof(kPageContent));
-    std::memcpy(buf->data(), kPageContent, *bytes_read);
+    max_bytes =
+        std::min(max_bytes, base::checked_cast<int>(sizeof(kPageContent)));
+    std::memcpy(buf->data(), kPageContent, max_bytes);
     sent_data_ = true;
-    return true;
+    return max_bytes;
   }
 
-  SetStatus(net::URLRequestStatus(net::URLRequestStatus::FAILED,
-                                  net::ERR_CONNECTION_ABORTED));
-  *bytes_read = -1;
-  return false;
+  return net::ERR_CONNECTION_ABORTED;
 }
 
 }  // namespace content
diff --git a/content/test/net/url_request_abort_on_end_job.h b/content/test/net/url_request_abort_on_end_job.h
index 88e348c..8a95533 100644
--- a/content/test/net/url_request_abort_on_end_job.h
+++ b/content/test/net/url_request_abort_on_end_job.h
@@ -29,7 +29,7 @@
   void Start() override;
   bool GetMimeType(std::string* mime_type) const override;
   void GetResponseInfo(net::HttpResponseInfo* info) override;
-  bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override;
+  int ReadRawData(net::IOBuffer* buf, int buf_size) override;
 
   static void AddUrlHandler();
 
diff --git a/content/test/test_blink_web_unit_test_support.cc b/content/test/test_blink_web_unit_test_support.cc
index d6e2b90..6f060587 100644
--- a/content/test/test_blink_web_unit_test_support.cc
+++ b/content/test/test_blink_web_unit_test_support.cc
@@ -110,8 +110,7 @@
   }
   renderer_scheduler_ = make_scoped_ptr(new scheduler::RendererSchedulerImpl(
       scheduler::LazySchedulerMessageLoopDelegateForTests::Create()));
-  web_thread_.reset(new scheduler::WebThreadImplForRendererScheduler(
-      renderer_scheduler_.get()));
+  web_thread_ = renderer_scheduler_->CreateMainThread();
 
   blink::initialize(this);
   blink::setLayoutTestMode(true);
diff --git a/crypto/crypto_export.h b/crypto/crypto_export.h
index 983afe6..605af94 100644
--- a/crypto/crypto_export.h
+++ b/crypto/crypto_export.h
@@ -6,33 +6,27 @@
 #define CRYPTO_CRYPTO_EXPORT_H_
 
 // Defines CRYPTO_EXPORT so that functionality implemented by the crypto module
-// can be exported to consumers, and CRYPTO_EXPORT_PRIVATE that allows unit
-// tests to access features not intended to be used directly by real consumers.
+// can be exported to consumers.
 
 #if defined(COMPONENT_BUILD)
 #if defined(WIN32)
 
 #if defined(CRYPTO_IMPLEMENTATION)
 #define CRYPTO_EXPORT __declspec(dllexport)
-#define CRYPTO_EXPORT_PRIVATE __declspec(dllexport)
 #else
 #define CRYPTO_EXPORT __declspec(dllimport)
-#define CRYPTO_EXPORT_PRIVATE __declspec(dllimport)
 #endif  // defined(CRYPTO_IMPLEMENTATION)
 
 #else  // defined(WIN32)
 #if defined(CRYPTO_IMPLEMENTATION)
 #define CRYPTO_EXPORT __attribute__((visibility("default")))
-#define CRYPTO_EXPORT_PRIVATE __attribute__((visibility("default")))
 #else
 #define CRYPTO_EXPORT
-#define CRYPTO_EXPORT_PRIVATE
 #endif
 #endif
 
 #else  // defined(COMPONENT_BUILD)
 #define CRYPTO_EXPORT
-#define CRYPTO_EXPORT_PRIVATE
 #endif
 
 #endif  // CRYPTO_CRYPTO_EXPORT_H_
diff --git a/crypto/ghash.h b/crypto/ghash.h
index 6dc247be..53f6b51 100644
--- a/crypto/ghash.h
+++ b/crypto/ghash.h
@@ -25,7 +25,7 @@
 //
 // WARNING: this code is not constant time. However, in all likelihood, nor is
 // the implementation of AES that is used.
-class CRYPTO_EXPORT_PRIVATE GaloisHash {
+class CRYPTO_EXPORT GaloisHash {
  public:
   explicit GaloisHash(const uint8 key[16]);
 
diff --git a/crypto/nss_util_internal.h b/crypto/nss_util_internal.h
index f321343..17d61878 100644
--- a/crypto/nss_util_internal.h
+++ b/crypto/nss_util_internal.h
@@ -24,9 +24,8 @@
 // Opens an NSS software database in folder |path|, with the (potentially)
 // user-visible description |description|. Returns the slot for the opened
 // database, or NULL if the database could not be opened.
-CRYPTO_EXPORT_PRIVATE ScopedPK11Slot
-    OpenSoftwareNSSDB(const base::FilePath& path,
-                      const std::string& description);
+CRYPTO_EXPORT ScopedPK11Slot OpenSoftwareNSSDB(const base::FilePath& path,
+                                               const std::string& description);
 
 #if !defined(OS_CHROMEOS)
 // Returns a reference to the default NSS key slot for storing persistent data.
@@ -59,7 +58,7 @@
 // does not have to be called if the test system slot is set.
 // This must must not be called consecutively with a |slot| != NULL. If |slot|
 // is NULL, the test system slot is unset.
-CRYPTO_EXPORT_PRIVATE void SetSystemKeySlotForTesting(ScopedPK11Slot slot);
+CRYPTO_EXPORT void SetSystemKeySlotForTesting(ScopedPK11Slot slot);
 
 // Prepare per-user NSS slot mapping. It is safe to call this function multiple
 // times. Returns true if the user was added, or false if it already existed.
@@ -104,7 +103,7 @@
 
 // Closes the NSS DB for |username_hash| that was previously opened by the
 // *Initialize*ForChromeOSUser functions.
-CRYPTO_EXPORT_PRIVATE void CloseChromeOSUserForTesting(
+CRYPTO_EXPORT void CloseChromeOSUserForTesting(
     const std::string& username_hash);
 #endif  // defined(OS_CHROMEOS)
 
diff --git a/crypto/scoped_test_nss_chromeos_user.h b/crypto/scoped_test_nss_chromeos_user.h
index 1638517..9202b0f 100644
--- a/crypto/scoped_test_nss_chromeos_user.h
+++ b/crypto/scoped_test_nss_chromeos_user.h
@@ -16,7 +16,7 @@
 // Opens a persistent NSS software database in a temporary directory for the
 // user with |username_hash|. This database will be used for both the user's
 // public and private slot.
-class CRYPTO_EXPORT_PRIVATE ScopedTestNSSChromeOSUser {
+class CRYPTO_EXPORT ScopedTestNSSChromeOSUser {
  public:
   // Opens the software database and sets the public slot for the user. The
   // private slot will not be initialized until FinishInit() is called.
diff --git a/crypto/scoped_test_nss_db.h b/crypto/scoped_test_nss_db.h
index 88c2d55..a305b7f4 100644
--- a/crypto/scoped_test_nss_db.h
+++ b/crypto/scoped_test_nss_db.h
@@ -15,7 +15,7 @@
 // Opens a persistent NSS database in a temporary directory.
 // Prior NSS version 3.15.1, because of http://bugzil.la/875601 , the opened DB
 // will not be closed automatically.
-class CRYPTO_EXPORT_PRIVATE ScopedTestNSSDB {
+class CRYPTO_EXPORT ScopedTestNSSDB {
  public:
   ScopedTestNSSDB();
   ~ScopedTestNSSDB();
diff --git a/crypto/scoped_test_system_nss_key_slot.h b/crypto/scoped_test_system_nss_key_slot.h
index ac3b72c..99a269c 100644
--- a/crypto/scoped_test_system_nss_key_slot.h
+++ b/crypto/scoped_test_system_nss_key_slot.h
@@ -24,7 +24,7 @@
 // |InitializeTPMTokenAndSystemSlot|, which triggers the TPM initialization,
 // does not have to be called if this helper is used.
 // At most one instance of this helper must be used at a time.
-class CRYPTO_EXPORT_PRIVATE ScopedTestSystemNSSKeySlot {
+class CRYPTO_EXPORT ScopedTestSystemNSSKeySlot {
  public:
   explicit ScopedTestSystemNSSKeySlot();
   ~ScopedTestSystemNSSKeySlot();
diff --git a/device/bluetooth/test/bluetooth_test_android.h b/device/bluetooth/test/bluetooth_test_android.h
index 0c2b35696..d807e4c5 100644
--- a/device/bluetooth/test/bluetooth_test_android.h
+++ b/device/bluetooth/test/bluetooth_test_android.h
@@ -38,9 +38,9 @@
   void SimulateGattCharacteristic(BluetoothGattService* service,
                                   const std::string& uuid,
                                   int properties) override;
-  virtual void SimulateGattNotifySessionStarted(
+  void SimulateGattNotifySessionStarted(
       BluetoothGattCharacteristic* characteristic) override;
-  virtual void SimulateGattCharacteristicSetNotifyWillFailSynchronouslyOnce(
+  void SimulateGattCharacteristicSetNotifyWillFailSynchronouslyOnce(
       BluetoothGattCharacteristic* characteristic) override;
   void SimulateGattCharacteristicRead(
       BluetoothGattCharacteristic* characteristic,
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index f37b82a..9f65074 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -5522,6 +5522,10 @@
     return 0;
   }
 
+  // CreateImage creates a fence sync so we must flush first to ensure all
+  // previously created fence syncs are flushed first.
+  FlushHelper();
+
   int32_t image_id =
       gpu_control_->CreateImage(buffer, width, height, internalformat);
   if (image_id < 0) {
diff --git a/gpu/command_buffer/client/gpu_memory_buffer_manager.h b/gpu/command_buffer/client/gpu_memory_buffer_manager.h
index 9502b28..c95f841 100644
--- a/gpu/command_buffer/client/gpu_memory_buffer_manager.h
+++ b/gpu/command_buffer/client/gpu_memory_buffer_manager.h
@@ -12,6 +12,8 @@
 
 namespace gpu {
 
+struct SyncToken;
+
 class GPU_EXPORT GpuMemoryBufferManager {
  public:
   GpuMemoryBufferManager();
@@ -34,8 +36,8 @@
       ClientBuffer buffer) = 0;
 
   // Associates destruction sync point with |buffer|.
-  virtual void SetDestructionSyncPoint(gfx::GpuMemoryBuffer* buffer,
-                                       uint32 sync_point) = 0;
+  virtual void SetDestructionSyncToken(gfx::GpuMemoryBuffer* buffer,
+                                       const gpu::SyncToken& sync_token) = 0;
 
  protected:
   virtual ~GpuMemoryBufferManager();
diff --git a/gpu/command_buffer/common/capabilities.h b/gpu/command_buffer/common/capabilities.h
index 532c2df..5137928d 100644
--- a/gpu/command_buffer/common/capabilities.h
+++ b/gpu/command_buffer/common/capabilities.h
@@ -33,7 +33,7 @@
     int precision;
   };
 
-  struct PerStagePrecisions {
+  struct GPU_EXPORT PerStagePrecisions {
     PerStagePrecisions();
 
     ShaderPrecision low_int;
diff --git a/gpu/command_buffer/service/in_process_command_buffer.cc b/gpu/command_buffer/service/in_process_command_buffer.cc
index b3b1b12..5e1921a 100644
--- a/gpu/command_buffer/service/in_process_command_buffer.cc
+++ b/gpu/command_buffer/service/in_process_command_buffer.cc
@@ -65,6 +65,21 @@
   completion->Signal();
 }
 
+struct ScopedOrderNumberProcessor {
+  ScopedOrderNumberProcessor(SyncPointOrderData* order_data, uint32_t order_num)
+      : order_data_(order_data), order_num_(order_num) {
+    order_data_->BeginProcessingOrderNumber(order_num_);
+  }
+
+  ~ScopedOrderNumberProcessor() {
+    order_data_->FinishProcessingOrderNumber(order_num_);
+  }
+
+ private:
+  SyncPointOrderData* order_data_;
+  uint32_t order_num_;
+};
+
 struct GpuInProcessThreadHolder {
   GpuInProcessThreadHolder()
       : sync_point_manager(new SyncPointManager(false)),
@@ -497,22 +512,24 @@
   ScopedEvent handle_flush(&flush_event_);
   base::AutoLock lock(command_buffer_lock_);
 
-  sync_point_order_data_->BeginProcessingOrderNumber(order_num);
-  command_buffer_->Flush(put_offset);
   {
-    // Update state before signaling the flush event.
-    base::AutoLock lock(state_after_last_flush_lock_);
-    state_after_last_flush_ = command_buffer_->GetLastState();
-  }
-  DCHECK((!error::IsError(state_after_last_flush_.error) && !context_lost_) ||
-         (error::IsError(state_after_last_flush_.error) && context_lost_));
+    ScopedOrderNumberProcessor scoped_order_num(sync_point_order_data_.get(),
+                                                order_num);
+    command_buffer_->Flush(put_offset);
+    {
+      // Update state before signaling the flush event.
+      base::AutoLock lock(state_after_last_flush_lock_);
+      state_after_last_flush_ = command_buffer_->GetLastState();
+    }
+    DCHECK((!error::IsError(state_after_last_flush_.error) && !context_lost_) ||
+           (error::IsError(state_after_last_flush_.error) && context_lost_));
 
-  // Currently the in process command buffer does not support being descheduled,
-  // if it does we would need to back off on calling the finish processing
-  // order number function until the message is rescheduled and finished
-  // processing. This DCHECK is to enforce this.
-  DCHECK(context_lost_ || put_offset == state_after_last_flush_.get_offset);
-  sync_point_order_data_->FinishProcessingOrderNumber(order_num);
+    // Currently the in process command buffer does not support being
+    // descheduled, if it does we would need to back off on calling the finish
+    // processing number function until the message is rescheduled and finished
+    // processing. This DCHECK is to enforce this.
+    DCHECK(context_lost_ || put_offset == state_after_last_flush_.get_offset);
+  }
 
   // If we've processed all pending commands but still have pending queries,
   // pump idle work until the query is passed.
@@ -668,17 +685,29 @@
       ShareGpuMemoryBufferToGpuThread(gpu_memory_buffer->GetHandle(),
                                       &requires_sync_point);
 
-  QueueTask(base::Bind(&InProcessCommandBuffer::CreateImageOnGpuThread,
-                       base::Unretained(this),
-                       new_id,
-                       handle,
-                       gfx::Size(width, height),
-                       gpu_memory_buffer->GetFormat(),
-                       internalformat));
+  SyncPointManager* sync_manager = service_->sync_point_manager();
+  const uint32_t order_num =
+      sync_point_order_data_->GenerateUnprocessedOrderNumber(sync_manager);
 
+  uint64_t fence_sync = 0;
   if (requires_sync_point) {
-    gpu_memory_buffer_manager_->SetDestructionSyncPoint(gpu_memory_buffer,
-                                                        InsertSyncPoint());
+    fence_sync = GenerateFenceSyncRelease();
+
+    // Previous fence syncs should be flushed already.
+    DCHECK_EQ(fence_sync - 1, flushed_fence_sync_release_);
+  }
+
+  QueueTask(base::Bind(&InProcessCommandBuffer::CreateImageOnGpuThread,
+                       base::Unretained(this), new_id, handle,
+                       gfx::Size(width, height), gpu_memory_buffer->GetFormat(),
+                       internalformat, order_num, fence_sync));
+
+  if (fence_sync) {
+    flushed_fence_sync_release_ = fence_sync;
+    SyncToken sync_token(GetNamespaceID(), GetCommandBufferID(), fence_sync);
+    sync_token.SetVerifyFlush();
+    gpu_memory_buffer_manager_->SetDestructionSyncToken(gpu_memory_buffer,
+                                                        sync_token);
   }
 
   return new_id;
@@ -689,7 +718,11 @@
     const gfx::GpuMemoryBufferHandle& handle,
     const gfx::Size& size,
     gfx::BufferFormat format,
-    uint32 internalformat) {
+    uint32 internalformat,
+    uint32_t order_num,
+    uint64_t fence_sync) {
+  ScopedOrderNumberProcessor scoped_order_num(sync_point_order_data_.get(),
+                                              order_num);
   if (!decoder_)
     return;
 
@@ -733,6 +766,10 @@
       break;
     }
   }
+
+  if (fence_sync) {
+    sync_point_client_->ReleaseFenceSync(fence_sync);
+  }
 }
 
 void InProcessCommandBuffer::DestroyImage(int32 id) {
diff --git a/gpu/command_buffer/service/in_process_command_buffer.h b/gpu/command_buffer/service/in_process_command_buffer.h
index 83318b5..0c881c1 100644
--- a/gpu/command_buffer/service/in_process_command_buffer.h
+++ b/gpu/command_buffer/service/in_process_command_buffer.h
@@ -230,7 +230,9 @@
                               const gfx::GpuMemoryBufferHandle& handle,
                               const gfx::Size& size,
                               gfx::BufferFormat format,
-                              uint32 internalformat);
+                              uint32 internalformat,
+                              uint32_t order_num,
+                              uint64_t fence_sync);
   void DestroyImageOnGpuThread(int32 id);
   void SetGetBufferOnGpuThread(int32 shm_id, base::WaitableEvent* completion);
 
diff --git a/gpu/command_buffer/service/sync_point_manager.cc b/gpu/command_buffer/service/sync_point_manager.cc
index bc73adb..3fa7539 100644
--- a/gpu/command_buffer/service/sync_point_manager.cc
+++ b/gpu/command_buffer/service/sync_point_manager.cc
@@ -282,6 +282,29 @@
       namespace_id_(namespace_id),
       client_id_(client_id) {}
 
+bool SyncPointClientWaiter::Wait(SyncPointClientState* release_state,
+                                 uint64_t release_count,
+                                 const base::Closure& wait_complete_callback) {
+  // No order number associated with the current execution context, using
+  // UINT32_MAX will just assume the release is in the SyncPointClientState's
+  // order numbers to be executed.
+  if (!release_state->WaitForRelease(UINT32_MAX, release_count,
+                                     wait_complete_callback)) {
+    wait_complete_callback.Run();
+    return false;
+  }
+  return true;
+}
+
+bool SyncPointClientWaiter::WaitNonThreadSafe(
+    SyncPointClientState* release_state,
+    uint64_t release_count,
+    scoped_refptr<base::SingleThreadTaskRunner> runner,
+    const base::Closure& wait_complete_callback) {
+  return Wait(release_state, release_count,
+              base::Bind(&RunOnThread, runner, wait_complete_callback));
+}
+
 SyncPointManager::SyncPointManager(bool allow_threaded_wait)
     : allow_threaded_wait_(allow_threaded_wait),
       // To reduce the risk that a sync point created in a previous GPU process
diff --git a/gpu/command_buffer/service/sync_point_manager.h b/gpu/command_buffer/service/sync_point_manager.h
index a72566b0d..c71b471 100644
--- a/gpu/command_buffer/service/sync_point_manager.h
+++ b/gpu/command_buffer/service/sync_point_manager.h
@@ -13,6 +13,7 @@
 #include "base/callback.h"
 #include "base/containers/hash_tables.h"
 #include "base/logging.h"
+#include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/synchronization/condition_variable.h"
@@ -137,6 +138,7 @@
  private:
   friend class base::RefCountedThreadSafe<SyncPointClientState>;
   friend class SyncPointClient;
+  friend class SyncPointClientWaiter;
   friend class SyncPointOrderData;
 
   struct ReleaseCallback {
@@ -232,6 +234,32 @@
   DISALLOW_COPY_AND_ASSIGN(SyncPointClient);
 };
 
+// A SyncPointClientWaiter is a Sync Point Client which can only wait and on
+// fence syncs and not release any fence syncs itself. Because they cannot
+// release any fence syncs they do not need an associated order number since
+// deadlocks cannot happen. Note that it is important that this class does
+// not exist in the same execution context as a SyncPointClient, or else a
+// deadlock could occur. Basically, SyncPointClientWaiter::Wait() should never
+// be called between SyncPointOrderData::BeginProcessingOrderNumber() and
+// SyncPointOrderData::FinishProcessingOrderNumber() on the same thread.
+class GPU_EXPORT SyncPointClientWaiter {
+ public:
+  SyncPointClientWaiter() {}
+  ~SyncPointClientWaiter() {}
+
+  bool Wait(SyncPointClientState* release_state,
+            uint64_t release_count,
+            const base::Closure& wait_complete_callback);
+
+  bool WaitNonThreadSafe(SyncPointClientState* release_state,
+                         uint64_t release_count,
+                         scoped_refptr<base::SingleThreadTaskRunner> runner,
+                         const base::Closure& wait_complete_callback);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SyncPointClientWaiter);
+};
+
 // This class manages the sync points, which allow cross-channel
 // synchronization.
 class GPU_EXPORT SyncPointManager {
diff --git a/ios/web/web_state/ui/crw_ui_web_view_web_controller.mm b/ios/web/web_state/ui/crw_ui_web_view_web_controller.mm
index a001266d..072b026 100644
--- a/ios/web/web_state/ui/crw_ui_web_view_web_controller.mm
+++ b/ios/web/web_state/ui/crw_ui_web_view_web_controller.mm
@@ -881,6 +881,16 @@
   }
 }
 
+- (void)loadCompletedForURL:(const GURL&)loadedURL {
+  // This is not actually the right place to call this, and is here to preserve
+  // the existing UIWebView behavior during the WKWebView transition. This
+  // should actually be called at the point where the web view URL is known to
+  // have actually changed, but currently there's not a clear way of knowing
+  // when that happens as a result of a load (vs. an in-page navigation), and
+  // over-calling this would regress other behavior.
+  self.webStateImpl->OnNavigationCommitted(loadedURL);
+}
+
 #pragma mark - JS to ObjC messaging
 
 - (void)respondToJSInvoke {
diff --git a/ios/web/web_state/ui/crw_web_controller+protected.h b/ios/web/web_state/ui/crw_web_controller+protected.h
index bfabca4..2a034cd 100644
--- a/ios/web/web_state/ui/crw_web_controller+protected.h
+++ b/ios/web/web_state/ui/crw_web_controller+protected.h
@@ -174,6 +174,10 @@
 // Handles cancelled load in WKWebView (error with NSURLErrorCancelled code).
 - (void)handleCancelledError:(NSError*)error;
 
+// Called when a load completes, to perform any final actions before informing
+// delegates.
+- (void)loadCompletedForURL:(const GURL&)loadedURL;
+
 #pragma mark - Optional methods for subclasses
 // Subclasses may overwrite methods in this section.
 
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 630a84b..14f76f50 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -1784,6 +1784,7 @@
       _webStateImpl->GetCacheMode());
 
   [self restoreStateFromHistory];
+  [self loadCompletedForURL:currentURL];
   _webStateImpl->OnPageLoaded(currentURL, loadSuccess);
   _webStateImpl->SetIsLoading(false);
   // Inform the embedder the load completed.
diff --git a/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm b/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm
index d85fdb7..65a8f84 100644
--- a/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm
+++ b/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm
@@ -139,9 +139,6 @@
   // Referrer for the current page.
   base::scoped_nsobject<NSString> _currentReferrerString;
 
-  // Backs the property of the same name.
-  base::scoped_nsobject<NSString> _documentMIMEType;
-
   // Navigation type of the pending navigation action of the main frame. This
   // value is assigned at |decidePolicyForNavigationAction| where the navigation
   // type is extracted from the request and associated with a committed
@@ -181,9 +178,6 @@
   BOOL _interactionRegisteredSinceLastURLChange;
 }
 
-// Response's MIME type of the last known navigation.
-@property(nonatomic, copy) NSString* documentMIMEType;
-
 // Dictionary where keys are the names of WKWebView properties and values are
 // selector names which should be called when a corresponding property has
 // changed. e.g. @{ @"URL" : @"webViewURLDidChange" } means that
@@ -510,13 +504,13 @@
     return web::WEB_VIEW_DOCUMENT_TYPE_GENERIC;
   }
 
-  if (!self.documentMIMEType) {
+  std::string mimeType = self.webState->GetContentsMimeType();
+  if (mimeType.empty()) {
     return web::WEB_VIEW_DOCUMENT_TYPE_UNKNOWN;
   }
 
-  if ([self.documentMIMEType isEqualToString:@"text/html"] ||
-      [self.documentMIMEType isEqualToString:@"application/xhtml+xml"] ||
-      [self.documentMIMEType isEqualToString:@"application/xml"]) {
+  if (mimeType == "text/html" || mimeType == "application/xhtml+xml" ||
+      mimeType == "application/xml") {
     return web::WEB_VIEW_DOCUMENT_TYPE_HTML;
   }
 
@@ -670,16 +664,12 @@
   }
 }
 
+- (void)loadCompletedForURL:(const GURL&)loadedURL {
+  // Nothing to do.
+}
+
 #pragma mark Private methods
 
-- (NSString*)documentMIMEType {
-  return _documentMIMEType.get();
-}
-
-- (void)setDocumentMIMEType:(NSString*)type {
-  _documentMIMEType.reset([type copy]);
-}
-
 - (NSDictionary*)wkWebViewObservers {
   return @{
 #if !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW)
@@ -1517,9 +1507,6 @@
   [self updatePendingNavigationTypeForMainFrameFromNavigationAction:
             navigationAction];
 
-  if (navigationAction.sourceFrame.mainFrame)
-    self.documentMIMEType = nil;
-
   web::FrameInfo targetFrame(navigationAction.targetFrame.mainFrame);
   BOOL isLinkClick = [self isLinkNavigation:navigationAction.navigationType];
   BOOL allowLoad = [self shouldAllowLoadWithRequest:request
@@ -1552,8 +1539,6 @@
     self.webStateImpl->OnHttpResponseHeadersReceived(
         HTTPHeaders.get(), net::GURLWithNSURL(navigationResponse.response.URL));
   }
-  if (navigationResponse.isForMainFrame)
-    self.documentMIMEType = navigationResponse.response.MIMEType;
 
   BOOL allowNavigation = navigationResponse.canShowMIMEType;
   if (allowNavigation) {
@@ -1663,6 +1648,7 @@
   // This is the point where the document's URL has actually changed.
   [self setDocumentURL:net::GURLWithNSURL([_wkWebView URL])];
   DCHECK(_documentURL == self.lastRegisteredRequestURL);
+  self.webStateImpl->OnNavigationCommitted(_documentURL);
   [self webPageChanged];
 
   [self updateCurrentBackForwardListItemHolder];
diff --git a/ios/web/web_state/web_state_impl.h b/ios/web/web_state/web_state_impl.h
index 55eea50..b5d346a 100644
--- a/ios/web/web_state/web_state_impl.h
+++ b/ios/web/web_state/web_state_impl.h
@@ -77,6 +77,9 @@
   // Notifies the observers that a provisional navigation has started.
   void OnProvisionalNavigationStarted(const GURL& url);
 
+  // Called when a navigation is committed.
+  void OnNavigationCommitted(const GURL& url);
+
   // Notifies the observers that the URL hash of the current page changed.
   void OnUrlHashChanged();
 
diff --git a/ios/web/web_state/web_state_impl.mm b/ios/web/web_state/web_state_impl.mm
index 51297891..7a8aaf8 100644
--- a/ios/web/web_state/web_state_impl.mm
+++ b/ios/web/web_state/web_state_impl.mm
@@ -109,6 +109,10 @@
   return copy;
 }
 
+void WebStateImpl::OnNavigationCommitted(const GURL& url) {
+  UpdateHttpResponseHeaders(url);
+}
+
 void WebStateImpl::OnUrlHashChanged() {
   FOR_EACH_OBSERVER(WebStateObserver, observers_, UrlHashChanged());
 }
@@ -157,7 +161,6 @@
 }
 
 void WebStateImpl::OnPageLoaded(const GURL& url, bool load_success) {
-  UpdateHttpResponseHeaders(url);
   if (facade_delegate_)
     facade_delegate_->OnPageLoaded();
 
@@ -315,6 +318,8 @@
   // Store the headers in a map until the page finishes loading, as we do not
   // know which URL corresponds to the main page yet.
   // Remove the hash (if any) as it is sometimes altered by in-page navigations.
+  // TODO(crbug/551677): Simplify all this logic once UIWebView is no longer
+  // supported.
   const GURL& url = GURLByRemovingRefFromGURL(resource_url);
   response_headers_map_[url] = response_headers;
 }
diff --git a/ios/web/web_state/web_state_impl_unittest.mm b/ios/web/web_state/web_state_impl_unittest.mm
index a3d5e91d..1c13c781 100644
--- a/ios/web/web_state/web_state_impl_unittest.mm
+++ b/ios/web/web_state/web_state_impl_unittest.mm
@@ -250,7 +250,8 @@
   web_state_->OnHttpResponseHeadersReceived(real_headers.get(), real_url);
   web_state_->OnHttpResponseHeadersReceived(frame_headers.get(), frame_url);
   // Include a hash to be sure it's handled correctly.
-  web_state_->OnPageLoaded(GURL(real_url.spec() + std::string("#baz")), true);
+  web_state_->OnNavigationCommitted(
+      GURL(real_url.spec() + std::string("#baz")));
 
   // Verify that the right header set was kept.
   EXPECT_TRUE(
@@ -276,14 +277,14 @@
   EXPECT_EQ(NULL, web_state_->GetHttpResponseHeaders());
 
   // There should be headers and parsed values after loading.
-  web_state_->OnPageLoaded(url, true);
+  web_state_->OnNavigationCommitted(url);
   EXPECT_TRUE(web_state_->GetHttpResponseHeaders()->HasHeader("Content-Type"));
   EXPECT_NE("", web_state_->GetContentsMimeType());
   EXPECT_NE("", web_state_->GetContentLanguageHeader());
 
   // ... but not after loading another page, nor should there be specific
   // parsed values.
-  web_state_->OnPageLoaded(GURL("http://elsewhere.com/"), true);
+  web_state_->OnNavigationCommitted(GURL("http://elsewhere.com/"));
   EXPECT_EQ(NULL, web_state_->GetHttpResponseHeaders());
   EXPECT_EQ("", web_state_->GetContentsMimeType());
   EXPECT_EQ("", web_state_->GetContentLanguageHeader());
diff --git a/ios/web/webui/url_data_manager_ios_backend.cc b/ios/web/webui/url_data_manager_ios_backend.cc
index cc3e3e9..d5117c2 100644
--- a/ios/web/webui/url_data_manager_ios_backend.cc
+++ b/ios/web/webui/url_data_manager_ios_backend.cc
@@ -96,7 +96,7 @@
   // net::URLRequestJob implementation.
   void Start() override;
   void Kill() override;
-  bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override;
+  int ReadRawData(net::IOBuffer* buf, int buf_size) override;
   bool GetMimeType(std::string* mime_type) const override;
   int GetResponseCode() const override;
   void GetResponseInfo(net::HttpResponseInfo* info) override;
@@ -142,7 +142,7 @@
 
   // Do the actual copy from data_ (the data we're serving) into |buf|.
   // Separate from ReadRawData so we can handle async I/O.
-  void CompleteRead(net::IOBuffer* buf, int buf_size, int* bytes_read);
+  int CompleteRead(net::IOBuffer* buf, int buf_size);
 
   // The actual data we're serving.  NULL until it's been fetched.
   scoped_refptr<base::RefCountedMemory> data_;
@@ -291,58 +291,46 @@
 void URLRequestChromeJob::DataAvailable(base::RefCountedMemory* bytes) {
   TRACE_EVENT_ASYNC_END0("browser", "DataManager:Request", this);
   if (bytes) {
-    // The request completed, and we have all the data.
-    // Clear any IO pending status.
-    SetStatus(net::URLRequestStatus());
-
     data_ = bytes;
-    int bytes_read;
     if (pending_buf_.get()) {
       CHECK(pending_buf_->data());
-      CompleteRead(pending_buf_.get(), pending_buf_size_, &bytes_read);
+      int rv = CompleteRead(pending_buf_.get(), pending_buf_size_);
       pending_buf_ = NULL;
-      NotifyReadComplete(bytes_read);
+      ReadRawDataComplete(rv);
     }
   } else {
-    // The request failed.
-    NotifyDone(
-        net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED));
+    ReadRawDataComplete(net::ERR_FAILED);
   }
 }
 
-bool URLRequestChromeJob::ReadRawData(net::IOBuffer* buf,
-                                      int buf_size,
-                                      int* bytes_read) {
+int URLRequestChromeJob::ReadRawData(net::IOBuffer* buf, int buf_size) {
   if (!data_.get()) {
-    SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
     DCHECK(!pending_buf_.get());
     CHECK(buf->data());
     pending_buf_ = buf;
     pending_buf_size_ = buf_size;
-    return false;  // Tell the caller we're still waiting for data.
+    return net::ERR_IO_PENDING;  // Tell the caller we're still waiting for
+                                 // data.
   }
 
   // Otherwise, the data is available.
-  CompleteRead(buf, buf_size, bytes_read);
-  return true;
+  return CompleteRead(buf, buf_size);
 }
 
-void URLRequestChromeJob::CompleteRead(net::IOBuffer* buf,
-                                       int buf_size,
-                                       int* bytes_read) {
+int URLRequestChromeJob::CompleteRead(net::IOBuffer* buf, int buf_size) {
   // http://crbug.com/373841
   char url_buf[128];
   base::strlcpy(url_buf, request_->url().spec().c_str(), arraysize(url_buf));
   base::debug::Alias(url_buf);
 
-  int remaining = static_cast<int>(data_->size()) - data_offset_;
+  int remaining = data_->size() - data_offset_;
   if (buf_size > remaining)
     buf_size = remaining;
   if (buf_size > 0) {
     memcpy(buf->data(), data_->front() + data_offset_, buf_size);
     data_offset_ += buf_size;
   }
-  *bytes_read = buf_size;
+  return buf_size;
 }
 
 namespace {
diff --git a/mandoline/BUILD.gn b/mandoline/BUILD.gn
index bc32cb0..e077bf08 100644
--- a/mandoline/BUILD.gn
+++ b/mandoline/BUILD.gn
@@ -12,15 +12,13 @@
     ":tests",
   ]
 
-  if (!is_component_build) {
-    if (is_android) {
-      deps += [ "//mandoline/app/android" ]
-    } else {
-      deps += [
-        "//components/mus/example",
-        "//mandoline/app/desktop",
-      ]
-    }
+  if (is_android) {
+    deps += [ "//mandoline/app/android" ]
+  } else {
+    deps += [
+      "//components/mus/example",
+      "//mandoline/app/desktop",
+    ]
   }
 }
 
@@ -38,7 +36,7 @@
     deps += [ "//tools/xdisplaycheck" ]
   }
 
-  if (!is_component_build && !is_mac) {
+  if (!is_mac) {
     deps += [
       "//components/clipboard:apptests",
       "//components/filesystem:apptests",
diff --git a/media/base/video_frame.cc b/media/base/video_frame.cc
index f73d5ac..f14e91f 100644
--- a/media/base/video_frame.cc
+++ b/media/base/video_frame.cc
@@ -813,7 +813,7 @@
   // occurred when it waits on |release_sync_token_|.
   if (release_sync_token_.HasData())
     client->WaitSyncToken(release_sync_token_);
-  release_sync_token_ = gpu::SyncToken(client->InsertSyncPoint());
+  client->GenerateSyncToken(&release_sync_token_);
 }
 
 // static
diff --git a/media/base/video_frame.h b/media/base/video_frame.h
index 717649e..a6ff33a4 100644
--- a/media/base/video_frame.h
+++ b/media/base/video_frame.h
@@ -80,7 +80,7 @@
   class SyncTokenClient {
    public:
     SyncTokenClient() {}
-    virtual uint32 InsertSyncPoint() = 0;
+    virtual void GenerateSyncToken(gpu::SyncToken* sync_token) = 0;
     virtual void WaitSyncToken(const gpu::SyncToken& sync_token) = 0;
 
    protected:
diff --git a/media/base/video_frame_unittest.cc b/media/base/video_frame_unittest.cc
index c9f05ec..ee2a454 100644
--- a/media/base/video_frame_unittest.cc
+++ b/media/base/video_frame_unittest.cc
@@ -269,7 +269,7 @@
 // Verify the gpu::MailboxHolder::ReleaseCallback is called when VideoFrame is
 // destroyed with the default release sync point.
 TEST(VideoFrame, TextureNoLongerNeededCallbackIsCalled) {
-  gpu::SyncToken called_sync_token(1);
+  gpu::SyncToken called_sync_token(gpu::CommandBufferNamespace::GPU_IO, 1, 1);
 
   {
     scoped_refptr<VideoFrame> frame = VideoFrame::WrapNativeTexture(
@@ -296,8 +296,8 @@
   explicit SyncTokenClientImpl(const gpu::SyncToken& sync_token)
       : sync_token_(sync_token) {}
   ~SyncTokenClientImpl() override {}
-  uint32 InsertSyncPoint() override {
-    return static_cast<uint32>(sync_token_.release_count());
+  void GenerateSyncToken(gpu::SyncToken* sync_token) override {
+    *sync_token = sync_token_;
   }
   void WaitSyncToken(const gpu::SyncToken& sync_token) override {}
 
@@ -313,14 +313,20 @@
 TEST(VideoFrame,
      TexturesNoLongerNeededCallbackAfterTakingAndReleasingMailboxes) {
   const int kPlanesNum = 3;
+  const gpu::CommandBufferNamespace kNamespace =
+      gpu::CommandBufferNamespace::GPU_IO;
+  const uint64_t kCommandBufferId = 0x123;
   gpu::Mailbox mailbox[kPlanesNum];
   for (int i = 0; i < kPlanesNum; ++i) {
     mailbox[i].name[0] = 50 + 1;
   }
 
-  gpu::SyncToken sync_token(7);
+  gpu::SyncToken sync_token(kNamespace, kCommandBufferId, 7);
+  sync_token.SetVerifyFlush();
   uint32 target = 9;
-  gpu::SyncToken release_sync_token(111);
+  gpu::SyncToken release_sync_token(kNamespace, kCommandBufferId, 111);
+  release_sync_token.SetVerifyFlush();
+
   gpu::SyncToken called_sync_token;
   {
     scoped_refptr<VideoFrame> frame = VideoFrame::WrapYUV420NativeTextures(
diff --git a/media/blink/run_all_unittests.cc b/media/blink/run_all_unittests.cc
index bdd34a74..787091b 100644
--- a/media/blink/run_all_unittests.cc
+++ b/media/blink/run_all_unittests.cc
@@ -58,7 +58,7 @@
 
  private:
   scoped_refptr<scheduler::SchedulerTqmDelegate> task_runner_delegate_;
-  scoped_ptr<scheduler::RendererScheduler> scheduler_;
+  scoped_ptr<scheduler::RendererSchedulerImpl> scheduler_;
   scoped_ptr<blink::WebScheduler> web_scheduler_;
   scoped_ptr<blink::WebTaskRunner> web_task_runner_;
 };
diff --git a/media/cdm/default_cdm_factory.h b/media/cdm/default_cdm_factory.h
index 78d4f2f..1c7b0c7 100644
--- a/media/cdm/default_cdm_factory.h
+++ b/media/cdm/default_cdm_factory.h
@@ -7,12 +7,13 @@
 
 #include "base/macros.h"
 #include "media/base/cdm_factory.h"
+#include "media/base/media_export.h"
 
 namespace media {
 
 struct CdmConfig;
 
-class DefaultCdmFactory : public CdmFactory {
+class MEDIA_EXPORT DefaultCdmFactory : public CdmFactory {
  public:
   DefaultCdmFactory();
   ~DefaultCdmFactory() final;
diff --git a/media/mojo/services/BUILD.gn b/media/mojo/services/BUILD.gn
index c478c098..ee178a7c 100644
--- a/media/mojo/services/BUILD.gn
+++ b/media/mojo/services/BUILD.gn
@@ -184,54 +184,52 @@
   ]
 }
 
-if (!is_component_build) {
-  mojo_native_application("media") {
-    sources = [
-      "main.cc",
-    ]
+mojo_native_application("media") {
+  sources = [
+    "main.cc",
+  ]
 
-    deps = [
-      ":application",
-      "//third_party/mojo/src/mojo/public/c/system:for_shared_library",
-    ]
-  }
+  deps = [
+    ":application",
+    "//third_party/mojo/src/mojo/public/c/system:for_shared_library",
+  ]
+}
 
-  # Note, the following tests must be loaded via mojo_runner as an app, e.g.
-  #
-  #   out/Debug/mojo_runner mojo:media_apptests
-  #   out/Debug/mojo_runner mojo:media_pipeline_integration_apptests
-  #
-  mojo_native_application("media_apptests") {
-    testonly = true
+# Note, the following tests must be loaded via mojo_runner as an app, e.g.
+#
+#   out/Debug/mojo_runner mojo:media_apptests
+#   out/Debug/mojo_runner mojo:media_pipeline_integration_apptests
+#
+mojo_native_application("media_apptests") {
+  testonly = true
 
-    sources = [
-      "media_apptest.cc",
-    ]
+  sources = [
+    "media_apptest.cc",
+  ]
 
-    deps = [
-      ":proxy",
-      "//media/base:test_support",
-      "//mojo/application/public/cpp:test_support",
-      "//testing/gmock",
-      "//testing/gtest",
-    ]
+  deps = [
+    ":proxy",
+    "//media/base:test_support",
+    "//mojo/application/public/cpp:test_support",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
 
-    data_deps = [
-      ":media",
-    ]
-  }
+  data_deps = [
+    ":media",
+  ]
+}
 
-  mojo_native_application("media_pipeline_integration_apptests") {
-    testonly = true
+mojo_native_application("media_pipeline_integration_apptests") {
+  testonly = true
 
-    deps = [
-      "//media/test:mojo_pipeline_integration_tests",
-    ]
+  deps = [
+    "//media/test:mojo_pipeline_integration_tests",
+  ]
 
-    data_deps = [
-      ":media",
-    ]
-  }
+  data_deps = [
+    ":media",
+  ]
 }
 
 group("services") {
diff --git a/media/mojo/services/mojo_renderer_factory.h b/media/mojo/services/mojo_renderer_factory.h
index 64b68382..01a325a 100644
--- a/media/mojo/services/mojo_renderer_factory.h
+++ b/media/mojo/services/mojo_renderer_factory.h
@@ -17,7 +17,7 @@
 }
 
 // The default factory class for creating MojoRendererImpl.
-class MEDIA_EXPORT MojoRendererFactory : public RendererFactory {
+class MojoRendererFactory : public RendererFactory {
  public:
   explicit MojoRendererFactory(interfaces::ServiceFactory* service_factory);
   ~MojoRendererFactory() final;
diff --git a/media/renderers/skcanvas_video_renderer.cc b/media/renderers/skcanvas_video_renderer.cc
index 675839b..d2f25d63 100644
--- a/media/renderers/skcanvas_video_renderer.cc
+++ b/media/renderers/skcanvas_video_renderer.cc
@@ -63,7 +63,11 @@
  public:
   explicit SyncTokenClientImpl(gpu::gles2::GLES2Interface* gl) : gl_(gl) {}
   ~SyncTokenClientImpl() override {}
-  uint32 InsertSyncPoint() override { return gl_->InsertSyncPointCHROMIUM(); }
+  void GenerateSyncToken(gpu::SyncToken* sync_token) override {
+    const uint64_t fence_sync = gl_->InsertFenceSyncCHROMIUM();
+    gl_->ShallowFlushCHROMIUM();
+    gl_->GenSyncTokenCHROMIUM(fence_sync, sync_token->GetData());
+  }
   void WaitSyncToken(const gpu::SyncToken& sync_token) override {
     gl_->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
   }
diff --git a/media/test/BUILD.gn b/media/test/BUILD.gn
index c4f4d4d..3ce4648 100644
--- a/media/test/BUILD.gn
+++ b/media/test/BUILD.gn
@@ -77,40 +77,38 @@
   }
 }
 
-if (!is_component_build) {
-  source_set("mojo_pipeline_integration_tests") {
-    testonly = true
+source_set("mojo_pipeline_integration_tests") {
+  testonly = true
 
-    if (media_use_ffmpeg && !is_android) {
-      sources = [
-        "pipeline_integration_test.cc",
-      ]
+  if (media_use_ffmpeg && !is_android) {
+    sources = [
+      "pipeline_integration_test.cc",
+    ]
 
-      defines = [ "MOJO_RENDERER" ]
+    defines = [ "MOJO_RENDERER" ]
 
-      configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+    configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
 
-      deps = [
-        ":pipeline_integration_test_base",
-        "//base",
-        "//base/test:test_support",
-        "//media",
-        "//media:test_support",
-        "//media/audio:test_support",
-        "//media/base:test_support",
-        "//media/mojo/interfaces",
-        "//media/mojo/services:proxy",
-        "//media/mojo/services:renderer_service",
-        "//mojo/application/public/cpp:test_support",
-        "//testing/gtest",
-        "//ui/gfx/geometry",
-        "//ui/gfx:test_support",
+    deps = [
+      ":pipeline_integration_test_base",
+      "//base",
+      "//base/test:test_support",
+      "//media",
+      "//media:test_support",
+      "//media/audio:test_support",
+      "//media/base:test_support",
+      "//media/mojo/interfaces",
+      "//media/mojo/services:proxy",
+      "//media/mojo/services:renderer_service",
+      "//mojo/application/public/cpp:test_support",
+      "//testing/gtest",
+      "//ui/gfx/geometry",
+      "//ui/gfx:test_support",
 
-        # TODO(dalecurtis): Required since the gmock header is included in the
-        # header for pipeline_integration_test_base.h.  This should be moved
-        # into the .cc file to avoid the extra dependency here.
-        "//testing/gmock",
-      ]
-    }
+      # TODO(dalecurtis): Required since the gmock header is included in the
+      # header for pipeline_integration_test_base.h.  This should be moved
+      # into the .cc file to avoid the extra dependency here.
+      "//testing/gmock",
+    ]
   }
 }
diff --git a/mojo/BUILD.gn b/mojo/BUILD.gn
index 04f79cb1..584421b 100644
--- a/mojo/BUILD.gn
+++ b/mojo/BUILD.gn
@@ -24,9 +24,7 @@
     deps += [ "//mojo/android" ]
   }
 
-  if (!is_component_build) {
-    deps += [ "//mojo/runner" ]
-  }
+  deps += [ "//mojo/runner" ]
 }
 
 # TODO(GYP): Delete this after we've converted everything to GN.
@@ -96,17 +94,15 @@
     "//third_party/mojo/src/mojo/edk/test:mojo_public_utility_unittests",
   ]
 
-  if (!is_component_build) {
-    deps += [
-      "//mojo/package_manager:unittests",
-      "//mojo/runner:apptests",
-      "//mojo/runner:mojo_runner_unittests",
-      "//mojo/services/network:apptests",
-      "//mojo/shell:mojo_shell_unittests",
-    ]
+  deps += [
+    "//mojo/package_manager:unittests",
+    "//mojo/runner:apptests",
+    "//mojo/runner:mojo_runner_unittests",
+    "//mojo/services/network:apptests",
+    "//mojo/shell:mojo_shell_unittests",
+  ]
 
-    if (is_android) {
-      deps += [ "//mojo/runner:mojo_runner_apptests_apk" ]
-    }
+  if (is_android) {
+    deps += [ "//mojo/runner:mojo_runner_apptests_apk" ]
   }
 }
diff --git a/mojo/common/data_pipe_drainer.h b/mojo/common/data_pipe_drainer.h
index 906d040..19af32d 100644
--- a/mojo/common/data_pipe_drainer.h
+++ b/mojo/common/data_pipe_drainer.h
@@ -7,13 +7,14 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "mojo/common/mojo_common_export.h"
 #include "mojo/message_pump/handle_watcher.h"
 #include "third_party/mojo/src/mojo/public/cpp/system/core.h"
 
 namespace mojo {
 namespace common {
 
-class DataPipeDrainer {
+class MOJO_COMMON_EXPORT DataPipeDrainer {
  public:
   class Client {
    public:
diff --git a/mojo/common/user_agent.h b/mojo/common/user_agent.h
index 741ef8f..031b1029 100644
--- a/mojo/common/user_agent.h
+++ b/mojo/common/user_agent.h
@@ -12,7 +12,7 @@
 namespace mojo {
 namespace common {
 
-std::string GetUserAgent();
+std::string MOJO_COMMON_EXPORT GetUserAgent();
 
 }  // namespace common
 }  // namespace mojo
diff --git a/mojo/converters/surfaces/surfaces_type_converters.h b/mojo/converters/surfaces/surfaces_type_converters.h
index a172a8d..765cb31 100644
--- a/mojo/converters/surfaces/surfaces_type_converters.h
+++ b/mojo/converters/surfaces/surfaces_type_converters.h
@@ -198,7 +198,7 @@
       const mus::mojom::CompositorFrameMetadataPtr& input);
 };
 
-scoped_ptr<cc::CompositorFrame> ConvertToCompositorFrame(
+MOJO_SURFACES_EXPORT scoped_ptr<cc::CompositorFrame> ConvertToCompositorFrame(
     const mus::mojom::CompositorFramePtr& input,
     CustomSurfaceConverter* custom_converter);
 
diff --git a/mojo/gles2/BUILD.gn b/mojo/gles2/BUILD.gn
index cfb331a2..39912e3b 100644
--- a/mojo/gles2/BUILD.gn
+++ b/mojo/gles2/BUILD.gn
@@ -22,12 +22,13 @@
     "//gpu/command_buffer/client",
     "//gpu/command_buffer/client:gles2_implementation",
     "//gpu/command_buffer/common",
-    "//third_party/mojo/src/mojo/public/c/gles2:headers",
+    "//third_party/mojo/src/mojo/public/c/gles2",
     "//third_party/mojo/src/mojo/public/cpp/bindings",
   ]
 }
 
-source_set("gles2") {
+component("gles2") {
+  output_name = "mojo_gles2_impl"
   sources = [
     "command_buffer_client_impl.cc",
     "command_buffer_client_impl.h",
@@ -57,15 +58,18 @@
     "//gpu/command_buffer/client:gles2_cmd_helper",
     "//gpu/command_buffer/client:gles2_implementation",
     "//gpu/command_buffer/client:gles2_interface",
-    "//gpu/command_buffer/service:service_sources",
     "//gpu/command_buffer/common",
     "//mojo/environment:chromium",
-    "//mojo/platform_handle:defs",
-    "//third_party/mojo/src/mojo/public/c/gles2:headers",
-    "//third_party/mojo/src/mojo/public/c/system",
+    "//mojo/platform_handle:for_component",
+    "//third_party/mojo/src/mojo/public/c/gles2",
+    "//third_party/mojo/src/mojo/public/c/system:for_component",
     "//third_party/mojo/src/mojo/public/cpp/bindings",
     "//third_party/mojo/src/mojo/public/cpp/system",
   ]
 
+  if (!is_component_build) {
+    deps += [ "//gpu/command_buffer/service:service_sources" ]
+  }
+
   include_dirs = [ ".." ]
 }
diff --git a/mojo/gles2/gles2_impl.cc b/mojo/gles2/gles2_impl.cc
index 448e6c4..d9c42a61 100644
--- a/mojo/gles2/gles2_impl.cc
+++ b/mojo/gles2/gles2_impl.cc
@@ -9,6 +9,9 @@
 #include "gpu/GLES2/gl2extchromium.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "mojo/gles2/gles2_context.h"
+// Even though this isn't used here, we need to include it to get the symbols to
+// be exported in component build.
+#include "third_party/mojo/src/mojo/public/c/gles2/chromium_extension.h"
 
 using gles2::GLES2Context;
 
diff --git a/mojo/platform_handle/BUILD.gn b/mojo/platform_handle/BUILD.gn
index f224dd9..2afc90a 100644
--- a/mojo/platform_handle/BUILD.gn
+++ b/mojo/platform_handle/BUILD.gn
@@ -2,42 +2,76 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+# See comments in third_party/mojo/src/mojo/public/c/system/BUILD.gn which this
+# is based on.
+# Summary: depend on this target to use the platform handle functions without
+# linking against a specific implementation.
+# For component targets, add //mojo/platform_handle:for_component to your deps
+# section.
+# For shared_library targets (e.g., a Mojo App), add
+# //mojo/platform_handle:for_shared_library to your deps.
 source_set("platform_handle") {
   sources = [
+    "platform_handle.h",
+    "platform_handle_functions.h",
+  ]
+  deps = [
+    "//third_party/mojo/src/mojo/public/c/system",
+  ]
+}
+
+component("platform_handle_impl") {
+  output_name = "platform_handle_impl"
+  public_deps = [
+    ":platform_handle",
+  ]
+  sources = [
+    "platform_handle_functions.cc",
+  ]
+  defines = [ "PLATFORM_HANDLE_IMPLEMENTATION" ]
+  deps = [
+    "//base",
+    "//third_party/mojo/src/mojo/edk/embedder:headers",
+    "//third_party/mojo/src/mojo/public/c/system:for_component",
+  ]
+}
+
+source_set("platform_handle_thunks") {
+  public_deps = [
+    ":platform_handle",
+  ]
+  sources = [
     "platform_handle_private_thunks.cc",
     "platform_handle_private_thunks.h",
   ]
-
+  defines = [ "PLATFORM_HANDLE_IMPLEMENTATION" ]
   deps = [
     "//third_party/mojo/src/mojo/public/c/system",
   ]
-
-  public_deps = [
-    ":defs",
-  ]
-
-  defines = [ "PLATFORM_HANDLE_IMPLEMENTATION" ]
 }
 
-# Only targets that are registering the thunks or get linked into the runner
-# depend upon this target. The rest should use the |platform_handle| target
-# above.
-source_set("defs") {
-  visibility = [
+group("for_shared_library") {
+  public_deps = [
     ":platform_handle",
-    "//components/font_service/public/cpp",
-    "//components/mus/gles2",
-    "//mojo/gles2",
-    "//mojo/runner:platform_handle",
   ]
+  if (is_component_build) {
+    deps = [
+      ":platform_handle_impl",
+    ]
+  } else {
+    deps = [
+      ":platform_handle_thunks",
+    ]
+  }
+}
 
-  sources = [
-    "platform_handle.h",
-    "platform_handle_exports.h",
-    "platform_handle_functions.h",
+group("for_component") {
+  public_deps = [
+    ":platform_handle",
   ]
-
-  deps = [
-    "//third_party/mojo/src/mojo/public/c/system",
-  ]
+  if (is_component_build) {
+    deps = [
+      ":platform_handle_impl",
+    ]
+  }
 }
diff --git a/mojo/platform_handle/platform_handle_exports.h b/mojo/platform_handle/platform_handle_exports.h
index 6c57f9b..82fffd9 100644
--- a/mojo/platform_handle/platform_handle_exports.h
+++ b/mojo/platform_handle/platform_handle_exports.h
@@ -5,7 +5,7 @@
 #ifndef MOJO_PLATFORM_HANDLE_PLATFORM_HANDLE_EXPORTS_H_
 #define MOJO_PLATFORM_HANDLE_PLATFORM_HANDLE_EXPORTS_H_
 
-#if defined(COMPONENT_BUILD) && defined(MOJO_USE_SYSTEM_IMPL)
+#if defined(COMPONENT_BUILD)
 #if defined(WIN32)
 
 #if defined(PLATFORM_HANDLE_IMPLEMENTATION)
@@ -24,10 +24,10 @@
 
 #endif  // defined(WIN32)
 
-#else  // !defined(COMPONENT_BUILD) || !defined(MOJO_USE_SYSTEM_IMPL)
+#else  // !defined(COMPONENT_BUILD)
 
 #define PLATFORM_HANDLE_EXPORT
 
-#endif  // defined(COMPONENT_BUILD) && defined(MOJO_USE_SYSTEM_IMPL)
+#endif  // defined(COMPONENT_BUILD)
 
 #endif  // MOJO_PLATFORM_HANDLE_PLATFORM_HANDLE_EXPORTS_H_
diff --git a/mojo/runner/platform_handle_impl.cc b/mojo/platform_handle/platform_handle_functions.cc
similarity index 94%
rename from mojo/runner/platform_handle_impl.cc
rename to mojo/platform_handle/platform_handle_functions.cc
index c5e7999..1359ddad 100644
--- a/mojo/runner/platform_handle_impl.cc
+++ b/mojo/platform_handle/platform_handle_functions.cc
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "mojo/platform_handle/platform_handle.h"
+#include "mojo/platform_handle/platform_handle_functions.h"
+
 #include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
 
 extern "C" {
diff --git a/mojo/public/mojo_application.gni b/mojo/public/mojo_application.gni
index 364a092..1609b02 100644
--- a/mojo/public/mojo_application.gni
+++ b/mojo/public/mojo_application.gni
@@ -95,13 +95,12 @@
       }
 
       deps = rebase_path([
-                           "mojo/public/c/system",
-                           "mojo/public/platform/native:gles2",
-                           "mojo/public/platform/native:system",
+                           "mojo/public/gles2:for_shared_library",
+                           "mojo/public/c/system:for_shared_library",
                          ],
                          ".",
                          mojo_root)
-      deps += [ "//mojo/platform_handle" ]
+      deps += [ "//mojo/platform_handle:for_shared_library" ]
 
       deps += mojo_deps
       if (defined(invoker.public_deps)) {
diff --git a/mojo/runner/BUILD.gn b/mojo/runner/BUILD.gn
index 6dd96424..92a2342a 100644
--- a/mojo/runner/BUILD.gn
+++ b/mojo/runner/BUILD.gn
@@ -7,10 +7,6 @@
 import("//testing/test.gni")
 import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
 
-# We don't support building in the component build since mojo apps are
-# inherently components.
-assert(!is_component_build)
-
 group("runner") {
   testonly = true
 
@@ -200,21 +196,6 @@
   check_includes = false
 }
 
-source_set("platform_handle") {
-  sources = [
-    "platform_handle_impl.cc",
-  ]
-
-  public_deps = [
-    "//third_party/mojo/src/mojo/public/cpp/bindings",
-  ]
-
-  deps = [
-    "//mojo/platform_handle:defs",
-    "//third_party/mojo/src/mojo/edk/embedder:embedder",
-  ]
-}
-
 source_set("native_application_support") {
   sources = [
     "native_application_support.cc",
@@ -222,9 +203,9 @@
   ]
 
   deps = [
-    ":platform_handle",
     "//base",
     "//mojo/gles2",
+    "//mojo/platform_handle:platform_handle_impl",
     "//mojo/shell",
   ]
 
diff --git a/mojo/runner/child/BUILD.gn b/mojo/runner/child/BUILD.gn
index fae89c08..0bd6786e 100644
--- a/mojo/runner/child/BUILD.gn
+++ b/mojo/runner/child/BUILD.gn
@@ -25,7 +25,7 @@
     "//mojo/application/public/interfaces",
     "//mojo/gles2",
     "//mojo/message_pump",
-    "//mojo/runner:platform_handle",
+    "//mojo/platform_handle:for_shared_library",
     "//third_party/mojo/src/mojo/edk/system",
   ]
 }
@@ -90,12 +90,13 @@
     ":apptest_interfaces",
     ":lib",
     "//base",
+    "//base:base_static",
     "//mojo/application/public/cpp",
     "//mojo/application/public/interfaces",
     "//mojo/common:common_base",
     "//mojo/gles2",
     "//mojo/message_pump",
     "//mojo/runner:init",
-    "//third_party/mojo/src/mojo/edk/embedder:embedder",
+    "//third_party/mojo/src/mojo/edk/system",
   ]
 }
diff --git a/mojo/runner/native_application_support.cc b/mojo/runner/native_application_support.cc
index e1e35dcc..0e46803 100644
--- a/mojo/runner/native_application_support.cc
+++ b/mojo/runner/native_application_support.cc
@@ -56,6 +56,9 @@
   if (!app_library)
     return false;
 
+// Thunks aren't needed/used in component build, since the thunked methods
+// just live in their own dynamically loaded library.
+#if !defined(COMPONENT_BUILD)
   if (!SetThunks(&MojoMakeSystemThunks, "MojoSetSystemThunks", app_library)) {
     LOG(ERROR) << "MojoSetSystemThunks not found";
     return false;
@@ -104,6 +107,7 @@
   // Apps need not include platform handle thunks.
   SetThunks(&MojoMakePlatformHandlePrivateThunks,
             "MojoSetPlatformHandlePrivateThunks", app_library);
+#endif
 
   typedef MojoResult (*MojoMainFunction)(MojoHandle);
   MojoMainFunction main_function = reinterpret_cast<MojoMainFunction>(
diff --git a/mojo/services/BUILD.gn b/mojo/services/BUILD.gn
index 9272f92..bc9ae26 100644
--- a/mojo/services/BUILD.gn
+++ b/mojo/services/BUILD.gn
@@ -11,11 +11,9 @@
     "//mojo/services/network/public/interfaces",
   ]
 
-  if (!is_component_build) {
-    deps += [
-      "//mojo/services/network",
-      "//mojo/services/test_service",
-      "//mojo/services/tracing",
-    ]
-  }
+  deps += [
+    "//mojo/services/network",
+    "//mojo/services/test_service",
+    "//mojo/services/tracing",
+  ]
 }
diff --git a/mojo/services/network/url_loader_impl_apptest.cc b/mojo/services/network/url_loader_impl_apptest.cc
index 2fb2210..76c1fee6 100644
--- a/mojo/services/network/url_loader_impl_apptest.cc
+++ b/mojo/services/network/url_loader_impl_apptest.cc
@@ -49,30 +49,22 @@
 
   void Start() override { status_ = STARTED; }
 
-  bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override {
+  int ReadRawData(net::IOBuffer* buf, int buf_size) override {
     status_ = READING;
     buf_size_ = buf_size;
-    SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
-    return false;
+    return net::ERR_IO_PENDING;
   }
 
   void NotifyHeadersComplete() { net::URLRequestJob::NotifyHeadersComplete(); }
 
-  void NotifyReadComplete(int bytes_read) {
-    if (bytes_read < 0) {
-      status_ = COMPLETED;
-      NotifyDone(net::URLRequestStatus(
-          net::URLRequestStatus::FromError(net::ERR_FAILED)));
-      net::URLRequestJob::NotifyReadComplete(0);
-    } else if (bytes_read == 0) {
-      status_ = COMPLETED;
-      NotifyDone(net::URLRequestStatus());
-      net::URLRequestJob::NotifyReadComplete(bytes_read);
-    } else {
-      status_ = STARTED;
-      SetStatus(net::URLRequestStatus());
-      net::URLRequestJob::NotifyReadComplete(bytes_read);
-    }
+  void NotifyReadComplete(int result) {
+    status_ = result <= 0 ? COMPLETED : STARTED;
+
+    // Map errors to net::ERR_FAILED.
+    if (result < 0)
+      result = net::ERR_FAILED;
+
+    ReadRawDataComplete(result);
   }
 
  private:
diff --git a/net/base/address_family.cc b/net/base/address_family.cc
new file mode 100644
index 0000000..1af5e00
--- /dev/null
+++ b/net/base/address_family.cc
@@ -0,0 +1,36 @@
+// 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 "net/base/address_family.h"
+
+#include "base/logging.h"
+#include "net/base/sys_addrinfo.h"
+
+namespace net {
+
+AddressFamily GetAddressFamily(const IPAddressNumber& address) {
+  switch (address.size()) {
+    case kIPv4AddressSize:
+      return ADDRESS_FAMILY_IPV4;
+    case kIPv6AddressSize:
+      return ADDRESS_FAMILY_IPV6;
+    default:
+      return ADDRESS_FAMILY_UNSPECIFIED;
+  }
+}
+
+int ConvertAddressFamily(AddressFamily address_family) {
+  switch (address_family) {
+    case ADDRESS_FAMILY_UNSPECIFIED:
+      return AF_UNSPEC;
+    case ADDRESS_FAMILY_IPV4:
+      return AF_INET;
+    case ADDRESS_FAMILY_IPV6:
+      return AF_INET6;
+  }
+  NOTREACHED();
+  return AF_UNSPEC;
+}
+
+}  // namespace net
diff --git a/net/base/address_family.h b/net/base/address_family.h
index eb87ae3b..57ec48d 100644
--- a/net/base/address_family.h
+++ b/net/base/address_family.h
@@ -5,6 +5,9 @@
 #ifndef NET_BASE_ADDRESS_FAMILY_H_
 #define NET_BASE_ADDRESS_FAMILY_H_
 
+#include "net/base/ip_address_number.h"
+#include "net/base/net_export.h"
+
 namespace net {
 
 // Enum wrapper around the address family types supported by host resolver
@@ -30,6 +33,12 @@
 };
 typedef int HostResolverFlags;
 
+// Returns AddressFamily for |address|.
+NET_EXPORT AddressFamily GetAddressFamily(const IPAddressNumber& address);
+
+// Maps the given AddressFamily to either AF_INET, AF_INET6 or AF_UNSPEC.
+NET_EXPORT int ConvertAddressFamily(AddressFamily address_family);
+
 }  // namespace net
 
 #endif  // NET_BASE_ADDRESS_FAMILY_H_
diff --git a/net/base/address_family_unittest.cc b/net/base/address_family_unittest.cc
new file mode 100644
index 0000000..6668ea2
--- /dev/null
+++ b/net/base/address_family_unittest.cc
@@ -0,0 +1,22 @@
+// 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 "net/base/address_family.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace {
+
+TEST(AddressFamilyTest, GetAddressFamily) {
+  IPAddressNumber number;
+  EXPECT_EQ(ADDRESS_FAMILY_UNSPECIFIED, GetAddressFamily(number));
+  EXPECT_TRUE(ParseIPLiteralToNumber("192.168.0.1", &number));
+  EXPECT_EQ(ADDRESS_FAMILY_IPV4, GetAddressFamily(number));
+  EXPECT_TRUE(ParseIPLiteralToNumber("1:abcd::3:4:ff", &number));
+  EXPECT_EQ(ADDRESS_FAMILY_IPV6, GetAddressFamily(number));
+}
+
+}  // namespace
+}  // namespace net
diff --git a/net/base/net_util.cc b/net/base/net_util.cc
index 97fecb4..d1ac2a5 100644
--- a/net/base/net_util.cc
+++ b/net/base/net_util.cc
@@ -481,30 +481,6 @@
 #endif  // defined(various platforms)
 }
 
-AddressFamily GetAddressFamily(const IPAddressNumber& address) {
-  switch (address.size()) {
-    case kIPv4AddressSize:
-      return ADDRESS_FAMILY_IPV4;
-    case kIPv6AddressSize:
-      return ADDRESS_FAMILY_IPV6;
-    default:
-      return ADDRESS_FAMILY_UNSPECIFIED;
-  }
-}
-
-int ConvertAddressFamily(AddressFamily address_family) {
-  switch (address_family) {
-    case ADDRESS_FAMILY_UNSPECIFIED:
-      return AF_UNSPEC;
-    case ADDRESS_FAMILY_IPV4:
-      return AF_INET;
-    case ADDRESS_FAMILY_IPV6:
-      return AF_INET6;
-  }
-  NOTREACHED();
-  return AF_UNSPEC;
-}
-
 const uint16_t* GetPortFieldFromSockaddr(const struct sockaddr* address,
                                          socklen_t address_len) {
   if (address->sa_family == AF_INET) {
diff --git a/net/base/net_util.h b/net/base/net_util.h
index 5de9332c..1e4e388 100644
--- a/net/base/net_util.h
+++ b/net/base/net_util.h
@@ -21,9 +21,7 @@
 #include "base/basictypes.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_offset_string_conversions.h"
-#include "net/base/address_family.h"
 #include "net/base/escape.h"
-#include "net/base/net_export.h"
 #include "net/base/network_change_notifier.h"
 
 class GURL;
@@ -176,13 +174,6 @@
 // Also returns false if it cannot determine this.
 bool HaveOnlyLoopbackAddresses();
 
-// Returns AddressFamily of the address.
-NET_EXPORT_PRIVATE AddressFamily GetAddressFamily(
-    const IPAddressNumber& address);
-
-// Maps the given AddressFamily to either AF_INET, AF_INET6 or AF_UNSPEC.
-NET_EXPORT_PRIVATE int ConvertAddressFamily(AddressFamily address_family);
-
 // Retuns the port field of the |sockaddr|.
 const uint16_t* GetPortFieldFromSockaddr(const struct sockaddr* address,
                                          socklen_t address_len);
diff --git a/net/base/net_util_unittest.cc b/net/base/net_util_unittest.cc
index 0d69900..2704707d 100644
--- a/net/base/net_util_unittest.cc
+++ b/net/base/net_util_unittest.cc
@@ -449,14 +449,6 @@
             GetHostOrSpecFromURL(GURL("file:///tmp/test.html")));
 }
 
-TEST(NetUtilTest, GetAddressFamily) {
-  IPAddressNumber number;
-  EXPECT_TRUE(ParseIPLiteralToNumber("192.168.0.1", &number));
-  EXPECT_EQ(ADDRESS_FAMILY_IPV4, GetAddressFamily(number));
-  EXPECT_TRUE(ParseIPLiteralToNumber("1:abcd::3:4:ff", &number));
-  EXPECT_EQ(ADDRESS_FAMILY_IPV6, GetAddressFamily(number));
-}
-
 TEST(NetUtilTest, IsLocalhost) {
   EXPECT_TRUE(IsLocalhost("localhost"));
   EXPECT_TRUE(IsLocalhost("localHosT"));
diff --git a/net/base/sys_addrinfo.h b/net/base/sys_addrinfo.h
index 62a6317e..78f491c 100644
--- a/net/base/sys_addrinfo.h
+++ b/net/base/sys_addrinfo.h
@@ -10,6 +10,7 @@
 //     getaddrinfo()
 //     freeaddrinfo()
 //     AI_*
+//     AF_*
 //
 // Prefer including this file instead of directly writing the #if / #else,
 // since it avoids duplicating the platform-specific selections.
diff --git a/net/net.gypi b/net/net.gypi
index 6b56678..9d97fd1 100644
--- a/net/net.gypi
+++ b/net/net.gypi
@@ -11,6 +11,7 @@
     # These files must not depend on files listed in sources list in the net
     # target.
     'net_nacl_common_sources' : [
+      'base/address_family.cc',
       'base/address_family.h',
       'base/address_list.cc',
       'base/address_list.h',
@@ -1260,6 +1261,7 @@
       'android/keystore_unittest.cc',
       'android/network_change_notifier_android_unittest.cc',
       'android/traffic_stats_unittest.cc',
+      'base/address_family_unittest.cc',
       'base/address_list_unittest.cc',
       'base/address_tracker_linux_unittest.cc',
       'base/backoff_entry_serializer_unittest.cc',
diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc
index 9288ed0a..d5dc67d5 100644
--- a/net/quic/quic_connection_logger.cc
+++ b/net/quic/quic_connection_logger.cc
@@ -14,7 +14,6 @@
 #include "base/profiler/scoped_tracker.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/values.h"
-#include "net/base/net_util.h"
 #include "net/cert/cert_verify_result.h"
 #include "net/cert/x509_certificate.h"
 #include "net/log/net_log.h"
diff --git a/net/quic/quic_socket_address_coder_test.cc b/net/quic/quic_socket_address_coder_test.cc
index 6a94550d..f8b7884 100644
--- a/net/quic/quic_socket_address_coder_test.cc
+++ b/net/quic/quic_socket_address_coder_test.cc
@@ -4,7 +4,6 @@
 
 #include "net/quic/quic_socket_address_coder.h"
 
-#include "net/base/net_util.h"
 #include "net/base/sys_addrinfo.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/net/socket/tcp_socket_posix.cc b/net/socket/tcp_socket_posix.cc
index e432894..5a0a25fb 100644
--- a/net/socket/tcp_socket_posix.cc
+++ b/net/socket/tcp_socket_posix.cc
@@ -21,7 +21,6 @@
 #include "net/base/io_buffer.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/base/network_activity_monitor.h"
 #include "net/base/network_change_notifier.h"
 #include "net/socket/socket_net_log_params.h"
diff --git a/net/test/url_request/url_request_failed_job.cc b/net/test/url_request/url_request_failed_job.cc
index e4ac6a6..d7c479b 100644
--- a/net/test/url_request/url_request_failed_job.cc
+++ b/net/test/url_request/url_request_failed_job.cc
@@ -97,40 +97,20 @@
 }
 
 void URLRequestFailedJob::Start() {
-  if (phase_ == START) {
-    if (net_error_ != ERR_IO_PENDING) {
-      NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, net_error_));
-      return;
-    }
-    SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
-    return;
-  }
-  response_info_.headers = new net::HttpResponseHeaders("HTTP/1.1 200 OK");
-  NotifyHeadersComplete();
-}
-
-bool URLRequestFailedJob::ReadRawData(IOBuffer* buf,
-                                      int buf_size,
-                                      int* bytes_read) {
-  CHECK(phase_ == READ_SYNC || phase_ == READ_ASYNC);
-  if (net_error_ != ERR_IO_PENDING && phase_ == READ_SYNC) {
-    NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, net_error_));
-    return false;
-  }
-
-  SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
-
-  if (net_error_ == ERR_IO_PENDING)
-    return false;
-
-  DCHECK_EQ(READ_ASYNC, phase_);
-  DCHECK_NE(ERR_IO_PENDING, net_error_);
-
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
-      base::Bind(&URLRequestFailedJob::NotifyDone, weak_factory_.GetWeakPtr(),
-                 URLRequestStatus(URLRequestStatus::FAILED, net_error_)));
-  return false;
+      base::Bind(&URLRequestFailedJob::StartAsync, weak_factory_.GetWeakPtr()));
+}
+
+int URLRequestFailedJob::ReadRawData(IOBuffer* buf, int buf_size) {
+  CHECK(phase_ == READ_SYNC || phase_ == READ_ASYNC);
+  if (net_error_ == ERR_IO_PENDING || phase_ == READ_SYNC)
+    return net_error_;
+
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&URLRequestFailedJob::ReadRawDataComplete,
+                            weak_factory_.GetWeakPtr(), net_error_));
+  return ERR_IO_PENDING;
 }
 
 int URLRequestFailedJob::GetResponseCode() const {
@@ -195,4 +175,17 @@
 URLRequestFailedJob::~URLRequestFailedJob() {
 }
 
+void URLRequestFailedJob::StartAsync() {
+  if (phase_ == START) {
+    if (net_error_ != ERR_IO_PENDING) {
+      NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, net_error_));
+      return;
+    }
+    SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
+    return;
+  }
+  response_info_.headers = new net::HttpResponseHeaders("HTTP/1.1 200 OK");
+  NotifyHeadersComplete();
+}
+
 }  // namespace net
diff --git a/net/test/url_request/url_request_failed_job.h b/net/test/url_request/url_request_failed_job.h
index 0413111..45b1911 100644
--- a/net/test/url_request/url_request_failed_job.h
+++ b/net/test/url_request/url_request_failed_job.h
@@ -39,7 +39,7 @@
 
   // URLRequestJob implementation:
   void Start() override;
-  bool ReadRawData(IOBuffer* buf, int buf_size, int* bytes_read) override;
+  int ReadRawData(IOBuffer* buf, int buf_size) override;
   int GetResponseCode() const override;
   void GetResponseInfo(HttpResponseInfo* info) override;
 
@@ -71,6 +71,7 @@
 
  protected:
   ~URLRequestFailedJob() override;
+  void StartAsync();
 
  private:
   HttpResponseInfo response_info_;
diff --git a/net/test/url_request/url_request_mock_data_job.cc b/net/test/url_request/url_request_mock_data_job.cc
index 9549242..b9ef385b 100644
--- a/net/test/url_request/url_request_mock_data_job.cc
+++ b/net/test/url_request/url_request_mock_data_job.cc
@@ -104,15 +104,12 @@
 URLRequestMockDataJob::~URLRequestMockDataJob() {
 }
 
-bool URLRequestMockDataJob::ReadRawData(IOBuffer* buf,
-                                        int buf_size,
-                                        int* bytes_read) {
-  DCHECK(bytes_read);
-  *bytes_read = static_cast<int>(
-      std::min(static_cast<size_t>(buf_size), data_.length() - data_offset_));
-  memcpy(buf->data(), data_.c_str() + data_offset_, *bytes_read);
-  data_offset_ += *bytes_read;
-  return true;
+int URLRequestMockDataJob::ReadRawData(IOBuffer* buf, int buf_size) {
+  int bytes_read =
+      std::min(static_cast<size_t>(buf_size), data_.length() - data_offset_);
+  memcpy(buf->data(), data_.c_str() + data_offset_, bytes_read);
+  data_offset_ += bytes_read;
+  return bytes_read;
 }
 
 int URLRequestMockDataJob::GetResponseCode() const {
diff --git a/net/test/url_request/url_request_mock_data_job.h b/net/test/url_request/url_request_mock_data_job.h
index 3d84e37..14ad665 100644
--- a/net/test/url_request/url_request_mock_data_job.h
+++ b/net/test/url_request/url_request_mock_data_job.h
@@ -24,7 +24,7 @@
                         int data_repeat_count);
 
   void Start() override;
-  bool ReadRawData(IOBuffer* buf, int buf_size, int* bytes_read) override;
+  int ReadRawData(IOBuffer* buf, int buf_size) override;
   int GetResponseCode() const override;
   void GetResponseInfo(HttpResponseInfo* info) override;
 
diff --git a/net/test/url_request/url_request_slow_download_job.cc b/net/test/url_request/url_request_slow_download_job.cc
index f344feb..52fd71c 100644
--- a/net/test/url_request/url_request_slow_download_job.cc
+++ b/net/test/url_request/url_request_slow_download_job.cc
@@ -179,39 +179,34 @@
   return REQUEST_COMPLETE;
 }
 
-bool URLRequestSlowDownloadJob::ReadRawData(IOBuffer* buf,
-                                            int buf_size,
-                                            int* bytes_read) {
+int URLRequestSlowDownloadJob::ReadRawData(IOBuffer* buf, int buf_size) {
   if (base::LowerCaseEqualsASCII(kFinishDownloadUrl,
                                  request_->url().spec().c_str()) ||
       base::LowerCaseEqualsASCII(kErrorDownloadUrl,
                                  request_->url().spec().c_str())) {
     VLOG(10) << __FUNCTION__ << " called w/ kFinish/ErrorDownloadUrl.";
-    *bytes_read = 0;
-    return true;
+    return 0;
   }
 
   VLOG(10) << __FUNCTION__ << " called at position " << bytes_already_sent_
            << " in the stream.";
-  ReadStatus status = FillBufferHelper(buf, buf_size, bytes_read);
+  int bytes_read = 0;
+  ReadStatus status = FillBufferHelper(buf, buf_size, &bytes_read);
   switch (status) {
     case BUFFER_FILLED:
-      return true;
+    case REQUEST_COMPLETE:
+      return bytes_read;
     case REQUEST_BLOCKED:
       buffer_ = buf;
       buffer_size_ = buf_size;
-      SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
       base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
           FROM_HERE, base::Bind(&URLRequestSlowDownloadJob::CheckDoneStatus,
                                 weak_factory_.GetWeakPtr()),
           base::TimeDelta::FromMilliseconds(100));
-      return false;
-    case REQUEST_COMPLETE:
-      *bytes_read = 0;
-      return true;
+      return ERR_IO_PENDING;
   }
   NOTREACHED();
-  return true;
+  return OK;
 }
 
 void URLRequestSlowDownloadJob::CheckDoneStatus() {
@@ -223,12 +218,10 @@
         FillBufferHelper(buffer_.get(), buffer_size_, &bytes_written);
     DCHECK_EQ(BUFFER_FILLED, status);
     buffer_ = NULL;  // Release the reference.
-    SetStatus(URLRequestStatus());
-    NotifyReadComplete(bytes_written);
+    ReadRawDataComplete(bytes_written);
   } else if (should_error_download_) {
     VLOG(10) << __FUNCTION__ << " called w/ should_finish_ownload_ set.";
-    NotifyDone(
-        URLRequestStatus(URLRequestStatus::FAILED, ERR_CONNECTION_RESET));
+    ReadRawDataComplete(ERR_CONNECTION_RESET);
   } else {
     base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE, base::Bind(&URLRequestSlowDownloadJob::CheckDoneStatus,
diff --git a/net/test/url_request/url_request_slow_download_job.h b/net/test/url_request/url_request_slow_download_job.h
index 115a6ac..fcd7f661b 100644
--- a/net/test/url_request/url_request_slow_download_job.h
+++ b/net/test/url_request/url_request_slow_download_job.h
@@ -37,7 +37,7 @@
   void Start() override;
   bool GetMimeType(std::string* mime_type) const override;
   void GetResponseInfo(HttpResponseInfo* info) override;
-  bool ReadRawData(IOBuffer* buf, int buf_size, int* bytes_read) override;
+  int ReadRawData(IOBuffer* buf, int buf_size) override;
 
   // Returns the current number of URLRequestSlowDownloadJobs that have
   // not yet completed.
diff --git a/net/tools/quic/quic_socket_utils.cc b/net/tools/quic/quic_socket_utils.cc
index ae55732..3bc0db0 100644
--- a/net/tools/quic/quic_socket_utils.cc
+++ b/net/tools/quic/quic_socket_utils.cc
@@ -12,7 +12,6 @@
 
 #include "base/basictypes.h"
 #include "base/logging.h"
-#include "net/base/net_util.h"
 #include "net/quic/quic_protocol.h"
 
 #ifndef SO_RXQ_OVFL
diff --git a/net/url_request/url_request_context_builder.cc b/net/url_request/url_request_context_builder.cc
index fb7512c3..a7beaa83 100644
--- a/net/url_request/url_request_context_builder.cc
+++ b/net/url_request/url_request_context_builder.cc
@@ -149,7 +149,7 @@
 
   void set_transport_security_persister(
       scoped_ptr<TransportSecurityPersister> transport_security_persister) {
-    transport_security_persister = transport_security_persister.Pass();
+    transport_security_persister_ = transport_security_persister.Pass();
   }
 
  private:
diff --git a/net/url_request/url_request_file_dir_job.cc b/net/url_request/url_request_file_dir_job.cc
index 64597d5..1dafbf2 100644
--- a/net/url_request/url_request_file_dir_job.cc
+++ b/net/url_request/url_request_file_dir_job.cc
@@ -13,7 +13,6 @@
 #include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
 #include "net/base/net_util.h"
 #include "net/url_request/url_request_status.h"
 #include "url/gurl.h"
@@ -66,23 +65,19 @@
   weak_factory_.InvalidateWeakPtrs();
 }
 
-bool URLRequestFileDirJob::ReadRawData(IOBuffer* buf, int buf_size,
-                                       int* bytes_read) {
-  DCHECK(bytes_read);
-  *bytes_read = 0;
-
+int URLRequestFileDirJob::ReadRawData(IOBuffer* buf, int buf_size) {
   if (is_done())
-    return true;
+    return 0;
 
-  if (FillReadBuffer(buf->data(), buf_size, bytes_read))
-    return true;
+  int bytes_read = 0;
+  if (FillReadBuffer(buf->data(), buf_size, &bytes_read))
+    return bytes_read;
 
   // We are waiting for more data
   read_pending_ = true;
   read_buffer_ = buf;
   read_buffer_length_ = buf_size;
-  SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
-  return false;
+  return ERR_IO_PENDING;
 }
 
 bool URLRequestFileDirJob::GetMimeType(std::string* mime_type) const {
@@ -131,40 +126,45 @@
       data.info.GetLastModifiedTime()));
 
   // TODO(darin): coalesce more?
-  CompleteRead();
+  CompleteRead(OK);
 }
 
 void URLRequestFileDirJob::OnListDone(int error) {
   DCHECK(!canceled_);
-  if (error != OK) {
-    read_pending_ = false;
-    NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, error));
-  } else {
+  DCHECK_LE(error, OK);
+  if (error == OK)
     list_complete_ = true;
-    CompleteRead();
-  }
+  CompleteRead(static_cast<Error>(error));
 }
 
 URLRequestFileDirJob::~URLRequestFileDirJob() {}
 
-void URLRequestFileDirJob::CompleteRead() {
-  if (read_pending_) {
-    int bytes_read;
+void URLRequestFileDirJob::CompleteRead(Error status) {
+  DCHECK_LE(status, OK);
+  DCHECK_NE(status, ERR_IO_PENDING);
+
+  // Do nothing if there is no read pending.
+  if (!read_pending_)
+    return;
+
+  int result = status;
+  if (status == OK) {
+    int filled_bytes = 0;
     if (FillReadBuffer(read_buffer_->data(), read_buffer_length_,
-                       &bytes_read)) {
+                       &filled_bytes)) {
+      result = filled_bytes;
       // We completed the read, so reset the read buffer.
-      read_pending_ = false;
       read_buffer_ = NULL;
       read_buffer_length_ = 0;
-
-      SetStatus(URLRequestStatus());
-      NotifyReadComplete(bytes_read);
     } else {
       NOTREACHED();
       // TODO: Better error code.
-      NotifyDone(URLRequestStatus::FromError(ERR_FAILED));
+      result = ERR_FAILED;
     }
   }
+
+  read_pending_ = false;
+  ReadRawDataComplete(result);
 }
 
 bool URLRequestFileDirJob::FillReadBuffer(char* buf, int buf_size,
diff --git a/net/url_request/url_request_file_dir_job.h b/net/url_request/url_request_file_dir_job.h
index dfb2d74..f7a7b45 100644
--- a/net/url_request/url_request_file_dir_job.h
+++ b/net/url_request/url_request_file_dir_job.h
@@ -10,6 +10,7 @@
 #include "base/files/file_path.h"
 #include "base/memory/weak_ptr.h"
 #include "net/base/directory_lister.h"
+#include "net/base/net_errors.h"
 #include "net/url_request/url_request_job.h"
 
 namespace net {
@@ -29,7 +30,7 @@
   // Overridden from URLRequestJob:
   void Start() override;
   void Kill() override;
-  bool ReadRawData(IOBuffer* buf, int buf_size, int* bytes_read) override;
+  int ReadRawData(IOBuffer* buf, int buf_size) override;
   bool GetMimeType(std::string* mime_type) const override;
   bool GetCharset(std::string* charset) override;
 
@@ -45,10 +46,10 @@
   // When we have data and a read has been pending, this function
   // will fill the response buffer and notify the request
   // appropriately.
-  void CompleteRead();
+  void CompleteRead(Error error);
 
   // Fills a buffer with the output.
-  bool FillReadBuffer(char *buf, int buf_size, int *bytes_read);
+  bool FillReadBuffer(char* buf, int buf_size, int* bytes_read);
 
   DirectoryLister lister_;
   base::FilePath dir_path_;
@@ -67,6 +68,7 @@
   bool read_pending_;
   scoped_refptr<IOBuffer> read_buffer_;
   int read_buffer_length_;
+
   base::WeakPtrFactory<URLRequestFileDirJob> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(URLRequestFileDirJob);
diff --git a/net/url_request/url_request_file_job.cc b/net/url_request/url_request_file_job.cc
index b035c0d..2c5cf6a 100644
--- a/net/url_request/url_request_file_job.cc
+++ b/net/url_request/url_request_file_job.cc
@@ -33,7 +33,6 @@
 #include "net/base/io_buffer.h"
 #include "net/base/load_flags.h"
 #include "net/base/mime_util.h"
-#include "net/base/net_errors.h"
 #include "net/filter/filter.h"
 #include "net/http/http_util.h"
 #include "net/url_request/url_request_error_job.h"
@@ -63,6 +62,7 @@
       stream_(new FileStream(file_task_runner)),
       file_task_runner_(file_task_runner),
       remaining_bytes_(0),
+      range_parse_result_(OK),
       weak_ptr_factory_(this) {}
 
 void URLRequestFileJob::Start() {
@@ -83,22 +83,17 @@
   URLRequestJob::Kill();
 }
 
-bool URLRequestFileJob::ReadRawData(IOBuffer* dest,
-                                    int dest_size,
-                                    int* bytes_read) {
+int URLRequestFileJob::ReadRawData(IOBuffer* dest, int dest_size) {
   DCHECK_NE(dest_size, 0);
-  DCHECK(bytes_read);
   DCHECK_GE(remaining_bytes_, 0);
 
   if (remaining_bytes_ < dest_size)
-    dest_size = static_cast<int>(remaining_bytes_);
+    dest_size = remaining_bytes_;
 
   // If we should copy zero bytes because |remaining_bytes_| is zero, short
   // circuit here.
-  if (!dest_size) {
-    *bytes_read = 0;
-    return true;
-  }
+  if (!dest_size)
+    return 0;
 
   int rv = stream_->Read(dest,
                          dest_size,
@@ -106,20 +101,11 @@
                                     weak_ptr_factory_.GetWeakPtr(),
                                     make_scoped_refptr(dest)));
   if (rv >= 0) {
-    // Data is immediately available.
-    *bytes_read = rv;
     remaining_bytes_ -= rv;
     DCHECK_GE(remaining_bytes_, 0);
-    return true;
   }
 
-  // Otherwise, a read error occured.  We may just need to wait...
-  if (rv == ERR_IO_PENDING) {
-    SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
-  } else {
-    NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv));
-  }
-  return false;
+  return rv;
 }
 
 bool URLRequestFileJob::IsRedirectResponse(GURL* location,
@@ -179,7 +165,10 @@
     const HttpRequestHeaders& headers) {
   std::string range_header;
   if (headers.GetHeader(HttpRequestHeaders::kRange, &range_header)) {
-    // We only care about "Range" header here.
+    // This job only cares about the Range header. This method stashes the value
+    // for later use in DidOpen(), which is responsible for some of the range
+    // validation as well. NotifyStartError is not legal to call here since
+    // the job has not started.
     std::vector<HttpByteRange> ranges;
     if (HttpUtil::ParseRangeHeader(range_header, &ranges)) {
       if (ranges.size() == 1) {
@@ -189,8 +178,7 @@
         // because we need to do multipart encoding here.
         // TODO(hclam): decide whether we want to support multiple range
         // requests.
-        NotifyDone(URLRequestStatus(URLRequestStatus::FAILED,
-                                    ERR_REQUEST_RANGE_NOT_SATISFIABLE));
+        range_parse_result_ = net::ERR_REQUEST_RANGE_NOT_SATISFIABLE;
       }
     }
   }
@@ -251,13 +239,19 @@
 
 void URLRequestFileJob::DidOpen(int result) {
   if (result != OK) {
-    NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, result));
+    NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, result));
+    return;
+  }
+
+  if (range_parse_result_ != net::OK) {
+    NotifyStartError(
+        URLRequestStatus(URLRequestStatus::FAILED, range_parse_result_));
     return;
   }
 
   if (!byte_range_.ComputeBounds(meta_info_.file_size)) {
-    NotifyDone(URLRequestStatus(URLRequestStatus::FAILED,
-               ERR_REQUEST_RANGE_NOT_SATISFIABLE));
+    NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED,
+                                      net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
     return;
   }
 
@@ -285,8 +279,8 @@
 void URLRequestFileJob::DidSeek(int64 result) {
   OnSeekComplete(result);
   if (result != byte_range_.first_byte_position()) {
-    NotifyDone(URLRequestStatus(URLRequestStatus::FAILED,
-                                ERR_REQUEST_RANGE_NOT_SATISFIABLE));
+    NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED,
+                                      ERR_REQUEST_RANGE_NOT_SATISFIABLE));
     return;
   }
 
@@ -295,8 +289,7 @@
 }
 
 void URLRequestFileJob::DidRead(scoped_refptr<IOBuffer> buf, int result) {
-  if (result > 0) {
-    SetStatus(URLRequestStatus());  // Clear the IO_PENDING status
+  if (result >= 0) {
     remaining_bytes_ -= result;
     DCHECK_GE(remaining_bytes_, 0);
   }
@@ -304,13 +297,7 @@
   OnReadComplete(buf.get(), result);
   buf = NULL;
 
-  if (result == 0) {
-    NotifyDone(URLRequestStatus());
-  } else if (result < 0) {
-    NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, result));
-  }
-
-  NotifyReadComplete(result);
+  ReadRawDataComplete(result);
 }
 
 }  // namespace net
diff --git a/net/url_request/url_request_file_job.h b/net/url_request/url_request_file_job.h
index 0436dac5..97c6c21 100644
--- a/net/url_request/url_request_file_job.h
+++ b/net/url_request/url_request_file_job.h
@@ -11,6 +11,7 @@
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "net/base/net_errors.h"
 #include "net/base/net_export.h"
 #include "net/http/http_byte_range.h"
 #include "net/url_request/url_request.h"
@@ -38,7 +39,7 @@
   // URLRequestJob:
   void Start() override;
   void Kill() override;
-  bool ReadRawData(IOBuffer* buf, int buf_size, int* bytes_read) override;
+  int ReadRawData(IOBuffer* buf, int buf_size) override;
   bool IsRedirectResponse(GURL* location, int* http_status_code) override;
   Filter* SetupFilter() const override;
   bool GetMimeType(std::string* mime_type) const override;
@@ -97,9 +98,12 @@
   FileMetaInfo meta_info_;
   const scoped_refptr<base::TaskRunner> file_task_runner_;
 
+  std::vector<HttpByteRange> byte_ranges_;
   HttpByteRange byte_range_;
   int64 remaining_bytes_;
 
+  Error range_parse_result_;
+
   base::WeakPtrFactory<URLRequestFileJob> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(URLRequestFileJob);
diff --git a/net/url_request/url_request_ftp_job.cc b/net/url_request/url_request_ftp_job.cc
index 0d3eb25..e422d03 100644
--- a/net/url_request/url_request_ftp_job.cc
+++ b/net/url_request/url_request_ftp_job.cc
@@ -239,7 +239,7 @@
     HandleAuthNeededResponse();
     return;
   } else {
-    NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, result));
+    NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, result));
   }
 }
 
@@ -251,15 +251,7 @@
 
 void URLRequestFtpJob::OnReadCompleted(int result) {
   read_in_progress_ = false;
-  if (result == 0) {
-    NotifyDone(URLRequestStatus());
-  } else if (result < 0) {
-    NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, result));
-  } else {
-    // Clear the IO_PENDING status
-    SetStatus(URLRequestStatus());
-  }
-  NotifyReadComplete(result);
+  ReadRawDataComplete(result);
 }
 
 void URLRequestFtpJob::RestartTransactionWithAuth() {
@@ -352,14 +344,12 @@
   return UploadProgress();
 }
 
-bool URLRequestFtpJob::ReadRawData(IOBuffer* buf,
-                                   int buf_size,
-                                   int *bytes_read) {
+int URLRequestFtpJob::ReadRawData(IOBuffer* buf, int buf_size) {
   DCHECK_NE(buf_size, 0);
-  DCHECK(bytes_read);
   DCHECK(!read_in_progress_);
 
   int rv;
+
   if (proxy_info_.is_direct()) {
     rv = ftp_transaction_->Read(buf, buf_size,
                                 base::Bind(&URLRequestFtpJob::OnReadCompleted,
@@ -370,18 +360,9 @@
                                             base::Unretained(this)));
   }
 
-  if (rv >= 0) {
-    *bytes_read = rv;
-    return true;
-  }
-
-  if (rv == ERR_IO_PENDING) {
+  if (rv == ERR_IO_PENDING)
     read_in_progress_ = true;
-    SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
-  } else {
-    NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv));
-  }
-  return false;
+  return rv;
 }
 
 void URLRequestFtpJob::HandleAuthNeededResponse() {
diff --git a/net/url_request/url_request_ftp_job.h b/net/url_request/url_request_ftp_job.h
index 74caf726..6315d8f 100644
--- a/net/url_request/url_request_ftp_job.h
+++ b/net/url_request/url_request_ftp_job.h
@@ -71,7 +71,7 @@
 
   // TODO(ibrar):  Yet to give another look at this function.
   UploadProgress GetUploadProgress() const override;
-  bool ReadRawData(IOBuffer* buf, int buf_size, int* bytes_read) override;
+  int ReadRawData(IOBuffer* buf, int buf_size) override;
 
   void HandleAuthNeededResponse();
 
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index b34f825..13365df 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -414,11 +414,6 @@
   URLRequestJob::NotifyHeadersComplete();
 }
 
-void URLRequestHttpJob::NotifyDone(const URLRequestStatus& status) {
-  DoneWithRequest(FINISHED);
-  URLRequestJob::NotifyDone(status);
-}
-
 void URLRequestHttpJob::DestroyTransaction() {
   DCHECK(transaction_.get());
 
@@ -998,19 +993,16 @@
 void URLRequestHttpJob::OnReadCompleted(int result) {
   read_in_progress_ = false;
 
+  DCHECK_NE(ERR_IO_PENDING, result);
+
   if (ShouldFixMismatchedContentLength(result))
     result = OK;
 
-  if (result == OK) {
-    NotifyDone(URLRequestStatus());
-  } else if (result < 0) {
-    NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, result));
-  } else {
-    // Clear the IO_PENDING status
-    SetStatus(URLRequestStatus());
-  }
+  // EOF or error, done with this job.
+  if (result <= 0)
+    DoneWithRequest(FINISHED);
 
-  NotifyReadComplete(result);
+  ReadRawDataComplete(result);
 }
 
 void URLRequestHttpJob::RestartTransactionWithAuth(
@@ -1334,10 +1326,8 @@
   return false;
 }
 
-bool URLRequestHttpJob::ReadRawData(IOBuffer* buf, int buf_size,
-                                    int* bytes_read) {
+int URLRequestHttpJob::ReadRawData(IOBuffer* buf, int buf_size) {
   DCHECK_NE(buf_size, 0);
-  DCHECK(bytes_read);
   DCHECK(!read_in_progress_);
 
   int rv = transaction_->Read(
@@ -1345,23 +1335,15 @@
       base::Bind(&URLRequestHttpJob::OnReadCompleted, base::Unretained(this)));
 
   if (ShouldFixMismatchedContentLength(rv))
-    rv = 0;
+    rv = OK;
 
-  if (rv >= 0) {
-    *bytes_read = rv;
-    if (!rv)
-      DoneWithRequest(FINISHED);
-    return true;
-  }
+  if (rv == 0 || (rv < 0 && rv != ERR_IO_PENDING))
+    DoneWithRequest(FINISHED);
 
-  if (rv == ERR_IO_PENDING) {
+  if (rv == ERR_IO_PENDING)
     read_in_progress_ = true;
-    SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
-  } else {
-    NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv));
-  }
 
-  return false;
+  return rv;
 }
 
 void URLRequestHttpJob::StopCaching() {
diff --git a/net/url_request/url_request_http_job.h b/net/url_request/url_request_http_job.h
index 4ee4440..f9ce401 100644
--- a/net/url_request/url_request_http_job.h
+++ b/net/url_request/url_request_http_job.h
@@ -78,9 +78,6 @@
   // Shadows URLRequestJob's version of this method so we can grab cookies.
   void NotifyHeadersComplete();
 
-  // Shadows URLRequestJob's method so we can record histograms.
-  void NotifyDone(const URLRequestStatus& status);
-
   void DestroyTransaction();
 
   void AddExtraHeaders();
@@ -131,7 +128,7 @@
   void ContinueWithCertificate(X509Certificate* client_cert) override;
   void ContinueDespiteLastError() override;
   void ResumeNetworkStart() override;
-  bool ReadRawData(IOBuffer* buf, int buf_size, int* bytes_read) override;
+  int ReadRawData(IOBuffer* buf, int buf_size) override;
   void StopCaching() override;
   bool GetFullRequestHeaders(HttpRequestHeaders* headers) const override;
   int64 GetTotalReceivedBytes() const override;
diff --git a/net/url_request/url_request_job.cc b/net/url_request/url_request_job.cc
index 641c07b..14ae8e5d 100644
--- a/net/url_request/url_request_job.cc
+++ b/net/url_request/url_request_job.cc
@@ -101,45 +101,46 @@
   request_ = NULL;
 }
 
-// This function calls ReadData to get stream data. If a filter exists, passes
-// the data to the attached filter. Then returns the output from filter back to
-// the caller.
+// This function calls ReadRawData to get stream data. If a filter exists, it
+// passes the data to the attached filter. It then returns the output from
+// filter back to the caller.
 bool URLRequestJob::Read(IOBuffer* buf, int buf_size, int *bytes_read) {
-  bool rv = false;
-
   DCHECK_LT(buf_size, 1000000);  // Sanity check.
   DCHECK(buf);
   DCHECK(bytes_read);
   DCHECK(filtered_read_buffer_.get() == NULL);
   DCHECK_EQ(0, filtered_read_buffer_len_);
 
+  Error error = OK;
   *bytes_read = 0;
 
   // Skip Filter if not present.
-  if (!filter_.get()) {
-    rv = ReadRawDataHelper(buf, buf_size, bytes_read);
+  if (!filter_) {
+    error = ReadRawDataHelper(buf, buf_size, bytes_read);
   } else {
     // Save the caller's buffers while we do IO
     // in the filter's buffers.
     filtered_read_buffer_ = buf;
     filtered_read_buffer_len_ = buf_size;
 
-    if (ReadFilteredData(bytes_read)) {
-      rv = true;   // We have data to return.
+    error = ReadFilteredData(bytes_read);
 
-      // It is fine to call DoneReading even if ReadFilteredData receives 0
-      // bytes from the net, but we avoid making that call if we know for
-      // sure that's the case (ReadRawDataHelper path).
-      if (*bytes_read == 0)
-        DoneReading();
-    } else {
-      rv = false;  // Error, or a new IO is pending.
-    }
+    // Synchronous EOF from the filter.
+    if (error == OK && *bytes_read == 0)
+      DoneReading();
   }
 
-  if (rv && *bytes_read == 0)
-    NotifyDone(URLRequestStatus());
-  return rv;
+  if (error == OK) {
+    // If URLRequestJob read zero bytes, the job is at EOF.
+    if (*bytes_read == 0)
+      NotifyDone(URLRequestStatus());
+  } else if (error == ERR_IO_PENDING) {
+    SetStatus(URLRequestStatus::FromError(ERR_IO_PENDING));
+  } else {
+    NotifyDone(URLRequestStatus::FromError(error));
+    *bytes_read = -1;
+  }
+  return error == OK;
 }
 
 void URLRequestJob::StopCaching() {
@@ -480,11 +481,25 @@
   request_->NotifyResponseStarted();
 }
 
-void URLRequestJob::NotifyReadComplete(int bytes_read) {
+void URLRequestJob::ConvertResultToError(int result, Error* error, int* count) {
+  if (result >= 0) {
+    *error = OK;
+    *count = result;
+  } else {
+    *error = static_cast<Error>(result);
+    *count = 0;
+  }
+}
+
+void URLRequestJob::ReadRawDataComplete(int result) {
   // TODO(cbentzel): Remove ScopedTracker below once crbug.com/475755 is fixed.
   tracked_objects::ScopedTracker tracking_profile(
       FROM_HERE_WITH_EXPLICIT_FUNCTION(
-          "475755 URLRequestJob::NotifyReadComplete"));
+          "475755 URLRequestJob::RawReadCompleted"));
+
+  Error error;
+  int bytes_read;
+  ConvertResultToError(result, &error, &bytes_read);
 
   if (!request_ || !request_->has_delegate())
     return;  // The request was destroyed, so there is no more work to do.
@@ -497,11 +512,32 @@
   // The headers should be complete before reads complete
   DCHECK(has_handled_response_);
 
-  OnRawReadComplete(bytes_read);
+  GatherRawReadStats(error, bytes_read);
 
-  // Don't notify if we had an error.
-  if (!request_->status().is_success())
-    return;
+  if (filter_.get() && error == OK) {
+    int filter_bytes_read = 0;
+    // Tell the filter that it has more data.
+    PushInputToFilter(bytes_read);
+
+    // Filter the data.
+    error = ReadFilteredData(&filter_bytes_read);
+
+    if (!filter_bytes_read)
+      DoneReading();
+
+    DVLOG(1) << __FUNCTION__ << "() "
+             << "\"" << (request_ ? request_->url().spec() : "???") << "\""
+             << " pre bytes read = " << bytes_read
+             << " pre total = " << prefilter_bytes_read_
+             << " post total = " << postfilter_bytes_read_;
+    bytes_read = filter_bytes_read;
+  } else {
+    DVLOG(1) << __FUNCTION__ << "() "
+             << "\"" << (request_ ? request_->url().spec() : "???") << "\""
+             << " pre bytes read = " << bytes_read
+             << " pre total = " << prefilter_bytes_read_
+             << " post total = " << postfilter_bytes_read_;
+  }
 
   // When notifying the delegate, the delegate can release the request
   // (and thus release 'this').  After calling to the delegate, we must
@@ -510,25 +546,24 @@
   // survival until we can get out of this method.
   scoped_refptr<URLRequestJob> self_preservation(this);
 
-  if (filter_.get()) {
-    // Tell the filter that it has more data
-    FilteredDataRead(bytes_read);
-
-    // Filter the data.
-    int filter_bytes_read = 0;
-    if (ReadFilteredData(&filter_bytes_read)) {
-      if (!filter_bytes_read)
-        DoneReading();
-      request_->NotifyReadCompleted(filter_bytes_read);
-    }
+  // Synchronize the URLRequest state machine with the URLRequestJob state
+  // machine. If this read succeeded, either the request is at EOF and the
+  // URLRequest state machine goes to 'finished', or it is not and the
+  // URLRequest state machine goes to 'success'. If the read failed, the
+  // URLRequest state machine goes directly to 'finished'.
+  //
+  // Update the URLRequest's status first, so that NotifyReadCompleted has an
+  // accurate view of the request.
+  if (error == OK && bytes_read > 0) {
+    SetStatus(URLRequestStatus());
   } else {
-    request_->NotifyReadCompleted(bytes_read);
+    NotifyDone(URLRequestStatus::FromError(error));
   }
-  DVLOG(1) << __FUNCTION__ << "() "
-           << "\"" << (request_ ? request_->url().spec() : "???") << "\""
-           << " pre bytes read = " << bytes_read
-           << " pre total = " << prefilter_bytes_read_
-           << " post total = " << postfilter_bytes_read_;
+
+  // NotifyReadCompleted should be called after SetStatus or NotifyDone updates
+  // the status.
+  if (error == OK)
+    request_->NotifyReadCompleted(bytes_read);
 }
 
 void URLRequestJob::NotifyStartError(const URLRequestStatus &status) {
@@ -555,7 +590,7 @@
   // the response before getting here.
   DCHECK(has_handled_response_ || !status.is_success());
 
-  // As with NotifyReadComplete, we need to take care to notice if we were
+  // As with RawReadCompleted, we need to take care to notice if we were
   // destroyed during a delegate callback.
   if (request_) {
     request_->set_is_pending(false);
@@ -638,11 +673,8 @@
   request_->OnCallToDelegateComplete();
 }
 
-bool URLRequestJob::ReadRawData(IOBuffer* buf, int buf_size,
-                                int *bytes_read) {
-  DCHECK(bytes_read);
-  *bytes_read = 0;
-  return true;
+int URLRequestJob::ReadRawData(IOBuffer* buf, int buf_size) {
+  return 0;
 }
 
 void URLRequestJob::DoneReading() {
@@ -652,38 +684,34 @@
 void URLRequestJob::DoneReadingRedirectResponse() {
 }
 
-void URLRequestJob::FilteredDataRead(int bytes_read) {
+void URLRequestJob::PushInputToFilter(int bytes_read) {
   DCHECK(filter_);
   filter_->FlushStreamBuffer(bytes_read);
 }
 
-bool URLRequestJob::ReadFilteredData(int* bytes_read) {
+Error URLRequestJob::ReadFilteredData(int* bytes_read) {
   DCHECK(filter_);
   DCHECK(filtered_read_buffer_.get());
   DCHECK_GT(filtered_read_buffer_len_, 0);
   DCHECK_LT(filtered_read_buffer_len_, 1000000);  // Sanity check.
-  DCHECK(!raw_read_buffer_.get());
+  DCHECK(!raw_read_buffer_);
 
   *bytes_read = 0;
-  bool rv = false;
+  Error error = ERR_FAILED;
 
   for (;;) {
     if (is_done())
-      return true;
+      return OK;
 
     if (!filter_needs_more_output_space_ && !filter_->stream_data_len()) {
       // We don't have any raw data to work with, so read from the transaction.
       int filtered_data_read;
-      if (ReadRawDataForFilter(&filtered_data_read)) {
-        if (filtered_data_read > 0) {
-          // Give data to filter.
-          filter_->FlushStreamBuffer(filtered_data_read);
-        } else {
-          return true;  // EOF.
-        }
-      } else {
-        return false;  // IO Pending (or error).
-      }
+      error = ReadRawDataForFilter(&filtered_data_read);
+      // If ReadRawDataForFilter returned some data, fall through to the case
+      // below; otherwise, return early.
+      if (error != OK || filtered_data_read == 0)
+        return error;
+      filter_->FlushStreamBuffer(filtered_data_read);
     }
 
     if ((filter_->stream_data_len() || filter_needs_more_output_space_) &&
@@ -709,7 +737,7 @@
           filter_needs_more_output_space_ = false;
           *bytes_read = filtered_data_len;
           postfilter_bytes_read_ += filtered_data_len;
-          rv = true;
+          error = OK;
           break;
         }
         case Filter::FILTER_NEED_MORE_DATA: {
@@ -722,7 +750,7 @@
           if (filtered_data_len > 0) {
             *bytes_read = filtered_data_len;
             postfilter_bytes_read_ += filtered_data_len;
-            rv = true;
+            error = OK;
           } else {
             // Read again since we haven't received enough data yet (e.g., we
             // may not have a complete gzip header yet).
@@ -733,7 +761,7 @@
         case Filter::FILTER_OK: {
           *bytes_read = filtered_data_len;
           postfilter_bytes_read_ += filtered_data_len;
-          rv = true;
+          error = OK;
           break;
         }
         case Filter::FILTER_ERROR: {
@@ -741,21 +769,19 @@
                    << "\"" << (request_ ? request_->url().spec() : "???")
                    << "\"" << " Filter Error";
           filter_needs_more_output_space_ = false;
-          NotifyDone(URLRequestStatus(URLRequestStatus::FAILED,
-                     ERR_CONTENT_DECODING_FAILED));
-          rv = false;
+          error = ERR_CONTENT_DECODING_FAILED;
           break;
         }
         default: {
           NOTREACHED();
           filter_needs_more_output_space_ = false;
-          rv = false;
+          error = ERR_FAILED;
           break;
         }
       }
 
       // If logging all bytes is enabled, log the filtered bytes read.
-      if (rv && request() && filtered_data_len > 0 &&
+      if (error == OK && request() && filtered_data_len > 0 &&
           request()->net_log().IsCapturing()) {
         request()->net_log().AddByteTransferEvent(
             NetLog::TYPE_URL_REQUEST_JOB_FILTERED_BYTES_READ, filtered_data_len,
@@ -763,18 +789,18 @@
       }
     } else {
       // we are done, or there is no data left.
-      rv = true;
+      error = OK;
     }
     break;
   }
 
-  if (rv) {
+  if (error == OK) {
     // When we successfully finished a read, we no longer need to save the
     // caller's buffers. Release our reference.
     filtered_read_buffer_ = NULL;
     filtered_read_buffer_len_ = 0;
   }
-  return rv;
+  return error;
 }
 
 void URLRequestJob::DestroyFilters() {
@@ -807,9 +833,8 @@
   request_->proxy_server_ = proxy_server;
 }
 
-bool URLRequestJob::ReadRawDataForFilter(int* bytes_read) {
-  bool rv = false;
-
+Error URLRequestJob::ReadRawDataForFilter(int* bytes_read) {
+  Error error = ERR_FAILED;
   DCHECK(bytes_read);
   DCHECK(filter_.get());
 
@@ -821,29 +846,28 @@
   if (!filter_->stream_data_len() && !is_done()) {
     IOBuffer* stream_buffer = filter_->stream_buffer();
     int stream_buffer_size = filter_->stream_buffer_size();
-    rv = ReadRawDataHelper(stream_buffer, stream_buffer_size, bytes_read);
+    error = ReadRawDataHelper(stream_buffer, stream_buffer_size, bytes_read);
   }
-  return rv;
+  return error;
 }
 
-bool URLRequestJob::ReadRawDataHelper(IOBuffer* buf, int buf_size,
-                                      int* bytes_read) {
-  DCHECK(!request_->status().is_io_pending());
-  DCHECK(raw_read_buffer_.get() == NULL);
+Error URLRequestJob::ReadRawDataHelper(IOBuffer* buf,
+                                       int buf_size,
+                                       int* bytes_read) {
+  DCHECK(!raw_read_buffer_);
 
-  // Keep a pointer to the read buffer, so we have access to it in the
-  // OnRawReadComplete() callback in the event that the read completes
-  // asynchronously.
+  // Keep a pointer to the read buffer, so we have access to it in
+  // GatherRawReadStats() in the event that the read completes asynchronously.
   raw_read_buffer_ = buf;
-  bool rv = ReadRawData(buf, buf_size, bytes_read);
+  Error error;
+  ConvertResultToError(ReadRawData(buf, buf_size), &error, bytes_read);
 
-  if (!request_->status().is_io_pending()) {
-    // If the read completes synchronously, either success or failure,
-    // invoke the OnRawReadComplete callback so we can account for the
-    // completed read.
-    OnRawReadComplete(*bytes_read);
+  if (error != ERR_IO_PENDING) {
+    // If the read completes synchronously, either success or failure, invoke
+    // GatherRawReadStats so we can account for the completed read.
+    GatherRawReadStats(error, *bytes_read);
   }
-  return rv;
+  return error;
 }
 
 void URLRequestJob::FollowRedirect(const RedirectInfo& redirect_info) {
@@ -852,20 +876,27 @@
     NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv));
 }
 
-void URLRequestJob::OnRawReadComplete(int bytes_read) {
-  DCHECK(raw_read_buffer_.get());
-  // If |filter_| is non-NULL, bytes will be logged after it is applied instead.
+void URLRequestJob::GatherRawReadStats(Error error, int bytes_read) {
+  DCHECK(raw_read_buffer_ || bytes_read == 0);
+  DCHECK_NE(ERR_IO_PENDING, error);
+
+  if (error != OK) {
+    raw_read_buffer_ = nullptr;
+    return;
+  }
+  // If |filter_| is non-NULL, bytes will be logged after it is applied
+  // instead.
   if (!filter_.get() && request() && bytes_read > 0 &&
       request()->net_log().IsCapturing()) {
     request()->net_log().AddByteTransferEvent(
-        NetLog::TYPE_URL_REQUEST_JOB_BYTES_READ,
-        bytes_read, raw_read_buffer_->data());
+        NetLog::TYPE_URL_REQUEST_JOB_BYTES_READ, bytes_read,
+        raw_read_buffer_->data());
   }
 
   if (bytes_read > 0) {
     RecordBytesRead(bytes_read);
   }
-  raw_read_buffer_ = NULL;
+  raw_read_buffer_ = nullptr;
 }
 
 void URLRequestJob::RecordBytesRead(int bytes_read) {
diff --git a/net/url_request/url_request_job.h b/net/url_request/url_request_job.h
index 82b13633c..002dc62 100644
--- a/net/url_request/url_request_job.h
+++ b/net/url_request/url_request_job.h
@@ -17,6 +17,7 @@
 #include "base/power_monitor/power_observer.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/load_states.h"
+#include "net/base/net_errors.h"
 #include "net/base/net_export.h"
 #include "net/base/request_priority.h"
 #include "net/base/upload_progress.h"
@@ -276,23 +277,9 @@
   // Notifies the job that headers have been received.
   void NotifyHeadersComplete();
 
-  // Notifies the request that the job has completed a Read operation.
-  void NotifyReadComplete(int bytes_read);
-
   // Notifies the request that a start error has occurred.
   void NotifyStartError(const URLRequestStatus& status);
 
-  // NotifyDone marks when we are done with a request.  It is really
-  // a glorified set_status, but also does internal state checking and
-  // job tracking.  It should be called once per request, when the job is
-  // finished doing all IO.
-  void NotifyDone(const URLRequestStatus& status);
-
-  // Some work performed by NotifyDone must be completed on a separate task
-  // so as to avoid re-entering the delegate.  This method exists to perform
-  // that work.
-  void CompleteNotifyDone();
-
   // Used as an asynchronous callback for Kill to notify the URLRequest
   // that we were canceled.
   void NotifyCanceled();
@@ -305,17 +292,19 @@
   void OnCallToDelegate();
   void OnCallToDelegateComplete();
 
-  // Called to read raw (pre-filtered) data from this Job.
-  // If returning true, data was read from the job.  buf will contain
-  // the data, and bytes_read will receive the number of bytes read.
-  // If returning true, and bytes_read is returned as 0, there is no
-  // additional data to be read.
-  // If returning false, an error occurred or an async IO is now pending.
-  // If async IO is pending, the status of the request will be
-  // URLRequestStatus::IO_PENDING, and buf must remain available until the
-  // operation is completed.  See comments on URLRequest::Read for more
-  // info.
-  virtual bool ReadRawData(IOBuffer* buf, int buf_size, int *bytes_read);
+  // Called to read raw (pre-filtered) data from this Job. Reads at most
+  // |buf_size| bytes into |buf|.
+  // Possible return values:
+  //   >= 0: Read completed synchronously. Return value is the number of bytes
+  //         read. 0 means eof.
+  //   ERR_IO_PENDING: Read pending asynchronously.
+  //                   When the read completes, |ReadRawDataComplete| should be
+  //                   called.
+  //   Any other negative number: Read failed synchronously. Return value is a
+  //                   network error code.
+  // This method might hold onto a reference to |buf| (by incrementing the
+  // refcount) until the method completes or is cancelled.
+  virtual int ReadRawData(IOBuffer* buf, int buf_size);
 
   // Called to tell the job that a filter has successfully reached the end of
   // the stream.
@@ -326,14 +315,14 @@
   // bodies are never read.
   virtual void DoneReadingRedirectResponse();
 
-  // Informs the filter that data has been read into its buffer
-  void FilteredDataRead(int bytes_read);
-
-  // Reads filtered data from the request.  Returns true if successful,
-  // false otherwise.  Note, if there is not enough data received to
-  // return data, this call can issue a new async IO request under
-  // the hood.
-  bool ReadFilteredData(int *bytes_read);
+  // Reads filtered data from the request. Returns OK if immediately successful,
+  // ERR_IO_PENDING if the request couldn't complete synchronously, and some
+  // other error code if the request failed synchronously. Note that this
+  // function can issue new asynchronous requests if needed, in which case it
+  // returns ERR_IO_PENDING. If this method completes synchronously,
+  // |*bytes_read| is the number of bytes output by the filter chain if this
+  // method returns OK, or zero if this method returns an error.
+  Error ReadFilteredData(int* bytes_read);
 
   // Whether the response is being filtered in this job.
   // Only valid after NotifyHeadersComplete() has been called.
@@ -365,19 +354,33 @@
   // reflects bytes read even when there is no filter.
   int64 postfilter_bytes_read() const { return postfilter_bytes_read_; }
 
+  // Turns an integer result code into an Error and a count of bytes read.
+  // The semantics are:
+  //   |result| >= 0: |*error| == OK, |*count| == |result|
+  //   |result| < 0: |*error| = |result|, |*count| == 0
+  static void ConvertResultToError(int result, Error* error, int* count);
+
+  // Completion callback for raw reads. See |ReadRawData| for details.
+  // |bytes_read| is either >= 0 to indicate a successful read and count of
+  // bytes read, or < 0 to indicate an error.
+  void ReadRawDataComplete(int bytes_read);
+
   // The request that initiated this job. This value MAY BE NULL if the
   // request was released by DetachRequest().
   URLRequest* request_;
 
  private:
   // When data filtering is enabled, this function is used to read data
-  // for the filter.  Returns true if raw data was read.  Returns false if
-  // an error occurred (or we are waiting for IO to complete).
-  bool ReadRawDataForFilter(int *bytes_read);
+  // for the filter. Returns a net error code to indicate if raw data was
+  // successfully read,  an error happened, or the IO is pending.
+  Error ReadRawDataForFilter(int* bytes_read);
+
+  // Informs the filter chain that data has been read into its buffer.
+  void PushInputToFilter(int bytes_read);
 
   // Invokes ReadRawData and records bytes read if the read completes
   // synchronously.
-  bool ReadRawDataHelper(IOBuffer* buf, int buf_size, int* bytes_read);
+  Error ReadRawDataHelper(IOBuffer* buf, int buf_size, int* bytes_read);
 
   // Called in response to a redirect that was not canceled to follow the
   // redirect. The current job will be replaced with a new job loading the
@@ -386,9 +389,9 @@
 
   // Called after every raw read. If |bytes_read| is > 0, this indicates
   // a successful read of |bytes_read| unfiltered bytes. If |bytes_read|
-  // is 0, this indicates that there is no additional data to read. If
-  // |bytes_read| is < 0, an error occurred and no bytes were read.
-  void OnRawReadComplete(int bytes_read);
+  // is 0, this indicates that there is no additional data to read. |error|
+  // specifies whether an error occurred and no bytes were read.
+  void GatherRawReadStats(Error error, int bytes_read);
 
   // Updates the profiling info and notifies observers that an additional
   // |bytes_read| unfiltered bytes have been read for this job.
@@ -398,6 +401,16 @@
   // out.
   bool FilterHasData();
 
+  // NotifyDone marks that request is done. It is really a glorified
+  // set_status, but also does internal state checking and job tracking. It
+  // should be called once per request, when the job is finished doing all IO.
+  void NotifyDone(const URLRequestStatus& status);
+
+  // Some work performed by NotifyDone must be completed asynchronously so
+  // as to avoid re-entering URLRequest::Delegate. This method performs that
+  // work.
+  void CompleteNotifyDone();
+
   // Subclasses may implement this method to record packet arrival times.
   // The default implementation does nothing.  Only invoked when bytes have been
   // read since the last invocation.
diff --git a/net/url_request/url_request_simple_job.cc b/net/url_request/url_request_simple_job.cc
index 2fdbef4..c12555d4 100644
--- a/net/url_request/url_request_simple_job.cc
+++ b/net/url_request/url_request_simple_job.cc
@@ -65,32 +65,20 @@
 
 URLRequestSimpleJob::~URLRequestSimpleJob() {}
 
-bool URLRequestSimpleJob::ReadRawData(IOBuffer* buf, int buf_size,
-                                      int* bytes_read) {
-  DCHECK(bytes_read);
-  buf_size = static_cast<int>(
-      std::min(static_cast<int64>(buf_size),
-               byte_range_.last_byte_position() - next_data_offset_ + 1));
-  DCHECK_GE(buf_size, 0);
-  if (buf_size == 0) {
-    *bytes_read = 0;
-    return true;
-  }
+int URLRequestSimpleJob::ReadRawData(IOBuffer* buf, int buf_size) {
+  buf_size = std::min(static_cast<int64>(buf_size),
+                      byte_range_.last_byte_position() - next_data_offset_ + 1);
+  if (buf_size == 0)
+    return 0;
 
   // Do memory copy on a background thread. See crbug.com/422489.
   GetTaskRunner()->PostTaskAndReply(
       FROM_HERE, base::Bind(&CopyData, make_scoped_refptr(buf), buf_size, data_,
                             next_data_offset_),
-      base::Bind(&URLRequestSimpleJob::OnReadCompleted,
+      base::Bind(&URLRequestSimpleJob::ReadRawDataComplete,
                  weak_factory_.GetWeakPtr(), buf_size));
   next_data_offset_ += buf_size;
-  SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
-  return false;
-}
-
-void URLRequestSimpleJob::OnReadCompleted(int bytes_read) {
-  SetStatus(URLRequestStatus());
-  NotifyReadComplete(bytes_read);
+  return ERR_IO_PENDING;
 }
 
 base::TaskRunner* URLRequestSimpleJob::GetTaskRunner() const {
@@ -121,8 +109,8 @@
     return;
 
   if (ranges().size() > 1) {
-    NotifyDone(URLRequestStatus(URLRequestStatus::FAILED,
-                                ERR_REQUEST_RANGE_NOT_SATISFIABLE));
+    NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED,
+                                      ERR_REQUEST_RANGE_NOT_SATISFIABLE));
     return;
   }
 
@@ -142,8 +130,8 @@
   if (result == OK) {
     // Notify that the headers are complete
     if (!byte_range_.ComputeBounds(data_->size())) {
-      NotifyDone(URLRequestStatus(URLRequestStatus::FAILED,
-                 ERR_REQUEST_RANGE_NOT_SATISFIABLE));
+      NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED,
+                                        ERR_REQUEST_RANGE_NOT_SATISFIABLE));
       return;
     }
 
diff --git a/net/url_request/url_request_simple_job.h b/net/url_request/url_request_simple_job.h
index 6c9d5e8..06f718e 100644
--- a/net/url_request/url_request_simple_job.h
+++ b/net/url_request/url_request_simple_job.h
@@ -28,7 +28,7 @@
 
   void Start() override;
   void Kill() override;
-  bool ReadRawData(IOBuffer* buf, int buf_size, int* bytes_read) override;
+  int ReadRawData(IOBuffer* buf, int buf_size) override;
   bool GetMimeType(std::string* mime_type) const override;
   bool GetCharset(std::string* charset) override;
 
@@ -66,7 +66,6 @@
 
  private:
   void OnGetDataCompleted(int result);
-  void OnReadCompleted(int bytes_read);
 
   HttpByteRange byte_range_;
   std::string mime_type_;
diff --git a/net/url_request/url_request_status.cc b/net/url_request/url_request_status.cc
index 2a6a2fa..7207df2f 100644
--- a/net/url_request/url_request_status.cc
+++ b/net/url_request/url_request_status.cc
@@ -46,4 +46,19 @@
   }
 }
 
+Error URLRequestStatus::ToNetError() const {
+  switch (status_) {
+    case SUCCESS:
+      return OK;
+    case IO_PENDING:
+      return ERR_IO_PENDING;
+    case CANCELED:
+      return ERR_ABORTED;
+    case FAILED:
+      return static_cast<Error>(error_);
+  }
+  NOTREACHED();
+  return ERR_FAILED;
+}
+
 }  // namespace net
diff --git a/net/url_request/url_request_status.h b/net/url_request/url_request_status.h
index 44a5d22b..694c5100 100644
--- a/net/url_request/url_request_status.h
+++ b/net/url_request/url_request_status.h
@@ -5,6 +5,7 @@
 #ifndef NET_URL_REQUEST_URL_REQUEST_STATUS_H_
 #define NET_URL_REQUEST_URL_REQUEST_STATUS_H_
 
+#include "net/base/net_errors.h"
 #include "net/base/net_export.h"
 
 namespace net {
@@ -41,6 +42,13 @@
   // deprecated. See https://crbug.com/490311.
   static URLRequestStatus FromError(int error);
 
+  // Returns a Error corresponding to |status_|.
+  //   OK for OK
+  //   ERR_IO_PENDING for IO_PENDING
+  //   ERR_ABORTED for CANCELLED
+  //   Error for FAILED
+  Error ToNetError() const;
+
   Status status() const { return status_; }
   int error() const { return error_; }
 
diff --git a/net/url_request/url_request_test_job.cc b/net/url_request/url_request_test_job.cc
index c808d0b..bd1c9052 100644
--- a/net/url_request/url_request_test_job.cc
+++ b/net/url_request/url_request_test_job.cc
@@ -210,8 +210,8 @@
       // unexpected url, return error
       // FIXME(brettw) we may want to use WININET errors or have some more types
       // of errors
-      NotifyDone(URLRequestStatus(URLRequestStatus::FAILED,
-                                  ERR_INVALID_URL));
+      NotifyStartError(
+          URLRequestStatus(URLRequestStatus::FAILED, ERR_INVALID_URL));
       // FIXME(brettw): this should emulate a network error, and not just fail
       // initiating a connection
       return;
@@ -223,21 +223,15 @@
   this->NotifyHeadersComplete();
 }
 
-bool URLRequestTestJob::ReadRawData(IOBuffer* buf, int buf_size,
-                                    int *bytes_read) {
+int URLRequestTestJob::ReadRawData(IOBuffer* buf, int buf_size) {
   if (stage_ == WAITING) {
     async_buf_ = buf;
     async_buf_size_ = buf_size;
-    SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
-    return false;
+    return ERR_IO_PENDING;
   }
 
-  DCHECK(bytes_read);
-  *bytes_read = 0;
-
-  if (offset_ >= static_cast<int>(response_data_.length())) {
-    return true;  // done reading
-  }
+  if (offset_ >= static_cast<int>(response_data_.length()))
+    return 0;  // done reading
 
   int to_read = buf_size;
   if (to_read + offset_ > static_cast<int>(response_data_.length()))
@@ -246,8 +240,7 @@
   memcpy(buf->data(), &response_data_.c_str()[offset_], to_read);
   offset_ += to_read;
 
-  *bytes_read = to_read;
-  return true;
+  return to_read;
 }
 
 void URLRequestTestJob::GetResponseInfo(HttpResponseInfo* info) {
@@ -305,16 +298,15 @@
       stage_ = DATA_AVAILABLE;
       // OK if ReadRawData wasn't called yet.
       if (async_buf_) {
-        int bytes_read;
-        if (!ReadRawData(async_buf_, async_buf_size_, &bytes_read))
-          NOTREACHED() << "This should not return false in DATA_AVAILABLE.";
-        SetStatus(URLRequestStatus());  // clear the io pending flag
+        int result = ReadRawData(async_buf_, async_buf_size_);
+        if (result < 0)
+          NOTREACHED() << "Reads should not fail in DATA_AVAILABLE.";
         if (NextReadAsync()) {
           // Make all future reads return io pending until the next
           // ProcessNextOperation().
           stage_ = WAITING;
         }
-        NotifyReadComplete(bytes_read);
+        ReadRawDataComplete(result);
       }
       break;
     case DATA_AVAILABLE:
diff --git a/net/url_request/url_request_test_job.h b/net/url_request/url_request_test_job.h
index 09b31a4..eb1db01 100644
--- a/net/url_request/url_request_test_job.h
+++ b/net/url_request/url_request_test_job.h
@@ -111,7 +111,7 @@
   // Job functions
   void SetPriority(RequestPriority priority) override;
   void Start() override;
-  bool ReadRawData(IOBuffer* buf, int buf_size, int* bytes_read) override;
+  int ReadRawData(IOBuffer* buf, int buf_size) override;
   void Kill() override;
   bool GetMimeType(std::string* mime_type) const override;
   void GetResponseInfo(HttpResponseInfo* info) override;
diff --git a/sandbox/sandbox_export.h b/sandbox/sandbox_export.h
index 40a40366..35d6a1ba 100644
--- a/sandbox/sandbox_export.h
+++ b/sandbox/sandbox_export.h
@@ -13,16 +13,13 @@
 
 #if defined(SANDBOX_IMPLEMENTATION)
 #define SANDBOX_EXPORT __attribute__((visibility("default")))
-#define SANDBOX_EXPORT_PRIVATE __attribute__((visibility("default")))
 #else
 #define SANDBOX_EXPORT
-#define SANDBOX_EXPORT_PRIVATE
 #endif  // defined(SANDBOX_IMPLEMENTATION)
 
 #else  // defined(COMPONENT_BUILD)
 
 #define SANDBOX_EXPORT
-#define SANDBOX_EXPORT_PRIVATE
 
 #endif  // defined(COMPONENT_BUILD)
 
diff --git a/storage/browser/blob/blob_url_request_job.cc b/storage/browser/blob/blob_url_request_job.cc
index 6ec2fe5..deea300 100644
--- a/storage/browser/blob/blob_url_request_job.cc
+++ b/storage/browser/blob/blob_url_request_job.cc
@@ -75,41 +75,37 @@
   weak_factory_.InvalidateWeakPtrs();
 }
 
-bool BlobURLRequestJob::ReadRawData(net::IOBuffer* dest,
-                                    int dest_size,
-                                    int* bytes_read) {
+int BlobURLRequestJob::ReadRawData(net::IOBuffer* dest, int dest_size) {
   TRACE_EVENT_ASYNC_BEGIN1("Blob", "BlobRequest::ReadRawData", this, "uuid",
                            blob_handle_ ? blob_handle_->uuid() : "NotFound");
   DCHECK_NE(dest_size, 0);
-  DCHECK(bytes_read);
 
-  // Bail out immediately if we encounter an error.
-  if (error_) {
-    *bytes_read = 0;
-    return true;
-  }
+  // Bail out immediately if we encounter an error. This happens if a previous
+  // ReadRawData signalled an error to its caller but the caller called
+  // ReadRawData again anyway.
+  if (error_)
+    return 0;
 
+  int bytes_read = 0;
   BlobReader::Status read_status =
-      blob_reader_->Read(dest, dest_size, bytes_read,
+      blob_reader_->Read(dest, dest_size, &bytes_read,
                          base::Bind(&BlobURLRequestJob::DidReadRawData,
                                     weak_factory_.GetWeakPtr()));
 
   switch (read_status) {
     case BlobReader::Status::NET_ERROR:
-      NotifyFailure(blob_reader_->net_error());
       TRACE_EVENT_ASYNC_END1("Blob", "BlobRequest::ReadRawData", this, "uuid",
                              blob_handle_ ? blob_handle_->uuid() : "NotFound");
-      return false;
+      return blob_reader_->net_error();
     case BlobReader::Status::IO_PENDING:
-      SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
-      return false;
+      return net::ERR_IO_PENDING;
     case BlobReader::Status::DONE:
       TRACE_EVENT_ASYNC_END1("Blob", "BlobRequest::ReadRawData", this, "uuid",
                              blob_handle_ ? blob_handle_->uuid() : "NotFound");
-      return true;
+      return bytes_read;
   }
   NOTREACHED();
-  return true;
+  return 0;
 }
 
 bool BlobURLRequestJob::GetMimeType(std::string* mime_type) const {
@@ -222,13 +218,7 @@
 void BlobURLRequestJob::DidReadRawData(int result) {
   TRACE_EVENT_ASYNC_END1("Blob", "BlobRequest::ReadRawData", this, "uuid",
                          blob_handle_ ? blob_handle_->uuid() : "NotFound");
-  if (result < 0) {
-    NotifyFailure(result);
-    return;
-  }
-  // Clear the IO_PENDING status
-  SetStatus(net::URLRequestStatus());
-  NotifyReadComplete(result);
+  ReadRawDataComplete(result);
 }
 
 void BlobURLRequestJob::NotifyFailure(int error_code) {
@@ -236,11 +226,7 @@
 
   // If we already return the headers on success, we can't change the headers
   // now. Instead, we just error out.
-  if (response_info_) {
-    NotifyDone(
-        net::URLRequestStatus(net::URLRequestStatus::FAILED, error_code));
-    return;
-  }
+  DCHECK(!response_info_) << "Cannot NotifyFailure after headers.";
 
   net::HttpStatusCode status_code = net::HTTP_INTERNAL_SERVER_ERROR;
   switch (error_code) {
diff --git a/storage/browser/blob/blob_url_request_job.h b/storage/browser/blob/blob_url_request_job.h
index 21baa2c..1f0b9fb 100644
--- a/storage/browser/blob/blob_url_request_job.h
+++ b/storage/browser/blob/blob_url_request_job.h
@@ -44,7 +44,7 @@
   // net::URLRequestJob methods.
   void Start() override;
   void Kill() override;
-  bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override;
+  int ReadRawData(net::IOBuffer* buf, int buf_size) override;
   bool GetMimeType(std::string* mime_type) const override;
   void GetResponseInfo(net::HttpResponseInfo* info) override;
   int GetResponseCode() const override;
diff --git a/storage/browser/database/database_quota_client.h b/storage/browser/database/database_quota_client.h
index 8612310..a8760297e 100644
--- a/storage/browser/database/database_quota_client.h
+++ b/storage/browser/database/database_quota_client.h
@@ -21,8 +21,7 @@
 // A QuotaClient implementation to integrate WebSQLDatabases
 // with the quota  management system. This interface is used
 // on the IO thread by the quota manager.
-class STORAGE_EXPORT_PRIVATE DatabaseQuotaClient
-    : public storage::QuotaClient {
+class STORAGE_EXPORT DatabaseQuotaClient : public storage::QuotaClient {
  public:
   DatabaseQuotaClient(
       base::SingleThreadTaskRunner* tracker_thread,
diff --git a/storage/browser/database/databases_table.h b/storage/browser/database/databases_table.h
index 2ade812..0b98c31 100644
--- a/storage/browser/database/databases_table.h
+++ b/storage/browser/database/databases_table.h
@@ -16,7 +16,7 @@
 
 namespace storage {
 
-struct STORAGE_EXPORT_PRIVATE DatabaseDetails {
+struct STORAGE_EXPORT DatabaseDetails {
   DatabaseDetails();
   ~DatabaseDetails();
 
@@ -26,7 +26,7 @@
   int64 estimated_size;
 };
 
-class STORAGE_EXPORT_PRIVATE DatabasesTable {
+class STORAGE_EXPORT DatabasesTable {
  public:
   explicit DatabasesTable(sql::Connection* db) : db_(db) { }
 
diff --git a/storage/browser/fileapi/dragged_file_util.h b/storage/browser/fileapi/dragged_file_util.h
index efa14c4..50a4e83 100644
--- a/storage/browser/fileapi/dragged_file_util.h
+++ b/storage/browser/fileapi/dragged_file_util.h
@@ -16,8 +16,7 @@
 // Dragged file system is a specialized LocalFileUtil where read access to
 // the virtual root directory (i.e. empty cracked path case) is allowed
 // and single isolated context may be associated with multiple file paths.
-class STORAGE_EXPORT_PRIVATE DraggedFileUtil
-    : public LocalFileUtil {
+class STORAGE_EXPORT DraggedFileUtil : public LocalFileUtil {
  public:
   DraggedFileUtil();
   ~DraggedFileUtil() override {}
diff --git a/storage/browser/fileapi/file_system_dir_url_request_job.cc b/storage/browser/fileapi/file_system_dir_url_request_job.cc
index 35b6c1d8..2a0984b7 100644
--- a/storage/browser/fileapi/file_system_dir_url_request_job.cc
+++ b/storage/browser/fileapi/file_system_dir_url_request_job.cc
@@ -14,7 +14,6 @@
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
 #include "net/base/net_util.h"
 #include "net/url_request/url_request.h"
 #include "storage/browser/fileapi/file_system_context.h"
@@ -44,15 +43,14 @@
 FileSystemDirURLRequestJob::~FileSystemDirURLRequestJob() {
 }
 
-bool FileSystemDirURLRequestJob::ReadRawData(net::IOBuffer* dest, int dest_size,
-                                             int *bytes_read) {
-  int count = std::min(dest_size, static_cast<int>(data_.size()));
+int FileSystemDirURLRequestJob::ReadRawData(net::IOBuffer* dest,
+                                            int dest_size) {
+  int count = std::min(dest_size, base::checked_cast<int>(data_.size()));
   if (count > 0) {
     memcpy(dest->data(), data_.data(), count);
     data_.erase(0, count);
   }
-  *bytes_read = count;
-  return true;
+  return count;
 }
 
 void FileSystemDirURLRequestJob::Start() {
@@ -98,8 +96,7 @@
                        false);
       return;
     }
-    NotifyDone(URLRequestStatus(URLRequestStatus::FAILED,
-                                net::ERR_FILE_NOT_FOUND));
+    NotifyStartError(URLRequestStatus::FromError(net::ERR_FILE_NOT_FOUND));
     return;
   }
   file_system_context_->operation_runner()->ReadDirectory(
@@ -112,8 +109,7 @@
       file_system_context_->CrackURL(request_->url()).is_valid()) {
     StartAsync();
   } else {
-    NotifyDone(URLRequestStatus(URLRequestStatus::FAILED,
-                                net::ERR_FILE_NOT_FOUND));
+    NotifyStartError(URLRequestStatus::FromError(net::ERR_FILE_NOT_FOUND));
   }
 }
 
@@ -125,7 +121,7 @@
     int rv = net::ERR_FILE_NOT_FOUND;
     if (result == base::File::FILE_ERROR_INVALID_URL)
       rv = net::ERR_INVALID_URL;
-    NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv));
+    NotifyStartError(URLRequestStatus::FromError(rv));
     return;
   }
 
diff --git a/storage/browser/fileapi/file_system_dir_url_request_job.h b/storage/browser/fileapi/file_system_dir_url_request_job.h
index 8715c96b..67104d6 100644
--- a/storage/browser/fileapi/file_system_dir_url_request_job.h
+++ b/storage/browser/fileapi/file_system_dir_url_request_job.h
@@ -21,8 +21,7 @@
 struct DirectoryEntry;
 
 // A request job that handles reading filesystem: URLs for directories.
-class STORAGE_EXPORT_PRIVATE FileSystemDirURLRequestJob
-    : public net::URLRequestJob {
+class STORAGE_EXPORT FileSystemDirURLRequestJob : public net::URLRequestJob {
  public:
   FileSystemDirURLRequestJob(
       net::URLRequest* request,
@@ -33,7 +32,7 @@
   // URLRequestJob methods:
   void Start() override;
   void Kill() override;
-  bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override;
+  int ReadRawData(net::IOBuffer* buf, int buf_size) override;
   bool GetCharset(std::string* charset) override;
 
   // FilterContext methods (via URLRequestJob):
diff --git a/storage/browser/fileapi/file_system_file_stream_reader.h b/storage/browser/fileapi/file_system_file_stream_reader.h
index 41c01577..b4095b0 100644
--- a/storage/browser/fileapi/file_system_file_stream_reader.h
+++ b/storage/browser/fileapi/file_system_file_stream_reader.h
@@ -32,7 +32,7 @@
 // remote filesystem should implement its own reader rather than relying
 // on FileSystemOperation::GetSnapshotFile() which may force downloading
 // the entire contents for remote files.
-class STORAGE_EXPORT_PRIVATE FileSystemFileStreamReader
+class STORAGE_EXPORT FileSystemFileStreamReader
     : public NON_EXPORTED_BASE(storage::FileStreamReader) {
  public:
   ~FileSystemFileStreamReader() override;
diff --git a/storage/browser/fileapi/file_system_operation_context.h b/storage/browser/fileapi/file_system_operation_context.h
index 96563ad..25fd5cf 100644
--- a/storage/browser/fileapi/file_system_operation_context.h
+++ b/storage/browser/fileapi/file_system_operation_context.h
@@ -26,7 +26,7 @@
 // the same context (e.g. use the same task runner, share the quota etc).
 // Note that the remaining quota bytes (allowed_bytes_growth) may be
 // updated during the execution of write operations.
-class STORAGE_EXPORT_PRIVATE FileSystemOperationContext
+class STORAGE_EXPORT FileSystemOperationContext
     : public base::SupportsUserData {
  public:
   explicit FileSystemOperationContext(FileSystemContext* context);
diff --git a/storage/browser/fileapi/file_system_quota_client.h b/storage/browser/fileapi/file_system_quota_client.h
index 869e63e..51d927a 100644
--- a/storage/browser/fileapi/file_system_quota_client.h
+++ b/storage/browser/fileapi/file_system_quota_client.h
@@ -31,7 +31,7 @@
 // is called.
 // All of the public methods of this class are called by the quota manager
 // (except for the constructor/destructor).
-class STORAGE_EXPORT_PRIVATE FileSystemQuotaClient
+class STORAGE_EXPORT FileSystemQuotaClient
     : public NON_EXPORTED_BASE(storage::QuotaClient) {
  public:
   FileSystemQuotaClient(
diff --git a/storage/browser/fileapi/file_system_url_request_job.cc b/storage/browser/fileapi/file_system_url_request_job.cc
index 95727218..6c33fc86 100644
--- a/storage/browser/fileapi/file_system_url_request_job.cc
+++ b/storage/browser/fileapi/file_system_url_request_job.cc
@@ -62,8 +62,8 @@
       file_system_context_(file_system_context),
       is_directory_(false),
       remaining_bytes_(0),
-      weak_factory_(this) {
-}
+      range_parse_result_(net::OK),
+      weak_factory_(this) {}
 
 FileSystemURLRequestJob::~FileSystemURLRequestJob() {}
 
@@ -80,39 +80,28 @@
   weak_factory_.InvalidateWeakPtrs();
 }
 
-bool FileSystemURLRequestJob::ReadRawData(net::IOBuffer* dest,
-                                          int dest_size,
-                                          int* bytes_read) {
+int FileSystemURLRequestJob::ReadRawData(net::IOBuffer* dest, int dest_size) {
   DCHECK_NE(dest_size, 0);
-  DCHECK(bytes_read);
   DCHECK_GE(remaining_bytes_, 0);
 
   if (reader_.get() == NULL)
-    return false;
+    return net::ERR_FAILED;
 
   if (remaining_bytes_ < dest_size)
-    dest_size = static_cast<int>(remaining_bytes_);
+    dest_size = remaining_bytes_;
 
-  if (!dest_size) {
-    *bytes_read = 0;
-    return true;
-  }
+  if (!dest_size)
+    return 0;
 
   const int rv = reader_->Read(dest, dest_size,
                                base::Bind(&FileSystemURLRequestJob::DidRead,
                                           weak_factory_.GetWeakPtr()));
   if (rv >= 0) {
-    // Data is immediately available.
-    *bytes_read = rv;
     remaining_bytes_ -= rv;
     DCHECK_GE(remaining_bytes_, 0);
-    return true;
   }
-  if (rv == net::ERR_IO_PENDING)
-    SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
-  else
-    NotifyFailed(rv);
-  return false;
+
+  return rv;
 }
 
 bool FileSystemURLRequestJob::GetMimeType(std::string* mime_type) const {
@@ -127,8 +116,12 @@
 void FileSystemURLRequestJob::SetExtraRequestHeaders(
     const net::HttpRequestHeaders& headers) {
   std::string range_header;
+  // Currently this job only cares about the Range header. Note that validation
+  // is deferred to DidGetMetaData(), because NotifyStartError is not legal to
+  // call since the job has not started.
   if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) {
     std::vector<net::HttpByteRange> ranges;
+
     if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) {
       if (ranges.size() == 1) {
         byte_range_ = ranges[0];
@@ -136,7 +129,7 @@
         // We don't support multiple range requests in one single URL request.
         // TODO(adamk): decide whether we want to support multiple range
         // requests.
-        NotifyFailed(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE);
+        range_parse_result_ = net::ERR_REQUEST_RANGE_NOT_SATISFIABLE;
       }
     }
   }
@@ -168,7 +161,7 @@
   }
   if (!file_system_context_->CanServeURLRequest(url_)) {
     // In incognito mode the API is not usable and there should be no data.
-    NotifyFailed(net::ERR_FILE_NOT_FOUND);
+    NotifyStartError(URLRequestStatus::FromError(net::ERR_FILE_NOT_FOUND));
     return;
   }
   file_system_context_->operation_runner()->GetMetadata(
@@ -182,7 +175,7 @@
       file_system_context_->CrackURL(request_->url()).is_valid()) {
     StartAsync();
   } else {
-    NotifyFailed(net::ERR_FILE_NOT_FOUND);
+    NotifyStartError(URLRequestStatus::FromError(net::ERR_FILE_NOT_FOUND));
   }
 }
 
@@ -190,8 +183,10 @@
     base::File::Error error_code,
     const base::File::Info& file_info) {
   if (error_code != base::File::FILE_OK) {
-    NotifyFailed(error_code == base::File::FILE_ERROR_INVALID_URL ?
-                 net::ERR_INVALID_URL : net::ERR_FILE_NOT_FOUND);
+    NotifyStartError(URLRequestStatus::FromError(
+        error_code == base::File::FILE_ERROR_INVALID_URL
+            ? net::ERR_INVALID_URL
+            : net::ERR_FILE_NOT_FOUND));
     return;
   }
 
@@ -201,8 +196,14 @@
 
   is_directory_ = file_info.is_directory;
 
+  if (range_parse_result_ != net::OK) {
+    NotifyStartError(URLRequestStatus::FromError(range_parse_result_));
+    return;
+  }
+
   if (!byte_range_.ComputeBounds(file_info.size)) {
-    NotifyFailed(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE);
+    NotifyStartError(
+        URLRequestStatus::FromError(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
     return;
   }
 
@@ -226,17 +227,12 @@
 }
 
 void FileSystemURLRequestJob::DidRead(int result) {
-  if (result > 0)
-    SetStatus(URLRequestStatus());  // Clear the IO_PENDING status
-  else if (result == 0)
-    NotifyDone(URLRequestStatus());
-  else
-    NotifyFailed(result);
+  if (result >= 0) {
+    remaining_bytes_ -= result;
+    DCHECK_GE(remaining_bytes_, 0);
+  }
 
-  remaining_bytes_ -= result;
-  DCHECK_GE(remaining_bytes_, 0);
-
-  NotifyReadComplete(result);
+  ReadRawDataComplete(result);
 }
 
 bool FileSystemURLRequestJob::IsRedirectResponse(GURL* location,
@@ -256,8 +252,4 @@
   return false;
 }
 
-void FileSystemURLRequestJob::NotifyFailed(int rv) {
-  NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv));
-}
-
 }  // namespace storage
diff --git a/storage/browser/fileapi/file_system_url_request_job.h b/storage/browser/fileapi/file_system_url_request_job.h
index 00212102..308b66c 100644
--- a/storage/browser/fileapi/file_system_url_request_job.h
+++ b/storage/browser/fileapi/file_system_url_request_job.h
@@ -11,6 +11,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "net/base/net_errors.h"
 #include "net/http/http_byte_range.h"
 #include "net/url_request/url_request_job.h"
 #include "storage/browser/fileapi/file_system_url.h"
@@ -30,8 +31,7 @@
 class FileSystemContext;
 
 // A request job that handles reading filesystem: URLs
-class STORAGE_EXPORT_PRIVATE FileSystemURLRequestJob
-    : public net::URLRequestJob {
+class STORAGE_EXPORT FileSystemURLRequestJob : public net::URLRequestJob {
  public:
   FileSystemURLRequestJob(
       net::URLRequest* request,
@@ -42,7 +42,7 @@
   // URLRequestJob methods:
   void Start() override;
   void Kill() override;
-  bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override;
+  int ReadRawData(net::IOBuffer* buf, int buf_size) override;
   bool IsRedirectResponse(GURL* location, int* http_status_code) override;
   void SetExtraRequestHeaders(const net::HttpRequestHeaders& headers) override;
   void GetResponseInfo(net::HttpResponseInfo* info) override;
@@ -61,7 +61,6 @@
   void DidGetMetadata(base::File::Error error_code,
                       const base::File::Info& file_info);
   void DidRead(int result);
-  void NotifyFailed(int rv);
 
   const std::string storage_domain_;
   FileSystemContext* file_system_context_;
@@ -70,6 +69,7 @@
   bool is_directory_;
   scoped_ptr<net::HttpResponseInfo> response_info_;
   int64 remaining_bytes_;
+  net::Error range_parse_result_;
   net::HttpByteRange byte_range_;
   base::WeakPtrFactory<FileSystemURLRequestJob> weak_factory_;
 
diff --git a/storage/browser/fileapi/file_system_usage_cache.h b/storage/browser/fileapi/file_system_usage_cache.h
index c2b2aef0..901df289 100644
--- a/storage/browser/fileapi/file_system_usage_cache.h
+++ b/storage/browser/fileapi/file_system_usage_cache.h
@@ -19,7 +19,7 @@
 
 class TimedTaskHelper;
 
-class STORAGE_EXPORT_PRIVATE FileSystemUsageCache {
+class STORAGE_EXPORT FileSystemUsageCache {
  public:
   explicit FileSystemUsageCache(base::SequencedTaskRunner* task_runner);
   ~FileSystemUsageCache();
diff --git a/storage/browser/fileapi/file_writer_delegate.h b/storage/browser/fileapi/file_writer_delegate.h
index 01c89a9..dca4bd8d 100644
--- a/storage/browser/fileapi/file_writer_delegate.h
+++ b/storage/browser/fileapi/file_writer_delegate.h
@@ -20,8 +20,7 @@
 class FileStreamWriter;
 enum class FlushPolicy;
 
-class STORAGE_EXPORT_PRIVATE FileWriterDelegate
-    : public net::URLRequest::Delegate {
+class STORAGE_EXPORT FileWriterDelegate : public net::URLRequest::Delegate {
  public:
   enum WriteProgressStatus {
     SUCCESS_IO_PENDING,
diff --git a/storage/browser/fileapi/native_file_util.h b/storage/browser/fileapi/native_file_util.h
index 28833ff..39b865c4 100644
--- a/storage/browser/fileapi/native_file_util.h
+++ b/storage/browser/fileapi/native_file_util.h
@@ -28,7 +28,7 @@
 //
 // Note that all the methods of this class are static and this does NOT
 // inherit from FileSystemFileUtil.
-class STORAGE_EXPORT_PRIVATE NativeFileUtil {
+class STORAGE_EXPORT NativeFileUtil {
  public:
   enum CopyOrMoveMode {
     COPY_NOSYNC,
diff --git a/storage/browser/fileapi/obfuscated_file_util.h b/storage/browser/fileapi/obfuscated_file_util.h
index 5557ba18..5b71e2d7 100644
--- a/storage/browser/fileapi/obfuscated_file_util.h
+++ b/storage/browser/fileapi/obfuscated_file_util.h
@@ -68,8 +68,7 @@
 //
 // This class must be deleted on the FILE thread, because that's where
 // DropDatabases needs to be called.
-class STORAGE_EXPORT_PRIVATE ObfuscatedFileUtil
-    : public FileSystemFileUtil {
+class STORAGE_EXPORT ObfuscatedFileUtil : public FileSystemFileUtil {
  public:
   // Origin enumerator interface.
   // An instance of this interface is assumed to be called on the file thread.
diff --git a/storage/browser/fileapi/sandbox_directory_database.h b/storage/browser/fileapi/sandbox_directory_database.h
index 7918d12..e765c5b 100644
--- a/storage/browser/fileapi/sandbox_directory_database.h
+++ b/storage/browser/fileapi/sandbox_directory_database.h
@@ -40,11 +40,11 @@
 // TODO(ericu): Safe mode, which does more checks such as the above on debug
 // builds.
 // TODO(ericu): Add a method that will give a unique filename for a data file.
-class STORAGE_EXPORT_PRIVATE SandboxDirectoryDatabase {
+class STORAGE_EXPORT SandboxDirectoryDatabase {
  public:
   typedef int64 FileId;
 
-  struct STORAGE_EXPORT_PRIVATE FileInfo {
+  struct STORAGE_EXPORT FileInfo {
     FileInfo();
     ~FileInfo();
 
diff --git a/storage/browser/fileapi/sandbox_file_stream_writer.h b/storage/browser/fileapi/sandbox_file_stream_writer.h
index 61375b11..2e62421 100644
--- a/storage/browser/fileapi/sandbox_file_stream_writer.h
+++ b/storage/browser/fileapi/sandbox_file_stream_writer.h
@@ -23,7 +23,7 @@
 class FileSystemQuotaUtil;
 class FileStreamWriter;
 
-class STORAGE_EXPORT_PRIVATE SandboxFileStreamWriter
+class STORAGE_EXPORT SandboxFileStreamWriter
     : public NON_EXPORTED_BASE(FileStreamWriter) {
  public:
   SandboxFileStreamWriter(FileSystemContext* file_system_context,
diff --git a/storage/browser/fileapi/sandbox_isolated_origin_database.h b/storage/browser/fileapi/sandbox_isolated_origin_database.h
index b5203d25..f01b5c0 100644
--- a/storage/browser/fileapi/sandbox_isolated_origin_database.h
+++ b/storage/browser/fileapi/sandbox_isolated_origin_database.h
@@ -16,7 +16,7 @@
 
 // This origin database implementation supports only one origin
 // (therefore is expected to run very fast).
-class STORAGE_EXPORT_PRIVATE SandboxIsolatedOriginDatabase
+class STORAGE_EXPORT SandboxIsolatedOriginDatabase
     : public SandboxOriginDatabaseInterface {
  public:
   static const base::FilePath::CharType kObsoleteOriginDirectory[];
diff --git a/storage/browser/fileapi/sandbox_origin_database.h b/storage/browser/fileapi/sandbox_origin_database.h
index 30e66c92..7d700a39 100644
--- a/storage/browser/fileapi/sandbox_origin_database.h
+++ b/storage/browser/fileapi/sandbox_origin_database.h
@@ -26,7 +26,7 @@
 
 // All methods of this class other than the constructor may be used only from
 // the browser's FILE thread.  The constructor may be used on any thread.
-class STORAGE_EXPORT_PRIVATE SandboxOriginDatabase
+class STORAGE_EXPORT SandboxOriginDatabase
     : public SandboxOriginDatabaseInterface {
  public:
   // Only one instance of SandboxOriginDatabase should exist for a given path
diff --git a/storage/browser/fileapi/sandbox_origin_database_interface.h b/storage/browser/fileapi/sandbox_origin_database_interface.h
index 4a01e436..a2498c6 100644
--- a/storage/browser/fileapi/sandbox_origin_database_interface.h
+++ b/storage/browser/fileapi/sandbox_origin_database_interface.h
@@ -13,9 +13,9 @@
 
 namespace storage {
 
-class STORAGE_EXPORT_PRIVATE SandboxOriginDatabaseInterface {
+class STORAGE_EXPORT SandboxOriginDatabaseInterface {
  public:
-  struct STORAGE_EXPORT_PRIVATE OriginRecord {
+  struct STORAGE_EXPORT OriginRecord {
     std::string origin;
     base::FilePath path;
 
diff --git a/storage/browser/fileapi/sandbox_prioritized_origin_database.h b/storage/browser/fileapi/sandbox_prioritized_origin_database.h
index c1b6a80..40be0c7 100644
--- a/storage/browser/fileapi/sandbox_prioritized_origin_database.h
+++ b/storage/browser/fileapi/sandbox_prioritized_origin_database.h
@@ -22,7 +22,7 @@
 class SandboxIsolatedOriginDatabase;
 class SandboxOriginDatabase;
 
-class STORAGE_EXPORT_PRIVATE SandboxPrioritizedOriginDatabase
+class STORAGE_EXPORT SandboxPrioritizedOriginDatabase
     : public SandboxOriginDatabaseInterface {
  public:
   static const base::FilePath::CharType* kPrimaryDirectory;
diff --git a/storage/browser/fileapi/transient_file_util.h b/storage/browser/fileapi/transient_file_util.h
index b14969b0..d81708a 100644
--- a/storage/browser/fileapi/transient_file_util.h
+++ b/storage/browser/fileapi/transient_file_util.h
@@ -13,8 +13,7 @@
 
 class FileSystemOperationContext;
 
-class STORAGE_EXPORT_PRIVATE TransientFileUtil
-    : public LocalFileUtil {
+class STORAGE_EXPORT TransientFileUtil : public LocalFileUtil {
  public:
   TransientFileUtil() {}
   ~TransientFileUtil() override {}
diff --git a/storage/browser/quota/quota_database.h b/storage/browser/quota/quota_database.h
index dae5581f..4650dccc 100644
--- a/storage/browser/quota/quota_database.h
+++ b/storage/browser/quota/quota_database.h
@@ -34,9 +34,9 @@
 class SpecialStoragePolicy;
 
 // All the methods of this class must run on the DB thread.
-class STORAGE_EXPORT_PRIVATE QuotaDatabase {
+class STORAGE_EXPORT QuotaDatabase {
  public:
-  struct STORAGE_EXPORT_PRIVATE OriginInfoTableEntry {
+  struct STORAGE_EXPORT OriginInfoTableEntry {
     OriginInfoTableEntry();
     OriginInfoTableEntry(const GURL& origin,
                          StorageType type,
@@ -127,7 +127,7 @@
   bool SetOriginDatabaseBootstrapped(bool bootstrap_flag);
 
  private:
-  struct STORAGE_EXPORT_PRIVATE QuotaTableEntry {
+  struct STORAGE_EXPORT QuotaTableEntry {
     QuotaTableEntry();
     QuotaTableEntry(
         const std::string& host,
@@ -137,9 +137,9 @@
     StorageType type;
     int64 quota;
   };
-  friend STORAGE_EXPORT_PRIVATE bool operator <(
+  friend STORAGE_EXPORT bool operator <(
       const QuotaTableEntry& lhs, const QuotaTableEntry& rhs);
-  friend STORAGE_EXPORT_PRIVATE bool operator <(
+  friend STORAGE_EXPORT bool operator <(
       const OriginInfoTableEntry& lhs, const OriginInfoTableEntry& rhs);
 
   // Structures used for CreateSchema.
diff --git a/storage/browser/quota/quota_temporary_storage_evictor.h b/storage/browser/quota/quota_temporary_storage_evictor.h
index 9b896e93ba..7c42855 100644
--- a/storage/browser/quota/quota_temporary_storage_evictor.h
+++ b/storage/browser/quota/quota_temporary_storage_evictor.h
@@ -25,8 +25,7 @@
 class QuotaEvictionHandler;
 struct UsageAndQuota;
 
-class STORAGE_EXPORT_PRIVATE QuotaTemporaryStorageEvictor
-    : public base::NonThreadSafe {
+class STORAGE_EXPORT QuotaTemporaryStorageEvictor : public base::NonThreadSafe {
  public:
   struct Statistics {
     Statistics()
diff --git a/storage/browser/quota/storage_monitor.h b/storage/browser/quota/storage_monitor.h
index 8c7960f..143815a0 100644
--- a/storage/browser/quota/storage_monitor.h
+++ b/storage/browser/quota/storage_monitor.h
@@ -22,7 +22,7 @@
 
 // This class dispatches storage events to observers of a common
 // StorageObserver::Filter.
-class STORAGE_EXPORT_PRIVATE StorageObserverList {
+class STORAGE_EXPORT StorageObserverList {
  public:
   StorageObserverList();
   virtual ~StorageObserverList();
@@ -47,7 +47,7 @@
   void ScheduleUpdateForObserver(StorageObserver* observer);
 
  private:
-  struct STORAGE_EXPORT_PRIVATE ObserverState {
+  struct STORAGE_EXPORT ObserverState {
     GURL origin;
     base::TimeTicks last_notification_time;
     base::TimeDelta rate;
@@ -71,7 +71,7 @@
 
 // Manages the storage observers of a common host. Caches the usage and quota of
 // the host to avoid accumulating for every change.
-class STORAGE_EXPORT_PRIVATE HostStorageObservers {
+class STORAGE_EXPORT HostStorageObservers {
  public:
   explicit HostStorageObservers(QuotaManager* quota_manager);
   virtual ~HostStorageObservers();
@@ -118,7 +118,7 @@
 
 
 // Manages the observers of a common storage type.
-class STORAGE_EXPORT_PRIVATE StorageTypeObservers {
+class STORAGE_EXPORT StorageTypeObservers {
  public:
   explicit StorageTypeObservers(QuotaManager* quota_manager);
   virtual ~StorageTypeObservers();
@@ -147,7 +147,7 @@
 
 
 // Storage monitor manages observers and dispatches storage events to them.
-class STORAGE_EXPORT_PRIVATE StorageMonitor {
+class STORAGE_EXPORT StorageMonitor {
  public:
   explicit StorageMonitor(QuotaManager* quota_manager);
   virtual ~StorageMonitor();
diff --git a/storage/browser/storage_browser_export.h b/storage/browser/storage_browser_export.h
index c6d6a37..bad5e41 100644
--- a/storage/browser/storage_browser_export.h
+++ b/storage/browser/storage_browser_export.h
@@ -10,25 +10,20 @@
 
 #if defined(STORAGE_BROWSER_IMPLEMENTATION)
 #define STORAGE_EXPORT __declspec(dllexport)
-#define STORAGE_EXPORT_PRIVATE __declspec(dllexport)
 #else
 #define STORAGE_EXPORT __declspec(dllimport)
-#define STORAGE_EXPORT_PRIVATE __declspec(dllimport)
 #endif  // defined(STORAGE_BROWSER_IMPLEMENTATION)
 
 #else // defined(WIN32)
 #if defined(STORAGE_BROWSER_IMPLEMENTATION)
 #define STORAGE_EXPORT __attribute__((visibility("default")))
-#define STORAGE_EXPORT_PRIVATE __attribute__((visibility("default")))
 #else
 #define STORAGE_EXPORT
-#define STORAGE_EXPORT_PRIVATE
 #endif
 #endif
 
 #else // defined(COMPONENT_BUILD)
 #define STORAGE_EXPORT
-#define STORAGE_EXPORT_PRIVATE
 #endif
 
 #endif  // STORAGE_BROWSER_STORAGE_BROWSER_EXPORT_H__
diff --git a/styleguide/c++/c++11.html b/styleguide/c++/c++11.html
index ed917712..3da5810 100644
--- a/styleguide/c++/c++11.html
+++ b/styleguide/c++/c++11.html
@@ -339,7 +339,7 @@
 sequences, easing parsing in regex expressions, for example</td>
 <td><a href="http://en.cppreference.com/w/cpp/language/string_literal">
 string literal</a></td>
-<td>Causes incorrect line numbers in MSVS2014 and gcc. Reevaluate once that works. <a href="https://groups.google.com/a/chromium.org/forum/#!topic/chromium-dev/2kWQHbbuMHI">Discussion thread</a></td>
+<td>Causes incorrect line numbers in MSVS2013 and gcc. Reevaluate once that works. <a href="https://groups.google.com/a/chromium.org/forum/#!topic/chromium-dev/2kWQHbbuMHI">Discussion thread</a></td>
 </tr>
 
 <tr>
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index b272bb19..5d6f81f 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -259,6 +259,34 @@
 
 crbug.com/535408 fast/js/function-bind.html [ NeedsManualRebaseline ]
 
+crbug.com/552456 [ Linux ] fast/mediarecorder/MediaRecorder-basic-video.html [ Pass Failure ]
+crbug.com/552456 [ Linux ] fast/mediarecorder/MediaRecorder-creation.html [ Pass Failure ]
+crbug.com/552456 [ Linux ] fast/mediarecorder/MediaRecorder-events-and-exceptions.html [ Pass Failure ]
+crbug.com/552456 [ Linux ] fast/mediarecorder/MediaRecorder-requestData.html [ Pass Failure ]
+crbug.com/552456 [ Linux ] fast/mediastream/MediaStream-add-remove-tracks.html [ Pass Failure ]
+crbug.com/552456 [ Linux ] fast/mediastream/MediaStream-clone.html [ Pass Failure ]
+crbug.com/552456 [ Linux ] fast/mediastream/MediaStream-onactive-oninactive.html [ Pass Failure ]
+crbug.com/552456 [ Linux ] fast/mediastream/MediaStream-stop.html [ Pass Failure ]
+crbug.com/552456 [ Linux ] fast/mediastream/MediaStreamTrack-getSources.html [ Pass Failure ]
+crbug.com/552456 [ Linux ] fast/mediastream/RTCPeerConnection-AddRemoveStream.html [ Pass Failure ]
+crbug.com/552456 [ Linux ] fast/mediastream/RTCPeerConnection-events.html [ Pass Failure ]
+crbug.com/552456 [ Linux ] fast/mediastream/RTCPeerConnection-onnegotiationneeded.html [ Pass Failure ]
+crbug.com/552456 [ Linux ] fast/mediastream/RTCPeerConnection-remotestreams.html [ Pass Failure ]
+crbug.com/552456 [ Linux ] fast/mediastream/RTCPeerConnection-stats.html [ Pass Failure ]
+crbug.com/552456 [ Linux ] fast/mediastream/RTCPeerConnection-statsSelector.html [ Pass Failure ]
+crbug.com/552456 [ Linux ] fast/mediastream/argument-types.html [ Pass Failure ]
+crbug.com/552456 [ Linux ] fast/mediastream/getusermedia-constraints.html [ Pass Failure ]
+crbug.com/552456 [ Linux ] fast/mediastream/getusermedia-promise.html [ Pass Failure ]
+crbug.com/552456 [ Linux ] fast/mediastream/getusermedia.html [ Pass Failure ]
+crbug.com/552456 [ Linux ] imported/web-platform-tests/mediacapture-streams/stream-api/mediastream/mediastream-addtrack.html [ Pass Failure ]
+crbug.com/552456 [ Linux ] imported/web-platform-tests/mediacapture-streams/stream-api/mediastream/mediastream-gettrackid.html [ Pass Failure ]
+crbug.com/552456 [ Linux ] imported/web-platform-tests/mediacapture-streams/stream-api/mediastream/stream-ended.html [ Pass Failure ]
+crbug.com/552456 [ Linux ] imported/web-platform-tests/mediacapture-streams/stream-api/mediastream/video.html [ Pass Failure ]
+crbug.com/552456 [ Linux ] imported/web-platform-tests/mediacapture-streams/stream-api/mediastreamtrack/mediastreamtrack-id.html [ Pass Failure ]
+crbug.com/552456 [ Linux ] imported/web-platform-tests/webrtc/simplecall.html [ Pass Failure ]
+crbug.com/552456 [ Linux ] media/video-capture-canvas.html [ Pass Failure ]
+crbug.com/552456 [ Linux ] media/video-capture-preview.html [ Pass Failure ]
+
 crbug.com/498539 http/tests/inspector/elements/styles/selector-line.html [ Pass Timeout ]
 crbug.com/498539 http/tests/inspector/network/network-datareceived.html [ Pass Timeout ]
 crbug.com/498539 [ Win ] inspector/tracing/decode-resize.html [ Failure Timeout ]
@@ -324,6 +352,8 @@
 crbug.com/498539 [ Win7 Debug ] inspector/elements/styles-3/styles-computed-trace.html [ Crash Pass ]
 crbug.com/498539 [ Win7 ] inspector/elements/styles-4/styles-update-from-js.html [ Crash Pass ]
 
+crbug.com/552507 http/tests/serviceworker/registration.html [ Pass Crash Failure ]
+
 crbug.com/248938 [ Win Debug ] virtual/threaded/animations/transition-and-animation-2.html [ Timeout ]
 
 crbug.com/487281 [ Mac ] fast/forms/menulist-narrow-width.html [ Failure ]
@@ -332,6 +362,11 @@
 
 crbug.com/548904 [ Linux Win7 ] fast/writing-mode/Kusa-Makura-background-canvas.html [ Failure Pass ]
 
+crbug.com/552433 svg/W3C-SVG-1.1/coords-units-02-b.svg [ Pass Failure ]
+crbug.com/552433 svg/dom/length-list-parser.html [ Pass Failure ]
+crbug.com/552433 svg/transforms/text-with-pattern-with-svg-transform.svg [ Pass Failure ]
+crbug.com/552433 svg/hixie/perf/006.xml [ Pass Failure ]
+
 crbug.com/441840 [ Mac XP ] cssom/ahem-ex-units.html [ Failure ]
 
 crbug.com/530044 transforms/2d/transform-borderbox.html [ NeedsManualRebaseline ]
@@ -398,7 +433,9 @@
 crbug.com/537409 virtual/spv2/paint/invalidation/spv2/repaint-squashed-layer-in-rect.html [ Skip ]
 crbug.com/537409 virtual/spv2/paint/invalidation/spv2/repaint-via-layout-offset.html [ Skip ]
 crbug.com/537409 virtual/spv2/paint/invalidation/spv2/resize-repaint.html [ Skip ]
+crbug.com/537409 virtual/spv2/paint/invalidation/spv2/scroll-fixed-layer-with-reflection.html [ Skip ]
 crbug.com/537409 virtual/spv2/paint/invalidation/spv2/scroll-fixed-squahed-layer.html [ Skip ]
+crbug.com/537409 virtual/spv2/paint/invalidation/spv2/scroll-fixed-reflected-layer.html [ Skip ]
 crbug.com/537409 virtual/spv2/paint/invalidation/spv2/selection-change-in-iframe-with-relative-parent.html [ Skip ]
 crbug.com/537409 virtual/spv2/paint/invalidation/spv2/selection-within-composited-scroller.html [ Skip ]
 crbug.com/537409 virtual/spv2/paint/invalidation/spv2/should-not-clip-composited-overflow-scrolling-layer.html [ Skip ]
@@ -540,6 +577,10 @@
 crbug.com/318978 [ Linux ] permissionclient/plugin-permission.html [ Skip ]
 crbug.com/318978 [ Linux ] plugins/ [ Skip ]
 
+crbug.com/552494 scrollbars/overflow-scrollbar-combinations.html [ Pass Failure ]
+crbug.com/552494 virtual/prefer_compositing_to_lcd_text/scrollbars/overflow-scrollbar-combinations.html [ Pass Failure ]
+crbug.com/552494 virtual/rootlayerscrolls/scrollbars/overflow-scrollbar-combinations.html [ Pass Failure ]
+
 crbug.com/380217 [ Linux Win ] fast/shapes/shape-outside-floats/shape-outside-floats-inset-rounded-large-radius.html [ Skip ]
 crbug.com/380217 [ Win ] fast/shapes/shape-outside-floats/shape-outside-floats-inset-rounded-bottom-left.html [ Skip ]
 
@@ -662,8 +703,6 @@
 crbug.com/492664 imported/csswg-test/css-writing-modes-3/text-orientation-script-001.html [ Skip ]
 crbug.com/492664 imported/csswg-test/css-writing-modes-3/text-orientation-script-001e.html [ Failure ]
 
-crbug.com/551966 [ Linux ] inspector-protocol/input/dispatchTouchEvent.html [ Pass Failure Crash ]
-
 # These tests pass but images do not match because of wrong half-leading in vertical-lr
 crbug.com/537080 imported/csswg-test/css-writing-modes-3/vertical-alignment-003.xht [ Failure ]
 crbug.com/537080 imported/csswg-test/css-writing-modes-3/vertical-alignment-009.xht [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/css3/flexbox/flexitem-expected.txt b/third_party/WebKit/LayoutTests/css3/flexbox/flexitem-expected.txt
index 82e780f..32ba6829 100644
--- a/third_party/WebKit/LayoutTests/css3/flexbox/flexitem-expected.txt
+++ b/third_party/WebKit/LayoutTests/css3/flexbox/flexitem-expected.txt
@@ -1,3 +1,4 @@
+CONSOLE WARNING: 'SVGElement.offsetWidth' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
 button
 
 object
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-ImageData-neutered-source-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-ImageData-neutered-source-expected.txt
new file mode 100644
index 0000000..b6d96bc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-ImageData-neutered-source-expected.txt
@@ -0,0 +1,25 @@
+Tests how putImageData and createImageBitmap would react when the source data is neutered
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS len is 4
+PASS image.data[0] is 255
+PASS image.data[1] is 0
+PASS image.data[2] is 0
+PASS image.data[3] is 255
+PASS newImage.data[0] is 255
+PASS newImage.data[1] is 0
+PASS newImage.data[2] is 0
+PASS newImage.data[3] is 255
+PASS len is 0
+PASS image.data[0] is undefined
+PASS image.data[1] is undefined
+PASS image.data[2] is undefined
+PASS image.data[3] is undefined
+PASS context.putImageData(image, 0, 0) threw exception InvalidStateError: Failed to execute 'putImageData' on 'CanvasRenderingContext2D': The source data has been neutered..
+PASS Promise rejected as expected: InvalidStateError: Failed to execute 'createImageBitmap' on 'Window': The source data has been neutered.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-ImageData-neutered-source.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-ImageData-neutered-source.html
new file mode 100644
index 0000000..aebd4a3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-ImageData-neutered-source.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html>
+<body>
+<canvas id="canvas" width="1" height="1"></canvas>
+<script src="../../resources/js-test.js"></script>
+<script>
+jsTestIsAsync = true;
+var worker = new Worker('./resources/worker-onmessage-noop.js');
+
+description("Tests how putImageData and createImageBitmap would react when the source data is neutered");
+
+var imageWidth = 1;
+var imageHeight = 1;
+var arrBuffer = new Uint8ClampedArray(new ArrayBuffer(4));
+arrBuffer[0] = 255;
+arrBuffer[1] = 0;
+arrBuffer[2] = 0;
+arrBuffer[3] = 255;
+var image = new ImageData(arrBuffer, imageWidth, imageHeight);
+var context = document.getElementById("canvas").getContext("2d");
+
+var len = image.data.byteLength;
+shouldBe("len", "4");
+shouldBe("image.data[0]", "255");
+shouldBe("image.data[1]", "0");
+shouldBe("image.data[2]", "0");
+shouldBe("image.data[3]", "255");
+
+context.putImageData(image, 0, 0);
+var newImage = context.getImageData(0, 0, 1, 1);
+shouldBe("newImage.data[0]", "255");
+shouldBe("newImage.data[1]", "0");
+shouldBe("newImage.data[2]", "0");
+shouldBe("newImage.data[3]", "255");
+
+// transfer the array buffer to the worker so that the source data is now neutered
+worker.postMessage({data: image.data.buffer}, [image.data.buffer]);
+
+len = image.data.byteLength;
+shouldBe("len", "0");
+shouldBe("image.data[0]", "undefined");
+shouldBe("image.data[1]", "undefined");
+shouldBe("image.data[2]", "undefined");
+shouldBe("image.data[3]", "undefined");
+
+shouldThrow("context.putImageData(image, 0, 0)");
+
+createImageBitmap(image).then(function() {
+    testFailed('Promise resolved unexpectedly');
+    finishJSTest();
+}, function(err) {
+    testPassed('Promise rejected as expected: ' + err);
+    finishJSTest();
+});
+
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/resources/worker-onmessage-noop.js b/third_party/WebKit/LayoutTests/fast/canvas/resources/worker-onmessage-noop.js
new file mode 100644
index 0000000..c0a352b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/canvas/resources/worker-onmessage-noop.js
@@ -0,0 +1,3 @@
+self.onmessage = function(e) {
+};
+
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-display-expected.txt b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-display-expected.txt
index c9c1bc2..7c3656e 100644
--- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-display-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-display-expected.txt
@@ -1,3 +1,5 @@
+CONSOLE WARNING: 'SVGElement.offsetLeft' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
+CONSOLE WARNING: 'SVGElement.offsetTop' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
 This test checks that the grid items' 'display' computed value matches the specification. It also checks that the grid items are placed in the right grid area.
 
 PASS
diff --git a/third_party/WebKit/LayoutTests/fast/dom/shadow/shadow-dom-event-dispatching-svg-in-shadow-subtree-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/shadow/shadow-dom-event-dispatching-svg-in-shadow-subtree-expected.txt
index fb1d7ef..46333d1 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/shadow/shadow-dom-event-dispatching-svg-in-shadow-subtree-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/dom/shadow/shadow-dom-event-dispatching-svg-in-shadow-subtree-expected.txt
@@ -1,3 +1,7 @@
+CONSOLE WARNING: 'SVGElement.offsetLeft' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
+CONSOLE WARNING: 'SVGElement.offsetWidth' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
+CONSOLE WARNING: 'SVGElement.offsetTop' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
+CONSOLE WARNING: 'SVGElement.offsetHeight' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
 
 
 Composed Shadow Tree will be:
diff --git a/third_party/WebKit/LayoutTests/fast/events/click-focus-anchor.html b/third_party/WebKit/LayoutTests/fast/events/click-focus-anchor.html
index e4384cd8..d90ed86 100644
--- a/third_party/WebKit/LayoutTests/fast/events/click-focus-anchor.html
+++ b/third_party/WebKit/LayoutTests/fast/events/click-focus-anchor.html
@@ -34,8 +34,8 @@
 if (window.testRunner) {
     var testAnchors = document.querySelectorAll('p > a, svg > a > text');
     for (var i = 0; i < testAnchors.length; i++) {
-        var aElement = testAnchors[i];
-        eventSender.mouseMoveTo(aElement.offsetLeft + 2, aElement.offsetTop + 2);
+        var clientRect = testAnchors[i].getBoundingClientRect();
+        eventSender.mouseMoveTo(clientRect.left + 2, clientRect.top + 2);
         eventSender.mouseDown();
         eventSender.mouseUp();
     }
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/resources/text-based-repaint.js b/third_party/WebKit/LayoutTests/fast/repaint/resources/text-based-repaint.js
index 30d9f52..a02cfcbc 100644
--- a/third_party/WebKit/LayoutTests/fast/repaint/resources/text-based-repaint.js
+++ b/third_party/WebKit/LayoutTests/fast/repaint/resources/text-based-repaint.js
@@ -55,9 +55,9 @@
 function forceStyleRecalc()
 {
     if (document.body)
-        document.body.offsetTop;
+        document.body.clientTop;
     else if (document.documentElement)
-        document.documentElement.offsetTop;
+        document.documentElement.clientTop;
 }
 
 function finishRepaintTest()
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/security/blank-origins-not-shown-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/security/blank-origins-not-shown-expected.txt
index f67f8bf..66f040e 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/security/blank-origins-not-shown-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/security/blank-origins-not-shown-expected.txt
@@ -1,5 +1,6 @@
 Tests that blank origins aren't shown in the security panel origins list.
 
+Group: Unknown / Canceled
 <SPAN class=title >
 https://foo.test
 </SPAN>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/security/blank-origins-not-shown.html b/third_party/WebKit/LayoutTests/http/tests/inspector/security/blank-origins-not-shown.html
index 469cc72b..6e760de7 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/security/blank-origins-not-shown.html
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/security/blank-origins-not-shown.html
@@ -14,9 +14,16 @@
     var request2 = new WebInspector.NetworkRequest(targets[0], 0, "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAKCAYAAABmBXS+AAAAPElEQVR42mNgQAMZGRn/GfABkIIdO3b8x6kQpgAEsCpEVgADKAqxKcBQCCLwARRFIBodYygiyiSCighhAO4e2jskhrm3AAAAAElFTkSuQmCC", "https://foo.test", 0, 0, null);
     targets[0].model(WebInspector.NetworkManager).dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.RequestFinished, request2);
 
-    var originTitles = WebInspector.SecurityPanel._instance()._sidebarTree._originSection.childrenListElement.getElementsByClassName("title");
-    for (var i = 0; i < originTitles.length; i++)
-        InspectorTest.dumpDeepInnerHTML(originTitles[i]);
+    for (var key in WebInspector.SecurityPanelSidebarTree.OriginGroupName) {
+        var originGroupName = WebInspector.SecurityPanelSidebarTree.OriginGroupName[key];
+        var originTitles = WebInspector.SecurityPanel._instance()._sidebarTree._originGroups.get(originGroupName).childrenListElement.getElementsByClassName("title");
+        if (originTitles.length > 0) {
+            InspectorTest.addResult("Group: " + originGroupName);
+            for (var originTitle of originTitles)
+                InspectorTest.dumpDeepInnerHTML(originTitle);
+        }
+    }
+
     InspectorTest.completeTest();
 }
 </script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/security/failed-request-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/security/failed-request-expected.txt
index 0b6587a0..a4bbb3a 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/security/failed-request-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/security/failed-request-expected.txt
@@ -1,8 +1,10 @@
 Tests that origins with failed requests are shown correctly in the security panel origins list.
 
+Group: Secure Origins
 <SPAN class=title >
 https://foo.test
 </SPAN>
+Group: Unknown / Canceled
 <SPAN class=title >
 https://does-not-resolve.test
 </SPAN>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/security/failed-request.html b/third_party/WebKit/LayoutTests/http/tests/inspector/security/failed-request.html
index db80538d..63c60290 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/security/failed-request.html
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/security/failed-request.html
@@ -16,9 +16,16 @@
     // Leave the security state unknown.
     targets[0].model(WebInspector.NetworkManager).dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.RequestFinished, request2);
 
-    var originTitles = WebInspector.SecurityPanel._instance()._sidebarTree._originSection.childrenListElement.getElementsByClassName("title");
-    for (var i = 0; i < originTitles.length; i++)
-        InspectorTest.dumpDeepInnerHTML(originTitles[i]);
+    for (var key in WebInspector.SecurityPanelSidebarTree.OriginGroupName) {
+        var originGroupName = WebInspector.SecurityPanelSidebarTree.OriginGroupName[key];
+        var originTitles = WebInspector.SecurityPanel._instance()._sidebarTree._originGroups.get(originGroupName).childrenListElement.getElementsByClassName("title");
+        if (originTitles.length > 0) {
+            InspectorTest.addResult("Group: " + originGroupName);
+            for (var originTitle of originTitles)
+                InspectorTest.dumpDeepInnerHTML(originTitle);
+        }
+    }
+
     InspectorTest.completeTest();
 }
 </script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/security/origin-group-names-unique-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/security/origin-group-names-unique-expected.txt
new file mode 100644
index 0000000..c677a06
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/security/origin-group-names-unique-expected.txt
@@ -0,0 +1,4 @@
+Tests that origin group names in the Security panel are distinct.
+
+Number of names (4) == number of unique names (4): true (expected: true)
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/security/origin-group-names-unique.html b/third_party/WebKit/LayoutTests/http/tests/inspector/security/origin-group-names-unique.html
new file mode 100644
index 0000000..a5f81aa1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/security/origin-group-names-unique.html
@@ -0,0 +1,29 @@
+<html>
+<head>
+<script src="../inspector-test.js"></script>
+<script>
+var initialize_SecurityTest = function()
+{
+    InspectorTest.preloadPanel("security");
+}
+
+function test()
+{
+    var originGroupNameSize = Object.keys(WebInspector.SecurityPanelSidebarTree.OriginGroupName).length;
+
+    var deduplicatedNames = new Set();
+    for (var key in WebInspector.SecurityPanelSidebarTree.OriginGroupName) {
+        var name = WebInspector.SecurityPanelSidebarTree.OriginGroupName[key];
+        deduplicatedNames.add(name);
+    }
+
+    InspectorTest.addResult("Number of names (" + originGroupNameSize + ") == number of unique names (" + deduplicatedNames.size + "): " + (originGroupNameSize == deduplicatedNames.size) + " (expected: true)");
+
+    InspectorTest.completeTest();
+}
+</script>
+</head>
+<body onload="runTest()">
+<p>Tests that origin group names in the Security panel are distinct.</p>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/svg/W3C-SVG-1.1-SE/text-intro-09-b.svg b/third_party/WebKit/LayoutTests/svg/W3C-SVG-1.1-SE/text-intro-09-b.svg
index 3bd9ca4..7d411870 100644
--- a/third_party/WebKit/LayoutTests/svg/W3C-SVG-1.1-SE/text-intro-09-b.svg
+++ b/third_party/WebKit/LayoutTests/svg/W3C-SVG-1.1-SE/text-intro-09-b.svg
@@ -71,7 +71,7 @@
   </g>
   <rect id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000000"/>
   <script>
-    document.documentElement.offsetLeft;
+    document.documentElement.clientLeft;
   </script>
   <!-- comment out this watermark once the test is approved -->
   <!--<g id="draft-watermark">
diff --git a/third_party/WebKit/LayoutTests/svg/animations/resources/SVGTestCase.js b/third_party/WebKit/LayoutTests/svg/animations/resources/SVGTestCase.js
index c53ac75..f93c8df5 100644
--- a/third_party/WebKit/LayoutTests/svg/animations/resources/SVGTestCase.js
+++ b/third_party/WebKit/LayoutTests/svg/animations/resources/SVGTestCase.js
@@ -45,8 +45,9 @@
 
 function clickAt(x, y) {
     // Translation due to <h1> above us
-    x = x + rootSVGElement.offsetLeft;
-    y = y + rootSVGElement.offsetTop;
+    var clientRect = rootSVGElement.getBoundingClientRect();
+    x = x + clientRect.left;
+    y = y + clientRect.top;
 
     if (window.eventSender) {
         eventSender.mouseMoveTo(x, y);
diff --git a/third_party/WebKit/LayoutTests/svg/css/cursor-replace.svg b/third_party/WebKit/LayoutTests/svg/css/cursor-replace.svg
index c19debc..2827edc1 100644
--- a/third_party/WebKit/LayoutTests/svg/css/cursor-replace.svg
+++ b/third_party/WebKit/LayoutTests/svg/css/cursor-replace.svg
@@ -1,7 +1,7 @@
 <svg version="1.1" xmlns="http://www.w3.org/2000/svg">
 <script>
 function runTest() {
-    g.offsetTop;
+    g.clientTop;
     g.removeChild(g.firstChild);
     if (g.firstChild)
         setTimeout(runTest(),0);
@@ -14,7 +14,7 @@
         testRunner.dumpAsText();
         testRunner.waitUntilDone();
     }
-    
+
     g = document.getElementById("g1");
     if (location.hash != "#2") {
         if (location.hash)
diff --git a/third_party/WebKit/LayoutTests/svg/custom/animate-reference-crash-expected.txt b/third_party/WebKit/LayoutTests/svg/custom/animate-reference-crash-expected.txt
index db9481e..bf7f6f5 100644
--- a/third_party/WebKit/LayoutTests/svg/custom/animate-reference-crash-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/custom/animate-reference-crash-expected.txt
@@ -1,2 +1,7 @@
+CONSOLE WARNING: 'SVGElement.offsetParent' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
+CONSOLE WARNING: 'SVGElement.offsetTop' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
+CONSOLE WARNING: 'SVGElement.offsetLeft' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
+CONSOLE WARNING: 'SVGElement.offsetWidth' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
+CONSOLE WARNING: 'SVGElement.offsetHeight' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
 CONSOLE WARNING: SVG's SMIL animations (<animate>, <set>, etc.) are deprecated and will be removed. Please use CSS animations or Web animations instead.
 PASS
diff --git a/third_party/WebKit/LayoutTests/svg/custom/detached-outermost-svg-crash-expected.txt b/third_party/WebKit/LayoutTests/svg/custom/detached-outermost-svg-crash-expected.txt
index 4ad3823..9204887 100644
--- a/third_party/WebKit/LayoutTests/svg/custom/detached-outermost-svg-crash-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/custom/detached-outermost-svg-crash-expected.txt
@@ -1 +1,6 @@
+CONSOLE WARNING: 'SVGElement.offsetParent' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
+CONSOLE WARNING: 'SVGElement.offsetTop' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
+CONSOLE WARNING: 'SVGElement.offsetLeft' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
+CONSOLE WARNING: 'SVGElement.offsetWidth' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
+CONSOLE WARNING: 'SVGElement.offsetHeight' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
 PASSED -- webkit did not crash in SVGSVGElement::isOutermostSVG(). See https://bugs.webkit.org/show_bug.cgi?id=25105
diff --git a/third_party/WebKit/LayoutTests/svg/custom/font-platformDestroy-crash.svg b/third_party/WebKit/LayoutTests/svg/custom/font-platformDestroy-crash.svg
index 632ae948..01cb043 100644
--- a/third_party/WebKit/LayoutTests/svg/custom/font-platformDestroy-crash.svg
+++ b/third_party/WebKit/LayoutTests/svg/custom/font-platformDestroy-crash.svg
@@ -29,7 +29,7 @@
         var parent = style.parentNode;
 
         for (var t = 0; t < 50; t++) {
-            parent.offsetTop;
+            parent.clientTop;
             parent.removeChild(style);
             parent.appendChild(style);
         }
diff --git a/third_party/WebKit/LayoutTests/svg/custom/pointer-events-invalid-fill.svg b/third_party/WebKit/LayoutTests/svg/custom/pointer-events-invalid-fill.svg
index 7053bfd..0f7a97e5 100644
--- a/third_party/WebKit/LayoutTests/svg/custom/pointer-events-invalid-fill.svg
+++ b/third_party/WebKit/LayoutTests/svg/custom/pointer-events-invalid-fill.svg
@@ -64,7 +64,7 @@
       }
       function runTest() {
         if (window.eventSender) {
-          document.documentElement.offsetLeft;
+          document.documentElement.clientLeft;
           eventSender.mouseMoveTo(30, 100);
         }
       }
diff --git a/third_party/WebKit/LayoutTests/svg/custom/touch-events.html b/third_party/WebKit/LayoutTests/svg/custom/touch-events.html
index 6d13a69..9dd4d8a 100644
--- a/third_party/WebKit/LayoutTests/svg/custom/touch-events.html
+++ b/third_party/WebKit/LayoutTests/svg/custom/touch-events.html
@@ -34,8 +34,9 @@
       document.write('This test does not work in manual mode.');
     } else {
       var svg = document.getElementById('svg');
-      var positionX = svg.offsetLeft + 30;
-      var positionY = svg.offsetTop + 30;
+      var clientRect = svg.getBoundingClientRect();
+      var positionX = clientRect.left + 30;
+      var positionY = clientRect.top + 30;
 
       // Touch, move, end.
       eventSender.addTouchPoint(positionX, positionY);
@@ -83,4 +84,4 @@
     <rect id="rect" x="20" y="20" width="60" height="60" fill="green" onclick="handleClick()" ontouchstart="handleTouchStart()" ontouchmove="handleTouchMove()"   ontouchend="handleTouchEnd()" ontouchcancel="handleTouchCancel()"/>
   </svg>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/resources/SVGTestCase.js b/third_party/WebKit/LayoutTests/svg/dynamic-updates/resources/SVGTestCase.js
index b27ff89..1709ea80 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/resources/SVGTestCase.js
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/resources/SVGTestCase.js
@@ -65,8 +65,9 @@
 
 function clickAt(x, y) {
     // Translation due to <h1> above us
-    x = x + rootSVGElement.offsetLeft;
-    y = y + rootSVGElement.offsetTop;
+    var clientRect = rootSVGElement.getBoundingClientRect();
+    x = x + clientRect.left;
+    y = y + clientRect.top;
 
     if (window.eventSender) {
         eventSender.mouseMoveTo(x, y);
diff --git a/third_party/WebKit/LayoutTests/svg/foreignObject/fO-percentage-height-style-expected.txt b/third_party/WebKit/LayoutTests/svg/foreignObject/fO-percentage-height-style-expected.txt
index b3ad3a7..df1d95a 100644
--- a/third_party/WebKit/LayoutTests/svg/foreignObject/fO-percentage-height-style-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/foreignObject/fO-percentage-height-style-expected.txt
@@ -3,9 +3,9 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS nestedSvg.offsetHeight is 250
-PASS nestedSvg.offsetHeight is 125
-PASS nestedSvg.offsetHeight is 200
+PASS getComputedStyle(nestedSvg).height is '250px'
+PASS getComputedStyle(nestedSvg).height is '125px'
+PASS getComputedStyle(nestedSvg).height is '200px'
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/svg/foreignObject/fO-percentage-height-style.html b/third_party/WebKit/LayoutTests/svg/foreignObject/fO-percentage-height-style.html
index 16475cb..bce3cfd 100644
--- a/third_party/WebKit/LayoutTests/svg/foreignObject/fO-percentage-height-style.html
+++ b/third_party/WebKit/LayoutTests/svg/foreignObject/fO-percentage-height-style.html
@@ -10,12 +10,12 @@
   description("Test use of percentages inside foreignObject");
 
   var nestedSvg = document.querySelectorAll('svg')[1];
-  shouldBe("nestedSvg.offsetHeight", "250");
+  shouldBe("getComputedStyle(nestedSvg).height", "'250px'");
 
   nestedSvg.style.height = "50%";
-  shouldBe("nestedSvg.offsetHeight", "125");
+  shouldBe("getComputedStyle(nestedSvg).height", "'125px'");
 
   var foreignObject = nestedSvg.parentNode;
   foreignObject.height.baseVal.value = 400;
-  shouldBe("nestedSvg.offsetHeight", "200");
+  shouldBe("getComputedStyle(nestedSvg).height", "'200px'");
 </script>
diff --git a/third_party/WebKit/LayoutTests/svg/text/inline-text-destroy-attributes-crash.xhtml b/third_party/WebKit/LayoutTests/svg/text/inline-text-destroy-attributes-crash.xhtml
index 6b4d01d..17b0f3c 100644
--- a/third_party/WebKit/LayoutTests/svg/text/inline-text-destroy-attributes-crash.xhtml
+++ b/third_party/WebKit/LayoutTests/svg/text/inline-text-destroy-attributes-crash.xhtml
@@ -10,13 +10,13 @@
 <text id="text2"></text>
 <script>
     if (window.testRunner)
-	    testRunner.dumpAsText();
+        testRunner.dumpAsText();
 
     var range = document.createRange();
     range.setStart(document.getElementById("use1"), 0);
     range.setEnd(document.getElementById("text2"), 0);
     (new XMLSerializer()).serializeToString(range.extractContents());
-	document.getElementById('text1').offsetTop;
+    document.getElementById('text1').clientTop;
     range.surroundContents(document.getElementById("tspan1"));
 </script>
 </svg>
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index d8b897b..48d165e3 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -381,6 +381,7 @@
     method start
     setter onmessage
 interface Notification : EventTarget
+    static getter maxActions
     static getter permission
     getter body
     getter data
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
index e096619..886ce38 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -379,6 +379,7 @@
 [Worker]     method start
 [Worker]     setter onmessage
 [Worker] interface Notification : EventTarget
+[Worker]     static getter maxActions
 [Worker]     static getter permission
 [Worker]     getter body
 [Worker]     getter data
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
index 12b0967..e26f5d41 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -3095,6 +3095,7 @@
     method constructor
     method item
 interface Notification : EventTarget
+    static getter maxActions
     static getter permission
     static method requestPermission
     getter body
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
index c832f54..9af80ab 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -369,6 +369,7 @@
 [Worker]     method start
 [Worker]     setter onmessage
 [Worker] interface Notification : EventTarget
+[Worker]     static getter maxActions
 [Worker]     static getter permission
 [Worker]     getter body
 [Worker]     getter data
diff --git a/third_party/WebKit/PerformanceTests/Canvas/asyncPngImageEncoding.js b/third_party/WebKit/PerformanceTests/Canvas/asyncPngImageEncoding.js
deleted file mode 100644
index d6831174b7..0000000
--- a/third_party/WebKit/PerformanceTests/Canvas/asyncPngImageEncoding.js
+++ /dev/null
@@ -1,32 +0,0 @@
-var isDone = false;
-
-function createCanvas4kBy4k(canvas_id) {
-    var myCanvas = document.createElement("canvas");
-    myCanvas.id = canvas_id;
-    myCanvas.width = 4000;
-    myCanvas.height = 4000;
-    myCanvas.getContext("2d").fillStyle = 'green';
-    myCanvas.getContext("2d").fillRect(0, 0, myCanvas.width, myCanvas.height);
-    return myCanvas;
-}
-
-function invokeToBlobPng(myCanvas) {
-    var startTime = PerfTestRunner.now();
-    myCanvas.toBlob(function(blob){
-        PerfTestRunner.measureValueAsync(PerfTestRunner.now() - startTime);
-        if (!isDone) {
-            PerfTestRunner.gc();
-            runTest(myCanvas);
-        }
-    });
-}
-
-function draw() {
-    if (!isDone)
-        requestAnimationFrame(draw);
-}
-
-function runTest(myCanvas) {
-    draw(); //repeatedly draw the frame to keep main thread busy
-    invokeToBlobPng(myCanvas);
-}
diff --git a/third_party/WebKit/PerformanceTests/Canvas/idlePngImageEncoding.html b/third_party/WebKit/PerformanceTests/Canvas/idlePngImageEncoding.html
deleted file mode 100644
index 1862cb2e..0000000
--- a/third_party/WebKit/PerformanceTests/Canvas/idlePngImageEncoding.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<script src = "../resources/runner.js"></script>
-<script src = "./asyncPngImageEncoding.js"></script>
-<script>
-
-var canvas_idle = null;
-
-window.onload = function () {
-    window.internals.settings.setIdleCanvasImageEncodingEnabled(true);
-    canvas_idle = createCanvas4kBy4k("canvas_idle");
-    PerfTestRunner.prepareToMeasureValuesAsync({
-        unit: 'ms',
-        done: function () {
-            isDone = true;
-        },
-        description: "Measures performance of canvas." + 
-            "toBlob that has png image encoding performed in idle periods."
-    });
-    runTest(canvas_idle);
-};
-</script>
-</body>
-</html>
-
diff --git a/third_party/WebKit/PerformanceTests/Canvas/threadedPngImageEncoding.html b/third_party/WebKit/PerformanceTests/Canvas/threadedPngImageEncoding.html
deleted file mode 100644
index a362ef4..0000000
--- a/third_party/WebKit/PerformanceTests/Canvas/threadedPngImageEncoding.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<script src = "../resources/runner.js"></script>
-<script src = "./asyncPngImageEncoding.js"></script>
-<script>
-
-var canvas_threaded = null;
-
-window.onload = function () {
-    window.internals.settings.setIdleCanvasImageEncodingEnabled(false);
-    canvas_threaded = createCanvas4kBy4k("canvas_threaded");
-    PerfTestRunner.prepareToMeasureValuesAsync({
-        unit: 'ms',
-        done: function () {
-            isDone = true;
-        },
-        description: "Measures performance of canvas." + 
-            "toBlob that has png image encoding performed on a separate thread."
-    });
-    runTest(canvas_threaded);
-};
-</script>
-</body>
-</html>
-
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptPromisePropertyBase.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptPromisePropertyBase.cpp
index 3685a094..b54a8b06 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptPromisePropertyBase.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptPromisePropertyBase.cpp
@@ -159,8 +159,8 @@
     for (WeakPersistentSet::iterator i = m_wrappers.begin(); i != m_wrappers.end(); ++i) {
         v8::Local<v8::Object> wrapper = (*i)->newLocal(m_isolate);
         if (!wrapper.IsEmpty()) {
-            wrapper->DeleteHiddenValue(resolverName());
-            wrapper->DeleteHiddenValue(promiseName());
+            V8HiddenValue::deleteHiddenValue(m_isolate, wrapper, resolverName());
+            V8HiddenValue::deleteHiddenValue(m_isolate, wrapper, promiseName());
         }
     }
     m_wrappers.clear();
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8EventListenerList.h b/third_party/WebKit/Source/bindings/core/v8/V8EventListenerList.h
index 5e8e8923..b3de613 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8EventListenerList.h
+++ b/third_party/WebKit/Source/bindings/core/v8/V8EventListenerList.h
@@ -64,7 +64,7 @@
     static void clearWrapper(v8::Local<v8::Object> listenerObject, bool isAttribute, v8::Isolate* isolate)
     {
         v8::Local<v8::String> wrapperProperty = getHiddenProperty(isAttribute, isolate);
-        listenerObject->DeleteHiddenValue(wrapperProperty);
+        V8HiddenValue::deleteHiddenValue(isolate, listenerObject, wrapperProperty);
     }
 
     CORE_EXPORT static PassRefPtrWillBeRawPtr<EventListener> getEventListener(ScriptState*, v8::Local<v8::Value>, bool isAttribute, ListenerLookupType);
@@ -74,7 +74,7 @@
     {
         v8::HandleScope scope(scriptState->isolate());
         ASSERT(scriptState->isolate()->InContext());
-        v8::Local<v8::Value> listener = object->GetHiddenValue(wrapperProperty);
+        v8::Local<v8::Value> listener = V8HiddenValue::getHiddenValue(scriptState->isolate(), object, wrapperProperty);
         if (listener.IsEmpty())
             return 0;
         return static_cast<V8EventListener*>(v8::External::Cast(*listener)->Value());
@@ -103,7 +103,7 @@
 
     RefPtrWillBeRawPtr<V8EventListener> wrapperPtr = WrapperType::create(object, isAttribute, scriptState);
     if (wrapperPtr)
-        object->SetHiddenValue(wrapperProperty, v8::External::New(isolate, wrapperPtr.get()));
+        V8HiddenValue::setHiddenValue(isolate, object, wrapperProperty, v8::External::New(isolate, wrapperPtr.get()));
 
     return wrapperPtr;
 }
diff --git a/third_party/WebKit/Source/bindings/templates/methods.cpp b/third_party/WebKit/Source/bindings/templates/methods.cpp
index 8ab03a55..ab0d03e 100644
--- a/third_party/WebKit/Source/bindings/templates/methods.cpp
+++ b/third_party/WebKit/Source/bindings/templates/methods.cpp
@@ -541,7 +541,7 @@
     }
 
     {# The findInstanceInPrototypeChain() call above only returns a non-empty handle if info.This() is an Object. #}
-    v8::Local<v8::Value> hiddenValue = v8::Local<v8::Object>::Cast(info.This())->GetHiddenValue(v8AtomicString(info.GetIsolate(), "{{method.name}}"));
+    v8::Local<v8::Value> hiddenValue = V8HiddenValue::getHiddenValue(info.GetIsolate(), v8::Local<v8::Object>::Cast(info.This()), v8AtomicString(info.GetIsolate(), "{{method.name}}"));
     if (!hiddenValue.IsEmpty()) {
         v8SetReturnValue(info, hiddenValue);
         return;
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceCheckSecurity.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceCheckSecurity.cpp
index 40d7dcfbe..d2ac18e6 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceCheckSecurity.cpp
+++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceCheckSecurity.cpp
@@ -281,7 +281,7 @@
         return;
     }
 
-    v8::Local<v8::Value> hiddenValue = v8::Local<v8::Object>::Cast(info.This())->GetHiddenValue(v8AtomicString(info.GetIsolate(), "doNotCheckSecurityVoidMethod"));
+    v8::Local<v8::Value> hiddenValue = V8HiddenValue::getHiddenValue(info.GetIsolate(), v8::Local<v8::Object>::Cast(info.This()), v8AtomicString(info.GetIsolate(), "doNotCheckSecurityVoidMethod"));
     if (!hiddenValue.IsEmpty()) {
         v8SetReturnValue(info, hiddenValue);
         return;
@@ -329,7 +329,7 @@
         return;
     }
 
-    v8::Local<v8::Value> hiddenValue = v8::Local<v8::Object>::Cast(info.This())->GetHiddenValue(v8AtomicString(info.GetIsolate(), "doNotCheckSecurityDoNotCheckSignatureVoidMethod"));
+    v8::Local<v8::Value> hiddenValue = V8HiddenValue::getHiddenValue(info.GetIsolate(), v8::Local<v8::Object>::Cast(info.This()), v8AtomicString(info.GetIsolate(), "doNotCheckSecurityDoNotCheckSignatureVoidMethod"));
     if (!hiddenValue.IsEmpty()) {
         v8SetReturnValue(info, hiddenValue);
         return;
@@ -377,7 +377,7 @@
         return;
     }
 
-    v8::Local<v8::Value> hiddenValue = v8::Local<v8::Object>::Cast(info.This())->GetHiddenValue(v8AtomicString(info.GetIsolate(), "doNotCheckSecurityPerWorldBindingsVoidMethod"));
+    v8::Local<v8::Value> hiddenValue = V8HiddenValue::getHiddenValue(info.GetIsolate(), v8::Local<v8::Object>::Cast(info.This()), v8AtomicString(info.GetIsolate(), "doNotCheckSecurityPerWorldBindingsVoidMethod"));
     if (!hiddenValue.IsEmpty()) {
         v8SetReturnValue(info, hiddenValue);
         return;
@@ -425,7 +425,7 @@
         return;
     }
 
-    v8::Local<v8::Value> hiddenValue = v8::Local<v8::Object>::Cast(info.This())->GetHiddenValue(v8AtomicString(info.GetIsolate(), "doNotCheckSecurityPerWorldBindingsVoidMethod"));
+    v8::Local<v8::Value> hiddenValue = V8HiddenValue::getHiddenValue(info.GetIsolate(), v8::Local<v8::Object>::Cast(info.This()), v8AtomicString(info.GetIsolate(), "doNotCheckSecurityPerWorldBindingsVoidMethod"));
     if (!hiddenValue.IsEmpty()) {
         v8SetReturnValue(info, hiddenValue);
         return;
@@ -473,7 +473,7 @@
         return;
     }
 
-    v8::Local<v8::Value> hiddenValue = v8::Local<v8::Object>::Cast(info.This())->GetHiddenValue(v8AtomicString(info.GetIsolate(), "doNotCheckSecurityUnforgeableVoidMethod"));
+    v8::Local<v8::Value> hiddenValue = V8HiddenValue::getHiddenValue(info.GetIsolate(), v8::Local<v8::Object>::Cast(info.This()), v8AtomicString(info.GetIsolate(), "doNotCheckSecurityUnforgeableVoidMethod"));
     if (!hiddenValue.IsEmpty()) {
         v8SetReturnValue(info, hiddenValue);
         return;
diff --git a/third_party/WebKit/Source/core/core.gypi b/third_party/WebKit/Source/core/core.gypi
index a623167..c34fd02 100644
--- a/third_party/WebKit/Source/core/core.gypi
+++ b/third_party/WebKit/Source/core/core.gypi
@@ -1983,6 +1983,7 @@
             'paint/NinePieceImageGrid.h',
             'paint/NinePieceImagePainter.cpp',
             'paint/NinePieceImagePainter.h',
+            'paint/ObjectPaintProperties.cpp',
             'paint/ObjectPaintProperties.h',
             'paint/ObjectPainter.cpp',
             'paint/ObjectPainter.h',
diff --git a/third_party/WebKit/Source/core/dom/StyleEngine.cpp b/third_party/WebKit/Source/core/dom/StyleEngine.cpp
index 16804d7..4fde5b99 100644
--- a/third_party/WebKit/Source/core/dom/StyleEngine.cpp
+++ b/third_party/WebKit/Source/core/dom/StyleEngine.cpp
@@ -48,6 +48,7 @@
 #include "core/page/Page.h"
 #include "core/svg/SVGStyleElement.h"
 #include "platform/TraceEvent.h"
+#include "platform/fonts/FontCache.h"
 
 namespace blink {
 
@@ -492,6 +493,7 @@
     m_fontSelector->updateGenericFontFamilySettings(*m_document);
     if (m_resolver)
         m_resolver->invalidateMatchedPropertiesCache();
+    FontCache::fontCache()->invalidateShapeCache();
 }
 
 void StyleEngine::removeFontFaceRules(const WillBeHeapVector<RawPtrWillBeMember<const StyleRuleFontFace>>& fontFaceRules)
diff --git a/third_party/WebKit/Source/core/frame/FrameView.h b/third_party/WebKit/Source/core/frame/FrameView.h
index e6884a7..e704eaa 100644
--- a/third_party/WebKit/Source/core/frame/FrameView.h
+++ b/third_party/WebKit/Source/core/frame/FrameView.h
@@ -373,7 +373,7 @@
 
     // The window that hosts the FrameView. The FrameView will communicate scrolls and repaints to the
     // host window in the window's coordinate space.
-    HostWindow* hostWindow() const override;
+    HostWindow* hostWindow() const;
 
     // Returns a clip rect in host window coordinates. Used to clip the blit on a scroll.
     IntRect windowClipRect(IncludeScrollbarsInRect = ExcludeScrollbars) const;
diff --git a/third_party/WebKit/Source/core/frame/Settings.in b/third_party/WebKit/Source/core/frame/Settings.in
index 4ff73b5..c54a085 100644
--- a/third_party/WebKit/Source/core/frame/Settings.in
+++ b/third_party/WebKit/Source/core/frame/Settings.in
@@ -93,9 +93,6 @@
 antialiasedClips2dCanvasEnabled initial=false
 accelerated2dCanvasMSAASampleCount type=int, initial=0
 
-# Indicate if scheduling png image encoder of canvas toBlob on idle periods is enabled
-idleCanvasImageEncodingEnabled initial=true
-
 # WebAudio support.
 webAudioEnabled initial=false
 
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.cpp b/third_party/WebKit/Source/core/frame/UseCounter.cpp
index 10e8a55..11b0dc8d 100644
--- a/third_party/WebKit/Source/core/frame/UseCounter.cpp
+++ b/third_party/WebKit/Source/core/frame/UseCounter.cpp
@@ -921,6 +921,7 @@
     case SVGSMILElementInDocument:
     case SVGSMILAnimationInImageRegardlessOfCache:
         return "SVG's SMIL animations (<animate>, <set>, etc.) are deprecated and will be removed. Please use CSS animations or Web animations instead.";
+
     case PrefixedPerformanceClearResourceTimings:
         return replacedBy("Performance.webkitClearResourceTimings", "Performance.clearResourceTimings");
 
@@ -939,6 +940,21 @@
     case BluetoothDeviceInstanceId:
         return replacedBy("BluetoothDevice.instanceID", "BluetoothDevice.id");
 
+    case V8SVGElement_OffsetParent_AttributeGetter:
+        return "'SVGElement.offsetParent' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.";
+
+    case V8SVGElement_OffsetTop_AttributeGetter:
+        return "'SVGElement.offsetTop' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.";
+
+    case V8SVGElement_OffsetLeft_AttributeGetter:
+        return "'SVGElement.offsetLeft' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.";
+
+    case V8SVGElement_OffsetWidth_AttributeGetter:
+        return "'SVGElement.offsetWidth' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.";
+
+    case V8SVGElement_OffsetHeight_AttributeGetter:
+        return "'SVGElement.offsetHeight' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.";
+
     // Features that aren't deprecated don't have a deprecation message.
     default:
         return String();
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
index be8027d9..bf12c2f 100644
--- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
@@ -558,7 +558,7 @@
     RefPtr<DOMUint8ClampedArray> imageDataRef(imageData->data());
 
     RefPtr<CanvasAsyncBlobCreator> asyncCreatorRef = CanvasAsyncBlobCreator::create(imageDataRef.release(), encodingMimeType, imageData->size(), callback);
-    if (document().settings()->idleCanvasImageEncodingEnabled() && Platform::current()->isThreadedCompositingEnabled() && (encodingMimeType == DefaultMimeType)) {
+    if (Platform::current()->isThreadedCompositingEnabled() && (encodingMimeType == DefaultMimeType)) {
         asyncCreatorRef->scheduleAsyncBlobCreation(true);
     } else {
         asyncCreatorRef->scheduleAsyncBlobCreation(false, quality);
diff --git a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.cpp b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.cpp
index 422ab06..284ba8f 100644
--- a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.cpp
+++ b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.cpp
@@ -93,6 +93,10 @@
         exceptionState.throwDOMException(IndexSizeError, String::format("The source %s provided is 0.", sw ? "height" : "width"));
         return ScriptPromise();
     }
+    if (data->data()->bufferBase()->isNeutered()) {
+        exceptionState.throwDOMException(InvalidStateError, "The source data has been neutered.");
+        return ScriptPromise();
+    }
     // FIXME: make ImageBitmap creation asynchronous crbug.com/258082
     return fulfillImageBitmap(scriptState, ImageBitmap::create(data, IntRect(sx, sy, sw, sh)));
 }
diff --git a/third_party/WebKit/Source/core/inspector/v8/InspectorWrapper.cpp b/third_party/WebKit/Source/core/inspector/v8/InspectorWrapper.cpp
index 56d45a7..7acf308 100644
--- a/third_party/WebKit/Source/core/inspector/v8/InspectorWrapper.cpp
+++ b/third_party/WebKit/Source/core/inspector/v8/InspectorWrapper.cpp
@@ -51,7 +51,7 @@
 void* InspectorWrapperBase::unwrap(v8::Local<v8::Object> object, const char* name)
 {
     v8::Isolate* isolate = object->GetIsolate();
-    v8::Local<v8::Value> value = object->GetHiddenValue(v8InternalizedString(isolate, name));
+    v8::Local<v8::Value> value = V8HiddenValue::getHiddenValue(isolate, object, v8InternalizedString(isolate, name));
     if (value.IsEmpty())
         return nullptr;
     if (!value->IsExternal())
diff --git a/third_party/WebKit/Source/core/inspector/v8/InspectorWrapper.h b/third_party/WebKit/Source/core/inspector/v8/InspectorWrapper.h
index 736884ad..6a9cb96 100644
--- a/third_party/WebKit/Source/core/inspector/v8/InspectorWrapper.h
+++ b/third_party/WebKit/Source/core/inspector/v8/InspectorWrapper.h
@@ -5,6 +5,7 @@
 #ifndef InspectorWrapper_h
 #define InspectorWrapper_h
 
+#include "bindings/core/v8/V8HiddenValue.h"
 #include "platform/heap/Handle.h"
 #include "wtf/PassRefPtr.h"
 #include "wtf/RefPtr.h"
@@ -85,7 +86,7 @@
         typename blink::InspectorWrapperTypeTrait<T>::Type impl(object);
         v8::Isolate* isolate = context->GetIsolate();
         v8::Local<v8::External> objectReference = v8::External::New(isolate, new WeakCallbackData(isolate, impl, result));
-        result->SetHiddenValue(v8InternalizedString(isolate, hiddenPropertyName), objectReference);
+        V8HiddenValue::setHiddenValue(isolate, result, v8InternalizedString(isolate, hiddenPropertyName), objectReference);
         return result;
     }
     static T* unwrap(v8::Local<v8::Object> object)
diff --git a/third_party/WebKit/Source/core/paint/ObjectPaintProperties.cpp b/third_party/WebKit/Source/core/paint/ObjectPaintProperties.cpp
new file mode 100644
index 0000000..73743be
--- /dev/null
+++ b/third_party/WebKit/Source/core/paint/ObjectPaintProperties.cpp
@@ -0,0 +1,20 @@
+// 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 "config.h"
+#include "core/paint/ObjectPaintProperties.h"
+
+namespace blink {
+
+TransformPaintPropertyNode* ObjectPaintProperties::transformForLayerContents() const
+{
+    // See the hierarchy diagram in the header.
+    if (m_transform)
+        return m_transform.get();
+    if (m_paintOffsetTranslation)
+        return m_paintOffsetTranslation.get();
+    return nullptr;
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/ObjectPaintProperties.h b/third_party/WebKit/Source/core/paint/ObjectPaintProperties.h
index 72886970..0148768e 100644
--- a/third_party/WebKit/Source/core/paint/ObjectPaintProperties.h
+++ b/third_party/WebKit/Source/core/paint/ObjectPaintProperties.h
@@ -7,6 +7,7 @@
 
 #include "platform/graphics/paint/EffectPaintPropertyNode.h"
 #include "platform/graphics/paint/TransformPaintPropertyNode.h"
+#include "wtf/PassOwnPtr.h"
 #include "wtf/PassRefPtr.h"
 #include "wtf/RefPtr.h"
 
@@ -41,12 +42,16 @@
     // +---[ transform ]                    The space created by CSS transform.
     //     +---[ perspective ]              The space created by CSS perspective.
     //         +---[ scrollTranslation ]    The space created by overflow clip.
-    const TransformPaintPropertyNode* paintOffsetTranslation() const { return m_paintOffsetTranslation.get(); }
-    const TransformPaintPropertyNode* transform() const { return m_transform.get(); }
-    const TransformPaintPropertyNode* perspective() const { return m_perspective.get(); }
-    const TransformPaintPropertyNode* scrollTranslation() const { return m_scrollTranslation.get(); }
+    TransformPaintPropertyNode* paintOffsetTranslation() const { return m_paintOffsetTranslation.get(); }
+    TransformPaintPropertyNode* transform() const { return m_transform.get(); }
+    TransformPaintPropertyNode* perspective() const { return m_perspective.get(); }
+    TransformPaintPropertyNode* scrollTranslation() const { return m_scrollTranslation.get(); }
 
-    const EffectPaintPropertyNode* effect() const { return m_effect.get(); }
+    // Transform that applies to layer contents, or nullptr if this object
+    // doesn't define one.
+    TransformPaintPropertyNode* transformForLayerContents() const;
+
+    EffectPaintPropertyNode* effect() const { return m_effect.get(); }
 
 private:
     ObjectPaintProperties(
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
index 4e6850d..71cd3e2 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
@@ -16,6 +16,7 @@
 #include "core/paint/FilterPainter.h"
 #include "core/paint/LayerClipRecorder.h"
 #include "core/paint/LayerFixedPositionRecorder.h"
+#include "core/paint/ObjectPaintProperties.h"
 #include "core/paint/PaintInfo.h"
 #include "core/paint/PaintLayer.h"
 #include "core/paint/SVGClipPainter.h"
@@ -23,11 +24,14 @@
 #include "core/paint/ScrollRecorder.h"
 #include "core/paint/ScrollableAreaPainter.h"
 #include "core/paint/Transform3DRecorder.h"
+#include "platform/RuntimeEnabledFeatures.h"
 #include "platform/geometry/FloatPoint3D.h"
 #include "platform/graphics/GraphicsLayer.h"
 #include "platform/graphics/paint/ClipPathRecorder.h"
 #include "platform/graphics/paint/ClipRecorder.h"
 #include "platform/graphics/paint/CompositingDisplayItem.h"
+#include "platform/graphics/paint/PaintChunkProperties.h"
+#include "platform/graphics/paint/ScopedPaintChunkProperties.h"
 #include "platform/graphics/paint/SubsequenceRecorder.h"
 #include "platform/graphics/paint/Transform3DDisplayItem.h"
 #include "wtf/Optional.h"
@@ -309,6 +313,18 @@
         FilterPainter filterPainter(m_paintLayer, context, offsetFromRoot, layerFragments.isEmpty() ? ClipRect() : layerFragments[0].backgroundRect, localPaintingInfo, paintFlags,
             rootRelativeBounds, rootRelativeBoundsComputed);
 
+        Optional<ScopedPaintChunkProperties> scopedPaintChunkProperties;
+        if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) {
+            if (const auto* objectProperties = m_paintLayer.layoutObject()->objectPaintProperties()) {
+                PaintChunkProperties properties(context->paintController().currentPaintChunkProperties());
+                if (TransformPaintPropertyNode* transform = objectProperties->transformForLayerContents())
+                    properties.transform = transform;
+                if (EffectPaintPropertyNode* effect = objectProperties->effect())
+                    properties.effect = effect;
+                scopedPaintChunkProperties.emplace(context->paintController(), properties);
+            }
+        }
+
         bool shouldPaintBackground = isPaintingCompositedBackground && shouldPaintContent && !selectionOnly;
         bool shouldPaintNegZOrderList = (isPaintingScrollingContent && isPaintingOverflowContents) || (!isPaintingScrollingContent && isPaintingCompositedBackground);
         bool shouldPaintOwnContents = isPaintingCompositedForeground && shouldPaintContent;
diff --git a/third_party/WebKit/Source/core/svg/SVGElement.idl b/third_party/WebKit/Source/core/svg/SVGElement.idl
index bace75e5..b16555f 100644
--- a/third_party/WebKit/Source/core/svg/SVGElement.idl
+++ b/third_party/WebKit/Source/core/svg/SVGElement.idl
@@ -35,11 +35,11 @@
     void blur();
 
     // TODO(tanay.c): SVGElement.offset* are non-standard. crbug.com/463116
-    [Measure, PerWorldBindings] readonly attribute Element? offsetParent;
-    [Measure] readonly attribute long offsetTop;
-    [Measure] readonly attribute long offsetLeft;
-    [Measure] readonly attribute long offsetWidth;
-    [Measure] readonly attribute long offsetHeight;
+    [DeprecateAs=V8SVGElement_OffsetParent_AttributeGetter, PerWorldBindings] readonly attribute Element? offsetParent;
+    [DeprecateAs=V8SVGElement_OffsetTop_AttributeGetter] readonly attribute long offsetTop;
+    [DeprecateAs=V8SVGElement_OffsetLeft_AttributeGetter] readonly attribute long offsetLeft;
+    [DeprecateAs=V8SVGElement_OffsetWidth_AttributeGetter] readonly attribute long offsetWidth;
+    [DeprecateAs=V8SVGElement_OffsetHeight_AttributeGetter] readonly attribute long offsetHeight;
 };
 
 SVGElement implements GlobalEventHandlers;
diff --git a/third_party/WebKit/Source/devtools/front_end/security/SecurityPanel.js b/third_party/WebKit/Source/devtools/front_end/security/SecurityPanel.js
index 152bceb..e603352 100644
--- a/third_party/WebKit/Source/devtools/front_end/security/SecurityPanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/security/SecurityPanel.js
@@ -276,6 +276,10 @@
         var frame = /** type {!PageAgent.Frame}*/ (event.data);
         var request = this._lastResponseReceivedForLoaderId.get(frame.loaderId);
         this._clearOrigins();
+
+        var origin = WebInspector.ParsedURL.splitURLIntoPathComponents(request.url)[0];
+        this._sidebarTree.setMainOrigin(origin);
+
         if (request)
             this._processRequest(request);
     },
@@ -322,6 +326,8 @@
 {
     this._showOriginInPanel = showOriginInPanel;
 
+    this._mainOrigin = null;
+
     TreeOutlineInShadow.call(this);
     this.element.classList.add("sidebar-tree");
     this.registerRequiredCSS("security/sidebar.css");
@@ -329,10 +335,17 @@
 
     this.appendChild(mainViewElement);
 
-    // TODO(lgarron): Add a section for the main origin. (https://crbug.com/523586)
-    this._originSection = new WebInspector.SidebarSectionTreeElement(WebInspector.UIString("Origins"));
-    this._originSection.listItemElement.classList.add("security-sidebar-origins");
-    this.appendChild(this._originSection);
+    /** @type {!Map<!WebInspector.SecurityPanelSidebarTree.OriginGroupName, !WebInspector.SidebarSectionTreeElement>} */
+    this._originGroups = new Map();
+
+    for (var key in WebInspector.SecurityPanelSidebarTree.OriginGroupName) {
+        var originGroupName = WebInspector.SecurityPanelSidebarTree.OriginGroupName[key];
+        var originGroup = new WebInspector.SidebarSectionTreeElement(WebInspector.UIString(originGroupName));
+        originGroup.listItemElement.classList.add("security-sidebar-origins");
+        this._originGroups.set(originGroupName, originGroup);
+        this.appendChild(originGroup);
+    }
+    this._clearOriginGroups();
 
     /** @type {!Map<!WebInspector.SecurityPanel.Origin, !WebInspector.SecurityPanelSidebarTreeElement>} */
     this._elementsByOrigin = new Map();
@@ -348,7 +361,15 @@
         var originElement = new WebInspector.SecurityPanelSidebarTreeElement(origin, this._showOriginInPanel.bind(this, origin), "security-sidebar-tree-item", "security-property");
         originElement.listItemElement.title = origin;
         this._elementsByOrigin.set(origin, originElement);
-        this._insertOriginElementSorted(originElement, securityState);
+        this.updateOrigin(origin, securityState);
+    },
+
+    /**
+     * @param {!WebInspector.SecurityPanel.Origin} origin
+     */
+    setMainOrigin: function(origin)
+    {
+        this._mainOrigin = origin;
     },
 
     /**
@@ -358,24 +379,50 @@
     updateOrigin: function(origin, securityState)
     {
         var originElement = /** @type {!WebInspector.SecurityPanelSidebarTreeElement} */ (this._elementsByOrigin.get(origin));
-        this._originSection.removeChild(originElement);
-        this._insertOriginElementSorted(originElement, securityState);
+        originElement.setSecurityState(securityState);
+
+        var newParent;
+        if (origin === this._mainOrigin) {
+            newParent = this._originGroups.get(WebInspector.SecurityPanelSidebarTree.OriginGroupName.MainOrigin);
+        } else {
+            switch (securityState) {
+            case SecurityAgent.SecurityState.Secure:
+                newParent = this._originGroups.get(WebInspector.SecurityPanelSidebarTree.OriginGroupName.Secure);
+                break;
+            case SecurityAgent.SecurityState.Unknown:
+                newParent = this._originGroups.get(WebInspector.SecurityPanelSidebarTree.OriginGroupName.Unknown);
+                break;
+            default:
+                newParent = this._originGroups.get(WebInspector.SecurityPanelSidebarTree.OriginGroupName.NonSecure);
+                break;
+            }
+        }
+
+        var oldParent = originElement.parent;
+        if (oldParent !== newParent) {
+            if (oldParent) {
+                oldParent.removeChild(originElement);
+                if (oldParent.childCount() === 0)
+                    oldParent.hidden = true;
+            }
+            newParent.appendChild(originElement);
+            newParent.hidden = false;
+        }
+
     },
 
-    /**
-     * @param {!WebInspector.SecurityPanelSidebarTreeElement} originElement
-     * @param {!SecurityAgent.SecurityState} securityState
-     */
-    _insertOriginElementSorted: function(originElement, securityState)
+    _clearOriginGroups: function()
     {
-        originElement.setSecurityState(securityState);
-        var originSectionChildList = /** @type {!Array.<!WebInspector.SecurityPanelSidebarTreeElement>} */ (this._originSection.children());
-        this._originSection.insertChild(originElement, originSectionChildList.upperBound(originElement, WebInspector.SecurityPanelSidebarTreeElement.SecurityStateComparator));
+        for (var originGroup of this._originGroups.values()) {
+            originGroup.removeChildren();
+            originGroup.hidden = true;
+        }
+        this._originGroups.get(WebInspector.SecurityPanelSidebarTree.OriginGroupName.MainOrigin).hidden = false;
     },
 
     clearOrigins: function()
     {
-        this._originSection.removeChildren();
+        this._clearOriginGroups();
         this._elementsByOrigin.clear();
     },
 
@@ -384,6 +431,19 @@
 
 
 /**
+ * A mapping from Javascript key IDs to names (sidebar section titles).
+ * Note: The names are used as keys into a map, so they must be distinct from each other.
+ * @enum {string}
+ */
+WebInspector.SecurityPanelSidebarTree.OriginGroupName = {
+    MainOrigin: "Main Origin",
+    NonSecure: "Non-Secure Origins",
+    Secure: "Secure Origins",
+    Unknown: "Unknown / Canceled"
+}
+
+
+/**
  * @constructor
  * @extends {WebInspector.SidebarTreeElement}
  * @param {string} text
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
index 094234d4..f6d87e40 100644
--- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
+++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
@@ -1622,13 +1622,17 @@
         DOMUint8ClampedArray::create(arrayBuffer, 0, arrayBuffer->byteLength()));
 }
 
-void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy)
+void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy, ExceptionState& exceptionState)
 {
-    putImageData(data, dx, dy, 0, 0, data->width(), data->height());
+    putImageData(data, dx, dy, 0, 0, data->width(), data->height(), exceptionState);
 }
 
-void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy, float dirtyX, float dirtyY, float dirtyWidth, float dirtyHeight)
+void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy, float dirtyX, float dirtyY, float dirtyWidth, float dirtyHeight, ExceptionState& exceptionState)
 {
+    if (data->data()->bufferBase()->isNeutered()) {
+        exceptionState.throwDOMException(InvalidStateError, "The source data has been neutered.");
+        return;
+    }
     ImageBuffer* buffer = canvas()->buffer();
     if (!buffer)
         return;
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.h b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.h
index d884aaa..3611fb80 100644
--- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.h
+++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.h
@@ -176,8 +176,8 @@
     ImageData* createImageData(ImageData*) const;
     ImageData* createImageData(float width, float height, ExceptionState&) const;
     ImageData* getImageData(float sx, float sy, float sw, float sh, ExceptionState&) const;
-    void putImageData(ImageData*, float dx, float dy);
-    void putImageData(ImageData*, float dx, float dy, float dirtyX, float dirtyY, float dirtyWidth, float dirtyHeight);
+    void putImageData(ImageData*, float dx, float dy, ExceptionState&);
+    void putImageData(ImageData*, float dx, float dy, float dirtyX, float dirtyY, float dirtyWidth, float dirtyHeight, ExceptionState&);
 
     void reset() override;
 
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.idl b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.idl
index e385a17..2a53fa86 100644
--- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.idl
+++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.idl
@@ -121,8 +121,8 @@
     ImageData createImageData(ImageData imagedata);
     [RaisesException] ImageData createImageData(float sw, float sh);
     [RaisesException] ImageData getImageData(float sx, float sy, float sw, float sh);
-    void putImageData(ImageData imagedata, float dx, float dy);
-    void putImageData(ImageData imagedata, float dx, float dy, float dirtyX, float dirtyY, float dirtyWidth, float dirtyHeight);
+    [RaisesException] void putImageData(ImageData imagedata, float dx, float dy);
+    [RaisesException] void putImageData(ImageData imagedata, float dx, float dy, float dirtyX, float dirtyY, float dirtyWidth, float dirtyHeight);
 
     // Context state
     // Should be merged with WebGL counterpart in CanvasRenderingContext, once no-longer experimental
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp
index a57a198..63dc435 100644
--- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp
+++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp
@@ -326,16 +326,25 @@
 TEST_F(CanvasRenderingContext2DTest, detectOverdrawWithPutImageData)
 {
     createContext(NonOpaque);
+    NonThrowableExceptionState exceptionState;
 
     // Test putImageData
-    TEST_OVERDRAW_1(1, putImageData(m_fullImageData.get(), 0, 0));
-    TEST_OVERDRAW_1(1, putImageData(m_fullImageData.get(), 0, 0, 0, 0, 10, 10));
-    TEST_OVERDRAW_1(0, putImageData(m_fullImageData.get(), 0, 0, 1, 1, 8, 8));
-    TEST_OVERDRAW_2(1, setGlobalAlpha(0.5f), putImageData(m_fullImageData.get(), 0, 0)); // alpha has no effect
-    TEST_OVERDRAW_1(0, putImageData(m_partialImageData.get(), 0, 0));
-    TEST_OVERDRAW_2(1, translate(1, 1), putImageData(m_fullImageData.get(), 0, 0)); // ignores tranforms
-    TEST_OVERDRAW_1(0, putImageData(m_fullImageData.get(), 1, 0));
-    TEST_OVERDRAW_3(1, rect(0, 0, 5, 5), clip(), putImageData(m_fullImageData.get(), 0, 0)); // ignores clip
+    TEST_OVERDRAW_1(1, putImageData(m_fullImageData.get(), 0, 0, exceptionState));
+    EXPECT_FALSE(exceptionState.hadException());
+    TEST_OVERDRAW_1(1, putImageData(m_fullImageData.get(), 0, 0, 0, 0, 10, 10, exceptionState));
+    EXPECT_FALSE(exceptionState.hadException());
+    TEST_OVERDRAW_1(0, putImageData(m_fullImageData.get(), 0, 0, 1, 1, 8, 8, exceptionState));
+    EXPECT_FALSE(exceptionState.hadException());
+    TEST_OVERDRAW_2(1, setGlobalAlpha(0.5f), putImageData(m_fullImageData.get(), 0, 0, exceptionState)); // alpha has no effect
+    EXPECT_FALSE(exceptionState.hadException());
+    TEST_OVERDRAW_1(0, putImageData(m_partialImageData.get(), 0, 0, exceptionState));
+    EXPECT_FALSE(exceptionState.hadException());
+    TEST_OVERDRAW_2(1, translate(1, 1), putImageData(m_fullImageData.get(), 0, 0, exceptionState)); // ignores tranforms
+    EXPECT_FALSE(exceptionState.hadException());
+    TEST_OVERDRAW_1(0, putImageData(m_fullImageData.get(), 1, 0, exceptionState));
+    EXPECT_FALSE(exceptionState.hadException());
+    TEST_OVERDRAW_3(1, rect(0, 0, 5, 5), clip(), putImageData(m_fullImageData.get(), 0, 0, exceptionState)); // ignores clip
+    EXPECT_FALSE(exceptionState.hadException());
 }
 
 TEST_F(CanvasRenderingContext2DTest, detectOverdrawWithCompositeOperations)
diff --git a/third_party/WebKit/Source/modules/notifications/Notification.idl b/third_party/WebKit/Source/modules/notifications/Notification.idl
index 38297e7..b985e3db 100644
--- a/third_party/WebKit/Source/modules/notifications/Notification.idl
+++ b/third_party/WebKit/Source/modules/notifications/Notification.idl
@@ -53,7 +53,7 @@
 
     [CallWith=ScriptState, Exposed=Window, MeasureAs=NotificationPermissionRequested] static Promise<NotificationPermission> requestPermission(optional NotificationPermissionCallback deprecatedCallback);
 
-    [RuntimeEnabled=NotificationExperimental] static readonly attribute unsigned long maxActions;
+    static readonly attribute unsigned long maxActions;
 
     attribute EventHandler onclick;
     [MeasureAs=NotificationShowEvent] attribute EventHandler onshow;
@@ -72,7 +72,9 @@
     readonly attribute boolean requireInteraction;
     [CallWith=ScriptState, SameObject] readonly attribute any data;
 
-    // TODO(johnme): The spec requires a FrozenArray, but sequence seems to behave like one already?! https://crbug.com/515920
+    // TODO(johnme): Ship once Blink supports FrozenArray (https://crbug.com/515920)
+    // and we've implemented the additional Object.freeze described in
+    // https://notifications.spec.whatwg.org/#dom-notification-actions
     [RuntimeEnabled=NotificationExperimental] readonly attribute sequence<NotificationAction> actions;
 
     [MeasureAs=NotificationClosed] void close();
diff --git a/third_party/WebKit/Source/modules/notifications/NotificationData.cpp b/third_party/WebKit/Source/modules/notifications/NotificationData.cpp
index 34b697d9..4052706 100644
--- a/third_party/WebKit/Source/modules/notifications/NotificationData.cpp
+++ b/third_party/WebKit/Source/modules/notifications/NotificationData.cpp
@@ -71,35 +71,32 @@
         webData.data = serializedData;
     }
 
-    // Ignore experimental NotificationOptions members if the flag is not set.
-    if (RuntimeEnabledFeatures::notificationExperimentalEnabled()) {
-        Vector<WebNotificationAction> actions;
+    Vector<WebNotificationAction> actions;
 
-        const size_t maxActions = Notification::maxActions();
-        for (const NotificationAction& action : options.actions()) {
-            if (action.action().isEmpty()) {
-                exceptionState.throwTypeError("NotificationAction `action` must not be empty.");
-                return WebNotificationData();
-            }
-
-            if (action.title().isEmpty()) {
-                exceptionState.throwTypeError("NotificationAction `title` must not be empty.");
-                return WebNotificationData();
-            }
-
-            if (actions.size() >= maxActions)
-                continue;
-
-            WebNotificationAction webAction;
-            webAction.action = action.action();
-            webAction.title = action.title();
-
-            actions.append(webAction);
+    const size_t maxActions = Notification::maxActions();
+    for (const NotificationAction& action : options.actions()) {
+        if (action.action().isEmpty()) {
+            exceptionState.throwTypeError("NotificationAction `action` must not be empty.");
+            return WebNotificationData();
         }
 
-        webData.actions = actions;
+        if (action.title().isEmpty()) {
+            exceptionState.throwTypeError("NotificationAction `title` must not be empty.");
+            return WebNotificationData();
+        }
+
+        if (actions.size() >= maxActions)
+            continue;
+
+        WebNotificationAction webAction;
+        webAction.action = action.action();
+        webAction.title = action.title();
+
+        actions.append(webAction);
     }
 
+    webData.actions = actions;
+
     return webData;
 }
 
diff --git a/third_party/WebKit/Source/modules/notifications/NotificationOptions.idl b/third_party/WebKit/Source/modules/notifications/NotificationOptions.idl
index 3047c296..feba5b0e 100644
--- a/third_party/WebKit/Source/modules/notifications/NotificationOptions.idl
+++ b/third_party/WebKit/Source/modules/notifications/NotificationOptions.idl
@@ -21,5 +21,5 @@
     boolean silent = false;
     boolean requireInteraction = false;
     any data = null;
-    [RuntimeEnabled=NotificationExperimental] sequence<NotificationAction> actions = [];
+    sequence<NotificationAction> actions = [];
 };
diff --git a/third_party/WebKit/Source/platform/Cursor.cpp b/third_party/WebKit/Source/platform/Cursor.cpp
index 350f4e9..58d48bd 100644
--- a/third_party/WebKit/Source/platform/Cursor.cpp
+++ b/third_party/WebKit/Source/platform/Cursor.cpp
@@ -56,101 +56,6 @@
     return IntPoint();
 }
 
-const Cursor& Cursor::fromType(Cursor::Type type)
-{
-    switch (type) {
-    case Cursor::Pointer:
-        return pointerCursor();
-    case Cursor::Cross:
-        return crossCursor();
-    case Cursor::Hand:
-        return handCursor();
-    case Cursor::IBeam:
-        return iBeamCursor();
-    case Cursor::Wait:
-        return waitCursor();
-    case Cursor::Help:
-        return helpCursor();
-    case Cursor::EastResize:
-        return eastResizeCursor();
-    case Cursor::NorthResize:
-        return northResizeCursor();
-    case Cursor::NorthEastResize:
-        return northEastResizeCursor();
-    case Cursor::NorthWestResize:
-        return northWestResizeCursor();
-    case Cursor::SouthResize:
-        return southResizeCursor();
-    case Cursor::SouthEastResize:
-        return southEastResizeCursor();
-    case Cursor::SouthWestResize:
-        return southWestResizeCursor();
-    case Cursor::WestResize:
-        return westResizeCursor();
-    case Cursor::NorthSouthResize:
-        return northSouthResizeCursor();
-    case Cursor::EastWestResize:
-        return eastWestResizeCursor();
-    case Cursor::NorthEastSouthWestResize:
-        return northEastSouthWestResizeCursor();
-    case Cursor::NorthWestSouthEastResize:
-        return northWestSouthEastResizeCursor();
-    case Cursor::ColumnResize:
-        return columnResizeCursor();
-    case Cursor::RowResize:
-        return rowResizeCursor();
-    case Cursor::MiddlePanning:
-        return middlePanningCursor();
-    case Cursor::EastPanning:
-        return eastPanningCursor();
-    case Cursor::NorthPanning:
-        return northPanningCursor();
-    case Cursor::NorthEastPanning:
-        return northEastPanningCursor();
-    case Cursor::NorthWestPanning:
-        return northWestPanningCursor();
-    case Cursor::SouthPanning:
-        return southPanningCursor();
-    case Cursor::SouthEastPanning:
-        return southEastPanningCursor();
-    case Cursor::SouthWestPanning:
-        return southWestPanningCursor();
-    case Cursor::WestPanning:
-        return westPanningCursor();
-    case Cursor::Move:
-        return moveCursor();
-    case Cursor::VerticalText:
-        return verticalTextCursor();
-    case Cursor::Cell:
-        return cellCursor();
-    case Cursor::ContextMenu:
-        return contextMenuCursor();
-    case Cursor::Alias:
-        return aliasCursor();
-    case Cursor::Progress:
-        return progressCursor();
-    case Cursor::NoDrop:
-        return noDropCursor();
-    case Cursor::Copy:
-        return copyCursor();
-    case Cursor::None:
-        return noneCursor();
-    case Cursor::NotAllowed:
-        return notAllowedCursor();
-    case Cursor::ZoomIn:
-        return zoomInCursor();
-    case Cursor::ZoomOut:
-        return zoomOutCursor();
-    case Cursor::Grab:
-        return grabCursor();
-    case Cursor::Grabbing:
-        return grabbingCursor();
-    case Cursor::Custom:
-        ASSERT_NOT_REACHED();
-    }
-    return pointerCursor();
-}
-
 Cursor::Cursor(Image* image, bool hotSpotSpecified, const IntPoint& hotSpot)
     : m_type(Custom)
     , m_image(image)
diff --git a/third_party/WebKit/Source/platform/Cursor.h b/third_party/WebKit/Source/platform/Cursor.h
index 3b88adb3..0989e9b 100644
--- a/third_party/WebKit/Source/platform/Cursor.h
+++ b/third_party/WebKit/Source/platform/Cursor.h
@@ -84,8 +84,6 @@
         Custom
     };
 
-    static const Cursor& fromType(Cursor::Type);
-
     Cursor()
         // This is an invalid Cursor and should never actually get used.
         : m_type(static_cast<Type>(-1))
diff --git a/third_party/WebKit/Source/platform/PlatformTouchEvent.h b/third_party/WebKit/Source/platform/PlatformTouchEvent.h
index be75aa6..d687ded 100644
--- a/third_party/WebKit/Source/platform/PlatformTouchEvent.h
+++ b/third_party/WebKit/Source/platform/PlatformTouchEvent.h
@@ -31,6 +31,7 @@
     PlatformTouchEvent()
         : PlatformEvent(PlatformEvent::TouchStart)
         , m_cancelable(true)
+        , m_causesScrollingIfUncanceled(false)
     {
     }
 
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
index 189d728e..71ff2dc 100644
--- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
+++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
@@ -112,7 +112,7 @@
 NavigatorContentUtils
 WebNFC status=experimental
 NetworkInformation status=stable
-NetInfoDownlinkMax status=experimental
+NetInfoDownlinkMax status=stable
 NewMediaPlaybackUi
 NotificationConstructor status=stable
 NotificationExperimental status=test
diff --git a/third_party/WebKit/Source/platform/Widget.h b/third_party/WebKit/Source/platform/Widget.h
index d58fff4..60688933 100644
--- a/third_party/WebKit/Source/platform/Widget.h
+++ b/third_party/WebKit/Source/platform/Widget.h
@@ -66,8 +66,6 @@
 
     void resize(int w, int h) { setFrameRect(IntRect(x(), y(), w, h)); }
     void resize(const IntSize& s) { setFrameRect(IntRect(location(), s)); }
-    void move(int x, int y) { setFrameRect(IntRect(x, y, width(), height())); }
-    void move(const IntPoint& p) { setFrameRect(IntRect(p, size())); }
 
     virtual void paint(GraphicsContext*, const CullRect&) const { }
     void invalidate() { invalidateRect(boundsRect()); }
@@ -89,7 +87,6 @@
     virtual bool isPluginContainer() const { return false; }
     virtual bool isScrollbar() const { return false; }
 
-    virtual HostWindow* hostWindow() const { ASSERT_NOT_REACHED(); return 0; }
     virtual void setParent(Widget*);
     Widget* parent() const { return m_parent; }
     Widget* root() const;
diff --git a/third_party/WebKit/Source/platform/blink_platform.gypi b/third_party/WebKit/Source/platform/blink_platform.gypi
index d7ba0b5d2..e47adddb 100644
--- a/third_party/WebKit/Source/platform/blink_platform.gypi
+++ b/third_party/WebKit/Source/platform/blink_platform.gypi
@@ -697,6 +697,7 @@
       'graphics/paint/PaintChunker.h',
       'graphics/paint/PaintController.cpp',
       'graphics/paint/PaintController.h',
+      'graphics/paint/ScopedPaintChunkProperties.h',
       'graphics/paint/ScrollDisplayItem.cpp',
       'graphics/paint/ScrollDisplayItem.h',
       'graphics/paint/SkPictureBuilder.h',
diff --git a/third_party/WebKit/Source/platform/fonts/FallbackListCompositeKey.h b/third_party/WebKit/Source/platform/fonts/FallbackListCompositeKey.h
new file mode 100644
index 0000000..b32d133d
--- /dev/null
+++ b/third_party/WebKit/Source/platform/fonts/FallbackListCompositeKey.h
@@ -0,0 +1,102 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef FallbackListCompositeKey_h
+#define FallbackListCompositeKey_h
+
+#include "platform/fonts/FontCacheKey.h"
+#include "platform/fonts/FontDescription.h"
+#include "wtf/HashMap.h"
+#include "wtf/HashTableDeletedValueType.h"
+
+namespace blink {
+
+class FontDescription;
+
+// Cache key representing a font description and font fallback list combination
+// as passed into shaping. Used to look up an applicable ShapeCache instance
+// from the global FontCache.
+// TODO(eae,drott): Ideally this should be replaced by a combination of
+// FontDescription and CSSFontSelector.
+struct FallbackListCompositeKey {
+public:
+    FallbackListCompositeKey(const FontDescription& fontDescription)
+        : m_hash(fontDescription.styleHashWithoutFamilyList() << 1)
+        , m_computedSize(fontDescription.computedSize())
+        , m_letterSpacing(fontDescription.letterSpacing())
+        , m_wordSpacing(fontDescription.wordSpacing())
+        , m_bitmapFields(fontDescription.bitmapFields())
+        , m_auxiliaryBitmapFields(fontDescription.auxiliaryBitmapFields()) { }
+    FallbackListCompositeKey()
+        : m_hash(0)
+        , m_computedSize(0)
+        , m_letterSpacing(0)
+        , m_wordSpacing(0)
+        , m_bitmapFields(0)
+        , m_auxiliaryBitmapFields(0) { }
+    FallbackListCompositeKey(WTF::HashTableDeletedValueType)
+        : m_hash(s_deletedValueHash)
+        , m_computedSize(0)
+        , m_letterSpacing(0)
+        , m_wordSpacing(0)
+        , m_bitmapFields(0)
+        , m_auxiliaryBitmapFields(0) { }
+
+    void add(FontCacheKey key)
+    {
+        m_fontCacheKeys.append(key);
+        // Djb2 with the first bit reserved for deleted.
+        m_hash = (((m_hash << 5) + m_hash) + key.hash()) << 1;
+    }
+
+    unsigned hash() const { return m_hash; }
+
+    bool operator==(const FallbackListCompositeKey& other) const
+    {
+        return m_hash == other.m_hash
+            && m_computedSize == other.m_computedSize
+            && m_letterSpacing == other.m_letterSpacing
+            && m_wordSpacing == other.m_wordSpacing
+            && m_bitmapFields == other.m_bitmapFields
+            && m_auxiliaryBitmapFields == other.m_auxiliaryBitmapFields
+            && m_fontCacheKeys == other.m_fontCacheKeys;
+    }
+
+    bool isHashTableDeletedValue() const
+    {
+        return m_hash == s_deletedValueHash;
+    }
+
+private:
+    static const unsigned s_deletedValueHash = 1;
+    FontDescription m_fontDescription;
+    Vector<FontCacheKey> m_fontCacheKeys;
+    unsigned m_hash;
+
+    float m_computedSize;
+    float m_letterSpacing;
+    float m_wordSpacing;
+    unsigned m_bitmapFields;
+    unsigned m_auxiliaryBitmapFields;
+};
+
+struct FallbackListCompositeKeyHash {
+    static unsigned hash(const FallbackListCompositeKey& key)
+    {
+        return key.hash();
+    }
+
+    static bool equal(const FallbackListCompositeKey& a, const FallbackListCompositeKey& b)
+    {
+        return a == b;
+    }
+
+    static const bool safeToCompareToEmptyOrDeleted = false;
+};
+
+struct FallbackListCompositeKeyTraits : WTF::SimpleClassHashTraits<FallbackListCompositeKey> { };
+
+} // namespace blink
+
+#endif // FallbackListCompositeKey_h
diff --git a/third_party/WebKit/Source/platform/fonts/Font.cpp b/third_party/WebKit/Source/platform/fonts/Font.cpp
index 5b0df14..342a9dbf 100644
--- a/third_party/WebKit/Source/platform/fonts/Font.cpp
+++ b/third_party/WebKit/Source/platform/fonts/Font.cpp
@@ -35,6 +35,7 @@
 #include "platform/fonts/GlyphBuffer.h"
 #include "platform/fonts/GlyphPageTreeNode.h"
 #include "platform/fonts/SimpleFontData.h"
+#include "platform/fonts/shaping/CachingWordShaper.h"
 #include "platform/fonts/shaping/HarfBuzzFace.h"
 #include "platform/fonts/shaping/HarfBuzzShaper.h"
 #include "platform/fonts/shaping/SimpleShaper.h"
@@ -112,7 +113,7 @@
 {
     if (codePath(runInfo) == ComplexPath) {
         float width;
-        CachingWordShaper& shaper = m_fontFallbackList->cachingWordShaper();
+        CachingWordShaper shaper(m_fontFallbackList->shapeCache(m_fontDescription));
         if (emphasisData) {
             width = shaper.fillGlyphBufferForTextEmphasis(this, runInfo.run,
                 emphasisData, &glyphBuffer, runInfo.from, runInfo.to);
@@ -702,7 +703,7 @@
 
 float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, FloatRect* glyphBounds) const
 {
-    CachingWordShaper& shaper = m_fontFallbackList->cachingWordShaper();
+    CachingWordShaper shaper(m_fontFallbackList->shapeCache(m_fontDescription));
     float width = shaper.width(this, run, fallbackFonts, glyphBounds);
     return width;
 }
@@ -711,7 +712,7 @@
 int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat,
     bool includePartialGlyphs) const
 {
-    CachingWordShaper& shaper = m_fontFallbackList->cachingWordShaper();
+    CachingWordShaper shaper(m_fontFallbackList->shapeCache(m_fontDescription));
     return shaper.offsetForPosition(this, run, xFloat);
 }
 
@@ -719,7 +720,7 @@
 FloatRect Font::selectionRectForComplexText(const TextRun& run,
     const FloatPoint& point, int height, int from, int to) const
 {
-    CachingWordShaper& shaper = m_fontFallbackList->cachingWordShaper();
+    CachingWordShaper shaper(m_fontFallbackList->shapeCache(m_fontDescription));
     return shaper.selectionRect(this, run, point, height, from, to);
 }
 
@@ -838,4 +839,5 @@
     return !m_fontFallbackList || m_fontFallbackList->isValid();
 }
 
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/FontCache.cpp b/third_party/WebKit/Source/platform/fonts/FontCache.cpp
index 55d3943..3a3aa14 100644
--- a/third_party/WebKit/Source/platform/fonts/FontCache.cpp
+++ b/third_party/WebKit/Source/platform/fonts/FontCache.cpp
@@ -43,6 +43,8 @@
 #include "platform/fonts/SimpleFontData.h"
 #include "platform/fonts/TextRenderingMode.h"
 #include "platform/fonts/opentype/OpenTypeVerticalData.h"
+#include "platform/fonts/shaping/ShapeCache.h"
+#include "public/platform/Platform.h"
 #include "wtf/HashMap.h"
 #include "wtf/ListHashSet.h"
 #include "wtf/StdLibExtras.h"
@@ -62,8 +64,10 @@
 #endif // !OS(WIN)
 
 typedef HashMap<FontCacheKey, OwnPtr<FontPlatformData>, FontCacheKeyHash, FontCacheKeyTraits> FontPlatformDataCache;
+typedef HashMap<FallbackListCompositeKey, OwnPtr<ShapeCache>, FallbackListCompositeKeyHash, FallbackListCompositeKeyTraits> FallbackListShaperCache;
 
-static FontPlatformDataCache* gFontPlatformDataCache = 0;
+static FontPlatformDataCache* gFontPlatformDataCache = nullptr;
+static FallbackListShaperCache* gFallbackListShaperCache = nullptr;
 
 #if OS(WIN)
 bool FontCache::s_useDirectWrite = false;
@@ -114,6 +118,24 @@
     return result;
 }
 
+ShapeCache* FontCache::getShapeCache(const FallbackListCompositeKey& key)
+{
+    if (!gFallbackListShaperCache)
+        gFallbackListShaperCache = new FallbackListShaperCache;
+
+    FallbackListShaperCache::iterator it = gFallbackListShaperCache->find(key);
+    ShapeCache* result = nullptr;
+    if (it == gFallbackListShaperCache->end()) {
+        result = new ShapeCache();
+        gFallbackListShaperCache->set(key, adoptPtr(result));
+    } else {
+        result = it->value.get();
+    }
+
+    ASSERT(result);
+    return result;
+}
+
 typedef HashMap<FontCache::FontFileKey, RefPtr<OpenTypeVerticalData>, IntHash<FontCache::FontFileKey>, UnsignedWithZeroKeyHashTraits<FontCache::FontFileKey>> FontVerticalDataCache;
 
 FontVerticalDataCache& fontVerticalDataCacheInstance()
@@ -215,6 +237,25 @@
     }
 }
 
+static inline void purgeFallbackListShaperCache()
+{
+    unsigned items = 0;
+    if (gFallbackListShaperCache) {
+        FallbackListShaperCache::iterator iter;
+        for (iter = gFallbackListShaperCache->begin();
+            iter != gFallbackListShaperCache->end(); ++iter) {
+            items += iter->value->size();
+        }
+        gFallbackListShaperCache->clear();
+    }
+    Platform::current()->histogramCustomCounts("Blink.Fonts.ShapeCache", items, 1, 1000000, 50);
+}
+
+void FontCache::invalidateShapeCache()
+{
+    purgeFallbackListShaperCache();
+}
+
 void FontCache::purge(PurgeSeverity PurgeSeverity)
 {
     // We should never be forcing the purge while the FontCachePurgePreventer is in scope.
@@ -227,6 +268,7 @@
 
     purgePlatformFontDataCache();
     purgeFontVerticalDataCache();
+    purgeFallbackListShaperCache();
 }
 
 static bool invalidateFontCache = false;
diff --git a/third_party/WebKit/Source/platform/fonts/FontCache.h b/third_party/WebKit/Source/platform/fonts/FontCache.h
index 72cf61d..fc0fdc95 100644
--- a/third_party/WebKit/Source/platform/fonts/FontCache.h
+++ b/third_party/WebKit/Source/platform/fonts/FontCache.h
@@ -31,6 +31,8 @@
 #define FontCache_h
 
 #include "platform/PlatformExport.h"
+#include "platform/fonts/FallbackListCompositeKey.h"
+#include "platform/fonts/FontCacheKey.h"
 #include "platform/fonts/FontFaceCreationParams.h"
 #include "wtf/Forward.h"
 #include "wtf/HashMap.h"
@@ -55,6 +57,7 @@
 class FontPlatformData;
 class FontDescription;
 class OpenTypeVerticalData;
+class ShapeCache;
 class SimpleFontData;
 
 enum ShouldRetain { Retain, DoNotRetain };
@@ -81,6 +84,11 @@
     SimpleFontData* getNonRetainedLastResortFallbackFont(const FontDescription&);
     bool isPlatformFontAvailable(const FontDescription&, const AtomicString&);
 
+    // Returns the ShapeCache instance associated with the given cache key.
+    // Creates a new instance as needed and as such is guaranteed not to return
+    // a nullptr. The life time of instances are managed by the FontCache.
+    ShapeCache* getShapeCache(const FallbackListCompositeKey&);
+
     void addClient(FontCacheClient*);
 #if !ENABLE(OILPAN)
     void removeClient(FontCacheClient*);
@@ -129,6 +137,8 @@
 #endif
     PassRefPtr<SimpleFontData> fontDataFromFontPlatformData(const FontPlatformData*, ShouldRetain = Retain);
 
+    void invalidateShapeCache();
+
 private:
     FontCache();
     ~FontCache();
diff --git a/third_party/WebKit/Source/platform/fonts/FontDescription.cpp b/third_party/WebKit/Source/platform/fonts/FontDescription.cpp
index cc39aaf..36193b2 100644
--- a/third_party/WebKit/Source/platform/fonts/FontDescription.cpp
+++ b/third_party/WebKit/Source/platform/fonts/FontDescription.cpp
@@ -31,8 +31,10 @@
 #include "platform/fonts/FontDescription.h"
 
 #include "platform/RuntimeEnabledFeatures.h"
+#include "wtf/StringHasher.h"
 #include "wtf/text/AtomicStringHash.h"
 #include "wtf/text/StringHash.h"
+#include <string.h>
 
 namespace blink {
 
@@ -162,18 +164,20 @@
     return floorf(computedOrAdjustedSize * FontCacheKey::precisionMultiplier()) / FontCacheKey::precisionMultiplier();
 }
 
-FontCacheKey FontDescription::cacheKey(const FontFaceCreationParams& creationParams, FontTraits desiredTraits) const
+FontCacheKey FontDescription::cacheKey(const FontFaceCreationParams& creationParams, FontTraits desiredTraits, bool loading, unsigned version) const
 {
     FontTraits fontTraits = desiredTraits.bitfield() ? desiredTraits : traits();
 
     unsigned options =
+        version << 8 | // bit 9-15
+        static_cast<unsigned>(loading ? 1 : 0) << 7 | // bit 8
         static_cast<unsigned>(m_fields.m_syntheticItalic) << 6 | // bit 7
         static_cast<unsigned>(m_fields.m_syntheticBold) << 5 | // bit 6
         static_cast<unsigned>(m_fields.m_textRendering) << 3 | // bits 4-5
         static_cast<unsigned>(m_fields.m_orientation) << 1 | // bit 2-3
         static_cast<unsigned>(m_fields.m_subpixelTextPosition); // bit 1
 
-    return FontCacheKey(creationParams, effectiveFontSize(), options | fontTraits.bitfield() << 7);
+    return FontCacheKey(creationParams, effectiveFontSize(), options | fontTraits.bitfield() << 16);
 }
 
 
@@ -238,4 +242,44 @@
     }
 }
 
+static inline void addToHash(unsigned& hash, unsigned key)
+{
+    hash = ((hash << 5) + hash) + key; // Djb2
+}
+
+static inline void addFloatToHash(unsigned& hash, float value)
+{
+    addToHash(hash, StringHasher::hashMemory(&value, sizeof(value)));
+}
+
+unsigned FontDescription::styleHashWithoutFamilyList() const
+{
+    unsigned hash = 0;
+    StringHasher stringHasher;
+    const FontFeatureSettings* settings = featureSettings();
+    if (settings) {
+        unsigned numFeatures = settings->size();
+        for (unsigned i = 0; i < numFeatures; ++i) {
+            const AtomicString& tag = settings->at(i).tag();
+            for (unsigned j = 0; j < tag.length(); j++)
+                stringHasher.addCharacter(tag[j]);
+            addToHash(hash, settings->at(i).value());
+        }
+    }
+    for (unsigned i = 0; i < m_locale.length(); i++)
+        stringHasher.addCharacter(m_locale[i]);
+    addToHash(hash, stringHasher.hash());
+
+    addFloatToHash(hash, m_specifiedSize);
+    addFloatToHash(hash, m_computedSize);
+    addFloatToHash(hash, m_adjustedSize);
+    addFloatToHash(hash, m_sizeAdjust);
+    addFloatToHash(hash, m_letterSpacing);
+    addFloatToHash(hash, m_wordSpacing);
+    addToHash(hash, m_fieldsAsUnsigned[0]);
+    addToHash(hash, m_fieldsAsUnsigned[1]);
+
+    return hash;
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/FontDescription.h b/third_party/WebKit/Source/platform/fonts/FontDescription.h
index c68cc951..5a90c97 100644
--- a/third_party/WebKit/Source/platform/fonts/FontDescription.h
+++ b/third_party/WebKit/Source/platform/fonts/FontDescription.h
@@ -181,7 +181,7 @@
     FontFeatureSettings* featureSettings() const { return m_featureSettings.get(); }
 
     float effectiveFontSize() const; // Returns either the computedSize or the computedPixelSize
-    FontCacheKey cacheKey(const FontFaceCreationParams&, FontTraits desiredTraits = FontTraits(0)) const;
+    FontCacheKey cacheKey(const FontFaceCreationParams&, FontTraits desiredTraits = FontTraits(0), bool loading = false, unsigned version = 0) const;
 
     void setFamily(const FontFamily& family) { m_familyList = family; }
     void setComputedSize(float s) { m_computedSize = clampTo<float>(s); }
@@ -218,6 +218,10 @@
     static void setDefaultTypesettingFeatures(TypesettingFeatures);
     static TypesettingFeatures defaultTypesettingFeatures();
 
+    unsigned styleHashWithoutFamilyList() const;
+    unsigned bitmapFields() const { return m_fieldsAsUnsigned[0]; }
+    unsigned auxiliaryBitmapFields() const { return m_fieldsAsUnsigned[1]; }
+
 private:
     FontFamily m_familyList; // The list of font families to be used.
     RefPtr<FontFeatureSettings> m_featureSettings;
diff --git a/third_party/WebKit/Source/platform/fonts/FontDescriptionTest.cpp b/third_party/WebKit/Source/platform/fonts/FontDescriptionTest.cpp
index d0d24fd..b1a92fd 100644
--- a/third_party/WebKit/Source/platform/fonts/FontDescriptionTest.cpp
+++ b/third_party/WebKit/Source/platform/fonts/FontDescriptionTest.cpp
@@ -27,6 +27,7 @@
 
 #include "platform/fonts/FontDescription.h"
 
+#include "wtf/Vector.h"
 #include <gtest/gtest.h>
 
 namespace blink {
@@ -118,4 +119,58 @@
     assertDescriptionMatchesMask(source, source.traits().bitfield());
 }
 
+TEST(FontDescriptionTest, TestHashCollision)
+{
+    FontWeight weights[] = {
+        FontWeight100,
+        FontWeight200,
+        FontWeight300,
+        FontWeight400,
+        FontWeight500,
+        FontWeight600,
+        FontWeight700,
+        FontWeight800,
+        FontWeight900,
+    };
+    FontStretch stretches[] {
+        FontStretchUltraCondensed,
+        FontStretchExtraCondensed,
+        FontStretchCondensed,
+        FontStretchSemiCondensed,
+        FontStretchNormal,
+        FontStretchSemiExpanded,
+        FontStretchExpanded,
+        FontStretchExtraExpanded,
+        FontStretchUltraExpanded
+    };
+    FontStyle styles[] = {
+        FontStyleNormal,
+        FontStyleOblique,
+        FontStyleItalic
+    };
+    FontVariant variants[] = {
+        FontVariantNormal,
+        FontVariantSmallCaps
+    };
+
+    FontDescription source;
+    WTF::Vector<unsigned> hashes;
+    for (size_t i = 0; i < WTF_ARRAY_LENGTH(weights); i++) {
+        source.setWeight(weights[i]);
+        for (size_t j = 0; j < WTF_ARRAY_LENGTH(stretches); j++) {
+            source.setStretch(stretches[j]);
+            for (size_t k = 0; k < WTF_ARRAY_LENGTH(styles); k++) {
+                source.setStyle(styles[k]);
+                for (size_t m = 0; m < WTF_ARRAY_LENGTH(variants); m++) {
+                    source.setVariant(variants[m]);
+                    unsigned hash = source.styleHashWithoutFamilyList();
+                    ASSERT_FALSE(hashes.contains(hash));
+                    hashes.append(hash);
+                }
+            }
+        }
+    }
+
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/FontFallbackList.cpp b/third_party/WebKit/Source/platform/fonts/FontFallbackList.cpp
index 284f612..bbb451d 100644
--- a/third_party/WebKit/Source/platform/fonts/FontFallbackList.cpp
+++ b/third_party/WebKit/Source/platform/fonts/FontFallbackList.cpp
@@ -30,7 +30,9 @@
 #include "platform/fonts/FontFallbackList.h"
 
 #include "platform/FontFamilyNames.h"
+#include "platform/fonts/AlternateFontFamily.h"
 #include "platform/fonts/FontCache.h"
+#include "platform/fonts/FontCacheKey.h"
 #include "platform/fonts/FontDescription.h"
 #include "platform/fonts/FontFamily.h"
 #include "platform/fonts/SegmentedFontData.h"
@@ -62,7 +64,6 @@
         m_fontSelector = fontSelector;
     m_fontSelectorVersion = m_fontSelector ? m_fontSelector->version() : 0;
     m_generation = FontCache::fontCache()->generation();
-    m_cachingWordShaper.clear();
 }
 
 void FontFallbackList::releaseFontData()
@@ -190,6 +191,36 @@
 }
 
 
+FallbackListCompositeKey FontFallbackList::compositeKey(const FontDescription& fontDescription) const
+{
+    FallbackListCompositeKey key(fontDescription);
+    const FontFamily* currentFamily = &fontDescription.family();
+    while (currentFamily) {
+        if (currentFamily->family().length()) {
+            FontFaceCreationParams params(adjustFamilyNameToAvoidUnsupportedFonts(currentFamily->family()));
+            RefPtr<FontData> result;
+            if (m_fontSelector)
+                result = m_fontSelector->getFontData(fontDescription, currentFamily->family());
+            if (!result) {
+                if (FontPlatformData* platformData = FontCache::fontCache()->getFontPlatformData(fontDescription, params))
+                    result = FontCache::fontCache()->fontDataFromFontPlatformData(platformData);
+            }
+
+            // Include loading state and version when constructing key, that way if called when a font is loading
+            // and then again once it has been loaded or updated different keys are produced.
+            if (result) {
+                FontCacheKey cacheKey = fontDescription.cacheKey(params, FontTraits(0),
+                    result->isLoading() || result->isLoadingFallback(),
+                    m_fontSelector ? m_fontSelector->version() : 0);
+                key.add(cacheKey);
+            }
+        }
+        currentFamily = currentFamily->next();
+    }
+
+    return key;
+}
+
 const FontData* FontFallbackList::fontDataAt(const FontDescription& fontDescription, unsigned realizedFontIndex) const
 {
     if (realizedFontIndex < m_fontList.size())
diff --git a/third_party/WebKit/Source/platform/fonts/FontFallbackList.h b/third_party/WebKit/Source/platform/fonts/FontFallbackList.h
index 72f12681..1ca7231 100644
--- a/third_party/WebKit/Source/platform/fonts/FontFallbackList.h
+++ b/third_party/WebKit/Source/platform/fonts/FontFallbackList.h
@@ -21,9 +21,10 @@
 #ifndef FontFallbackList_h
 #define FontFallbackList_h
 
+#include "platform/fonts/FallbackListCompositeKey.h"
+#include "platform/fonts/FontCache.h"
 #include "platform/fonts/FontSelector.h"
 #include "platform/fonts/SimpleFontData.h"
-#include "platform/fonts/shaping/CachingWordShaper.h"
 #include "wtf/Forward.h"
 #include "wtf/MainThread.h"
 
@@ -74,7 +75,13 @@
     unsigned fontSelectorVersion() const { return m_fontSelectorVersion; }
     unsigned generation() const { return m_generation; }
 
-    CachingWordShaper& cachingWordShaper() const { return m_cachingWordShaper; }
+    ShapeCache* shapeCache(const FontDescription& fontDescription) const
+    {
+        FallbackListCompositeKey key = compositeKey(fontDescription);
+        ShapeCache* cache = FontCache::fontCache()->getShapeCache(key);
+        ASSERT(cache);
+        return cache;
+    }
 
     const SimpleFontData* primarySimpleFontData(const FontDescription& fontDescription)
     {
@@ -100,6 +107,8 @@
             m_pageZero = node;
     }
 
+    FallbackListCompositeKey compositeKey(const FontDescription&) const;
+
 private:
     FontFallbackList();
 
@@ -114,7 +123,6 @@
     GlyphPageTreeNodeBase* m_pageZero;
     mutable const SimpleFontData* m_cachedPrimarySimpleFontData;
     RefPtrWillBePersistent<FontSelector> m_fontSelector;
-    mutable CachingWordShaper m_cachingWordShaper;
     unsigned m_fontSelectorVersion;
     mutable int m_familyIndex;
     unsigned short m_generation;
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShapeIterator.h b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShapeIterator.h
index d66080e3..cedfe37c 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShapeIterator.h
+++ b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShapeIterator.h
@@ -34,7 +34,9 @@
 
 namespace blink {
 
-class CachingWordShapeIterator {
+class CachingWordShapeIterator final {
+    WTF_MAKE_NONCOPYABLE(CachingWordShapeIterator);
+    USING_FAST_MALLOC(CachingWordShapeIterator);
 public:
     CachingWordShapeIterator(ShapeCache* cache, const TextRun& run,
         const Font* font)
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaper.cpp b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaper.cpp
index 2c1d072..3ba5eb88 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaper.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaper.cpp
@@ -34,27 +34,13 @@
 
 namespace blink {
 
-CachingWordShaper::CachingWordShaper()
-    : m_shapeCache(adoptPtr(new ShapeCache))
-{
-}
-
-CachingWordShaper::~CachingWordShaper()
-{
-}
-
-void CachingWordShaper::clear()
-{
-    m_shapeCache->clear();
-}
-
 float CachingWordShaper::width(const Font* font, const TextRun& run,
     HashSet<const SimpleFontData*>* fallbackFonts,
     FloatRect* glyphBounds)
 {
     float width = 0;
     RefPtr<ShapeResult> wordResult;
-    CachingWordShapeIterator iterator(m_shapeCache.get(), run, font);
+    CachingWordShapeIterator iterator(m_shapeCache, run, font);
     while (iterator.next(&wordResult)) {
         if (wordResult) {
             width += wordResult->width();
@@ -89,7 +75,7 @@
 int CachingWordShaper::offsetForPosition(const Font* font, const TextRun& run, float targetX)
 {
     Vector<RefPtr<ShapeResult>> results;
-    shapeResultsForRun(m_shapeCache.get(), font, run, nullptr, &results);
+    shapeResultsForRun(m_shapeCache, font, run, nullptr, &results);
 
     return ShapeResult::offsetForPosition(results, run, targetX);
 }
@@ -99,7 +85,7 @@
     GlyphBuffer* glyphBuffer, unsigned from, unsigned to)
 {
     Vector<RefPtr<ShapeResult>> results;
-    shapeResultsForRun(m_shapeCache.get(), font, run, fallbackFonts, &results);
+    shapeResultsForRun(m_shapeCache, font, run, fallbackFonts, &results);
 
     return ShapeResult::fillGlyphBuffer(results, glyphBuffer, run, from, to);
 }
@@ -109,7 +95,7 @@
     unsigned from, unsigned to)
 {
     Vector<RefPtr<ShapeResult>> results;
-    shapeResultsForRun(m_shapeCache.get(), font, run, nullptr, &results);
+    shapeResultsForRun(m_shapeCache, font, run, nullptr, &results);
 
     return ShapeResult::fillGlyphBufferForTextEmphasis(results, glyphBuffer,
         run, emphasisData, from, to);
@@ -119,7 +105,7 @@
     const FloatPoint& point, int height, unsigned from, unsigned to)
 {
     Vector<RefPtr<ShapeResult>> results;
-    float totalWidth = shapeResultsForRun(m_shapeCache.get(), font, run, nullptr,
+    float totalWidth = shapeResultsForRun(m_shapeCache, font, run, nullptr,
         &results);
 
     return ShapeResult::selectionRect(results, run.direction(), totalWidth,
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaper.h b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaper.h
index 37f750d..c0ffedc 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaper.h
+++ b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaper.h
@@ -41,10 +41,10 @@
 struct GlyphData;
 
 class PLATFORM_EXPORT CachingWordShaper final {
+    WTF_MAKE_NONCOPYABLE(CachingWordShaper);
 public:
-    CachingWordShaper();
-    ~CachingWordShaper();
-    void clear();
+    CachingWordShaper(ShapeCache* cache) : m_shapeCache(cache) { }
+    ~CachingWordShaper() { }
 
     float width(const Font*, const TextRun&,
         HashSet<const SimpleFontData*>* fallbackFonts,
@@ -60,7 +60,7 @@
         int height, unsigned from, unsigned to);
 
 private:
-    OwnPtr<ShapeCache> m_shapeCache;
+    ShapeCache* m_shapeCache;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaperTest.cpp b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaperTest.cpp
index 51d2360..14429b2 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaperTest.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaperTest.cpp
@@ -4,6 +4,8 @@
 
 #include "config.h"
 
+#include "platform/fonts/shaping/CachingWordShaper.h"
+
 #include "platform/fonts/FontCache.h"
 #include "platform/fonts/GlyphBuffer.h"
 #include "platform/fonts/shaping/CachingWordShapeIterator.h"
@@ -19,23 +21,17 @@
         fontDescription.setScript(USCRIPT_LATIN);
         fontDescription.setGenericFamily(FontDescription::StandardFamily);
 
-        font = new Font(fontDescription);
+        font = adoptPtr(new Font(fontDescription));
         font->update(nullptr);
         ASSERT_TRUE(font->canShapeWordByWord());
         fallbackFonts = nullptr;
-        cache = new ShapeCache();
-    }
-
-    void TearDown() override
-    {
-        delete cache;
-        delete font;
+        cache = adoptPtr(new ShapeCache());
     }
 
     FontCachePurgePreventer fontCachePurgePreventer;
     FontDescription fontDescription;
-    Font* font;
-    ShapeCache* cache;
+    OwnPtr<Font> font;
+    OwnPtr<ShapeCache> cache;
     HashSet<const SimpleFontData*>* fallbackFonts;
     unsigned startIndex = 0;
     unsigned numGlyphs = 0;
@@ -47,7 +43,7 @@
     TextRun textRun(reinterpret_cast<const LChar*>("ABC DEF."), 8);
 
     RefPtr<ShapeResult> result;
-    CachingWordShapeIterator iterator(cache, textRun, font);
+    CachingWordShapeIterator iterator(cache.get(), textRun, font.get());
     ASSERT_TRUE(iterator.next(&result));
     ASSERT_TRUE(result->runInfoForTesting(0, startIndex, numGlyphs, script));
     EXPECT_EQ(0u, startIndex);
@@ -76,7 +72,7 @@
 
     unsigned offset = 0;
     RefPtr<ShapeResult> result;
-    CachingWordShapeIterator iterator(cache, textRun, font);
+    CachingWordShapeIterator iterator(cache.get(), textRun, font.get());
     ASSERT_TRUE(iterator.next(&result));
     ASSERT_TRUE(result->runInfoForTesting(0, startIndex, numGlyphs, script));
     EXPECT_EQ(0u, offset + startIndex);
@@ -110,14 +106,15 @@
     const UChar str[] = { 0x2F, 0x301, 0x2E, 0x20, 0x2E, 0x0 };
     TextRun textRun(str, 5);
 
-    CachingWordShaper shaper;
+    CachingWordShaper shaper(cache.get());
     GlyphBuffer glyphBuffer;
-    shaper.fillGlyphBuffer(font, textRun, fallbackFonts, &glyphBuffer, 0, 3);
+    shaper.fillGlyphBuffer(font.get(), textRun, fallbackFonts, &glyphBuffer, 0, 3);
 
-    CachingWordShaper referenceShaper;
+    OwnPtr<ShapeCache> referenceCache = adoptPtr(new ShapeCache());
+    CachingWordShaper referenceShaper(referenceCache.get());
     GlyphBuffer referenceGlyphBuffer;
     font->setCanShapeWordByWordForTesting(false);
-    referenceShaper.fillGlyphBuffer(font, textRun, fallbackFonts,
+    referenceShaper.fillGlyphBuffer(font.get(), textRun, fallbackFonts,
         &referenceGlyphBuffer, 0, 3);
 
     ASSERT_EQ(referenceGlyphBuffer.glyphAt(0), glyphBuffer.glyphAt(0));
@@ -134,14 +131,15 @@
     TextRun textRun(str, 6);
     textRun.setDirection(RTL);
 
-    CachingWordShaper shaper;
+    CachingWordShaper shaper(cache.get());
     GlyphBuffer glyphBuffer;
-    shaper.fillGlyphBuffer(font, textRun, fallbackFonts, &glyphBuffer, 1, 6);
+    shaper.fillGlyphBuffer(font.get(), textRun, fallbackFonts, &glyphBuffer, 1, 6);
 
-    CachingWordShaper referenceShaper;
+    OwnPtr<ShapeCache> referenceCache = adoptPtr(new ShapeCache());
+    CachingWordShaper referenceShaper(referenceCache.get());
     GlyphBuffer referenceGlyphBuffer;
     font->setCanShapeWordByWordForTesting(false);
-    referenceShaper.fillGlyphBuffer(font, textRun, fallbackFonts,
+    referenceShaper.fillGlyphBuffer(font.get(), textRun, fallbackFonts,
         &referenceGlyphBuffer, 1, 6);
 
     ASSERT_EQ(5u, referenceGlyphBuffer.size());
@@ -164,16 +162,16 @@
     };
     TextRun textRun(str, 9);
 
-    CachingWordShaper shaper;
+    CachingWordShaper shaper(cache.get());
     FloatRect glyphBounds;
-    ASSERT_GT(shaper.width(font, textRun, nullptr, &glyphBounds), 0);
+    ASSERT_GT(shaper.width(font.get(), textRun, nullptr, &glyphBounds), 0);
 
     GlyphBuffer glyphBuffer;
-    shaper.fillGlyphBuffer(font, textRun, fallbackFonts, &glyphBuffer, 0, 8);
+    shaper.fillGlyphBuffer(font.get(), textRun, fallbackFonts, &glyphBuffer, 0, 8);
 
     FloatPoint point;
     int height = 16;
-    shaper.selectionRect(font, textRun, point, height, 0, 8);
+    shaper.selectionRect(font.get(), textRun, point, height, 0, 8);
 }
 
 TEST_F(CachingWordShaperTest, TextOrientationFallbackShouldNotInFallbackList)
@@ -192,7 +190,7 @@
     verticalMixedFont->update(nullptr);
     ASSERT_TRUE(verticalMixedFont->canShapeWordByWord());
 
-    CachingWordShaper shaper;
+    CachingWordShaper shaper(cache.get());
     FloatRect glyphBounds;
     HashSet<const SimpleFontData*> fallbackFonts;
     ASSERT_GT(shaper.width(verticalMixedFont.get(), textRun, &fallbackFonts, &glyphBounds), 0);
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.h b/third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.h
index ac8278c3..1719726 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.h
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.h
@@ -144,6 +144,11 @@
         m_shortStringMap.clear();
     }
 
+    unsigned size() const
+    {
+        return m_singleCharMap.size() + m_shortStringMap.size();
+    }
+
 private:
     ShapeCacheEntry* addSlowCase(const TextRun& run, ShapeCacheEntry entry)
     {
@@ -171,14 +176,11 @@
             value = &addResult.storedValue->value;
         }
 
-        // Cache hit: ramp up by sampling the next few words.
-        if (!isNewEntry) {
+        if (!isNewEntry)
             return value;
-        }
 
-        if (m_singleCharMap.size() + m_shortStringMap.size() < s_maxSize) {
+        if (size() < s_maxSize)
             return value;
-        }
 
         // No need to be fancy: we're just trying to avoid pathological growth.
         m_singleCharMap.clear();
@@ -194,8 +196,10 @@
     // cache entries is a lot lower given the average word count for a web page
     // is well below 1,000 and even full length books rarely have over 10,000
     // unique words [1]. 1: http://www.mine-control.com/zack/guttenberg/
-    // 2,500 seems like a resonable number.
-    static const unsigned s_maxSize = 2500;
+    // Our definition of a word is somewhat different from the norm in that we
+    // only segment on space. Thus "foo", "foo-", and "foo)" would count as
+    // three separate words. Given that 10,000 seems like a reasonable maximum.
+    static const unsigned s_maxSize = 10000;
 
     SingleCharMap m_singleCharMap;
     SmallStringMap m_shortStringMap;
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp
index 3ef1958..18eb9a03 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp
@@ -314,11 +314,6 @@
     return picture.release();
 }
 
-bool GraphicsContext::isRecording() const
-{
-    return m_canvas != m_originalCanvas;
-}
-
 void GraphicsContext::drawPicture(const SkPicture* picture)
 {
     if (contextDisabled() || !picture || picture->cullRect().isEmpty())
@@ -1030,11 +1025,6 @@
     drawPath(pathToStroke.skPath(), immutableState()->strokePaint());
 }
 
-void GraphicsContext::strokeRect(const FloatRect& rect)
-{
-    strokeRect(rect, strokeThickness());
-}
-
 void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
 {
     if (contextDisabled())
@@ -1208,16 +1198,6 @@
     m_canvas->drawDRRect(SkRRect::MakeRect(rect), roundedHoleRect, paint);
 }
 
-void GraphicsContext::clearRect(const FloatRect& rect)
-{
-    if (contextDisabled())
-        return;
-
-    SkPaint paint(immutableState()->fillPaint());
-    paint.setXfermodeMode(SkXfermode::kClear_Mode);
-    drawRect(rect, paint);
-}
-
 void GraphicsContext::adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, StrokeStyle penStyle)
 {
     // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsContext.h b/third_party/WebKit/Source/platform/graphics/GraphicsContext.h
index bf524bd..be487e63 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsContext.h
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsContext.h
@@ -154,9 +154,6 @@
     void fillRoundedRect(const FloatRoundedRect&, const Color&);
     void fillDRRect(const FloatRoundedRect&, const FloatRoundedRect&, const Color&);
 
-    void clearRect(const FloatRect&);
-
-    void strokeRect(const FloatRect&);
     void strokeRect(const FloatRect&, float lineWidth);
 
     void drawPicture(const SkPicture*);
@@ -332,8 +329,6 @@
 
     void fillRectWithRoundedHole(const FloatRect&, const FloatRoundedRect& roundedHoleRect, const Color&);
 
-    bool isRecording() const;
-
     const SkMetaData& metaData() const { return m_metaData; }
 
     // null indicates painting is contextDisabled. Never delete this object.
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintChunker.h b/third_party/WebKit/Source/platform/graphics/paint/PaintChunker.h
index 8ad71ef8..ddf88111 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintChunker.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintChunker.h
@@ -22,6 +22,7 @@
 
     bool isInInitialState() const { return m_chunks.isEmpty() && m_currentProperties == PaintChunkProperties(); }
 
+    const PaintChunkProperties& currentPaintChunkProperties() const { return m_currentProperties; }
     void updateCurrentPaintChunkProperties(const PaintChunkProperties&);
 
     void incrementDisplayItemIndex();
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
index cbaa5e1..bef27b8d 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
@@ -99,6 +99,11 @@
     m_newPaintChunks.updateCurrentPaintChunkProperties(newProperties);
 }
 
+const PaintChunkProperties& PaintController::currentPaintChunkProperties() const
+{
+    return m_newPaintChunks.currentPaintChunkProperties();
+}
+
 void PaintController::beginScope()
 {
     ASSERT_WITH_SECURITY_IMPLICATION(m_nextScope < UINT_MAX);
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintController.h b/third_party/WebKit/Source/platform/graphics/paint/PaintController.h
index 4e87073..b62d539 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintController.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintController.h
@@ -63,6 +63,9 @@
     // items, for Slimming Paint v2.
     void updateCurrentPaintChunkProperties(const PaintChunkProperties&);
 
+    // Retrieve the current paint properties.
+    const PaintChunkProperties& currentPaintChunkProperties() const;
+
     template <typename DisplayItemClass, typename... Args>
     void createAndAppend(Args&&... args)
     {
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ScopedPaintChunkProperties.h b/third_party/WebKit/Source/platform/graphics/paint/ScopedPaintChunkProperties.h
new file mode 100644
index 0000000..9bf807d
--- /dev/null
+++ b/third_party/WebKit/Source/platform/graphics/paint/ScopedPaintChunkProperties.h
@@ -0,0 +1,36 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ScopedPaintChunkProperties_h
+#define ScopedPaintChunkProperties_h
+
+#include "platform/graphics/paint/PaintChunkProperties.h"
+#include "platform/graphics/paint/PaintController.h"
+#include "wtf/Noncopyable.h"
+
+namespace blink {
+
+class ScopedPaintChunkProperties {
+    WTF_MAKE_NONCOPYABLE(ScopedPaintChunkProperties);
+public:
+    ScopedPaintChunkProperties(PaintController& paintController, const PaintChunkProperties& properties)
+        : m_paintController(paintController)
+        , m_previousProperties(paintController.currentPaintChunkProperties())
+    {
+        m_paintController.updateCurrentPaintChunkProperties(properties);
+    }
+
+    ~ScopedPaintChunkProperties()
+    {
+        m_paintController.updateCurrentPaintChunkProperties(m_previousProperties);
+    }
+
+private:
+    PaintController& m_paintController;
+    PaintChunkProperties m_previousProperties;
+};
+
+} // namespace blink
+
+#endif // ScopedPaintChunkProperties_h
diff --git a/third_party/WebKit/Source/web/WebPagePopupImpl.cpp b/third_party/WebKit/Source/web/WebPagePopupImpl.cpp
index 8842945..18d01ed 100644
--- a/third_party/WebKit/Source/web/WebPagePopupImpl.cpp
+++ b/third_party/WebKit/Source/web/WebPagePopupImpl.cpp
@@ -124,7 +124,7 @@
 
         if (m_popup->isAcceleratedCompositingActive()) {
             ASSERT(m_popup->m_layerTreeView);
-            m_popup->m_layerTreeView->setNeedsCompositorUpdate();
+            m_popup->m_layerTreeView->setNeedsBeginFrame();
             return;
         }
         m_popup->m_widgetClient->scheduleAnimation();
diff --git a/third_party/WebKit/Source/wtf/text/StringUTF8Adaptor.h b/third_party/WebKit/Source/wtf/text/StringUTF8Adaptor.h
index 07f2825..567bb99 100644
--- a/third_party/WebKit/Source/wtf/text/StringUTF8Adaptor.h
+++ b/third_party/WebKit/Source/wtf/text/StringUTF8Adaptor.h
@@ -42,12 +42,7 @@
 // contain only ASCII characters.
 class StringUTF8Adaptor {
 public:
-    enum ShouldNormalize {
-        DoNotNormalize,
-        Normalize
-    };
-
-    explicit StringUTF8Adaptor(const String& string, ShouldNormalize normalize = DoNotNormalize, UnencodableHandling handling = EntitiesForUnencodables)
+    explicit StringUTF8Adaptor(const String& string)
         : m_data(0)
         , m_length(0)
     {
@@ -61,10 +56,7 @@
             m_data = reinterpret_cast<const char*>(string.characters8());
             m_length = string.length();
         } else {
-            if (normalize == Normalize)
-                m_utf8Buffer = UTF8Encoding().normalizeAndEncode(string, handling);
-            else
-                m_utf8Buffer = string.utf8();
+            m_utf8Buffer = string.utf8();
             m_data = m_utf8Buffer.data();
             m_length = m_utf8Buffer.length();
         }
diff --git a/third_party/WebKit/Source/wtf/text/TextEncoding.cpp b/third_party/WebKit/Source/wtf/text/TextEncoding.cpp
index fca629c..3b05638 100644
--- a/third_party/WebKit/Source/wtf/text/TextEncoding.cpp
+++ b/third_party/WebKit/Source/wtf/text/TextEncoding.cpp
@@ -34,7 +34,6 @@
 #include "wtf/text/CString.h"
 #include "wtf/text/TextEncodingRegistry.h"
 #include "wtf/text/WTFString.h"
-#include <unicode/unorm.h>
 
 namespace WTF {
 
@@ -85,45 +84,6 @@
     return encodedString;
 }
 
-CString TextEncoding::normalizeAndEncode(const String& string, UnencodableHandling handling) const
-{
-    if (!m_name)
-        return CString();
-
-    if (string.isEmpty())
-        return "";
-
-    // Text exclusively containing Latin-1 characters (U+0000..U+00FF) is left
-    // unaffected by NFC. This is effectively the same as saying that all
-    // Latin-1 text is already normalized to NFC.
-    // Source: http://unicode.org/reports/tr15/
-    if (string.is8Bit())
-        return newTextCodec(*this)->encode(string.characters8(), string.length(), handling);
-
-    const UChar* source = string.characters16();
-    size_t length = string.length();
-
-    Vector<UChar> normalizedCharacters;
-
-    UErrorCode err = U_ZERO_ERROR;
-    if (unorm_quickCheck(source, length, UNORM_NFC, &err) != UNORM_YES) {
-        // First try using the length of the original string, since normalization to NFC rarely increases length.
-        normalizedCharacters.grow(length);
-        int32_t normalizedLength = unorm_normalize(source, length, UNORM_NFC, 0, normalizedCharacters.data(), length, &err);
-        if (err == U_BUFFER_OVERFLOW_ERROR) {
-            err = U_ZERO_ERROR;
-            normalizedCharacters.resize(normalizedLength);
-            normalizedLength = unorm_normalize(source, length, UNORM_NFC, 0, normalizedCharacters.data(), normalizedLength, &err);
-        }
-        ASSERT(U_SUCCESS(err));
-
-        source = normalizedCharacters.data();
-        length = normalizedLength;
-    }
-
-    return newTextCodec(*this)->encode(source, length, handling);
-}
-
 bool TextEncoding::usesVisualOrdering() const
 {
     if (noExtendedTextEncodingNameUsed())
diff --git a/third_party/WebKit/Source/wtf/text/TextEncoding.h b/third_party/WebKit/Source/wtf/text/TextEncoding.h
index 14d256c..71b829a 100644
--- a/third_party/WebKit/Source/wtf/text/TextEncoding.h
+++ b/third_party/WebKit/Source/wtf/text/TextEncoding.h
@@ -52,12 +52,8 @@
     }
     String decode(const char*, size_t length, bool stopOnError, bool& sawError) const;
 
-    // Encodes the string, but does *not* normalize first.
     CString encode(const String&, UnencodableHandling) const;
 
-    // Applies Unicode NFC normalization, then encodes the normalized string.
-    CString normalizeAndEncode(const String&, UnencodableHandling) const;
-
 private:
     bool isNonByteBasedEncoding() const;
     bool isUTF7Encoding() const;
diff --git a/third_party/mojo/src/mojo/edk/embedder/BUILD.gn b/third_party/mojo/src/mojo/edk/embedder/BUILD.gn
index 3e4adae..f54d9cb4 100644
--- a/third_party/mojo/src/mojo/edk/embedder/BUILD.gn
+++ b/third_party/mojo/src/mojo/edk/embedder/BUILD.gn
@@ -4,17 +4,22 @@
 
 import("../mojo_edk.gni")
 
+mojo_edk_source_set("headers") {
+  sources = [
+    "channel_info_forward.h",
+    "configuration.h",
+    "embedder.h",
+    "embedder_internal.h",
+  ]
+}
+
 mojo_edk_source_set("embedder") {
   # This isn't really a standalone target; it must be linked into the
   # mojo_system_impl component.
   mojo_edk_visibility = [ "mojo/edk/system" ]
 
   sources = [
-    "channel_info_forward.h",
-    "configuration.h",
     "embedder.cc",
-    "embedder.h",
-    "embedder_internal.h",
     "entrypoints.cc",
 
     # Test-only code:
@@ -34,6 +39,7 @@
 
   public_deps = [
     ":delegates",
+    ":headers",
     ":platform",
   ]
 
diff --git a/third_party/mojo/src/mojo/public/c/gles2/BUILD.gn b/third_party/mojo/src/mojo/public/c/gles2/BUILD.gn
index 892b21bc..eb7a6f2 100644
--- a/third_party/mojo/src/mojo/public/c/gles2/BUILD.gn
+++ b/third_party/mojo/src/mojo/public/c/gles2/BUILD.gn
@@ -8,14 +8,7 @@
   defines = [ "GLES2_USE_MOJO" ]
 }
 
-group("gles2") {
-  public_configs = [ "//third_party/khronos:khronos_headers" ]
-  public_deps = [
-    ":headers",
-  ]
-}
-
-mojo_sdk_source_set("headers") {
+mojo_sdk_source_set("gles2") {
   sources = [
     "chromium_extension.h",
     "gles2.h",
diff --git a/third_party/mojo/src/mojo/public/c/system/BUILD.gn b/third_party/mojo/src/mojo/public/c/system/BUILD.gn
index 6a3827c..3c4b29a 100644
--- a/third_party/mojo/src/mojo/public/c/system/BUILD.gn
+++ b/third_party/mojo/src/mojo/public/c/system/BUILD.gn
@@ -33,14 +33,19 @@
 # For shared_library targets (e.g., a Mojo App), add
 # //mojo/public/c/system:for_shared_library to your deps
 
-# TODO(jamesr): Eliminate the need for these targets. crbug.com/438701
 group("for_shared_library") {
   public_deps = [
     ":system",
   ]
-  deps = [
-    "../../platform/native:system",
-  ]
+  if (is_component_build) {
+    deps = [
+      "../../../edk/system",
+    ]
+  } else {
+    deps = [
+      "../../platform/native:system",
+    ]
+  }
 }
 
 group("for_component") {
diff --git a/third_party/mojo/src/mojo/public/gles2/BUILD.gn b/third_party/mojo/src/mojo/public/gles2/BUILD.gn
new file mode 100644
index 0000000..c502f346
--- /dev/null
+++ b/third_party/mojo/src/mojo/public/gles2/BUILD.gn
@@ -0,0 +1,45 @@
+# 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.
+
+# In an is_component_build build, everything can link against //mojo/gles2
+# because it is built as a shared library. However, in a static build,
+# //mojo/gles2 is linked into an executable (e.g., mojo_shell), and must be
+# injected into other shared libraries (i.e., Mojo Apps) that need the mojo
+# gles2 API.
+#
+# For component targets, add //mojo/public/gles2:for_component to your deps
+# section.
+#
+# For shared_library targets (e.g., a Mojo App), add
+# //mojo/public/gles2:for_shared_library to your deps
+
+group("for_shared_library") {
+  public_configs = [ "//third_party/khronos:khronos_headers" ]
+  public_deps = [
+    "//third_party/mojo/src/mojo/public/c/gles2",
+  ]
+
+  if (is_component_build) {
+    deps = [
+      "//mojo/gles2",
+    ]
+  } else {
+    deps = [
+      "//third_party/mojo/src/mojo/public/platform/native:gles2",
+    ]
+  }
+}
+
+group("for_component") {
+  public_configs = [ "//third_party/khronos:khronos_headers" ]
+  public_deps = [
+    "//third_party/mojo/src/mojo/public/c/gles2",
+  ]
+
+  if (is_component_build) {
+    deps = [
+      "//mojo/gles2",
+    ]
+  }
+}
diff --git a/third_party/mojo/src/mojo/public/platform/native/BUILD.gn b/third_party/mojo/src/mojo/public/platform/native/BUILD.gn
index c3b0535..aded499 100644
--- a/third_party/mojo/src/mojo/public/platform/native/BUILD.gn
+++ b/third_party/mojo/src/mojo/public/platform/native/BUILD.gn
@@ -39,7 +39,7 @@
   configs = [ "//third_party/khronos:khronos_headers" ]
 
   mojo_sdk_deps = [
-    "mojo/public/c/gles2:headers",
+    "mojo/public/c/gles2",
     "mojo/public/c/environment",
     "mojo/public/c/system",
   ]
diff --git a/tools/copyright_scanner/third_party_files_whitelist.txt b/tools/copyright_scanner/third_party_files_whitelist.txt
index 97d63e3..a8eee6aed 100644
--- a/tools/copyright_scanner/third_party_files_whitelist.txt
+++ b/tools/copyright_scanner/third_party_files_whitelist.txt
@@ -55,8 +55,6 @@
 # Copyright Apple, Inc, Google Inc; BSD license. Not used on Android.
 # Moved from third_party/WebKit/.
 content/browser/renderer_host/input/web_input_event_builders_mac.mm
-# Copyright Alf Watt; BSD license. Not used on Android.
-content/browser/geolocation/osx_wifi.h
 # Copyright Apple Inc and Torch Mobile Inc; BSD license. Moved from
 # third_party/WebKit/.
 content/renderer/history_controller.h
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 2e384b6..4ee71d1 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -2848,6 +2848,14 @@
   <summary>Image codec inferred during decode.</summary>
 </histogram>
 
+<histogram name="Blink.Fonts.ShapeCache">
+  <owner>eae@chromium.org</owner>
+  <summary>
+    Total number of entires in all blink ShapeCache instances. The value is
+    reported each time the FontCache::purge() method is called.
+  </summary>
+</histogram>
+
 <histogram name="Blink.MediaElement.Autoplay" enum="MediaElementAutoPlay">
   <owner>oysteine@chromium.org</owner>
   <summary>
@@ -64144,7 +64152,6 @@
   <int value="33" label="SXS_OPTION_NOT_SUPPORTED"/>
   <int value="42" label="APPLY_DIFF_PATCH_FAILED"/>
   <int value="47" label="INVALID_STATE_FOR_OPTION"/>
-  <int value="48" label="WAIT_FOR_EXISTING_FAILED"/>
   <int value="49" label="PATCH_INVALID_ARGUMENTS"/>
   <int value="50" label="DIFF_PATCH_SOURCE_MISSING"/>
   <int value="51" label="UNUSED_BINARIES"/>
diff --git a/tools/perf/benchmarks/oortonline.py b/tools/perf/benchmarks/oortonline.py
new file mode 100644
index 0000000..216007f
--- /dev/null
+++ b/tools/perf/benchmarks/oortonline.py
@@ -0,0 +1,40 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import page_sets
+
+from core import perf_benchmark
+from telemetry import benchmark
+from telemetry.page import page_test
+from telemetry.value import scalar
+from telemetry.value import improvement_direction
+
+class _OortOnlineMeasurement(page_test.PageTest):
+  def __init__(self):
+    super(_OortOnlineMeasurement, self).__init__()
+
+  def ValidateAndMeasurePage(self, page, tab, results):
+    tab.WaitForJavaScriptExpression('window.benchmarkFinished', 1000)
+    scores = tab.EvaluateJavaScript('window.benchmarkScore')
+    for score in scores:
+      valid = score['valid']
+      if valid:
+        results.AddValue(scalar.ScalarValue(
+            results.current_page, score['name'], 'score', score['score'],
+            important=True, improvement_direction=improvement_direction.UP))
+
+@benchmark.Disabled('android')
+class OortOnline(perf_benchmark.PerfBenchmark):
+  """OortOnline benchmark that measures WebGL and V8 performance.
+  URL: http://oortonline.gl/#run
+  Info: http://v8project.blogspot.de/2015/10/jank-busters-part-one.html
+  """
+  test = _OortOnlineMeasurement
+
+  @classmethod
+  def Name(cls):
+    return 'oortonline'
+
+  def CreateStorySet(self, options):
+    return page_sets.OortOnlinePageSet()
diff --git a/tools/perf/benchmarks/v8.py b/tools/perf/benchmarks/v8.py
index 1249dba5..9bdf8404 100644
--- a/tools/perf/benchmarks/v8.py
+++ b/tools/perf/benchmarks/v8.py
@@ -14,9 +14,9 @@
 from telemetry.web_perf.metrics import smoothness
 from telemetry.web_perf.metrics import memory_timeline
 
-# Disabled on Win due to crbug.com/416502.
-@benchmark.Disabled('win')
-@benchmark.Disabled('reference') # crbug.com/547833
+
+@benchmark.Disabled('win',        # crbug.com/416502
+                    'reference')  # crbug.com/547833
 class V8Top25(perf_benchmark.PerfBenchmark):
   """Measures V8 GC metrics on the while scrolling down the top 25 web pages.
 
diff --git a/tools/perf/page_sets/data/oortonline.json b/tools/perf/page_sets/data/oortonline.json
new file mode 100644
index 0000000..095ff81
--- /dev/null
+++ b/tools/perf/page_sets/data/oortonline.json
@@ -0,0 +1,8 @@
+{
+    "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating.", 
+    "archives": {
+        "oortonline_000.wpr": [
+            "http://oortonline.gl/#run"
+        ]
+    }
+}
\ No newline at end of file
diff --git a/tools/perf/page_sets/data/oortonline_000.wpr.sha1 b/tools/perf/page_sets/data/oortonline_000.wpr.sha1
new file mode 100644
index 0000000..8131fd8
--- /dev/null
+++ b/tools/perf/page_sets/data/oortonline_000.wpr.sha1
@@ -0,0 +1 @@
+b89e7b2fbbc545d60c5b061ec83c65175e59d284
\ No newline at end of file
diff --git a/tools/perf/page_sets/oortonline.py b/tools/perf/page_sets/oortonline.py
new file mode 100644
index 0000000..bd57464
--- /dev/null
+++ b/tools/perf/page_sets/oortonline.py
@@ -0,0 +1,47 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from page_sets import webgl_supported_shared_state
+from telemetry import page as page_module
+from telemetry import story
+
+STARTUP_SCRIPT = '''
+    window.benchmarkStarted =false;
+    window.benchmarkFinished = false;
+    window.benchmarkBeforeRun = function() {
+      window.benchmarkStarted = true;
+    };
+    window.benchmarkAfterRun = function(score) {
+      window.benchmarkFinished = true;
+      window.benchmarkScore = score;
+      window.benchmarkAfterRun = null;
+    };'''
+
+class OortOnlinePage(page_module.Page):
+  def __init__(self, page_set):
+    super(OortOnlinePage, self).__init__(
+        url='http://oortonline.gl/#run', page_set=page_set,
+        shared_page_state_class=(
+            webgl_supported_shared_state.WebGLSupportedSharedState),
+        make_javascript_deterministic=False)
+    self.archive_data_file = 'data/oortonline.json'
+    self.script_to_evaluate_on_commit = STARTUP_SCRIPT
+
+  @property
+  def skipped_gpus(self):
+    # crbug.com/462729
+    return ['arm', 'broadcom', 'hisilicon', 'imagination', 'qualcomm',
+            'vivante', 'vmware']
+
+class OortOnlinePageSet(story.StorySet):
+  """Oort Online WebGL benchmark.
+  URL: http://oortonline.gl/#run
+  Info: http://v8project.blogspot.de/2015/10/jank-busters-part-one.html
+  """
+
+  def __init__(self):
+    super(OortOnlinePageSet, self).__init__(
+      archive_data_file='data/oortonline.json',
+      cloud_storage_bucket=story.PARTNER_BUCKET)
+    self.AddStory(OortOnlinePage(self))
diff --git a/tools/perf/page_sets/webgl_supported_shared_state.py b/tools/perf/page_sets/webgl_supported_shared_state.py
index 9b34af7..f2f7e7b 100644
--- a/tools/perf/page_sets/webgl_supported_shared_state.py
+++ b/tools/perf/page_sets/webgl_supported_shared_state.py
@@ -38,5 +38,7 @@
           return 'amd'
         elif vendor_id == 0x8086:
           return 'intel'
+        elif vendor_id == 0x15AD:
+          return 'vmware'
 
     return 'unknown_gpu'
diff --git a/tools/telemetry/telemetry/internal/backends/remote/trybot_browser_finder.py b/tools/telemetry/telemetry/internal/backends/remote/trybot_browser_finder.py
index 60fcf595..72db930 100644
--- a/tools/telemetry/telemetry/internal/backends/remote/trybot_browser_finder.py
+++ b/tools/telemetry/telemetry/internal/backends/remote/trybot_browser_finder.py
@@ -22,7 +22,7 @@
 SUCCESS, NO_CHANGES, ERROR = range(3)
 # Unsupported Perf bisect bots.
 EXCLUDED_BOTS = {
-    'win_xp_perf_bisect',
+    'win_xp_perf_bisect',  # Goma issues: crbug.com/330900
     'linux_perf_tester',
     'linux_perf_bisector',
     'win_perf_bisect_builder',
diff --git a/ui/platform_window/android/platform_ime_controller_android.h b/ui/platform_window/android/platform_ime_controller_android.h
index c06081e..fe7ed47 100644
--- a/ui/platform_window/android/platform_ime_controller_android.h
+++ b/ui/platform_window/android/platform_ime_controller_android.h
@@ -7,11 +7,13 @@
 
 #include "base/android/jni_weak_ref.h"
 #include "base/macros.h"
+#include "ui/platform_window/android/android_window_export.h"
 #include "ui/platform_window/platform_ime_controller.h"
 
 namespace ui {
 
-class PlatformImeControllerAndroid : public PlatformImeController {
+class ANDROID_WINDOW_EXPORT PlatformImeControllerAndroid :
+    public PlatformImeController {
  public:
   static bool Register(JNIEnv* env);
 
diff --git a/ui/platform_window/stub/stub_window.h b/ui/platform_window/stub/stub_window.h
index a17812ab..48f74b41 100644
--- a/ui/platform_window/stub/stub_window.h
+++ b/ui/platform_window/stub/stub_window.h
@@ -5,13 +5,14 @@
 #ifndef UI_PLATFORM_WINDOW_STUB_STUB_WINDOW_H_
 #define UI_PLATFORM_WINDOW_STUB_STUB_WINDOW_H_
 
+#include "base/compiler_specific.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/platform_window/platform_window.h"
 #include "ui/platform_window/stub/stub_window_export.h"
 
 namespace ui {
 
-class STUB_WINDOW_EXPORT StubWindow : public PlatformWindow {
+class STUB_WINDOW_EXPORT StubWindow : NON_EXPORTED_BASE(public PlatformWindow) {
  public:
   explicit StubWindow(PlatformWindowDelegate* delegate);
   ~StubWindow() override;
diff --git a/ui/views/mus/BUILD.gn b/ui/views/mus/BUILD.gn
index 1384128..9c92efb 100644
--- a/ui/views/mus/BUILD.gn
+++ b/ui/views/mus/BUILD.gn
@@ -61,6 +61,7 @@
     "//ui/gl",
     "//ui/mojo/ime:interfaces_cpp_sources",
     "//ui/mojo/init",
+    "//ui/native_theme",
     "//ui/views",
     "//ui/wm",
   ]