Update from https://crrev.com/307330

Includes several sky updates for skia API changes and the gn format
presubmit check from https://codereview.chromium.org/779193003/

Review URL: https://codereview.chromium.org/786123002
diff --git a/DEPS b/DEPS
index aac348f..3ff8a41 100644
--- a/DEPS
+++ b/DEPS
@@ -22,19 +22,19 @@
   'libcxx_revision': '48198f9110397fff47fe7c37cbfa296be7d44d3d',
   'libcxxabi_revision': '4ad1009ab3a59fa7a6896d74d5e4de5885697f95',
   'sfntly_revision': '1bdaae8fc788a5ac8936d68bf24f37d977a13dac',
-  'skia_revision': '32fee2907e2109ef420c3fec5f44e655ebc55c2a',
+  'skia_revision': 'cf56009d9058d25933d9840bf6cf9fdf6a80f647',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and V8 without interference from each other.
-  'v8_revision': '5e7bfaf5530837b94fa0c05189c0ab601e3a6355',
+  'v8_revision': '4f77f25857dd9ca5b51749006d6183c3eeb2d49b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  "angle_revision": "746d0ea79208b514e95e626310bec513fa666ca4",
+  "angle_revision": "16545669136028420f67ac496c45c2e9a32ed5a9",
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
-  'buildtools_revision': 'af2cab762e6de03ee53ba430a596ad98d5006778',
+  'buildtools_revision': '535aff24c308a715751028173e569596bcfe12a7',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -78,7 +78,7 @@
    Var('chromium_git') + '/angle/angle.git' + '@' +  Var('angle_revision'),
 
   'src/third_party/icu':
-   Var('chromium_git') + '/chromium/deps/icu52.git' + '@' + '866ff696e9022a6000afbab516fba62cfa306075', # from svn revision 293126
+   Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '53ecf0f68b27a004bef5526553b8e5f6c235b80b',
 
   'src/third_party/libc++/trunk':
    Var('chromium_git') + '/chromium/llvm-project/libcxx.git' + '@' +  Var('libcxx_revision'),
@@ -87,7 +87,7 @@
    Var('chromium_git') + '/chromium/llvm-project/libcxxabi.git' + '@' +  Var('libcxxabi_revision'),
 
   'src/tools/grit':
-    Var('chromium_git') + '/external/grit-i18n.git' + '@' + 'a24a0e647bb718b3540db89864cf586b12331e82', # from svn revision 182
+    Var('chromium_git') + '/external/grit-i18n.git' + '@' + 'ba706f5aa055960b40927d7e5b42186acac9c5e6', # from svn revision 184
 
   'src/v8':
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 47ccdc7..ce66452 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -1542,6 +1542,8 @@
   results.extend(_CommonChecks(input_api, output_api))
   results.extend(_CheckValidHostsInDEPS(input_api, output_api))
   results.extend(_CheckJavaStyle(input_api, output_api))
+  results.extend(
+      input_api.canned_checks.CheckGNFormatted(input_api, output_api))
   return results
 
 
diff --git a/base/command_line.cc b/base/command_line.cc
index 1f5edce..fb7c813 100644
--- a/base/command_line.cc
+++ b/base/command_line.cc
@@ -70,7 +70,7 @@
 }
 
 // Append switches and arguments, keeping switches before arguments.
-void AppendSwitchesAndArguments(CommandLine& command_line,
+void AppendSwitchesAndArguments(CommandLine* command_line,
                                 const CommandLine::StringVector& argv) {
   bool parse_switches = true;
   for (size_t i = 1; i < argv.size(); ++i) {
@@ -82,13 +82,13 @@
     parse_switches &= (arg != kSwitchTerminator);
     if (parse_switches && IsSwitch(arg, &switch_string, &switch_value)) {
 #if defined(OS_WIN)
-      command_line.AppendSwitchNative(UTF16ToASCII(switch_string),
-                                      switch_value);
+      command_line->AppendSwitchNative(UTF16ToASCII(switch_string),
+                                       switch_value);
 #elif defined(OS_POSIX)
-      command_line.AppendSwitchNative(switch_string, switch_value);
+      command_line->AppendSwitchNative(switch_string, switch_value);
 #endif
     } else {
-      command_line.AppendArgNative(arg);
+      command_line->AppendArgNative(arg);
     }
   }
 }
@@ -96,7 +96,7 @@
 // Lowercase switches for backwards compatiblity *on Windows*.
 std::string LowerASCIIOnWindows(const std::string& string) {
 #if defined(OS_WIN)
-  return base::StringToLowerASCII(string);
+  return StringToLowerASCII(string);
 #elif defined(OS_POSIX)
   return string;
 #endif
@@ -105,28 +105,27 @@
 
 #if defined(OS_WIN)
 // Quote a string as necessary for CommandLineToArgvW compatiblity *on Windows*.
-base::string16 QuoteForCommandLineToArgvW(const base::string16& arg,
-                                          bool quote_placeholders) {
+string16 QuoteForCommandLineToArgvW(const string16& arg,
+                                    bool quote_placeholders) {
   // We follow the quoting rules of CommandLineToArgvW.
   // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
-  base::string16 quotable_chars(L" \\\"");
+  string16 quotable_chars(L" \\\"");
   // We may also be required to quote '%', which is commonly used in a command
   // line as a placeholder. (It may be substituted for a string with spaces.)
   if (quote_placeholders)
     quotable_chars.push_back(L'%');
-  if (arg.find_first_of(quotable_chars) == base::string16::npos) {
+  if (arg.find_first_of(quotable_chars) == string16::npos) {
     // No quoting necessary.
     return arg;
   }
 
-  base::string16 out;
+  string16 out;
   out.push_back(L'"');
   for (size_t i = 0; i < arg.size(); ++i) {
     if (arg[i] == '\\') {
       // Find the extent of this run of backslashes.
       size_t start = i, end = start + 1;
-      for (; end < arg.size() && arg[end] == '\\'; ++end)
-        /* empty */;
+      for (; end < arg.size() && arg[end] == '\\'; ++end) {}
       size_t backslash_count = end - start;
 
       // Backslashes are escapes only if the run is followed by a double quote.
@@ -230,7 +229,7 @@
 
 #if defined(OS_WIN)
 // static
-CommandLine CommandLine::FromString(const base::string16& command_line) {
+CommandLine CommandLine::FromString(const string16& command_line) {
   CommandLine cmd(NO_PROGRAM);
   cmd.ParseFromString(command_line);
   return cmd;
@@ -250,7 +249,7 @@
   switches_.clear();
   begin_args_ = 1;
   SetProgram(argv.empty() ? FilePath() : FilePath(argv[0]));
-  AppendSwitchesAndArguments(*this, argv);
+  AppendSwitchesAndArguments(this, argv);
 }
 
 FilePath CommandLine::GetProgram() const {
@@ -304,7 +303,7 @@
                                      const CommandLine::StringType& value) {
   std::string switch_key(LowerASCIIOnWindows(switch_string));
 #if defined(OS_WIN)
-  StringType combined_switch_string(ASCIIToWide(switch_key));
+  StringType combined_switch_string(ASCIIToUTF16(switch_key));
 #elif defined(OS_POSIX)
   StringType combined_switch_string(switch_string);
 #endif
@@ -322,7 +321,7 @@
 void CommandLine::AppendSwitchASCII(const std::string& switch_string,
                                     const std::string& value_string) {
 #if defined(OS_WIN)
-  AppendSwitchNative(switch_string, ASCIIToWide(value_string));
+  AppendSwitchNative(switch_string, ASCIIToUTF16(value_string));
 #elif defined(OS_POSIX)
   AppendSwitchNative(switch_string, value_string);
 #endif
@@ -369,7 +368,7 @@
                                   bool include_program) {
   if (include_program)
     SetProgram(other.GetProgram());
-  AppendSwitchesAndArguments(*this, other.argv());
+  AppendSwitchesAndArguments(this, other.argv());
 }
 
 void CommandLine::PrependWrapper(const CommandLine::StringType& wrapper) {
@@ -385,8 +384,8 @@
 }
 
 #if defined(OS_WIN)
-void CommandLine::ParseFromString(const base::string16& command_line) {
-  base::string16 command_line_string;
+void CommandLine::ParseFromString(const string16& command_line) {
+  string16 command_line_string;
   TrimWhitespace(command_line, TRIM_ALL, &command_line_string);
   if (command_line_string.empty())
     return;
@@ -437,8 +436,7 @@
 #endif
         params.append(kSwitchValueSeparator + switch_value);
       }
-    }
-    else {
+    } else {
 #if defined(OS_WIN)
       arg = QuoteForCommandLineToArgvW(arg, quote_placeholders);
 #endif
diff --git a/base/debug/proc_maps_linux_unittest.cc b/base/debug/proc_maps_linux_unittest.cc
index c9f2267..cbc0dd0 100644
--- a/base/debug/proc_maps_linux_unittest.cc
+++ b/base/debug/proc_maps_linux_unittest.cc
@@ -181,20 +181,19 @@
   }
 }
 
-TEST(ProcMapsTest, ReadProcMaps) {
-  std::string proc_maps;
-  ASSERT_TRUE(ReadProcMaps(&proc_maps));
-
-  std::vector<MappedMemoryRegion> regions;
-  ASSERT_TRUE(ParseProcMaps(proc_maps, &regions));
-  ASSERT_FALSE(regions.empty());
-
+#if defined(ADDRESS_SANITIZER)
+// AddressSanitizer may move local variables to a dedicated "fake stack" which
+// is outside the stack region listed in /proc/self/maps. We disable ASan
+// instrumentation for this function to force the variable to be local.
+__attribute__((no_sanitize_address))
+#endif
+void CheckProcMapsRegions(const std::vector<MappedMemoryRegion> &regions) {
   // We should be able to find both the current executable as well as the stack
-  // mapped into memory. Use the address of |proc_maps| as a way of finding the
+  // mapped into memory. Use the address of |exe_path| as a way of finding the
   // stack.
   FilePath exe_path;
   EXPECT_TRUE(PathService::Get(FILE_EXE, &exe_path));
-  uintptr_t address = reinterpret_cast<uintptr_t>(&proc_maps);
+  uintptr_t address = reinterpret_cast<uintptr_t>(&exe_path);
   bool found_exe = false;
   bool found_stack = false;
   bool found_address = false;
@@ -246,6 +245,17 @@
   }
 }
 
+TEST(ProcMapsTest, ReadProcMaps) {
+  std::string proc_maps;
+  ASSERT_TRUE(ReadProcMaps(&proc_maps));
+
+  std::vector<MappedMemoryRegion> regions;
+  ASSERT_TRUE(ParseProcMaps(proc_maps, &regions));
+  ASSERT_FALSE(regions.empty());
+
+  CheckProcMapsRegions(regions);
+}
+
 TEST(ProcMapsTest, ReadProcMapsNonEmptyString) {
   std::string old_string("I forgot to clear the string");
   std::string proc_maps(old_string);
diff --git a/base/files/file_util_win.cc b/base/files/file_util_win.cc
index b511d3c..e254232 100644
--- a/base/files/file_util_win.cc
+++ b/base/files/file_util_win.cc
@@ -480,7 +480,7 @@
     }
     // Move to the next drive letter string, which starts one
     // increment after the '\0' that terminates the current string.
-    while (*drive_map_ptr++);
+    while (*drive_map_ptr++) {}
   }
 
   // No drive matched.  The path does not start with a device junction
@@ -496,7 +496,7 @@
   // code below to a call to GetFinalPathNameByHandle().  The method this
   // function uses is explained in the following msdn article:
   // http://msdn.microsoft.com/en-us/library/aa366789(VS.85).aspx
-  base::win::ScopedHandle file_handle(
+  win::ScopedHandle file_handle(
       ::CreateFile(path.value().c_str(),
                    GENERIC_READ,
                    kFileShareAll,
@@ -510,7 +510,7 @@
   // Create a file mapping object.  Can't easily use MemoryMappedFile, because
   // we only map the first byte, and need direct access to the handle. You can
   // not map an empty file, this call fails in that case.
-  base::win::ScopedHandle file_map_handle(
+  win::ScopedHandle file_map_handle(
       ::CreateFileMapping(file_handle.Get(),
                           NULL,
                           PAGE_READONLY,
@@ -575,7 +575,7 @@
 
 FILE* OpenFile(const FilePath& filename, const char* mode) {
   ThreadRestrictions::AssertIOAllowed();
-  std::wstring w_mode = ASCIIToWide(std::string(mode));
+  string16 w_mode = ASCIIToUTF16(mode);
   return _wfsopen(filename.value().c_str(), w_mode.c_str(), _SH_DENYNO);
 }
 
@@ -595,13 +595,13 @@
 
 int ReadFile(const FilePath& filename, char* data, int max_size) {
   ThreadRestrictions::AssertIOAllowed();
-  base::win::ScopedHandle file(CreateFile(filename.value().c_str(),
-                                          GENERIC_READ,
-                                          FILE_SHARE_READ | FILE_SHARE_WRITE,
-                                          NULL,
-                                          OPEN_EXISTING,
-                                          FILE_FLAG_SEQUENTIAL_SCAN,
-                                          NULL));
+  win::ScopedHandle file(CreateFile(filename.value().c_str(),
+                                    GENERIC_READ,
+                                    FILE_SHARE_READ | FILE_SHARE_WRITE,
+                                    NULL,
+                                    OPEN_EXISTING,
+                                    FILE_FLAG_SEQUENTIAL_SCAN,
+                                    NULL));
   if (!file.IsValid())
     return -1;
 
@@ -614,13 +614,13 @@
 
 int WriteFile(const FilePath& filename, const char* data, int size) {
   ThreadRestrictions::AssertIOAllowed();
-  base::win::ScopedHandle file(CreateFile(filename.value().c_str(),
-                                          GENERIC_WRITE,
-                                          0,
-                                          NULL,
-                                          CREATE_ALWAYS,
-                                          0,
-                                          NULL));
+  win::ScopedHandle file(CreateFile(filename.value().c_str(),
+                                    GENERIC_WRITE,
+                                    0,
+                                    NULL,
+                                    CREATE_ALWAYS,
+                                    0,
+                                    NULL));
   if (!file.IsValid()) {
     DPLOG(WARNING) << "CreateFile failed for path "
                    << UTF16ToUTF8(filename.value());
@@ -646,13 +646,13 @@
 
 bool AppendToFile(const FilePath& filename, const char* data, int size) {
   ThreadRestrictions::AssertIOAllowed();
-  base::win::ScopedHandle file(CreateFile(filename.value().c_str(),
-                                          FILE_APPEND_DATA,
-                                          0,
-                                          NULL,
-                                          OPEN_EXISTING,
-                                          0,
-                                          NULL));
+  win::ScopedHandle file(CreateFile(filename.value().c_str(),
+                                    FILE_APPEND_DATA,
+                                    0,
+                                    NULL,
+                                    OPEN_EXISTING,
+                                    0,
+                                    NULL));
   if (!file.IsValid()) {
     VPLOG(1) << "CreateFile failed for path " << UTF16ToUTF8(filename.value());
     return false;
diff --git a/base/ios/ios_util.h b/base/ios/ios_util.h
index fca9a50..d9d7e19 100644
--- a/base/ios/ios_util.h
+++ b/base/ios/ios_util.h
@@ -11,9 +11,6 @@
 namespace base {
 namespace ios {
 
-// Returns whether the operating system is iOS 7 or later.
-BASE_EXPORT bool IsRunningOnIOS7OrLater();
-
 // Returns whether the operating system is iOS 8 or later.
 BASE_EXPORT bool IsRunningOnIOS8OrLater();
 
diff --git a/base/ios/ios_util.mm b/base/ios/ios_util.mm
index 91fce0c..ca0a24d 100644
--- a/base/ios/ios_util.mm
+++ b/base/ios/ios_util.mm
@@ -20,10 +20,6 @@
 namespace base {
 namespace ios {
 
-bool IsRunningOnIOS7OrLater() {
-  return IsRunningOnOrLater(7, 0, 0);
-}
-
 bool IsRunningOnIOS8OrLater() {
   return IsRunningOnOrLater(8, 0, 0);
 }
diff --git a/base/memory/shared_memory_win.cc b/base/memory/shared_memory_win.cc
index eef7f03..5d2fa2a 100644
--- a/base/memory/shared_memory_win.cc
+++ b/base/memory/shared_memory_win.cc
@@ -118,8 +118,8 @@
     return false;
 
   size_t rounded_size = (options.size + kSectionMask) & ~kSectionMask;
-  name_ = ASCIIToWide(options.name_deprecated == NULL ? "" :
-                      *options.name_deprecated);
+  name_ = options.name_deprecated ?
+      ASCIIToUTF16(*options.name_deprecated) : L"";
   SECURITY_ATTRIBUTES sa = { sizeof(sa), NULL, FALSE };
   SECURITY_DESCRIPTOR sd;
   ACL dacl;
@@ -137,10 +137,10 @@
     // Windows ignores DACLs on certain unnamed objects (like shared sections).
     // So, we generate a random name when we need to enforce read-only.
     uint64_t rand_values[4];
-    base::RandBytes(&rand_values, sizeof(rand_values));
-    name_ = base::StringPrintf(L"CrSharedMem_%016x%016x%016x%016x",
-                               rand_values[0], rand_values[1],
-                               rand_values[2], rand_values[3]);
+    RandBytes(&rand_values, sizeof(rand_values));
+    name_ = StringPrintf(L"CrSharedMem_%016x%016x%016x%016x",
+                         rand_values[0], rand_values[1],
+                         rand_values[2], rand_values[3]);
   }
   mapped_file_ = CreateFileMapping(INVALID_HANDLE_VALUE, &sa,
       PAGE_READWRITE, 0, static_cast<DWORD>(rounded_size), name_.c_str());
@@ -171,7 +171,7 @@
 bool SharedMemory::Open(const std::string& name, bool read_only) {
   DCHECK(!mapped_file_);
 
-  name_ = ASCIIToWide(name);
+  name_ = ASCIIToUTF16(name);
   read_only_ = read_only;
   mapped_file_ = OpenFileMapping(
       read_only_ ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE,
@@ -218,7 +218,7 @@
 }
 
 bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
-                                        SharedMemoryHandle *new_handle,
+                                        SharedMemoryHandle* new_handle,
                                         bool close_self,
                                         ShareMode share_mode) {
   *new_handle = 0;
diff --git a/base/process/kill.h b/base/process/kill.h
index de72d7a..f697701 100644
--- a/base/process/kill.h
+++ b/base/process/kill.h
@@ -9,6 +9,7 @@
 #define BASE_PROCESS_KILL_H_
 
 #include "base/files/file_path.h"
+#include "base/process/process.h"
 #include "base/process/process_handle.h"
 #include "base/time/time.h"
 
@@ -146,10 +147,10 @@
 // On Linux this method does not block the calling thread.
 // On OS X this method may block for up to 2 seconds.
 //
-// NOTE: The process handle must have been opened with the PROCESS_TERMINATE
-// and SYNCHRONIZE permissions.
+// NOTE: The process must have been opened with the PROCESS_TERMINATE and
+// SYNCHRONIZE permissions.
 //
-BASE_EXPORT void EnsureProcessTerminated(ProcessHandle process_handle);
+BASE_EXPORT void EnsureProcessTerminated(Process process);
 
 #if defined(OS_POSIX) && !defined(OS_MACOSX)
 // The nicer version of EnsureProcessTerminated() that is patient and will
diff --git a/base/process/kill_mac.cc b/base/process/kill_mac.cc
index 9257ee6..a2632f6 100644
--- a/base/process/kill_mac.cc
+++ b/base/process/kill_mac.cc
@@ -165,8 +165,8 @@
 
 }  // namespace
 
-void EnsureProcessTerminated(ProcessHandle process) {
-  WaitForChildToDie(process, kWaitBeforeKillSeconds);
+void EnsureProcessTerminated(Process process) {
+  WaitForChildToDie(process.pid(), kWaitBeforeKillSeconds);
 }
 
 }  // namespace base
diff --git a/base/process/kill_posix.cc b/base/process/kill_posix.cc
index d17e990..3f304ca 100644
--- a/base/process/kill_posix.cc
+++ b/base/process/kill_posix.cc
@@ -463,13 +463,13 @@
 
 }  // namespace
 
-void EnsureProcessTerminated(ProcessHandle process) {
+void EnsureProcessTerminated(Process process) {
   // If the child is already dead, then there's nothing to do.
-  if (IsChildDead(process))
+  if (IsChildDead(process.pid()))
     return;
 
   const unsigned timeout = 2;  // seconds
-  BackgroundReaper* reaper = new BackgroundReaper(process, timeout);
+  BackgroundReaper* reaper = new BackgroundReaper(process.pid(), timeout);
   PlatformThread::CreateNonJoinable(0, reaper);
 }
 
diff --git a/base/process/kill_win.cc b/base/process/kill_win.cc
index b102a87..0a0c99c 100644
--- a/base/process/kill_win.cc
+++ b/base/process/kill_win.cc
@@ -38,7 +38,7 @@
 
 class TimerExpiredTask : public win::ObjectWatcher::Delegate {
  public:
-  explicit TimerExpiredTask(ProcessHandle process);
+  explicit TimerExpiredTask(Process process);
   ~TimerExpiredTask();
 
   void TimedOut();
@@ -50,24 +50,23 @@
   void KillProcess();
 
   // The process that we are watching.
-  ProcessHandle process_;
+  Process process_;
 
   win::ObjectWatcher watcher_;
 
   DISALLOW_COPY_AND_ASSIGN(TimerExpiredTask);
 };
 
-TimerExpiredTask::TimerExpiredTask(ProcessHandle process) : process_(process) {
-  watcher_.StartWatching(process_, this);
+TimerExpiredTask::TimerExpiredTask(Process process) : process_(process.Pass()) {
+  watcher_.StartWatching(process_.Handle(), this);
 }
 
 TimerExpiredTask::~TimerExpiredTask() {
   TimedOut();
-  DCHECK(!process_) << "Make sure to close the handle.";
 }
 
 void TimerExpiredTask::TimedOut() {
-  if (process_)
+  if (process_.IsValid())
     KillProcess();
 }
 
@@ -76,8 +75,7 @@
   tracked_objects::ScopedTracker tracking_profile(
       FROM_HERE_WITH_EXPLICIT_FUNCTION("TimerExpiredTask_OnObjectSignaled"));
 
-  CloseHandle(process_);
-  process_ = NULL;
+  process_.Close();
 }
 
 void TimerExpiredTask::KillProcess() {
@@ -88,10 +86,10 @@
   // terminates.  We just care that it eventually terminates, and that's what
   // TerminateProcess should do for us. Don't check for the result code since
   // it fails quite often. This should be investigated eventually.
-  base::KillProcess(process_, kProcessKilledExitCode, false);
+  base::KillProcess(process_.Handle(), kProcessKilledExitCode, false);
 
   // Now, just cleanup as if the process exited normally.
-  OnObjectSignaled(process_);
+  OnObjectSignaled(process_.Handle());
 }
 
 }  // namespace
@@ -241,19 +239,18 @@
   return false;
 }
 
-void EnsureProcessTerminated(ProcessHandle process) {
-  DCHECK(process != GetCurrentProcess());
+void EnsureProcessTerminated(Process process) {
+  DCHECK(!process.is_current());
 
   // If already signaled, then we are done!
-  if (WaitForSingleObject(process, 0) == WAIT_OBJECT_0) {
-    CloseHandle(process);
+  if (WaitForSingleObject(process.Handle(), 0) == WAIT_OBJECT_0) {
     return;
   }
 
   MessageLoop::current()->PostDelayedTask(
       FROM_HERE,
       base::Bind(&TimerExpiredTask::TimedOut,
-                 base::Owned(new TimerExpiredTask(process))),
+                 base::Owned(new TimerExpiredTask(process.Pass()))),
       base::TimeDelta::FromMilliseconds(kWaitInterval));
 }
 
diff --git a/base/process/launch.h b/base/process/launch.h
index 06abb29..0450ddf 100644
--- a/base/process/launch.h
+++ b/base/process/launch.h
@@ -22,7 +22,6 @@
 #include "base/posix/file_descriptor_shuffle.h"
 #elif defined(OS_WIN)
 #include <windows.h>
-#include "base/win/scoped_handle.h"
 #endif
 
 namespace base {
@@ -174,9 +173,8 @@
 //
 // Example (including literal quotes)
 //  cmdline = "c:\windows\explorer.exe" -foo "c:\bar\"
-BASE_EXPORT bool LaunchProcess(const string16& cmdline,
-                               const LaunchOptions& options,
-                               win::ScopedHandle* process_handle);
+BASE_EXPORT Process LaunchProcess(const string16& cmdline,
+                                  const LaunchOptions& options);
 
 // Launches a process with elevated privileges.  This does not behave exactly
 // like LaunchProcess as it uses ShellExecuteEx instead of CreateProcess to
diff --git a/base/process/launch_win.cc b/base/process/launch_win.cc
index 3c787fe..1d83ef9 100644
--- a/base/process/launch_win.cc
+++ b/base/process/launch_win.cc
@@ -232,6 +232,17 @@
   return true;
 }
 
+// TODO(rvargas) crbug.com/416721: Remove this stub after LaunchProcess is
+// fully migrated to use Process.
+Process LaunchProcess(const string16& cmdline,
+                      const LaunchOptions& options) {
+  win::ScopedHandle process_handle;
+  if (LaunchProcess(cmdline, options, &process_handle))
+    return Process(process_handle.Take());
+
+  return Process();
+}
+
 bool LaunchProcess(const CommandLine& cmdline,
                    const LaunchOptions& options,
                    ProcessHandle* process_handle) {
diff --git a/base/process/process_metrics_posix.cc b/base/process/process_metrics_posix.cc
index ea79d73..7afae21 100644
--- a/base/process/process_metrics_posix.cc
+++ b/base/process/process_metrics_posix.cc
@@ -12,9 +12,8 @@
 namespace base {
 
 int64 TimeValToMicroseconds(const struct timeval& tv) {
-  static const int kMicrosecondsPerSecond = 1000000;
   int64 ret = tv.tv_sec;  // Avoid (int * int) integer overflow.
-  ret *= kMicrosecondsPerSecond;
+  ret *= Time::kMicrosecondsPerSecond;
   ret += tv.tv_usec;
   return ret;
 }
diff --git a/base/process/process_util_unittest.cc b/base/process/process_util_unittest.cc
index c98884d..af88fe1 100644
--- a/base/process/process_util_unittest.cc
+++ b/base/process/process_util_unittest.cc
@@ -888,14 +888,14 @@
 }
 
 TEST_F(ProcessUtilTest, DelayedTermination) {
-  base::ProcessHandle child_process = SpawnChild("process_util_test_never_die");
-  ASSERT_TRUE(child_process);
-  base::EnsureProcessTerminated(child_process);
-  base::WaitForSingleProcess(child_process, base::TimeDelta::FromSeconds(5));
+  base::Process child_process(SpawnChild("process_util_test_never_die"));
+  ASSERT_TRUE(child_process.IsValid());
+  base::EnsureProcessTerminated(child_process.Duplicate());
+  base::WaitForSingleProcess(child_process.Handle(),
+                             base::TimeDelta::FromSeconds(5));
 
   // Check that process was really killed.
-  EXPECT_TRUE(IsProcessDead(child_process));
-  base::CloseProcessHandle(child_process);
+  EXPECT_TRUE(IsProcessDead(child_process.Handle()));
 }
 
 MULTIPROCESS_TEST_MAIN(process_util_test_never_die) {
@@ -906,16 +906,14 @@
 }
 
 TEST_F(ProcessUtilTest, ImmediateTermination) {
-  base::ProcessHandle child_process =
-      SpawnChild("process_util_test_die_immediately");
-  ASSERT_TRUE(child_process);
+  base::Process child_process(SpawnChild("process_util_test_die_immediately"));
+  ASSERT_TRUE(child_process.IsValid());
   // Give it time to die.
   sleep(2);
-  base::EnsureProcessTerminated(child_process);
+  base::EnsureProcessTerminated(child_process.Duplicate());
 
   // Check that process was really killed.
-  EXPECT_TRUE(IsProcessDead(child_process));
-  base::CloseProcessHandle(child_process);
+  EXPECT_TRUE(IsProcessDead(child_process.Handle()));
 }
 
 MULTIPROCESS_TEST_MAIN(process_util_test_die_immediately) {
diff --git a/base/strings/safe_sprintf_unittest.cc b/base/strings/safe_sprintf_unittest.cc
index 02c75f9..ff05c6e 100644
--- a/base/strings/safe_sprintf_unittest.cc
+++ b/base/strings/safe_sprintf_unittest.cc
@@ -61,7 +61,7 @@
   // always add a trailing NUL; it always deduplicates '%' characters).
   static const char text[] = "hello world";
   char ref[20], buf[20];
-  memset(ref, 'X', sizeof(char) * arraysize(buf));
+  memset(ref, 'X', sizeof(ref));
   memcpy(buf, ref, sizeof(buf));
 
   // A negative buffer size should always result in an error.
diff --git a/base/test/launcher/test_launcher.cc b/base/test/launcher/test_launcher.cc
index 0d3eba9..707a4d7 100644
--- a/base/test/launcher/test_launcher.cc
+++ b/base/test/launcher/test_launcher.cc
@@ -228,7 +228,7 @@
   // on a CommandLine with a wrapper is known to break.
   // TODO(phajdan.jr): Give it a try to support CommandLine removing switches.
 #if defined(OS_WIN)
-  new_command_line.PrependWrapper(ASCIIToWide(wrapper));
+  new_command_line.PrependWrapper(ASCIIToUTF16(wrapper));
 #elif defined(OS_POSIX)
   new_command_line.PrependWrapper(wrapper);
 #endif
@@ -242,7 +242,7 @@
 int LaunchChildTestProcessWithOptions(const CommandLine& command_line,
                                       const LaunchOptions& options,
                                       int flags,
-                                      base::TimeDelta timeout,
+                                      TimeDelta timeout,
                                       bool* was_timeout) {
 #if defined(OS_POSIX)
   // Make sure an option we rely on is present - see LaunchChildGTestProcess.
@@ -287,7 +287,7 @@
   new_options.allow_new_privs = true;
 #endif
 
-  base::ProcessHandle process_handle;
+  ProcessHandle process_handle;
 
   {
     // Note how we grab the lock before the process possibly gets created.
@@ -295,21 +295,19 @@
     // in the set.
     AutoLock lock(g_live_processes_lock.Get());
 
-    if (!base::LaunchProcess(command_line, new_options, &process_handle))
+    if (!LaunchProcess(command_line, new_options, &process_handle))
       return -1;
 
     g_live_processes.Get().insert(std::make_pair(process_handle, command_line));
   }
 
   int exit_code = 0;
-  if (!base::WaitForExitCodeWithTimeout(process_handle,
-                                        &exit_code,
-                                        timeout)) {
+  if (!WaitForExitCodeWithTimeout(process_handle, &exit_code, timeout)) {
     *was_timeout = true;
     exit_code = -1;  // Set a non-zero exit code to signal a failure.
 
     // Ensure that the process terminates.
-    base::KillProcess(process_handle, -1, true);
+    KillProcess(process_handle, -1, true);
   }
 
   {
@@ -324,14 +322,14 @@
       // or due to it timing out, we need to clean up any child processes that
       // it might have created. On Windows, child processes are automatically
       // cleaned up using JobObjects.
-      base::KillProcessGroup(process_handle);
+      KillProcessGroup(process_handle);
     }
 #endif
 
     g_live_processes.Get().erase(process_handle);
   }
 
-  base::CloseProcessHandle(process_handle);
+  CloseProcessHandle(process_handle);
 
   return exit_code;
 }
@@ -347,7 +345,7 @@
 
 void DoLaunchChildTestProcess(
     const CommandLine& command_line,
-    base::TimeDelta timeout,
+    TimeDelta timeout,
     int flags,
     bool redirect_stdio,
     scoped_refptr<MessageLoopProxy> message_loop_proxy,
@@ -355,8 +353,8 @@
   TimeTicks start_time = TimeTicks::Now();
 
   // Redirect child process output to a file.
-  base::FilePath output_file;
-  CHECK(base::CreateTemporaryFile(&output_file));
+  FilePath output_file;
+  CHECK(CreateTemporaryFile(&output_file));
 
   LaunchOptions options;
 #if defined(OS_WIN)
@@ -385,8 +383,8 @@
 #elif defined(OS_POSIX)
   options.new_process_group = true;
 
-  base::FileHandleMappingVector fds_mapping;
-  base::ScopedFD output_file_fd;
+  FileHandleMappingVector fds_mapping;
+  ScopedFD output_file_fd;
 
   if (redirect_stdio) {
     output_file_fd.reset(open(output_file.value().c_str(), O_RDWR));
@@ -412,9 +410,9 @@
   }
 
   std::string output_file_contents;
-  CHECK(base::ReadFileToString(output_file, &output_file_contents));
+  CHECK(ReadFileToString(output_file, &output_file_contents));
 
-  if (!base::DeleteFile(output_file, false)) {
+  if (!DeleteFile(output_file, false)) {
     // This needs to be non-fatal at least for Windows.
     LOG(WARNING) << "Failed to delete " << output_file.AsUTF8Unsafe();
   }
@@ -519,7 +517,7 @@
 void TestLauncher::LaunchChildGTestProcess(
     const CommandLine& command_line,
     const std::string& wrapper,
-    base::TimeDelta timeout,
+    TimeDelta timeout,
     int flags,
     const LaunchChildGTestProcessCallback& callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
@@ -945,10 +943,8 @@
     if (excluded)
       continue;
 
-    if (base::Hash(test_name) % total_shards_ !=
-        static_cast<uint32>(shard_index_)) {
+    if (Hash(test_name) % total_shards_ != static_cast<uint32>(shard_index_))
       continue;
-    }
 
     test_names.push_back(test_name);
   }
diff --git a/base/test/test_reg_util_win.cc b/base/test/test_reg_util_win.cc
index 2cbafef..e3b1ffc 100644
--- a/base/test/test_reg_util_win.cc
+++ b/base/test/test_reg_util_win.cc
@@ -54,7 +54,7 @@
                                    const base::Time& timestamp) {
   base::string16 key_path = test_key_root;
   key_path += L"\\" + base::Int64ToString16(timestamp.ToInternalValue());
-  key_path += kTimestampDelimiter + base::ASCIIToWide(base::GenerateGUID());
+  key_path += kTimestampDelimiter + base::ASCIIToUTF16(base::GenerateGUID());
 
   return key_path;
 }
diff --git a/base/third_party/dynamic_annotations/README.chromium b/base/third_party/dynamic_annotations/README.chromium
index dc8bdef..ff21b19 100644
--- a/base/third_party/dynamic_annotations/README.chromium
+++ b/base/third_party/dynamic_annotations/README.chromium
@@ -3,6 +3,13 @@
 Version: 4384
 License: BSD
 
+ATTENTION: please avoid using these annotations in Chromium code.
+They were mainly intended to instruct the Valgrind-based version of
+ThreadSanitizer to handle atomic operations. The new version of ThreadSanitizer
+based on compiler instrumentation understands atomic operations out of the box,
+so normally you don't need the annotations.
+If you still think you do, please consider writing a comment at http://crbug.com/349861
+
 One header and one source file (dynamic_annotations.h and dynamic_annotations.c)
 in this directory define runtime macros useful for annotating synchronization
 utilities and benign data races so data race detectors can handle Chromium code
diff --git a/build/android/pylib/device/adb_wrapper.py b/build/android/pylib/device/adb_wrapper.py
index e73d66c..39fe706 100644
--- a/build/android/pylib/device/adb_wrapper.py
+++ b/build/android/pylib/device/adb_wrapper.py
@@ -161,8 +161,13 @@
       timeout: (optional) Timeout per try in seconds.
       retries: (optional) Number of retries to attempt.
     """
-    self._RunDeviceAdbCmd(['pull', remote, local], timeout, retries)
-    _VerifyLocalFileExists(local)
+    cmd = ['pull', remote, local]
+    self._RunDeviceAdbCmd(cmd, timeout, retries)
+    try:
+      _VerifyLocalFileExists(local)
+    except IOError:
+      raise device_errors.AdbCommandFailedError(
+          cmd, 'File not found on host: %s' % local, device_serial=str(self))
 
   def Shell(self, command, expect_status=0, timeout=_DEFAULT_TIMEOUT,
             retries=_DEFAULT_RETRIES):
diff --git a/build/android/pylib/device/device_utils.py b/build/android/pylib/device/device_utils.py
index 66a62fd..403f235 100644
--- a/build/android/pylib/device/device_utils.py
+++ b/build/android/pylib/device/device_utils.py
@@ -855,11 +855,11 @@
       CommandFailedError on failure.
       CommandTimeoutError on timeout.
     """
-    try:
-      self.old_interface.PullFileFromDevice(device_path, host_path)
-    except AssertionError as e:
-      raise device_errors.CommandFailedError(
-          str(e), str(self)), None, sys.exc_info()[2]
+    # Create the base dir if it doesn't exist already
+    dirname = os.path.dirname(host_path)
+    if dirname and not os.path.exists(dirname):
+      os.makedirs(dirname)
+    self.adb.Pull(device_path, host_path)
 
   @decorators.WithTimeoutAndRetriesFromInstance()
   def ReadFile(self, device_path, as_root=False, timeout=None, retries=None):
diff --git a/build/android/pylib/device/device_utils_test.py b/build/android/pylib/device/device_utils_test.py
index 5f2249d..512a7d4 100755
--- a/build/android/pylib/device/device_utils_test.py
+++ b/build/android/pylib/device/device_utils_test.py
@@ -1093,26 +1093,22 @@
       self.assertFalse(self.device.FileExists('/does/not/exist'))
 
 
-class DeviceUtilsPullFileTest(DeviceUtilsOldImplTest):
+class DeviceUtilsPullFileTest(DeviceUtilsNewImplTest):
 
   def testPullFile_existsOnDevice(self):
     with mock.patch('os.path.exists', return_value=True):
-      with self.assertCallsSequence([
-          ('adb -s 0123456789abcdef shell '
-              'ls /data/app/test.file.exists',
-           '/data/app/test.file.exists'),
-          ('adb -s 0123456789abcdef pull '
-              '/data/app/test.file.exists /test/file/host/path',
-           '100 B/s (100 bytes in 1.000s)\r\n')]):
+      with self.assertCall(
+          self.call.adb.Pull('/data/app/test.file.exists',
+                             '/test/file/host/path')):
         self.device.PullFile('/data/app/test.file.exists',
                              '/test/file/host/path')
 
   def testPullFile_doesntExistOnDevice(self):
     with mock.patch('os.path.exists', return_value=True):
-      with self.assertCalls(
-          'adb -s 0123456789abcdef shell '
-              'ls /data/app/test.file.does.not.exist',
-          '/data/app/test.file.does.not.exist: No such file or directory\r\n'):
+      with self.assertCall(
+          self.call.adb.Pull('/data/app/test.file.does.not.exist',
+                             '/test/file/host/path'),
+          self.CommandError('remote object does not exist')):
         with self.assertRaises(device_errors.CommandFailedError):
           self.device.PullFile('/data/app/test.file.does.not.exist',
                                '/test/file/host/path')
diff --git a/build/common.gypi b/build/common.gypi
index 5a8f1b9..204a133 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -4185,13 +4185,6 @@
                 ],
               }],
             ],
-            'conditions': [
-              ['OS=="mac"', {
-                'cflags': [
-                  '-mllvm -asan-globals=0',  # http://crbug.com/352073
-                ],
-              }],
-            ],
           }],
           ['ubsan==1', {
             'target_conditions': [
@@ -4907,7 +4900,6 @@
             'xcode_settings': {
               'OTHER_CFLAGS': [
                 '-fsanitize=address',
-                '-mllvm -asan-globals=0',  # http://crbug.com/352073
                 '-gline-tables-only',
               ],
             },
diff --git a/build/config/clang/clang.gni b/build/config/clang/clang.gni
index 3b2d76f..cb84879 100644
--- a/build/config/clang/clang.gni
+++ b/build/config/clang/clang.gni
@@ -5,5 +5,5 @@
 declare_args() {
   # Indicates if the build should use the Chrome-specific plugins for enforcing
   # coding guidelines, etc. Only used when compiling with Clang.
-  clang_use_chrome_plugins = is_clang
+  clang_use_chrome_plugins = is_clang && !is_nacl
 }
diff --git a/build/grit_action.gypi b/build/grit_action.gypi
index ab7a70b..15ead28 100644
--- a/build/grit_action.gypi
+++ b/build/grit_action.gypi
@@ -21,6 +21,20 @@
     # instead of build/common.gypi .
     'grit_additional_defines%': [],
     'grit_rc_header_format%': [],
+
+    'conditions': [
+      # These scripts can skip writing generated files if they are identical
+      # to the already existing files, which avoids further build steps, like
+      # recompilation. However, a dependency (earlier build step) having a
+      # newer timestamp than an output (later build step) confuses some build
+      # systems, so only use this on ninja, which explicitly supports this use
+      # case (gyp turns all actions into ninja restat rules).
+      ['"<(GENERATOR)"=="ninja"', {
+        'write_only_new': '1',
+      }, {
+        'write_only_new': '0',
+      }],
+    ],
   },
   'inputs': [
     '<!@pymod_do_main(grit_info <@(grit_defines) <@(grit_additional_defines) '
@@ -35,6 +49,7 @@
              '-i', '<(grit_grd_file)', 'build',
              '-f', '<(grit_resource_ids)',
              '-o', '<(grit_out_dir)',
+             '--write-only-new=<(write_only_new)',
              '<@(grit_defines)',
              '<@(grit_additional_defines)',
              '<@(grit_rc_header_format)'],
diff --git a/build/ios/grit_whitelist.txt b/build/ios/grit_whitelist.txt
index 6fbe58d..17d9f89 100644
--- a/build/ios/grit_whitelist.txt
+++ b/build/ios/grit_whitelist.txt
@@ -77,7 +77,6 @@
 IDR_POLICY_HTML
 IDR_POLICY_JS
 IDR_PRINTER_FAVICON
-IDR_PRODUCT_LOGO_26
 IDR_SAD_FAVICON
 IDR_SAD_TAB
 IDR_SECURITY_INTERSTITIAL_HTML
diff --git a/build/sanitizers/sanitizer_options.cc b/build/sanitizers/sanitizer_options.cc
index 821ba48..a3b05c1 100644
--- a/build/sanitizers/sanitizer_options.cc
+++ b/build/sanitizers/sanitizer_options.cc
@@ -49,6 +49,8 @@
 //   fast_unwind_on_fatal=1 - use the fast (frame-pointer-based) stack unwinder
 //     to print error reports. V8 doesn't generate debug info for the JIT code,
 //     so the slow unwinder may not work properly.
+//   detect_stack_use_after_return=1 - use fake stack to delay the reuse of
+//     stack allocations and detect stack-use-after-return errors.
 #if defined(OS_LINUX)
 #if defined(GOOGLE_CHROME_BUILD)
 // Default AddressSanitizer options for the official build. These do not affect
@@ -62,13 +64,14 @@
 // Default AddressSanitizer options for buildbots and non-official builds.
 const char *kAsanDefaultOptions =
     "strict_memcmp=0 symbolize=false check_printf=1 use_sigaltstack=1 "
-    "detect_leaks=0 strip_path_prefix=Release/../../ fast_unwind_on_fatal=1";
+    "detect_leaks=0 strip_path_prefix=Release/../../ fast_unwind_on_fatal=1 "
+    "detect_stack_use_after_return=1 ";
 #endif  // GOOGLE_CHROME_BUILD
 
 #elif defined(OS_MACOSX)
 const char *kAsanDefaultOptions =
     "strict_memcmp=0 replace_intrin=0 check_printf=1 use_sigaltstack=1 "
-    "strip_path_prefix=Release/../../ fast_unwind_on_fatal=1";
+    "strip_path_prefix=Release/../../ fast_unwind_on_fatal=1 ";
 static const char kNaClDefaultOptions[] = "handle_segv=0";
 static const char kNaClFlag[] = "--type=nacl-loader";
 #endif  // OS_LINUX
diff --git a/build/sanitizers/tsan_suppressions.cc b/build/sanitizers/tsan_suppressions.cc
index 49e860d..7c10d6c 100644
--- a/build/sanitizers/tsan_suppressions.cc
+++ b/build/sanitizers/tsan_suppressions.cc
@@ -149,10 +149,6 @@
 // http://crbug.com/285242
 "race:media::PulseAudioOutputStream::SetVolume\n"
 
-// http://crbug.com/290964
-"race:PostponeInterruptsScope\n"
-"race:v8::internal::StackGuard::RequestInstallCode\n"
-
 // http://crbug.com/296883
 "race:net::URLFetcherCore::Stop\n"
 
diff --git a/build/secondary/tools/grit/grit_rule.gni b/build/secondary/tools/grit/grit_rule.gni
index 9010abc..7a1cc26 100644
--- a/build/secondary/tools/grit/grit_rule.gni
+++ b/build/secondary/tools/grit/grit_rule.gni
@@ -381,6 +381,7 @@
               ".",
               "--depfile",
               rebase_path(depfile, root_build_dir),
+              "--write-only-new=1",
             ] + grit_defines
 
     # Add extra defines with -D flags.
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 7402509..0e1a6a3 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -436,6 +436,8 @@
     "resources/tile_priority.h",
     "resources/tiling_set_eviction_queue.cc",
     "resources/tiling_set_eviction_queue.h",
+    "resources/tiling_set_raster_queue.cc",
+    "resources/tiling_set_raster_queue.h",
     "resources/transferable_resource.cc",
     "resources/transferable_resource.h",
     "resources/transform_display_item.cc",
diff --git a/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc b/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc
index 3f01c54..4c8b49b 100644
--- a/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc
+++ b/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc
@@ -130,13 +130,13 @@
 TEST_F(ScrollbarAnimationControllerLinearFadeTest, HideOnResize) {
   LayerImpl* scroll_layer = host_impl_.active_tree()->LayerById(1);
   ASSERT_TRUE(scroll_layer);
-  EXPECT_SIZE_EQ(gfx::Size(200, 200), scroll_layer->bounds());
+  EXPECT_EQ(gfx::Size(200, 200), scroll_layer->bounds());
 
   EXPECT_EQ(HORIZONTAL, scrollbar_layer_->orientation());
 
   // Shrink along X axis, horizontal scrollbar should appear.
   clip_layer_->SetBounds(gfx::Size(100, 200));
-  EXPECT_SIZE_EQ(gfx::Size(100, 200), clip_layer_->bounds());
+  EXPECT_EQ(gfx::Size(100, 200), clip_layer_->bounds());
 
   scrollbar_controller_->DidScrollBegin();
 
@@ -148,7 +148,7 @@
   // Shrink along Y axis and expand along X, horizontal scrollbar
   // should disappear.
   clip_layer_->SetBounds(gfx::Size(200, 100));
-  EXPECT_SIZE_EQ(gfx::Size(200, 100), clip_layer_->bounds());
+  EXPECT_EQ(gfx::Size(200, 100), clip_layer_->bounds());
 
   scrollbar_controller_->DidScrollBegin();
 
@@ -161,13 +161,13 @@
 TEST_F(VerticalScrollbarAnimationControllerLinearFadeTest, HideOnResize) {
   LayerImpl* scroll_layer = host_impl_.active_tree()->LayerById(1);
   ASSERT_TRUE(scroll_layer);
-  EXPECT_SIZE_EQ(gfx::Size(200, 200), scroll_layer->bounds());
+  EXPECT_EQ(gfx::Size(200, 200), scroll_layer->bounds());
 
   EXPECT_EQ(VERTICAL, scrollbar_layer_->orientation());
 
   // Shrink along X axis, vertical scrollbar should remain invisible.
   clip_layer_->SetBounds(gfx::Size(100, 200));
-  EXPECT_SIZE_EQ(gfx::Size(100, 200), clip_layer_->bounds());
+  EXPECT_EQ(gfx::Size(100, 200), clip_layer_->bounds());
 
   scrollbar_controller_->DidScrollBegin();
 
@@ -178,7 +178,7 @@
 
   // Shrink along Y axis and expand along X, vertical scrollbar should appear.
   clip_layer_->SetBounds(gfx::Size(200, 100));
-  EXPECT_SIZE_EQ(gfx::Size(200, 100), clip_layer_->bounds());
+  EXPECT_EQ(gfx::Size(200, 100), clip_layer_->bounds());
 
   scrollbar_controller_->DidScrollBegin();
 
diff --git a/cc/animation/scrollbar_animation_controller_thinning_unittest.cc b/cc/animation/scrollbar_animation_controller_thinning_unittest.cc
index d46431b..74e9517 100644
--- a/cc/animation/scrollbar_animation_controller_thinning_unittest.cc
+++ b/cc/animation/scrollbar_animation_controller_thinning_unittest.cc
@@ -85,13 +85,13 @@
 TEST_F(ScrollbarAnimationControllerThinningTest, HideOnResize) {
   LayerImpl* scroll_layer = host_impl_.active_tree()->LayerById(1);
   ASSERT_TRUE(scroll_layer);
-  EXPECT_SIZE_EQ(gfx::Size(200, 200), scroll_layer->bounds());
+  EXPECT_EQ(gfx::Size(200, 200), scroll_layer->bounds());
 
   EXPECT_EQ(HORIZONTAL, scrollbar_layer_->orientation());
 
   // Shrink along X axis, horizontal scrollbar should appear.
   clip_layer_->SetBounds(gfx::Size(100, 200));
-  EXPECT_SIZE_EQ(gfx::Size(100, 200), clip_layer_->bounds());
+  EXPECT_EQ(gfx::Size(100, 200), clip_layer_->bounds());
 
   scrollbar_controller_->DidScrollBegin();
 
@@ -103,7 +103,7 @@
   // Shrink along Y axis and expand along X, horizontal scrollbar
   // should disappear.
   clip_layer_->SetBounds(gfx::Size(200, 100));
-  EXPECT_SIZE_EQ(gfx::Size(200, 100), clip_layer_->bounds());
+  EXPECT_EQ(gfx::Size(200, 100), clip_layer_->bounds());
 
   scrollbar_controller_->DidScrollBegin();
 
diff --git a/cc/base/tiling_data_unittest.cc b/cc/base/tiling_data_unittest.cc
index 667719b..732b04d 100644
--- a/cc/base/tiling_data_unittest.cc
+++ b/cc/base/tiling_data_unittest.cc
@@ -775,26 +775,23 @@
 
 TEST(TilingDataTest, ExpandRectIgnoringBordersToTileBoundsEmpty) {
   TilingData empty_total_size(gfx::Size(0, 0), gfx::Size(8, 8), true);
-  EXPECT_RECT_EQ(
-      gfx::Rect(),
-      empty_total_size.ExpandRectIgnoringBordersToTileBounds(gfx::Rect()));
-  EXPECT_RECT_EQ(gfx::Rect(),
-                 empty_total_size.ExpandRectIgnoringBordersToTileBounds(
-                     gfx::Rect(100, 100, 100, 100)));
-  EXPECT_RECT_EQ(gfx::Rect(),
-                 empty_total_size.ExpandRectIgnoringBordersToTileBounds(
-                     gfx::Rect(100, 100)));
+  EXPECT_EQ(gfx::Rect(), empty_total_size.ExpandRectIgnoringBordersToTileBounds(
+                             gfx::Rect()));
+  EXPECT_EQ(gfx::Rect(), empty_total_size.ExpandRectIgnoringBordersToTileBounds(
+                             gfx::Rect(100, 100, 100, 100)));
+  EXPECT_EQ(gfx::Rect(), empty_total_size.ExpandRectIgnoringBordersToTileBounds(
+                             gfx::Rect(100, 100)));
 
   TilingData empty_max_texture_size(gfx::Size(8, 8), gfx::Size(0, 0), true);
-  EXPECT_RECT_EQ(gfx::Rect(),
-                 empty_max_texture_size.ExpandRectIgnoringBordersToTileBounds(
-                     gfx::Rect()));
-  EXPECT_RECT_EQ(gfx::Rect(),
-                 empty_max_texture_size.ExpandRectIgnoringBordersToTileBounds(
-                     gfx::Rect(100, 100, 100, 100)));
-  EXPECT_RECT_EQ(gfx::Rect(),
-                 empty_max_texture_size.ExpandRectIgnoringBordersToTileBounds(
-                     gfx::Rect(100, 100)));
+  EXPECT_EQ(gfx::Rect(),
+            empty_max_texture_size.ExpandRectIgnoringBordersToTileBounds(
+                gfx::Rect()));
+  EXPECT_EQ(gfx::Rect(),
+            empty_max_texture_size.ExpandRectIgnoringBordersToTileBounds(
+                gfx::Rect(100, 100, 100, 100)));
+  EXPECT_EQ(gfx::Rect(),
+            empty_max_texture_size.ExpandRectIgnoringBordersToTileBounds(
+                gfx::Rect(100, 100)));
 }
 
 TEST(TilingDataTest, ExpandRectIgnoringBordersToTileBounds) {
@@ -804,8 +801,8 @@
   gfx::Rect at_origin_src(1, 1);
   gfx::Rect at_origin_result(data.TileBounds(0, 0));
   EXPECT_NE(at_origin_src, at_origin_result);
-  EXPECT_RECT_EQ(at_origin_result,
-                 data.ExpandRectIgnoringBordersToTileBounds(at_origin_src));
+  EXPECT_EQ(at_origin_result,
+            data.ExpandRectIgnoringBordersToTileBounds(at_origin_src));
 
   // Arbitrary internal rect.
   gfx::Rect rect_src(6, 6, 1, 3);
@@ -814,32 +811,30 @@
   gfx::Rect rect_result(
       gfx::UnionRects(data.TileBounds(2, 2), data.TileBounds(2, 3)));
   EXPECT_NE(rect_src, rect_result);
-  EXPECT_RECT_EQ(rect_result,
-                 data.ExpandRectIgnoringBordersToTileBounds(rect_src));
+  EXPECT_EQ(rect_result, data.ExpandRectIgnoringBordersToTileBounds(rect_src));
 
   // On tile bounds does not round up to next tile (ignores the border).
   gfx::Rect border_rect_src(
       gfx::UnionRects(data.TileBounds(1, 2), data.TileBounds(3, 4)));
   gfx::Rect border_rect_result(
       gfx::UnionRects(data.TileBounds(1, 2), data.TileBounds(3, 4)));
-  EXPECT_RECT_EQ(border_rect_result,
-                 data.ExpandRectIgnoringBordersToTileBounds(border_rect_src));
+  EXPECT_EQ(border_rect_result,
+            data.ExpandRectIgnoringBordersToTileBounds(border_rect_src));
 
   // Equal to tiling rect.
-  EXPECT_RECT_EQ(gfx::Rect(data.tiling_size()),
-                 data.ExpandRectIgnoringBordersToTileBounds(
-                     gfx::Rect(data.tiling_size())));
+  EXPECT_EQ(gfx::Rect(data.tiling_size()),
+            data.ExpandRectIgnoringBordersToTileBounds(
+                gfx::Rect(data.tiling_size())));
 
   // Containing, but larger than tiling rect.
-  EXPECT_RECT_EQ(
-      gfx::Rect(data.tiling_size()),
-      data.ExpandRectIgnoringBordersToTileBounds(gfx::Rect(100, 100)));
+  EXPECT_EQ(gfx::Rect(data.tiling_size()),
+            data.ExpandRectIgnoringBordersToTileBounds(gfx::Rect(100, 100)));
 
   // Non-intersecting with tiling rect.
   gfx::Rect non_intersect(200, 200, 100, 100);
   EXPECT_FALSE(non_intersect.Intersects(gfx::Rect(data.tiling_size())));
-  EXPECT_RECT_EQ(gfx::Rect(),
-                 data.ExpandRectIgnoringBordersToTileBounds(non_intersect));
+  EXPECT_EQ(gfx::Rect(),
+            data.ExpandRectIgnoringBordersToTileBounds(non_intersect));
 
   TilingData data2(gfx::Size(8, 8), gfx::Size(32, 64), true);
 
@@ -859,7 +854,7 @@
   gfx::Rect at_origin_src(1, 1);
   gfx::Rect at_origin_result(data.TileBounds(0, 0));
   EXPECT_NE(at_origin_src, at_origin_result);
-  EXPECT_RECT_EQ(at_origin_result, data.ExpandRectToTileBounds(at_origin_src));
+  EXPECT_EQ(at_origin_result, data.ExpandRectToTileBounds(at_origin_src));
 
   // Arbitrary internal rect.
   gfx::Rect rect_src(6, 6, 1, 3);
@@ -868,28 +863,27 @@
   gfx::Rect rect_result(
       gfx::UnionRects(data.TileBounds(2, 2), data.TileBounds(3, 4)));
   EXPECT_NE(rect_src, rect_result);
-  EXPECT_RECT_EQ(rect_result, data.ExpandRectToTileBounds(rect_src));
+  EXPECT_EQ(rect_result, data.ExpandRectToTileBounds(rect_src));
 
   // On tile bounds rounds up to next tile (since border overlaps).
   gfx::Rect border_rect_src(
       gfx::UnionRects(data.TileBounds(1, 2), data.TileBounds(3, 4)));
   gfx::Rect border_rect_result(
       gfx::UnionRects(data.TileBounds(0, 1), data.TileBounds(4, 5)));
-  EXPECT_RECT_EQ(border_rect_result,
-                 data.ExpandRectToTileBounds(border_rect_src));
+  EXPECT_EQ(border_rect_result, data.ExpandRectToTileBounds(border_rect_src));
 
   // Equal to tiling rect.
-  EXPECT_RECT_EQ(gfx::Rect(data.tiling_size()),
-                 data.ExpandRectToTileBounds(gfx::Rect(data.tiling_size())));
+  EXPECT_EQ(gfx::Rect(data.tiling_size()),
+            data.ExpandRectToTileBounds(gfx::Rect(data.tiling_size())));
 
   // Containing, but larger than tiling rect.
-  EXPECT_RECT_EQ(gfx::Rect(data.tiling_size()),
-                 data.ExpandRectToTileBounds(gfx::Rect(100, 100)));
+  EXPECT_EQ(gfx::Rect(data.tiling_size()),
+            data.ExpandRectToTileBounds(gfx::Rect(100, 100)));
 
   // Non-intersecting with tiling rect.
   gfx::Rect non_intersect(200, 200, 100, 100);
   EXPECT_FALSE(non_intersect.Intersects(gfx::Rect(data.tiling_size())));
-  EXPECT_RECT_EQ(gfx::Rect(), data.ExpandRectToTileBounds(non_intersect));
+  EXPECT_EQ(gfx::Rect(), data.ExpandRectToTileBounds(non_intersect));
 
   TilingData data2(gfx::Size(8, 8), gfx::Size(32, 64), true);
 
@@ -953,17 +947,17 @@
   EXPECT_EQ(35, data.TileSizeY(4));
   EXPECT_EQ(5, data.num_tiles_y());
 
-  EXPECT_RECT_EQ(gfx::Rect(70, 50), data.TileBounds(0, 0));
-  EXPECT_RECT_EQ(gfx::Rect(70, 50, 40, 20), data.TileBounds(1, 1));
-  EXPECT_RECT_EQ(gfx::Rect(110, 110, 40, 35), data.TileBounds(2, 4));
-  EXPECT_RECT_EQ(gfx::Rect(150, 70, 50, 20), data.TileBounds(3, 2));
-  EXPECT_RECT_EQ(gfx::Rect(150, 110, 50, 35), data.TileBounds(3, 4));
+  EXPECT_EQ(gfx::Rect(70, 50), data.TileBounds(0, 0));
+  EXPECT_EQ(gfx::Rect(70, 50, 40, 20), data.TileBounds(1, 1));
+  EXPECT_EQ(gfx::Rect(110, 110, 40, 35), data.TileBounds(2, 4));
+  EXPECT_EQ(gfx::Rect(150, 70, 50, 20), data.TileBounds(3, 2));
+  EXPECT_EQ(gfx::Rect(150, 110, 50, 35), data.TileBounds(3, 4));
 
-  EXPECT_RECT_EQ(gfx::Rect(100, 80), data.TileBoundsWithBorder(0, 0));
-  EXPECT_RECT_EQ(gfx::Rect(40, 20, 100, 80), data.TileBoundsWithBorder(1, 1));
-  EXPECT_RECT_EQ(gfx::Rect(80, 80, 100, 65), data.TileBoundsWithBorder(2, 4));
-  EXPECT_RECT_EQ(gfx::Rect(120, 40, 80, 80), data.TileBoundsWithBorder(3, 2));
-  EXPECT_RECT_EQ(gfx::Rect(120, 80, 80, 65), data.TileBoundsWithBorder(3, 4));
+  EXPECT_EQ(gfx::Rect(100, 80), data.TileBoundsWithBorder(0, 0));
+  EXPECT_EQ(gfx::Rect(40, 20, 100, 80), data.TileBoundsWithBorder(1, 1));
+  EXPECT_EQ(gfx::Rect(80, 80, 100, 65), data.TileBoundsWithBorder(2, 4));
+  EXPECT_EQ(gfx::Rect(120, 40, 80, 80), data.TileBoundsWithBorder(3, 2));
+  EXPECT_EQ(gfx::Rect(120, 80, 80, 65), data.TileBoundsWithBorder(3, 4));
 
   EXPECT_EQ(0, data.TileXIndexFromSrcCoord(0));
   EXPECT_EQ(0, data.TileXIndexFromSrcCoord(69));
diff --git a/cc/blink/BUILD.gn b/cc/blink/BUILD.gn
index 138be59..f95291a 100644
--- a/cc/blink/BUILD.gn
+++ b/cc/blink/BUILD.gn
@@ -6,21 +6,6 @@
 component("blink") {
   output_name = "cc_blink"
 
-  public_deps = [
-    "//skia",
-  ]
-  deps = [
-    "//base",
-    "//base/third_party/dynamic_annotations",
-    "//cc",
-    "//gpu",
-    "//third_party/WebKit/public:blink",
-    "//ui/gfx",
-    "//ui/gfx/geometry",
-  ]
-
-  defines = [ "CC_BLINK_IMPLEMENTATION" ]
-
   sources = [
     "cc_blink_export.h",
     "scrollbar_impl.cc",
@@ -64,12 +49,34 @@
     "web_transform_operations_impl.cc",
     "web_transform_operations_impl.h",
   ]
+
+  defines = [ "CC_BLINK_IMPLEMENTATION" ]
+
+  public_deps = [
+    "//skia",
+  ]
+
+  deps = [
+    "//base",
+    "//base/third_party/dynamic_annotations",
+    "//cc",
+    "//gpu",
+    "//third_party/WebKit/public:blink",
+    "//ui/gfx",
+    "//ui/gfx/geometry",
+  ]
 }
 
 # GYP version: //cc/blink/cc_blink_tests.gyp:cc_blink_unittests
 # TODO(GYP): make linking work on the mac.
 if (!is_mac) {
   test("cc_blink_unittests") {
+    sources = [
+      "web_animation_unittest.cc",
+      "web_float_animation_curve_unittest.cc",
+      "web_layer_impl_fixed_bounds_unittest.cc",
+    ]
+
     deps = [
       ":blink",
       "//base/test:run_all_unittests",
@@ -81,11 +88,5 @@
       "//cc",
       "//cc:test_support",
     ]
-
-    sources = [
-      "web_animation_unittest.cc",
-      "web_float_animation_curve_unittest.cc",
-      "web_layer_impl_fixed_bounds_unittest.cc",
-    ]
   }
 }
diff --git a/cc/blink/web_layer_impl_fixed_bounds_unittest.cc b/cc/blink/web_layer_impl_fixed_bounds_unittest.cc
index ceeb311..083b0cf 100644
--- a/cc/blink/web_layer_impl_fixed_bounds_unittest.cc
+++ b/cc/blink/web_layer_impl_fixed_bounds_unittest.cc
@@ -53,9 +53,8 @@
       original_point.y() * bounds.height / fixed_bounds.height(),
       original_point.z());
   // Test if the bounds scale is correctly applied in transform.
-  EXPECT_POINT3F_EQ(
-      scaled_point,
-      TransformPoint(layer->layer()->transform(), original_point));
+  EXPECT_EQ(scaled_point,
+            TransformPoint(layer->layer()->transform(), original_point));
 }
 
 TEST(WebLayerImplFixedBoundsTest, BoundsScaleSimple) {
diff --git a/cc/cc.gyp b/cc/cc.gyp
index 732bc0d..5967098 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -472,6 +472,8 @@
         'resources/tile_priority.h',
         'resources/tiling_set_eviction_queue.cc',
         'resources/tiling_set_eviction_queue.h',
+        'resources/tiling_set_raster_queue.cc',
+        'resources/tiling_set_raster_queue.h',
         'resources/transferable_resource.cc',
         'resources/transferable_resource.h',
         'resources/transform_display_item.cc',
diff --git a/cc/input/scroll_elasticity_helper.cc b/cc/input/scroll_elasticity_helper.cc
index 54da888..6a38e4b 100644
--- a/cc/input/scroll_elasticity_helper.cc
+++ b/cc/input/scroll_elasticity_helper.cc
@@ -32,6 +32,7 @@
 }
 
 gfx::Vector2dF ScrollElasticityHelper::StretchAmount() {
+  // TODO(ccameron): Use the value of active_tree->elastic_overscroll directly
   return stretch_offset_;
 }
 
@@ -63,7 +64,7 @@
 
 gfx::Vector2dF ScrollElasticityHelper::AbsoluteScrollPosition() {
   // TODO(ccameron): This is function is redundant and may be removed.
-  return stretch_offset_;
+  return StretchAmount();
 }
 
 void ScrollElasticityHelper::ImmediateScrollBy(const gfx::Vector2dF& scroll) {
@@ -73,9 +74,14 @@
 void ScrollElasticityHelper::ImmediateScrollByWithoutContentEdgeConstraints(
     const gfx::Vector2dF& scroll) {
   stretch_offset_ += scroll;
-
-  // TODO(ccameron): Update the transform of the appropriate layer in the
-  // LayerTreeHostImpl, and request that a frame be drawn.
+  // TODO(ccameron): Use the value of active_tree->elastic_overscroll directly
+  // Note that this assumes that this property's true value is ever changed
+  // by the impl thread. While this is true, it is redundant state.
+  layer_tree_host_impl_->active_tree()->elastic_overscroll()->SetCurrent(
+      -stretch_offset_);
+  layer_tree_host_impl_->active_tree()->set_needs_update_draw_properties();
+  layer_tree_host_impl_->SetNeedsCommit();
+  layer_tree_host_impl_->SetNeedsRedraw();
 }
 
 void ScrollElasticityHelper::StartSnapRubberbandTimer() {
diff --git a/cc/input/top_controls_manager_unittest.cc b/cc/input/top_controls_manager_unittest.cc
index a209012..0be40ca 100644
--- a/cc/input/top_controls_manager_unittest.cc
+++ b/cc/input/top_controls_manager_unittest.cc
@@ -32,7 +32,8 @@
         top_controls_show_threshold_(top_controls_show_threshold),
         top_controls_hide_threshold_(top_controls_hide_threshold) {
     active_tree_ =
-        LayerTreeImpl::create(&host_impl_, new SyncedProperty<ScaleGroup>);
+        LayerTreeImpl::create(&host_impl_, new SyncedProperty<ScaleGroup>,
+                              new SyncedElasticOverscroll);
     root_scroll_layer_ = LayerImpl::Create(active_tree_.get(), 1);
   }
 
diff --git a/cc/layers/nine_patch_layer_impl_unittest.cc b/cc/layers/nine_patch_layer_impl_unittest.cc
index f6262d3..c901a97 100644
--- a/cc/layers/nine_patch_layer_impl_unittest.cc
+++ b/cc/layers/nine_patch_layer_impl_unittest.cc
@@ -80,7 +80,7 @@
   // Check if the left-over quad is the same size as the mapped aperture quad in
   // layer space.
   if (!fill_center) {
-    EXPECT_RECT_EQ(expected_remaining, gfx::ToEnclosedRect(remaining.bounds()));
+    EXPECT_EQ(expected_remaining, gfx::ToEnclosedRect(remaining.bounds()));
   } else {
     EXPECT_TRUE(remaining.bounds().IsEmpty());
   }
@@ -97,7 +97,7 @@
   }
 
   if (!fill_center) {
-    EXPECT_RECT_EQ(aperture_rect, tex_remaining.bounds());
+    EXPECT_EQ(aperture_rect, tex_remaining.bounds());
     Region aperture_region(aperture_rect);
     EXPECT_EQ(aperture_region, tex_remaining);
   } else {
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index eb90e95..6ec1f0a 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -106,6 +106,14 @@
       new TilingSetEvictionQueue(tilings_.get(), tree_priority));
 }
 
+scoped_ptr<TilingSetRasterQueue> PictureLayerImpl::CreateRasterQueue(
+    bool prioritize_low_res) {
+  if (!tilings_)
+    return make_scoped_ptr(new TilingSetRasterQueue());
+  return make_scoped_ptr(
+      new TilingSetRasterQueue(tilings_.get(), prioritize_low_res));
+}
+
 const char* PictureLayerImpl::LayerTypeAsString() const {
   return "cc::PictureLayerImpl";
 }
@@ -1368,123 +1376,4 @@
       &PictureLayerTiling::IsTileRequiredForDrawIfVisible);
 }
 
-PictureLayerImpl::LayerRasterTileIterator::LayerRasterTileIterator()
-    : layer_(nullptr), current_stage_(arraysize(stages_)) {
-}
-
-PictureLayerImpl::LayerRasterTileIterator::LayerRasterTileIterator(
-    PictureLayerImpl* layer,
-    bool prioritize_low_res)
-    : layer_(layer), current_stage_(0) {
-  DCHECK(layer_);
-
-  // Early out if the layer has no tilings.
-  if (!layer_->tilings_ || !layer_->tilings_->num_tilings()) {
-    current_stage_ = arraysize(stages_);
-    return;
-  }
-
-  // Tiles without valid priority are treated as having lowest priority and
-  // never considered for raster.
-  if (!layer_->HasValidTilePriorities()) {
-    current_stage_ = arraysize(stages_);
-    return;
-  }
-
-  // Find high and low res tilings and initialize the iterators.
-  for (size_t i = 0; i < layer_->tilings_->num_tilings(); ++i) {
-    PictureLayerTiling* tiling = layer_->tilings_->tiling_at(i);
-    if (tiling->resolution() == HIGH_RESOLUTION) {
-      iterators_[HIGH_RES] =
-          PictureLayerTiling::TilingRasterTileIterator(tiling);
-    }
-
-    if (prioritize_low_res && tiling->resolution() == LOW_RESOLUTION) {
-      iterators_[LOW_RES] =
-          PictureLayerTiling::TilingRasterTileIterator(tiling);
-    }
-  }
-
-  if (prioritize_low_res) {
-    stages_[0].iterator_type = LOW_RES;
-    stages_[0].tile_type = TilePriority::NOW;
-
-    stages_[1].iterator_type = HIGH_RES;
-    stages_[1].tile_type = TilePriority::NOW;
-  } else {
-    stages_[0].iterator_type = HIGH_RES;
-    stages_[0].tile_type = TilePriority::NOW;
-
-    stages_[1].iterator_type = LOW_RES;
-    stages_[1].tile_type = TilePriority::NOW;
-  }
-
-  stages_[2].iterator_type = HIGH_RES;
-  stages_[2].tile_type = TilePriority::SOON;
-
-  stages_[3].iterator_type = HIGH_RES;
-  stages_[3].tile_type = TilePriority::EVENTUALLY;
-
-  IteratorType index = stages_[current_stage_].iterator_type;
-  TilePriority::PriorityBin tile_type = stages_[current_stage_].tile_type;
-  if (!iterators_[index] || iterators_[index].get_type() != tile_type)
-    AdvanceToNextStage();
-}
-
-PictureLayerImpl::LayerRasterTileIterator::~LayerRasterTileIterator() {}
-
-PictureLayerImpl::LayerRasterTileIterator::operator bool() const {
-  return current_stage_ < arraysize(stages_);
-}
-
-PictureLayerImpl::LayerRasterTileIterator&
-PictureLayerImpl::LayerRasterTileIterator::
-operator++() {
-  IteratorType index = stages_[current_stage_].iterator_type;
-  TilePriority::PriorityBin tile_type = stages_[current_stage_].tile_type;
-
-  // First advance the iterator.
-  DCHECK(iterators_[index]);
-  DCHECK(iterators_[index].get_type() == tile_type);
-  ++iterators_[index];
-
-  if (!iterators_[index] || iterators_[index].get_type() != tile_type)
-    AdvanceToNextStage();
-
-  return *this;
-}
-
-Tile* PictureLayerImpl::LayerRasterTileIterator::operator*() {
-  DCHECK(*this);
-
-  IteratorType index = stages_[current_stage_].iterator_type;
-  DCHECK(iterators_[index]);
-  DCHECK(iterators_[index].get_type() == stages_[current_stage_].tile_type);
-
-  return *iterators_[index];
-}
-
-const Tile* PictureLayerImpl::LayerRasterTileIterator::operator*() const {
-  DCHECK(*this);
-
-  IteratorType index = stages_[current_stage_].iterator_type;
-  DCHECK(iterators_[index]);
-  DCHECK(iterators_[index].get_type() == stages_[current_stage_].tile_type);
-
-  return *iterators_[index];
-}
-
-void PictureLayerImpl::LayerRasterTileIterator::AdvanceToNextStage() {
-  DCHECK_LT(current_stage_, arraysize(stages_));
-  ++current_stage_;
-  while (current_stage_ < arraysize(stages_)) {
-    IteratorType index = stages_[current_stage_].iterator_type;
-    TilePriority::PriorityBin tile_type = stages_[current_stage_].tile_type;
-
-    if (iterators_[index] && iterators_[index].get_type() == tile_type)
-      break;
-    ++current_stage_;
-  }
-}
-
 }  // namespace cc
diff --git a/cc/layers/picture_layer_impl.h b/cc/layers/picture_layer_impl.h
index 52d8433..ddf928b 100644
--- a/cc/layers/picture_layer_impl.h
+++ b/cc/layers/picture_layer_impl.h
@@ -16,6 +16,7 @@
 #include "cc/resources/picture_layer_tiling_set.h"
 #include "cc/resources/picture_pile_impl.h"
 #include "cc/resources/tiling_set_eviction_queue.h"
+#include "cc/resources/tiling_set_raster_queue.h"
 #include "skia/ext/refptr.h"
 #include "third_party/skia/include/core/SkPicture.h"
 
@@ -38,36 +39,6 @@
     PictureLayerImpl* pending;
   };
 
-  class CC_EXPORT LayerRasterTileIterator {
-   public:
-    LayerRasterTileIterator();
-    LayerRasterTileIterator(PictureLayerImpl* layer, bool prioritize_low_res);
-    ~LayerRasterTileIterator();
-
-    Tile* operator*();
-    const Tile* operator*() const;
-    LayerRasterTileIterator& operator++();
-    operator bool() const;
-
-   private:
-    enum IteratorType { LOW_RES, HIGH_RES, NUM_ITERATORS };
-
-    void AdvanceToNextStage();
-
-    PictureLayerImpl* layer_;
-
-    struct IterationStage {
-      IteratorType iterator_type;
-      TilePriority::PriorityBin tile_type;
-    };
-
-    size_t current_stage_;
-
-    // One low res stage, and three high res stages.
-    IterationStage stages_[4];
-    PictureLayerTiling::TilingRasterTileIterator iterators_[NUM_ITERATORS];
-  };
-
   static scoped_ptr<PictureLayerImpl> Create(LayerTreeImpl* tree_impl, int id) {
     return make_scoped_ptr(new PictureLayerImpl(tree_impl, id));
   }
@@ -75,6 +46,7 @@
 
   scoped_ptr<TilingSetEvictionQueue> CreateEvictionQueue(
       TreePriority tree_priority);
+  scoped_ptr<TilingSetRasterQueue> CreateRasterQueue(bool prioritize_low_res);
 
   // LayerImpl overrides.
   const char* LayerTypeAsString() const override;
diff --git a/cc/layers/picture_layer_impl_perftest.cc b/cc/layers/picture_layer_impl_perftest.cc
index bfb5703..074467f 100644
--- a/cc/layers/picture_layer_impl_perftest.cc
+++ b/cc/layers/picture_layer_impl_perftest.cc
@@ -67,21 +67,21 @@
     pending_layer_->DoPostCommitInitializationIfNeeded();
   }
 
-  void RunRasterIteratorConstructAndIterateTest(
-      const std::string& test_name,
-      int num_tiles,
-      const gfx::Size& viewport_size) {
+  void RunRasterQueueConstructAndIterateTest(const std::string& test_name,
+                                             int num_tiles,
+                                             const gfx::Size& viewport_size) {
     host_impl_.SetViewportSize(viewport_size);
     host_impl_.pending_tree()->UpdateDrawProperties();
 
     timer_.Reset();
     do {
       int count = num_tiles;
-      PictureLayerImpl::LayerRasterTileIterator it(pending_layer_, false);
+      scoped_ptr<TilingSetRasterQueue> queue =
+          pending_layer_->CreateRasterQueue(false);
       while (count--) {
-        ASSERT_TRUE(it) << "count: " << count;
-        ASSERT_TRUE(*it != nullptr) << "count: " << count;
-        ++it;
+        ASSERT_TRUE(!queue->IsEmpty()) << "count: " << count;
+        ASSERT_TRUE(queue->Top() != nullptr) << "count: " << count;
+        queue->Pop();
       }
       timer_.NextLap();
     } while (!timer_.HasTimeLimitExpired());
@@ -94,8 +94,8 @@
                            true);
   }
 
-  void RunRasterIteratorConstructTest(const std::string& test_name,
-                                      const gfx::Rect& viewport) {
+  void RunRasterQueueConstructTest(const std::string& test_name,
+                                   const gfx::Rect& viewport) {
     host_impl_.SetViewportSize(viewport.size());
     pending_layer_->SetScrollOffset(
         gfx::ScrollOffset(viewport.x(), viewport.y()));
@@ -103,7 +103,8 @@
 
     timer_.Reset();
     do {
-      PictureLayerImpl::LayerRasterTileIterator it(pending_layer_, false);
+      scoped_ptr<TilingSetRasterQueue> queue =
+          pending_layer_->CreateRasterQueue(false);
       timer_.NextLap();
     } while (!timer_.HasTimeLimitExpired());
 
@@ -186,6 +187,7 @@
   DISALLOW_COPY_AND_ASSIGN(PictureLayerImplPerfTest);
 };
 
+// TODO(vmpstr): Rename these tests once the perf numbers are in.
 TEST_F(PictureLayerImplPerfTest, LayerRasterTileIteratorConstructAndIterate) {
   SetupPendingTree(gfx::Size(10000, 10000), gfx::Size(256, 256));
 
@@ -197,16 +199,13 @@
   pending_layer_->AddTiling(1.0f);
   pending_layer_->AddTiling(2.0f);
 
-  RunRasterIteratorConstructAndIterateTest(
-      "32_100x100", 32, gfx::Size(100, 100));
-  RunRasterIteratorConstructAndIterateTest(
-      "32_500x500", 32, gfx::Size(500, 500));
-  RunRasterIteratorConstructAndIterateTest(
-      "64_100x100", 64, gfx::Size(100, 100));
-  RunRasterIteratorConstructAndIterateTest(
-      "64_500x500", 64, gfx::Size(500, 500));
+  RunRasterQueueConstructAndIterateTest("32_100x100", 32, gfx::Size(100, 100));
+  RunRasterQueueConstructAndIterateTest("32_500x500", 32, gfx::Size(500, 500));
+  RunRasterQueueConstructAndIterateTest("64_100x100", 64, gfx::Size(100, 100));
+  RunRasterQueueConstructAndIterateTest("64_500x500", 64, gfx::Size(500, 500));
 }
 
+// TODO(vmpstr): Rename these tests once the perf numbers are in.
 TEST_F(PictureLayerImplPerfTest, LayerRasterTileIteratorConstruct) {
   SetupPendingTree(gfx::Size(10000, 10000), gfx::Size(256, 256));
 
@@ -218,11 +217,9 @@
   pending_layer_->AddTiling(1.0f);
   pending_layer_->AddTiling(2.0f);
 
-  RunRasterIteratorConstructTest("0_0_100x100", gfx::Rect(0, 0, 100, 100));
-  RunRasterIteratorConstructTest("5000_0_100x100",
-                                 gfx::Rect(5000, 0, 100, 100));
-  RunRasterIteratorConstructTest("9999_0_100x100",
-                                 gfx::Rect(9999, 0, 100, 100));
+  RunRasterQueueConstructTest("0_0_100x100", gfx::Rect(0, 0, 100, 100));
+  RunRasterQueueConstructTest("5000_0_100x100", gfx::Rect(5000, 0, 100, 100));
+  RunRasterQueueConstructTest("9999_0_100x100", gfx::Rect(9999, 0, 100, 100));
 }
 
 // TODO(e_hakkinen): Rename these tests once the perf numbers are in.
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index 7c2dbcb..4d3b751 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -2775,7 +2775,7 @@
   EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 4.f);
 }
 
-TEST_F(PictureLayerImplTest, LayerRasterTileIterator) {
+TEST_F(PictureLayerImplTest, TilingSetRasterQueue) {
   base::TimeTicks time_ticks;
   time_ticks += base::TimeDelta::FromMilliseconds(1);
   host_impl_.SetCurrentBeginFrameArgs(
@@ -2793,13 +2793,10 @@
 
   float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
 
-  // Empty iterator
-  PictureLayerImpl::LayerRasterTileIterator it;
-  EXPECT_FALSE(it);
-
   // No tilings.
-  it = PictureLayerImpl::LayerRasterTileIterator(pending_layer_, false);
-  EXPECT_FALSE(it);
+  scoped_ptr<TilingSetRasterQueue> queue =
+      pending_layer_->CreateRasterQueue(false);
+  EXPECT_TRUE(queue->IsEmpty());
 
   pending_layer_->AddTiling(low_res_factor);
   pending_layer_->AddTiling(0.3f);
@@ -2815,10 +2812,9 @@
   size_t non_ideal_tile_count = 0u;
   size_t low_res_tile_count = 0u;
   size_t high_res_tile_count = 0u;
-  for (it = PictureLayerImpl::LayerRasterTileIterator(pending_layer_, false);
-       it;
-       ++it) {
-    Tile* tile = *it;
+  queue = pending_layer_->CreateRasterQueue(false);
+  while (!queue->IsEmpty()) {
+    Tile* tile = queue->Top();
     TilePriority priority = tile->priority(PENDING_TREE);
 
     EXPECT_TRUE(tile);
@@ -2837,6 +2833,7 @@
     high_res_tile_count += priority.resolution == HIGH_RESOLUTION;
 
     unique_tiles.insert(tile);
+    queue->Pop();
   }
 
   EXPECT_TRUE(reached_prepaint);
@@ -2858,10 +2855,9 @@
 
   unique_tiles.clear();
   high_res_tile_count = 0u;
-  for (it = PictureLayerImpl::LayerRasterTileIterator(pending_layer_, false);
-       it;
-       ++it) {
-    Tile* tile = *it;
+  queue = pending_layer_->CreateRasterQueue(false);
+  while (!queue->IsEmpty()) {
+    Tile* tile = queue->Top();
     TilePriority priority = tile->priority(PENDING_TREE);
 
     EXPECT_TRUE(tile);
@@ -2873,6 +2869,7 @@
     high_res_tile_count += priority.resolution == HIGH_RESOLUTION;
 
     unique_tiles.insert(tile);
+    queue->Pop();
   }
 
   EXPECT_EQ(16u, high_res_tile_count);
@@ -2898,9 +2895,9 @@
   non_ideal_tile_count = 0;
   low_res_tile_count = 0;
   high_res_tile_count = 0;
-  for (it = PictureLayerImpl::LayerRasterTileIterator(pending_layer_, true); it;
-       ++it) {
-    Tile* tile = *it;
+  queue = pending_layer_->CreateRasterQueue(true);
+  while (!queue->IsEmpty()) {
+    Tile* tile = queue->Top();
     TilePriority priority = tile->priority(PENDING_TREE);
 
     EXPECT_TRUE(tile);
@@ -2908,6 +2905,7 @@
     non_ideal_tile_count += priority.resolution == NON_IDEAL_RESOLUTION;
     low_res_tile_count += priority.resolution == LOW_RESOLUTION;
     high_res_tile_count += priority.resolution == HIGH_RESOLUTION;
+    queue->Pop();
   }
 
   EXPECT_EQ(0u, non_ideal_tile_count);
@@ -3923,11 +3921,10 @@
 
   // No occlusion.
   int unoccluded_tile_count = 0;
-  for (PictureLayerImpl::LayerRasterTileIterator it =
-           PictureLayerImpl::LayerRasterTileIterator(pending_layer_, false);
-       it;
-       ++it) {
-    Tile* tile = *it;
+  scoped_ptr<TilingSetRasterQueue> queue =
+      pending_layer_->CreateRasterQueue(false);
+  while (!queue->IsEmpty()) {
+    Tile* tile = queue->Top();
 
     // Occluded tiles should not be iterated over.
     EXPECT_FALSE(tile->is_occluded(PENDING_TREE));
@@ -3938,6 +3935,7 @@
         tile->content_rect().Intersects(pending_layer_->visible_content_rect());
     if (tile_is_visible)
       unoccluded_tile_count++;
+    queue->Pop();
   }
   EXPECT_EQ(unoccluded_tile_count, 25);
 
@@ -3956,11 +3954,9 @@
   host_impl_.pending_tree()->UpdateDrawProperties();
 
   unoccluded_tile_count = 0;
-  for (PictureLayerImpl::LayerRasterTileIterator it =
-           PictureLayerImpl::LayerRasterTileIterator(pending_layer_, false);
-       it;
-       ++it) {
-    Tile* tile = *it;
+  queue = pending_layer_->CreateRasterQueue(false);
+  while (!queue->IsEmpty()) {
+    Tile* tile = queue->Top();
 
     EXPECT_FALSE(tile->is_occluded(PENDING_TREE));
 
@@ -3968,6 +3964,7 @@
         tile->content_rect().Intersects(pending_layer_->visible_content_rect());
     if (tile_is_visible)
       unoccluded_tile_count++;
+    queue->Pop();
   }
   EXPECT_EQ(20, unoccluded_tile_count);
 
@@ -3980,11 +3977,9 @@
   host_impl_.pending_tree()->UpdateDrawProperties();
 
   unoccluded_tile_count = 0;
-  for (PictureLayerImpl::LayerRasterTileIterator it =
-           PictureLayerImpl::LayerRasterTileIterator(pending_layer_, false);
-       it;
-       ++it) {
-    Tile* tile = *it;
+  queue = pending_layer_->CreateRasterQueue(false);
+  while (!queue->IsEmpty()) {
+    Tile* tile = queue->Top();
 
     EXPECT_FALSE(tile->is_occluded(PENDING_TREE));
 
@@ -3992,6 +3987,7 @@
         tile->content_rect().Intersects(pending_layer_->visible_content_rect());
     if (tile_is_visible)
       unoccluded_tile_count++;
+    queue->Pop();
   }
   EXPECT_EQ(unoccluded_tile_count, 0);
 }
diff --git a/cc/layers/render_surface_unittest.cc b/cc/layers/render_surface_unittest.cc
index 8175efa..6a3e168 100644
--- a/cc/layers/render_surface_unittest.cc
+++ b/cc/layers/render_surface_unittest.cc
@@ -131,8 +131,7 @@
   EXPECT_EQ(
       40.0,
       shared_quad_state->content_to_target_transform.matrix().getDouble(1, 3));
-  EXPECT_RECT_EQ(content_rect,
-                 gfx::Rect(shared_quad_state->visible_content_rect));
+  EXPECT_EQ(content_rect, gfx::Rect(shared_quad_state->visible_content_rect));
   EXPECT_EQ(1.f, shared_quad_state->opacity);
   EXPECT_EQ(blend_mode, shared_quad_state->blend_mode);
 }
@@ -182,7 +181,7 @@
   RenderPass* pass = pass_sink.RenderPasses()[0];
 
   EXPECT_EQ(RenderPassId(2, 0), pass->id);
-  EXPECT_RECT_EQ(content_rect, pass->output_rect);
+  EXPECT_EQ(content_rect, pass->output_rect);
   EXPECT_EQ(origin, pass->transform_to_root_target);
 }
 
diff --git a/cc/layers/scrollbar_layer_unittest.cc b/cc/layers/scrollbar_layer_unittest.cc
index 8a998f3..09de7d0 100644
--- a/cc/layers/scrollbar_layer_unittest.cc
+++ b/cc/layers/scrollbar_layer_unittest.cc
@@ -352,7 +352,7 @@
     const QuadList& quads = render_pass->quad_list;
     ASSERT_EQ(1u, quads.size());
     EXPECT_EQ(DrawQuad::SOLID_COLOR, quads.front()->material);
-    EXPECT_RECT_EQ(gfx::Rect(6, 0, 39, 3), quads.front()->rect);
+    EXPECT_EQ(gfx::Rect(6, 0, 39, 3), quads.front()->rect);
   }
 
   // Contents scale should scale the draw quad.
@@ -366,7 +366,7 @@
     const QuadList& quads = render_pass->quad_list;
     ASSERT_EQ(1u, quads.size());
     EXPECT_EQ(DrawQuad::SOLID_COLOR, quads.front()->material);
-    EXPECT_RECT_EQ(gfx::Rect(12, 0, 78, 6), quads.front()->rect);
+    EXPECT_EQ(gfx::Rect(12, 0, 78, 6), quads.front()->rect);
   }
   scrollbar_layer_impl->draw_properties().contents_scale_x = 1.f;
   scrollbar_layer_impl->draw_properties().contents_scale_y = 1.f;
@@ -382,7 +382,7 @@
     const QuadList& quads = render_pass->quad_list;
     ASSERT_EQ(1u, quads.size());
     EXPECT_EQ(DrawQuad::SOLID_COLOR, quads.front()->material);
-    EXPECT_RECT_EQ(gfx::Rect(8, 0, 19, 3), quads.front()->rect);
+    EXPECT_EQ(gfx::Rect(8, 0, 19, 3), quads.front()->rect);
   }
 
   // We shouldn't attempt div-by-zero when the maximum is zero.
@@ -396,7 +396,7 @@
     const QuadList& quads = render_pass->quad_list;
     ASSERT_EQ(1u, quads.size());
     EXPECT_EQ(DrawQuad::SOLID_COLOR, quads.front()->material);
-    EXPECT_RECT_EQ(gfx::Rect(1, 0, 19, 3), quads.front()->rect);
+    EXPECT_EQ(gfx::Rect(1, 0, 19, 3), quads.front()->rect);
   }
 }
 
@@ -455,7 +455,7 @@
     const QuadList& quads = render_pass->quad_list;
     ASSERT_EQ(1u, quads.size());
     EXPECT_EQ(DrawQuad::SOLID_COLOR, quads.front()->material);
-    EXPECT_RECT_EQ(gfx::Rect(3, 0, 3, 3), quads.front()->rect);
+    EXPECT_EQ(gfx::Rect(3, 0, 3, 3), quads.front()->rect);
   }
 }
 
@@ -544,10 +544,10 @@
   layers[0]->SetBounds(gfx::Size(100, 3));
   layers[1]->SetBounds(gfx::Size(3, 100));
 
-  EXPECT_RECT_EQ(gfx::RectF(20.f, 0.f, 20.f, 3.f),
-                 horizontal_scrollbar_layer_->ComputeThumbQuadRect());
-  EXPECT_RECT_EQ(gfx::RectF(0.f, 20.f, 3.f, 20.f),
-                 vertical_scrollbar_layer_->ComputeThumbQuadRect());
+  EXPECT_EQ(gfx::RectF(20.f, 0.f, 20.f, 3.f),
+            horizontal_scrollbar_layer_->ComputeThumbQuadRect());
+  EXPECT_EQ(gfx::RectF(0.f, 20.f, 3.f, 20.f),
+            vertical_scrollbar_layer_->ComputeThumbQuadRect());
 
   horizontal_scrollbar_layer_->SetVerticalAdjust(10.f);
   vertical_scrollbar_layer_->SetVerticalAdjust(10.f);
@@ -556,10 +556,10 @@
   // 1.) Moves the horizontal scrollbar down
   // 2.) Increases the vertical scrollbar's effective track length which both
   // increases the thumb's length and its position within the track.
-  EXPECT_RECT_EQ(gfx::Rect(20.f, 10.f, 20.f, 3.f),
-                 horizontal_scrollbar_layer_->ComputeThumbQuadRect());
-  EXPECT_RECT_EQ(gfx::Rect(0.f, 22, 3.f, 22.f),
-                 vertical_scrollbar_layer_->ComputeThumbQuadRect());
+  EXPECT_EQ(gfx::Rect(20.f, 10.f, 20.f, 3.f),
+            horizontal_scrollbar_layer_->ComputeThumbQuadRect());
+  EXPECT_EQ(gfx::Rect(0.f, 22, 3.f, 22.f),
+            vertical_scrollbar_layer_->ComputeThumbQuadRect());
 }
 
 class ScrollbarLayerTestMaxTextureSize : public LayerTreeTest {
diff --git a/cc/layers/tiled_layer_unittest.cc b/cc/layers/tiled_layer_unittest.cc
index 512fa51..a9a1e78 100644
--- a/cc/layers/tiled_layer_unittest.cc
+++ b/cc/layers/tiled_layer_unittest.cc
@@ -1711,7 +1711,7 @@
   layer->Update(queue_.get(), nullptr);
   layer->tracking_layer_painter()->ResetPaintedRect();
 
-  EXPECT_RECT_EQ(gfx::Rect(), layer->tracking_layer_painter()->PaintedRect());
+  EXPECT_EQ(gfx::Rect(), layer->tracking_layer_painter()->PaintedRect());
   UpdateTextures();
 
   // Invalidate the entire layer in content space. When painting, the rect given
@@ -1722,8 +1722,8 @@
   // Rounding leads to an extra pixel.
   gfx::Rect expanded_layer_rect(layer_rect);
   expanded_layer_rect.set_height(32);
-  EXPECT_RECT_EQ(expanded_layer_rect,
-                 layer->tracking_layer_painter()->PaintedRect());
+  EXPECT_EQ(expanded_layer_rect,
+            layer->tracking_layer_painter()->PaintedRect());
 }
 
 TEST_F(TiledLayerTest,
@@ -1750,7 +1750,7 @@
   layer->Update(queue_.get(), nullptr);
   layer->tracking_layer_painter()->ResetPaintedRect();
 
-  EXPECT_RECT_EQ(gfx::Rect(), layer->tracking_layer_painter()->PaintedRect());
+  EXPECT_EQ(gfx::Rect(), layer->tracking_layer_painter()->PaintedRect());
   UpdateTextures();
 
   // Invalidate the entire layer in layer space. When painting, the rect given
@@ -1761,8 +1761,8 @@
   // Rounding leads to an extra pixel.
   gfx::Rect expanded_layer_rect(layer_rect);
   expanded_layer_rect.set_height(32);
-  EXPECT_RECT_EQ(expanded_layer_rect,
-                 layer->tracking_layer_painter()->PaintedRect());
+  EXPECT_EQ(expanded_layer_rect,
+            layer->tracking_layer_painter()->PaintedRect());
 }
 
 }  // namespace
diff --git a/cc/output/overlay_unittest.cc b/cc/output/overlay_unittest.cc
index bb7451d..c98b3e8 100644
--- a/cc/output/overlay_unittest.cc
+++ b/cc/output/overlay_unittest.cc
@@ -205,10 +205,10 @@
     RenderPass* actual = actual_list[i];
 
     EXPECT_EQ(expected->id, actual->id);
-    EXPECT_RECT_EQ(expected->output_rect, actual->output_rect);
+    EXPECT_EQ(expected->output_rect, actual->output_rect);
     EXPECT_EQ(expected->transform_to_root_target,
               actual->transform_to_root_target);
-    EXPECT_RECT_EQ(expected->damage_rect, actual->damage_rect);
+    EXPECT_EQ(expected->damage_rect, actual->damage_rect);
     EXPECT_EQ(expected->has_transparent_background,
               actual->has_transparent_background);
 
diff --git a/cc/quads/draw_polygon_unittest.cc b/cc/quads/draw_polygon_unittest.cc
index 27cfed4..360a014 100644
--- a/cc/quads/draw_polygon_unittest.cc
+++ b/cc/quads/draw_polygon_unittest.cc
@@ -19,16 +19,11 @@
 #define EXPECT_FLOAT_WITHIN_EPSILON_OF(a, b) \
   EXPECT_TRUE(std::abs(a - b) < std::numeric_limits<float>::epsilon());
 
-#define EXPECT_POINT_EQ(point_a, point_b)    \
-  EXPECT_FLOAT_EQ(point_a.x(), point_b.x()); \
-  EXPECT_FLOAT_EQ(point_a.y(), point_b.y()); \
-  EXPECT_FLOAT_EQ(point_a.z(), point_b.z());
-
 static void ValidatePoints(const DrawPolygon& polygon,
                            const std::vector<gfx::Point3F>& points) {
   EXPECT_EQ(polygon.points().size(), points.size());
   for (size_t i = 0; i < points.size(); i++) {
-    EXPECT_POINT_EQ(polygon.points()[i], points[i]);
+    EXPECT_EQ(polygon.points()[i], points[i]);
   }
 }
 
diff --git a/cc/quads/draw_quad_unittest.cc b/cc/quads/draw_quad_unittest.cc
index 95c646b..e65b326 100644
--- a/cc/quads/draw_quad_unittest.cc
+++ b/cc/quads/draw_quad_unittest.cc
@@ -55,9 +55,9 @@
   scoped_ptr<SharedQuadState> copy(new SharedQuadState);
   copy->CopyFrom(state.get());
   EXPECT_EQ(quad_transform, copy->content_to_target_transform);
-  EXPECT_RECT_EQ(visible_content_rect, copy->visible_content_rect);
+  EXPECT_EQ(visible_content_rect, copy->visible_content_rect);
   EXPECT_EQ(opacity, copy->opacity);
-  EXPECT_RECT_EQ(clip_rect, copy->clip_rect);
+  EXPECT_EQ(clip_rect, copy->clip_rect);
   EXPECT_EQ(is_clipped, copy->is_clipped);
   EXPECT_EQ(blend_mode, copy->blend_mode);
 }
@@ -88,9 +88,9 @@
                      DrawQuad* copy,
                      SharedQuadState* copy_shared_state) {
   EXPECT_EQ(quad->material, copy->material);
-  EXPECT_RECT_EQ(quad->rect, copy->rect);
-  EXPECT_RECT_EQ(quad->visible_rect, copy->visible_rect);
-  EXPECT_RECT_EQ(quad->opaque_rect, copy->opaque_rect);
+  EXPECT_EQ(quad->rect, copy->rect);
+  EXPECT_EQ(quad->visible_rect, copy->visible_rect);
+  EXPECT_EQ(quad->opaque_rect, copy->opaque_rect);
   EXPECT_EQ(quad->needs_blending, copy->needs_blending);
   EXPECT_EQ(copy_shared_state, copy->shared_quad_state);
 }
@@ -373,7 +373,7 @@
 
   CREATE_QUAD_2_NEW(CheckerboardDrawQuad, visible_rect, color);
   EXPECT_EQ(DrawQuad::CHECKERBOARD, copy_quad->material);
-  EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
+  EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(color, copy_quad->color);
 
   CREATE_QUAD_1_ALL(CheckerboardDrawQuad, color);
@@ -389,7 +389,7 @@
 
   CREATE_QUAD_3_NEW(DebugBorderDrawQuad, visible_rect, color, width);
   EXPECT_EQ(DrawQuad::DEBUG_BORDER, copy_quad->material);
-  EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
+  EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(color, copy_quad->color);
   EXPECT_EQ(width, copy_quad->width);
 
@@ -414,8 +414,8 @@
                     resource_id,
                     orientation);
   EXPECT_EQ(DrawQuad::IO_SURFACE_CONTENT, copy_quad->material);
-  EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
-  EXPECT_RECT_EQ(opaque_rect, copy_quad->opaque_rect);
+  EXPECT_EQ(visible_rect, copy_quad->visible_rect);
+  EXPECT_EQ(opaque_rect, copy_quad->opaque_rect);
   EXPECT_EQ(size, copy_quad->io_surface_size);
   EXPECT_EQ(resource_id, copy_quad->io_surface_resource_id);
   EXPECT_EQ(orientation, copy_quad->orientation);
@@ -454,7 +454,7 @@
                      background_filters,
                      copied_render_pass_id);
   EXPECT_EQ(DrawQuad::RENDER_PASS, copy_quad->material);
-  EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
+  EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(copied_render_pass_id, copy_quad->render_pass_id);
   EXPECT_EQ(mask_resource_id, copy_quad->mask_resource_id);
   EXPECT_EQ(mask_uv_scale.ToString(), copy_quad->mask_uv_scale.ToString());
@@ -493,7 +493,7 @@
   CREATE_QUAD_3_NEW(
       SolidColorDrawQuad, visible_rect, color, force_anti_aliasing_off);
   EXPECT_EQ(DrawQuad::SOLID_COLOR, copy_quad->material);
-  EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
+  EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(color, copy_quad->color);
   EXPECT_EQ(force_anti_aliasing_off, copy_quad->force_anti_aliasing_off);
 
@@ -513,8 +513,8 @@
   CREATE_QUAD_4_NEW(
       StreamVideoDrawQuad, opaque_rect, visible_rect, resource_id, matrix);
   EXPECT_EQ(DrawQuad::STREAM_VIDEO_CONTENT, copy_quad->material);
-  EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
-  EXPECT_RECT_EQ(opaque_rect, copy_quad->opaque_rect);
+  EXPECT_EQ(visible_rect, copy_quad->visible_rect);
+  EXPECT_EQ(opaque_rect, copy_quad->opaque_rect);
   EXPECT_EQ(resource_id, copy_quad->resource_id);
   EXPECT_EQ(matrix, copy_quad->matrix);
 
@@ -531,7 +531,7 @@
 
   CREATE_QUAD_2_NEW(SurfaceDrawQuad, visible_rect, surface_id);
   EXPECT_EQ(DrawQuad::SURFACE_CONTENT, copy_quad->material);
-  EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
+  EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(surface_id, copy_quad->surface_id);
 
   CREATE_QUAD_1_ALL(SurfaceDrawQuad, surface_id);
@@ -564,8 +564,8 @@
                      flipped,
                      nearest_neighbor);
   EXPECT_EQ(DrawQuad::TEXTURE_CONTENT, copy_quad->material);
-  EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
-  EXPECT_RECT_EQ(opaque_rect, copy_quad->opaque_rect);
+  EXPECT_EQ(visible_rect, copy_quad->visible_rect);
+  EXPECT_EQ(opaque_rect, copy_quad->opaque_rect);
   EXPECT_EQ(resource_id, copy_quad->resource_id);
   EXPECT_EQ(premultiplied_alpha, copy_quad->premultiplied_alpha);
   EXPECT_EQ(uv_top_left, copy_quad->uv_top_left);
@@ -610,8 +610,8 @@
                     texture_size,
                     swizzle_contents);
   EXPECT_EQ(DrawQuad::TILED_CONTENT, copy_quad->material);
-  EXPECT_RECT_EQ(opaque_rect, copy_quad->opaque_rect);
-  EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
+  EXPECT_EQ(opaque_rect, copy_quad->opaque_rect);
+  EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(resource_id, copy_quad->resource_id);
   EXPECT_EQ(tex_coord_rect, copy_quad->tex_coord_rect);
   EXPECT_EQ(texture_size, copy_quad->texture_size);
@@ -650,8 +650,8 @@
                     a_plane_resource_id,
                     color_space);
   EXPECT_EQ(DrawQuad::YUV_VIDEO_CONTENT, copy_quad->material);
-  EXPECT_RECT_EQ(opaque_rect, copy_quad->opaque_rect);
-  EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
+  EXPECT_EQ(opaque_rect, copy_quad->opaque_rect);
+  EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(tex_coord_rect, copy_quad->tex_coord_rect);
   EXPECT_EQ(y_plane_resource_id, copy_quad->y_plane_resource_id);
   EXPECT_EQ(u_plane_resource_id, copy_quad->u_plane_resource_id);
@@ -690,12 +690,12 @@
                     texture_size, texture_format, content_rect, contents_scale,
                     raster_source);
   EXPECT_EQ(DrawQuad::PICTURE_CONTENT, copy_quad->material);
-  EXPECT_RECT_EQ(opaque_rect, copy_quad->opaque_rect);
-  EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
+  EXPECT_EQ(opaque_rect, copy_quad->opaque_rect);
+  EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(tex_coord_rect, copy_quad->tex_coord_rect);
   EXPECT_EQ(texture_size, copy_quad->texture_size);
   EXPECT_EQ(texture_format, copy_quad->texture_format);
-  EXPECT_RECT_EQ(content_rect, copy_quad->content_rect);
+  EXPECT_EQ(content_rect, copy_quad->content_rect);
   EXPECT_EQ(contents_scale, copy_quad->contents_scale);
   EXPECT_EQ(raster_source, copy_quad->raster_source);
 
@@ -706,7 +706,7 @@
   EXPECT_EQ(tex_coord_rect, copy_quad->tex_coord_rect);
   EXPECT_EQ(texture_size, copy_quad->texture_size);
   EXPECT_EQ(texture_format, copy_quad->texture_format);
-  EXPECT_RECT_EQ(content_rect, copy_quad->content_rect);
+  EXPECT_EQ(content_rect, copy_quad->content_rect);
   EXPECT_EQ(contents_scale, copy_quad->contents_scale);
   EXPECT_EQ(raster_source, copy_quad->raster_source);
 }
diff --git a/cc/quads/render_pass_unittest.cc b/cc/quads/render_pass_unittest.cc
index 4c3753f..8775d81 100644
--- a/cc/quads/render_pass_unittest.cc
+++ b/cc/quads/render_pass_unittest.cc
@@ -41,10 +41,10 @@
     RenderPass* actual = actual_list[i];
 
     EXPECT_EQ(expected->id, actual->id);
-    EXPECT_RECT_EQ(expected->output_rect, actual->output_rect);
+    EXPECT_EQ(expected->output_rect, actual->output_rect);
     EXPECT_EQ(expected->transform_to_root_target,
               actual->transform_to_root_target);
-    EXPECT_RECT_EQ(expected->damage_rect, actual->damage_rect);
+    EXPECT_EQ(expected->damage_rect, actual->damage_rect);
     EXPECT_EQ(expected->has_transparent_background,
               actual->has_transparent_background);
 
@@ -99,9 +99,9 @@
 
   scoped_ptr<RenderPass> copy = pass->Copy(new_id);
   EXPECT_EQ(new_id, copy->id);
-  EXPECT_RECT_EQ(pass->output_rect, copy->output_rect);
+  EXPECT_EQ(pass->output_rect, copy->output_rect);
   EXPECT_EQ(pass->transform_to_root_target, copy->transform_to_root_target);
-  EXPECT_RECT_EQ(pass->damage_rect, copy->damage_rect);
+  EXPECT_EQ(pass->damage_rect, copy->damage_rect);
   EXPECT_EQ(pass->has_transparent_background, copy->has_transparent_background);
   EXPECT_EQ(0u, copy->quad_list.size());
 
diff --git a/cc/resources/raster_tile_priority_queue.cc b/cc/resources/raster_tile_priority_queue.cc
index 667d54d..9b7942d 100644
--- a/cc/resources/raster_tile_priority_queue.cc
+++ b/cc/resources/raster_tile_priority_queue.cc
@@ -14,8 +14,8 @@
       : tree_priority_(tree_priority) {}
 
   bool operator()(
-      const RasterTilePriorityQueue::PairedPictureLayerQueue* a,
-      const RasterTilePriorityQueue::PairedPictureLayerQueue* b) const {
+      const RasterTilePriorityQueue::PairedTilingSetQueue* a,
+      const RasterTilePriorityQueue::PairedTilingSetQueue* b) const {
     // Note that in this function, we have to return true if and only if
     // a is strictly lower priority than b. Note that for the sake of
     // completeness, empty queue is considered to have lowest priority.
@@ -23,15 +23,15 @@
       return b->IsEmpty() < a->IsEmpty();
 
     WhichTree a_tree = a->NextTileIteratorTree(tree_priority_);
-    const PictureLayerImpl::LayerRasterTileIterator* a_iterator =
-        a_tree == ACTIVE_TREE ? &a->active_iterator : &a->pending_iterator;
+    const auto* a_queue =
+        a_tree == ACTIVE_TREE ? a->active_queue.get() : a->pending_queue.get();
 
     WhichTree b_tree = b->NextTileIteratorTree(tree_priority_);
-    const PictureLayerImpl::LayerRasterTileIterator* b_iterator =
-        b_tree == ACTIVE_TREE ? &b->active_iterator : &b->pending_iterator;
+    const auto* b_queue =
+        b_tree == ACTIVE_TREE ? b->active_queue.get() : b->pending_queue.get();
 
-    const Tile* a_tile = **a_iterator;
-    const Tile* b_tile = **b_iterator;
+    const Tile* a_tile = a_queue->Top();
+    const Tile* b_tile = b_queue->Top();
 
     const TilePriority& a_priority =
         a_tile->priority_for_tree_priority(tree_priority_);
@@ -80,15 +80,15 @@
   TreePriority tree_priority_;
 };
 
-WhichTree HigherPriorityTree(
-    TreePriority tree_priority,
-    const PictureLayerImpl::LayerRasterTileIterator* active_iterator,
-    const PictureLayerImpl::LayerRasterTileIterator* pending_iterator,
-    const Tile* shared_tile) {
+WhichTree HigherPriorityTree(TreePriority tree_priority,
+                             const TilingSetRasterQueue* active_queue,
+                             const TilingSetRasterQueue* pending_queue,
+                             const Tile* shared_tile) {
   switch (tree_priority) {
     case SMOOTHNESS_TAKES_PRIORITY: {
-      const Tile* active_tile = shared_tile ? shared_tile : **active_iterator;
-      const Tile* pending_tile = shared_tile ? shared_tile : **pending_iterator;
+      const Tile* active_tile = shared_tile ? shared_tile : active_queue->Top();
+      const Tile* pending_tile =
+          shared_tile ? shared_tile : pending_queue->Top();
 
       const TilePriority& active_priority = active_tile->priority(ACTIVE_TREE);
       const TilePriority& pending_priority =
@@ -106,8 +106,9 @@
     case NEW_CONTENT_TAKES_PRIORITY:
       return PENDING_TREE;
     case SAME_PRIORITY_FOR_BOTH_TREES: {
-      const Tile* active_tile = shared_tile ? shared_tile : **active_iterator;
-      const Tile* pending_tile = shared_tile ? shared_tile : **pending_iterator;
+      const Tile* active_tile = shared_tile ? shared_tile : active_queue->Top();
+      const Tile* pending_tile =
+          shared_tile ? shared_tile : pending_queue->Top();
 
       const TilePriority& active_priority = active_tile->priority(ACTIVE_TREE);
       const TilePriority& pending_priority =
@@ -140,7 +141,7 @@
        it != paired_layers.end();
        ++it) {
     paired_queues_.push_back(
-        make_scoped_ptr(new PairedPictureLayerQueue(*it, tree_priority_)));
+        make_scoped_ptr(new PairedTilingSetQueue(*it, tree_priority_)));
   }
   paired_queues_.make_heap(RasterOrderComparator(tree_priority_));
 }
@@ -162,72 +163,70 @@
   DCHECK(!IsEmpty());
 
   paired_queues_.pop_heap(RasterOrderComparator(tree_priority_));
-  PairedPictureLayerQueue* paired_queue = paired_queues_.back();
+  PairedTilingSetQueue* paired_queue = paired_queues_.back();
   paired_queue->Pop(tree_priority_);
   paired_queues_.push_heap(RasterOrderComparator(tree_priority_));
 }
 
-RasterTilePriorityQueue::PairedPictureLayerQueue::PairedPictureLayerQueue() {
+RasterTilePriorityQueue::PairedTilingSetQueue::PairedTilingSetQueue() {
 }
 
-RasterTilePriorityQueue::PairedPictureLayerQueue::PairedPictureLayerQueue(
+RasterTilePriorityQueue::PairedTilingSetQueue::PairedTilingSetQueue(
     const PictureLayerImpl::Pair& layer_pair,
     TreePriority tree_priority)
-    : active_iterator(layer_pair.active
-                          ? PictureLayerImpl::LayerRasterTileIterator(
-                                layer_pair.active,
-                                tree_priority == SMOOTHNESS_TAKES_PRIORITY)
-                          : PictureLayerImpl::LayerRasterTileIterator()),
-      pending_iterator(layer_pair.pending
-                           ? PictureLayerImpl::LayerRasterTileIterator(
-                                 layer_pair.pending,
-                                 tree_priority == SMOOTHNESS_TAKES_PRIORITY)
-                           : PictureLayerImpl::LayerRasterTileIterator()),
-      has_both_layers(layer_pair.active && layer_pair.pending) {
+    : has_both_layers(layer_pair.active && layer_pair.pending) {
+  if (layer_pair.active) {
+    active_queue = layer_pair.active->CreateRasterQueue(
+        tree_priority == SMOOTHNESS_TAKES_PRIORITY);
+  }
+
+  if (layer_pair.pending) {
+    pending_queue = layer_pair.pending->CreateRasterQueue(
+        tree_priority == SMOOTHNESS_TAKES_PRIORITY);
+  }
+
   if (has_both_layers)
     SkipTilesReturnedByTwin(tree_priority);
+
   TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
-                       "PairedPictureLayerQueue::PairedPictureLayerQueue",
-                       TRACE_EVENT_SCOPE_THREAD,
-                       "state",
-                       StateAsValue());
+                       "PairedTilingSetQueue::PairedTilingSetQueue",
+                       TRACE_EVENT_SCOPE_THREAD, "state", StateAsValue());
 }
 
-RasterTilePriorityQueue::PairedPictureLayerQueue::~PairedPictureLayerQueue() {
+RasterTilePriorityQueue::PairedTilingSetQueue::~PairedTilingSetQueue() {
   TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
-                       "PairedPictureLayerQueue::~PairedPictureLayerQueue",
-                       TRACE_EVENT_SCOPE_THREAD,
-                       "state",
-                       StateAsValue());
+                       "PairedTilingSetQueue::~PairedTilingSetQueue",
+                       TRACE_EVENT_SCOPE_THREAD, "state", StateAsValue());
 }
 
-bool RasterTilePriorityQueue::PairedPictureLayerQueue::IsEmpty() const {
-  return !active_iterator && !pending_iterator;
+bool RasterTilePriorityQueue::PairedTilingSetQueue::IsEmpty() const {
+  return (!active_queue || active_queue->IsEmpty()) &&
+         (!pending_queue || pending_queue->IsEmpty());
 }
 
-Tile* RasterTilePriorityQueue::PairedPictureLayerQueue::Top(
+Tile* RasterTilePriorityQueue::PairedTilingSetQueue::Top(
     TreePriority tree_priority) {
   DCHECK(!IsEmpty());
 
   WhichTree next_tree = NextTileIteratorTree(tree_priority);
-  PictureLayerImpl::LayerRasterTileIterator* next_iterator =
-      next_tree == ACTIVE_TREE ? &active_iterator : &pending_iterator;
-  DCHECK(*next_iterator);
-  Tile* tile = **next_iterator;
+  TilingSetRasterQueue* next_queue =
+      next_tree == ACTIVE_TREE ? active_queue.get() : pending_queue.get();
+  DCHECK(next_queue && !next_queue->IsEmpty());
+  Tile* tile = next_queue->Top();
   DCHECK(returned_tiles_for_debug.find(tile) == returned_tiles_for_debug.end());
   return tile;
 }
 
-void RasterTilePriorityQueue::PairedPictureLayerQueue::Pop(
+void RasterTilePriorityQueue::PairedTilingSetQueue::Pop(
     TreePriority tree_priority) {
   DCHECK(!IsEmpty());
 
   WhichTree next_tree = NextTileIteratorTree(tree_priority);
-  PictureLayerImpl::LayerRasterTileIterator* next_iterator =
-      next_tree == ACTIVE_TREE ? &active_iterator : &pending_iterator;
-  DCHECK(*next_iterator);
-  DCHECK(returned_tiles_for_debug.insert(**next_iterator).second);
-  ++(*next_iterator);
+  TilingSetRasterQueue* next_queue =
+      next_tree == ACTIVE_TREE ? active_queue.get() : pending_queue.get();
+  DCHECK(next_queue && !next_queue->IsEmpty());
+  DCHECK(returned_tiles_for_debug.insert(next_queue->Top()).second);
+  next_queue->Pop();
 
   if (has_both_layers)
     SkipTilesReturnedByTwin(tree_priority);
@@ -236,17 +235,18 @@
   DCHECK(IsEmpty() || Top(tree_priority));
 }
 
-void RasterTilePriorityQueue::PairedPictureLayerQueue::SkipTilesReturnedByTwin(
+void RasterTilePriorityQueue::PairedTilingSetQueue::SkipTilesReturnedByTwin(
     TreePriority tree_priority) {
   // We have both layers (active and pending) thus we can encounter shared
   // tiles twice (from the active iterator and from the pending iterator).
   while (!IsEmpty()) {
     WhichTree next_tree = NextTileIteratorTree(tree_priority);
-    PictureLayerImpl::LayerRasterTileIterator* next_iterator =
-        next_tree == ACTIVE_TREE ? &active_iterator : &pending_iterator;
+    TilingSetRasterQueue* next_queue =
+        next_tree == ACTIVE_TREE ? active_queue.get() : pending_queue.get();
+    DCHECK(next_queue && !next_queue->IsEmpty());
 
     // Accept all non-shared tiles.
-    const Tile* tile = **next_iterator;
+    const Tile* tile = next_queue->Top();
     if (!tile->is_shared())
       break;
 
@@ -256,51 +256,58 @@
     if (next_tree == HigherPriorityTree(tree_priority, nullptr, nullptr, tile))
       break;
 
-    ++(*next_iterator);
+    next_queue->Pop();
   }
 }
 
-WhichTree
-RasterTilePriorityQueue::PairedPictureLayerQueue::NextTileIteratorTree(
+WhichTree RasterTilePriorityQueue::PairedTilingSetQueue::NextTileIteratorTree(
     TreePriority tree_priority) const {
   DCHECK(!IsEmpty());
 
-  // If we only have one iterator with tiles, return it.
-  if (!active_iterator)
+  // If we only have one queue with tiles, return it.
+  if (!active_queue || active_queue->IsEmpty())
     return PENDING_TREE;
-  if (!pending_iterator)
+  if (!pending_queue || pending_queue->IsEmpty())
     return ACTIVE_TREE;
 
   // Now both iterators have tiles, so we have to decide based on tree priority.
-  return HigherPriorityTree(
-      tree_priority, &active_iterator, &pending_iterator, nullptr);
+  return HigherPriorityTree(tree_priority, active_queue.get(),
+                            pending_queue.get(), nullptr);
 }
 
 scoped_refptr<base::debug::ConvertableToTraceFormat>
-RasterTilePriorityQueue::PairedPictureLayerQueue::StateAsValue() const {
+RasterTilePriorityQueue::PairedTilingSetQueue::StateAsValue() const {
   scoped_refptr<base::debug::TracedValue> state =
       new base::debug::TracedValue();
-  state->BeginDictionary("active_iterator");
-  TilePriority::PriorityBin active_priority_bin =
-      active_iterator ? (*active_iterator)->priority(ACTIVE_TREE).priority_bin
-                      : TilePriority::EVENTUALLY;
-  TilePriority::PriorityBin pending_priority_bin =
-      active_iterator ? (*active_iterator)->priority(PENDING_TREE).priority_bin
-                      : TilePriority::EVENTUALLY;
-  state->SetBoolean("has_tile", !!active_iterator);
+
+  bool active_queue_has_tile = active_queue && !active_queue->IsEmpty();
+  TilePriority::PriorityBin active_priority_bin = TilePriority::EVENTUALLY;
+  TilePriority::PriorityBin pending_priority_bin = TilePriority::EVENTUALLY;
+  if (active_queue_has_tile) {
+    active_priority_bin =
+        active_queue->Top()->priority(ACTIVE_TREE).priority_bin;
+    pending_priority_bin =
+        active_queue->Top()->priority(PENDING_TREE).priority_bin;
+  }
+
+  state->BeginDictionary("active_queue");
+  state->SetBoolean("has_tile", active_queue_has_tile);
   state->SetInteger("active_priority_bin", active_priority_bin);
   state->SetInteger("pending_priority_bin", pending_priority_bin);
   state->EndDictionary();
 
-  state->BeginDictionary("pending_iterator");
-  active_priority_bin =
-      pending_iterator ? (*pending_iterator)->priority(ACTIVE_TREE).priority_bin
-                       : TilePriority::EVENTUALLY;
-  pending_priority_bin =
-      pending_iterator
-          ? (*pending_iterator)->priority(PENDING_TREE).priority_bin
-          : TilePriority::EVENTUALLY;
-  state->SetBoolean("has_tile", !!pending_iterator);
+  bool pending_queue_has_tile = pending_queue && !pending_queue->IsEmpty();
+  active_priority_bin = TilePriority::EVENTUALLY;
+  pending_priority_bin = TilePriority::EVENTUALLY;
+  if (pending_queue_has_tile) {
+    active_priority_bin =
+        pending_queue->Top()->priority(ACTIVE_TREE).priority_bin;
+    pending_priority_bin =
+        pending_queue->Top()->priority(PENDING_TREE).priority_bin;
+  }
+
+  state->BeginDictionary("pending_queue");
+  state->SetBoolean("has_tile", active_queue_has_tile);
   state->SetInteger("active_priority_bin", active_priority_bin);
   state->SetInteger("pending_priority_bin", pending_priority_bin);
   state->EndDictionary();
diff --git a/cc/resources/raster_tile_priority_queue.h b/cc/resources/raster_tile_priority_queue.h
index 3f04e97..416a57a 100644
--- a/cc/resources/raster_tile_priority_queue.h
+++ b/cc/resources/raster_tile_priority_queue.h
@@ -12,16 +12,17 @@
 #include "cc/base/cc_export.h"
 #include "cc/layers/picture_layer_impl.h"
 #include "cc/resources/tile_priority.h"
+#include "cc/resources/tiling_set_raster_queue.h"
 
 namespace cc {
 
 class CC_EXPORT RasterTilePriorityQueue {
  public:
-  struct PairedPictureLayerQueue {
-    PairedPictureLayerQueue();
-    PairedPictureLayerQueue(const PictureLayerImpl::Pair& layer_pair,
-                            TreePriority tree_priority);
-    ~PairedPictureLayerQueue();
+  struct PairedTilingSetQueue {
+    PairedTilingSetQueue();
+    PairedTilingSetQueue(const PictureLayerImpl::Pair& layer_pair,
+                         TreePriority tree_priority);
+    ~PairedTilingSetQueue();
 
     bool IsEmpty() const;
     Tile* Top(TreePriority tree_priority);
@@ -32,8 +33,8 @@
 
     scoped_refptr<base::debug::ConvertableToTraceFormat> StateAsValue() const;
 
-    PictureLayerImpl::LayerRasterTileIterator active_iterator;
-    PictureLayerImpl::LayerRasterTileIterator pending_iterator;
+    scoped_ptr<TilingSetRasterQueue> active_queue;
+    scoped_ptr<TilingSetRasterQueue> pending_queue;
     bool has_both_layers;
 
     // Set of returned tiles (excluding the current one) for DCHECKing.
@@ -53,9 +54,9 @@
 
  private:
   // TODO(vmpstr): This is potentially unnecessary if it becomes the case that
-  // PairedPictureLayerQueue is fast enough to copy. In that case, we can use
-  // objects directly (ie std::vector<PairedPictureLayerQueue>.
-  ScopedPtrVector<PairedPictureLayerQueue> paired_queues_;
+  // PairedTilingSetQueue is fast enough to copy. In that case, we can use
+  // objects directly (ie std::vector<PairedTilingSetQueue>.
+  ScopedPtrVector<PairedTilingSetQueue> paired_queues_;
   TreePriority tree_priority_;
 
   DISALLOW_COPY_AND_ASSIGN(RasterTilePriorityQueue);
diff --git a/cc/resources/tiling_set_raster_queue.cc b/cc/resources/tiling_set_raster_queue.cc
new file mode 100644
index 0000000..08f7642
--- /dev/null
+++ b/cc/resources/tiling_set_raster_queue.cc
@@ -0,0 +1,117 @@
+// 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 "cc/resources/tiling_set_raster_queue.h"
+
+namespace cc {
+
+TilingSetRasterQueue::TilingSetRasterQueue()
+    : tiling_set_(nullptr), current_stage_(arraysize(stages_)) {
+}
+
+TilingSetRasterQueue::TilingSetRasterQueue(PictureLayerTilingSet* tiling_set,
+                                           bool prioritize_low_res)
+    : tiling_set_(tiling_set), current_stage_(0) {
+  DCHECK(tiling_set_);
+
+  // Early out if the tiling set has no tilings.
+  if (!tiling_set_->num_tilings()) {
+    current_stage_ = arraysize(stages_);
+    return;
+  }
+
+  // Find high and low res tilings and initialize the iterators.
+  for (size_t i = 0; i < tiling_set_->num_tilings(); ++i) {
+    PictureLayerTiling* tiling = tiling_set_->tiling_at(i);
+    if (tiling->resolution() == HIGH_RESOLUTION) {
+      iterators_[HIGH_RES] =
+          PictureLayerTiling::TilingRasterTileIterator(tiling);
+    }
+
+    if (prioritize_low_res && tiling->resolution() == LOW_RESOLUTION) {
+      iterators_[LOW_RES] =
+          PictureLayerTiling::TilingRasterTileIterator(tiling);
+    }
+  }
+
+  if (prioritize_low_res) {
+    stages_[0].iterator_type = LOW_RES;
+    stages_[0].tile_type = TilePriority::NOW;
+
+    stages_[1].iterator_type = HIGH_RES;
+    stages_[1].tile_type = TilePriority::NOW;
+  } else {
+    stages_[0].iterator_type = HIGH_RES;
+    stages_[0].tile_type = TilePriority::NOW;
+
+    stages_[1].iterator_type = LOW_RES;
+    stages_[1].tile_type = TilePriority::NOW;
+  }
+
+  stages_[2].iterator_type = HIGH_RES;
+  stages_[2].tile_type = TilePriority::SOON;
+
+  stages_[3].iterator_type = HIGH_RES;
+  stages_[3].tile_type = TilePriority::EVENTUALLY;
+
+  IteratorType index = stages_[current_stage_].iterator_type;
+  TilePriority::PriorityBin tile_type = stages_[current_stage_].tile_type;
+  if (!iterators_[index] || iterators_[index].get_type() != tile_type)
+    AdvanceToNextStage();
+}
+
+TilingSetRasterQueue::~TilingSetRasterQueue() {
+}
+
+bool TilingSetRasterQueue::IsEmpty() const {
+  return current_stage_ >= arraysize(stages_);
+}
+
+void TilingSetRasterQueue::Pop() {
+  IteratorType index = stages_[current_stage_].iterator_type;
+  TilePriority::PriorityBin tile_type = stages_[current_stage_].tile_type;
+
+  // First advance the iterator.
+  DCHECK(iterators_[index]);
+  DCHECK(iterators_[index].get_type() == tile_type);
+  ++iterators_[index];
+
+  if (!iterators_[index] || iterators_[index].get_type() != tile_type)
+    AdvanceToNextStage();
+}
+
+Tile* TilingSetRasterQueue::Top() {
+  DCHECK(!IsEmpty());
+
+  IteratorType index = stages_[current_stage_].iterator_type;
+  DCHECK(iterators_[index]);
+  DCHECK(iterators_[index].get_type() == stages_[current_stage_].tile_type);
+
+  return *iterators_[index];
+}
+
+const Tile* TilingSetRasterQueue::Top() const {
+  DCHECK(!IsEmpty());
+
+  IteratorType index = stages_[current_stage_].iterator_type;
+  DCHECK(iterators_[index]);
+  DCHECK(iterators_[index].get_type() == stages_[current_stage_].tile_type);
+
+  return *iterators_[index];
+}
+
+void TilingSetRasterQueue::AdvanceToNextStage() {
+  DCHECK_LT(current_stage_, arraysize(stages_));
+  ++current_stage_;
+  while (current_stage_ < arraysize(stages_)) {
+    IteratorType index = stages_[current_stage_].iterator_type;
+    TilePriority::PriorityBin tile_type = stages_[current_stage_].tile_type;
+
+    if (iterators_[index] && iterators_[index].get_type() == tile_type)
+      break;
+    ++current_stage_;
+  }
+}
+
+}  // namespace cc
diff --git a/cc/resources/tiling_set_raster_queue.h b/cc/resources/tiling_set_raster_queue.h
new file mode 100644
index 0000000..58faa8a
--- /dev/null
+++ b/cc/resources/tiling_set_raster_queue.h
@@ -0,0 +1,46 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_RESOURCES_TILING_SET_RASTER_QUEUE_H_
+#define CC_RESOURCES_TILING_SET_RASTER_QUEUE_H_
+
+#include "cc/base/cc_export.h"
+#include "cc/resources/picture_layer_tiling_set.h"
+
+namespace cc {
+
+class CC_EXPORT TilingSetRasterQueue {
+ public:
+  TilingSetRasterQueue();
+  TilingSetRasterQueue(PictureLayerTilingSet* tiling_set,
+                       bool prioritize_low_res);
+  ~TilingSetRasterQueue();
+
+  Tile* Top();
+  const Tile* Top() const;
+  void Pop();
+  bool IsEmpty() const;
+
+ private:
+  enum IteratorType { LOW_RES, HIGH_RES, NUM_ITERATORS };
+
+  void AdvanceToNextStage();
+
+  PictureLayerTilingSet* tiling_set_;
+
+  struct IterationStage {
+    IteratorType iterator_type;
+    TilePriority::PriorityBin tile_type;
+  };
+
+  size_t current_stage_;
+
+  // One low res stage, and three high res stages.
+  IterationStage stages_[4];
+  PictureLayerTiling::TilingRasterTileIterator iterators_[NUM_ITERATORS];
+};
+
+}  // namespace cc
+
+#endif  // CC_RESOURCES_TILING_SET_RASTER_QUEUE_H_
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
index 0cce5dc..5a70ec6 100644
--- a/cc/scheduler/scheduler.cc
+++ b/cc/scheduler/scheduler.cc
@@ -543,9 +543,8 @@
 
   advance_commit_state_task_.Cancel();
 
-  base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate();
   begin_impl_frame_args_ = args;
-  begin_impl_frame_args_.deadline -= draw_duration_estimate;
+  begin_impl_frame_args_.deadline -= client_->DrawDurationEstimate();
 
   if (!state_machine_.impl_latency_takes_priority() &&
       main_thread_is_in_high_latency_mode &&
@@ -569,51 +568,43 @@
     // up the BeginImplFrame and deadline as well.
     OnBeginImplFrameDeadline();
   } else {
-    ScheduleBeginImplFrameDeadline(
-        AdjustedBeginImplFrameDeadline(args, draw_duration_estimate));
+    ScheduleBeginImplFrameDeadline();
   }
 }
 
-base::TimeTicks Scheduler::AdjustedBeginImplFrameDeadline(
-    const BeginFrameArgs& args,
-    base::TimeDelta draw_duration_estimate) const {
+void Scheduler::ScheduleBeginImplFrameDeadline() {
   // The synchronous compositor does not post a deadline task.
   DCHECK(!settings_.using_synchronous_renderer_compositor);
-  if (settings_.main_thread_should_always_be_low_latency) {
-    // In main thread low latency mode, always start deadline early.
-    return base::TimeTicks();
-  } else if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) {
-    // We are ready to draw a new active tree immediately.
-    // We don't use Now() here because it's somewhat expensive to call.
-    return base::TimeTicks();
-  } else if (settings_.main_thread_should_always_be_low_latency) {
-    // Post long deadline to keep advancing during idle period. After activation
-    // we will be able to trigger deadline early.
-    // TODO(weiliangc): Don't post deadline once input is deferred with
-    // BeginRetroFrames.
-    return args.frame_time + args.interval;
-  } else if (state_machine_.needs_redraw()) {
-    // We have an animation or fast input path on the impl thread that wants
-    // to draw, so don't wait too long for a new active tree.
-    return args.deadline - draw_duration_estimate;
-  } else {
-    // The impl thread doesn't have anything it wants to draw and we are just
-    // waiting for a new active tree, so post the deadline for the next
-    // expected BeginImplFrame start. This allows us to draw immediately when
-    // there is a new active tree, instead of waiting for the next
-    // BeginImplFrame.
-    // TODO(brianderson): Handle long deadlines (that are past the next frame's
-    // frame time) properly instead of using this hack.
-    return args.frame_time + args.interval;
-  }
-}
 
-void Scheduler::ScheduleBeginImplFrameDeadline(base::TimeTicks deadline) {
-  TRACE_EVENT1(
-      "cc", "Scheduler::ScheduleBeginImplFrameDeadline", "deadline", deadline);
   begin_impl_frame_deadline_task_.Cancel();
   begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_);
 
+  begin_impl_frame_deadline_mode_ =
+      state_machine_.CurrentBeginImplFrameDeadlineMode();
+
+  base::TimeTicks deadline;
+  switch (begin_impl_frame_deadline_mode_) {
+    case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE:
+      // We are ready to draw a new active tree immediately.
+      // We don't use Now() here because it's somewhat expensive to call.
+      deadline = base::TimeTicks();
+      break;
+    case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR:
+      // We are animating on the impl thread but we can wait for some time.
+      deadline = begin_impl_frame_args_.deadline;
+      break;
+    case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE:
+      // We are blocked for one reason or another and we should wait.
+      // TODO(brianderson): Handle long deadlines (that are past the next
+      // frame's frame time) properly instead of using this hack.
+      deadline =
+          begin_impl_frame_args_.frame_time + begin_impl_frame_args_.interval;
+      break;
+  }
+
+  TRACE_EVENT1(
+      "cc", "Scheduler::ScheduleBeginImplFrameDeadline", "deadline", deadline);
+
   base::TimeDelta delta = deadline - Now();
   if (delta <= base::TimeDelta())
     delta = base::TimeDelta();
@@ -621,6 +612,19 @@
       FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta);
 }
 
+void Scheduler::RescheduleBeginImplFrameDeadlineIfNeeded() {
+  if (settings_.using_synchronous_renderer_compositor)
+    return;
+
+  if (state_machine_.begin_impl_frame_state() !=
+      SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME)
+    return;
+
+  if (begin_impl_frame_deadline_mode_ !=
+      state_machine_.CurrentBeginImplFrameDeadlineMode())
+    ScheduleBeginImplFrameDeadline();
+}
+
 void Scheduler::OnBeginImplFrameDeadline() {
   TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline");
   begin_impl_frame_deadline_task_.Cancel();
@@ -716,10 +720,7 @@
   SetupNextBeginFrameIfNeeded();
   client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime());
 
-  if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) {
-    DCHECK(!settings_.using_synchronous_renderer_compositor);
-    ScheduleBeginImplFrameDeadline(base::TimeTicks());
-  }
+  RescheduleBeginImplFrameDeadlineIfNeeded();
 }
 
 bool Scheduler::WillDrawIfNeeded() const {
diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h
index ef52ccf..1175d73 100644
--- a/cc/scheduler/scheduler.h
+++ b/cc/scheduler/scheduler.h
@@ -205,6 +205,8 @@
   bool begin_retro_frame_posted_;
   std::deque<BeginFrameArgs> begin_retro_frame_args_;
   BeginFrameArgs begin_impl_frame_args_;
+  SchedulerStateMachine::BeginImplFrameDeadlineMode
+      begin_impl_frame_deadline_mode_;
 
   base::Closure begin_retro_frame_closure_;
   base::Closure begin_unthrottled_frame_closure_;
@@ -221,10 +223,8 @@
   SchedulerStateMachine::Action inside_action_;
 
  private:
-  base::TimeTicks AdjustedBeginImplFrameDeadline(
-      const BeginFrameArgs& args,
-      base::TimeDelta draw_duration_estimate) const;
-  void ScheduleBeginImplFrameDeadline(base::TimeTicks deadline);
+  void ScheduleBeginImplFrameDeadline();
+  void RescheduleBeginImplFrameDeadlineIfNeeded();
   void SetupNextBeginFrameIfNeeded();
   void PostBeginRetroFrameIfNeeded();
   void SetupPollingMechanisms(bool needs_begin_frame);
diff --git a/cc/scheduler/scheduler_settings.cc b/cc/scheduler/scheduler_settings.cc
index 53abe7b..6a5cbbc 100644
--- a/cc/scheduler/scheduler_settings.cc
+++ b/cc/scheduler/scheduler_settings.cc
@@ -39,8 +39,7 @@
       throttle_frame_production(settings.throttle_frame_production),
       disable_hi_res_timer_tasks_on_battery(
           settings.disable_hi_res_timer_tasks_on_battery),
-      main_thread_should_always_be_low_latency(
-          settings.main_thread_should_always_be_low_latency),
+      main_thread_should_always_be_low_latency(false),
       background_frame_interval(base::TimeDelta::FromSecondsD(
           1.0 / settings.background_animation_rate)) {
 }
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc
index 2946a2c..8e87c0f 100644
--- a/cc/scheduler/scheduler_state_machine.cc
+++ b/cc/scheduler/scheduler_state_machine.cc
@@ -820,7 +820,25 @@
   begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_IDLE;
 }
 
-bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineEarly() const {
+SchedulerStateMachine::BeginImplFrameDeadlineMode
+SchedulerStateMachine::CurrentBeginImplFrameDeadlineMode() const {
+  if (ShouldTriggerBeginImplFrameDeadlineImmediately()) {
+    return BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE;
+  } else if (needs_redraw_ && pending_swaps_ < max_pending_swaps_) {
+    // We have an animation or fast input path on the impl thread that wants
+    // to draw, so don't wait too long for a new active tree.
+    // If we are swap throttled we should wait until we are unblocked.
+    return BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR;
+  } else {
+    // The impl thread doesn't have anything it wants to draw and we are just
+    // waiting for a new active tree or we are swap throttled. In short we are
+    // blocked.
+    return BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE;
+  }
+}
+
+bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineImmediately()
+    const {
   // TODO(brianderson): This should take into account multiple commit sources.
 
   if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME)
diff --git a/cc/scheduler/scheduler_state_machine.h b/cc/scheduler/scheduler_state_machine.h
index 12f8635..6e30694 100644
--- a/cc/scheduler/scheduler_state_machine.h
+++ b/cc/scheduler/scheduler_state_machine.h
@@ -62,6 +62,14 @@
   };
   static const char* BeginImplFrameStateToString(BeginImplFrameState state);
 
+  enum BeginImplFrameDeadlineMode {
+    BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE,
+    BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR,
+    BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE,
+  };
+  static const char* BeginImplFrameDeadlineModeToString(
+      BeginImplFrameDeadlineMode mode);
+
   enum CommitState {
     COMMIT_STATE_IDLE,
     COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
@@ -128,10 +136,10 @@
   void OnBeginImplFrameDeadlinePending();
   void OnBeginImplFrameDeadline();
   void OnBeginImplFrameIdle();
-  bool ShouldTriggerBeginImplFrameDeadlineEarly() const;
   BeginImplFrameState begin_impl_frame_state() const {
     return begin_impl_frame_state_;
   }
+  BeginImplFrameDeadlineMode CurrentBeginImplFrameDeadlineMode() const;
 
   // If the main thread didn't manage to produce a new frame in time for the
   // impl thread to draw, it is in a high latency mode.
@@ -258,6 +266,8 @@
   bool BeginFrameNeededForChildren() const;
   bool ProactiveBeginFrameWanted() const;
 
+  bool ShouldTriggerBeginImplFrameDeadlineImmediately() const;
+
   // True if we need to force activations to make forward progress.
   bool PendingActivationsShouldBeForced() const;
 
diff --git a/cc/scheduler/scheduler_state_machine_unittest.cc b/cc/scheduler/scheduler_state_machine_unittest.cc
index f46389b..7bbfa37 100644
--- a/cc/scheduler/scheduler_state_machine_unittest.cc
+++ b/cc/scheduler/scheduler_state_machine_unittest.cc
@@ -103,6 +103,8 @@
   void SetHasPendingTree(bool has_pending_tree) {
     has_pending_tree_ = has_pending_tree;
   }
+
+  using SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineImmediately;
 };
 
 TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) {
@@ -232,7 +234,7 @@
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
 
-  EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+  EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
   state.OnBeginImplFrameDeadline();
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
   EXPECT_ACTION_UPDATE_STATE(
@@ -1731,7 +1733,8 @@
   EXPECT_FALSE(state.PendingDrawsShouldBeAborted());
 }
 
-TEST(SchedulerStateMachineTest, TestTriggerDeadlineEarlyAfterAbortedCommit) {
+TEST(SchedulerStateMachineTest,
+     TestTriggerDeadlineImmediatelyAfterAbortedCommit) {
   SchedulerSettings settings;
   settings.impl_side_painting = true;
   StateMachine state(settings);
@@ -1762,7 +1765,7 @@
 
   // Since the commit was aborted, we should draw right away instead of waiting
   // for the deadline.
-  EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+  EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
 }
 
 void FinishPreviousCommitAndDrawWithoutExitingDeadline(
@@ -1782,7 +1785,7 @@
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
 
-  EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+  EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
   state.OnBeginImplFrameDeadline();
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
@@ -1811,9 +1814,9 @@
 
   // Verify the deadline is not triggered early until we enter
   // prefer impl latency mode.
-  EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+  EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
   state.SetImplLatencyTakesPriority(true);
-  EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+  EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
 
   // Trigger the deadline.
   state.OnBeginImplFrameDeadline();
@@ -1842,12 +1845,13 @@
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
   state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
-  EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+  EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
   state.OnBeginImplFrameDeadline();
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
 }
 
-TEST(SchedulerStateMachineTest, TestTriggerDeadlineEarlyOnLostOutputSurface) {
+TEST(SchedulerStateMachineTest,
+     TestTriggerDeadlineImmediatelyOnLostOutputSurface) {
   SchedulerSettings default_scheduler_settings;
   StateMachine state(default_scheduler_settings);
   state.SetCanStart();
@@ -1862,12 +1866,12 @@
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
-  EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+  EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
 
   state.DidLoseOutputSurface();
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
   // The deadline should be triggered immediately when output surface is lost.
-  EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+  EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
 }
 
 TEST(SchedulerStateMachineTest, TestSetNeedsAnimate) {
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc
index 2992dbc..0997049 100644
--- a/cc/scheduler/scheduler_unittest.cc
+++ b/cc/scheduler/scheduler_unittest.cc
@@ -1319,6 +1319,7 @@
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
   scheduler->SetCanDraw(true);
+  scheduler->SetEstimatedParentDrawTime(base::TimeDelta::FromMicroseconds(1));
   InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
 
   // To test swap ack throttling, this test disables automatic swap acks.
@@ -1331,12 +1332,7 @@
   EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
   client.Reset();
 
-  // Create a BeginFrame with a long deadline to avoid race conditions.
-  // This is the first BeginFrame, which will be handled immediately.
-  BeginFrameArgs args =
-      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, client.now_src());
-  args.deadline += base::TimeDelta::FromHours(1);
-  client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
+  client.AdvanceFrame();
   EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
   EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
   EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
@@ -1344,11 +1340,10 @@
   client.Reset();
 
   // Queue BeginFrame while we are still handling the previous BeginFrame.
-  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-  args.frame_time += base::TimeDelta::FromSeconds(1);
-  client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
+  client.SendNextBeginFrame();
   EXPECT_NO_ACTION(client);
   EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_TRUE(client.needs_begin_frames());
   client.Reset();
 
   // NotifyReadyToCommit should trigger the pending commit and draw.
@@ -1359,7 +1354,8 @@
   client.Reset();
 
   // Swapping will put us into a swap throttled state.
-  client.task_runner().RunPendingTasks();  // Run posted deadline.
+  // Run posted deadline.
+  client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(true));
   EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
   EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
   EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
@@ -1369,35 +1365,32 @@
   // While swap throttled, BeginRetroFrames should trigger BeginImplFrames
   // but not a BeginMainFrame or draw.
   scheduler->SetNeedsCommit();
-  client.task_runner().RunPendingTasks();  // Run posted BeginRetroFrame.
-  EXPECT_ACTION("WillBeginImplFrame", client, 0, 1);
+  scheduler->SetNeedsRedraw();
+  // Run posted BeginRetroFrame.
+  client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(false));
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
   EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
   EXPECT_TRUE(client.needs_begin_frames());
   client.Reset();
 
-  // Queue BeginFrame while we are still handling the previous BeginFrame.
-  args.frame_time += base::TimeDelta::FromSeconds(1);
-  client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
-  EXPECT_NO_ACTION(client);
+  // Let time pass sufficiently beyond the regular deadline but not beyond the
+  // late deadline.
+  client.now_src()->AdvanceNow(BeginFrameArgs::DefaultInterval() -
+                               base::TimeDelta::FromMicroseconds(1));
+  client.task_runner().RunUntilTime(client.now_src()->Now());
   EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-  EXPECT_TRUE(client.needs_begin_frames());
-  client.Reset();
 
   // Take us out of a swap throttled state.
   scheduler->DidSwapBuffersComplete();
-  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 1);
+  EXPECT_SINGLE_ACTION("ScheduledActionSendBeginMainFrame", client);
   EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
   EXPECT_TRUE(client.needs_begin_frames());
   client.Reset();
 
-  // BeginImplFrame deadline should draw.
-  scheduler->SetNeedsRedraw();
-
-  EXPECT_TRUE(client.task_runner().RunTasksWhile(
-      client.ImplFrameDeadlinePending(true)));
-
-  EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
-  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
+  // Verify that the deadline was rescheduled.
+  client.task_runner().RunUntilTime(client.now_src()->Now());
+  EXPECT_SINGLE_ACTION("ScheduledActionDrawAndSwapIfPossible", client);
   EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
   EXPECT_TRUE(client.needs_begin_frames());
   client.Reset();
@@ -1630,6 +1623,7 @@
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
   scheduler->SetCanDraw(true);
+  scheduler->SetEstimatedParentDrawTime(base::TimeDelta::FromMicroseconds(1));
   InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
 
   DCHECK(!client.fake_external_begin_frame_source());
@@ -1645,7 +1639,7 @@
   client.Reset();
 
   // Trigger the first BeginImplFrame and BeginMainFrame
-  client.task_runner().RunPendingTasks();  // Run posted BeginFrame.
+  client.AdvanceFrame();
   EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
   EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
   EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
@@ -1658,7 +1652,8 @@
   client.Reset();
 
   // Swapping will put us into a swap throttled state.
-  client.task_runner().RunPendingTasks();  // Run posted deadline.
+  // Run posted deadline.
+  client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(true));
   EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
   EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
   EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
@@ -1667,22 +1662,33 @@
   // While swap throttled, BeginFrames should trigger BeginImplFrames,
   // but not a BeginMainFrame or draw.
   scheduler->SetNeedsCommit();
-  client.task_runner().RunPendingTasks();  // Run posted BeginFrame.
-  EXPECT_ACTION("WillBeginImplFrame", client, 0, 1);
+  scheduler->SetNeedsRedraw();
+  client.AdvanceFrame();  // Run posted BeginFrame.
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
   EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
   client.Reset();
 
+  // Let time pass sufficiently beyond the regular deadline but not beyond the
+  // late deadline.
+  client.now_src()->AdvanceNow(BeginFrameArgs::DefaultInterval() -
+                               base::TimeDelta::FromMicroseconds(1));
+  client.task_runner().RunUntilTime(client.now_src()->Now());
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
   // Take us out of a swap throttled state.
   scheduler->DidSwapBuffersComplete();
-  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 1);
+  EXPECT_SINGLE_ACTION("ScheduledActionSendBeginMainFrame", client);
   EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
   client.Reset();
 
-  // BeginImplFrame deadline should draw.
-  scheduler->SetNeedsRedraw();
-  client.task_runner().RunPendingTasks();  // Run posted deadline.
-  EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
-  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
+  // Verify that the deadline was rescheduled.
+  // We can't use RunUntilTime(now) here because the next frame is also
+  // scheduled if throttle_frame_production = false.
+  base::TimeTicks before_deadline = client.now_src()->Now();
+  client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(true));
+  base::TimeTicks after_deadline = client.now_src()->Now();
+  EXPECT_EQ(after_deadline, before_deadline);
   EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
   client.Reset();
 }
diff --git a/cc/test/geometry_test_utils.h b/cc/test/geometry_test_utils.h
index b743f58..38112a8 100644
--- a/cc/test/geometry_test_utils.h
+++ b/cc/test/geometry_test_utils.h
@@ -29,33 +29,6 @@
   EXPECT_NEAR((expected).height(), (actual).height(), (abs_error)); \
 } while (false)
 
-#define EXPECT_RECT_EQ(expected, actual) \
-do { \
-  EXPECT_EQ((expected).x(), (actual).x()); \
-  EXPECT_EQ((expected).y(), (actual).y()); \
-  EXPECT_EQ((expected).width(), (actual).width()); \
-  EXPECT_EQ((expected).height(), (actual).height()); \
-} while (false)
-
-#define EXPECT_SIZE_EQ(expected, actual) \
-do { \
-  EXPECT_EQ((expected).width(), (actual).width()); \
-  EXPECT_EQ((expected).height(), (actual).height()); \
-} while (false)
-
-#define EXPECT_POINT_EQ(expected, actual) \
-do { \
-  EXPECT_EQ((expected).x(), (actual).x()); \
-  EXPECT_EQ((expected).y(), (actual).y()); \
-} while (false)
-
-#define EXPECT_POINT3F_EQ(expected, actual) \
-do { \
-  EXPECT_FLOAT_EQ((expected).x(), (actual).x()); \
-  EXPECT_FLOAT_EQ((expected).y(), (actual).y()); \
-  EXPECT_FLOAT_EQ((expected).z(), (actual).z()); \
-} while (false)
-
 #define EXPECT_VECTOR_EQ(expected, actual) \
 do { \
   EXPECT_EQ((expected).x(), (actual).x()); \
diff --git a/cc/test/layer_tree_json_parser_unittest.cc b/cc/test/layer_tree_json_parser_unittest.cc
index 4f9c562..a11d545 100644
--- a/cc/test/layer_tree_json_parser_unittest.cc
+++ b/cc/test/layer_tree_json_parser_unittest.cc
@@ -27,10 +27,9 @@
 
   RETURN_IF_EXPECTATION_FAILS(EXPECT_EQ(layer_impl->children().size(),
                                         layer->children().size()));
-  RETURN_IF_EXPECTATION_FAILS(EXPECT_SIZE_EQ(layer_impl->bounds(),
-                                             layer->bounds()));
-  RETURN_IF_EXPECTATION_FAILS(EXPECT_POINT_EQ(layer_impl->position(),
-                                              layer->position()));
+  RETURN_IF_EXPECTATION_FAILS(EXPECT_EQ(layer_impl->bounds(), layer->bounds()));
+  RETURN_IF_EXPECTATION_FAILS(
+      EXPECT_EQ(layer_impl->position(), layer->position()));
   RETURN_IF_EXPECTATION_FAILS(
       EXPECT_TRANSFORMATION_MATRIX_EQ(layer_impl->draw_transform(),
                                       layer->draw_transform()));
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index 9f08677..5be1240 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -785,11 +785,6 @@
   RunTest(true, false, true);
 }
 
-void LayerTreeTest::RunTestWithMainThreadLowLatency() {
-  settings_.main_thread_should_always_be_low_latency = true;
-  RunTest(false, false, false);
-}
-
 void LayerTreeTest::RequestNewOutputSurface(bool fallback) {
   layer_tree_host_->SetOutputSurface(CreateOutputSurface(fallback));
 }
diff --git a/cc/test/layer_tree_test.h b/cc/test/layer_tree_test.h
index ba2ef69..863100b 100644
--- a/cc/test/layer_tree_test.h
+++ b/cc/test/layer_tree_test.h
@@ -176,7 +176,6 @@
                        bool delegating_renderer,
                        bool impl_side_painting);
   virtual void RunTestWithImplSidePainting();
-  virtual void RunTestWithMainThreadLowLatency();
 
   bool HasImplThread() { return proxy() ? proxy()->HasImplThread() : false; }
   base::SingleThreadTaskRunner* ImplThreadTaskRunner() {
@@ -237,18 +236,7 @@
 
 }  // namespace cc
 
-#define SINGLE_THREAD_DIRECT_RENDERER_NOIMPL_MAIN_THREAD_LOW_LATENCY_TEST_F( \
-    TEST_FIXTURE_NAME)                                                       \
-  TEST_F(                                                                    \
-      TEST_FIXTURE_NAME,                                                     \
-      RunSingleThread_DirectRenderer_MainThreadPaint_MainThreadLowLatency) { \
-    RunTestWithMainThreadLowLatency();                                       \
-  }                                                                          \
-  class SingleThreadDirectNoImplLowLatencyNeedsSemicolon##TEST_FIXTURE_NAME {}
-
 #define SINGLE_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME)        \
-  SINGLE_THREAD_DIRECT_RENDERER_NOIMPL_MAIN_THREAD_LOW_LATENCY_TEST_F(        \
-      TEST_FIXTURE_NAME);                                                     \
   TEST_F(TEST_FIXTURE_NAME, RunSingleThread_DirectRenderer_MainThreadPaint) { \
     RunTest(false, false, false);                                             \
   }                                                                           \
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 361fae1..22b1196 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -363,6 +363,9 @@
 
   sync_tree->PushPageScaleFromMainThread(
       page_scale_factor_, min_page_scale_factor_, max_page_scale_factor_);
+  sync_tree->elastic_overscroll()->PushFromMainThread(elastic_overscroll_);
+  if (sync_tree->IsActiveTree())
+    sync_tree->elastic_overscroll()->PushPendingToActive();
 
   sync_tree->PassSwapPromises(&swap_promise_list_);
 
@@ -875,6 +878,7 @@
     LayerTreeHostCommon::CalcDrawPropsMainInputs inputs(
         root_layer, device_viewport_size(), gfx::Transform(),
         device_scale_factor_, page_scale_factor_, page_scale_layer,
+        elastic_overscroll_, overscroll_elasticity_layer_.get(),
         GetRendererCapabilities().max_texture_size, settings_.can_use_lcd_text,
         settings_.layers_always_allowed_lcd_text,
         can_render_to_separate_surface,
@@ -1126,9 +1130,8 @@
   }
 
   if (!inner_viewport_scroll_delta.IsZero() ||
-      !outer_viewport_scroll_delta.IsZero() ||
-      info->page_scale_delta != 1.f ||
-      info->top_controls_delta) {
+      !outer_viewport_scroll_delta.IsZero() || info->page_scale_delta != 1.f ||
+      !info->elastic_overscroll_delta.IsZero() || info->top_controls_delta) {
     // Preemptively apply the scroll offset and scale delta here before sending
     // it to the client.  If the client comes back and sets it to the same
     // value, then the layer can early out without needing a full commit.
@@ -1147,12 +1150,15 @@
     }
 
     ApplyPageScaleDeltaFromImplSide(info->page_scale_delta);
+    elastic_overscroll_ += info->elastic_overscroll_delta;
     if (!settings_.use_pinch_virtual_viewport) {
       client_->ApplyViewportDeltas(
           inner_viewport_scroll_delta + outer_viewport_scroll_delta,
           info->page_scale_delta,
           info->top_controls_delta);
     } else {
+      // TODO(ccameron): pass the elastic overscroll here so that input events
+      // may be translated appropriately.
       client_->ApplyViewportDeltas(
           inner_viewport_scroll_delta,
           outer_viewport_scroll_delta,
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index 9d758c8..75165ad 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -223,6 +223,7 @@
                                    float min_page_scale_factor,
                                    float max_page_scale_factor);
   float page_scale_factor() const { return page_scale_factor_; }
+  gfx::Vector2dF elastic_overscroll() const { return elastic_overscroll_; }
 
   SkColor background_color() const { return background_color_; }
   void set_background_color(SkColor color) { background_color_ = color; }
@@ -428,6 +429,7 @@
   float page_scale_factor_;
   float min_page_scale_factor_;
   float max_page_scale_factor_;
+  gfx::Vector2dF elastic_overscroll_;
   bool has_gpu_rasterization_trigger_;
   bool content_is_suitable_for_gpu_rasterization_;
   bool gpu_rasterization_histogram_recorded_;
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc
index 6d75687..9a9650f 100644
--- a/cc/trees/layer_tree_host_common.cc
+++ b/cc/trees/layer_tree_host_common.cc
@@ -17,6 +17,7 @@
 #include "cc/trees/layer_sorter.h"
 #include "cc/trees/layer_tree_impl.h"
 #include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/geometry/vector2d_conversions.h"
 #include "ui/gfx/transform.h"
 
 namespace cc {
@@ -1267,6 +1268,8 @@
   float device_scale_factor;
   float page_scale_factor;
   const LayerType* page_scale_application_layer;
+  gfx::Vector2dF elastic_overscroll;
+  const LayerType* elastic_overscroll_application_layer;
   bool can_adjust_raster_scales;
   bool can_render_to_separate_surface;
   bool layers_always_allowed_lcd_text;
@@ -1418,6 +1421,14 @@
   return layer_list;
 }
 
+static inline gfx::Vector2d BoundsDelta(Layer* layer) {
+  return gfx::Vector2d();
+}
+
+static inline gfx::Vector2d BoundsDelta(LayerImpl* layer) {
+  return gfx::ToCeiledVector2d(layer->bounds_delta());
+}
+
 template <typename LayerType, typename GetIndexAndCountType>
 static void SortLayerListContributions(
     const LayerType& parent,
@@ -1806,8 +1817,6 @@
                              layer->contents_opaque();
   }
 
-  gfx::Rect content_rect(layer->content_bounds());
-
   // full_hierarchy_matrix is the matrix that transforms objects between screen
   // space (except projection matrix) and the most recent RenderSurfaceImpl's
   // space.  next_hierarchy_matrix will only change if this layer uses a new
@@ -2044,8 +2053,22 @@
   if (adjust_text_aa)
     layer_draw_properties.can_use_lcd_text = layer_can_use_lcd_text;
 
-  gfx::Rect rect_in_target_space =
-      MathUtil::MapEnclosingClippedRect(layer->draw_transform(), content_rect);
+  gfx::Size content_size_affected_by_delta(layer->content_bounds());
+
+  // Non-zero BoundsDelta imply the contents_scale of 1.0
+  // because BoundsDela is only set on Android where
+  // ContentScalingLayer is never used.
+  DCHECK_IMPLIES(!BoundsDelta(layer).IsZero(),
+                 (layer->contents_scale_x() == 1.0 &&
+                  layer->contents_scale_y() == 1.0));
+
+  // Thus we can omit contents scale in the following calculation.
+  gfx::Vector2d bounds_delta =  BoundsDelta(layer);
+  content_size_affected_by_delta.Enlarge(bounds_delta.x(), bounds_delta.y());
+
+  gfx::Rect rect_in_target_space = MathUtil::MapEnclosingClippedRect(
+      layer->draw_transform(),
+      gfx::Rect(content_size_affected_by_delta));
 
   if (LayerClipsSubtree(layer)) {
     layer_or_ancestor_clips_descendants = true;
@@ -2100,6 +2123,10 @@
           globals.page_scale_factor);
       data_for_children.in_subtree_of_page_scale_application_layer = true;
     }
+    if (layer == globals.elastic_overscroll_application_layer) {
+      data_for_children.parent_matrix.Translate(globals.elastic_overscroll.x(),
+                                                globals.elastic_overscroll.y());
+    }
 
     // Flatten to 2D if the layer doesn't preserve 3D.
     if (layer->should_flatten_transform())
@@ -2378,6 +2405,9 @@
       inputs.device_scale_factor * device_transform_scale;
   globals->page_scale_factor = inputs.page_scale_factor;
   globals->page_scale_application_layer = inputs.page_scale_application_layer;
+  globals->elastic_overscroll = inputs.elastic_overscroll;
+  globals->elastic_overscroll_application_layer =
+      inputs.elastic_overscroll_application_layer;
   globals->can_render_to_separate_surface =
       inputs.can_render_to_separate_surface;
   globals->can_adjust_raster_scales = inputs.can_adjust_raster_scales;
diff --git a/cc/trees/layer_tree_host_common.h b/cc/trees/layer_tree_host_common.h
index 349b341..81aca55 100644
--- a/cc/trees/layer_tree_host_common.h
+++ b/cc/trees/layer_tree_host_common.h
@@ -38,6 +38,8 @@
                         float device_scale_factor,
                         float page_scale_factor,
                         const LayerType* page_scale_application_layer,
+                        const gfx::Vector2dF& elastic_overscroll,
+                        const LayerType* elastic_overscroll_application_layer,
                         int max_texture_size,
                         bool can_use_lcd_text,
                         bool layers_always_allowed_lcd_text,
@@ -51,6 +53,9 @@
           device_scale_factor(device_scale_factor),
           page_scale_factor(page_scale_factor),
           page_scale_application_layer(page_scale_application_layer),
+          elastic_overscroll(elastic_overscroll),
+          elastic_overscroll_application_layer(
+              elastic_overscroll_application_layer),
           max_texture_size(max_texture_size),
           can_use_lcd_text(can_use_lcd_text),
           layers_always_allowed_lcd_text(layers_always_allowed_lcd_text),
@@ -66,6 +71,8 @@
     float device_scale_factor;
     float page_scale_factor;
     const LayerType* page_scale_application_layer;
+    gfx::Vector2dF elastic_overscroll;
+    const LayerType* elastic_overscroll_application_layer;
     int max_texture_size;
     bool can_use_lcd_text;
     bool layers_always_allowed_lcd_text;
@@ -145,6 +152,7 @@
 
   std::vector<LayerTreeHostCommon::ScrollUpdateInfo> scrolls;
   float page_scale_delta;
+  gfx::Vector2dF elastic_overscroll_delta;
   float top_controls_delta;
   ScopedPtrVector<SwapPromise> swap_promises;
 };
@@ -223,6 +231,8 @@
           1.f,
           1.f,
           NULL,
+          gfx::Vector2dF(),
+          NULL,
           std::numeric_limits<int>::max() / 2,
           false,
           false,
@@ -248,6 +258,8 @@
           1.f,
           1.f,
           NULL,
+          gfx::Vector2dF(),
+          NULL,
           std::numeric_limits<int>::max() / 2,
           false,
           false,
diff --git a/cc/trees/layer_tree_host_common_perftest.cc b/cc/trees/layer_tree_host_common_perftest.cc
index 2fd2146..ab72cf9 100644
--- a/cc/trees/layer_tree_host_common_perftest.cc
+++ b/cc/trees/layer_tree_host_common_perftest.cc
@@ -96,6 +96,8 @@
           layer_tree_host()->device_viewport_size(), gfx::Transform(),
           layer_tree_host()->device_scale_factor(),
           layer_tree_host()->page_scale_factor(),
+          layer_tree_host()->overscroll_elasticity_layer(),
+          layer_tree_host()->elastic_overscroll(),
           layer_tree_host()->page_scale_layer(), max_texture_size,
           layer_tree_host()->settings().can_use_lcd_text,
           layer_tree_host()->settings().layers_always_allowed_lcd_text,
@@ -148,7 +150,9 @@
         active_tree->root_layer(), active_tree->DrawViewportSize(),
         host_impl->DrawTransform(), active_tree->device_scale_factor(),
         active_tree->current_page_scale_factor(),
-        active_tree->InnerViewportContainerLayer(), max_texture_size,
+        active_tree->InnerViewportContainerLayer(),
+        active_tree->elastic_overscroll()->Current(active_tree->IsActiveTree()),
+        active_tree->overscroll_elasticity_layer(), max_texture_size,
         host_impl->settings().can_use_lcd_text,
         host_impl->settings().layers_always_allowed_lcd_text,
         can_render_to_separate_surface,
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc
index 8c02bd3..f8e5be9 100644
--- a/cc/trees/layer_tree_host_common_unittest.cc
+++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -1943,12 +1943,9 @@
   inputs.can_adjust_raster_scales = true;
   LayerTreeHostCommon::CalculateDrawProperties(&inputs);
 
-  EXPECT_RECT_EQ(gfx::Rect(5, 5, 10, 10),
-                 grand_child1->drawable_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(15, 15, 5, 5),
-                 grand_child3->drawable_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(15, 15, 5, 5),
-                 grand_child3->drawable_content_rect());
+  EXPECT_EQ(gfx::Rect(5, 5, 10, 10), grand_child1->drawable_content_rect());
+  EXPECT_EQ(gfx::Rect(15, 15, 5, 5), grand_child3->drawable_content_rect());
+  EXPECT_EQ(gfx::Rect(15, 15, 5, 5), grand_child3->drawable_content_rect());
   EXPECT_TRUE(grand_child4->drawable_content_rect().IsEmpty());
 }
 
@@ -2090,12 +2087,12 @@
 
   // Surfaces are clipped by their parent, but un-affected by the owning layer's
   // masksToBounds.
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 20, 20),
-                 grand_child1->render_surface()->clip_rect());
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 20, 20),
-                 grand_child2->render_surface()->clip_rect());
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 20, 20),
-                 grand_child3->render_surface()->clip_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 20, 20),
+            grand_child1->render_surface()->clip_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 20, 20),
+            grand_child2->render_surface()->clip_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 20, 20),
+            grand_child3->render_surface()->clip_rect());
 }
 
 TEST_F(LayerTreeHostCommonTest, AnimationsForRenderSurfaceHierarchy) {
@@ -2320,7 +2317,7 @@
   gfx::Rect expected = gfx::Rect(10, 10, 30, 30);
   gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect(
       target_surface_rect, layer_content_rect, layer_to_surface_transform);
-  EXPECT_RECT_EQ(expected, actual);
+  EXPECT_EQ(expected, actual);
 
   // Case 2: Layer is outside the surface rect.
   layer_content_rect = gfx::Rect(120, 120, 30, 30);
@@ -2333,7 +2330,7 @@
   expected = gfx::Rect(80, 80, 20, 20);
   actual = LayerTreeHostCommon::CalculateVisibleRect(
       target_surface_rect, layer_content_rect, layer_to_surface_transform);
-  EXPECT_RECT_EQ(expected, actual);
+  EXPECT_EQ(expected, actual);
 }
 
 TEST_F(LayerTreeHostCommonTest, VisibleRectForTranslations) {
@@ -2350,7 +2347,7 @@
   gfx::Rect expected = gfx::Rect(0, 0, 30, 30);
   gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect(
       target_surface_rect, layer_content_rect, layer_to_surface_transform);
-  EXPECT_RECT_EQ(expected, actual);
+  EXPECT_EQ(expected, actual);
 
   // Case 2: Layer is outside the surface rect.
   layer_to_surface_transform.MakeIdentity();
@@ -2365,7 +2362,7 @@
   expected = gfx::Rect(0, 0, 20, 20);
   actual = LayerTreeHostCommon::CalculateVisibleRect(
       target_surface_rect, layer_content_rect, layer_to_surface_transform);
-  EXPECT_RECT_EQ(expected, actual);
+  EXPECT_EQ(expected, actual);
 }
 
 TEST_F(LayerTreeHostCommonTest, VisibleRectFor2DRotations) {
@@ -2384,7 +2381,7 @@
   gfx::Rect expected = gfx::Rect(0, 0, 30, 30);
   gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect(
       target_surface_rect, layer_content_rect, layer_to_surface_transform);
-  EXPECT_RECT_EQ(expected, actual);
+  EXPECT_EQ(expected, actual);
 
   // Case 2: Layer is outside the surface rect.
   layer_to_surface_transform.MakeIdentity();
@@ -2404,7 +2401,7 @@
   expected = gfx::Rect(0, 0, 30, 30);
   actual = LayerTreeHostCommon::CalculateVisibleRect(
       target_surface_rect, layer_content_rect, layer_to_surface_transform);
-  EXPECT_RECT_EQ(expected, actual);
+  EXPECT_EQ(expected, actual);
 
   // Case 4: The layer is rotated about its top-left corner, and translated
   // upwards. In surface space, the layer is oriented diagonally, with only the
@@ -2417,7 +2414,7 @@
   expected = gfx::Rect(15, 0, 15, 30);  // Right half of layer bounds.
   actual = LayerTreeHostCommon::CalculateVisibleRect(
       target_surface_rect, layer_content_rect, layer_to_surface_transform);
-  EXPECT_RECT_EQ(expected, actual);
+  EXPECT_EQ(expected, actual);
 }
 
 TEST_F(LayerTreeHostCommonTest, VisibleRectFor3dOrthographicTransform) {
@@ -2435,7 +2432,7 @@
   gfx::Rect expected = gfx::Rect(0, 0, 100, 100);
   gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect(
       target_surface_rect, layer_content_rect, layer_to_surface_transform);
-  EXPECT_RECT_EQ(expected, actual);
+  EXPECT_EQ(expected, actual);
 
   // Case 2: Orthographic projection of a layer rotated about y-axis by 45
   // degrees, but shifted to the side so only the right-half the layer would be
@@ -2450,7 +2447,7 @@
   expected = gfx::Rect(50, 0, 50, 100);  // Tight half of the layer.
   actual = LayerTreeHostCommon::CalculateVisibleRect(
       target_surface_rect, layer_content_rect, layer_to_surface_transform);
-  EXPECT_RECT_EQ(expected, actual);
+  EXPECT_EQ(expected, actual);
 }
 
 TEST_F(LayerTreeHostCommonTest, VisibleRectFor3dPerspectiveTransform) {
@@ -2478,7 +2475,7 @@
   gfx::Rect expected = gfx::Rect(-50, -50, 200, 200);
   gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect(
       target_surface_rect, layer_content_rect, layer_to_surface_transform);
-  EXPECT_RECT_EQ(expected, actual);
+  EXPECT_EQ(expected, actual);
 
   // Case 2: same projection as before, except that the layer is also translated
   // to the side, so that only the right half of the layer should be visible.
@@ -2495,7 +2492,7 @@
                                               // bounding rect.
   actual = LayerTreeHostCommon::CalculateVisibleRect(
       target_surface_rect, layer_content_rect, layer_to_surface_transform);
-  EXPECT_RECT_EQ(expected, actual);
+  EXPECT_EQ(expected, actual);
 }
 
 TEST_F(LayerTreeHostCommonTest,
@@ -2519,7 +2516,7 @@
   gfx::Rect expected = gfx::Rect(0, 0, 100, 100);
   gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect(
       target_surface_rect, layer_content_rect, layer_to_surface_transform);
-  EXPECT_RECT_EQ(expected, actual);
+  EXPECT_EQ(expected, actual);
 }
 
 TEST_F(LayerTreeHostCommonTest, VisibleRectFor3dPerspectiveWhenClippedByW) {
@@ -2592,7 +2589,7 @@
   gfx::Rect expected = gfx::Rect(-10, -10, 20, 20);
   gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect(
       target_surface_rect, layer_content_rect, layer_to_surface_transform);
-  EXPECT_RECT_EQ(expected, actual);
+  EXPECT_EQ(expected, actual);
 }
 
 TEST_F(LayerTreeHostCommonTest, DrawableAndVisibleContentRectsForSimpleLayers) {
@@ -2642,22 +2639,22 @@
 
   ExecuteCalculateDrawProperties(root.get());
 
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100),
-                 root->render_surface()->DrawableContentRect());
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 100, 100),
+            root->render_surface()->DrawableContentRect());
+  EXPECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect());
 
   // Layers that do not draw content should have empty visible_content_rects.
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect());
 
   // layer visible_content_rects are clipped by their target surface.
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 25, 25), child2->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 25, 25), child2->visible_content_rect());
   EXPECT_TRUE(child3->visible_content_rect().IsEmpty());
 
   // layer drawable_content_rects are not clipped.
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child1->drawable_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(75, 75, 50, 50), child2->drawable_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(125, 125, 50, 50), child3->drawable_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->drawable_content_rect());
+  EXPECT_EQ(gfx::Rect(75, 75, 50, 50), child2->drawable_content_rect());
+  EXPECT_EQ(gfx::Rect(125, 125, 50, 50), child3->drawable_content_rect());
 }
 
 TEST_F(LayerTreeHostCommonTest,
@@ -2720,24 +2717,22 @@
 
   ASSERT_FALSE(child->render_surface());
 
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100),
-                 root->render_surface()->DrawableContentRect());
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 100, 100),
+            root->render_surface()->DrawableContentRect());
+  EXPECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect());
 
   // Layers that do not draw content should have empty visible content rects.
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), child->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 0, 0), child->visible_content_rect());
 
   // All grandchild visible content rects should be clipped by child.
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), grand_child1->visible_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 25, 25), grand_child2->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 50, 50), grand_child1->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 25, 25), grand_child2->visible_content_rect());
   EXPECT_TRUE(grand_child3->visible_content_rect().IsEmpty());
 
   // All grandchild DrawableContentRects should also be clipped by child.
-  EXPECT_RECT_EQ(gfx::Rect(5, 5, 50, 50),
-                 grand_child1->drawable_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(75, 75, 25, 25),
-                 grand_child2->drawable_content_rect());
+  EXPECT_EQ(gfx::Rect(5, 5, 50, 50), grand_child1->drawable_content_rect());
+  EXPECT_EQ(gfx::Rect(75, 75, 25, 25), grand_child2->drawable_content_rect());
   EXPECT_TRUE(grand_child3->drawable_content_rect().IsEmpty());
 }
 
@@ -2801,28 +2796,27 @@
 
   ASSERT_TRUE(render_surface1->render_surface());
 
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100),
-                 root->render_surface()->DrawableContentRect());
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 100, 100),
+            root->render_surface()->DrawableContentRect());
+  EXPECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect());
 
   // Layers that do not draw content should have empty visible content rects.
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0),
-                 render_surface1->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 0, 0), render_surface1->visible_content_rect());
 
   // An unclipped surface grows its DrawableContentRect to include all drawable
   // regions of the subtree.
-  EXPECT_RECT_EQ(gfx::Rect(5, 5, 170, 170),
-                 render_surface1->render_surface()->DrawableContentRect());
+  EXPECT_EQ(gfx::Rect(5, 5, 170, 170),
+            render_surface1->render_surface()->DrawableContentRect());
 
   // All layers that draw content into the unclipped surface are also unclipped.
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child2->visible_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child3->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child2->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child3->visible_content_rect());
 
-  EXPECT_RECT_EQ(gfx::Rect(5, 5, 50, 50), child1->drawable_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(75, 75, 50, 50), child2->drawable_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(125, 125, 50, 50), child3->drawable_content_rect());
+  EXPECT_EQ(gfx::Rect(5, 5, 50, 50), child1->drawable_content_rect());
+  EXPECT_EQ(gfx::Rect(75, 75, 50, 50), child2->drawable_content_rect());
+  EXPECT_EQ(gfx::Rect(125, 125, 50, 50), child3->drawable_content_rect());
 }
 
 TEST_F(LayerTreeHostCommonTest,
@@ -3085,30 +3079,29 @@
 
   ASSERT_TRUE(render_surface1->render_surface());
 
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100),
-                 root->render_surface()->DrawableContentRect());
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 100, 100),
+            root->render_surface()->DrawableContentRect());
+  EXPECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect());
 
   // Layers that do not draw content should have empty visible content rects.
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0),
-                 render_surface1->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 0, 0), render_surface1->visible_content_rect());
 
   // A clipped surface grows its DrawableContentRect to include all drawable
   // regions of the subtree, but also gets clamped by the ancestor's clip.
-  EXPECT_RECT_EQ(gfx::Rect(5, 5, 95, 95),
-                 render_surface1->render_surface()->DrawableContentRect());
+  EXPECT_EQ(gfx::Rect(5, 5, 95, 95),
+            render_surface1->render_surface()->DrawableContentRect());
 
   // All layers that draw content into the surface have their visible content
   // rect clipped by the surface clip rect.
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 25, 25), child2->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 25, 25), child2->visible_content_rect());
   EXPECT_TRUE(child3->visible_content_rect().IsEmpty());
 
   // But the DrawableContentRects are unclipped.
-  EXPECT_RECT_EQ(gfx::Rect(5, 5, 50, 50), child1->drawable_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(75, 75, 50, 50), child2->drawable_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(125, 125, 50, 50), child3->drawable_content_rect());
+  EXPECT_EQ(gfx::Rect(5, 5, 50, 50), child1->drawable_content_rect());
+  EXPECT_EQ(gfx::Rect(75, 75, 50, 50), child2->drawable_content_rect());
+  EXPECT_EQ(gfx::Rect(125, 125, 50, 50), child3->drawable_content_rect());
 }
 
 TEST_F(LayerTreeHostCommonTest,
@@ -3184,37 +3177,35 @@
   ASSERT_TRUE(render_surface1->render_surface());
   ASSERT_TRUE(render_surface2->render_surface());
 
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100),
-                 root->render_surface()->DrawableContentRect());
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 100, 100),
+            root->render_surface()->DrawableContentRect());
+  EXPECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect());
 
   // Layers that do not draw content should have empty visible content rects.
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0),
-                 render_surface1->visible_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0),
-                 render_surface2->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 0, 0), render_surface1->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 0, 0), render_surface2->visible_content_rect());
 
   // A clipped surface grows its DrawableContentRect to include all drawable
   // regions of the subtree, but also gets clamped by the ancestor's clip.
-  EXPECT_RECT_EQ(gfx::Rect(5, 5, 95, 95),
-                 render_surface1->render_surface()->DrawableContentRect());
+  EXPECT_EQ(gfx::Rect(5, 5, 95, 95),
+            render_surface1->render_surface()->DrawableContentRect());
 
   // render_surface1 lives in the "unclipped universe" of render_surface1, and
   // is only implicitly clipped by render_surface1's content rect. So,
   // render_surface2 grows to enclose all drawable content of its subtree.
-  EXPECT_RECT_EQ(gfx::Rect(5, 5, 170, 170),
-                 render_surface2->render_surface()->DrawableContentRect());
+  EXPECT_EQ(gfx::Rect(5, 5, 170, 170),
+            render_surface2->render_surface()->DrawableContentRect());
 
   // All layers that draw content into render_surface2 think they are unclipped.
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child2->visible_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child3->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child2->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child3->visible_content_rect());
 
   // DrawableContentRects are also unclipped.
-  EXPECT_RECT_EQ(gfx::Rect(5, 5, 50, 50), child1->drawable_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(75, 75, 50, 50), child2->drawable_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(125, 125, 50, 50), child3->drawable_content_rect());
+  EXPECT_EQ(gfx::Rect(5, 5, 50, 50), child1->drawable_content_rect());
+  EXPECT_EQ(gfx::Rect(75, 75, 50, 50), child2->drawable_content_rect());
+  EXPECT_EQ(gfx::Rect(125, 125, 50, 50), child3->drawable_content_rect());
 }
 
 TEST_F(LayerTreeHostCommonTest,
@@ -3262,14 +3253,13 @@
 
   ASSERT_TRUE(render_surface1->render_surface());
 
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100),
-                 root->render_surface()->DrawableContentRect());
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 100, 100),
+            root->render_surface()->DrawableContentRect());
+  EXPECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect());
 
   // Layers that do not draw content should have empty visible content rects.
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0),
-                 render_surface1->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 0, 0), render_surface1->visible_content_rect());
 
   // The unclipped surface grows its DrawableContentRect to include all drawable
   // regions of the subtree.
@@ -3279,13 +3269,12 @@
                 50 - diagonal_radius,
                 diagonal_radius * 2,
                 diagonal_radius * 2);
-  EXPECT_RECT_EQ(expected_surface_drawable_content,
-                 render_surface1->render_surface()->DrawableContentRect());
+  EXPECT_EQ(expected_surface_drawable_content,
+            render_surface1->render_surface()->DrawableContentRect());
 
   // All layers that draw content into the unclipped surface are also unclipped.
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect());
-  EXPECT_RECT_EQ(expected_surface_drawable_content,
-                 child1->drawable_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect());
+  EXPECT_EQ(expected_surface_drawable_content, child1->drawable_content_rect());
 }
 
 TEST_F(LayerTreeHostCommonTest,
@@ -3344,18 +3333,18 @@
                                                   diagonal_radius * 2);
   gfx::Rect expected_surface_drawable_content =
       gfx::IntersectRects(unclipped_surface_content, gfx::Rect(0, 0, 50, 50));
-  EXPECT_RECT_EQ(expected_surface_drawable_content,
-                 render_surface1->render_surface()->DrawableContentRect());
+  EXPECT_EQ(expected_surface_drawable_content,
+            render_surface1->render_surface()->DrawableContentRect());
 
   // On the clipped surface, only a quarter  of the child1 is visible, but when
   // rotating it back to  child1's content space, the actual enclosing rect ends
   // up covering the full left half of child1.
   //
   // Given the floating point math, this number is a little bit fuzzy.
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 26, 50), child1->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 26, 50), child1->visible_content_rect());
 
   // The child's DrawableContentRect is unclipped.
-  EXPECT_RECT_EQ(unclipped_surface_content, child1->drawable_content_rect());
+  EXPECT_EQ(unclipped_surface_content, child1->drawable_content_rect());
 }
 
 TEST_F(LayerTreeHostCommonTest, DrawableAndVisibleContentRectsInHighDPI) {
@@ -3434,35 +3423,31 @@
 
   // drawable_content_rects for all layers and surfaces are scaled by
   // device_scale_factor.
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 200, 200),
-                 root->render_surface()->DrawableContentRect());
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 200, 200), root->drawable_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(10, 10, 190, 190),
-                 render_surface1->render_surface()->DrawableContentRect());
+  EXPECT_EQ(gfx::Rect(0, 0, 200, 200),
+            root->render_surface()->DrawableContentRect());
+  EXPECT_EQ(gfx::Rect(0, 0, 200, 200), root->drawable_content_rect());
+  EXPECT_EQ(gfx::Rect(10, 10, 190, 190),
+            render_surface1->render_surface()->DrawableContentRect());
 
   // render_surface2 lives in the "unclipped universe" of render_surface1, and
   // is only implicitly clipped by render_surface1.
-  EXPECT_RECT_EQ(gfx::Rect(10, 10, 350, 350),
-                 render_surface2->render_surface()->DrawableContentRect());
+  EXPECT_EQ(gfx::Rect(10, 10, 350, 350),
+            render_surface2->render_surface()->DrawableContentRect());
 
-  EXPECT_RECT_EQ(gfx::Rect(10, 10, 100, 100), child1->drawable_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(150, 150, 100, 100),
-                 child2->drawable_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(250, 250, 100, 100),
-                 child3->drawable_content_rect());
+  EXPECT_EQ(gfx::Rect(10, 10, 100, 100), child1->drawable_content_rect());
+  EXPECT_EQ(gfx::Rect(150, 150, 100, 100), child2->drawable_content_rect());
+  EXPECT_EQ(gfx::Rect(250, 250, 100, 100), child3->drawable_content_rect());
 
   // The root layer does not actually draw content of its own.
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect());
 
   // All layer visible content rects are not expressed in content space of each
   // layer, so they are not scaled by the device_scale_factor.
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 3, 4),
-                 render_surface1->visible_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 7, 13),
-                 render_surface2->visible_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child2->visible_content_rect());
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child3->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 3, 4), render_surface1->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 7, 13), render_surface2->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child2->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child3->visible_content_rect());
 }
 
 TEST_F(LayerTreeHostCommonTest, BackFaceCullingWithoutPreserves3d) {
@@ -5458,8 +5443,8 @@
   EXPECT_TRANSFORMATION_MATRIX_EQ(
       child->screen_space_transform(),
       duplicate_child_non_owner->screen_space_transform());
-  EXPECT_RECT_EQ(child->drawable_content_rect(),
-                 duplicate_child_non_owner->drawable_content_rect());
+  EXPECT_EQ(child->drawable_content_rect(),
+            duplicate_child_non_owner->drawable_content_rect());
   EXPECT_EQ(child->content_bounds(),
             duplicate_child_non_owner->content_bounds());
 
@@ -8676,5 +8661,68 @@
   EXPECT_EQ(gfx::Rect(768 / 2, 582 / 2), content->visible_content_rect());
 }
 
+TEST_F(LayerTreeHostCommonTest, BoundsDeltaAffectVisibleContentRect) {
+  FakeImplProxy proxy;
+  TestSharedBitmapManager shared_bitmap_manager;
+  FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+
+  // Set two layers: the root layer clips it's child,
+  // the child draws its content.
+
+  gfx::Size root_size = gfx::Size(300, 500);
+
+  // Sublayer should be bigger than the root enlarged by bounds_delta.
+  gfx::Size sublayer_size = gfx::Size(300, 1000);
+
+  // Device viewport accomidated the root and the top controls.
+  gfx::Size device_viewport_size = gfx::Size(300, 600);
+  gfx::Transform identity_matrix;
+
+  host_impl.active_tree()->SetRootLayer(
+      LayerImpl::Create(host_impl.active_tree(), 1));
+
+  LayerImpl* root = host_impl.active_tree()->root_layer();
+  SetLayerPropertiesForTesting(root,
+                               identity_matrix,
+                               gfx::Point3F(),
+                               gfx::PointF(),
+                               root_size,
+                               false,
+                               false);
+
+  root->SetContentBounds(root_size);
+  root->SetMasksToBounds(true);
+
+  root->AddChild(LayerImpl::Create(host_impl.active_tree(), 2));
+
+  LayerImpl* sublayer = root->child_at(0);
+  SetLayerPropertiesForTesting(sublayer,
+                               identity_matrix,
+                               gfx::Point3F(),
+                               gfx::PointF(),
+                               sublayer_size,
+                               false,
+                               false);
+
+  sublayer->SetContentBounds(sublayer_size);
+  sublayer->SetDrawsContent(true);
+
+  LayerImplList layer_impl_list;
+  LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
+      root, device_viewport_size, &layer_impl_list);
+
+  LayerTreeHostCommon::CalculateDrawProperties(&inputs);
+
+  EXPECT_EQ(gfx::Rect(root_size), sublayer->visible_content_rect());
+
+  root->SetBoundsDelta(gfx::Vector2dF(0.0, 50.0));
+
+  LayerTreeHostCommon::CalculateDrawProperties(&inputs);
+
+  gfx::Rect affected_by_delta(0, 0, root_size.width(),
+                              root_size.height() + 50);
+  EXPECT_EQ(affected_by_delta, sublayer->visible_content_rect());
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 566fb57..e19c9a2 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -237,7 +237,8 @@
   SetDebugState(settings.initial_debug_state);
 
   // LTHI always has an active tree.
-  active_tree_ = LayerTreeImpl::create(this, new SyncedProperty<ScaleGroup>());
+  active_tree_ = LayerTreeImpl::create(this, new SyncedProperty<ScaleGroup>(),
+                                       new SyncedElasticOverscroll);
 
   TRACE_EVENT_OBJECT_CREATED_WITH_ID(
       TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::LayerTreeHostImpl", id_);
@@ -1101,8 +1102,8 @@
 void LayerTreeHostImpl::ResetTreesForTesting() {
   if (active_tree_)
     active_tree_->DetachLayerTree();
-  active_tree_ =
-      LayerTreeImpl::create(this, active_tree()->page_scale_factor());
+  active_tree_ = LayerTreeImpl::create(this, active_tree()->page_scale_factor(),
+                                       active_tree()->elastic_overscroll());
   if (pending_tree_)
     pending_tree_->DetachLayerTree();
   pending_tree_ = nullptr;
@@ -1748,7 +1749,8 @@
     recycle_tree_.swap(pending_tree_);
   else
     pending_tree_ =
-        LayerTreeImpl::create(this, active_tree()->page_scale_factor());
+        LayerTreeImpl::create(this, active_tree()->page_scale_factor(),
+                              active_tree()->elastic_overscroll());
 
   // Update the delta from the active tree, which may have
   // adjusted its delta prior to the pending tree being created.
@@ -2008,16 +2010,13 @@
   }
 
   if (GetRendererCapabilities().using_image) {
-    unsigned image_target = GL_TEXTURE_2D;
-#if defined(OS_MACOSX)
-    // GL_TEXTURE_RECTANGLE_ARB target is required by IOSurface backed images.
-    DCHECK(context_provider->ContextCapabilities().gpu.texture_rectangle);
-    image_target = GL_TEXTURE_RECTANGLE_ARB;
-#endif
-    if (settings_.use_image_external) {
-      DCHECK(context_provider->ContextCapabilities().gpu.egl_image_external);
-      image_target = GL_TEXTURE_EXTERNAL_OES;
-    }
+    unsigned image_target = settings_.use_image_texture_target;
+    DCHECK_IMPLIES(
+        image_target == GL_TEXTURE_RECTANGLE_ARB,
+        context_provider->ContextCapabilities().gpu.texture_rectangle);
+    DCHECK_IMPLIES(
+        image_target == GL_TEXTURE_EXTERNAL_OES,
+        context_provider->ContextCapabilities().gpu.egl_image_external);
 
     if (settings_.use_zero_copy || IsSynchronousSingleThreaded()) {
       *resource_pool =
@@ -2681,10 +2680,16 @@
     }
 
     did_lock_scrolling_layer_ = true;
-    if (!allow_bubbling_for_current_layer) {
+
+    // When scrolls are allowed to bubble, it's important that the original
+    // scrolling layer be preserved. This ensures that, after a scroll bubbles,
+    // the user can reverse scroll directions and immediately resume scrolling
+    // the original layer that scrolled.
+    if (!should_bubble_scrolls_)
       active_tree_->SetCurrentlyScrollingLayer(layer_impl);
+
+    if (!allow_bubbling_for_current_layer)
       break;
-    }
 
     if (allow_unrestricted_bubbling_for_current_layer) {
       pending_delta -= applied_delta;
@@ -3022,6 +3027,8 @@
   CollectScrollDeltas(scroll_info.get(), active_tree_->root_layer());
   scroll_info->page_scale_delta =
       active_tree_->page_scale_factor()->PullDeltaForMainThread();
+  scroll_info->elastic_overscroll_delta =
+      active_tree_->elastic_overscroll()->PullDeltaForMainThread();
   scroll_info->swap_promises.swap(swap_promises_for_main_thread_scroll_update_);
   scroll_info->top_controls_delta = active_tree()->top_controls_delta();
   active_tree_->set_sent_top_controls_delta(scroll_info->top_controls_delta);
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 934946b..3ef9445 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -5373,7 +5373,7 @@
 
       // Verify the damage rect for the root render pass.
       const RenderPass* root_render_pass = frame.render_passes.back();
-      EXPECT_RECT_EQ(expected_damage, root_render_pass->damage_rect);
+      EXPECT_EQ(expected_damage, root_render_pass->damage_rect);
 
       // Verify the root and child layers' quads are generated and not being
       // culled.
@@ -5381,13 +5381,13 @@
 
       LayerImpl* child = host_impl_->active_tree()->root_layer()->children()[0];
       gfx::RectF expected_child_visible_rect(child->content_bounds());
-      EXPECT_RECT_EQ(expected_child_visible_rect,
-                     root_render_pass->quad_list.front()->visible_rect);
+      EXPECT_EQ(expected_child_visible_rect,
+                root_render_pass->quad_list.front()->visible_rect);
 
       LayerImpl* root = host_impl_->active_tree()->root_layer();
       gfx::RectF expected_root_visible_rect(root->content_bounds());
-      EXPECT_RECT_EQ(expected_root_visible_rect,
-                     root_render_pass->quad_list.ElementAt(1)->visible_rect);
+      EXPECT_EQ(expected_root_visible_rect,
+                root_render_pass->quad_list.ElementAt(1)->visible_rect);
     }
 
     host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
@@ -7621,6 +7621,56 @@
   }
 }
 
+TEST_F(LayerTreeHostImplVirtualViewportTest,
+       TouchFlingCanLockToViewportLayerAfterBubbling) {
+  gfx::Size content_size = gfx::Size(100, 160);
+  gfx::Size outer_viewport = gfx::Size(50, 80);
+  gfx::Size inner_viewport = gfx::Size(25, 40);
+
+  SetupVirtualViewportLayers(content_size, outer_viewport, inner_viewport);
+
+  LayerImpl* outer_scroll = host_impl_->OuterViewportScrollLayer();
+  LayerImpl* inner_scroll = host_impl_->InnerViewportScrollLayer();
+
+  scoped_ptr<LayerImpl> child =
+      CreateScrollableLayer(10, outer_viewport, outer_scroll);
+  LayerImpl* child_scroll = child.get();
+  outer_scroll->children()[0]->AddChild(child.Pass());
+
+  DrawFrame();
+  {
+    scoped_ptr<ScrollAndScaleSet> scroll_info;
+
+    gfx::Vector2d scroll_delta(0, inner_viewport.height());
+    EXPECT_EQ(InputHandler::ScrollStarted,
+              host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+    EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll);
+
+    // The child should have scrolled up to its limit.
+    scroll_info = host_impl_->ProcessScrollDeltas();
+    ASSERT_EQ(1u, scroll_info->scrolls.size());
+    ExpectContains(*scroll_info, child_scroll->id(), scroll_delta);
+    EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child_scroll);
+
+    // The first |ScrollBy| after the fling should re-lock the scrolling
+    // layer to the first layer that scrolled, the inner viewport scroll layer.
+    EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->FlingScrollBegin());
+    EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll);
+    EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), inner_scroll);
+
+    // The inner viewport should have scrolled up to its limit.
+    scroll_info = host_impl_->ProcessScrollDeltas();
+    ASSERT_EQ(2u, scroll_info->scrolls.size());
+    ExpectContains(*scroll_info, child_scroll->id(), scroll_delta);
+    ExpectContains(*scroll_info, inner_scroll->id(), scroll_delta);
+
+    // As the locked layer is at its limit, no further scrolling can occur.
+    EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll);
+    EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), inner_scroll);
+    host_impl_->ScrollEnd();
+  }
+}
+
 class LayerTreeHostImplWithImplicitLimitsTest : public LayerTreeHostImplTest {
  public:
   void SetUp() override {
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index c029c78..d70d832 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -442,7 +442,7 @@
 
     if (!num_draws_) {
       // If this is the first frame, expect full frame damage.
-      EXPECT_RECT_EQ(root_damage_rect, gfx::Rect(bounds_));
+      EXPECT_EQ(root_damage_rect, gfx::Rect(bounds_));
     } else {
       // Check that invalid_rect_ is indeed repainted.
       EXPECT_TRUE(root_damage_rect.Contains(invalid_rect_));
@@ -624,17 +624,17 @@
 
     switch (num_draws_) {
       case 0:
-        EXPECT_RECT_EQ(gfx::Rect(bounds_), root_damage_rect);
+        EXPECT_EQ(gfx::Rect(bounds_), root_damage_rect);
         break;
       case 1:
       case 2:
-        EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), root_damage_rect);
+        EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root_damage_rect);
         break;
       case 3:
-        EXPECT_RECT_EQ(invalid_rect_, root_damage_rect);
+        EXPECT_EQ(invalid_rect_, root_damage_rect);
         break;
       case 4:
-        EXPECT_RECT_EQ(gfx::Rect(bounds_), root_damage_rect);
+        EXPECT_EQ(gfx::Rect(bounds_), root_damage_rect);
         break;
       default:
         NOTREACHED();
@@ -736,12 +736,12 @@
     // box.
     switch (host_impl->active_tree()->source_frame_number()) {
       case 0:
-        EXPECT_RECT_EQ(gfx::Rect(root_layer_->bounds()), root_damage_rect);
+        EXPECT_EQ(gfx::Rect(root_layer_->bounds()), root_damage_rect);
         break;
       case 1:
       case 2:
       case 3:
-        EXPECT_RECT_EQ(gfx::Rect(child_layer_->bounds()), root_damage_rect);
+        EXPECT_EQ(gfx::Rect(child_layer_->bounds()), root_damage_rect);
         break;
       default:
         NOTREACHED();
@@ -1269,8 +1269,7 @@
     ASSERT_EQ(2u, root->render_surface()->layer_list().size());
 
     // The root render surface is the size of the viewport.
-    EXPECT_RECT_EQ(gfx::Rect(0, 0, 60, 60),
-                   root->render_surface()->content_rect());
+    EXPECT_EQ(gfx::Rect(0, 0, 60, 60), root->render_surface()->content_rect());
 
     // The max tiling scale of the child should be scaled.
     EXPECT_FLOAT_EQ(1.5f, child->MaximumTilingContentsScale());
@@ -2643,10 +2642,10 @@
     num_commits_++;
     if (num_commits_ == 1) {
       LayerImpl* root_layer = host_impl->active_tree()->root_layer();
-      EXPECT_SIZE_EQ(gfx::Size(1, 1), root_layer->bounds());
+      EXPECT_EQ(gfx::Size(1, 1), root_layer->bounds());
     } else {
       LayerImpl* root_layer = host_impl->active_tree()->root_layer();
-      EXPECT_SIZE_EQ(gfx::Size(2, 2), root_layer->bounds());
+      EXPECT_EQ(gfx::Size(2, 2), root_layer->bounds());
       EndTest();
     }
   }
@@ -2769,7 +2768,7 @@
     CHECK_EQ(DrawQuad::IO_SURFACE_CONTENT, quad->material);
     const IOSurfaceDrawQuad* io_surface_draw_quad =
         IOSurfaceDrawQuad::MaterialCast(quad);
-    EXPECT_SIZE_EQ(io_surface_size_, io_surface_draw_quad->io_surface_size);
+    EXPECT_EQ(io_surface_size_, io_surface_draw_quad->io_surface_size);
     EXPECT_NE(0u, io_surface_draw_quad->io_surface_resource_id);
     EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_RECTANGLE_ARB),
               resource_provider->TargetForTesting(
@@ -4719,6 +4718,62 @@
 
 MULTI_THREAD_TEST_F(LayerTreeHostTestBreakSwapPromise);
 
+class LayerTreeHostTestKeepSwapPromise : public LayerTreeTest {
+ public:
+  LayerTreeHostTestKeepSwapPromise() {}
+
+  void BeginTest() override {
+    layer_ = SolidColorLayer::Create();
+    layer_->SetIsDrawable(true);
+    layer_->SetBounds(gfx::Size(10, 10));
+    layer_tree_host()->SetRootLayer(layer_);
+    gfx::Size bounds(100, 100);
+    layer_tree_host()->SetViewportSize(bounds);
+    PostSetNeedsCommitToMainThread();
+  }
+
+  void DidCommit() override {
+    MainThreadTaskRunner()->PostTask(
+        FROM_HERE, base::Bind(&LayerTreeHostTestKeepSwapPromise::ChangeFrame,
+                              base::Unretained(this)));
+  }
+
+  void ChangeFrame() {
+    switch (layer_tree_host()->source_frame_number()) {
+      case 1:
+        layer_->SetBounds(gfx::Size(10, 11));
+        layer_tree_host()->QueueSwapPromise(
+            make_scoped_ptr(new TestSwapPromise(&swap_promise_result_)));
+        break;
+      case 2:
+        break;
+      default:
+        NOTREACHED();
+        break;
+    }
+  }
+
+  void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, bool result) override {
+    EXPECT_TRUE(result);
+    if (host_impl->active_tree()->source_frame_number() >= 1) {
+      // The commit changes layers so it should cause a swap.
+      base::AutoLock lock(swap_promise_result_.lock);
+      EXPECT_TRUE(swap_promise_result_.did_swap_called);
+      EXPECT_FALSE(swap_promise_result_.did_not_swap_called);
+      EXPECT_TRUE(swap_promise_result_.dtor_called);
+      EndTest();
+    }
+  }
+
+  void AfterTest() override {}
+
+ private:
+  scoped_refptr<Layer> layer_;
+  TestSwapPromiseResult swap_promise_result_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestKeepSwapPromise);
+
 class LayerTreeHostTestBreakSwapPromiseForVisibilityAbortedCommit
     : public LayerTreeHostTest {
  protected:
@@ -4780,17 +4835,9 @@
 
   void BeginMainFrameAbortedOnThread(LayerTreeHostImpl* host_impl,
                                      bool did_handle) override {
+    // This is needed so that the impl-thread state matches main-thread state.
+    host_impl->DidLoseOutputSurface();
     EndTest();
-    // This lets the test finally commit and exit.
-    MainThreadTaskRunner()->PostTask(
-        FROM_HERE,
-        base::Bind(&LayerTreeHostTestBreakSwapPromiseForContextAbortedCommit::
-                       FindOutputSurface,
-                   base::Unretained(this)));
-  }
-
-  void FindOutputSurface() {
-    layer_tree_host()->OnCreateAndInitializeOutputSurfaceAttempted(true);
   }
 
   void AfterTest() override {
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index 3a4d36d..6a88834 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -75,7 +75,8 @@
 
 LayerTreeImpl::LayerTreeImpl(
     LayerTreeHostImpl* layer_tree_host_impl,
-    scoped_refptr<SyncedProperty<ScaleGroup>> page_scale_factor)
+    scoped_refptr<SyncedProperty<ScaleGroup>> page_scale_factor,
+    scoped_refptr<SyncedElasticOverscroll> elastic_overscroll)
     : layer_tree_host_impl_(layer_tree_host_impl),
       source_frame_number_(-1),
       hud_layer_(0),
@@ -83,12 +84,14 @@
       root_layer_scroll_offset_delegate_(NULL),
       background_color_(0),
       has_transparent_background_(false),
+      overscroll_elasticity_layer_(NULL),
       page_scale_layer_(NULL),
       inner_viewport_scroll_layer_(NULL),
       outer_viewport_scroll_layer_(NULL),
       page_scale_factor_(page_scale_factor),
       min_page_scale_factor_(0),
       max_page_scale_factor_(0),
+      elastic_overscroll_(elastic_overscroll),
       scrolling_layer_id_from_previous_tree_(0),
       contents_textures_purged_(false),
       viewport_size_invalid_(false),
@@ -230,6 +233,7 @@
   // tree so only the limits need to be provided.
   target_tree->PushPageScaleFactorAndLimits(nullptr, min_page_scale_factor(),
                                             max_page_scale_factor());
+  target_tree->elastic_overscroll()->PushPendingToActive();
 
   target_tree->pending_page_scale_animation_ =
       pending_page_scale_animation_.Pass();
@@ -428,6 +432,7 @@
   DCHECK(IsActiveTree());
 
   page_scale_factor()->AbortCommit();
+  elastic_overscroll()->AbortCommit();
 
   top_controls_content_offset_ += sent_top_controls_delta_;
   top_controls_delta_ -= sent_top_controls_delta_;
@@ -524,8 +529,9 @@
         root_layer(), DrawViewportSize(),
         layer_tree_host_impl_->DrawTransform(), device_scale_factor(),
         current_page_scale_factor(), page_scale_layer,
-        resource_provider()->max_texture_size(), settings().can_use_lcd_text,
-        settings().layers_always_allowed_lcd_text,
+        elastic_overscroll()->Current(IsActiveTree()),
+        overscroll_elasticity_layer_, resource_provider()->max_texture_size(),
+        settings().can_use_lcd_text, settings().layers_always_allowed_lcd_text,
         can_render_to_separate_surface,
         settings().layer_transforms_should_scale_layer_contents,
         &render_surface_layer_list_, render_surface_layer_list_id_);
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h
index d16234b..46b8312 100644
--- a/cc/trees/layer_tree_impl.h
+++ b/cc/trees/layer_tree_impl.h
@@ -50,14 +50,16 @@
 struct SelectionHandle;
 
 typedef std::list<UIResourceRequest> UIResourceRequestQueue;
+typedef SyncedProperty<AdditionGroup<gfx::Vector2dF>> SyncedElasticOverscroll;
 
 class CC_EXPORT LayerTreeImpl {
  public:
   static scoped_ptr<LayerTreeImpl> create(
       LayerTreeHostImpl* layer_tree_host_impl,
-      scoped_refptr<SyncedProperty<ScaleGroup>> page_scale_factor) {
-    return make_scoped_ptr(
-        new LayerTreeImpl(layer_tree_host_impl, page_scale_factor));
+      scoped_refptr<SyncedProperty<ScaleGroup>> page_scale_factor,
+      scoped_refptr<SyncedElasticOverscroll> elastic_overscroll) {
+    return make_scoped_ptr(new LayerTreeImpl(
+        layer_tree_host_impl, page_scale_factor, elastic_overscroll));
   }
   virtual ~LayerTreeImpl();
 
@@ -179,6 +181,13 @@
   SyncedProperty<ScaleGroup>* page_scale_factor();
   const SyncedProperty<ScaleGroup>* page_scale_factor() const;
 
+  SyncedElasticOverscroll* elastic_overscroll() {
+    return elastic_overscroll_.get();
+  }
+  const SyncedElasticOverscroll* elastic_overscroll() const {
+    return elastic_overscroll_.get();
+  }
+
   // Updates draw properties and render surface layer list, as well as tile
   // priorities. Returns false if it was unable to update.
   bool UpdateDrawProperties();
@@ -325,7 +334,8 @@
  protected:
   explicit LayerTreeImpl(
       LayerTreeHostImpl* layer_tree_host_impl,
-      scoped_refptr<SyncedProperty<ScaleGroup>> page_scale_factor);
+      scoped_refptr<SyncedProperty<ScaleGroup>> page_scale_factor,
+      scoped_refptr<SyncedElasticOverscroll> elastic_overscroll);
   void ReleaseResourcesRecursive(LayerImpl* current);
   float ClampPageScaleFactorToLimits(float page_scale_factor) const;
   void PushPageScaleFactorAndLimits(const float* page_scale_factor,
@@ -360,6 +370,8 @@
   float min_page_scale_factor_;
   float max_page_scale_factor_;
 
+  scoped_refptr<SyncedElasticOverscroll> elastic_overscroll_;
+
   typedef base::hash_map<int, LayerImpl*> LayerIdMap;
   LayerIdMap layer_id_map_;
 
diff --git a/cc/trees/layer_tree_impl_unittest.cc b/cc/trees/layer_tree_impl_unittest.cc
index 2131d4c..78d72de 100644
--- a/cc/trees/layer_tree_impl_unittest.cc
+++ b/cc/trees/layer_tree_impl_unittest.cc
@@ -463,7 +463,7 @@
   // its layout size is 50x50, positioned at 25x25.
   LayerImpl* test_layer =
       host_impl().active_tree()->root_layer()->children()[0];
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), test_layer->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 100, 100), test_layer->visible_content_rect());
   ASSERT_EQ(1u, RenderSurfaceLayerList().size());
   ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
 
@@ -1697,7 +1697,7 @@
   // its layout size is 50x50, positioned at 25x25.
   LayerImpl* test_layer =
       host_impl().active_tree()->root_layer()->children()[0];
-  EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), test_layer->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(0, 0, 100, 100), test_layer->visible_content_rect());
   ASSERT_EQ(1u, RenderSurfaceLayerList().size());
   ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
 
@@ -1812,8 +1812,8 @@
   ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
 
   // Check whether the child layer fits into the root after scaled.
-  EXPECT_RECT_EQ(gfx::Rect(test_layer->content_bounds()),
-                 test_layer->visible_content_rect());
+  EXPECT_EQ(gfx::Rect(test_layer->content_bounds()),
+            test_layer->visible_content_rect());
 
   // Hit checking for a point outside the layer should return a null pointer
   // (the root layer does not draw content, so it will not be tested either).
diff --git a/cc/trees/layer_tree_settings.cc b/cc/trees/layer_tree_settings.cc
index ab44a66..508e7ea 100644
--- a/cc/trees/layer_tree_settings.cc
+++ b/cc/trees/layer_tree_settings.cc
@@ -4,6 +4,7 @@
 
 #include "cc/trees/layer_tree_settings.h"
 
+#include <GLES2/gl2.h>
 #include <limits>
 
 #include "base/command_line.h"
@@ -60,13 +61,12 @@
       strict_layer_property_change_checking(false),
       use_one_copy(false),
       use_zero_copy(false),
-      use_image_external(false),
+      use_image_texture_target(GL_TEXTURE_2D),
       ignore_root_layer_flings(false),
       scheduled_raster_task_limit(32),
       use_occlusion_for_tile_prioritization(false),
       record_full_layer(false),
-      use_display_lists(false),
-      main_thread_should_always_be_low_latency(false) {
+      use_display_lists(false) {
 }
 
 LayerTreeSettings::~LayerTreeSettings() {}
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index 2660dae..1892b39 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -72,13 +72,12 @@
   bool strict_layer_property_change_checking;
   bool use_one_copy;
   bool use_zero_copy;
-  bool use_image_external;
+  unsigned use_image_texture_target;
   bool ignore_root_layer_flings;
   size_t scheduled_raster_task_limit;
   bool use_occlusion_for_tile_prioritization;
   bool record_full_layer;
   bool use_display_lists;
-  bool main_thread_should_always_be_low_latency;
 
   LayerTreeDebugState initial_debug_state;
 };
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index 9a13457..dfce808 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -90,6 +90,7 @@
   if (layer_tree_host_->settings().single_thread_proxy_scheduler &&
       !scheduler_on_impl_thread_) {
     SchedulerSettings scheduler_settings(layer_tree_host_->settings());
+    scheduler_settings.main_thread_should_always_be_low_latency = true;
     scheduler_on_impl_thread_ =
         Scheduler::Create(this,
                           scheduler_settings,
diff --git a/gpu/GLES2/gl2chromium_autogen.h b/gpu/GLES2/gl2chromium_autogen.h
index f7b0c5d..454c67b 100644
--- a/gpu/GLES2/gl2chromium_autogen.h
+++ b/gpu/GLES2/gl2chromium_autogen.h
@@ -98,6 +98,8 @@
 #define glGetVertexAttribiv GLES2_GET_FUN(GetVertexAttribiv)
 #define glGetVertexAttribPointerv GLES2_GET_FUN(GetVertexAttribPointerv)
 #define glHint GLES2_GET_FUN(Hint)
+#define glInvalidateFramebuffer GLES2_GET_FUN(InvalidateFramebuffer)
+#define glInvalidateSubFramebuffer GLES2_GET_FUN(InvalidateSubFramebuffer)
 #define glIsBuffer GLES2_GET_FUN(IsBuffer)
 #define glIsEnabled GLES2_GET_FUN(IsEnabled)
 #define glIsFramebuffer GLES2_GET_FUN(IsFramebuffer)
@@ -109,6 +111,7 @@
 #define glLinkProgram GLES2_GET_FUN(LinkProgram)
 #define glPixelStorei GLES2_GET_FUN(PixelStorei)
 #define glPolygonOffset GLES2_GET_FUN(PolygonOffset)
+#define glReadBuffer GLES2_GET_FUN(ReadBuffer)
 #define glReadPixels GLES2_GET_FUN(ReadPixels)
 #define glReleaseShaderCompiler GLES2_GET_FUN(ReleaseShaderCompiler)
 #define glRenderbufferStorage GLES2_GET_FUN(RenderbufferStorage)
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index 7a3db58..b057477 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -2017,6 +2017,20 @@
     'result': ['SizedResult<GLuint>'],
     'client_test': False,
   },
+  'InvalidateFramebuffer': {
+    'type': 'PUTn',
+    'count': 1,
+    'client_test': False,
+    'unit_test': False,
+    'unsafe': True,
+  },
+  'InvalidateSubFramebuffer': {
+    'type': 'PUTn',
+    'count': 1,
+    'client_test': False,
+    'unit_test': False,
+    'unsafe': True,
+  },
   'IsBuffer': {
     'type': 'Is',
     'decoder_func': 'DoIsBuffer',
@@ -2133,6 +2147,9 @@
     'unit_test': False,
     'extension_flag': 'multisampled_render_to_texture',
   },
+  'ReadBuffer': {
+    'unsafe': True,
+  },
   'ReadPixels': {
     'cmd_comment':
         '// ReadPixels has the result separated from the pixel buffer so that\n'
@@ -2742,8 +2759,6 @@
   'DiscardFramebufferEXT': {
     'type': 'PUTn',
     'count': 1,
-    'cmd_args': 'GLenum target, GLsizei count, '
-        'const GLenum* attachments',
     'decoder_func': 'DoDiscardFramebufferEXT',
     'unit_test': False,
     'client_test': False,
@@ -3132,12 +3147,10 @@
     self.WriteServiceHandlerFunctionHeader(func, file)
     self.WriteHandlerExtensionCheck(func, file)
     self.WriteHandlerDeferReadWrite(func, file);
-    last_arg = func.GetLastOriginalArg()
-    all_but_last_arg = func.GetOriginalArgs()[:-1]
-    for arg in all_but_last_arg:
+    for arg in func.GetOriginalArgs():
+      if arg.IsPointer():
+        self.WriteGetDataSizeCode(func, file)
       arg.WriteGetCode(file)
-    self.WriteGetDataSizeCode(func, file)
-    last_arg.WriteGetCode(file)
     func.WriteHandlerValidation(file)
     func.WriteHandlerImplementation(file)
     file.Write("  return error::kNoError;\n")
@@ -3149,12 +3162,10 @@
     self.WriteServiceHandlerFunctionHeader(func, file)
     self.WriteHandlerExtensionCheck(func, file)
     self.WriteHandlerDeferReadWrite(func, file);
-    last_arg = func.GetLastOriginalArg()
-    all_but_last_arg = func.GetOriginalArgs()[:-1]
-    for arg in all_but_last_arg:
+    for arg in func.GetOriginalArgs():
+      if arg.IsPointer():
+        self.WriteGetDataSizeCode(func, file)
       arg.WriteGetCode(file)
-    self.WriteGetDataSizeCode(func, file)
-    last_arg.WriteGetCode(file)
     func.WriteHandlerValidation(file)
     func.WriteHandlerImplementation(file)
     file.Write("  return error::kNoError;\n")
@@ -4224,9 +4235,7 @@
     SetGLError(GL_INVALID_OPERATION, "%(name)s\", \"%(id)s reserved id");
     return;
   }
-  if (%(name)sHelper(%(arg_string)s)) {
-    helper_->%(name)s(%(arg_string)s);
-  }
+  %(name)sHelper(%(arg_string)s);
   CheckGLError();
 }
 
@@ -5526,13 +5535,13 @@
     file.Write("  GPU_CLIENT_SINGLE_THREAD_CHECK();\n")
     func.WriteDestinationInitalizationValidation(file)
     self.WriteClientGLCallLog(func, file)
-    last_arg_name = func.GetLastOriginalArg().name
+    last_pointer_name = func.GetLastOriginalPointerArg().name
     file.Write("""  GPU_CLIENT_LOG_CODE_BLOCK({
     for (GLsizei i = 0; i < count; ++i) {
 """)
     values_str = ' << ", " << '.join(
         ["%s[%d + i * %d]" % (
-            last_arg_name, ndx, self.GetArrayCount(func)) for ndx in range(
+            last_pointer_name, ndx, self.GetArrayCount(func)) for ndx in range(
                 0, self.GetArrayCount(func))])
     file.Write('       GPU_CLIENT_LOG("  " << i << ": " << %s);\n' % values_str)
     file.Write("    }\n  });\n")
@@ -5560,18 +5569,26 @@
       data[ii][jj] = static_cast<%(type)s>(ii * %(count)d + jj);
     }
   }
-  expected.cmd.Init(%(cmd_args)s, &data[0][0]);
-  gl_->%(name)s(%(args)s, &data[0][0]);
+  expected.cmd.Init(%(cmd_args)s);
+  gl_->%(name)s(%(args)s);
   EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
 }
 """
-    cmd_arg_strings = [
-      arg.GetValidClientSideCmdArg(func) for arg in func.GetCmdArgs()[0:-2]
-    ]
+    cmd_arg_strings = []
+    for arg in func.GetCmdArgs():
+      if arg.name.endswith("_shm_id"):
+        cmd_arg_strings.append("&data[0][0]")
+      elif arg.name.endswith("_shm_offset"):
+        continue
+      else:
+        cmd_arg_strings.append(arg.GetValidClientSideCmdArg(func))
     gl_arg_strings = []
     count_param = 0
-    for arg in func.GetOriginalArgs()[0:-1]:
-      valid_value = arg.GetValidClientSideArg(func)
+    for arg in func.GetOriginalArgs():
+      if arg.IsPointer():
+        valid_value = "&data[0][0]"
+      else:
+        valid_value = arg.GetValidClientSideArg(func)
       gl_arg_strings.append(valid_value)
       if arg.name == "count":
         count_param = int(valid_value)
@@ -5600,7 +5617,7 @@
       data[ii][jj] = static_cast<%(type)s>(ii * %(count)d + jj);
     }
   }
-  gl_->%(name)s(%(args)s, &data[0][0]);
+  gl_->%(name)s(%(args)s);
   EXPECT_TRUE(NoCommandsWritten());
   EXPECT_EQ(%(gl_error)s, CheckError());
 }
@@ -5608,9 +5625,11 @@
     for invalid_arg in constants:
       gl_arg_strings = []
       invalid = invalid_arg.GetInvalidArg(func)
-      for arg in func.GetOriginalArgs()[0:-1]:
+      for arg in func.GetOriginalArgs():
         if arg is invalid_arg:
           gl_arg_strings.append(invalid[0])
+        elif arg.IsPointer():
+          gl_arg_strings.append("&data[0][0]")
         else:
           valid_value = arg.GetValidClientSideArg(func)
           gl_arg_strings.append(valid_value)
@@ -5653,28 +5672,24 @@
 
   def WriteImmediateCmdInit(self, func, file):
     """Overrriden from TypeHandler."""
-    last_arg = func.GetLastOriginalArg()
-    file.Write("  void Init(%s, %s _%s) {\n" %
-               (func.MakeTypedCmdArgString("_"),
-                last_arg.type, last_arg.name))
+    file.Write("  void Init(%s) {\n" %
+               func.MakeTypedInitString("_"))
     file.Write("    SetHeader(_count);\n")
     args = func.GetCmdArgs()
     for arg in args:
       file.Write("    %s = _%s;\n" % (arg.name, arg.name))
     file.Write("    memcpy(ImmediateDataAddress(this),\n")
-    file.Write("           _%s, ComputeDataSize(_count));\n" % last_arg.name)
+    pointer_arg = func.GetLastOriginalPointerArg()
+    file.Write("           _%s, ComputeDataSize(_count));\n" % pointer_arg.name)
     file.Write("  }\n")
     file.Write("\n")
 
   def WriteImmediateCmdSet(self, func, file):
     """Overrriden from TypeHandler."""
-    last_arg = func.GetLastOriginalArg()
-    copy_args = func.MakeCmdArgString("_", False)
-    file.Write("  void* Set(void* cmd%s, %s _%s) {\n" %
-               (func.MakeTypedCmdArgString("_", True),
-                last_arg.type, last_arg.name))
-    file.Write("    static_cast<ValueType*>(cmd)->Init(%s, _%s);\n" %
-               (copy_args, last_arg.name))
+    file.Write("  void* Set(void* cmd%s) {\n" %
+               func.MakeTypedInitString("_", True))
+    file.Write("    static_cast<ValueType*>(cmd)->Init(%s);\n" %
+               func.MakeInitString("_"))
     file.Write("    const uint32_t size = ComputeSize(_count);\n")
     file.Write("    return NextImmediateCmdAddressTotalSize<ValueType>("
                "cmd, size);\n")
@@ -5701,7 +5716,7 @@
 
   def WriteImmediateFormatTest(self, func, file):
     """Overrriden from TypeHandler."""
-    args = func.GetCmdArgs()
+    args = func.GetOriginalArgs()
     count_param = 0
     for arg in args:
       if arg.name == "count":
@@ -5722,13 +5737,20 @@
     file.Write("  void* next_cmd = cmd.Set(\n")
     file.Write("      &cmd")
     for value, arg in enumerate(args):
-      file.Write(",\n      static_cast<%s>(%d)" % (arg.type, value + 1))
-    file.Write(",\n      data);\n")
+      if arg.IsPointer():
+        file.Write(",\n      data")
+      elif arg.IsConstant():
+        continue
+      else:
+        file.Write(",\n      static_cast<%s>(%d)" % (arg.type, value + 1))
+    file.Write(");\n")
     file.Write("  EXPECT_EQ(static_cast<uint32_t>(cmds::%s::kCmdId),\n" %
                func.name)
     file.Write("            cmd.header.command);\n")
     file.Write("  EXPECT_EQ(kExpectedCmdSize, cmd.header.size * 4u);\n")
     for value, arg in enumerate(args):
+      if arg.IsPointer() or arg.IsConstant():
+        continue
       file.Write("  EXPECT_EQ(static_cast<%s>(%d), cmd.%s);\n" %
                  (arg.type, value + 1, arg.name))
     file.Write("  CheckBytesWrittenMatchesExpectedSize(\n")
@@ -6978,6 +7000,13 @@
 
     self.num_pointer_args = sum(
       [1 for arg in self.args_for_cmds if arg.IsPointer()])
+    if self.num_pointer_args > 0:
+      for arg in reversed(self.original_args):
+        if arg.IsPointer():
+          self.last_original_pointer_arg = arg
+          break
+    else:
+      self.last_original_pointer_arg = None
     self.info = info
     self.type_handler = self.type_handlers[info['type']]
     self.can_auto_generate = (self.num_pointer_args == 0 and
@@ -7124,6 +7153,9 @@
     """Gets the last original argument to this function."""
     return self.original_args[len(self.original_args) - 1]
 
+  def GetLastOriginalPointerArg(self):
+    return self.last_original_pointer_arg
+
   def __MaybePrependComma(self, arg_string, add_comma):
     """Adds a comma if arg_string is not empty and add_comma is true."""
     comma = ""
diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h
index 727d39a..c1a1114 100644
--- a/gpu/command_buffer/client/gles2_c_lib_autogen.h
+++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h
@@ -378,6 +378,21 @@
 void GLES2Hint(GLenum target, GLenum mode) {
   gles2::GetGLContext()->Hint(target, mode);
 }
+void GLES2InvalidateFramebuffer(GLenum target,
+                                GLsizei count,
+                                const GLenum* attachments) {
+  gles2::GetGLContext()->InvalidateFramebuffer(target, count, attachments);
+}
+void GLES2InvalidateSubFramebuffer(GLenum target,
+                                   GLsizei count,
+                                   const GLenum* attachments,
+                                   GLint x,
+                                   GLint y,
+                                   GLsizei width,
+                                   GLsizei height) {
+  gles2::GetGLContext()->InvalidateSubFramebuffer(target, count, attachments, x,
+                                                  y, width, height);
+}
 GLboolean GLES2IsBuffer(GLuint buffer) {
   return gles2::GetGLContext()->IsBuffer(buffer);
 }
@@ -411,6 +426,9 @@
 void GLES2PolygonOffset(GLfloat factor, GLfloat units) {
   gles2::GetGLContext()->PolygonOffset(factor, units);
 }
+void GLES2ReadBuffer(GLenum src) {
+  gles2::GetGLContext()->ReadBuffer(src);
+}
 void GLES2ReadPixels(GLint x,
                      GLint y,
                      GLsizei width,
@@ -1415,6 +1433,14 @@
      reinterpret_cast<GLES2FunctionPointer>(glHint),
     },
     {
+     "glInvalidateFramebuffer",
+     reinterpret_cast<GLES2FunctionPointer>(glInvalidateFramebuffer),
+    },
+    {
+     "glInvalidateSubFramebuffer",
+     reinterpret_cast<GLES2FunctionPointer>(glInvalidateSubFramebuffer),
+    },
+    {
      "glIsBuffer",
      reinterpret_cast<GLES2FunctionPointer>(glIsBuffer),
     },
@@ -1459,6 +1485,10 @@
      reinterpret_cast<GLES2FunctionPointer>(glPolygonOffset),
     },
     {
+     "glReadBuffer",
+     reinterpret_cast<GLES2FunctionPointer>(glReadBuffer),
+    },
+    {
      "glReadPixels",
      reinterpret_cast<GLES2FunctionPointer>(glReadPixels),
     },
diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
index b8e3b66..dc43a41 100644
--- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
+++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
@@ -813,6 +813,36 @@
   }
 }
 
+void InvalidateFramebufferImmediate(GLenum target,
+                                    GLsizei count,
+                                    const GLenum* attachments) {
+  const uint32_t size =
+      gles2::cmds::InvalidateFramebufferImmediate::ComputeSize(count);
+  gles2::cmds::InvalidateFramebufferImmediate* c =
+      GetImmediateCmdSpaceTotalSize<
+          gles2::cmds::InvalidateFramebufferImmediate>(size);
+  if (c) {
+    c->Init(target, count, attachments);
+  }
+}
+
+void InvalidateSubFramebufferImmediate(GLenum target,
+                                       GLsizei count,
+                                       const GLenum* attachments,
+                                       GLint x,
+                                       GLint y,
+                                       GLsizei width,
+                                       GLsizei height) {
+  const uint32_t size =
+      gles2::cmds::InvalidateSubFramebufferImmediate::ComputeSize(count);
+  gles2::cmds::InvalidateSubFramebufferImmediate* c =
+      GetImmediateCmdSpaceTotalSize<
+          gles2::cmds::InvalidateSubFramebufferImmediate>(size);
+  if (c) {
+    c->Init(target, count, attachments, x, y, width, height);
+  }
+}
+
 void IsBuffer(GLuint buffer,
               uint32_t result_shm_id,
               uint32_t result_shm_offset) {
@@ -902,6 +932,13 @@
   }
 }
 
+void ReadBuffer(GLenum src) {
+  gles2::cmds::ReadBuffer* c = GetCmdSpace<gles2::cmds::ReadBuffer>();
+  if (c) {
+    c->Init(src);
+  }
+}
+
 void ReadPixels(GLint x,
                 GLint y,
                 GLsizei width,
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index 1916e7d..4c148e9 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -2314,7 +2314,7 @@
 // the old model but possibly not true in the new model if another context has
 // deleted the resource.
 
-bool GLES2Implementation::BindBufferHelper(
+void GLES2Implementation::BindBufferHelper(
     GLenum target, GLuint buffer_id) {
   // TODO(gman): See note #1 above.
   bool changed = false;
@@ -2340,11 +2340,19 @@
   }
   // TODO(gman): There's a bug here. If the target is invalid the ID will not be
   // used even though it's marked it as used here.
-  GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(buffer_id);
-  return changed;
+  if (changed) {
+    GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
+        this, target, buffer_id, &GLES2Implementation::BindBufferStub);
+  }
 }
 
-bool GLES2Implementation::BindFramebufferHelper(
+void GLES2Implementation::BindBufferStub(GLenum target, GLuint buffer) {
+  helper_->BindBuffer(target, buffer);
+  if (share_group_->bind_generates_resource())
+    helper_->CommandBufferHelper::Flush();
+}
+
+void GLES2Implementation::BindFramebufferHelper(
     GLenum target, GLuint framebuffer) {
   // TODO(gman): See note #1 above.
   bool changed = false;
@@ -2360,7 +2368,7 @@
     case GL_READ_FRAMEBUFFER:
       if (!IsChromiumFramebufferMultisampleAvailable()) {
         SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
-        return false;
+        return;
       }
       if (bound_read_framebuffer_ != framebuffer) {
         bound_read_framebuffer_ = framebuffer;
@@ -2370,7 +2378,7 @@
     case GL_DRAW_FRAMEBUFFER:
       if (!IsChromiumFramebufferMultisampleAvailable()) {
         SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
-        return false;
+        return;
       }
       if (bound_framebuffer_ != framebuffer) {
         bound_framebuffer_ = framebuffer;
@@ -2379,13 +2387,23 @@
       break;
     default:
       SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
-      return false;
+      return;
   }
-  GetIdHandler(id_namespaces::kFramebuffers)->MarkAsUsedForBind(framebuffer);
-  return changed;
+
+  if (changed) {
+    GetIdHandler(id_namespaces::kFramebuffers)->MarkAsUsedForBind(
+        this, target, framebuffer, &GLES2Implementation::BindFramebufferStub);
+  }
 }
 
-bool GLES2Implementation::BindRenderbufferHelper(
+void GLES2Implementation::BindFramebufferStub(GLenum target,
+                                              GLuint framebuffer) {
+  helper_->BindFramebuffer(target, framebuffer);
+  if (share_group_->bind_generates_resource())
+    helper_->CommandBufferHelper::Flush();
+}
+
+void GLES2Implementation::BindRenderbufferHelper(
     GLenum target, GLuint renderbuffer) {
   // TODO(gman): See note #1 above.
   bool changed = false;
@@ -2402,11 +2420,21 @@
   }
   // TODO(gman): There's a bug here. If the target is invalid the ID will not be
   // used even though it's marked it as used here.
-  GetIdHandler(id_namespaces::kRenderbuffers)->MarkAsUsedForBind(renderbuffer);
-  return changed;
+  if (changed) {
+    GetIdHandler(id_namespaces::kRenderbuffers)->MarkAsUsedForBind(
+        this, target, renderbuffer,
+        &GLES2Implementation::BindRenderbufferStub);
+  }
 }
 
-bool GLES2Implementation::BindTextureHelper(GLenum target, GLuint texture) {
+void GLES2Implementation::BindRenderbufferStub(GLenum target,
+                                               GLuint renderbuffer) {
+  helper_->BindRenderbuffer(target, renderbuffer);
+  if (share_group_->bind_generates_resource())
+    helper_->CommandBufferHelper::Flush();
+}
+
+void GLES2Implementation::BindTextureHelper(GLenum target, GLuint texture) {
   // TODO(gman): See note #1 above.
   // TODO(gman): Change this to false once we figure out why it's failing
   //     on daisy.
@@ -2437,26 +2465,37 @@
   }
   // TODO(gman): There's a bug here. If the target is invalid the ID will not be
   // used. even though it's marked it as used here.
-  GetIdHandler(id_namespaces::kTextures)->MarkAsUsedForBind(texture);
-  return changed;
+  if (changed) {
+    GetIdHandler(id_namespaces::kTextures)->MarkAsUsedForBind(
+        this, target, texture, &GLES2Implementation::BindTextureStub);
+  }
 }
 
-bool GLES2Implementation::BindVertexArrayOESHelper(GLuint array) {
+void GLES2Implementation::BindTextureStub(GLenum target, GLuint texture) {
+  helper_->BindTexture(target, texture);
+  if (share_group_->bind_generates_resource())
+    helper_->CommandBufferHelper::Flush();
+}
+
+void GLES2Implementation::BindVertexArrayOESHelper(GLuint array) {
   // TODO(gman): See note #1 above.
   bool changed = false;
-  if (!vertex_array_object_manager_->BindVertexArray(array, &changed)) {
+  if (vertex_array_object_manager_->BindVertexArray(array, &changed)) {
+    if (changed) {
+      // Unlike other BindXXXHelpers we don't call MarkAsUsedForBind
+      // because unlike other resources VertexArrayObject ids must
+      // be generated by GenVertexArrays. A random id to Bind will not
+      // generate a new object.
+      helper_->BindVertexArrayOES(array);
+    }
+  } else {
     SetGLError(
         GL_INVALID_OPERATION, "glBindVertexArrayOES",
         "id was not generated with glGenVertexArrayOES");
   }
-  // Unlike other BindXXXHelpers we don't call MarkAsUsedForBind
-  // because unlike other resources VertexArrayObject ids must
-  // be generated by GenVertexArrays. A random id to Bind will not
-  // generate a new object.
-  return changed;
 }
 
-bool GLES2Implementation::BindValuebufferCHROMIUMHelper(GLenum target,
+void GLES2Implementation::BindValuebufferCHROMIUMHelper(GLenum target,
                                                         GLuint valuebuffer) {
   bool changed = false;
   switch (target) {
@@ -2472,17 +2511,25 @@
   }
   // TODO(gman): There's a bug here. If the target is invalid the ID will not be
   // used even though it's marked it as used here.
-  GetIdHandler(id_namespaces::kValuebuffers)->MarkAsUsedForBind(valuebuffer);
-  return changed;
+  if (changed) {
+    GetIdHandler(id_namespaces::kValuebuffers)->MarkAsUsedForBind(
+        this, target, valuebuffer,
+        &GLES2Implementation::BindValuebufferCHROMIUMStub);
+  }
 }
 
-bool GLES2Implementation::UseProgramHelper(GLuint program) {
-  bool changed = false;
+void GLES2Implementation::BindValuebufferCHROMIUMStub(GLenum target,
+                                                      GLuint valuebuffer) {
+  helper_->BindValuebufferCHROMIUM(target, valuebuffer);
+  if (share_group_->bind_generates_resource())
+    helper_->CommandBufferHelper::Flush();
+}
+
+void GLES2Implementation::UseProgramHelper(GLuint program) {
   if (current_program_ != program) {
     current_program_ = program;
-    changed = true;
+    helper_->UseProgram(program);
   }
-  return changed;
 }
 
 bool GLES2Implementation::IsBufferReservedId(GLuint id) {
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h
index 77b8a87..df6e014 100644
--- a/gpu/command_buffer/client/gles2_implementation.h
+++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -432,13 +432,19 @@
   bool IsProgramReservedId(GLuint id) { return false; }
   bool IsValuebufferReservedId(GLuint id) { return false; }
 
-  bool BindBufferHelper(GLenum target, GLuint texture);
-  bool BindFramebufferHelper(GLenum target, GLuint texture);
-  bool BindRenderbufferHelper(GLenum target, GLuint texture);
-  bool BindTextureHelper(GLenum target, GLuint texture);
-  bool BindVertexArrayOESHelper(GLuint array);
-  bool BindValuebufferCHROMIUMHelper(GLenum target, GLuint valuebuffer);
-  bool UseProgramHelper(GLuint program);
+  void BindBufferHelper(GLenum target, GLuint buffer);
+  void BindFramebufferHelper(GLenum target, GLuint framebuffer);
+  void BindRenderbufferHelper(GLenum target, GLuint renderbuffer);
+  void BindTextureHelper(GLenum target, GLuint texture);
+  void BindVertexArrayOESHelper(GLuint array);
+  void BindValuebufferCHROMIUMHelper(GLenum target, GLuint valuebuffer);
+  void UseProgramHelper(GLuint program);
+
+  void BindBufferStub(GLenum target, GLuint buffer);
+  void BindFramebufferStub(GLenum target, GLuint framebuffer);
+  void BindRenderbufferStub(GLenum target, GLuint renderbuffer);
+  void BindTextureStub(GLenum target, GLuint texture);
+  void BindValuebufferCHROMIUMStub(GLenum target, GLuint valuebuffer);
 
   void GenBuffersHelper(GLsizei n, const GLuint* buffers);
   void GenFramebuffersHelper(GLsizei n, const GLuint* framebuffers);
diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h
index 66cfcef..48bccd5 100644
--- a/gpu/command_buffer/client/gles2_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_autogen.h
@@ -278,6 +278,18 @@
 
 void Hint(GLenum target, GLenum mode) override;
 
+void InvalidateFramebuffer(GLenum target,
+                           GLsizei count,
+                           const GLenum* attachments) override;
+
+void InvalidateSubFramebuffer(GLenum target,
+                              GLsizei count,
+                              const GLenum* attachments,
+                              GLint x,
+                              GLint y,
+                              GLsizei width,
+                              GLsizei height) override;
+
 GLboolean IsBuffer(GLuint buffer) override;
 
 GLboolean IsEnabled(GLenum cap) override;
@@ -300,6 +312,8 @@
 
 void PolygonOffset(GLfloat factor, GLfloat units) override;
 
+void ReadBuffer(GLenum src) override;
+
 void ReadPixels(GLint x,
                 GLint y,
                 GLsizei width,
diff --git a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
index d67e7ed..d7a45ce 100644
--- a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
@@ -30,9 +30,7 @@
     SetGLError(GL_INVALID_OPERATION, "BindBuffer", "buffer reserved id");
     return;
   }
-  if (BindBufferHelper(target, buffer)) {
-    helper_->BindBuffer(target, buffer);
-  }
+  BindBufferHelper(target, buffer);
   CheckGLError();
 }
 
@@ -46,9 +44,7 @@
                "framebuffer reserved id");
     return;
   }
-  if (BindFramebufferHelper(target, framebuffer)) {
-    helper_->BindFramebuffer(target, framebuffer);
-  }
+  BindFramebufferHelper(target, framebuffer);
   CheckGLError();
 }
 
@@ -62,9 +58,7 @@
                "renderbuffer reserved id");
     return;
   }
-  if (BindRenderbufferHelper(target, renderbuffer)) {
-    helper_->BindRenderbuffer(target, renderbuffer);
-  }
+  BindRenderbufferHelper(target, renderbuffer);
   CheckGLError();
 }
 
@@ -77,9 +71,7 @@
     SetGLError(GL_INVALID_OPERATION, "BindTexture", "texture reserved id");
     return;
   }
-  if (BindTextureHelper(target, texture)) {
-    helper_->BindTexture(target, texture);
-  }
+  BindTextureHelper(target, texture);
   CheckGLError();
 }
 
@@ -1032,6 +1024,62 @@
   CheckGLError();
 }
 
+void GLES2Implementation::InvalidateFramebuffer(GLenum target,
+                                                GLsizei count,
+                                                const GLenum* attachments) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInvalidateFramebuffer("
+                     << GLES2Util::GetStringFrameBufferTarget(target) << ", "
+                     << count << ", " << static_cast<const void*>(attachments)
+                     << ")");
+  GPU_CLIENT_LOG_CODE_BLOCK({
+    for (GLsizei i = 0; i < count; ++i) {
+      GPU_CLIENT_LOG("  " << i << ": " << attachments[0 + i * 1]);
+    }
+  });
+  if (count < 0) {
+    SetGLError(GL_INVALID_VALUE, "glInvalidateFramebuffer", "count < 0");
+    return;
+  }
+  helper_->InvalidateFramebufferImmediate(target, count, attachments);
+  CheckGLError();
+}
+
+void GLES2Implementation::InvalidateSubFramebuffer(GLenum target,
+                                                   GLsizei count,
+                                                   const GLenum* attachments,
+                                                   GLint x,
+                                                   GLint y,
+                                                   GLsizei width,
+                                                   GLsizei height) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInvalidateSubFramebuffer("
+                     << GLES2Util::GetStringFrameBufferTarget(target) << ", "
+                     << count << ", " << static_cast<const void*>(attachments)
+                     << ", " << x << ", " << y << ", " << width << ", "
+                     << height << ")");
+  GPU_CLIENT_LOG_CODE_BLOCK({
+    for (GLsizei i = 0; i < count; ++i) {
+      GPU_CLIENT_LOG("  " << i << ": " << attachments[0 + i * 1]);
+    }
+  });
+  if (count < 0) {
+    SetGLError(GL_INVALID_VALUE, "glInvalidateSubFramebuffer", "count < 0");
+    return;
+  }
+  if (width < 0) {
+    SetGLError(GL_INVALID_VALUE, "glInvalidateSubFramebuffer", "width < 0");
+    return;
+  }
+  if (height < 0) {
+    SetGLError(GL_INVALID_VALUE, "glInvalidateSubFramebuffer", "height < 0");
+    return;
+  }
+  helper_->InvalidateSubFramebufferImmediate(target, count, attachments, x, y,
+                                             width, height);
+  CheckGLError();
+}
+
 GLboolean GLES2Implementation::IsBuffer(GLuint buffer) {
   GPU_CLIENT_SINGLE_THREAD_CHECK();
   TRACE_EVENT0("gpu", "GLES2Implementation::IsBuffer");
@@ -1157,6 +1205,14 @@
   CheckGLError();
 }
 
+void GLES2Implementation::ReadBuffer(GLenum src) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReadBuffer("
+                     << GLES2Util::GetStringEnum(src) << ")");
+  helper_->ReadBuffer(src);
+  CheckGLError();
+}
+
 void GLES2Implementation::ReleaseShaderCompiler() {
   GPU_CLIENT_SINGLE_THREAD_CHECK();
   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReleaseShaderCompiler("
@@ -1997,9 +2053,7 @@
     SetGLError(GL_INVALID_OPERATION, "UseProgram", "program reserved id");
     return;
   }
-  if (UseProgramHelper(program)) {
-    helper_->UseProgram(program);
-  }
+  UseProgramHelper(program);
   CheckGLError();
 }
 
@@ -2408,9 +2462,7 @@
     SetGLError(GL_INVALID_OPERATION, "BindVertexArrayOES", "array reserved id");
     return;
   }
-  if (BindVertexArrayOESHelper(array)) {
-    helper_->BindVertexArrayOES(array);
-  }
+  BindVertexArrayOESHelper(array);
   CheckGLError();
 }
 
@@ -2558,9 +2610,7 @@
                "valuebuffer reserved id");
     return;
   }
-  if (BindValuebufferCHROMIUMHelper(target, valuebuffer)) {
-    helper_->BindValuebufferCHROMIUM(target, valuebuffer);
-  }
+  BindValuebufferCHROMIUMHelper(target, valuebuffer);
   CheckGLError();
 }
 
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
index f48e9ab..3d0eaa2 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
@@ -810,6 +810,42 @@
   EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
 }
 
+TEST_F(GLES2ImplementationTest, InvalidateFramebuffer) {
+  GLenum data[2][1] = {{0}};
+  struct Cmds {
+    cmds::InvalidateFramebufferImmediate cmd;
+    GLenum data[2][1];
+  };
+
+  Cmds expected;
+  for (int ii = 0; ii < 2; ++ii) {
+    for (int jj = 0; jj < 1; ++jj) {
+      data[ii][jj] = static_cast<GLenum>(ii * 1 + jj);
+    }
+  }
+  expected.cmd.Init(GL_FRAMEBUFFER, 2, &data[0][0]);
+  gl_->InvalidateFramebuffer(GL_FRAMEBUFFER, 2, &data[0][0]);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, InvalidateSubFramebuffer) {
+  GLenum data[2][1] = {{0}};
+  struct Cmds {
+    cmds::InvalidateSubFramebufferImmediate cmd;
+    GLenum data[2][1];
+  };
+
+  Cmds expected;
+  for (int ii = 0; ii < 2; ++ii) {
+    for (int jj = 0; jj < 1; ++jj) {
+      data[ii][jj] = static_cast<GLenum>(ii * 1 + jj);
+    }
+  }
+  expected.cmd.Init(GL_FRAMEBUFFER, 2, &data[0][0], 4, 5, 6, 7);
+  gl_->InvalidateSubFramebuffer(GL_FRAMEBUFFER, 2, &data[0][0], 4, 5, 6, 7);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
 TEST_F(GLES2ImplementationTest, IsBuffer) {
   struct Cmds {
     cmds::IsBuffer cmd;
@@ -987,6 +1023,17 @@
   EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
 }
 
+TEST_F(GLES2ImplementationTest, ReadBuffer) {
+  struct Cmds {
+    cmds::ReadBuffer cmd;
+  };
+  Cmds expected;
+  expected.cmd.Init(1);
+
+  gl_->ReadBuffer(1);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
 TEST_F(GLES2ImplementationTest, ReleaseShaderCompiler) {
   struct Cmds {
     cmds::ReleaseShaderCompiler cmd;
diff --git a/gpu/command_buffer/client/gles2_interface_autogen.h b/gpu/command_buffer/client/gles2_interface_autogen.h
index f8c2707..5970747 100644
--- a/gpu/command_buffer/client/gles2_interface_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_autogen.h
@@ -206,6 +206,16 @@
                                      GLenum pname,
                                      void** pointer) = 0;
 virtual void Hint(GLenum target, GLenum mode) = 0;
+virtual void InvalidateFramebuffer(GLenum target,
+                                   GLsizei count,
+                                   const GLenum* attachments) = 0;
+virtual void InvalidateSubFramebuffer(GLenum target,
+                                      GLsizei count,
+                                      const GLenum* attachments,
+                                      GLint x,
+                                      GLint y,
+                                      GLsizei width,
+                                      GLsizei height) = 0;
 virtual GLboolean IsBuffer(GLuint buffer) = 0;
 virtual GLboolean IsEnabled(GLenum cap) = 0;
 virtual GLboolean IsFramebuffer(GLuint framebuffer) = 0;
@@ -217,6 +227,7 @@
 virtual void LinkProgram(GLuint program) = 0;
 virtual void PixelStorei(GLenum pname, GLint param) = 0;
 virtual void PolygonOffset(GLfloat factor, GLfloat units) = 0;
+virtual void ReadBuffer(GLenum src) = 0;
 virtual void ReadPixels(GLint x,
                         GLint y,
                         GLsizei width,
diff --git a/gpu/command_buffer/client/gles2_interface_stub_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
index 5d8a40a..01a7e07 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
@@ -201,6 +201,16 @@
                              GLenum pname,
                              void** pointer) override;
 void Hint(GLenum target, GLenum mode) override;
+void InvalidateFramebuffer(GLenum target,
+                           GLsizei count,
+                           const GLenum* attachments) override;
+void InvalidateSubFramebuffer(GLenum target,
+                              GLsizei count,
+                              const GLenum* attachments,
+                              GLint x,
+                              GLint y,
+                              GLsizei width,
+                              GLsizei height) override;
 GLboolean IsBuffer(GLuint buffer) override;
 GLboolean IsEnabled(GLenum cap) override;
 GLboolean IsFramebuffer(GLuint framebuffer) override;
@@ -212,6 +222,7 @@
 void LinkProgram(GLuint program) override;
 void PixelStorei(GLenum pname, GLint param) override;
 void PolygonOffset(GLfloat factor, GLfloat units) override;
+void ReadBuffer(GLenum src) override;
 void ReadPixels(GLint x,
                 GLint y,
                 GLsizei width,
diff --git a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
index b4792ca..a5797f0 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
@@ -331,6 +331,20 @@
 }
 void GLES2InterfaceStub::Hint(GLenum /* target */, GLenum /* mode */) {
 }
+void GLES2InterfaceStub::InvalidateFramebuffer(
+    GLenum /* target */,
+    GLsizei /* count */,
+    const GLenum* /* attachments */) {
+}
+void GLES2InterfaceStub::InvalidateSubFramebuffer(
+    GLenum /* target */,
+    GLsizei /* count */,
+    const GLenum* /* attachments */,
+    GLint /* x */,
+    GLint /* y */,
+    GLsizei /* width */,
+    GLsizei /* height */) {
+}
 GLboolean GLES2InterfaceStub::IsBuffer(GLuint /* buffer */) {
   return 0;
 }
@@ -361,6 +375,8 @@
 void GLES2InterfaceStub::PolygonOffset(GLfloat /* factor */,
                                        GLfloat /* units */) {
 }
+void GLES2InterfaceStub::ReadBuffer(GLenum /* src */) {
+}
 void GLES2InterfaceStub::ReadPixels(GLint /* x */,
                                     GLint /* y */,
                                     GLsizei /* width */,
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
index 72860f1..b88ec6a 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
@@ -201,6 +201,16 @@
                              GLenum pname,
                              void** pointer) override;
 void Hint(GLenum target, GLenum mode) override;
+void InvalidateFramebuffer(GLenum target,
+                           GLsizei count,
+                           const GLenum* attachments) override;
+void InvalidateSubFramebuffer(GLenum target,
+                              GLsizei count,
+                              const GLenum* attachments,
+                              GLint x,
+                              GLint y,
+                              GLsizei width,
+                              GLsizei height) override;
 GLboolean IsBuffer(GLuint buffer) override;
 GLboolean IsEnabled(GLenum cap) override;
 GLboolean IsFramebuffer(GLuint framebuffer) override;
@@ -212,6 +222,7 @@
 void LinkProgram(GLuint program) override;
 void PixelStorei(GLenum pname, GLint param) override;
 void PolygonOffset(GLfloat factor, GLfloat units) override;
+void ReadBuffer(GLenum src) override;
 void ReadPixels(GLint x,
                 GLint y,
                 GLsizei width,
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
index 28e6f43..70729c3 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
@@ -577,6 +577,27 @@
   gl_->Hint(target, mode);
 }
 
+void GLES2TraceImplementation::InvalidateFramebuffer(
+    GLenum target,
+    GLsizei count,
+    const GLenum* attachments) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::InvalidateFramebuffer");
+  gl_->InvalidateFramebuffer(target, count, attachments);
+}
+
+void GLES2TraceImplementation::InvalidateSubFramebuffer(
+    GLenum target,
+    GLsizei count,
+    const GLenum* attachments,
+    GLint x,
+    GLint y,
+    GLsizei width,
+    GLsizei height) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::InvalidateSubFramebuffer");
+  gl_->InvalidateSubFramebuffer(target, count, attachments, x, y, width,
+                                height);
+}
+
 GLboolean GLES2TraceImplementation::IsBuffer(GLuint buffer) {
   TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::IsBuffer");
   return gl_->IsBuffer(buffer);
@@ -632,6 +653,11 @@
   gl_->PolygonOffset(factor, units);
 }
 
+void GLES2TraceImplementation::ReadBuffer(GLenum src) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::ReadBuffer");
+  gl_->ReadBuffer(src);
+}
+
 void GLES2TraceImplementation::ReadPixels(GLint x,
                                           GLint y,
                                           GLsizei width,
diff --git a/gpu/command_buffer/client/share_group.cc b/gpu/command_buffer/client/share_group.cc
index c7e3845..b5261ee 100644
--- a/gpu/command_buffer/client/share_group.cc
+++ b/gpu/command_buffer/client/share_group.cc
@@ -67,11 +67,14 @@
   }
 
   // Overridden from IdHandlerInterface.
-  bool MarkAsUsedForBind(GLuint id) override {
-    if (id == 0)
-      return true;
+  bool MarkAsUsedForBind(GLES2Implementation* gl_impl,
+                         GLenum target,
+                         GLuint id,
+                         BindFn bind_fn) override {
     base::AutoLock auto_lock(lock_);
-    return id_allocator_.MarkAsUsed(id);
+    bool result = id ? id_allocator_.MarkAsUsed(id) : true;
+    (gl_impl->*bind_fn)(target, id);
+    return result;
   }
 
   void FreeContext(GLES2Implementation* gl_impl) override {}
@@ -147,13 +150,20 @@
   }
 
   // Overridden from IdHandler.
-  bool MarkAsUsedForBind(GLuint id) override {
+  bool MarkAsUsedForBind(GLES2Implementation* gl_impl,
+                         GLenum target,
+                         GLuint id,
+                         BindFn bind_fn) override {
 #ifndef NDEBUG
     if (id != 0) {
       base::AutoLock auto_lock(lock_);
       DCHECK(id_states_[id - 1] == kIdInUse);
     }
 #endif
+    // StrictIdHandler is used if |bind_generates_resource| is false. In that
+    // case, |bind_fn| will not use Flush() after helper->Bind*(), so it is OK
+    // to call |bind_fn| without holding the lock.
+    (gl_impl->*bind_fn)(target, id);
     return true;
   }
 
@@ -218,7 +228,10 @@
   }
 
   // Overridden from IdHandlerInterface.
-  bool MarkAsUsedForBind(GLuint /* id */) override {
+  bool MarkAsUsedForBind(GLES2Implementation* /* gl_impl */,
+                         GLenum /* target */,
+                         GLuint /* id */,
+                         BindFn /* bind_fn */) override {
     // This is only used for Shaders and Programs which have no bind.
     return false;
   }
diff --git a/gpu/command_buffer/client/share_group.h b/gpu/command_buffer/client/share_group.h
index c66704b..09d960b 100644
--- a/gpu/command_buffer/client/share_group.h
+++ b/gpu/command_buffer/client/share_group.h
@@ -19,6 +19,7 @@
 class ProgramInfoManager;
 
 typedef void (GLES2Implementation::*DeleteFn)(GLsizei n, const GLuint* ids);
+typedef void (GLES2Implementation::*BindFn)(GLenum target, GLuint id);
 
 class ShareGroupContextData {
  public:
@@ -55,7 +56,11 @@
       DeleteFn delete_fn) = 0;
 
   // Marks an id as used for glBind functions. id = 0 does nothing.
-  virtual bool MarkAsUsedForBind(GLuint id) = 0;
+  virtual bool MarkAsUsedForBind(
+      GLES2Implementation* gl_impl,
+      GLenum target,
+      GLuint id,
+      BindFn bind_fn) = 0;
 
   // Called when a context in the share group is destructed.
   virtual void FreeContext(GLES2Implementation* gl_impl) = 0;
diff --git a/gpu/command_buffer/cmd_buffer_functions.txt b/gpu/command_buffer/cmd_buffer_functions.txt
index dc613b9..03b851f 100644
--- a/gpu/command_buffer/cmd_buffer_functions.txt
+++ b/gpu/command_buffer/cmd_buffer_functions.txt
@@ -88,6 +88,8 @@
 GL_APICALL void         GL_APIENTRY glGetVertexAttribiv (GLuint index, GLenumVertexAttribute pname, GLint* params);
 GL_APICALL void         GL_APIENTRY glGetVertexAttribPointerv (GLuint index, GLenumVertexPointer pname, void** pointer);
 GL_APICALL void         GL_APIENTRY glHint (GLenumHintTarget target, GLenumHintMode mode);
+GL_APICALL void         GL_APIENTRY glInvalidateFramebuffer (GLenumFrameBufferTarget target, GLsizeiNotNegative count, const GLenum* attachments);
+GL_APICALL void         GL_APIENTRY glInvalidateSubFramebuffer (GLenumFrameBufferTarget target, GLsizeiNotNegative count, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height);
 GL_APICALL GLboolean    GL_APIENTRY glIsBuffer (GLidBuffer buffer);
 GL_APICALL GLboolean    GL_APIENTRY glIsEnabled (GLenumCapability cap);
 GL_APICALL GLboolean    GL_APIENTRY glIsFramebuffer (GLidFramebuffer framebuffer);
@@ -99,6 +101,7 @@
 GL_APICALL void         GL_APIENTRY glLinkProgram (GLidProgram program);
 GL_APICALL void         GL_APIENTRY glPixelStorei (GLenumPixelStore pname, GLintPixelStoreAlignment param);
 GL_APICALL void         GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units);
+GL_APICALL void         GL_APIENTRY glReadBuffer (GLenum src);
 GL_APICALL void         GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenumReadPixelFormat format, GLenumPixelType type, void* pixels);
 GL_APICALL void         GL_APIENTRY glReleaseShaderCompiler (void);
 GL_APICALL void         GL_APIENTRY glRenderbufferStorage (GLenumRenderBufferTarget target, GLenumRenderBufferFormat internalformat, GLsizei width, GLsizei height);
diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
index c451b98..923d5a1 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
@@ -3962,6 +3962,131 @@
 COMPILE_ASSERT(offsetof(Hint, target) == 4, OffsetOf_Hint_target_not_4);
 COMPILE_ASSERT(offsetof(Hint, mode) == 8, OffsetOf_Hint_mode_not_8);
 
+struct InvalidateFramebufferImmediate {
+  typedef InvalidateFramebufferImmediate ValueType;
+  static const CommandId kCmdId = kInvalidateFramebufferImmediate;
+  static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+  static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeDataSize(GLsizei count) {
+    return static_cast<uint32_t>(sizeof(GLenum) * 1 * count);  // NOLINT
+  }
+
+  static uint32_t ComputeSize(GLsizei count) {
+    return static_cast<uint32_t>(sizeof(ValueType) +
+                                 ComputeDataSize(count));  // NOLINT
+  }
+
+  void SetHeader(GLsizei count) {
+    header.SetCmdByTotalSize<ValueType>(ComputeSize(count));
+  }
+
+  void Init(GLenum _target, GLsizei _count, const GLenum* _attachments) {
+    SetHeader(_count);
+    target = _target;
+    count = _count;
+    memcpy(ImmediateDataAddress(this), _attachments, ComputeDataSize(_count));
+  }
+
+  void* Set(void* cmd,
+            GLenum _target,
+            GLsizei _count,
+            const GLenum* _attachments) {
+    static_cast<ValueType*>(cmd)->Init(_target, _count, _attachments);
+    const uint32_t size = ComputeSize(_count);
+    return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t target;
+  int32_t count;
+};
+
+COMPILE_ASSERT(sizeof(InvalidateFramebufferImmediate) == 12,
+               Sizeof_InvalidateFramebufferImmediate_is_not_12);
+COMPILE_ASSERT(offsetof(InvalidateFramebufferImmediate, header) == 0,
+               OffsetOf_InvalidateFramebufferImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(InvalidateFramebufferImmediate, target) == 4,
+               OffsetOf_InvalidateFramebufferImmediate_target_not_4);
+COMPILE_ASSERT(offsetof(InvalidateFramebufferImmediate, count) == 8,
+               OffsetOf_InvalidateFramebufferImmediate_count_not_8);
+
+struct InvalidateSubFramebufferImmediate {
+  typedef InvalidateSubFramebufferImmediate ValueType;
+  static const CommandId kCmdId = kInvalidateSubFramebufferImmediate;
+  static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+  static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeDataSize(GLsizei count) {
+    return static_cast<uint32_t>(sizeof(GLenum) * 1 * count);  // NOLINT
+  }
+
+  static uint32_t ComputeSize(GLsizei count) {
+    return static_cast<uint32_t>(sizeof(ValueType) +
+                                 ComputeDataSize(count));  // NOLINT
+  }
+
+  void SetHeader(GLsizei count) {
+    header.SetCmdByTotalSize<ValueType>(ComputeSize(count));
+  }
+
+  void Init(GLenum _target,
+            GLsizei _count,
+            const GLenum* _attachments,
+            GLint _x,
+            GLint _y,
+            GLsizei _width,
+            GLsizei _height) {
+    SetHeader(_count);
+    target = _target;
+    count = _count;
+    x = _x;
+    y = _y;
+    width = _width;
+    height = _height;
+    memcpy(ImmediateDataAddress(this), _attachments, ComputeDataSize(_count));
+  }
+
+  void* Set(void* cmd,
+            GLenum _target,
+            GLsizei _count,
+            const GLenum* _attachments,
+            GLint _x,
+            GLint _y,
+            GLsizei _width,
+            GLsizei _height) {
+    static_cast<ValueType*>(cmd)
+        ->Init(_target, _count, _attachments, _x, _y, _width, _height);
+    const uint32_t size = ComputeSize(_count);
+    return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t target;
+  int32_t count;
+  int32_t x;
+  int32_t y;
+  int32_t width;
+  int32_t height;
+};
+
+COMPILE_ASSERT(sizeof(InvalidateSubFramebufferImmediate) == 28,
+               Sizeof_InvalidateSubFramebufferImmediate_is_not_28);
+COMPILE_ASSERT(offsetof(InvalidateSubFramebufferImmediate, header) == 0,
+               OffsetOf_InvalidateSubFramebufferImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(InvalidateSubFramebufferImmediate, target) == 4,
+               OffsetOf_InvalidateSubFramebufferImmediate_target_not_4);
+COMPILE_ASSERT(offsetof(InvalidateSubFramebufferImmediate, count) == 8,
+               OffsetOf_InvalidateSubFramebufferImmediate_count_not_8);
+COMPILE_ASSERT(offsetof(InvalidateSubFramebufferImmediate, x) == 12,
+               OffsetOf_InvalidateSubFramebufferImmediate_x_not_12);
+COMPILE_ASSERT(offsetof(InvalidateSubFramebufferImmediate, y) == 16,
+               OffsetOf_InvalidateSubFramebufferImmediate_y_not_16);
+COMPILE_ASSERT(offsetof(InvalidateSubFramebufferImmediate, width) == 20,
+               OffsetOf_InvalidateSubFramebufferImmediate_width_not_20);
+COMPILE_ASSERT(offsetof(InvalidateSubFramebufferImmediate, height) == 24,
+               OffsetOf_InvalidateSubFramebufferImmediate_height_not_24);
+
 struct IsBuffer {
   typedef IsBuffer ValueType;
   static const CommandId kCmdId = kIsBuffer;
@@ -4426,6 +4551,37 @@
 COMPILE_ASSERT(offsetof(PolygonOffset, units) == 8,
                OffsetOf_PolygonOffset_units_not_8);
 
+struct ReadBuffer {
+  typedef ReadBuffer ValueType;
+  static const CommandId kCmdId = kReadBuffer;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLenum _src) {
+    SetHeader();
+    src = _src;
+  }
+
+  void* Set(void* cmd, GLenum _src) {
+    static_cast<ValueType*>(cmd)->Init(_src);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t src;
+};
+
+COMPILE_ASSERT(sizeof(ReadBuffer) == 8, Sizeof_ReadBuffer_is_not_8);
+COMPILE_ASSERT(offsetof(ReadBuffer, header) == 0,
+               OffsetOf_ReadBuffer_header_not_0);
+COMPILE_ASSERT(offsetof(ReadBuffer, src) == 4, OffsetOf_ReadBuffer_src_not_4);
+
 // ReadPixels has the result separated from the pixel buffer so that
 // it is easier to specify the result going to some specific place
 // that exactly fits the rectangle of pixels.
diff --git a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
index acc5e77..7473650 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
@@ -1218,6 +1218,59 @@
   CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
 }
 
+TEST_F(GLES2FormatTest, InvalidateFramebufferImmediate) {
+  const int kSomeBaseValueToTestWith = 51;
+  static GLenum data[] = {
+      static_cast<GLenum>(kSomeBaseValueToTestWith + 0),
+      static_cast<GLenum>(kSomeBaseValueToTestWith + 1),
+  };
+  cmds::InvalidateFramebufferImmediate& cmd =
+      *GetBufferAs<cmds::InvalidateFramebufferImmediate>();
+  const GLsizei kNumElements = 2;
+  const size_t kExpectedCmdSize =
+      sizeof(cmd) + kNumElements * sizeof(GLenum) * 1;
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLenum>(1), static_cast<GLsizei>(2), data);
+  EXPECT_EQ(static_cast<uint32_t>(cmds::InvalidateFramebufferImmediate::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(kExpectedCmdSize, cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLenum>(1), cmd.target);
+  EXPECT_EQ(static_cast<GLsizei>(2), cmd.count);
+  CheckBytesWrittenMatchesExpectedSize(
+      next_cmd, sizeof(cmd) + RoundSizeToMultipleOfEntries(sizeof(data)));
+  // TODO(gman): Check that data was inserted;
+}
+
+TEST_F(GLES2FormatTest, InvalidateSubFramebufferImmediate) {
+  const int kSomeBaseValueToTestWith = 51;
+  static GLenum data[] = {
+      static_cast<GLenum>(kSomeBaseValueToTestWith + 0),
+      static_cast<GLenum>(kSomeBaseValueToTestWith + 1),
+  };
+  cmds::InvalidateSubFramebufferImmediate& cmd =
+      *GetBufferAs<cmds::InvalidateSubFramebufferImmediate>();
+  const GLsizei kNumElements = 2;
+  const size_t kExpectedCmdSize =
+      sizeof(cmd) + kNumElements * sizeof(GLenum) * 1;
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLenum>(1), static_cast<GLsizei>(2), data,
+              static_cast<GLint>(4), static_cast<GLint>(5),
+              static_cast<GLsizei>(6), static_cast<GLsizei>(7));
+  EXPECT_EQ(
+      static_cast<uint32_t>(cmds::InvalidateSubFramebufferImmediate::kCmdId),
+      cmd.header.command);
+  EXPECT_EQ(kExpectedCmdSize, cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLenum>(1), cmd.target);
+  EXPECT_EQ(static_cast<GLsizei>(2), cmd.count);
+  EXPECT_EQ(static_cast<GLint>(4), cmd.x);
+  EXPECT_EQ(static_cast<GLint>(5), cmd.y);
+  EXPECT_EQ(static_cast<GLsizei>(6), cmd.width);
+  EXPECT_EQ(static_cast<GLsizei>(7), cmd.height);
+  CheckBytesWrittenMatchesExpectedSize(
+      next_cmd, sizeof(cmd) + RoundSizeToMultipleOfEntries(sizeof(data)));
+  // TODO(gman): Check that data was inserted;
+}
+
 TEST_F(GLES2FormatTest, IsBuffer) {
   cmds::IsBuffer& cmd = *GetBufferAs<cmds::IsBuffer>();
   void* next_cmd =
@@ -1354,6 +1407,16 @@
   CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
 }
 
+TEST_F(GLES2FormatTest, ReadBuffer) {
+  cmds::ReadBuffer& cmd = *GetBufferAs<cmds::ReadBuffer>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLenum>(11));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::ReadBuffer::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLenum>(11), cmd.src);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
 TEST_F(GLES2FormatTest, ReadPixels) {
   cmds::ReadPixels& cmd = *GetBufferAs<cmds::ReadPixels>();
   void* next_cmd = cmd.Set(&cmd, static_cast<GLint>(11), static_cast<GLint>(12),
diff --git a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
index f1bb286..94aa86c 100644
--- a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
@@ -98,148 +98,151 @@
   OP(GetVertexAttribiv)                        /* 339 */ \
   OP(GetVertexAttribPointerv)                  /* 340 */ \
   OP(Hint)                                     /* 341 */ \
-  OP(IsBuffer)                                 /* 342 */ \
-  OP(IsEnabled)                                /* 343 */ \
-  OP(IsFramebuffer)                            /* 344 */ \
-  OP(IsProgram)                                /* 345 */ \
-  OP(IsRenderbuffer)                           /* 346 */ \
-  OP(IsShader)                                 /* 347 */ \
-  OP(IsTexture)                                /* 348 */ \
-  OP(LineWidth)                                /* 349 */ \
-  OP(LinkProgram)                              /* 350 */ \
-  OP(PixelStorei)                              /* 351 */ \
-  OP(PolygonOffset)                            /* 352 */ \
-  OP(ReadPixels)                               /* 353 */ \
-  OP(ReleaseShaderCompiler)                    /* 354 */ \
-  OP(RenderbufferStorage)                      /* 355 */ \
-  OP(SampleCoverage)                           /* 356 */ \
-  OP(Scissor)                                  /* 357 */ \
-  OP(ShaderBinary)                             /* 358 */ \
-  OP(ShaderSourceBucket)                       /* 359 */ \
-  OP(StencilFunc)                              /* 360 */ \
-  OP(StencilFuncSeparate)                      /* 361 */ \
-  OP(StencilMask)                              /* 362 */ \
-  OP(StencilMaskSeparate)                      /* 363 */ \
-  OP(StencilOp)                                /* 364 */ \
-  OP(StencilOpSeparate)                        /* 365 */ \
-  OP(TexImage2D)                               /* 366 */ \
-  OP(TexParameterf)                            /* 367 */ \
-  OP(TexParameterfvImmediate)                  /* 368 */ \
-  OP(TexParameteri)                            /* 369 */ \
-  OP(TexParameterivImmediate)                  /* 370 */ \
-  OP(TexStorage3D)                             /* 371 */ \
-  OP(TexSubImage2D)                            /* 372 */ \
-  OP(Uniform1f)                                /* 373 */ \
-  OP(Uniform1fvImmediate)                      /* 374 */ \
-  OP(Uniform1i)                                /* 375 */ \
-  OP(Uniform1ivImmediate)                      /* 376 */ \
-  OP(Uniform1ui)                               /* 377 */ \
-  OP(Uniform1uivImmediate)                     /* 378 */ \
-  OP(Uniform2f)                                /* 379 */ \
-  OP(Uniform2fvImmediate)                      /* 380 */ \
-  OP(Uniform2i)                                /* 381 */ \
-  OP(Uniform2ivImmediate)                      /* 382 */ \
-  OP(Uniform2ui)                               /* 383 */ \
-  OP(Uniform2uivImmediate)                     /* 384 */ \
-  OP(Uniform3f)                                /* 385 */ \
-  OP(Uniform3fvImmediate)                      /* 386 */ \
-  OP(Uniform3i)                                /* 387 */ \
-  OP(Uniform3ivImmediate)                      /* 388 */ \
-  OP(Uniform3ui)                               /* 389 */ \
-  OP(Uniform3uivImmediate)                     /* 390 */ \
-  OP(Uniform4f)                                /* 391 */ \
-  OP(Uniform4fvImmediate)                      /* 392 */ \
-  OP(Uniform4i)                                /* 393 */ \
-  OP(Uniform4ivImmediate)                      /* 394 */ \
-  OP(Uniform4ui)                               /* 395 */ \
-  OP(Uniform4uivImmediate)                     /* 396 */ \
-  OP(UniformMatrix2fvImmediate)                /* 397 */ \
-  OP(UniformMatrix2x3fvImmediate)              /* 398 */ \
-  OP(UniformMatrix2x4fvImmediate)              /* 399 */ \
-  OP(UniformMatrix3fvImmediate)                /* 400 */ \
-  OP(UniformMatrix3x2fvImmediate)              /* 401 */ \
-  OP(UniformMatrix3x4fvImmediate)              /* 402 */ \
-  OP(UniformMatrix4fvImmediate)                /* 403 */ \
-  OP(UniformMatrix4x2fvImmediate)              /* 404 */ \
-  OP(UniformMatrix4x3fvImmediate)              /* 405 */ \
-  OP(UseProgram)                               /* 406 */ \
-  OP(ValidateProgram)                          /* 407 */ \
-  OP(VertexAttrib1f)                           /* 408 */ \
-  OP(VertexAttrib1fvImmediate)                 /* 409 */ \
-  OP(VertexAttrib2f)                           /* 410 */ \
-  OP(VertexAttrib2fvImmediate)                 /* 411 */ \
-  OP(VertexAttrib3f)                           /* 412 */ \
-  OP(VertexAttrib3fvImmediate)                 /* 413 */ \
-  OP(VertexAttrib4f)                           /* 414 */ \
-  OP(VertexAttrib4fvImmediate)                 /* 415 */ \
-  OP(VertexAttribI4i)                          /* 416 */ \
-  OP(VertexAttribI4ivImmediate)                /* 417 */ \
-  OP(VertexAttribI4ui)                         /* 418 */ \
-  OP(VertexAttribI4uivImmediate)               /* 419 */ \
-  OP(VertexAttribIPointer)                     /* 420 */ \
-  OP(VertexAttribPointer)                      /* 421 */ \
-  OP(Viewport)                                 /* 422 */ \
-  OP(BlitFramebufferCHROMIUM)                  /* 423 */ \
-  OP(RenderbufferStorageMultisampleCHROMIUM)   /* 424 */ \
-  OP(RenderbufferStorageMultisampleEXT)        /* 425 */ \
-  OP(FramebufferTexture2DMultisampleEXT)       /* 426 */ \
-  OP(TexStorage2DEXT)                          /* 427 */ \
-  OP(GenQueriesEXTImmediate)                   /* 428 */ \
-  OP(DeleteQueriesEXTImmediate)                /* 429 */ \
-  OP(BeginQueryEXT)                            /* 430 */ \
-  OP(EndQueryEXT)                              /* 431 */ \
-  OP(InsertEventMarkerEXT)                     /* 432 */ \
-  OP(PushGroupMarkerEXT)                       /* 433 */ \
-  OP(PopGroupMarkerEXT)                        /* 434 */ \
-  OP(GenVertexArraysOESImmediate)              /* 435 */ \
-  OP(DeleteVertexArraysOESImmediate)           /* 436 */ \
-  OP(IsVertexArrayOES)                         /* 437 */ \
-  OP(BindVertexArrayOES)                       /* 438 */ \
-  OP(SwapBuffers)                              /* 439 */ \
-  OP(GetMaxValueInBufferCHROMIUM)              /* 440 */ \
-  OP(EnableFeatureCHROMIUM)                    /* 441 */ \
-  OP(ResizeCHROMIUM)                           /* 442 */ \
-  OP(GetRequestableExtensionsCHROMIUM)         /* 443 */ \
-  OP(RequestExtensionCHROMIUM)                 /* 444 */ \
-  OP(GetProgramInfoCHROMIUM)                   /* 445 */ \
-  OP(GetTranslatedShaderSourceANGLE)           /* 446 */ \
-  OP(PostSubBufferCHROMIUM)                    /* 447 */ \
-  OP(TexImageIOSurface2DCHROMIUM)              /* 448 */ \
-  OP(CopyTextureCHROMIUM)                      /* 449 */ \
-  OP(DrawArraysInstancedANGLE)                 /* 450 */ \
-  OP(DrawElementsInstancedANGLE)               /* 451 */ \
-  OP(VertexAttribDivisorANGLE)                 /* 452 */ \
-  OP(GenMailboxCHROMIUM)                       /* 453 */ \
-  OP(ProduceTextureCHROMIUMImmediate)          /* 454 */ \
-  OP(ProduceTextureDirectCHROMIUMImmediate)    /* 455 */ \
-  OP(ConsumeTextureCHROMIUMImmediate)          /* 456 */ \
-  OP(CreateAndConsumeTextureCHROMIUMImmediate) /* 457 */ \
-  OP(BindUniformLocationCHROMIUMBucket)        /* 458 */ \
-  OP(GenValuebuffersCHROMIUMImmediate)         /* 459 */ \
-  OP(DeleteValuebuffersCHROMIUMImmediate)      /* 460 */ \
-  OP(IsValuebufferCHROMIUM)                    /* 461 */ \
-  OP(BindValuebufferCHROMIUM)                  /* 462 */ \
-  OP(SubscribeValueCHROMIUM)                   /* 463 */ \
-  OP(PopulateSubscribedValuesCHROMIUM)         /* 464 */ \
-  OP(UniformValuebufferCHROMIUM)               /* 465 */ \
-  OP(BindTexImage2DCHROMIUM)                   /* 466 */ \
-  OP(ReleaseTexImage2DCHROMIUM)                /* 467 */ \
-  OP(TraceBeginCHROMIUM)                       /* 468 */ \
-  OP(TraceEndCHROMIUM)                         /* 469 */ \
-  OP(AsyncTexSubImage2DCHROMIUM)               /* 470 */ \
-  OP(AsyncTexImage2DCHROMIUM)                  /* 471 */ \
-  OP(WaitAsyncTexImage2DCHROMIUM)              /* 472 */ \
-  OP(WaitAllAsyncTexImage2DCHROMIUM)           /* 473 */ \
-  OP(DiscardFramebufferEXTImmediate)           /* 474 */ \
-  OP(LoseContextCHROMIUM)                      /* 475 */ \
-  OP(InsertSyncPointCHROMIUM)                  /* 476 */ \
-  OP(WaitSyncPointCHROMIUM)                    /* 477 */ \
-  OP(DrawBuffersEXTImmediate)                  /* 478 */ \
-  OP(DiscardBackbufferCHROMIUM)                /* 479 */ \
-  OP(ScheduleOverlayPlaneCHROMIUM)             /* 480 */ \
-  OP(MatrixLoadfCHROMIUMImmediate)             /* 481 */ \
-  OP(MatrixLoadIdentityCHROMIUM)               /* 482 */ \
-  OP(BlendBarrierKHR)                          /* 483 */
+  OP(InvalidateFramebufferImmediate)           /* 342 */ \
+  OP(InvalidateSubFramebufferImmediate)        /* 343 */ \
+  OP(IsBuffer)                                 /* 344 */ \
+  OP(IsEnabled)                                /* 345 */ \
+  OP(IsFramebuffer)                            /* 346 */ \
+  OP(IsProgram)                                /* 347 */ \
+  OP(IsRenderbuffer)                           /* 348 */ \
+  OP(IsShader)                                 /* 349 */ \
+  OP(IsTexture)                                /* 350 */ \
+  OP(LineWidth)                                /* 351 */ \
+  OP(LinkProgram)                              /* 352 */ \
+  OP(PixelStorei)                              /* 353 */ \
+  OP(PolygonOffset)                            /* 354 */ \
+  OP(ReadBuffer)                               /* 355 */ \
+  OP(ReadPixels)                               /* 356 */ \
+  OP(ReleaseShaderCompiler)                    /* 357 */ \
+  OP(RenderbufferStorage)                      /* 358 */ \
+  OP(SampleCoverage)                           /* 359 */ \
+  OP(Scissor)                                  /* 360 */ \
+  OP(ShaderBinary)                             /* 361 */ \
+  OP(ShaderSourceBucket)                       /* 362 */ \
+  OP(StencilFunc)                              /* 363 */ \
+  OP(StencilFuncSeparate)                      /* 364 */ \
+  OP(StencilMask)                              /* 365 */ \
+  OP(StencilMaskSeparate)                      /* 366 */ \
+  OP(StencilOp)                                /* 367 */ \
+  OP(StencilOpSeparate)                        /* 368 */ \
+  OP(TexImage2D)                               /* 369 */ \
+  OP(TexParameterf)                            /* 370 */ \
+  OP(TexParameterfvImmediate)                  /* 371 */ \
+  OP(TexParameteri)                            /* 372 */ \
+  OP(TexParameterivImmediate)                  /* 373 */ \
+  OP(TexStorage3D)                             /* 374 */ \
+  OP(TexSubImage2D)                            /* 375 */ \
+  OP(Uniform1f)                                /* 376 */ \
+  OP(Uniform1fvImmediate)                      /* 377 */ \
+  OP(Uniform1i)                                /* 378 */ \
+  OP(Uniform1ivImmediate)                      /* 379 */ \
+  OP(Uniform1ui)                               /* 380 */ \
+  OP(Uniform1uivImmediate)                     /* 381 */ \
+  OP(Uniform2f)                                /* 382 */ \
+  OP(Uniform2fvImmediate)                      /* 383 */ \
+  OP(Uniform2i)                                /* 384 */ \
+  OP(Uniform2ivImmediate)                      /* 385 */ \
+  OP(Uniform2ui)                               /* 386 */ \
+  OP(Uniform2uivImmediate)                     /* 387 */ \
+  OP(Uniform3f)                                /* 388 */ \
+  OP(Uniform3fvImmediate)                      /* 389 */ \
+  OP(Uniform3i)                                /* 390 */ \
+  OP(Uniform3ivImmediate)                      /* 391 */ \
+  OP(Uniform3ui)                               /* 392 */ \
+  OP(Uniform3uivImmediate)                     /* 393 */ \
+  OP(Uniform4f)                                /* 394 */ \
+  OP(Uniform4fvImmediate)                      /* 395 */ \
+  OP(Uniform4i)                                /* 396 */ \
+  OP(Uniform4ivImmediate)                      /* 397 */ \
+  OP(Uniform4ui)                               /* 398 */ \
+  OP(Uniform4uivImmediate)                     /* 399 */ \
+  OP(UniformMatrix2fvImmediate)                /* 400 */ \
+  OP(UniformMatrix2x3fvImmediate)              /* 401 */ \
+  OP(UniformMatrix2x4fvImmediate)              /* 402 */ \
+  OP(UniformMatrix3fvImmediate)                /* 403 */ \
+  OP(UniformMatrix3x2fvImmediate)              /* 404 */ \
+  OP(UniformMatrix3x4fvImmediate)              /* 405 */ \
+  OP(UniformMatrix4fvImmediate)                /* 406 */ \
+  OP(UniformMatrix4x2fvImmediate)              /* 407 */ \
+  OP(UniformMatrix4x3fvImmediate)              /* 408 */ \
+  OP(UseProgram)                               /* 409 */ \
+  OP(ValidateProgram)                          /* 410 */ \
+  OP(VertexAttrib1f)                           /* 411 */ \
+  OP(VertexAttrib1fvImmediate)                 /* 412 */ \
+  OP(VertexAttrib2f)                           /* 413 */ \
+  OP(VertexAttrib2fvImmediate)                 /* 414 */ \
+  OP(VertexAttrib3f)                           /* 415 */ \
+  OP(VertexAttrib3fvImmediate)                 /* 416 */ \
+  OP(VertexAttrib4f)                           /* 417 */ \
+  OP(VertexAttrib4fvImmediate)                 /* 418 */ \
+  OP(VertexAttribI4i)                          /* 419 */ \
+  OP(VertexAttribI4ivImmediate)                /* 420 */ \
+  OP(VertexAttribI4ui)                         /* 421 */ \
+  OP(VertexAttribI4uivImmediate)               /* 422 */ \
+  OP(VertexAttribIPointer)                     /* 423 */ \
+  OP(VertexAttribPointer)                      /* 424 */ \
+  OP(Viewport)                                 /* 425 */ \
+  OP(BlitFramebufferCHROMIUM)                  /* 426 */ \
+  OP(RenderbufferStorageMultisampleCHROMIUM)   /* 427 */ \
+  OP(RenderbufferStorageMultisampleEXT)        /* 428 */ \
+  OP(FramebufferTexture2DMultisampleEXT)       /* 429 */ \
+  OP(TexStorage2DEXT)                          /* 430 */ \
+  OP(GenQueriesEXTImmediate)                   /* 431 */ \
+  OP(DeleteQueriesEXTImmediate)                /* 432 */ \
+  OP(BeginQueryEXT)                            /* 433 */ \
+  OP(EndQueryEXT)                              /* 434 */ \
+  OP(InsertEventMarkerEXT)                     /* 435 */ \
+  OP(PushGroupMarkerEXT)                       /* 436 */ \
+  OP(PopGroupMarkerEXT)                        /* 437 */ \
+  OP(GenVertexArraysOESImmediate)              /* 438 */ \
+  OP(DeleteVertexArraysOESImmediate)           /* 439 */ \
+  OP(IsVertexArrayOES)                         /* 440 */ \
+  OP(BindVertexArrayOES)                       /* 441 */ \
+  OP(SwapBuffers)                              /* 442 */ \
+  OP(GetMaxValueInBufferCHROMIUM)              /* 443 */ \
+  OP(EnableFeatureCHROMIUM)                    /* 444 */ \
+  OP(ResizeCHROMIUM)                           /* 445 */ \
+  OP(GetRequestableExtensionsCHROMIUM)         /* 446 */ \
+  OP(RequestExtensionCHROMIUM)                 /* 447 */ \
+  OP(GetProgramInfoCHROMIUM)                   /* 448 */ \
+  OP(GetTranslatedShaderSourceANGLE)           /* 449 */ \
+  OP(PostSubBufferCHROMIUM)                    /* 450 */ \
+  OP(TexImageIOSurface2DCHROMIUM)              /* 451 */ \
+  OP(CopyTextureCHROMIUM)                      /* 452 */ \
+  OP(DrawArraysInstancedANGLE)                 /* 453 */ \
+  OP(DrawElementsInstancedANGLE)               /* 454 */ \
+  OP(VertexAttribDivisorANGLE)                 /* 455 */ \
+  OP(GenMailboxCHROMIUM)                       /* 456 */ \
+  OP(ProduceTextureCHROMIUMImmediate)          /* 457 */ \
+  OP(ProduceTextureDirectCHROMIUMImmediate)    /* 458 */ \
+  OP(ConsumeTextureCHROMIUMImmediate)          /* 459 */ \
+  OP(CreateAndConsumeTextureCHROMIUMImmediate) /* 460 */ \
+  OP(BindUniformLocationCHROMIUMBucket)        /* 461 */ \
+  OP(GenValuebuffersCHROMIUMImmediate)         /* 462 */ \
+  OP(DeleteValuebuffersCHROMIUMImmediate)      /* 463 */ \
+  OP(IsValuebufferCHROMIUM)                    /* 464 */ \
+  OP(BindValuebufferCHROMIUM)                  /* 465 */ \
+  OP(SubscribeValueCHROMIUM)                   /* 466 */ \
+  OP(PopulateSubscribedValuesCHROMIUM)         /* 467 */ \
+  OP(UniformValuebufferCHROMIUM)               /* 468 */ \
+  OP(BindTexImage2DCHROMIUM)                   /* 469 */ \
+  OP(ReleaseTexImage2DCHROMIUM)                /* 470 */ \
+  OP(TraceBeginCHROMIUM)                       /* 471 */ \
+  OP(TraceEndCHROMIUM)                         /* 472 */ \
+  OP(AsyncTexSubImage2DCHROMIUM)               /* 473 */ \
+  OP(AsyncTexImage2DCHROMIUM)                  /* 474 */ \
+  OP(WaitAsyncTexImage2DCHROMIUM)              /* 475 */ \
+  OP(WaitAllAsyncTexImage2DCHROMIUM)           /* 476 */ \
+  OP(DiscardFramebufferEXTImmediate)           /* 477 */ \
+  OP(LoseContextCHROMIUM)                      /* 478 */ \
+  OP(InsertSyncPointCHROMIUM)                  /* 479 */ \
+  OP(WaitSyncPointCHROMIUM)                    /* 480 */ \
+  OP(DrawBuffersEXTImmediate)                  /* 481 */ \
+  OP(DiscardBackbufferCHROMIUM)                /* 482 */ \
+  OP(ScheduleOverlayPlaneCHROMIUM)             /* 483 */ \
+  OP(MatrixLoadfCHROMIUMImmediate)             /* 484 */ \
+  OP(MatrixLoadIdentityCHROMIUM)               /* 485 */ \
+  OP(BlendBarrierKHR)                          /* 486 */
 
 enum CommandId {
   kStartPoint = cmd::kLastCommonId,  // All GLES2 commands start after this.
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index 9fec2e1..a15c791 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -139,7 +139,6 @@
       map_buffer_range(false),
       ext_discard_framebuffer(false),
       angle_depth_texture(false),
-      is_angle(false),
       is_swiftshader(false),
       angle_texture_usage(false),
       ext_texture_storage(false),
@@ -271,17 +270,10 @@
 
   const char* renderer_str =
       reinterpret_cast<const char*>(glGetString(GL_RENDERER));
-  if (renderer_str) {
-    feature_flags_.is_angle = StartsWithASCII(renderer_str, "ANGLE", true);
-  }
-
-  bool is_es3 = false;
   const char* version_str =
       reinterpret_cast<const char*>(glGetString(GL_VERSION));
-  if (version_str) {
-    std::string lstr(base::StringToLowerASCII(std::string(version_str)));
-    is_es3 = (lstr.substr(0, 12) == "opengl es 3.");
-  }
+
+  gl_version_info_.reset(new gfx::GLVersionInfo(version_str, renderer_str));
 
   AddExtensionString("GL_ANGLE_translated_shader_source");
   AddExtensionString("GL_CHROMIUM_async_pixel_transfers");
@@ -386,7 +378,8 @@
   if (!workarounds_.disable_depth_texture &&
       (extensions.Contains("GL_ARB_depth_texture") ||
        extensions.Contains("GL_OES_depth_texture") ||
-       extensions.Contains("GL_ANGLE_depth_texture") || is_es3)) {
+       extensions.Contains("GL_ANGLE_depth_texture") ||
+       gl_version_info_->is_es3)) {
     enable_depth_texture = true;
     feature_flags_.angle_depth_texture =
         extensions.Contains("GL_ANGLE_depth_texture");
@@ -404,7 +397,8 @@
   }
 
   if (extensions.Contains("GL_EXT_packed_depth_stencil") ||
-      extensions.Contains("GL_OES_packed_depth_stencil") || is_es3) {
+      extensions.Contains("GL_OES_packed_depth_stencil") ||
+      gl_version_info_->is_es3) {
     AddExtensionString("GL_OES_packed_depth_stencil");
     feature_flags_.packed_depth24_stencil8 = true;
     if (enable_depth_texture) {
@@ -417,7 +411,8 @@
     validators_.render_buffer_format.AddValue(GL_DEPTH24_STENCIL8);
   }
 
-  if (is_es3 || extensions.Contains("GL_OES_vertex_array_object") ||
+  if (gl_version_info_->is_es3 ||
+      extensions.Contains("GL_OES_vertex_array_object") ||
       extensions.Contains("GL_ARB_vertex_array_object") ||
       extensions.Contains("GL_APPLE_vertex_array_object")) {
     feature_flags_.native_vertex_array_object = true;
@@ -430,7 +425,8 @@
     feature_flags_.native_vertex_array_object = false;
   }
 
-  if (is_es3 || extensions.Contains("GL_OES_element_index_uint") ||
+  if (gl_version_info_->is_es3 ||
+      extensions.Contains("GL_OES_element_index_uint") ||
       gfx::HasDesktopGLFeatures()) {
     AddExtensionString("GL_OES_element_index_uint");
     validators_.index_type.AddValue(GL_UNSIGNED_INT);
@@ -442,7 +438,8 @@
   // sized formats GL_SRGB8 and GL_SRGB8_ALPHA8. Also, SRGB_EXT isn't a valid
   // <format> in this case. So, even with GLES3 explicitly check for
   // GL_EXT_sRGB.
-  if (((is_es3 || extensions.Contains("GL_OES_rgb8_rgba8")) &&
+  if (((gl_version_info_->is_es3 ||
+        extensions.Contains("GL_OES_rgb8_rgba8")) &&
       extensions.Contains("GL_EXT_sRGB")) || gfx::HasDesktopGLFeatures()) {
     AddExtensionString("GL_EXT_sRGB");
     texture_format_validators_[GL_SRGB_EXT].AddValue(GL_UNSIGNED_BYTE);
@@ -503,7 +500,8 @@
   }
 
   // Check if we should allow GL_OES_texture_npot
-  if (is_es3 || extensions.Contains("GL_ARB_texture_non_power_of_two") ||
+  if (gl_version_info_->is_es3 ||
+      extensions.Contains("GL_ARB_texture_non_power_of_two") ||
       extensions.Contains("GL_OES_texture_npot")) {
     AddExtensionString("GL_OES_texture_npot");
     feature_flags_.npot_ok = true;
@@ -535,8 +533,9 @@
       // This extension allows a variety of floating point formats to be
       // rendered to via framebuffer objects. Enable it's usage only if
       // support for Floating textures is enabled.
-      if ((is_es3 && extensions.Contains("GL_EXT_color_buffer_float")) ||
-          feature_flags_.is_angle) {
+      if ((gl_version_info_->is_es3 &&
+           extensions.Contains("GL_EXT_color_buffer_float")) ||
+          gl_version_info_->is_angle) {
         may_enable_chromium_color_buffer_float = true;
       }
     }
@@ -638,12 +637,13 @@
   // Check for multisample support
   if (!workarounds_.disable_multisampling) {
     bool ext_has_multisample =
-        extensions.Contains("GL_EXT_framebuffer_multisample") || is_es3;
-    if (feature_flags_.is_angle) {
+        extensions.Contains("GL_EXT_framebuffer_multisample") ||
+        gl_version_info_->is_es3;
+    if (gl_version_info_->is_angle) {
       ext_has_multisample |=
           extensions.Contains("GL_ANGLE_framebuffer_multisample");
     }
-    feature_flags_.use_core_framebuffer_multisample = is_es3;
+    feature_flags_.use_core_framebuffer_multisample = gl_version_info_->is_es3;
     if (ext_has_multisample) {
       feature_flags_.chromium_framebuffer_multisample = true;
       validators_.frame_buffer_target.AddValue(GL_READ_FRAMEBUFFER_EXT);
@@ -670,14 +670,15 @@
   }
 
   if (extensions.Contains("GL_OES_depth24") || gfx::HasDesktopGLFeatures() ||
-      is_es3) {
+      gl_version_info_->is_es3) {
     AddExtensionString("GL_OES_depth24");
     feature_flags_.oes_depth24 = true;
     validators_.render_buffer_format.AddValue(GL_DEPTH_COMPONENT24);
   }
 
   if (!workarounds_.disable_oes_standard_derivatives &&
-      (is_es3 || extensions.Contains("GL_OES_standard_derivatives") ||
+      (gl_version_info_->is_es3 ||
+       extensions.Contains("GL_OES_standard_derivatives") ||
        gfx::HasDesktopGLFeatures())) {
     AddExtensionString("GL_OES_standard_derivatives");
     feature_flags_.oes_standard_derivatives = true;
@@ -771,8 +772,10 @@
   // However we expose GL_EXT_texture_storage when just ES3 because we don't
   // claim to handle GL_BGRA8.
   bool support_texture_storage_on_es3 =
-      (is_es3 && enable_immutable_texture_format_bgra_on_es3) ||
-      (is_es3 && !enable_texture_format_bgra8888);
+      (gl_version_info_->is_es3 &&
+       enable_immutable_texture_format_bgra_on_es3) ||
+      (gl_version_info_->is_es3 &&
+       !enable_texture_format_bgra8888);
   if (extensions.Contains("GL_EXT_texture_storage") ||
       extensions.Contains("GL_ARB_texture_storage") ||
       support_texture_storage_on_es3) {
@@ -825,7 +828,7 @@
       (extensions.Contains("GL_ANGLE_instanced_arrays") ||
        (extensions.Contains("GL_ARB_instanced_arrays") &&
         extensions.Contains("GL_ARB_draw_instanced")) ||
-       is_es3)) {
+       gl_version_info_->is_es3)) {
     AddExtensionString("GL_ANGLE_instanced_arrays");
     feature_flags_.angle_instanced_arrays = true;
     validators_.vertex_attribute.AddValue(GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
@@ -836,7 +839,8 @@
       extensions.Contains("GL_EXT_draw_buffers");
   if (!workarounds_.disable_ext_draw_buffers &&
       (vendor_agnostic_draw_buffers ||
-       (extensions.Contains("GL_NV_draw_buffers") && is_es3))) {
+       (extensions.Contains("GL_NV_draw_buffers") &&
+        gl_version_info_->is_es3))) {
     AddExtensionString("GL_EXT_draw_buffers");
     feature_flags_.ext_draw_buffers = true;
 
@@ -871,7 +875,8 @@
     }
   }
 
-  if (is_es3 || extensions.Contains("GL_EXT_blend_minmax") ||
+  if (gl_version_info_->is_es3 ||
+      extensions.Contains("GL_EXT_blend_minmax") ||
       gfx::HasDesktopGLFeatures()) {
     AddExtensionString("GL_EXT_blend_minmax");
     validators_.equation.AddValue(GL_MIN_EXT);
@@ -906,13 +911,15 @@
   UMA_HISTOGRAM_BOOLEAN("GPU.FenceSupport", ui_gl_fence_works);
 
   feature_flags_.map_buffer_range =
-      is_es3 || extensions.Contains("GL_ARB_map_buffer_range") ||
+      gl_version_info_->is_es3 ||
+      extensions.Contains("GL_ARB_map_buffer_range") ||
       extensions.Contains("GL_EXT_map_buffer_range");
 
   // Really it's part of core OpenGL 2.1 and up, but let's assume the
   // extension is still advertised.
   bool has_pixel_buffers =
-      is_es3 || extensions.Contains("GL_ARB_pixel_buffer_object") ||
+      gl_version_info_->is_es3 ||
+      extensions.Contains("GL_ARB_pixel_buffer_object") ||
       extensions.Contains("GL_NV_pixel_buffer_object");
 
   // We will use either glMapBuffer() or glMapBufferRange() for async readbacks.
@@ -921,13 +928,15 @@
     feature_flags_.use_async_readpixels = true;
   }
 
-  if (is_es3 || extensions.Contains("GL_ARB_sampler_objects")) {
+  if (gl_version_info_->is_es3 ||
+      extensions.Contains("GL_ARB_sampler_objects")) {
     feature_flags_.enable_samplers = true;
     // TODO(dsinclair): Add AddExtensionString("GL_CHROMIUM_sampler_objects")
     // when available.
   }
 
-  if ((is_es3 || extensions.Contains("GL_EXT_discard_framebuffer")) &&
+  if ((gl_version_info_->is_es3 ||
+       extensions.Contains("GL_EXT_discard_framebuffer")) &&
       !workarounds_.disable_ext_discard_framebuffer) {
     // DiscardFramebufferEXT is automatically bound to InvalidateFramebuffer.
     AddExtensionString("GL_EXT_discard_framebuffer");
@@ -974,7 +983,8 @@
   }
 
   if (extensions.Contains("GL_NV_path_rendering")) {
-    if (extensions.Contains("GL_EXT_direct_state_access") || is_es3) {
+    if (extensions.Contains("GL_EXT_direct_state_access") ||
+        gl_version_info_->is_es3) {
       AddExtensionString("GL_CHROMIUM_path_rendering");
       feature_flags_.chromium_path_rendering = true;
       validators_.g_l_state.AddValue(GL_PATH_MODELVIEW_MATRIX_CHROMIUM);
@@ -982,7 +992,7 @@
     }
   }
 
-  if ((is_es3 || extensions.Contains("GL_EXT_texture_rg") ||
+  if ((gl_version_info_->is_es3 || extensions.Contains("GL_EXT_texture_rg") ||
        extensions.Contains("GL_ARB_texture_rg")) &&
       IsGL_REDSupportedOnFBOs()) {
     feature_flags_.ext_texture_rg = true;
diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h
index 816ab49..c4bf479 100644
--- a/gpu/command_buffer/service/feature_info.h
+++ b/gpu/command_buffer/service/feature_info.h
@@ -14,6 +14,7 @@
 #include "gpu/command_buffer/service/gles2_cmd_validation.h"
 #include "gpu/config/gpu_driver_bug_workaround_type.h"
 #include "gpu/gpu_export.h"
+#include "ui/gl/gl_version_info.h"
 
 namespace base {
 class CommandLine;
@@ -66,7 +67,6 @@
     bool map_buffer_range;
     bool ext_discard_framebuffer;
     bool angle_depth_texture;
-    bool is_angle;
     bool is_swiftshader;
     bool angle_texture_usage;
     bool ext_texture_storage;
@@ -122,6 +122,11 @@
     return workarounds_;
   }
 
+  const gfx::GLVersionInfo& gl_version_info() const {
+    CHECK(gl_version_info_.get());
+    return *(gl_version_info_.get());
+  }
+
  private:
   friend class base::RefCounted<FeatureInfo>;
   friend class BufferManagerClientSideArraysTest;
@@ -148,6 +153,8 @@
   // Flags for Workarounds.
   Workarounds workarounds_;
 
+  scoped_ptr<gfx::GLVersionInfo> gl_version_info_;
+
   DISALLOW_COPY_AND_ASSIGN(FeatureInfo);
 };
 
diff --git a/gpu/command_buffer/service/feature_info_unittest.cc b/gpu/command_buffer/service/feature_info_unittest.cc
index b314262..06f3d11 100644
--- a/gpu/command_buffer/service/feature_info_unittest.cc
+++ b/gpu/command_buffer/service/feature_info_unittest.cc
@@ -127,7 +127,6 @@
   EXPECT_FALSE(info_->feature_flags().nv_draw_buffers);
   EXPECT_FALSE(info_->feature_flags().ext_discard_framebuffer);
   EXPECT_FALSE(info_->feature_flags().angle_depth_texture);
-  EXPECT_FALSE(info_->feature_flags().is_angle);
 
 #define GPU_OP(type, name) EXPECT_FALSE(info_->workarounds().name);
   GPU_DRIVER_BUG_WORKAROUNDS(GPU_OP)
@@ -345,7 +344,7 @@
 
 TEST_F(FeatureInfoTest, InitializeWithANGLE) {
   SetupInitExpectationsWithGLVersion("", kGLRendererStringANGLE, "");
-  EXPECT_TRUE(info_->feature_flags().is_angle);
+  EXPECT_TRUE(info_->gl_version_info().is_angle);
 }
 
 TEST_F(FeatureInfoTest, InitializeNPOTExtensionGLES) {
diff --git a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
index ffb9370..5122613 100644
--- a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
+++ b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
@@ -260,8 +260,9 @@
       framebuffer_(0u) {}
 
 CopyTextureCHROMIUMResourceManager::~CopyTextureCHROMIUMResourceManager() {
-  DCHECK(!buffer_id_);
-  DCHECK(!framebuffer_);
+  // |buffer_id_| and |framebuffer_| can be not-null because when GPU context is
+  // lost, this class can be deleted without releasing resources like
+  // GLES2DecoderImpl.
 }
 
 void CopyTextureCHROMIUMResourceManager::Initialize(
@@ -330,7 +331,8 @@
   // format of internalformat.
   // https://www.khronos.org/opengles/sdk/docs/man/xhtml/glCopyTexImage2D.xml
   bool source_format_contain_superset_of_dest_format =
-      source_internal_format == dest_internal_format ||
+      (source_internal_format == dest_internal_format &&
+       source_internal_format != GL_BGRA_EXT) ||
       (source_internal_format == GL_RGBA && dest_internal_format == GL_RGB);
   // GL_TEXTURE_RECTANGLE_ARB on FBO is supported by OpenGL, not GLES2,
   // so restrict this to GL_TEXTURE_2D.
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 422168c..919d8d8 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -4494,7 +4494,13 @@
   }
 
   ScopedRenderTo do_render(framebuffer);
-  glDiscardFramebufferEXT(target, numAttachments, translated_attachments.get());
+  if (feature_info_->gl_version_info().is_es3) {
+    glInvalidateFramebuffer(
+        target, numAttachments, translated_attachments.get());
+  } else {
+    glDiscardFramebufferEXT(
+        target, numAttachments, translated_attachments.get());
+  }
 }
 
 void GLES2DecoderImpl::DoEnableVertexAttribArray(GLuint index) {
@@ -5495,7 +5501,7 @@
     GLsizei height) {
   // TODO(sievers): This could be resolved at the GL binding level, but the
   // binding process is currently a bit too 'brute force'.
-  if (feature_info->feature_flags().is_angle) {
+  if (feature_info->gl_version_info().is_angle) {
     glRenderbufferStorageMultisampleANGLE(
         target, samples, internal_format, width, height);
   } else if (feature_info->feature_flags().use_core_framebuffer_multisample) {
@@ -5519,7 +5525,7 @@
                                              GLenum filter) {
   // TODO(sievers): This could be resolved at the GL binding level, but the
   // binding process is currently a bit too 'brute force'.
-  if (feature_info_->feature_flags().is_angle) {
+  if (feature_info_->gl_version_info().is_angle) {
     glBlitFramebufferANGLE(
         srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
   } else if (feature_info_->feature_flags().use_core_framebuffer_multisample) {
@@ -7865,8 +7871,8 @@
       glGenBuffersARB(1, &buffer);
       glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, buffer);
       // For ANGLE client version 2, GL_STREAM_READ is not available.
-      const GLenum usage_hint =
-          features().is_angle ? GL_STATIC_DRAW : GL_STREAM_READ;
+      const GLenum usage_hint = feature_info_->gl_version_info().is_angle ?
+          GL_STATIC_DRAW : GL_STREAM_READ;
       glBufferData(GL_PIXEL_PACK_BUFFER_ARB, pixels_size, NULL, usage_hint);
       GLenum error = glGetError();
       if (error == GL_NO_ERROR) {
@@ -9703,7 +9709,7 @@
       // Ensure the side effects of the copy are visible to the parent
       // context. There is no need to do this for ANGLE because it uses a
       // single D3D device for all contexts.
-      if (!feature_info_->feature_flags().is_angle)
+      if (!feature_info_->gl_version_info().is_angle)
         glFlush();
     }
   } else {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
index ebdb625..b84fc2a 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
@@ -1493,6 +1493,74 @@
   return error::kNoError;
 }
 
+error::Error GLES2DecoderImpl::HandleInvalidateFramebufferImmediate(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  if (!unsafe_es3_apis_enabled())
+    return error::kUnknownCommand;
+  const gles2::cmds::InvalidateFramebufferImmediate& c =
+      *static_cast<const gles2::cmds::InvalidateFramebufferImmediate*>(
+          cmd_data);
+  (void)c;
+  GLenum target = static_cast<GLenum>(c.target);
+  GLsizei count = static_cast<GLsizei>(c.count);
+  uint32_t data_size;
+  if (!ComputeDataSize(count, sizeof(GLenum), 1, &data_size)) {
+    return error::kOutOfBounds;
+  }
+  if (data_size > immediate_data_size) {
+    return error::kOutOfBounds;
+  }
+  const GLenum* attachments =
+      GetImmediateDataAs<const GLenum*>(c, data_size, immediate_data_size);
+  if (attachments == NULL) {
+    return error::kOutOfBounds;
+  }
+  glInvalidateFramebuffer(target, count, attachments);
+  return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleInvalidateSubFramebufferImmediate(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  if (!unsafe_es3_apis_enabled())
+    return error::kUnknownCommand;
+  const gles2::cmds::InvalidateSubFramebufferImmediate& c =
+      *static_cast<const gles2::cmds::InvalidateSubFramebufferImmediate*>(
+          cmd_data);
+  (void)c;
+  GLenum target = static_cast<GLenum>(c.target);
+  GLsizei count = static_cast<GLsizei>(c.count);
+  uint32_t data_size;
+  if (!ComputeDataSize(count, sizeof(GLenum), 1, &data_size)) {
+    return error::kOutOfBounds;
+  }
+  if (data_size > immediate_data_size) {
+    return error::kOutOfBounds;
+  }
+  const GLenum* attachments =
+      GetImmediateDataAs<const GLenum*>(c, data_size, immediate_data_size);
+  GLint x = static_cast<GLint>(c.x);
+  GLint y = static_cast<GLint>(c.y);
+  GLsizei width = static_cast<GLsizei>(c.width);
+  GLsizei height = static_cast<GLsizei>(c.height);
+  if (attachments == NULL) {
+    return error::kOutOfBounds;
+  }
+  if (width < 0) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glInvalidateSubFramebuffer",
+                       "width < 0");
+    return error::kNoError;
+  }
+  if (height < 0) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glInvalidateSubFramebuffer",
+                       "height < 0");
+    return error::kNoError;
+  }
+  glInvalidateSubFramebuffer(target, count, attachments, x, y, width, height);
+  return error::kNoError;
+}
+
 error::Error GLES2DecoderImpl::HandleIsBuffer(uint32_t immediate_data_size,
                                               const void* cmd_data) {
   const gles2::cmds::IsBuffer& c =
@@ -1653,6 +1721,18 @@
   return error::kNoError;
 }
 
+error::Error GLES2DecoderImpl::HandleReadBuffer(uint32_t immediate_data_size,
+                                                const void* cmd_data) {
+  if (!unsafe_es3_apis_enabled())
+    return error::kUnknownCommand;
+  const gles2::cmds::ReadBuffer& c =
+      *static_cast<const gles2::cmds::ReadBuffer*>(cmd_data);
+  (void)c;
+  GLenum src = static_cast<GLenum>(c.src);
+  glReadBuffer(src);
+  return error::kNoError;
+}
+
 error::Error GLES2DecoderImpl::HandleReleaseShaderCompiler(
     uint32_t immediate_data_size,
     const void* cmd_data) {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h
index f9b450e..014007a 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h
@@ -1698,6 +1698,8 @@
   EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
   EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
 }
+// TODO(gman): InvalidateFramebufferImmediate
+// TODO(gman): InvalidateSubFramebufferImmediate
 
 TEST_P(GLES2DecoderTest1, IsBufferValidArgs) {
   SpecializedSetup<cmds::IsBuffer, 0>(true);
@@ -1875,14 +1877,4 @@
 }
 // TODO(gman): PixelStorei
 
-TEST_P(GLES2DecoderTest1, PolygonOffsetValidArgs) {
-  EXPECT_CALL(*gl_, PolygonOffset(1, 2));
-  SpecializedSetup<cmds::PolygonOffset, 0>(true);
-  cmds::PolygonOffset cmd;
-  cmd.Init(1, 2);
-  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(GL_NO_ERROR, GetGLError());
-}
-// TODO(gman): ReadPixels
-
 #endif  // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_1_AUTOGEN_H_
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h
index b69197f..602be42 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h
@@ -12,6 +12,28 @@
 #ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_2_AUTOGEN_H_
 #define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_2_AUTOGEN_H_
 
+TEST_P(GLES2DecoderTest2, PolygonOffsetValidArgs) {
+  EXPECT_CALL(*gl_, PolygonOffset(1, 2));
+  SpecializedSetup<cmds::PolygonOffset, 0>(true);
+  cmds::PolygonOffset cmd;
+  cmd.Init(1, 2);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_P(GLES2DecoderTest2, ReadBufferValidArgs) {
+  EXPECT_CALL(*gl_, ReadBuffer(1));
+  SpecializedSetup<cmds::ReadBuffer, 0>(true);
+  cmds::ReadBuffer cmd;
+  cmd.Init(1);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+}
+// TODO(gman): ReadPixels
+
 // TODO(gman): ReleaseShaderCompiler
 
 TEST_P(GLES2DecoderTest2, RenderbufferStorageValidArgs) {
@@ -1015,7 +1037,4 @@
 // TODO(gman): GetTranslatedShaderSourceANGLE
 // TODO(gman): PostSubBufferCHROMIUM
 // TODO(gman): TexImageIOSurface2DCHROMIUM
-// TODO(gman): CopyTextureCHROMIUM
-// TODO(gman): DrawArraysInstancedANGLE
-// TODO(gman): DrawElementsInstancedANGLE
 #endif  // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_2_AUTOGEN_H_
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
index 0ee2ba5..4509676 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
@@ -12,6 +12,9 @@
 #ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_
 #define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_
 
+// TODO(gman): CopyTextureCHROMIUM
+// TODO(gman): DrawArraysInstancedANGLE
+// TODO(gman): DrawElementsInstancedANGLE
 // TODO(gman): VertexAttribDivisorANGLE
 // TODO(gman): GenMailboxCHROMIUM
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
index 78fa020..d230be7 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
@@ -2120,7 +2120,7 @@
 
   // EXPECT_EQ can't be used to compare function pointers
   EXPECT_TRUE(
-      gfx::MockGLInterface::GetGLProcAddress("glInvalidateFramebuffer") ==
+      gfx::MockGLInterface::GetGLProcAddress("glInvalidateFramebuffer") !=
       gfx::g_driver_gl.fn.glDiscardFramebufferEXTFn);
   EXPECT_TRUE(
       gfx::MockGLInterface::GetGLProcAddress("glInvalidateFramebuffer") !=
diff --git a/gpu/command_buffer/service/gpu_scheduler.cc b/gpu/command_buffer/service/gpu_scheduler.cc
index 48df8dd..3f8f1bf 100644
--- a/gpu/command_buffer/service/gpu_scheduler.cc
+++ b/gpu/command_buffer/service/gpu_scheduler.cc
@@ -22,8 +22,6 @@
 
 namespace gpu {
 
-const int64 kUnscheduleFenceTimeOutDelay = 10000;
-
 #if defined(OS_WIN)
 const int64 kRescheduleTimeOutDelay = 1000;
 #endif
@@ -59,10 +57,6 @@
   if (state.error != error::kNoError)
     return;
 
-  // Check that the GPU has passed all fences.
-  if (!PollUnscheduleFences())
-    return;
-
   // One of the unschedule fence tasks might have unscheduled us.
   if (!IsScheduled())
     return;
@@ -76,7 +70,6 @@
       break;
 
     DCHECK(IsScheduled());
-    DCHECK(unschedule_fences_.empty());
 
     error = parser_->ProcessCommands(CommandParser::kParseCommandsSlice);
 
@@ -169,8 +162,7 @@
 }
 
 bool GpuScheduler::HasMoreWork() {
-  return !unschedule_fences_.empty() ||
-         (decoder_ && decoder_->ProcessPendingQueries(false)) ||
+  return (decoder_ && decoder_->ProcessPendingQueries(false)) ||
          HasMoreIdleWork();
 }
 
@@ -222,45 +214,6 @@
   command_processed_callback_ = callback;
 }
 
-void GpuScheduler::DeferToFence(base::Closure task) {
-  unschedule_fences_.push(make_linked_ptr(
-       new UnscheduleFence(gfx::GLFence::Create(), task)));
-  SetScheduled(false);
-}
-
-bool GpuScheduler::PollUnscheduleFences() {
-  if (unschedule_fences_.empty())
-    return true;
-
-  if (unschedule_fences_.front()->fence.get()) {
-    base::Time now = base::Time::Now();
-    base::TimeDelta timeout =
-        base::TimeDelta::FromMilliseconds(kUnscheduleFenceTimeOutDelay);
-
-    while (!unschedule_fences_.empty()) {
-      const UnscheduleFence& fence = *unschedule_fences_.front();
-      if (fence.fence->HasCompleted() ||
-          now - fence.issue_time > timeout) {
-        unschedule_fences_.front()->task.Run();
-        unschedule_fences_.pop();
-        SetScheduled(true);
-      } else {
-        return false;
-      }
-    }
-  } else {
-    glFinish();
-
-    while (!unschedule_fences_.empty()) {
-      unschedule_fences_.front()->task.Run();
-      unschedule_fences_.pop();
-      SetScheduled(true);
-    }
-  }
-
-  return true;
-}
-
 bool GpuScheduler::IsPreempted() {
   if (!preemption_flag_.get())
     return false;
@@ -297,14 +250,4 @@
   rescheduled_count_ = new_count;
 }
 
-GpuScheduler::UnscheduleFence::UnscheduleFence(gfx::GLFence* fence_,
-                                               base::Closure task_)
-  : fence(fence_),
-    issue_time(base::Time::Now()),
-    task(task_) {
-}
-
-GpuScheduler::UnscheduleFence::~UnscheduleFence() {
-}
-
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/gpu_scheduler.h b/gpu/command_buffer/service/gpu_scheduler.h
index 5e47d4a..b0b2630 100644
--- a/gpu/command_buffer/service/gpu_scheduler.h
+++ b/gpu/command_buffer/service/gpu_scheduler.h
@@ -91,12 +91,6 @@
 
   void SetCommandProcessedCallback(const base::Closure& callback);
 
-  void DeferToFence(base::Closure task);
-
-  // Polls the fences, invoking callbacks that were waiting to be triggered
-  // by them and returns whether all fences were complete.
-  bool PollUnscheduleFences();
-
   bool HasMoreIdleWork();
   void PerformIdleWork();
 
@@ -136,18 +130,6 @@
   // account of a timeout.
   int rescheduled_count_;
 
-  // The GpuScheduler will unschedule itself in the event that further GL calls
-  // are issued to it before all these fences have been crossed by the GPU.
-  struct UnscheduleFence {
-    UnscheduleFence(gfx::GLFence* fence, base::Closure task);
-    ~UnscheduleFence();
-
-    scoped_ptr<gfx::GLFence> fence;
-    base::Time issue_time;
-    base::Closure task;
-  };
-  std::queue<linked_ptr<UnscheduleFence> > unschedule_fences_;
-
   SchedulingChangedCallback scheduling_changed_callback_;
   base::Closure descheduled_callback_;
   base::Closure command_processed_callback_;
diff --git a/gpu/command_buffer/service/test_helper.cc b/gpu/command_buffer/service/test_helper.cc
index 7d9fb6f..7e9f7bd 100644
--- a/gpu/command_buffer/service/test_helper.cc
+++ b/gpu/command_buffer/service/test_helper.cc
@@ -440,7 +440,7 @@
     EXPECT_CALL(*gl, BindTexture(GL_TEXTURE_2D, tx_ids[1]))
         .Times(1)
         .RetiresOnSaturation();
-    EXPECT_CALL(*gl, TexImage2D(GL_TEXTURE_2D, 0, GL_RED_EXT, width, width, 0,
+    EXPECT_CALL(*gl, TexImage2D(GL_TEXTURE_2D, 0, _, width, width, 0,
         GL_RED_EXT, GL_UNSIGNED_BYTE, _))
         .Times(1)
         .RetiresOnSaturation();
diff --git a/gpu/khronos_glcts_support/generate_khronos_glcts_tests.py b/gpu/khronos_glcts_support/generate_khronos_glcts_tests.py
index 3147286..2b4705b 100755
--- a/gpu/khronos_glcts_support/generate_khronos_glcts_tests.py
+++ b/gpu/khronos_glcts_support/generate_khronos_glcts_tests.py
@@ -20,6 +20,18 @@
   "mustpass_es20.run" : "ES2-CTS.gtf",
 }
 
+BUILT_IN_TESTS = {
+  "mustpass_es20.run" : [
+    "CTS-Configs.es2",
+    "ES2-CTS.info.vendor",
+    "ES2-CTS.info.renderer",
+    "ES2-CTS.info.version",
+    "ES2-CTS.info.shading_language_version",
+    "ES2-CTS.info.extensions",
+    "ES2-CTS.info.render_target",
+  ],
+}
+
 def ReadFileAsLines(filename):
   """
     Reads a file, yielding each non-blank line
@@ -64,6 +76,13 @@
     run_file_dir = os.path.dirname(run_file)
     suite_prefix = RUN_FILE_SUITE_PREFIX[run_file_name]
     output.write("// " + run_file_name + "\n")
+    builtin_tests = BUILT_IN_TESTS[run_file_name]
+    for test in builtin_tests:
+      output.write(TEST_DEF_TEMPLATE
+        % {
+          "gname": re.sub(r'[^A-Za-z0-9]', '_', test),
+          "cname": test,
+        })
     for test in ReadRunFile(run_file):
       rel_path = os.path.relpath(test, run_file_dir)
       root, ext = os.path.splitext(rel_path)
diff --git a/net/base/directory_lister.cc b/net/base/directory_lister.cc
index 841f454..f746f9b 100644
--- a/net/base/directory_lister.cc
+++ b/net/base/directory_lister.cc
@@ -5,12 +5,12 @@
 #include "net/base/directory_lister.h"
 
 #include <algorithm>
-#include <vector>
 
 #include "base/bind.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_util.h"
 #include "base/i18n/file_util_icu.h"
+#include "base/logging.h"
 #include "base/message_loop/message_loop.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/threading/worker_pool.h"
@@ -73,22 +73,23 @@
               DirectoryLister::SortType sort_type) {
   // Sort the results. See the TODO below (this sort should be removed and we
   // should do it from JS).
-  if (sort_type == DirectoryLister::DATE)
+  if (sort_type == DirectoryLister::DATE) {
     std::sort(data->begin(), data->end(), CompareDate);
-  else if (sort_type == DirectoryLister::FULL_PATH)
+  } else if (sort_type == DirectoryLister::FULL_PATH) {
     std::sort(data->begin(), data->end(), CompareFullPath);
-  else if (sort_type == DirectoryLister::ALPHA_DIRS_FIRST)
+  } else if (sort_type == DirectoryLister::ALPHA_DIRS_FIRST) {
     std::sort(data->begin(), data->end(), CompareAlphaDirsFirst);
-  else
+  } else {
     DCHECK_EQ(DirectoryLister::NO_SORT, sort_type);
+  }
 }
 
 }  // namespace
 
 DirectoryLister::DirectoryLister(const base::FilePath& dir,
                                  DirectoryListerDelegate* delegate)
-    : core_(new Core(dir, false, ALPHA_DIRS_FIRST, this)),
-      delegate_(delegate) {
+    : delegate_(delegate) {
+  core_ = new Core(dir, false, ALPHA_DIRS_FIRST, this);
   DCHECK(delegate_);
   DCHECK(!dir.value().empty());
 }
@@ -97,8 +98,8 @@
                                  bool recursive,
                                  SortType sort,
                                  DirectoryListerDelegate* delegate)
-    : core_(new Core(dir, recursive, sort, this)),
-      delegate_(delegate) {
+    : delegate_(delegate) {
+  core_ = new Core(dir, recursive, sort, this);
   DCHECK(delegate_);
   DCHECK(!dir.value().empty());
 }
@@ -108,11 +109,14 @@
 }
 
 bool DirectoryLister::Start() {
-  return core_->Start();
+  return base::WorkerPool::PostTask(
+      FROM_HERE,
+      base::Bind(&Core::Start, core_),
+      true);
 }
 
 void DirectoryLister::Cancel() {
-  return core_->Cancel();
+  core_->CancelOnOriginThread();
 }
 
 DirectoryLister::Core::Core(const base::FilePath& dir,
@@ -122,29 +126,32 @@
     : dir_(dir),
       recursive_(recursive),
       sort_(sort),
-      lister_(lister) {
+      origin_loop_(base::MessageLoopProxy::current()),
+      lister_(lister),
+      cancelled_(0) {
   DCHECK(lister_);
 }
 
 DirectoryLister::Core::~Core() {}
 
-bool DirectoryLister::Core::Start() {
-  origin_loop_ = base::MessageLoopProxy::current();
+void DirectoryLister::Core::CancelOnOriginThread() {
+  DCHECK(origin_loop_->BelongsToCurrentThread());
 
-  return base::WorkerPool::PostTask(
-      FROM_HERE, base::Bind(&Core::StartInternal, this), true);
+  base::subtle::NoBarrier_Store(&cancelled_, 1);
+  // Core must not call into |lister_| after cancellation, as the |lister_| may
+  // have been destroyed. Setting |lister_| to NULL ensures any such access will
+  // cause a crash.
+  lister_ = nullptr;
 }
 
-void DirectoryLister::Core::Cancel() {
-  lister_ = NULL;
-}
-
-void DirectoryLister::Core::StartInternal() {
+void DirectoryLister::Core::Start() {
+  scoped_ptr<DirectoryList> directory_list(new DirectoryList());
 
   if (!base::DirectoryExists(dir_)) {
     origin_loop_->PostTask(
         FROM_HERE,
-        base::Bind(&DirectoryLister::Core::OnDone, this, ERR_FILE_NOT_FOUND));
+        base::Bind(&Core::DoneOnOriginThread, this,
+                   base::Passed(directory_list.Pass()), ERR_FILE_NOT_FOUND));
     return;
   }
 
@@ -155,12 +162,16 @@
   base::FileEnumerator file_enum(dir_, recursive_, types);
 
   base::FilePath path;
-  std::vector<DirectoryListerData> file_data;
-  while (lister_ && !(path = file_enum.Next()).empty()) {
+  while (!(path = file_enum.Next()).empty()) {
+    // Abort on cancellation. This is purely for performance reasons.
+    // Correctness guarantees are made by checks in DoneOnOriginThread.
+    if (IsCancelled())
+      return;
+
     DirectoryListerData data;
     data.info = file_enum.GetInfo();
     data.path = path;
-    file_data.push_back(data);
+    directory_list->push_back(data);
 
     /* TODO(brettw) bug 24107: It would be nice to send incremental updates.
        We gather them all so they can be sorted, but eventually the sorting
@@ -178,36 +189,40 @@
     */
   }
 
-  SortData(&file_data, sort_);
-  origin_loop_->PostTask(
-      FROM_HERE,
-      base::Bind(&DirectoryLister::Core::SendData, this, file_data));
+  SortData(directory_list.get(), sort_);
 
   origin_loop_->PostTask(
       FROM_HERE,
-      base::Bind(&DirectoryLister::Core::OnDone, this, OK));
+      base::Bind(&Core::DoneOnOriginThread, this,
+                 base::Passed(directory_list.Pass()), OK));
 }
 
-void DirectoryLister::Core::SendData(
-    const std::vector<DirectoryLister::DirectoryListerData>& data) {
+bool DirectoryLister::Core::IsCancelled() const {
+  return !!base::subtle::NoBarrier_Load(&cancelled_);
+}
+
+void DirectoryLister::Core::DoneOnOriginThread(
+    scoped_ptr<DirectoryList> directory_list, int error) const {
   DCHECK(origin_loop_->BelongsToCurrentThread());
-  // We need to check for cancellation (indicated by NULL'ing of |lister_|)
-  // which can happen during each callback.
-  for (size_t i = 0; lister_ && i < data.size(); ++i)
-    lister_->OnReceivedData(data[i]);
+
+  // Need to check if the operation was before first callback.
+  if (IsCancelled())
+    return;
+
+  for (const auto& lister_data : *directory_list) {
+    lister_->OnListFile(lister_data);
+    // Need to check if the operation was cancelled during the callback.
+    if (IsCancelled())
+      return;
+  }
+  lister_->OnListDone(error);
 }
 
-void DirectoryLister::Core::OnDone(int error) {
-  DCHECK(origin_loop_->BelongsToCurrentThread());
-  if (lister_)
-    lister_->OnDone(error);
-}
-
-void DirectoryLister::OnReceivedData(const DirectoryListerData& data) {
+void DirectoryLister::OnListFile(const DirectoryListerData& data) {
   delegate_->OnListFile(data);
 }
 
-void DirectoryLister::OnDone(int error) {
+void DirectoryLister::OnListDone(int error) {
   delegate_->OnListDone(error);
 }
 
diff --git a/net/base/directory_lister.h b/net/base/directory_lister.h
index 5fbc9dc..51387e8 100644
--- a/net/base/directory_lister.h
+++ b/net/base/directory_lister.h
@@ -7,21 +7,22 @@
 
 #include <vector>
 
+#include "base/atomicops.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_path.h"
+#include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop_proxy.h"
 #include "net/base/net_export.h"
 
 namespace net {
 
-//
-// This class provides an API for listing the contents of a directory on the
-// filesystem asynchronously.  It spawns a background thread, and enumerates
-// the specified directory on that thread.  It marshalls WIN32_FIND_DATA
-// structs over to the main application thread.  The consumer of this class
-// is insulated from any of the multi-threading details.
-//
+// This class provides an API for asynchronously listing the contents of a
+// directory on the filesystem.  It runs a task on a background thread, and
+// enumerates all files in the specified directory on that thread.  Destroying
+// the lister cancels the list operation.  The DirectoryLister must only be
+// used on a thread with a MessageLoop.
 class NET_EXPORT DirectoryLister  {
  public:
   // Represents one file found.
@@ -48,6 +49,9 @@
   //   directories first in name order, then files by name order
   // FULL_PATH sorts by paths as strings, ignoring files v. directories
   // DATE sorts by last modified date
+  // TODO(mmenke):  Only NO_SORT and ALPHA_DIRS_FIRST appear to be used in
+  //     production code, and there's very little testing of some of these
+  //     options.  Remove unused options, improve testing of the others.
   enum SortType {
     NO_SORT,
     DATE,
@@ -74,6 +78,15 @@
   void Cancel();
 
  private:
+  typedef std::vector<DirectoryListerData> DirectoryList;
+
+  // Class responsible for retrieving and sorting the actual directory list on
+  // a worker pool thread. Created on the DirectoryLister's thread. As it's
+  // refcounted, it's destroyed when the final reference is released, which may
+  // happen on either thread.
+  //
+  // It's kept alive during the calls to Start() and DoneOnOriginThread() by the
+  // reference owned by the callback itself.
   class Core : public base::RefCountedThreadSafe<Core> {
    public:
     Core(const base::FilePath& dir,
@@ -81,9 +94,11 @@
          SortType sort,
          DirectoryLister* lister);
 
-    bool Start();
+    // May only be called on a worker pool thread.
+    void Start();
 
-    void Cancel();
+    // Must be called on the origin thread.
+    void CancelOnOriginThread();
 
    private:
     friend class base::RefCountedThreadSafe<Core>;
@@ -91,28 +106,35 @@
 
     ~Core();
 
-    // This method runs on a WorkerPool thread.
-    void StartInternal();
+    // Called on both threads.
+    bool IsCancelled() const;
 
-    void SendData(const std::vector<DirectoryListerData>& data);
+    // Called on origin thread.
+    void DoneOnOriginThread(scoped_ptr<DirectoryList> directory_list,
+                            int error) const;
 
-    void OnDone(int error);
+    const base::FilePath dir_;
+    const bool recursive_;
+    const SortType sort_;
+    const scoped_refptr<base::MessageLoopProxy> origin_loop_;
 
-    base::FilePath dir_;
-    bool recursive_;
-    SortType sort_;
-    scoped_refptr<base::MessageLoopProxy> origin_loop_;
-
-    // |lister_| gets set to NULL when canceled.
+    // Only used on the origin thread.
     DirectoryLister* lister_;
 
+    // Set to 1 on cancellation. Used both to abort listing files early on the
+    // worker pool thread for performance reasons and to ensure |lister_| isn't
+    // called after cancellation on the origin thread.
+    base::subtle::Atomic32 cancelled_;
+
     DISALLOW_COPY_AND_ASSIGN(Core);
   };
 
-  void OnReceivedData(const DirectoryListerData& data);
-  void OnDone(int error);
+  // Call into the corresponding DirectoryListerDelegate. Must not be called
+  // after cancellation.
+  void OnListFile(const DirectoryListerData& data);
+  void OnListDone(int error);
 
-  const scoped_refptr<Core> core_;
+  scoped_refptr<Core> core_;
   DirectoryListerDelegate* const delegate_;
 
   DISALLOW_COPY_AND_ASSIGN(DirectoryLister);
diff --git a/net/base/directory_lister_unittest.cc b/net/base/directory_lister_unittest.cc
index 869e4f6..adc3d5e 100644
--- a/net/base/directory_lister_unittest.cc
+++ b/net/base/directory_lister_unittest.cc
@@ -4,12 +4,15 @@
 
 #include <list>
 #include <utility>
+#include <vector>
 
+#include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/i18n/file_util_icu.h"
 #include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
 #include "net/base/directory_lister.h"
 #include "net/base/net_errors.h"
@@ -18,29 +21,59 @@
 
 namespace net {
 
+namespace {
+
+const int kMaxDepth = 3;
+const int kBranchingFactor = 4;
+const int kFilesPerDirectory = 5;
+
 class ListerDelegate : public DirectoryLister::DirectoryListerDelegate {
  public:
-  ListerDelegate(bool recursive,
-                 bool quit_loop_after_each_file)
-      : error_(-1),
-        recursive_(recursive),
-        quit_loop_after_each_file_(quit_loop_after_each_file) {
+  explicit ListerDelegate(bool recursive)
+      : cancel_lister_on_list_file_(false),
+        cancel_lister_on_list_done_(false),
+        lister_(nullptr),
+        done_(false),
+        error_(-1),
+        recursive_(recursive) {
+  }
+
+  // When set to true, this signals that the directory list operation should be
+  // cancelled (And the run loop quit) in the first call to OnListFile.
+  void set_cancel_lister_on_list_file(bool cancel_lister_on_list_file) {
+    cancel_lister_on_list_file_ = cancel_lister_on_list_file;
+  }
+
+  // When set to true, this signals that the directory list operation should be
+  // cancelled (And the run loop quit) when OnDone is called.
+  void set_cancel_lister_on_list_done(bool cancel_lister_on_list_done) {
+    cancel_lister_on_list_done_ = cancel_lister_on_list_done;
   }
 
   void OnListFile(const DirectoryLister::DirectoryListerData& data) override {
+    ASSERT_FALSE(done_);
+
     file_list_.push_back(data.info);
     paths_.push_back(data.path);
-    if (quit_loop_after_each_file_)
-      base::MessageLoop::current()->Quit();
+    if (cancel_lister_on_list_file_) {
+      lister_->Cancel();
+      run_loop.Quit();
+    }
   }
 
   void OnListDone(int error) override {
+    ASSERT_FALSE(done_);
+
+    done_ = true;
     error_ = error;
-    base::MessageLoop::current()->Quit();
     if (recursive_)
       CheckRecursiveSort();
     else
       CheckSort();
+
+    if (cancel_lister_on_list_done_)
+      lister_->Cancel();
+    run_loop.Quit();
   }
 
   void CheckRecursiveSort() {
@@ -77,25 +110,45 @@
     }
   }
 
+  void Run(DirectoryLister* lister) {
+    lister_ = lister;
+    lister_->Start();
+    run_loop.Run();
+  }
+
   int error() const { return error_; }
 
   int num_files() const { return file_list_.size(); }
 
+  bool done() const { return done_; }
+
  private:
+  bool cancel_lister_on_list_file_;
+  bool cancel_lister_on_list_done_;
+
+  // This is owned by the individual tests, rather than the ListerDelegate.
+  DirectoryLister* lister_;
+
+  base::RunLoop run_loop;
+
+  bool done_;
   int error_;
   bool recursive_;
-  bool quit_loop_after_each_file_;
+
   std::vector<base::FileEnumerator::FileInfo> file_list_;
   std::vector<base::FilePath> paths_;
 };
 
+}  // namespace
+
 class DirectoryListerTest : public PlatformTest {
  public:
-  void SetUp() override {
-    const int kMaxDepth = 3;
-    const int kBranchingFactor = 4;
-    const int kFilesPerDirectory = 5;
+  DirectoryListerTest()
+      : total_created_file_system_objects_in_temp_root_dir_(0),
+        created_file_system_objects_in_temp_root_dir_(0) {
+  }
 
+  void SetUp() override {
     // Randomly create a directory structure of depth 3 in a temporary root
     // directory.
     std::list<std::pair<base::FilePath, int> > directories;
@@ -110,12 +163,18 @@
         base::File file(file_path,
                         base::File::FLAG_CREATE | base::File::FLAG_WRITE);
         ASSERT_TRUE(file.IsValid());
+        ++total_created_file_system_objects_in_temp_root_dir_;
+        if (dir_data.first == temp_root_dir_.path())
+          ++created_file_system_objects_in_temp_root_dir_;
       }
       if (dir_data.second < kMaxDepth - 1) {
         for (int i = 0; i < kBranchingFactor; i++) {
           std::string dir_name = base::StringPrintf("child_dir_%d", i);
           base::FilePath dir_path = dir_data.first.AppendASCII(dir_name);
           ASSERT_TRUE(base::CreateDirectory(dir_path));
+          ++total_created_file_system_objects_in_temp_root_dir_;
+          if (dir_data.first == temp_root_dir_.path())
+            ++created_file_system_objects_in_temp_root_dir_;
           directories.push_back(std::make_pair(dir_path, dir_data.second + 1));
         }
       }
@@ -127,62 +186,125 @@
     return temp_root_dir_.path();
   }
 
+  int expected_list_length_recursive() const {
+    // List should include everything but the top level directory, and does not
+    // include "..".
+    return total_created_file_system_objects_in_temp_root_dir_;
+  }
+
+  int expected_list_length_non_recursive() const {
+    // List should include everything in the top level directory, and "..".
+    return created_file_system_objects_in_temp_root_dir_ + 1;
+  }
+
  private:
+  // Number of files and directories created in SetUp, excluding
+  // |temp_root_dir_| itself.  Includes all nested directories and their files.
+  int total_created_file_system_objects_in_temp_root_dir_;
+  // Number of files and directories created directly in |temp_root_dir_|.
+  int created_file_system_objects_in_temp_root_dir_;
+
   base::ScopedTempDir temp_root_dir_;
 };
 
 TEST_F(DirectoryListerTest, BigDirTest) {
-  ListerDelegate delegate(false, false);
+  ListerDelegate delegate(false);
   DirectoryLister lister(root_path(), &delegate);
-  lister.Start();
+  delegate.Run(&lister);
 
-  base::MessageLoop::current()->Run();
-
+  EXPECT_TRUE(delegate.done());
   EXPECT_EQ(OK, delegate.error());
+  EXPECT_EQ(expected_list_length_non_recursive(), delegate.num_files());
 }
 
 TEST_F(DirectoryListerTest, BigDirRecursiveTest) {
-  ListerDelegate delegate(true, false);
-  DirectoryLister lister(root_path(), true, DirectoryLister::FULL_PATH,
-                         &delegate);
-  lister.Start();
+  ListerDelegate delegate(true);
+  DirectoryLister lister(
+      root_path(), true, DirectoryLister::FULL_PATH, &delegate);
+  delegate.Run(&lister);
 
-  base::MessageLoop::current()->Run();
-
+  EXPECT_TRUE(delegate.done());
   EXPECT_EQ(OK, delegate.error());
-}
-
-TEST_F(DirectoryListerTest, CancelTest) {
-  ListerDelegate delegate(false, true);
-  DirectoryLister lister(root_path(), &delegate);
-  lister.Start();
-
-  base::MessageLoop::current()->Run();
-
-  int num_files = delegate.num_files();
-
-  lister.Cancel();
-
-  base::MessageLoop::current()->RunUntilIdle();
-
-  EXPECT_EQ(num_files, delegate.num_files());
+  EXPECT_EQ(expected_list_length_recursive(), delegate.num_files());
 }
 
 TEST_F(DirectoryListerTest, EmptyDirTest) {
   base::ScopedTempDir tempDir;
   EXPECT_TRUE(tempDir.CreateUniqueTempDir());
 
-  bool kRecursive = false;
-  bool kQuitLoopAfterEachFile = false;
-  ListerDelegate delegate(kRecursive, kQuitLoopAfterEachFile);
+  ListerDelegate delegate(false);
   DirectoryLister lister(tempDir.path(), &delegate);
-  lister.Start();
+  delegate.Run(&lister);
 
-  base::MessageLoop::current()->Run();
-
-  // Contains only the parent directory ("..")
-  EXPECT_EQ(1, delegate.num_files());
+  EXPECT_TRUE(delegate.done());
   EXPECT_EQ(OK, delegate.error());
+  // Contains only the parent directory ("..").
+  EXPECT_EQ(1, delegate.num_files());
+}
+
+// This doesn't really test much, except make sure calling cancel before any
+// callbacks are invoked doesn't crash.  Can't wait for all tasks running on a
+// worker pool to complete, unfortunately.
+// TODO(mmenke):  See if there's a way to make this fail more reliably on
+// regression.
+TEST_F(DirectoryListerTest, BasicCancelTest) {
+  ListerDelegate delegate(false);
+  scoped_ptr<DirectoryLister> lister(new DirectoryLister(
+      root_path(), &delegate));
+  lister->Start();
+  lister->Cancel();
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_FALSE(delegate.done());
+  EXPECT_EQ(0, delegate.num_files());
+}
+
+TEST_F(DirectoryListerTest, CancelOnListFileTest) {
+  ListerDelegate delegate(false);
+  DirectoryLister lister(root_path(), &delegate);
+  delegate.set_cancel_lister_on_list_file(true);
+  delegate.Run(&lister);
+
+  EXPECT_FALSE(delegate.done());
+  EXPECT_EQ(1, delegate.num_files());
+}
+
+TEST_F(DirectoryListerTest, CancelOnListDoneTest) {
+  ListerDelegate delegate(false);
+  DirectoryLister lister(root_path(), &delegate);
+  delegate.set_cancel_lister_on_list_done(true);
+  delegate.Run(&lister);
+
+  EXPECT_TRUE(delegate.done());
+  EXPECT_EQ(OK, delegate.error());
+  EXPECT_EQ(expected_list_length_non_recursive(), delegate.num_files());
+}
+
+TEST_F(DirectoryListerTest, CancelOnLastElementTest) {
+  base::ScopedTempDir tempDir;
+  EXPECT_TRUE(tempDir.CreateUniqueTempDir());
+
+  ListerDelegate delegate(false);
+  DirectoryLister lister(tempDir.path(), &delegate);
+  delegate.set_cancel_lister_on_list_file(true);
+  delegate.Run(&lister);
+
+  EXPECT_FALSE(delegate.done());
+  // Contains only the parent directory ("..").
+  EXPECT_EQ(1, delegate.num_files());
+}
+
+TEST_F(DirectoryListerTest, NoSuchDirTest) {
+  base::ScopedTempDir tempDir;
+  EXPECT_TRUE(tempDir.CreateUniqueTempDir());
+
+  ListerDelegate delegate(false);
+  DirectoryLister lister(
+      tempDir.path().AppendASCII("this_path_does_not_exist"), &delegate);
+  delegate.Run(&lister);
+
+  EXPECT_EQ(ERR_FILE_NOT_FOUND, delegate.error());
+  EXPECT_EQ(0, delegate.num_files());
 }
 
 }  // namespace net
diff --git a/net/base/net_util.cc b/net/base/net_util.cc
index 3b49dff..6f28068 100644
--- a/net/base/net_util.cc
+++ b/net/base/net_util.cc
@@ -107,6 +107,7 @@
   143,  // imap2
   179,  // BGP
   389,  // ldap
+  443,  // https / wss (see https://crbug.com/436451)
   465,  // smtp+ssl
   512,  // print / exec
   513,  // login
@@ -144,6 +145,11 @@
   22,   // ssh
 };
 
+// HTTPS and WSS override the following restricted port.
+static const int kAllowedHttpsOrWssPorts[] = {
+  443,  // https / wss
+};
+
 bool IPNumberPrefixCheck(const IPAddressNumber& ip_number,
                          const unsigned char* ip_prefix,
                          size_t prefix_length_in_bits) {
@@ -320,6 +326,29 @@
   return IsPortAllowedByDefault(port);
 }
 
+bool IsPortAllowedByHttpsOrWss(int port) {
+  int array_size = arraysize(kAllowedHttpsOrWssPorts);
+  for (int i = 0; i < array_size; i++) {
+    if (kAllowedHttpsOrWssPorts[i] == port) {
+        return true;
+    }
+  }
+  // Port not explicitly allowed by HTTPS or WSS, so return the default
+  // restrictions.
+  return IsPortAllowedByDefault(port);
+}
+
+bool IsEffectivePortAllowedByScheme(const GURL& url) {
+  int port = url.EffectiveIntPort();
+  if (url.SchemeIs("ftp")) {
+    return IsPortAllowedByFtp(port);
+  } else if (url.SchemeIs("https") || url.SchemeIs("wss")) {
+    return IsPortAllowedByHttpsOrWss(port);
+  } else {
+    return IsPortAllowedByDefault(port);
+  }
+}
+
 bool IsPortAllowedByOverride(int port) {
   if (g_explicitly_allowed_ports.Get().empty())
     return false;
diff --git a/net/base/net_util.h b/net/base/net_util.h
index 9e9dbad..9802097 100644
--- a/net/base/net_util.h
+++ b/net/base/net_util.h
@@ -260,6 +260,15 @@
 // protocol.  Returns true if |port| is allowed, false if it is restricted.
 NET_EXPORT_PRIVATE bool IsPortAllowedByFtp(int port);
 
+// Checks |port| against a list of ports which are restricted by the HTTPS/WSS
+// protocols.  Returns true if |port| is allowed, false if it is restricted.
+NET_EXPORT_PRIVATE bool IsPortAllowedByHttpsOrWss(int port);
+
+// Checks the effective port of the |url| against a list of ports which are
+// restricted by the scheme of the |url|. Returns true if the port is allowed,
+// false if it is restricted.
+NET_EXPORT_PRIVATE bool IsEffectivePortAllowedByScheme(const GURL& url);
+
 // Check if banned |port| has been overriden by an entry in
 // |explicitly_allowed_ports_|.
 NET_EXPORT_PRIVATE bool IsPortAllowedByOverride(int port);
diff --git a/net/disk_cache/blockfile/sparse_control.cc b/net/disk_cache/blockfile/sparse_control.cc
index 30ea836..e5096dc 100644
--- a/net/disk_cache/blockfile/sparse_control.cc
+++ b/net/disk_cache/blockfile/sparse_control.cc
@@ -483,7 +483,7 @@
     return KillChildAndContinue(key, false);
 
   if (child_data_.header.last_block_len < 0 ||
-      child_data_.header.last_block_len > kBlockSize) {
+      child_data_.header.last_block_len >= kBlockSize) {
     // Make sure these values are always within range.
     child_data_.header.last_block_len = 0;
     child_data_.header.last_block = -1;
@@ -590,7 +590,7 @@
   if (child_map_.FindNextBit(&start, last_bit, false)) {
     // Something is not here.
     DCHECK_GE(child_data_.header.last_block_len, 0);
-    DCHECK_LT(child_data_.header.last_block_len, kMaxEntrySize);
+    DCHECK_LT(child_data_.header.last_block_len, kBlockSize);
     int partial_block_len = PartialBlockLength(start);
     if (start == child_offset_ >> 10) {
       // It looks like we don't have anything.
@@ -615,7 +615,7 @@
     return;
 
   DCHECK_GE(child_data_.header.last_block_len, 0);
-  DCHECK_LT(child_data_.header.last_block_len, kMaxEntrySize);
+  DCHECK_LT(child_data_.header.last_block_len, kBlockSize);
 
   // Write the bitmap.
   int first_bit = child_offset_ >> 10;
@@ -651,11 +651,6 @@
   if (block_index == child_data_.header.last_block)
     return child_data_.header.last_block_len;
 
-  // This may be the last stored index.
-  int entry_len = child_->GetDataSize(kSparseData);
-  if (block_index == entry_len >> 10)
-    return entry_len & (kBlockSize - 1);
-
   // This is really empty.
   return 0;
 }
@@ -769,27 +764,49 @@
   if (!child_)
     return child_len_;  // Move on to the next child.
 
-  // Check that there are no holes in this range.
-  int last_bit = (child_offset_ + child_len_ + 1023) >> 10;
+  // Bits on the bitmap should only be set when the corresponding block was
+  // fully written (it's really being used). If a block is partially used, it
+  // has to start with valid data, the length of the valid data is saved in
+  // |header.last_block_len| and the block itself should match
+  // |header.last_block|.
+  //
+  // In other words, (|header.last_block| + |header.last_block_len|) is the
+  // offset where the last write ended, and data in that block (which is not
+  // marked as used because it is not full) will only be reused if the next
+  // write continues at that point.
+  //
+  // This code has to find if there is any data between child_offset_ and
+  // child_offset_ + child_len_.
+  int last_bit = (child_offset_ + child_len_ + kBlockSize - 1) >> 10;
   int start = child_offset_ >> 10;
   int partial_start_bytes = PartialBlockLength(start);
   int found = start;
   int bits_found = child_map_.FindBits(&found, last_bit, true);
+  bool is_last_block_in_range = start < child_data_.header.last_block &&
+                                child_data_.header.last_block < last_bit;
 
-  // We don't care if there is a partial block in the middle of the range.
   int block_offset = child_offset_ & (kBlockSize - 1);
-  if (!bits_found && partial_start_bytes <= block_offset)
-    return child_len_;
+  if (!bits_found && partial_start_bytes <= block_offset) {
+    if (!is_last_block_in_range)
+      return child_len_;
+    found = last_bit - 1;  // There are some bytes here.
+  }
 
   // We are done. Just break the loop and reset result_ to our real result.
   range_found_ = true;
 
-  // found now points to the first 1. Lets see if we have zeros before it.
-  int empty_start = std::max((found << 10) - child_offset_, 0);
-
   int bytes_found = bits_found << 10;
   bytes_found += PartialBlockLength(found + bits_found);
 
+  // found now points to the first bytes. Lets see if we have data before it.
+  int empty_start = std::max((found << 10) - child_offset_, 0);
+  if (empty_start >= child_len_)
+    return child_len_;
+
+  // At this point we have bytes_found stored after (found << 10), and we want
+  // child_len_ bytes after child_offset_. The first empty_start bytes after
+  // child_offset_ are invalid.
+
   if (start == found)
     bytes_found -= block_offset;
 
@@ -798,7 +815,7 @@
   // query that we have to subtract from the range that we searched.
   result_ = std::min(bytes_found, child_len_ - empty_start);
 
-  if (!bits_found) {
+  if (partial_start_bytes) {
     result_ = std::min(partial_start_bytes - block_offset, child_len_);
     empty_start = 0;
   }
diff --git a/net/disk_cache/entry_unittest.cc b/net/disk_cache/entry_unittest.cc
index aac45ac..03cc86b 100644
--- a/net/disk_cache/entry_unittest.cc
+++ b/net/disk_cache/entry_unittest.cc
@@ -1798,6 +1798,111 @@
   GetAvailableRange();
 }
 
+// Tests that non-sequential writes that are not aligned with the minimum sparse
+// data granularity (1024 bytes) do in fact result in dropped data.
+TEST_F(DiskCacheEntryTest, SparseWriteDropped) {
+  InitCache();
+  std::string key("the first key");
+  disk_cache::Entry* entry;
+  ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+
+  const int kSize = 180;
+  scoped_refptr<net::IOBuffer> buf_1(new net::IOBuffer(kSize));
+  scoped_refptr<net::IOBuffer> buf_2(new net::IOBuffer(kSize));
+  CacheTestFillBuffer(buf_1->data(), kSize, false);
+
+  // Do small writes (180 bytes) that get increasingly close to a 1024-byte
+  // boundary. All data should be dropped until a boundary is crossed, at which
+  // point the data after the boundary is saved (at least for a while).
+  int offset = 1024 - 500;
+  int rv = 0;
+  net::TestCompletionCallback cb;
+  int64 start;
+  for (int i = 0; i < 5; i++) {
+    // Check result of last GetAvailableRange.
+    EXPECT_EQ(0, rv);
+
+    rv = entry->WriteSparseData(offset, buf_1.get(), kSize, cb.callback());
+    EXPECT_EQ(kSize, cb.GetResult(rv));
+
+    rv = entry->GetAvailableRange(offset - 100, kSize, &start, cb.callback());
+    EXPECT_EQ(0, cb.GetResult(rv));
+
+    rv = entry->GetAvailableRange(offset, kSize, &start, cb.callback());
+    rv = cb.GetResult(rv);
+    if (!rv) {
+      rv = entry->ReadSparseData(offset, buf_2.get(), kSize, cb.callback());
+      EXPECT_EQ(0, cb.GetResult(rv));
+      rv = 0;
+    }
+    offset += 1024 * i + 100;
+  }
+
+  // The last write started 100 bytes below a bundary, so there should be 80
+  // bytes after the boundary.
+  EXPECT_EQ(80, rv);
+  EXPECT_EQ(1024 * 7, start);
+  rv = entry->ReadSparseData(start, buf_2.get(), kSize, cb.callback());
+  EXPECT_EQ(80, cb.GetResult(rv));
+  EXPECT_EQ(0, memcmp(buf_1.get()->data() + 100, buf_2.get()->data(), 80));
+
+  // And even that part is dropped when another write changes the offset.
+  offset = start;
+  rv = entry->WriteSparseData(0, buf_1.get(), kSize, cb.callback());
+  EXPECT_EQ(kSize, cb.GetResult(rv));
+
+  rv = entry->GetAvailableRange(offset, kSize, &start, cb.callback());
+  EXPECT_EQ(0, cb.GetResult(rv));
+  entry->Close();
+}
+
+// Tests that small sequential writes are not dropped.
+TEST_F(DiskCacheEntryTest, SparseSquentialWriteNotDropped) {
+  InitCache();
+  std::string key("the first key");
+  disk_cache::Entry* entry;
+  ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+
+  const int kSize = 180;
+  scoped_refptr<net::IOBuffer> buf_1(new net::IOBuffer(kSize));
+  scoped_refptr<net::IOBuffer> buf_2(new net::IOBuffer(kSize));
+  CacheTestFillBuffer(buf_1->data(), kSize, false);
+
+  // Any starting offset is fine as long as it is 1024-bytes aligned.
+  int rv = 0;
+  net::TestCompletionCallback cb;
+  int64 start;
+  int64 offset = 1024 * 11;
+  for (; offset < 20000; offset += kSize) {
+    rv = entry->WriteSparseData(offset, buf_1.get(), kSize, cb.callback());
+    EXPECT_EQ(kSize, cb.GetResult(rv));
+
+    rv = entry->GetAvailableRange(offset, kSize, &start, cb.callback());
+    EXPECT_EQ(kSize, cb.GetResult(rv));
+    EXPECT_EQ(offset, start);
+
+    rv = entry->ReadSparseData(offset, buf_2.get(), kSize, cb.callback());
+    EXPECT_EQ(kSize, cb.GetResult(rv));
+    EXPECT_EQ(0, memcmp(buf_1.get()->data(), buf_2.get()->data(), kSize));
+  }
+
+  entry->Close();
+  FlushQueueForTest();
+
+  // Verify again the last write made.
+  ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+  offset -= kSize;
+  rv = entry->GetAvailableRange(offset, kSize, &start, cb.callback());
+  EXPECT_EQ(kSize, cb.GetResult(rv));
+  EXPECT_EQ(offset, start);
+
+  rv = entry->ReadSparseData(offset, buf_2.get(), kSize, cb.callback());
+  EXPECT_EQ(kSize, cb.GetResult(rv));
+  EXPECT_EQ(0, memcmp(buf_1.get()->data(), buf_2.get()->data(), kSize));
+
+  entry->Close();
+}
+
 void DiskCacheEntryTest::CouldBeSparse() {
   std::string key("the first key");
   disk_cache::Entry* entry;
@@ -2133,7 +2238,11 @@
   EXPECT_EQ(0, ReadSparseData(entry, 0, buf2.get(), kSize));
 
   // This read should not change anything.
-  EXPECT_EQ(96, ReadSparseData(entry, 24000, buf2.get(), kSize));
+  if (memory_only_ || simple_cache_mode_)
+    EXPECT_EQ(96, ReadSparseData(entry, 24000, buf2.get(), kSize));
+  else
+    EXPECT_EQ(0, ReadSparseData(entry, 24000, buf2.get(), kSize));
+
   EXPECT_EQ(500, ReadSparseData(entry, kSize, buf2.get(), kSize));
   EXPECT_EQ(0, ReadSparseData(entry, 99, buf2.get(), kSize));
 
@@ -2153,7 +2262,11 @@
   EXPECT_EQ(500, cb.GetResult(rv));
   EXPECT_EQ(kSize, start);
   rv = entry->GetAvailableRange(20 * 1024, 10000, &start, cb.callback());
-  EXPECT_EQ(3616, cb.GetResult(rv));
+  if (memory_only_ || simple_cache_mode_)
+    EXPECT_EQ(3616, cb.GetResult(rv));
+  else
+    EXPECT_EQ(3072, cb.GetResult(rv));
+
   EXPECT_EQ(20 * 1024, start);
 
   // 1. Query before a filled 1KB block.
diff --git a/net/ftp/ftp_network_transaction.cc b/net/ftp/ftp_network_transaction.cc
index 74bd6bf..17d5754 100644
--- a/net/ftp/ftp_network_transaction.cc
+++ b/net/ftp/ftp_network_transaction.cc
@@ -8,6 +8,7 @@
 #include "base/bind_helpers.h"
 #include "base/compiler_specific.h"
 #include "base/metrics/histogram.h"
+#include "base/profiler/scoped_tracker.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/string_split.h"
@@ -372,6 +373,11 @@
 }
 
 void FtpNetworkTransaction::OnIOComplete(int result) {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed.
+  tracked_objects::ScopedTracker tracking_profile(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "436634 FtpNetworkTransaction::OnIOComplete"));
+
   int rv = DoLoop(result);
   if (rv != ERR_IO_PENDING)
     DoCallback(rv);
diff --git a/net/http/disk_cache_based_quic_server_info.cc b/net/http/disk_cache_based_quic_server_info.cc
index fd3a6fa..6a5ee17 100644
--- a/net/http/disk_cache_based_quic_server_info.cc
+++ b/net/http/disk_cache_based_quic_server_info.cc
@@ -200,12 +200,18 @@
   rv = DoLoop(rv);
   if (rv == ERR_IO_PENDING)
     return;
+
+  base::WeakPtr<DiskCacheBasedQuicServerInfo> weak_this =
+      weak_factory_.GetWeakPtr();
+
   if (!wait_for_ready_callback_.is_null()) {
     wait_for_data_end_time_ = base::TimeTicks::Now();
     RecordLastFailure();
     base::ResetAndReturn(&wait_for_ready_callback_).Run(rv);
   }
-  if (ready_ && !pending_write_data_.empty()) {
+  // |wait_for_ready_callback_| could delete the object if there is an error.
+  // Check if |weak_this| still exists before accessing it.
+  if (weak_this.get() && ready_ && !pending_write_data_.empty()) {
     DCHECK_EQ(NONE, state_);
     PersistInternal();
   }
diff --git a/net/http/disk_cache_based_quic_server_info_unittest.cc b/net/http/disk_cache_based_quic_server_info_unittest.cc
index 847b3d8..ef69b43 100644
--- a/net/http/disk_cache_based_quic_server_info_unittest.cc
+++ b/net/http/disk_cache_based_quic_server_info_unittest.cc
@@ -14,6 +14,8 @@
 #include "net/quic/quic_server_id.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using std::string;
+
 namespace net {
 namespace {
 
@@ -48,6 +50,27 @@
   0
 };
 
+class DeleteCacheCompletionCallback : public net::TestCompletionCallbackBase {
+ public:
+  explicit DeleteCacheCompletionCallback(QuicServerInfo* server_info)
+      : server_info_(server_info),
+        callback_(base::Bind(&DeleteCacheCompletionCallback::OnComplete,
+                             base::Unretained(this))) {}
+
+  const net::CompletionCallback& callback() const { return callback_; }
+
+ private:
+  void OnComplete(int result) {
+    delete server_info_;
+    SetResult(result);
+  }
+
+  QuicServerInfo* server_info_;
+  net::CompletionCallback callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeleteCacheCompletionCallback);
+};
+
 }  // namespace
 
 // Tests that we can delete a DiskCacheBasedQuicServerInfo object in a
@@ -582,4 +605,24 @@
   RemoveMockTransaction(&kHostInfoTransaction1);
 }
 
+// crbug.com/439209: test deletion of QuicServerInfo object in the callback
+// doesn't crash.
+TEST(DiskCacheBasedQuicServerInfo, DeleteServerInfoInCallback) {
+  // Use the blocking mock backend factory to force asynchronous completion
+  // of quic_server_info->WaitForDataReady(), so that the callback will run.
+  MockBlockingBackendFactory* factory = new MockBlockingBackendFactory();
+  MockHttpCache cache(factory);
+  QuicServerId server_id("www.verisign.com", 443, true, PRIVACY_MODE_DISABLED);
+  QuicServerInfo* quic_server_info =
+      new DiskCacheBasedQuicServerInfo(server_id, cache.http_cache());
+  // |cb| takes owndership and deletes |quic_server_info| when it is called.
+  DeleteCacheCompletionCallback cb(quic_server_info);
+  quic_server_info->Start();
+  int rv = quic_server_info->WaitForDataReady(cb.callback());
+  EXPECT_EQ(ERR_IO_PENDING, rv);
+  // Now complete the backend creation and let the callback run.
+  factory->FinishCreation();
+  EXPECT_EQ(OK, cb.GetResult(rv));
+}
+
 }  // namespace net
diff --git a/net/http/http_auth_handler_negotiate.cc b/net/http/http_auth_handler_negotiate.cc
index 422ddd7..557051c 100644
--- a/net/http/http_auth_handler_negotiate.cc
+++ b/net/http/http_auth_handler_negotiate.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/logging.h"
+#include "base/profiler/scoped_tracker.h"
 #include "base/strings/stringprintf.h"
 #include "net/base/address_family.h"
 #include "net/base/net_errors.h"
@@ -232,6 +233,11 @@
 }
 
 void HttpAuthHandlerNegotiate::OnIOComplete(int result) {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed.
+  tracked_objects::ScopedTracker tracking_profile(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "436634 HttpAuthHandlerNegotiate::OnIOComplete"));
+
   int rv = DoLoop(result);
   if (rv != ERR_IO_PENDING)
     DoCallback(rv);
diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc
index a167e32..a34bef1 100644
--- a/net/http/http_cache.cc
+++ b/net/http/http_cache.cc
@@ -603,7 +603,7 @@
 
 void HttpCache::OnExternalCacheHit(const GURL& url,
                                    const std::string& http_method) {
-  if (!disk_cache_.get())
+  if (!disk_cache_.get() || mode_ == DISABLE)
     return;
 
   HttpRequestInfo request_info;
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index eacd06c..a0248fe 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -3262,8 +3262,8 @@
       new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
 
   // CONNECT to www.google.com:443 via SPDY
-  scoped_ptr<SpdyFrame> connect(spdy_util_.ConstructSpdyConnect(NULL, 0, 1,
-                                                                LOWEST));
+  scoped_ptr<SpdyFrame> connect(spdy_util_.ConstructSpdyConnect(
+      NULL, 0, 1, LOWEST, HostPortPair("www.google.com", 443)));
   // fetch https://www.google.com/ via HTTP
 
   const char get[] = "GET / HTTP/1.1\r\n"
@@ -3349,8 +3349,8 @@
       new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
 
   // CONNECT to www.google.com:443 via SPDY
-  scoped_ptr<SpdyFrame> connect(spdy_util_.ConstructSpdyConnect(NULL, 0, 1,
-                                                                LOWEST));
+  scoped_ptr<SpdyFrame> connect(spdy_util_.ConstructSpdyConnect(
+      NULL, 0, 1, LOWEST, HostPortPair("www.google.com", 443)));
   // fetch https://www.google.com/ via SPDY
   const char* const kMyUrl = "https://www.google.com/";
   scoped_ptr<SpdyFrame> get(
@@ -3438,8 +3438,8 @@
       new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
 
   // CONNECT to www.google.com:443 via SPDY
-  scoped_ptr<SpdyFrame> connect(spdy_util_.ConstructSpdyConnect(NULL, 0, 1,
-                                                                LOWEST));
+  scoped_ptr<SpdyFrame> connect(spdy_util_.ConstructSpdyConnect(
+      NULL, 0, 1, LOWEST, HostPortPair("www.google.com", 443)));
   scoped_ptr<SpdyFrame> get(
       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
 
@@ -3501,8 +3501,8 @@
   request2.load_flags = 0;
 
   // CONNECT to www.google.com:443 via SPDY.
-  scoped_ptr<SpdyFrame> connect1(spdy_util_.ConstructSpdyConnect(NULL, 0, 1,
-                                                                 LOWEST));
+  scoped_ptr<SpdyFrame> connect1(spdy_util_.ConstructSpdyConnect(
+      NULL, 0, 1, LOWEST, HostPortPair("www.google.com", 443)));
   scoped_ptr<SpdyFrame> conn_resp1(
       spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
 
@@ -3651,8 +3651,8 @@
   request2.load_flags = 0;
 
   // CONNECT to www.google.com:443 via SPDY.
-  scoped_ptr<SpdyFrame> connect1(spdy_util_.ConstructSpdyConnect(NULL, 0, 1,
-                                                                 LOWEST));
+  scoped_ptr<SpdyFrame> connect1(spdy_util_.ConstructSpdyConnect(
+      NULL, 0, 1, LOWEST, HostPortPair("www.google.com", 443)));
   scoped_ptr<SpdyFrame> conn_resp1(
       spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
 
@@ -6220,8 +6220,8 @@
   request.url = GURL("https://www.google.com/");
   request.load_flags = 0;
 
-  scoped_ptr<SpdyFrame> conn(spdy_util_.ConstructSpdyConnect(NULL, 0, 1,
-                                                             LOWEST));
+  scoped_ptr<SpdyFrame> conn(spdy_util_.ConstructSpdyConnect(
+      NULL, 0, 1, LOWEST, HostPortPair("www.google.com", 443)));
   scoped_ptr<SpdyFrame> goaway(
       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
   MockWrite data_writes[] = {
@@ -6329,8 +6329,8 @@
   request.url = GURL("https://www.google.com/");
   request.load_flags = 0;
 
-  scoped_ptr<SpdyFrame> conn(spdy_util_.ConstructSpdyConnect(NULL, 0, 1,
-                                                             LOWEST));
+  scoped_ptr<SpdyFrame> conn(spdy_util_.ConstructSpdyConnect(
+      NULL, 0, 1, LOWEST, HostPortPair("www.google.com", 443)));
   scoped_ptr<SpdyFrame> rst(
       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
   MockWrite data_writes[] = {
@@ -6396,8 +6396,8 @@
   scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
 
   // Since we have proxy, should try to establish tunnel.
-  scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyConnect(NULL, 0, 1,
-                                                            LOWEST));
+  scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyConnect(
+      NULL, 0, 1, LOWEST, HostPortPair("www.google.com", 443)));
   scoped_ptr<SpdyFrame> rst(
       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
 
@@ -6407,7 +6407,8 @@
       "proxy-authorization", "Basic Zm9vOmJhcg==",
   };
   scoped_ptr<SpdyFrame> connect2(spdy_util_.ConstructSpdyConnect(
-      kAuthCredentials, arraysize(kAuthCredentials) / 2, 3, LOWEST));
+      kAuthCredentials, arraysize(kAuthCredentials) / 2, 3, LOWEST,
+      HostPortPair("www.google.com", 443)));
   // fetch https://www.google.com/ via HTTP
   const char get[] = "GET / HTTP/1.1\r\n"
     "Host: www.google.com\r\n"
@@ -11312,8 +11313,8 @@
 #undef MAYBE_UseIPConnectionPoolingWithHostCacheExpiration
 
 TEST_P(HttpNetworkTransactionTest, DoNotUseSpdySessionForHttp) {
-  const std::string https_url = "https://www.google.com/";
-  const std::string http_url = "http://www.google.com:443/";
+  const std::string https_url = "https://www.google.com:8080/";
+  const std::string http_url = "http://www.google.com:8080/";
 
   // SPDY GET for HTTPS URL
   scoped_ptr<SpdyFrame> req1(
@@ -11339,10 +11340,10 @@
 
   // HTTP GET for the HTTP URL
   MockWrite writes2[] = {
-    MockWrite(ASYNC, 4,
-              "GET / HTTP/1.1\r\n"
-              "Host: www.google.com:443\r\n"
-              "Connection: keep-alive\r\n\r\n"),
+      MockWrite(ASYNC, 4,
+                "GET / HTTP/1.1\r\n"
+                "Host: www.google.com:8080\r\n"
+                "Connection: keep-alive\r\n\r\n"),
   };
 
   MockRead reads2[] = {
@@ -11393,12 +11394,13 @@
 }
 
 TEST_P(HttpNetworkTransactionTest, DoNotUseSpdySessionForHttpOverTunnel) {
-  const std::string https_url = "https://www.google.com/";
-  const std::string http_url = "http://www.google.com:443/";
+  const std::string https_url = "https://www.google.com:8080/";
+  const std::string http_url = "http://www.google.com:8080/";
 
   // SPDY GET for HTTPS URL (through CONNECT tunnel)
-  scoped_ptr<SpdyFrame> connect(spdy_util_.ConstructSpdyConnect(NULL, 0, 1,
-                                                                LOWEST));
+  const HostPortPair host_port_pair("www.google.com", 8080);
+  scoped_ptr<SpdyFrame> connect(
+      spdy_util_.ConstructSpdyConnect(NULL, 0, 1, LOWEST, host_port_pair));
   scoped_ptr<SpdyFrame> req1(
       spdy_util_.ConstructSpdyGet(https_url.c_str(), false, 1, LOWEST));
   scoped_ptr<SpdyFrame> wrapped_req1(
@@ -11408,7 +11410,7 @@
   SpdyHeaderBlock req2_block;
   req2_block[spdy_util_.GetMethodKey()] = "GET";
   req2_block[spdy_util_.GetPathKey()] = "/";
-  req2_block[spdy_util_.GetHostKey()] = "www.google.com:443";
+  req2_block[spdy_util_.GetHostKey()] = "www.google.com:8080";
   req2_block[spdy_util_.GetSchemeKey()] = "http";
   spdy_util_.MaybeAddVersionHeader(&req2_block);
   scoped_ptr<SpdyFrame> req2(
@@ -11505,8 +11507,8 @@
 
 TEST_P(HttpNetworkTransactionTest, UseSpdySessionForHttpWhenForced) {
   session_deps_.force_spdy_always = true;
-  const std::string https_url = "https://www.google.com/";
-  const std::string http_url = "http://www.google.com:443/";
+  const std::string https_url = "https://www.google.com:8080/";
+  const std::string http_url = "http://www.google.com:8080/";
 
   // SPDY GET for HTTPS URL
   scoped_ptr<SpdyFrame> req1(
diff --git a/net/http/http_proxy_client_socket_pool_unittest.cc b/net/http/http_proxy_client_socket_pool_unittest.cc
index f818432..909da62 100644
--- a/net/http/http_proxy_client_socket_pool_unittest.cc
+++ b/net/http/http_proxy_client_socket_pool_unittest.cc
@@ -393,8 +393,8 @@
     MockRead(ASYNC, 3, "Content-Length: 10\r\n\r\n"),
     MockRead(ASYNC, 4, "0123456789"),
   };
-  scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyConnect(NULL, 0, 1, LOW));
+  scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyConnect(
+      NULL, 0, 1, LOW, HostPortPair("www.google.com", 443)));
   scoped_ptr<SpdyFrame> rst(
       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
   MockWrite spdy_writes[] = {
@@ -502,7 +502,8 @@
   };
 
   scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW));
+      spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW,
+                                      HostPortPair("www.google.com", 443)));
   MockWrite spdy_writes[] = {
     CreateMockWrite(*req, 0, ASYNC)
   };
@@ -544,8 +545,8 @@
     return;
 
   scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize,
-                                      1, MEDIUM));
+      spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, MEDIUM,
+                                      HostPortPair("www.google.com", 443)));
   MockWrite spdy_writes[] = {
     CreateMockWrite(*req, 0, ASYNC)
   };
@@ -651,7 +652,8 @@
     MockRead(ASYNC, ERR_CONNECTION_CLOSED, 2),
   };
   scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW));
+      spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW,
+                                      HostPortPair("www.google.com", 443)));
   MockWrite spdy_writes[] = {
     CreateMockWrite(*req, 0, ASYNC)
   };
@@ -725,7 +727,8 @@
     MockRead(ASYNC, 1, "HTTP/1.1 304 Not Modified\r\n\r\n"),
   };
   scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW));
+      spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW,
+                                      HostPortPair("www.google.com", 443)));
   scoped_ptr<SpdyFrame> rst(
       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
   MockWrite spdy_writes[] = {
@@ -776,7 +779,8 @@
     MockRead(ASYNC, 1, responseText.c_str()),
   };
   scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW));
+      spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW,
+                                      HostPortPair("www.google.com", 443)));
   scoped_ptr<SpdyFrame> rst(
       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
 
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc
index 8369443..5887d2a 100644
--- a/net/http/http_stream_factory_impl_job.cc
+++ b/net/http/http_stream_factory_impl_job.cc
@@ -623,15 +623,15 @@
                                  &request_info_.url, &origin_url_,
                                  priority_));
 
-  // Don't connect to restricted ports.
-  bool is_port_allowed = IsPortAllowedByDefault(origin_.port());
   if (request_info_.url.SchemeIs("ftp")) {
     // Never share connection with other jobs for FTP requests.
     DCHECK(!waiting_job_);
-
-    is_port_allowed = IsPortAllowedByFtp(origin_.port());
   }
-  if (!is_port_allowed && !IsPortAllowedByOverride(origin_.port())) {
+
+  // Don't connect to restricted ports.
+  // Note: origin_.port() == request_info_.url.EffectiveIntPort()
+  if (!IsEffectivePortAllowedByScheme(request_info_.url) &&
+      !IsPortAllowedByOverride(origin_.port())) {
     if (waiting_job_) {
       waiting_job_->Resume(this);
       waiting_job_ = NULL;
diff --git a/net/proxy/proxy_script_decider.cc b/net/proxy/proxy_script_decider.cc
index 939f7af..47e6ca8 100644
--- a/net/proxy/proxy_script_decider.cc
+++ b/net/proxy/proxy_script_decider.cc
@@ -10,6 +10,7 @@
 #include "base/format_macros.h"
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
+#include "base/profiler/scoped_tracker.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
@@ -164,6 +165,11 @@
 }
 
 void ProxyScriptDecider::OnIOCompletion(int result) {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed.
+  tracked_objects::ScopedTracker tracking_profile(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "436634 ProxyScriptDecider::OnIOCompletion"));
+
   DCHECK_NE(STATE_NONE, next_state_);
   int rv = DoLoop(result);
   if (rv != ERR_IO_PENDING) {
diff --git a/net/quic/congestion_control/send_algorithm_simulator.cc b/net/quic/congestion_control/send_algorithm_simulator.cc
index 7653943..eedebe5 100644
--- a/net/quic/congestion_control/send_algorithm_simulator.cc
+++ b/net/quic/congestion_control/send_algorithm_simulator.cc
@@ -14,6 +14,7 @@
 using std::make_pair;
 using std::max;
 using std::min;
+using std::string;
 using std::vector;
 
 namespace net {
diff --git a/net/quic/congestion_control/send_algorithm_simulator.h b/net/quic/congestion_control/send_algorithm_simulator.h
index 7f52d8f..2685d23 100644
--- a/net/quic/congestion_control/send_algorithm_simulator.h
+++ b/net/quic/congestion_control/send_algorithm_simulator.h
@@ -80,7 +80,7 @@
     Transfer(Sender* sender,
              QuicByteCount num_bytes,
              QuicTime start_time,
-             string name);
+             std::string name);
 
     Sender* sender;
     QuicByteCount num_bytes;
@@ -88,7 +88,7 @@
     QuicByteCount bytes_lost;
     QuicByteCount bytes_in_flight;
     QuicTime start_time;
-    string name;
+    std::string name;
   };
 
   struct SentPacket {
@@ -157,8 +157,10 @@
   void AddTransfer(Sender* sender, size_t num_bytes);
 
   // Adds a pending sending to start at the specified time.
-  void AddTransfer(
-      Sender* sender, size_t num_bytes, QuicTime start_time, string name);
+  void AddTransfer(Sender* sender,
+                   size_t num_bytes,
+                   QuicTime start_time,
+                   std::string name);
 
   // Convenience method to transfer all bytes.
   void TransferBytes();
diff --git a/net/quic/crypto/aes_128_gcm_12_decrypter_test.cc b/net/quic/crypto/aes_128_gcm_12_decrypter_test.cc
index 37ee8f9..037bf7e 100644
--- a/net/quic/crypto/aes_128_gcm_12_decrypter_test.cc
+++ b/net/quic/crypto/aes_128_gcm_12_decrypter_test.cc
@@ -7,6 +7,7 @@
 #include "net/quic/test_tools/quic_test_utils.h"
 
 using base::StringPiece;
+using std::string;
 
 namespace {
 
diff --git a/net/quic/crypto/aes_128_gcm_12_encrypter_test.cc b/net/quic/crypto/aes_128_gcm_12_encrypter_test.cc
index 8ccaaed..b7345b5 100644
--- a/net/quic/crypto/aes_128_gcm_12_encrypter_test.cc
+++ b/net/quic/crypto/aes_128_gcm_12_encrypter_test.cc
@@ -7,6 +7,7 @@
 #include "net/quic/test_tools/quic_test_utils.h"
 
 using base::StringPiece;
+using std::string;
 
 namespace {
 
diff --git a/net/quic/crypto/chacha20_poly1305_decrypter_test.cc b/net/quic/crypto/chacha20_poly1305_decrypter_test.cc
index e83acc0..312e2d4 100644
--- a/net/quic/crypto/chacha20_poly1305_decrypter_test.cc
+++ b/net/quic/crypto/chacha20_poly1305_decrypter_test.cc
@@ -7,6 +7,7 @@
 #include "net/quic/test_tools/quic_test_utils.h"
 
 using base::StringPiece;
+using std::string;
 
 namespace {
 
diff --git a/net/quic/crypto/chacha20_poly1305_encrypter_test.cc b/net/quic/crypto/chacha20_poly1305_encrypter_test.cc
index 4f33337..5b05c7f 100644
--- a/net/quic/crypto/chacha20_poly1305_encrypter_test.cc
+++ b/net/quic/crypto/chacha20_poly1305_encrypter_test.cc
@@ -7,6 +7,7 @@
 #include "net/quic/test_tools/quic_test_utils.h"
 
 using base::StringPiece;
+using std::string;
 
 namespace {
 
diff --git a/net/quic/crypto/crypto_handshake_message.cc b/net/quic/crypto/crypto_handshake_message.cc
index 23e8ea2..6ed8014 100644
--- a/net/quic/crypto/crypto_handshake_message.cc
+++ b/net/quic/crypto/crypto_handshake_message.cc
@@ -244,7 +244,6 @@
       case kCFCW:
       case kSFCW:
       case kIRTT:
-      case kKATO:
       case kMSPC:
       case kSWND:
         // uint32 value
diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h
index 57a5508..a9337a5 100644
--- a/net/quic/crypto/crypto_protocol.h
+++ b/net/quic/crypto/crypto_protocol.h
@@ -94,7 +94,7 @@
 const QuicTag kCOPT = TAG('C', 'O', 'P', 'T');   // Connection options
 const QuicTag kICSL = TAG('I', 'C', 'S', 'L');   // Idle connection state
                                                  // lifetime
-const QuicTag kKATO = TAG('K', 'A', 'T', 'O');   // Keepalive timeout
+const QuicTag kSCLS = TAG('S', 'C', 'L', 'S');   // Silently close on timeout
 const QuicTag kMSPC = TAG('M', 'S', 'P', 'C');   // Max streams per connection.
 const QuicTag kIRTT = TAG('I', 'R', 'T', 'T');   // Estimated initial RTT in us.
 const QuicTag kSWND = TAG('S', 'W', 'N', 'D');   // Server's Initial congestion
diff --git a/net/quic/crypto/crypto_utils_test.cc b/net/quic/crypto/crypto_utils_test.cc
index 882a9b5..1395cc3 100644
--- a/net/quic/crypto/crypto_utils_test.cc
+++ b/net/quic/crypto/crypto_utils_test.cc
@@ -7,6 +7,8 @@
 #include "net/quic/test_tools/quic_test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using std::string;
+
 namespace net {
 namespace test {
 namespace {
diff --git a/net/quic/quic_client_session.cc b/net/quic/quic_client_session.cc
index ef8bc20..1a99cf9 100644
--- a/net/quic/quic_client_session.cc
+++ b/net/quic/quic_client_session.cc
@@ -761,6 +761,7 @@
                          read_buffer_->size(),
                          base::Bind(&QuicClientSession::OnReadComplete,
                                     weak_factory_.GetWeakPtr()));
+  UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.AsyncRead", rv == ERR_IO_PENDING);
   if (rv == ERR_IO_PENDING) {
     num_packets_read_ = 0;
     return;
diff --git a/net/quic/quic_config.cc b/net/quic/quic_config.cc
index d2a10a4..bb686e7 100644
--- a/net/quic/quic_config.cc
+++ b/net/quic/quic_config.cc
@@ -431,7 +431,7 @@
       congestion_feedback_(kCGST, PRESENCE_REQUIRED),
       connection_options_(kCOPT, PRESENCE_OPTIONAL),
       idle_connection_state_lifetime_seconds_(kICSL, PRESENCE_REQUIRED),
-      keepalive_timeout_seconds_(kKATO, PRESENCE_OPTIONAL),
+      silent_close_(kSCLS, PRESENCE_OPTIONAL),
       max_streams_per_connection_(kMSPC, PRESENCE_REQUIRED),
       bytes_for_connection_id_(kTCID, PRESENCE_OPTIONAL),
       initial_round_trip_time_us_(kIRTT, PRESENCE_OPTIONAL),
@@ -493,9 +493,12 @@
       idle_connection_state_lifetime_seconds_.GetUint32());
 }
 
-QuicTime::Delta QuicConfig::KeepaliveTimeout() const {
-  return QuicTime::Delta::FromSeconds(
-      keepalive_timeout_seconds_.GetUint32());
+void QuicConfig::SetSilentClose(bool silent_close) {
+  silent_close_.set(silent_close ? 1 : 0, silent_close ? 1 : 0);
+}
+
+bool QuicConfig::SilentClose() const {
+  return silent_close_.GetUint32() > 0;
 }
 
 void QuicConfig::SetMaxStreamsPerConnection(size_t max_streams,
@@ -631,7 +634,6 @@
   // ProcessServerHello.
   return congestion_feedback_.negotiated() &&
       idle_connection_state_lifetime_seconds_.negotiated() &&
-      keepalive_timeout_seconds_.negotiated() &&
       max_streams_per_connection_.negotiated();
 }
 
@@ -641,8 +643,11 @@
   congestion_feedback_.set(congestion_feedback, kQBIC);
   idle_connection_state_lifetime_seconds_.set(kMaximumIdleTimeoutSecs,
                                               kDefaultIdleTimeoutSecs);
-  // kKATO is optional. Return 0 if not negotiated.
-  keepalive_timeout_seconds_.set(0, 0);
+  if (FLAGS_quic_allow_silent_close) {
+    silent_close_.set(1, 0);
+  } else {
+    silent_close_.set(0, 0);
+  }
   SetMaxStreamsPerConnection(kDefaultMaxStreamsPerConnection,
                              kDefaultMaxStreamsPerConnection);
   max_time_before_crypto_handshake_ =
@@ -659,7 +664,7 @@
 void QuicConfig::ToHandshakeMessage(CryptoHandshakeMessage* out) const {
   congestion_feedback_.ToHandshakeMessage(out);
   idle_connection_state_lifetime_seconds_.ToHandshakeMessage(out);
-  keepalive_timeout_seconds_.ToHandshakeMessage(out);
+  silent_close_.ToHandshakeMessage(out);
   max_streams_per_connection_.ToHandshakeMessage(out);
   bytes_for_connection_id_.ToHandshakeMessage(out);
   initial_round_trip_time_us_.ToHandshakeMessage(out);
@@ -686,8 +691,8 @@
         peer_hello, hello_type, error_details);
   }
   if (error == QUIC_NO_ERROR) {
-    error = keepalive_timeout_seconds_.ProcessPeerHello(
-        peer_hello, hello_type, error_details);
+    error =
+        silent_close_.ProcessPeerHello(peer_hello, hello_type, error_details);
   }
   if (error == QUIC_NO_ERROR) {
     error = max_streams_per_connection_.ProcessPeerHello(
diff --git a/net/quic/quic_config.h b/net/quic/quic_config.h
index 507dd9d..12097f8 100644
--- a/net/quic/quic_config.h
+++ b/net/quic/quic_config.h
@@ -277,7 +277,9 @@
 
   QuicTime::Delta IdleConnectionStateLifetime() const;
 
-  QuicTime::Delta KeepaliveTimeout() const;
+  void SetSilentClose(bool silent_close);
+
+  bool SilentClose() const;
 
   void SetMaxStreamsPerConnection(size_t max_streams, size_t default_streams);
 
@@ -400,8 +402,8 @@
   QuicFixedTagVector connection_options_;
   // Idle connection state lifetime
   QuicNegotiableUint32 idle_connection_state_lifetime_seconds_;
-  // Keepalive timeout, or 0 to turn off keepalive probes
-  QuicNegotiableUint32 keepalive_timeout_seconds_;
+  // Whether to use silent close.  Defaults to 0 (false) and is otherwise true.
+  QuicNegotiableUint32 silent_close_;
   // Maximum number of streams that the connection can support.
   QuicNegotiableUint32 max_streams_per_connection_;
   // The number of bytes required for the connection ID.
diff --git a/net/quic/quic_config_test.cc b/net/quic/quic_config_test.cc
index 413d7fb..36321d1 100644
--- a/net/quic/quic_config_test.cc
+++ b/net/quic/quic_config_test.cc
@@ -95,6 +95,7 @@
   client_config.SetConnectionOptionsToSend(copt);
   CryptoHandshakeMessage msg;
   client_config.ToHandshakeMessage(&msg);
+
   string error_details;
   const QuicErrorCode error =
       config_.ProcessPeerHello(msg, CLIENT, &error_details);
@@ -105,7 +106,6 @@
             config_.IdleConnectionStateLifetime());
   EXPECT_EQ(kDefaultMaxStreamsPerConnection,
             config_.MaxStreamsPerConnection());
-  EXPECT_EQ(QuicTime::Delta::FromSeconds(0), config_.KeepaliveTimeout());
   EXPECT_EQ(10 * kNumMicrosPerMilli, config_.ReceivedInitialRoundTripTimeUs());
   EXPECT_TRUE(config_.HasReceivedConnectionOptions());
   EXPECT_EQ(2u, config_.ReceivedConnectionOptions().size());
@@ -152,7 +152,6 @@
             config_.IdleConnectionStateLifetime());
   EXPECT_EQ(kDefaultMaxStreamsPerConnection / 2,
             config_.MaxStreamsPerConnection());
-  EXPECT_EQ(QuicTime::Delta::FromSeconds(0), config_.KeepaliveTimeout());
   EXPECT_EQ(10 * kNumMicrosPerMilli, config_.ReceivedInitialRoundTripTimeUs());
   EXPECT_EQ(config_.ReceivedInitialFlowControlWindowBytes(),
             2 * kInitialSessionFlowControlWindowForTest);
@@ -179,6 +178,7 @@
   const QuicErrorCode error =
       config_.ProcessPeerHello(msg, CLIENT, &error_details);
   EXPECT_EQ(QUIC_NO_ERROR, error);
+  EXPECT_TRUE(config_.negotiated());
 
   EXPECT_FALSE(config_.HasReceivedInitialFlowControlWindowBytes());
 }
@@ -196,6 +196,7 @@
   const QuicErrorCode error =
       config_.ProcessPeerHello(msg, SERVER, &error_details);
   EXPECT_EQ(QUIC_NO_ERROR, error);
+  EXPECT_TRUE(config_.negotiated());
 
   EXPECT_FALSE(config_.HasReceivedInitialFlowControlWindowBytes());
 }
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index c33aec5..74d1758 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -192,7 +192,8 @@
                                bool is_server,
                                bool is_secure,
                                const QuicVersionVector& supported_versions)
-    : framer_(supported_versions, helper->GetClock()->ApproximateNow(),
+    : framer_(supported_versions,
+              helper->GetClock()->ApproximateNow(),
               is_server),
       helper_(helper),
       writer_(writer_factory.Create(this)),
@@ -213,6 +214,7 @@
       largest_seen_packet_with_stop_waiting_(0),
       max_undecryptable_packets_(0),
       pending_version_negotiation_packet_(false),
+      silent_close_enabled_(false),
       received_packet_manager_(&stats_),
       ack_queued_(false),
       num_packets_received_since_last_ack_sent_(0),
@@ -230,7 +232,9 @@
       time_of_last_sent_new_packet_(clock_->ApproximateNow()),
       sequence_number_of_last_sent_packet_(0),
       sent_packet_manager_(
-          is_server, clock_, &stats_,
+          is_server,
+          clock_,
+          &stats_,
           FLAGS_quic_use_bbr_congestion_control ? kBBR : kCubic,
           FLAGS_quic_use_time_loss_detection ? kTime : kNack,
           is_secure),
@@ -268,6 +272,9 @@
   if (config.negotiated()) {
     SetNetworkTimeouts(QuicTime::Delta::Infinite(),
                        config.IdleConnectionStateLifetime());
+    if (FLAGS_quic_allow_silent_close && config.SilentClose()) {
+      silent_close_enabled_ = true;
+    }
   } else {
     SetNetworkTimeouts(config.max_time_before_crypto_handshake(),
                        config.max_idle_time_before_crypto_handshake());
@@ -313,14 +320,8 @@
 void QuicConnection::OnError(QuicFramer* framer) {
   // Packets that we can not or have not decrypted are dropped.
   // TODO(rch): add stats to measure this.
-  if (FLAGS_quic_drop_junk_packets) {
-    if (!connected_ || last_packet_decrypted_ == false) {
-      return;
-    }
-  } else {
-    if (!connected_ || framer->error() == QUIC_DECRYPTION_FAILURE) {
-      return;
-    }
+  if (!connected_ || last_packet_decrypted_ == false) {
+    return;
   }
   SendConnectionCloseWithDetails(framer->error(), framer->detailed_error());
 }
@@ -1854,6 +1855,12 @@
   DVLOG(1) << ENDPOINT << "Force closing " << connection_id()
            << " with error " << QuicUtils::ErrorToString(error)
            << " (" << error << ") " << details;
+  // Don't send explicit connection close packets for timeouts.
+  // This is particularly important on mobile, where connections are short.
+  if (silent_close_enabled_ &&
+      error == QuicErrorCode::QUIC_CONNECTION_TIMED_OUT) {
+    return;
+  }
   ScopedPacketBundler ack_bundler(this, SEND_ACK);
   QuicConnectionCloseFrame* frame = new QuicConnectionCloseFrame();
   frame->error_code = error;
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h
index 14c45a1..76dabff 100644
--- a/net/quic/quic_connection.h
+++ b/net/quic/quic_connection.h
@@ -745,6 +745,9 @@
   // Contains the connection close packet if the connection has been closed.
   scoped_ptr<QuicEncryptedPacket> connection_close_packet_;
 
+  // When true, the connection does not send a close packet on timeout.
+  bool silent_close_enabled_;
+
   FecGroupMap group_map_;
 
   QuicReceivedPacketManager received_packet_manager_;
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index 32d7544..cb46bd9 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -31,6 +31,7 @@
 
 using base::StringPiece;
 using std::map;
+using std::string;
 using std::vector;
 using testing::AnyNumber;
 using testing::AtLeast;
@@ -2987,6 +2988,7 @@
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
   QuicConfig config;
   connection_.SetFromConfig(config);
+  EXPECT_FALSE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_));
 
   const QuicTime::Delta initial_idle_timeout =
       QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1);
@@ -3021,6 +3023,67 @@
   EXPECT_FALSE(connection_.connected());
 }
 
+TEST_P(QuicConnectionTest, TimeoutAfterSendSilentClose) {
+  // Same test as above, but complete a handshake which enables silent close,
+  // causing no connection close packet to be sent.
+  ValueRestore<bool> old_flag(&FLAGS_quic_allow_silent_close, true);
+  EXPECT_TRUE(connection_.connected());
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
+  QuicConfig config;
+
+  // Create a handshake message that also enables silent close.
+  CryptoHandshakeMessage msg;
+  string error_details;
+  QuicConfig client_config;
+  client_config.SetInitialFlowControlWindowToSend(
+      kInitialSessionFlowControlWindowForTest);
+  client_config.SetInitialStreamFlowControlWindowToSend(
+      kInitialStreamFlowControlWindowForTest);
+  client_config.SetInitialSessionFlowControlWindowToSend(
+      kInitialSessionFlowControlWindowForTest);
+  client_config.SetIdleConnectionStateLifetime(
+      QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs),
+      QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs));
+  client_config.ToHandshakeMessage(&msg);
+  const QuicErrorCode error =
+      config.ProcessPeerHello(msg, CLIENT, &error_details);
+  EXPECT_EQ(QUIC_NO_ERROR, error);
+
+  connection_.SetFromConfig(config);
+  EXPECT_TRUE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_));
+
+  const QuicTime::Delta default_idle_timeout =
+      QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs - 1);
+  const QuicTime::Delta five_ms = QuicTime::Delta::FromMilliseconds(5);
+  QuicTime default_timeout = clock_.ApproximateNow().Add(default_idle_timeout);
+
+  // When we send a packet, the timeout will change to 5ms +
+  // kInitialIdleTimeoutSecs.
+  clock_.AdvanceTime(five_ms);
+
+  // Send an ack so we don't set the retransmission alarm.
+  SendAckPacketToPeer();
+  EXPECT_EQ(default_timeout, connection_.GetTimeoutAlarm()->deadline());
+
+  // The original alarm will fire.  We should not time out because we had a
+  // network event at t=5ms.  The alarm will reregister.
+  clock_.AdvanceTime(default_idle_timeout.Subtract(five_ms));
+  EXPECT_EQ(default_timeout, clock_.ApproximateNow());
+  connection_.GetTimeoutAlarm()->Fire();
+  EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
+  EXPECT_TRUE(connection_.connected());
+  EXPECT_EQ(default_timeout.Add(five_ms),
+            connection_.GetTimeoutAlarm()->deadline());
+
+  // This time, we should time out.
+  EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_CONNECTION_TIMED_OUT, false));
+  clock_.AdvanceTime(five_ms);
+  EXPECT_EQ(default_timeout.Add(five_ms), clock_.ApproximateNow());
+  connection_.GetTimeoutAlarm()->Fire();
+  EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
+  EXPECT_FALSE(connection_.connected());
+}
+
 TEST_P(QuicConnectionTest, SendScheduler) {
   // Test that if we send a packet without delay, it is not queued.
   QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc
index fd740dd..6777b2e 100644
--- a/net/quic/quic_crypto_client_stream.cc
+++ b/net/quic/quic_crypto_client_stream.cc
@@ -12,6 +12,8 @@
 #include "net/quic/quic_protocol.h"
 #include "net/quic/quic_session.h"
 
+using std::string;
+
 namespace net {
 
 QuicCryptoClientStream::ChannelIDSourceCallbackImpl::
diff --git a/net/quic/quic_crypto_client_stream.h b/net/quic/quic_crypto_client_stream.h
index f2a4244..ae9304c 100644
--- a/net/quic/quic_crypto_client_stream.h
+++ b/net/quic/quic_crypto_client_stream.h
@@ -81,7 +81,7 @@
 
     // ProofVerifierCallback interface.
     void Run(bool ok,
-             const string& error_details,
+             const std::string& error_details,
              scoped_ptr<ProofVerifyDetails>* details) override;
 
     // Cancel causes any future callbacks to be ignored. It must be called on
@@ -208,7 +208,7 @@
   // verification. These members must not be used after
   // STATE_VERIFY_PROOF_COMPLETE.
   bool verify_ok_;
-  string verify_error_details_;
+  std::string verify_error_details_;
   scoped_ptr<ProofVerifyDetails> verify_details_;
 
   DISALLOW_COPY_AND_ASSIGN(QuicCryptoClientStream);
diff --git a/net/quic/quic_crypto_client_stream_test.cc b/net/quic/quic_crypto_client_stream_test.cc
index 8e14d77..584b6fb 100644
--- a/net/quic/quic_crypto_client_stream_test.cc
+++ b/net/quic/quic_crypto_client_stream_test.cc
@@ -18,6 +18,8 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using std::string;
+
 namespace net {
 namespace test {
 namespace {
@@ -98,7 +100,6 @@
             config->IdleConnectionStateLifetime().ToSeconds());
   EXPECT_EQ(kDefaultMaxStreamsPerConnection,
             config->MaxStreamsPerConnection());
-  EXPECT_EQ(0, config->KeepaliveTimeout().ToSeconds());
 
   const QuicCryptoNegotiatedParameters& crypto_params(
       stream_->crypto_negotiated_params());
diff --git a/net/quic/quic_crypto_server_stream.cc b/net/quic/quic_crypto_server_stream.cc
index c4b5893..baf8a93 100644
--- a/net/quic/quic_crypto_server_stream.cc
+++ b/net/quic/quic_crypto_server_stream.cc
@@ -15,6 +15,8 @@
 #include "net/quic/quic_protocol.h"
 #include "net/quic/quic_session.h"
 
+using std::string;
+
 namespace net {
 
 void ServerHelloNotifier::OnAckNotification(
diff --git a/net/quic/quic_crypto_server_stream_test.cc b/net/quic/quic_crypto_server_stream_test.cc
index f3ea48a..ebb5af2 100644
--- a/net/quic/quic_crypto_server_stream_test.cc
+++ b/net/quic/quic_crypto_server_stream_test.cc
@@ -32,6 +32,7 @@
 }  // namespace net
 
 using std::pair;
+using std::string;
 using testing::_;
 
 namespace net {
diff --git a/net/quic/quic_data_stream.h b/net/quic/quic_data_stream.h
index 0337b30..965a5ae 100644
--- a/net/quic/quic_data_stream.h
+++ b/net/quic/quic_data_stream.h
@@ -12,6 +12,7 @@
 #include <sys/types.h>
 
 #include <list>
+#include <string>
 
 #include "base/basictypes.h"
 #include "base/strings/string_piece.h"
@@ -133,7 +134,7 @@
   QuicPriority priority_;
   // Contains a copy of the decompressed headers until they are consumed
   // via ProcessData or Readv.
-  string decompressed_headers_;
+  std::string decompressed_headers_;
   // True if an error was encountered during decompression.
   bool decompression_failed_;
   // True if the priority has been read, false otherwise.
diff --git a/net/quic/quic_data_stream_test.cc b/net/quic/quic_data_stream_test.cc
index 16e6341..cc865c0 100644
--- a/net/quic/quic_data_stream_test.cc
+++ b/net/quic/quic_data_stream_test.cc
@@ -18,6 +18,7 @@
 
 using base::StringPiece;
 using std::min;
+using std::string;
 using testing::AnyNumber;
 using testing::InSequence;
 using testing::Return;
diff --git a/net/quic/quic_default_packet_writer.cc b/net/quic/quic_default_packet_writer.cc
index d851dfb..177d292 100644
--- a/net/quic/quic_default_packet_writer.cc
+++ b/net/quic/quic_default_packet_writer.cc
@@ -6,6 +6,7 @@
 
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/metrics/histogram.h"
 #include "base/metrics/sparse_histogram.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
@@ -24,12 +25,14 @@
 QuicDefaultPacketWriter::~QuicDefaultPacketWriter() {}
 
 WriteResult QuicDefaultPacketWriter::WritePacket(
-    const char* buffer, size_t buf_len,
+    const char* buffer,
+    size_t buf_len,
     const net::IPAddressNumber& self_address,
     const net::IPEndPoint& peer_address) {
   scoped_refptr<StringIOBuffer> buf(
       new StringIOBuffer(std::string(buffer, buf_len)));
   DCHECK(!IsWriteBlocked());
+  base::TimeTicks now = base::TimeTicks::Now();
   int rv = socket_->Write(buf.get(),
                           buf_len,
                           base::Bind(&QuicDefaultPacketWriter::OnWriteComplete,
@@ -45,6 +48,13 @@
     }
   }
 
+  base::TimeDelta delta = base::TimeTicks::Now() - now;
+  if (status == WRITE_STATUS_OK) {
+    UMA_HISTOGRAM_TIMES("Net.QuicSession.PacketWriteTime.Synchronous", delta);
+  } else if (status == WRITE_STATUS_BLOCKED) {
+    UMA_HISTOGRAM_TIMES("Net.QuicSession.PacketWriteTime.Asynchronous", delta);
+  }
+
   return WriteResult(status, rv);
 }
 
diff --git a/net/quic/quic_flags.cc b/net/quic/quic_flags.cc
index c9658c1..306ac2d 100644
--- a/net/quic/quic_flags.cc
+++ b/net/quic/quic_flags.cc
@@ -32,10 +32,6 @@
 // When true, defaults to BBR congestion control instead of Cubic.
 bool FLAGS_quic_use_bbr_congestion_control = false;
 
-// If true, QUIC will be more resilliant to junk packets with valid connection
-// IDs.
-bool FLAGS_quic_drop_junk_packets = true;
-
 // If true, QUIC BBR congestion control may be enabled via Finch and/or via QUIC
 // connection options.
 bool FLAGS_quic_allow_bbr = false;
@@ -61,3 +57,11 @@
 // If true, enables the QUIC bandwidth resumption experiment (triggered by
 // Chrome/Finch).
 bool FLAGS_quic_enable_bandwidth_resumption_experiment = true;
+
+// If true, QUIC congestion control will be paced.  If false, pacing may be
+// controlled by QUIC connection options in the config or by enabling BBR
+// congestion control.
+bool FLAGS_quic_enable_pacing = false;
+
+// If true, the silent close option will be honored.
+bool FLAGS_quic_allow_silent_close = true;
diff --git a/net/quic/quic_flags.h b/net/quic/quic_flags.h
index 32c5edf..05e939e 100644
--- a/net/quic/quic_flags.h
+++ b/net/quic/quic_flags.h
@@ -14,7 +14,6 @@
 NET_EXPORT_PRIVATE extern bool FLAGS_send_quic_crypto_reject_reason;
 NET_EXPORT_PRIVATE extern bool FLAGS_enable_quic_fec;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_bbr_congestion_control;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_drop_junk_packets;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_allow_bbr;
 NET_EXPORT_PRIVATE extern bool FLAGS_allow_truncated_connection_ids_for_quic;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_too_many_outstanding_packets;
@@ -22,5 +21,7 @@
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_record_send_time_before_write;
 NET_EXPORT_PRIVATE
 extern bool FLAGS_quic_enable_bandwidth_resumption_experiment;
+NET_EXPORT_PRIVATE extern bool FLAGS_quic_enable_pacing;
+NET_EXPORT_PRIVATE extern bool FLAGS_quic_allow_silent_close;
 
 #endif  // NET_QUIC_QUIC_FLAGS_H_
diff --git a/net/quic/quic_headers_stream.cc b/net/quic/quic_headers_stream.cc
index 10a02a7..9d26e4a 100644
--- a/net/quic/quic_headers_stream.cc
+++ b/net/quic/quic_headers_stream.cc
@@ -7,6 +7,7 @@
 #include "net/quic/quic_session.h"
 
 using base::StringPiece;
+using std::string;
 
 namespace net {
 
diff --git a/net/quic/quic_reliable_client_stream_test.cc b/net/quic/quic_reliable_client_stream_test.cc
index caa697a..4da460c 100644
--- a/net/quic/quic_reliable_client_stream_test.cc
+++ b/net/quic/quic_reliable_client_stream_test.cc
@@ -90,7 +90,7 @@
 
 TEST_P(QuicReliableClientStreamTest, OnFinRead) {
   InitializeHeaders();
-  string uncompressed_headers =
+  std::string uncompressed_headers =
       SpdyUtils::SerializeUncompressedHeaders(headers_);
   EXPECT_CALL(delegate_, OnDataReceived(StrEq(uncompressed_headers.data()),
                                         uncompressed_headers.size()));
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc
index 56c327c..9f3f3d3 100644
--- a/net/quic/quic_sent_packet_manager.cc
+++ b/net/quic/quic_sent_packet_manager.cc
@@ -134,8 +134,8 @@
         clock_, &rtt_stats_, kReno, stats_, initial_congestion_window_));
   }
   if (HasClientSentConnectionOption(config, kPACE) ||
-      (FLAGS_quic_allow_bbr &&
-       HasClientSentConnectionOption(config, kTBBR))) {
+      FLAGS_quic_enable_pacing ||
+      (FLAGS_quic_allow_bbr && HasClientSentConnectionOption(config, kTBBR))) {
     EnablePacing();
   }
   if (HasClientSentConnectionOption(config, k1CON)) {
diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc
index c1e6f20..1a907ff 100644
--- a/net/quic/quic_sent_packet_manager_test.cc
+++ b/net/quic/quic_sent_packet_manager_test.cc
@@ -1384,6 +1384,20 @@
   EXPECT_TRUE(manager_.using_pacing());
 }
 
+TEST_F(QuicSentPacketManagerTest, EnablePacingViaFlag) {
+  EXPECT_FALSE(manager_.using_pacing());
+
+  // If pacing is enabled via command-line flag, it will be turned on,
+  // regardless of the contents of the config.
+  ValueRestore<bool> old_flag(&FLAGS_quic_enable_pacing, true);
+  QuicConfig config;
+  EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, /* using_pacing= */ true));
+  manager_.SetFromConfig(config);
+
+  EXPECT_TRUE(manager_.using_pacing());
+}
+
 TEST_F(QuicSentPacketManagerTest, NegotiateReceiveWindowFromOptions) {
   EXPECT_EQ(kDefaultSocketReceiveBuffer,
             QuicSentPacketManagerPeer::GetReceiveWindow(&manager_));
diff --git a/net/quic/quic_server_session.cc b/net/quic/quic_server_session.cc
index e0defd6..64857c0 100644
--- a/net/quic/quic_server_session.cc
+++ b/net/quic/quic_server_session.cc
@@ -83,6 +83,11 @@
     return;
   }
 
+  // Only send updates when the application has no data to write.
+  if (HasDataToWrite()) {
+    return;
+  }
+
   // If not enough time has passed since the last time we sent an update to the
   // client, or not enough packets have been sent, then return early.
   const QuicSentPacketManager& sent_packet_manager =
diff --git a/net/quic/quic_server_session.h b/net/quic/quic_server_session.h
index 43107a0..5614b21 100644
--- a/net/quic/quic_server_session.h
+++ b/net/quic/quic_server_session.h
@@ -8,6 +8,7 @@
 #define NET_QUIC_QUIC_SERVER_SESSION_H_
 
 #include <set>
+#include <string>
 #include <vector>
 
 #include "base/basictypes.h"
@@ -67,7 +68,7 @@
   // Override base class to process FEC config received from client.
   void OnConfigNegotiated() override;
 
-  void set_serving_region(string serving_region) {
+  void set_serving_region(std::string serving_region) {
     serving_region_ = serving_region;
   }
 
@@ -96,7 +97,7 @@
 
   // Text describing server location. Sent to the client as part of the bandwith
   // estimate in the source-address token. Optional, can be left empty.
-  string serving_region_;
+  std::string serving_region_;
 
   // Time at which we send the last SCUP to the client.
   QuicTime last_scup_time_;
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index f05395e..1efefda 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -15,7 +15,9 @@
 using base::hash_map;
 using base::hash_set;
 using std::make_pair;
+using std::map;
 using std::max;
+using std::string;
 using std::vector;
 
 namespace net {
diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h
index 7bc743a..3339d42 100644
--- a/net/quic/quic_session.h
+++ b/net/quic/quic_session.h
@@ -7,6 +7,8 @@
 #ifndef NET_QUIC_QUIC_SESSION_H_
 #define NET_QUIC_QUIC_SESSION_H_
 
+#include <map>
+#include <string>
 #include <vector>
 
 #include "base/compiler_specific.h"
diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc
index d953678..e404929 100644
--- a/net/quic/quic_session_test.cc
+++ b/net/quic/quic_session_test.cc
@@ -5,7 +5,6 @@
 #include "net/quic/quic_session.h"
 
 #include <set>
-#include <vector>
 
 #include "base/basictypes.h"
 #include "base/containers/hash_tables.h"
@@ -33,6 +32,7 @@
 
 using base::hash_map;
 using std::set;
+using std::string;
 using std::vector;
 using testing::CreateFunctor;
 using testing::InSequence;
diff --git a/net/quic/quic_spdy_server_stream.h b/net/quic/quic_spdy_server_stream.h
index 54506d1..a8bd9f3 100644
--- a/net/quic/quic_spdy_server_stream.h
+++ b/net/quic/quic_spdy_server_stream.h
@@ -51,7 +51,7 @@
                           base::StringPiece body);
 
   SpdyHeaderBlock headers_;
-  string body_;
+  std::string body_;
   GURL request_url_;
 
   // Buffer into which response header data is read.
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index e7612a0..738326a 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -10,6 +10,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/message_loop/message_loop_proxy.h"
 #include "base/metrics/histogram.h"
+#include "base/profiler/scoped_tracker.h"
 #include "base/rand_util.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
@@ -40,9 +41,6 @@
 #include "base/win/windows_version.h"
 #endif
 
-using std::string;
-using std::vector;
-
 namespace net {
 
 namespace {
@@ -294,6 +292,11 @@
 }
 
 void QuicStreamFactory::Job::OnIOComplete(int rv) {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed.
+  tracked_objects::ScopedTracker tracking_profile(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "436634 QuicStreamFactory::Job::OnIOComplete"));
+
   rv = DoLoop(rv);
 
   if (rv != ERR_IO_PENDING && !callback_.is_null()) {
diff --git a/net/quic/quic_stream_sequencer.cc b/net/quic/quic_stream_sequencer.cc
index 153e6cf..ceeaa94 100644
--- a/net/quic/quic_stream_sequencer.cc
+++ b/net/quic/quic_stream_sequencer.cc
@@ -14,6 +14,7 @@
 using std::make_pair;
 using std::min;
 using std::numeric_limits;
+using std::string;
 
 namespace net {
 
diff --git a/net/quic/quic_stream_sequencer.h b/net/quic/quic_stream_sequencer.h
index 5da2c0e..025dca4 100644
--- a/net/quic/quic_stream_sequencer.h
+++ b/net/quic/quic_stream_sequencer.h
@@ -6,14 +6,12 @@
 #define NET_QUIC_QUIC_STREAM_SEQUENCER_H_
 
 #include <map>
+#include <string>
 
 #include "base/basictypes.h"
 #include "net/base/iovec.h"
 #include "net/quic/quic_protocol.h"
 
-using std::map;
-using std::string;
-
 namespace net {
 
 namespace test {
@@ -103,7 +101,7 @@
   // frames, in which case we will have to allow receipt of overlapping frames.
   // Maybe write new frames into a ring buffer, and keep track of consumed
   // bytes, and gaps.
-  typedef map<QuicStreamOffset, string> FrameMap;
+  typedef std::map<QuicStreamOffset, std::string> FrameMap;
 
   // Stores buffered frames (maps from sequence number -> frame data as string).
   FrameMap buffered_frames_;
diff --git a/net/quic/quic_stream_sequencer_test.cc b/net/quic/quic_stream_sequencer_test.cc
index 43a105b..8a71c4c 100644
--- a/net/quic/quic_stream_sequencer_test.cc
+++ b/net/quic/quic_stream_sequencer_test.cc
@@ -22,6 +22,7 @@
 using std::map;
 using std::min;
 using std::pair;
+using std::string;
 using std::vector;
 using testing::_;
 using testing::AnyNumber;
diff --git a/net/quic/quic_time_wait_list_manager.cc b/net/quic/quic_time_wait_list_manager.cc
index 67d347f..8f1f564 100644
--- a/net/quic/quic_time_wait_list_manager.cc
+++ b/net/quic/quic_time_wait_list_manager.cc
@@ -27,8 +27,9 @@
 
 namespace {
 
-// Time period for which the connection_id should live in time wait state.
-const int kTimeWaitSeconds = 5;
+// Time period for which a given connection_id should live in the time-wait
+// state.
+int64 FLAGS_quic_time_wait_list_seconds = 5;
 
 }  // namespace
 
@@ -88,7 +89,8 @@
     QuicConnectionHelperInterface* helper,
     const QuicVersionVector& supported_versions)
     : helper_(helper),
-      kTimeWaitPeriod_(QuicTime::Delta::FromSeconds(kTimeWaitSeconds)),
+      kTimeWaitPeriod_(
+          QuicTime::Delta::FromSeconds(FLAGS_quic_time_wait_list_seconds)),
       connection_id_clean_up_alarm_(
           helper_->CreateAlarm(new ConnectionIdCleanUpAlarm(this))),
       writer_(writer),
@@ -276,6 +278,7 @@
       break;
     }
     // This connection_id has lived its age, retire it now.
+    DVLOG(1) << "Retiring " << it->first << " from the time-wait state.";
     delete it->second.close_packet;
     connection_id_map_.erase(it);
   }
diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc
index 116d843..a4b90b7 100644
--- a/net/quic/reliable_quic_stream.cc
+++ b/net/quic/reliable_quic_stream.cc
@@ -12,6 +12,7 @@
 
 using base::StringPiece;
 using std::min;
+using std::string;
 
 namespace net {
 
diff --git a/net/quic/reliable_quic_stream.h b/net/quic/reliable_quic_stream.h
index 698fefb..1de6004 100644
--- a/net/quic/reliable_quic_stream.h
+++ b/net/quic/reliable_quic_stream.h
@@ -10,6 +10,7 @@
 #include <sys/types.h>
 
 #include <list>
+#include <string>
 
 #include "base/basictypes.h"
 #include "base/memory/ref_counted.h"
@@ -67,7 +68,7 @@
   // Called to close the entire connection from this end.
   virtual void CloseConnection(QuicErrorCode error);
   virtual void CloseConnectionWithDetails(QuicErrorCode error,
-                                          const string& details);
+                                          const std::string& details);
 
   // Returns the effective priority for the stream.  This value may change
   // during the life of the stream.
@@ -181,11 +182,11 @@
   class ProxyAckNotifierDelegate;
 
   struct PendingData {
-    PendingData(string data_in,
+    PendingData(std::string data_in,
                 scoped_refptr<ProxyAckNotifierDelegate> delegate_in);
     ~PendingData();
 
-    string data;
+    std::string data;
     // Delegate that should be notified when the pending data is acked.
     // Can be nullptr.
     scoped_refptr<ProxyAckNotifierDelegate> delegate;
diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc
index d63a5d8..4a77aa0 100644
--- a/net/quic/reliable_quic_stream_test.cc
+++ b/net/quic/reliable_quic_stream_test.cc
@@ -21,6 +21,7 @@
 
 using base::StringPiece;
 using std::min;
+using std::string;
 using testing::CreateFunctor;
 using testing::InSequence;
 using testing::Invoke;
diff --git a/net/quic/test_tools/mock_crypto_client_stream.cc b/net/quic/test_tools/mock_crypto_client_stream.cc
index eef3b80..b45d371 100644
--- a/net/quic/test_tools/mock_crypto_client_stream.cc
+++ b/net/quic/test_tools/mock_crypto_client_stream.cc
@@ -9,6 +9,8 @@
 #include "net/quic/quic_server_id.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using std::string;
+
 namespace net {
 
 MockCryptoClientStream::MockCryptoClientStream(
diff --git a/net/quic/test_tools/quic_connection_peer.cc b/net/quic/test_tools/quic_connection_peer.cc
index 8a8df46..f986d2e 100644
--- a/net/quic/test_tools/quic_connection_peer.cc
+++ b/net/quic/test_tools/quic_connection_peer.cc
@@ -154,6 +154,11 @@
 }
 
 // static
+bool QuicConnectionPeer::IsSilentCloseEnabled(QuicConnection* connection) {
+  return connection->silent_close_enabled_;
+}
+
+// static
 void QuicConnectionPeer::SwapCrypters(QuicConnection* connection,
                                       QuicFramer* framer) {
   QuicFramerPeer::SwapCrypters(framer, &connection->framer_);
diff --git a/net/quic/test_tools/quic_connection_peer.h b/net/quic/test_tools/quic_connection_peer.h
index d452d43..268b139 100644
--- a/net/quic/test_tools/quic_connection_peer.h
+++ b/net/quic/test_tools/quic_connection_peer.h
@@ -91,6 +91,8 @@
   static void SetPeerAddress(QuicConnection* connection,
                              const IPEndPoint& peer_address);
 
+  static bool IsSilentCloseEnabled(QuicConnection* connection);
+
   static void SwapCrypters(QuicConnection* connection, QuicFramer* framer);
 
   static QuicConnectionHelperInterface* GetHelper(QuicConnection* connection);
diff --git a/net/quic/test_tools/quic_session_peer.cc b/net/quic/test_tools/quic_session_peer.cc
index 14897b2..7dd7b66 100644
--- a/net/quic/test_tools/quic_session_peer.cc
+++ b/net/quic/test_tools/quic_session_peer.cc
@@ -7,6 +7,8 @@
 #include "net/quic/quic_session.h"
 #include "net/quic/reliable_quic_stream.h"
 
+using std::map;
+
 namespace net {
 namespace test {
 
diff --git a/net/quic/test_tools/quic_session_peer.h b/net/quic/test_tools/quic_session_peer.h
index e69f6ba..4a88c88 100644
--- a/net/quic/test_tools/quic_session_peer.h
+++ b/net/quic/test_tools/quic_session_peer.h
@@ -5,6 +5,8 @@
 #ifndef NET_QUIC_TEST_TOOLS_QUIC_SESSION_PEER_H_
 #define NET_QUIC_TEST_TOOLS_QUIC_SESSION_PEER_H_
 
+#include <map>
+
 #include "net/quic/quic_protocol.h"
 #include "net/quic/quic_write_blocked_list.h"
 
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index 6b6efe3..980132d 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -304,16 +304,17 @@
                                       const IPEndPoint& peer_address,
                                       const QuicEncryptedPacket& packet));
   MOCK_METHOD1(SendConnectionClose, void(QuicErrorCode error));
-  MOCK_METHOD2(SendConnectionCloseWithDetails, void(QuicErrorCode error,
-                                                    const string& details));
-  MOCK_METHOD2(SendConnectionClosePacket, void(QuicErrorCode error,
-                                               const string& details));
+  MOCK_METHOD2(SendConnectionCloseWithDetails,
+               void(QuicErrorCode error, const std::string& details));
+  MOCK_METHOD2(SendConnectionClosePacket,
+               void(QuicErrorCode error, const std::string& details));
   MOCK_METHOD3(SendRstStream, void(QuicStreamId id,
                                    QuicRstStreamErrorCode error,
                                    QuicStreamOffset bytes_written));
-  MOCK_METHOD3(SendGoAway, void(QuicErrorCode error,
-                                QuicStreamId last_good_stream_id,
-                                const string& reason));
+  MOCK_METHOD3(SendGoAway,
+               void(QuicErrorCode error,
+                    QuicStreamId last_good_stream_id,
+                    const std::string& reason));
   MOCK_METHOD1(SendBlocked, void(QuicStreamId id));
   MOCK_METHOD2(SendWindowUpdate, void(QuicStreamId id,
                                       QuicStreamOffset byte_offset));
diff --git a/net/socket/socks_client_socket.cc b/net/socket/socks_client_socket.cc
index f7c69f2..ecf717f 100644
--- a/net/socket/socks_client_socket.cc
+++ b/net/socket/socks_client_socket.cc
@@ -8,6 +8,7 @@
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/compiler_specific.h"
+#include "base/profiler/scoped_tracker.h"
 #include "base/sys_byteorder.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_log.h"
@@ -230,6 +231,11 @@
 }
 
 void SOCKSClientSocket::OnIOComplete(int result) {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed.
+  tracked_objects::ScopedTracker tracking_profile(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "436634 SOCKSClientSocket::OnIOComplete"));
+
   DCHECK_NE(STATE_NONE, next_state_);
   int rv = DoLoop(result);
   if (rv != ERR_IO_PENDING) {
diff --git a/net/socket/transport_client_socket_pool.h b/net/socket/transport_client_socket_pool.h
index 15cef5c..bcc369f 100644
--- a/net/socket/transport_client_socket_pool.h
+++ b/net/socket/transport_client_socket_pool.h
@@ -10,6 +10,7 @@
 #include "base/basictypes.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/profiler/scoped_tracker.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "net/base/host_port_pair.h"
@@ -319,6 +320,11 @@
 
 template <class T>
 void TransportConnectJobHelper::OnIOComplete(T* job, int result) {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed.
+  tracked_objects::ScopedTracker tracking_profile(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "436634 TransportConnectJobHelper::OnIOComplete"));
+
   result = this->DoLoop(job, result);
   if (result != ERR_IO_PENDING)
     job->NotifyDelegateOfCompletion(result);  // Deletes |job| and |this|
diff --git a/net/spdy/buffered_spdy_framer.cc b/net/spdy/buffered_spdy_framer.cc
index f3fc575..568507e 100644
--- a/net/spdy/buffered_spdy_framer.cc
+++ b/net/spdy/buffered_spdy_framer.cc
@@ -336,7 +336,7 @@
 }
 
 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyPingIR).
-SpdyFrame* BufferedSpdyFramer::CreatePingFrame(uint32 unique_id,
+SpdyFrame* BufferedSpdyFramer::CreatePingFrame(SpdyPingId unique_id,
                                                bool is_ack) const {
   SpdyPingIR ping_ir(unique_id);
   ping_ir.set_is_ack(is_ack);
diff --git a/net/spdy/buffered_spdy_framer.h b/net/spdy/buffered_spdy_framer.h
index 1227a42..b8428ce 100644
--- a/net/spdy/buffered_spdy_framer.h
+++ b/net/spdy/buffered_spdy_framer.h
@@ -194,7 +194,7 @@
   SpdyFrame* CreateRstStream(SpdyStreamId stream_id,
                              SpdyRstStreamStatus status) const;
   SpdyFrame* CreateSettings(const SettingsMap& values) const;
-  SpdyFrame* CreatePingFrame(uint32 unique_id, bool is_ack) const;
+  SpdyFrame* CreatePingFrame(SpdyPingId unique_id, bool is_ack) const;
   SpdyFrame* CreateGoAway(
       SpdyStreamId last_accepted_stream_id,
       SpdyGoAwayStatus status) const;
diff --git a/net/spdy/fuzzing/hpack_fuzz_util.cc b/net/spdy/fuzzing/hpack_fuzz_util.cc
index 58f2ec1..29604fe 100644
--- a/net/spdy/fuzzing/hpack_fuzz_util.cc
+++ b/net/spdy/fuzzing/hpack_fuzz_util.cc
@@ -107,7 +107,8 @@
 
 // static
 size_t HpackFuzzUtil::SampleExponential(size_t mean, size_t sanity_bound) {
-  return std::min<size_t>(-std::log(base::RandDouble()) * mean, sanity_bound);
+  return std::min(static_cast<size_t>(-std::log(base::RandDouble()) * mean),
+                  sanity_bound);
 }
 
 // static
diff --git a/net/spdy/hpack_huffman_table.cc b/net/spdy/hpack_huffman_table.cc
index 9e8f6a1..d9cff25 100644
--- a/net/spdy/hpack_huffman_table.cc
+++ b/net/spdy/hpack_huffman_table.cc
@@ -8,6 +8,7 @@
 #include <cmath>
 
 #include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
 #include "net/spdy/hpack_input_stream.h"
 #include "net/spdy/hpack_output_stream.h"
 
@@ -56,10 +57,11 @@
 bool HpackHuffmanTable::Initialize(const HpackHuffmanSymbol* input_symbols,
                                    size_t symbol_count) {
   CHECK(!IsInitialized());
+  DCHECK(base::IsValueInRangeForNumericType<uint16>(symbol_count));
 
   std::vector<Symbol> symbols(symbol_count);
   // Validate symbol id sequence, and copy into |symbols|.
-  for (size_t i = 0; i != symbol_count; i++) {
+  for (uint16 i = 0; i < symbol_count; i++) {
     if (i != input_symbols[i].id) {
       failed_symbol_id_ = i;
       return false;
diff --git a/net/spdy/hpack_huffman_table.h b/net/spdy/hpack_huffman_table.h
index f776ddd..55352d4 100644
--- a/net/spdy/hpack_huffman_table.h
+++ b/net/spdy/hpack_huffman_table.h
@@ -67,7 +67,8 @@
   // Prepares HpackHuffmanTable to encode & decode the canonical Huffman
   // code as determined by the given symbols. Must be called exactly once.
   // Returns false if the input symbols define an invalid coding, and true
-  // otherwise. Symbols must be presented in ascending ID order with no gaps.
+  // otherwise. Symbols must be presented in ascending ID order with no gaps,
+  // and |symbol_count| must fit in a uint16.
   bool Initialize(const Symbol* input_symbols, size_t symbol_count);
 
   // Returns whether Initialize() has been successfully called.
diff --git a/net/spdy/hpack_huffman_table_test.cc b/net/spdy/hpack_huffman_table_test.cc
index f3c09d4..b1da6a8 100644
--- a/net/spdy/hpack_huffman_table_test.cc
+++ b/net/spdy/hpack_huffman_table_test.cc
@@ -238,18 +238,12 @@
     {bits32("10011000000000000000000000000000"), 8, 6},  // 8th.
     {bits32("10010000000000000000000000000000"), 5, 7}};  // 7th.
   EXPECT_TRUE(table_.Initialize(code, arraysize(code)));
-
-  EXPECT_THAT(peer_.code_by_id(), ElementsAre(
-      bits32("01100000000000000000000000000000"),
-      bits32("01110000000000000000000000000000"),
-      bits32("00000000000000000000000000000000"),
-      bits32("01000000000000000000000000000000"),
-      bits32("10000000000000000000000000000000"),
-      bits32("10001000000000000000000000000000"),
-      bits32("10011000000000000000000000000000"),
-      bits32("10010000000000000000000000000000")));
-  EXPECT_THAT(peer_.length_by_id(), ElementsAre(
-      4, 4, 2, 3, 5, 5, 8, 5));
+  ASSERT_EQ(arraysize(code), peer_.code_by_id().size());
+  ASSERT_EQ(arraysize(code), peer_.length_by_id().size());
+  for (size_t i = 0; i < arraysize(code); ++i) {
+    EXPECT_EQ(code[i].code, peer_.code_by_id()[i]);
+    EXPECT_EQ(code[i].length, peer_.length_by_id()[i]);
+  }
 
   EXPECT_EQ(1u, peer_.decode_tables().size());
   {
diff --git a/net/spdy/spdy_frame_builder.h b/net/spdy/spdy_frame_builder.h
index 7aa6db4..bd70977 100644
--- a/net/spdy/spdy_frame_builder.h
+++ b/net/spdy/spdy_frame_builder.h
@@ -106,7 +106,7 @@
   }
   bool WriteUInt64(uint64 value) {
     uint32 upper = htonl(value >> 32);
-    uint32 lower = htonl(value);
+    uint32 lower = htonl(static_cast<uint32>(value));
     return (WriteBytes(&upper, sizeof(upper)) &&
             WriteBytes(&lower, sizeof(lower)));
   }
diff --git a/net/spdy/spdy_frame_reader_test.cc b/net/spdy/spdy_frame_reader_test.cc
index 90f593b..8db2d99 100644
--- a/net/spdy/spdy_frame_reader_test.cc
+++ b/net/spdy/spdy_frame_reader_test.cc
@@ -18,8 +18,8 @@
     htons(1), htons(1<<15),
   };
 
-  SpdyFrameReader frame_reader(reinterpret_cast<const char *>(kFrameData),
-                               arraysize(kFrameData) * sizeof(uint16));
+  SpdyFrameReader frame_reader(reinterpret_cast<const char*>(kFrameData),
+                               sizeof(kFrameData));
   EXPECT_FALSE(frame_reader.IsDoneReading());
 
   uint16 uint16_val;
diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc
index f1b1de3..990f722 100644
--- a/net/spdy/spdy_framer.cc
+++ b/net/spdy/spdy_framer.cc
@@ -689,7 +689,7 @@
 
   bool is_control_frame = false;
 
-  uint16 control_frame_type_field =
+  int control_frame_type_field =
       SpdyConstants::DataFrameType(protocol_version());
   // ProcessControlFrameHeader() will set current_frame_type_ to the
   // correct value if this is a valid control frame.
@@ -715,7 +715,9 @@
       }
       // We check control_frame_type_field's validity in
       // ProcessControlFrameHeader().
-      successful_read = reader->ReadUInt16(&control_frame_type_field);
+      uint16 control_frame_type_field_uint16;
+      successful_read = reader->ReadUInt16(&control_frame_type_field_uint16);
+      control_frame_type_field = control_frame_type_field_uint16;
     } else {
       reader->Rewind();
       successful_read = reader->ReadUInt31(&current_frame_stream_id_);
@@ -735,17 +737,14 @@
     bool successful_read = reader->ReadUInt24(&length_field);
     DCHECK(successful_read);
 
-    uint8 control_frame_type_field_uint8 =
-      SpdyConstants::DataFrameType(protocol_version());
+    uint8 control_frame_type_field_uint8;
     successful_read = reader->ReadUInt8(&control_frame_type_field_uint8);
     DCHECK(successful_read);
     // We check control_frame_type_field's validity in
     // ProcessControlFrameHeader().
     control_frame_type_field = control_frame_type_field_uint8;
-    is_control_frame = (protocol_version() > SPDY3) ?
-      control_frame_type_field !=
-      SpdyConstants::SerializeFrameType(protocol_version(), DATA) :
-      control_frame_type_field != 0;
+    is_control_frame = control_frame_type_field !=
+        SpdyConstants::SerializeFrameType(protocol_version(), DATA);
 
     if (is_control_frame) {
       current_frame_length_ = length_field + GetControlFrameHeaderSize();
@@ -838,7 +837,7 @@
   return original_len - len;
 }
 
-void SpdyFramer::ProcessControlFrameHeader(uint16 control_frame_type_field) {
+void SpdyFramer::ProcessControlFrameHeader(int control_frame_type_field) {
   DCHECK_EQ(SPDY_NO_ERROR, error_code_);
   DCHECK_LE(GetControlFrameHeaderSize(), current_frame_buffer_length_);
 
@@ -1191,7 +1190,7 @@
                                   const SpdyMajorVersion spdy_version,
                                   const SpdyHeaderBlock* headers) {
   if (spdy_version < SPDY3) {
-    frame->WriteUInt16(headers->size());
+    frame->WriteUInt16(static_cast<uint16>(headers->size()));
   } else {
     frame->WriteUInt32(headers->size());
   }
@@ -1270,7 +1269,7 @@
   char buf[4];
   DCHECK_LE(length, sizeof(buf));
   for (unsigned i = 1; i <= length; i++) {
-    buf[length - i] = n;
+    buf[length - i] = static_cast<char>(n);
     n >>= 8;
   }
   WriteZ(base::StringPiece(buf, length), clas, out);
@@ -1489,7 +1488,7 @@
           }
           const bool has_priority =
               (current_frame_flags_ & HEADERS_FLAG_PRIORITY) != 0;
-          uint32 priority = 0;
+          SpdyPriority priority = 0;
           if (protocol_version() > SPDY3 && has_priority) {
             // TODO(jgraettinger): Process dependency rather than ignoring it.
             reader.Seek(kPriorityDependencyPayloadSize);
@@ -2471,7 +2470,7 @@
   // which doesn't currently include RST_STREAM payloads. GFE flags have been
   // commented but left in place to simplify future patching.
   // Compute the output buffer size, taking opaque data into account.
-  uint16 expected_length = GetRstStreamMinimumSize();
+  size_t expected_length = GetRstStreamMinimumSize();
   if (protocol_version() > SPDY3) {
     expected_length += rst_stream.description().size();
   }
@@ -2536,6 +2535,9 @@
   for (SpdySettingsIR::ValueMap::const_iterator it = values->begin();
        it != values->end();
        ++it) {
+    int setting_id =
+        SpdyConstants::SerializeSettingId(protocol_version(), it->first);
+    DCHECK_GE(setting_id, 0);
     if (protocol_version() <= SPDY3) {
       uint8 setting_flags = 0;
       if (it->second.persist_value) {
@@ -2544,14 +2546,11 @@
       if (it->second.persisted) {
         setting_flags |= SETTINGS_FLAG_PERSISTED;
       }
-      SettingsFlagsAndId flags_and_id(
-          setting_flags,
-          SpdyConstants::SerializeSettingId(protocol_version(), it->first));
+      SettingsFlagsAndId flags_and_id(setting_flags, setting_id);
       uint32 id_and_flags_wire = flags_and_id.GetWireFormat(protocol_version());
       builder.WriteBytes(&id_and_flags_wire, 4);
     } else {
-      builder.WriteUInt16(SpdyConstants::SerializeSettingId(protocol_version(),
-                                                            it->first));
+      builder.WriteUInt16(static_cast<uint16>(setting_id));
     }
     builder.WriteUInt32(it->second.value);
   }
@@ -2580,7 +2579,7 @@
     const SpdyGoAwayIR& goaway) const {
 
   // Compute the output buffer size, take opaque data into account.
-  uint16 expected_length = GetGoAwayMinimumSize();
+  size_t expected_length = GetGoAwayMinimumSize();
   if (protocol_version() > SPDY3) {
     expected_length += goaway.description().size();
   }
@@ -2639,9 +2638,9 @@
     size += headers.padding_payload_len();
   }
 
-  uint32 priority = headers.priority();
+  SpdyPriority priority = static_cast<SpdyPriority>(headers.priority());
   if (headers.has_priority()) {
-    if (priority > GetLowestPriority()) {
+    if (headers.priority() > GetLowestPriority()) {
       DLOG(DFATAL) << "Priority out-of-bounds.";
       priority = GetLowestPriority();
     }
@@ -2854,13 +2853,15 @@
   SpdyFrameBuilder builder(size, protocol_version());
   builder.BeginNewFrame(*this, ALTSVC, kNoFlags, altsvc.stream_id());
 
+  // TODO(bnc): http://crbug.com/438263
+  // Update the binary format here to the new text-based payload format.
   builder.WriteUInt32(altsvc.max_age());
   builder.WriteUInt16(altsvc.port());
   builder.WriteUInt8(0);  // Reserved.
-  builder.WriteUInt8(altsvc.protocol_id().length());
+  builder.WriteUInt8(static_cast<uint8>(altsvc.protocol_id().length()));
   builder.WriteBytes(altsvc.protocol_id().data(),
                      altsvc.protocol_id().length());
-  builder.WriteUInt8(altsvc.host().length());
+  builder.WriteUInt8(static_cast<uint8>(altsvc.host().length()));
   builder.WriteBytes(altsvc.host().data(), altsvc.host().length());
   builder.WriteBytes(altsvc.origin().data(), altsvc.origin().length());
   DCHECK_LT(GetAltSvcMinimumSize(), builder.length());
@@ -3207,7 +3208,7 @@
     const SpdyNameValueBlock& name_value_block) const {
   // Serialize number of headers.
   if (protocol_version() <= SPDY2) {
-    builder->WriteUInt16(name_value_block.size());
+    builder->WriteUInt16(static_cast<uint16>(name_value_block.size()));
   } else {
     builder->WriteUInt32(name_value_block.size());
   }
diff --git a/net/spdy/spdy_framer.h b/net/spdy/spdy_framer.h
index dcb2911..8224e9e 100644
--- a/net/spdy/spdy_framer.h
+++ b/net/spdy/spdy_framer.h
@@ -653,7 +653,7 @@
   void DeliverHpackBlockAsSpdy3Block();
 
   // Helpers for above internal breakouts from ProcessInput.
-  void ProcessControlFrameHeader(uint16 control_frame_type_field);
+  void ProcessControlFrameHeader(int control_frame_type_field);
   // Always passed exactly 1 setting's worth of data.
   bool ProcessSetting(const char* data);
 
diff --git a/net/spdy/spdy_framer_test.cc b/net/spdy/spdy_framer_test.cc
index 2fac61c..2309bda 100644
--- a/net/spdy/spdy_framer_test.cc
+++ b/net/spdy/spdy_framer_test.cc
@@ -18,13 +18,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/platform_test.h"
 
-using base::StringPiece;
 using std::string;
-using std::max;
-using std::min;
-using std::numeric_limits;
-using testing::ElementsAre;
-using testing::Pair;
 using testing::_;
 
 namespace net {
@@ -368,7 +362,7 @@
 
   bool OnRstStreamFrameData(const char* rst_stream_data, size_t len) override {
     if ((rst_stream_data != NULL) && (len > 0)) {
-      fin_opaque_data_ += std::string(rst_stream_data, len);
+      fin_opaque_data_ += string(rst_stream_data, len);
     }
     return true;
   }
@@ -478,7 +472,7 @@
       // the socket.
       const size_t kMaxReadSize = 32;
       size_t bytes_read =
-          (rand() % min(input_remaining, kMaxReadSize)) + 1;
+          (rand() % std::min(input_remaining, kMaxReadSize)) + 1;
       size_t bytes_processed = framer_.ProcessInput(input_ptr, bytes_read);
       input_remaining -= bytes_processed;
       input_ptr += bytes_processed;
@@ -542,7 +536,7 @@
   SpdyStreamId last_push_promise_promised_stream_;
   int data_bytes_;
   int fin_frame_count_;  // The count of RST_STREAM type frames received.
-  std::string fin_opaque_data_;
+  string fin_opaque_data_;
   int fin_flag_count_;  // The count of frames with the FIN flag set.
   int zero_length_data_frame_count_;  // The count of zero-length data frames.
   int control_frame_header_data_count_;  // The count of chunks received.
@@ -950,8 +944,8 @@
       reinterpret_cast<unsigned char*>(control_frame->data()),
       control_frame->size());
 
-  EXPECT_THAT(visitor.headers_, ElementsAre(
-      Pair("name", value)));
+  EXPECT_THAT(visitor.headers_,
+              testing::ElementsAre(testing::Pair("name", value)));
 }
 
 TEST_P(SpdyFramerTest, BasicCompression) {
@@ -3770,21 +3764,23 @@
   SpdyFramer framer(spdy_version_);
   // Create a GoAway frame that has a few extra bytes at the end.
   // We create enough overhead to overflow the framer's control frame buffer.
-  ASSERT_GE(250u, SpdyFramer::kControlFrameBufferSize);
-  const unsigned char length =  1 + SpdyFramer::kControlFrameBufferSize;
+  ASSERT_LE(SpdyFramer::kControlFrameBufferSize, 250u);
+  const size_t length = SpdyFramer::kControlFrameBufferSize + 1;
   const unsigned char kV3FrameData[] = {  // Also applies for V2.
     0x80, spdy_version_ch_, 0x00, 0x07,
-    0x00, 0x00, 0x00, length,
+    0x00, 0x00, 0x00, static_cast<unsigned char>(length),
     0x00, 0x00, 0x00, 0x00,  // Stream ID
     0x00, 0x00, 0x00, 0x00,  // Status
   };
 
   // SPDY version 4 and up GOAWAY frames are only bound to a minimal length,
   // since it may carry opaque data. Verify that minimal length is tested.
-  const unsigned char less_than_min_length =
+  ASSERT_GT(framer.GetGoAwayMinimumSize(), framer.GetControlFrameHeaderSize());
+  const size_t less_than_min_length =
       framer.GetGoAwayMinimumSize() - framer.GetControlFrameHeaderSize() - 1;
+  ASSERT_LE(less_than_min_length, std::numeric_limits<unsigned char>::max());
   const unsigned char kV4FrameData[] = {
-    0x00, 0x00, static_cast<uint8>(less_than_min_length), 0x07,
+    0x00, 0x00, static_cast<unsigned char>(less_than_min_length), 0x07,
     0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00,  // Stream Id
     0x00, 0x00, 0x00, 0x00,  // Status
@@ -3793,7 +3789,7 @@
   const size_t pad_length =
       length + framer.GetControlFrameHeaderSize() -
       (IsSpdy4() ? sizeof(kV4FrameData) : sizeof(kV3FrameData));
-  string pad('A', pad_length);
+  string pad(pad_length, 'A');
   TestSpdyVisitor visitor(spdy_version_);
 
   if (IsSpdy4()) {
@@ -3893,7 +3889,7 @@
   size_t unframed_data = control_frame->size();
   size_t kReadChunkSize = 5;  // Read five bytes at a time.
   while (unframed_data > 0) {
-    size_t to_read = min(kReadChunkSize, unframed_data);
+    size_t to_read = std::min(kReadChunkSize, unframed_data);
     visitor.SimulateInFramer(
         reinterpret_cast<unsigned char*>(control_frame->data() + framed_data),
         to_read);
@@ -4294,9 +4290,10 @@
   EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
   EXPECT_EQ(0, visitor.zero_length_data_frame_count_);
 
-  EXPECT_THAT(visitor.headers_, ElementsAre(
-      Pair("cookie", "foo=bar; baz=bing; "),
-      Pair("name", "value")));
+  EXPECT_THAT(visitor.headers_,
+              testing::ElementsAre(
+                  testing::Pair("cookie", "foo=bar; baz=bing; "),
+                  testing::Pair("name", "value")));
 }
 
 TEST_P(SpdyFramerTest, ReadHeadersWithContinuationAndFin) {
@@ -4340,9 +4337,10 @@
   EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
   EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
 
-  EXPECT_THAT(visitor.headers_, ElementsAre(
-      Pair("cookie", "foo=bar; baz=bing; "),
-      Pair("name", "value")));
+  EXPECT_THAT(visitor.headers_,
+              testing::ElementsAre(
+                  testing::Pair("cookie", "foo=bar; baz=bing; "),
+                  testing::Pair("name", "value")));
 }
 
 TEST_P(SpdyFramerTest, ReadPushPromiseWithContinuation) {
@@ -4389,9 +4387,10 @@
   EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
   EXPECT_EQ(0, visitor.zero_length_data_frame_count_);
 
-  EXPECT_THAT(visitor.headers_, ElementsAre(
-      Pair("cookie", "foo=bar; baz=bing; "),
-      Pair("name", "value")));
+  EXPECT_THAT(visitor.headers_,
+              testing::ElementsAre(
+                  testing::Pair("cookie", "foo=bar; baz=bing; "),
+                  testing::Pair("name", "value")));
 }
 
 TEST_P(SpdyFramerTest, ReadContinuationWithWrongStreamId) {
@@ -4570,8 +4569,8 @@
   EXPECT_EQ(1, visitor.headers_frame_count_);
   EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
 
-  EXPECT_THAT(visitor.headers_, ElementsAre(
-      Pair("cookie", "foo=bar")));
+  EXPECT_THAT(visitor.headers_,
+              testing::ElementsAre(testing::Pair("cookie", "foo=bar")));
 }
 
 TEST_P(SpdyFramerTest, ReadGarbage) {
@@ -4860,7 +4859,8 @@
     return;
   }
 
-  for (int flags = 0; flags < 256; ++flags) {
+  uint8 flags = 0;
+  do {
     SCOPED_TRACE(testing::Message() << "Flags " << flags);
 
     testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
@@ -4892,7 +4892,7 @@
       EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
           << SpdyFramer::ErrorCodeToString(framer.error_code());
     }
-  }
+  } while (++flags != 0);
 }
 
 TEST_P(SpdyFramerTest, DataFrameFlagsV4) {
@@ -4903,7 +4903,8 @@
   uint8 valid_data_flags = DATA_FLAG_FIN | DATA_FLAG_END_SEGMENT |
       DATA_FLAG_PADDED;
 
-  for (int flags = 0; flags < 256; ++flags) {
+  uint8 flags = 0;
+  do {
     SCOPED_TRACE(testing::Message() << "Flags " << flags);
 
     testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
@@ -4940,7 +4941,7 @@
       EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
           << SpdyFramer::ErrorCodeToString(framer.error_code());
     }
-  }
+  } while (++flags != 0);
 }
 
 TEST_P(SpdyFramerTest, SynStreamFrameFlags) {
@@ -4948,7 +4949,8 @@
     // SYN_STREAM not supported in SPDY>3
     return;
   }
-  for (int flags = 0; flags < 256; ++flags) {
+  uint8 flags = 0;
+  do {
     SCOPED_TRACE(testing::Message() << "Flags " << flags);
 
     testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
@@ -4964,8 +4966,7 @@
     syn_stream.set_priority(1);
     syn_stream.SetHeader("foo", "bar");
     scoped_ptr<SpdyFrame> frame(framer.SerializeSynStream(syn_stream));
-    int set_flags = flags;
-    SetFrameFlags(frame.get(), set_flags, spdy_version_);
+    SetFrameFlags(frame.get(), flags, spdy_version_);
 
     if (flags & ~(CONTROL_FLAG_FIN | CONTROL_FLAG_UNIDIRECTIONAL)) {
       EXPECT_CALL(visitor, OnError(_));
@@ -4994,7 +4995,7 @@
       EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
           << SpdyFramer::ErrorCodeToString(framer.error_code());
     }
-  }
+  } while (++flags != 0);
 }
 
 TEST_P(SpdyFramerTest, SynReplyFrameFlags) {
@@ -5002,7 +5003,8 @@
     // SYN_REPLY not supported in SPDY>3
     return;
   }
-  for (int flags = 0; flags < 256; ++flags) {
+  uint8 flags = 0;
+  do {
     SCOPED_TRACE(testing::Message() << "Flags " << flags);
 
     testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
@@ -5036,11 +5038,12 @@
       EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
           << SpdyFramer::ErrorCodeToString(framer.error_code());
     }
-  }
+  } while (++flags != 0);
 }
 
 TEST_P(SpdyFramerTest, RstStreamFrameFlags) {
-  for (int flags = 0; flags < 256; ++flags) {
+  uint8 flags = 0;
+  do {
     SCOPED_TRACE(testing::Message() << "Flags " << flags);
 
     testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
@@ -5068,12 +5071,13 @@
       EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
           << SpdyFramer::ErrorCodeToString(framer.error_code());
     }
-  }
+  } while (++flags != 0);
 }
 
 TEST_P(SpdyFramerTest, SettingsFrameFlagsOldFormat) {
   if (spdy_version_ > SPDY3) { return; }
-  for (int flags = 0; flags < 256; ++flags) {
+  uint8 flags = 0;
+  do {
     SCOPED_TRACE(testing::Message() << "Flags " << flags);
 
     testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
@@ -5109,12 +5113,13 @@
       EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
           << SpdyFramer::ErrorCodeToString(framer.error_code());
     }
-  }
+  } while (++flags != 0);
 }
 
 TEST_P(SpdyFramerTest, SettingsFrameFlags) {
   if (spdy_version_ <= SPDY3) { return; }
-  for (int flags = 0; flags < 256; ++flags) {
+  uint8 flags = 0;
+  do {
     SCOPED_TRACE(testing::Message() << "Flags " << flags);
 
     testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
@@ -5151,11 +5156,12 @@
       EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
           << SpdyFramer::ErrorCodeToString(framer.error_code());
     }
-  }
+  } while (++flags != 0);
 }
 
 TEST_P(SpdyFramerTest, GoawayFrameFlags) {
-  for (int flags = 0; flags < 256; ++flags) {
+  uint8 flags = 0;
+  do {
     SCOPED_TRACE(testing::Message() << "Flags " << flags);
 
     testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
@@ -5183,11 +5189,12 @@
       EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
           << SpdyFramer::ErrorCodeToString(framer.error_code());
     }
-  }
+  } while (++flags != 0);
 }
 
 TEST_P(SpdyFramerTest, HeadersFrameFlags) {
-  for (int flags = 0; flags < 256; ++flags) {
+  uint8 flags = 0;
+  do {
     SCOPED_TRACE(testing::Message() << "Flags " << flags);
 
     testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
@@ -5201,7 +5208,7 @@
     }
     headers_ir.SetHeader("foo", "bar");
     scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers_ir));
-    int set_flags = flags;
+    uint8 set_flags = flags;
     if (IsSpdy4()) {
       // TODO(jgraettinger): Add padding to SpdyHeadersIR,
       // and implement framing.
@@ -5266,11 +5273,12 @@
       EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
           << SpdyFramer::ErrorCodeToString(framer.error_code());
     }
-  }
+  } while (++flags != 0);
 }
 
 TEST_P(SpdyFramerTest, PingFrameFlags) {
-  for (int flags = 0; flags < 256; ++flags) {
+  uint8 flags = 0;
+  do {
     SCOPED_TRACE(testing::Message() << "Flags " << flags);
 
     testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
@@ -5301,11 +5309,12 @@
                 framer.error_code())
           << SpdyFramer::ErrorCodeToString(framer.error_code());
     }
-  }
+  } while (++flags != 0);
 }
 
 TEST_P(SpdyFramerTest, WindowUpdateFrameFlags) {
-  for (int flags = 0; flags < 256; ++flags) {
+  uint8 flags = 0;
+  do {
     SCOPED_TRACE(testing::Message() << "Flags " << flags);
 
     testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
@@ -5333,7 +5342,7 @@
       EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
           << SpdyFramer::ErrorCodeToString(framer.error_code());
     }
-  }
+  } while (++flags != 0);
 }
 
 TEST_P(SpdyFramerTest, PushPromiseFrameFlags) {
@@ -5341,7 +5350,8 @@
     return;
   }
 
-  for (int flags = 0; flags < 256; ++flags) {
+  uint8 flags = 0;
+  do {
     SCOPED_TRACE(testing::Message() << "Flags " << flags);
 
     testing::StrictMock<net::test::MockSpdyFramerVisitor> visitor;
@@ -5358,8 +5368,7 @@
     framer.SerializePushPromise(push_promise));
     // TODO(jgraettinger): Add padding to SpdyPushPromiseIR,
     // and implement framing.
-    int set_flags = flags & ~HEADERS_FLAG_PADDED;
-    SetFrameFlags(frame.get(), set_flags, spdy_version_);
+    SetFrameFlags(frame.get(), flags & ~HEADERS_FLAG_PADDED, spdy_version_);
 
     if (flags & ~(PUSH_PROMISE_FLAG_END_PUSH_PROMISE | HEADERS_FLAG_PADDED)) {
       EXPECT_CALL(visitor, OnError(_));
@@ -5382,7 +5391,7 @@
       EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
           << SpdyFramer::ErrorCodeToString(framer.error_code());
     }
-  }
+  } while (++flags != 0);
 }
 
 TEST_P(SpdyFramerTest, ContinuationFrameFlags) {
@@ -5390,7 +5399,8 @@
     return;
   }
 
-  for (int flags = 0; flags < 256; ++flags) {
+  uint8 flags = 0;
+  do {
     SCOPED_TRACE(testing::Message() << "Flags " << flags);
 
     testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
@@ -5438,7 +5448,7 @@
       EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
           << SpdyFramer::ErrorCodeToString(framer.error_code());
     }
-  }
+  } while (++flags != 0);
 }
 
 // TODO(mlavan): Add TEST_P(SpdyFramerTest, AltSvcFrameFlags)
@@ -5842,7 +5852,7 @@
   size_t unframed_data = control_frame->size();
   size_t kReadChunkSize = 5;  // Read five bytes at a time.
   while (unframed_data > 0) {
-    size_t to_read = min(kReadChunkSize, unframed_data);
+    size_t to_read = std::min(kReadChunkSize, unframed_data);
     visitor.SimulateInFramer(
         reinterpret_cast<unsigned char*>(control_frame->data() + framed_data),
         to_read);
diff --git a/net/spdy/spdy_protocol.h b/net/spdy/spdy_protocol.h
index b02c44f..112e928 100644
--- a/net/spdy/spdy_protocol.h
+++ b/net/spdy/spdy_protocol.h
@@ -11,6 +11,7 @@
 #ifndef NET_SPDY_SPDY_PROTOCOL_H_
 #define NET_SPDY_SPDY_PROTOCOL_H_
 
+#include <limits>
 #include <map>
 #include <string>
 #include <vector>
@@ -983,12 +984,8 @@
   void set_protocol_id(SpdyProtocolId protocol_id) {
     protocol_id_ = protocol_id;
   }
-  void set_host(std::string host) {
-    host_ = host;
-  }
-  void set_origin(std::string origin) {
-    origin_ = origin;
-  }
+  void set_host(std::string host) { host_ = host; }
+  void set_origin(std::string origin) { origin_ = origin; }
 
   void Visit(SpdyFrameVisitor* visitor) const override;
 
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc
index 4b91909..a2e239e 100644
--- a/net/spdy/spdy_session.cc
+++ b/net/spdy/spdy_session.cc
@@ -238,7 +238,7 @@
                                     const char* type,
                                     NetLog::LogLevel /* log_level */) {
   base::DictionaryValue* dict = new base::DictionaryValue();
-  dict->SetInteger("unique_id", unique_id);
+  dict->SetInteger("unique_id", static_cast<int>(unique_id));
   dict->SetString("type", type);
   dict->SetBoolean("is_ack", is_ack);
   return dict;
@@ -2922,7 +2922,7 @@
   EnqueueSessionWrite(priority, WINDOW_UPDATE, window_update_frame.Pass());
 }
 
-void SpdySession::WritePingFrame(uint32 unique_id, bool is_ack) {
+void SpdySession::WritePingFrame(SpdyPingId unique_id, bool is_ack) {
   DCHECK(buffered_spdy_framer_.get());
   scoped_ptr<SpdyFrame> ping_frame(
       buffered_spdy_framer_->CreatePingFrame(unique_id, is_ack));
diff --git a/net/spdy/spdy_session.h b/net/spdy/spdy_session.h
index 06dfae6..a468dc4 100644
--- a/net/spdy/spdy_session.h
+++ b/net/spdy/spdy_session.h
@@ -729,7 +729,7 @@
                              RequestPriority priority);
 
   // Send the PING frame.
-  void WritePingFrame(uint32 unique_id, bool is_ack);
+  void WritePingFrame(SpdyPingId unique_id, bool is_ack);
 
   // Post a CheckPingStatus call after delay. Don't post if there is already
   // CheckPingStatus running.
@@ -948,7 +948,7 @@
 
   int64 pings_in_flight() const { return pings_in_flight_; }
 
-  uint32 next_ping_id() const { return next_ping_id_; }
+  SpdyPingId next_ping_id() const { return next_ping_id_; }
 
   base::TimeTicks last_activity_time() const { return last_activity_time_; }
 
@@ -1085,7 +1085,7 @@
   int64 pings_in_flight_;
 
   // This is the next ping_id (unique_id) to be sent in PING frame.
-  uint32 next_ping_id_;
+  SpdyPingId next_ping_id_;
 
   // This is the last time we have sent a PING.
   base::TimeTicks last_ping_sent_time_;
diff --git a/net/spdy/spdy_test_util_common.cc b/net/spdy/spdy_test_util_common.cc
index f0765a0..490af6b 100644
--- a/net/spdy/spdy_test_util_common.cc
+++ b/net/spdy/spdy_test_util_common.cc
@@ -969,11 +969,14 @@
     const char* const extra_headers[],
     int extra_header_count,
     int stream_id,
-    RequestPriority priority) const {
+    RequestPriority priority,
+    const HostPortPair& host_port_pair) const {
   SpdyHeaderBlock block;
   block[GetMethodKey()] = "CONNECT";
-  block[GetPathKey()] = "www.google.com:443";
-  block[GetHostKey()] = "www.google.com";
+  block[GetPathKey()] = host_port_pair.ToString();
+  block[GetHostKey()] = (host_port_pair.port() == 443)
+                            ? host_port_pair.host()
+                            : host_port_pair.ToString();
   MaybeAddVersionHeader(&block);
   AppendToHeaderBlock(extra_headers, extra_header_count, &block);
   return ConstructSpdySyn(stream_id, block, priority, false, false);
diff --git a/net/spdy/spdy_test_util_common.h b/net/spdy/spdy_test_util_common.h
index 0ee59d4..58e1b00 100644
--- a/net/spdy/spdy_test_util_common.h
+++ b/net/spdy/spdy_test_util_common.h
@@ -436,7 +436,8 @@
   SpdyFrame* ConstructSpdyConnect(const char* const extra_headers[],
                                   int extra_header_count,
                                   int stream_id,
-                                  RequestPriority priority) const;
+                                  RequestPriority priority,
+                                  const HostPortPair& host_port_pair) const;
 
   // Constructs a standard SPDY push SYN frame.
   // |extra_headers| are the extra header-value pairs, which typically
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index f7efc71..0cde019 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -1347,6 +1347,28 @@
   server_thread_->Resume();
 }
 
+TEST_P(EndToEndTest, EnablePacingViaFlag) {
+  // When pacing is enabled via command-line flag, it will always be enabled,
+  // regardless of the config. or the specific congestion-control algorithm.
+  ValueRestore<bool> old_flag(&FLAGS_quic_enable_pacing, true);
+  ASSERT_TRUE(Initialize());
+
+  client_->client()->WaitForCryptoHandshakeConfirmed();
+  server_thread_->WaitForCryptoHandshakeConfirmed();
+
+  // Pause the server so we can access the server's internals without races.
+  server_thread_->Pause();
+  QuicDispatcher* dispatcher =
+      QuicServerPeer::GetDispatcher(server_thread_->server());
+  ASSERT_EQ(1u, dispatcher->session_map().size());
+  const QuicSentPacketManager& client_sent_packet_manager =
+      client_->client()->session()->connection()->sent_packet_manager();
+  const QuicSentPacketManager& server_sent_packet_manager =
+      *GetSentPacketManagerFromFirstServerSession();
+  EXPECT_TRUE(server_sent_packet_manager.using_pacing());
+  EXPECT_TRUE(client_sent_packet_manager.using_pacing());
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace tools
diff --git a/net/tools/quic/quic_client.cc b/net/tools/quic/quic_client.cc
index 74874d7..6264be0 100644
--- a/net/tools/quic/quic_client.cc
+++ b/net/tools/quic/quic_client.cc
@@ -235,6 +235,10 @@
     headers.SetRequestFirstlineFromStringPieces("GET", args[i], "HTTP/1.1");
     QuicSpdyClientStream* stream = CreateReliableClientStream();
     DCHECK(stream != nullptr);
+    if (stream == nullptr) {
+      LOG(ERROR) << "stream creation failed!";
+      break;
+    }
     stream->SendRequest(headers, "", true);
     stream->set_visitor(this);
   }
@@ -317,6 +321,10 @@
       session_->connection()->connected();
 }
 
+bool QuicClient::goaway_received() const {
+  return session_ != nullptr && session_->goaway_received();
+}
+
 QuicConnectionId QuicClient::GenerateConnectionId() {
   return QuicRandom::GetInstance()->RandUint64();
 }
diff --git a/net/tools/quic/quic_client.h b/net/tools/quic/quic_client.h
index 6bf87f9..c095a4d 100644
--- a/net/tools/quic/quic_client.h
+++ b/net/tools/quic/quic_client.h
@@ -44,7 +44,7 @@
     virtual ~ResponseListener() {}
     virtual void OnCompleteResponse(QuicStreamId id,
                                     const BalsaHeaders& response_headers,
-                                    const string& response_body) = 0;
+                                    const std::string& response_body) = 0;
   };
 
   // Create a quic client, which will have events managed by an externally owned
@@ -120,6 +120,7 @@
   QuicClientSession* session() { return session_.get(); }
 
   bool connected() const;
+  bool goaway_received() const;
 
   void set_bind_to_address(IPAddressNumber address) {
     bind_to_address_ = address;
@@ -142,7 +143,7 @@
     server_id_ = server_id;
   }
 
-  void SetUserAgentID(const string& user_agent_id) {
+  void SetUserAgentID(const std::string& user_agent_id) {
     crypto_config_.set_user_agent_id(user_agent_id);
   }
 
diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc
index 45cddb0..fc1e10d 100644
--- a/net/tools/quic/quic_dispatcher_test.cc
+++ b/net/tools/quic/quic_dispatcher_test.cc
@@ -29,6 +29,7 @@
 using net::test::ValueRestore;
 using net::tools::test::MockConnection;
 using std::make_pair;
+using std::string;
 using testing::DoAll;
 using testing::InSequence;
 using testing::Invoke;
diff --git a/net/tools/quic/quic_server_session.cc b/net/tools/quic/quic_server_session.cc
index 9db2365..6e64da5 100644
--- a/net/tools/quic/quic_server_session.cc
+++ b/net/tools/quic/quic_server_session.cc
@@ -84,6 +84,11 @@
     return;
   }
 
+  // Only send updates when the application has no data to write.
+  if (HasDataToWrite()) {
+    return;
+  }
+
   // If not enough time has passed since the last time we sent an update to the
   // client, or not enough packets have been sent, then return early.
   const QuicSentPacketManager& sent_packet_manager =
diff --git a/net/tools/quic/quic_server_session.h b/net/tools/quic/quic_server_session.h
index 603ad35..81cae12 100644
--- a/net/tools/quic/quic_server_session.h
+++ b/net/tools/quic/quic_server_session.h
@@ -8,6 +8,7 @@
 #define NET_TOOLS_QUIC_QUIC_SERVER_SESSION_H_
 
 #include <set>
+#include <string>
 #include <vector>
 
 #include "base/basictypes.h"
@@ -68,7 +69,7 @@
   // Override base class to process FEC config received from client.
   void OnConfigNegotiated() override;
 
-  void set_serving_region(string serving_region) {
+  void set_serving_region(std::string serving_region) {
     serving_region_ = serving_region;
   }
 
@@ -97,7 +98,7 @@
 
   // Text describing server location. Sent to the client as part of the bandwith
   // estimate in the source-address token. Optional, can be left empty.
-  string serving_region_;
+  std::string serving_region_;
 
   // Time at which we send the last SCUP to the client.
   QuicTime last_scup_time_;
diff --git a/net/tools/quic/quic_server_session_test.cc b/net/tools/quic/quic_server_session_test.cc
index 4705c05..c8f8bce 100644
--- a/net/tools/quic/quic_server_session_test.cc
+++ b/net/tools/quic/quic_server_session_test.cc
@@ -37,6 +37,7 @@
 using net::test::kClientDataStreamId2;
 using net::test::kClientDataStreamId3;
 using net::test::kClientDataStreamId4;
+using std::string;
 using testing::StrictMock;
 using testing::_;
 
@@ -305,7 +306,8 @@
   }
 
   // Test that bandwidth estimate updates are sent to the client, only after the
-  // bandwidth estimate has changes sufficiently, and enough time has passed.
+  // bandwidth estimate has changes sufficiently, and enough time has passed,
+  // and we don't have any other data to write.
 
   int32 bandwidth_estimate_kbytes_per_second = 123;
   int32 max_bandwidth_estimate_kbytes_per_second = 134;
@@ -332,6 +334,10 @@
   QuicSustainedBandwidthRecorderPeer::SetMaxBandwidthEstimate(
       &bandwidth_recorder, max_bandwidth_estimate_kbytes_per_second,
       max_bandwidth_estimate_timestamp);
+  // Queue up some pending data.
+  session_->MarkWriteBlocked(kCryptoStreamId,
+                             QuicWriteBlockedList::kHighestPriority);
+  EXPECT_TRUE(session_->HasDataToWrite());
 
   // There will be no update sent yet - not enough time has passed.
   QuicTime now = QuicTime::Zero();
@@ -351,6 +357,11 @@
       kMinIntervalBetweenServerConfigUpdatesRTTs * srtt_ms));
   session_->OnCongestionWindowChange(now);
 
+  // The connection no longer has pending data to be written.
+  session_->OnCanWrite();
+  EXPECT_FALSE(session_->HasDataToWrite());
+  session_->OnCongestionWindowChange(now);
+
   // Bandwidth estimate has now changed sufficiently, enough time has passed,
   // and enough packets have been sent.
   QuicConnectionPeer::SetSequenceNumberOfLastSentPacket(
diff --git a/net/tools/quic/quic_socket_utils.cc b/net/tools/quic/quic_socket_utils.cc
index 3ac0bf3..0eb1185 100644
--- a/net/tools/quic/quic_socket_utils.cc
+++ b/net/tools/quic/quic_socket_utils.cc
@@ -23,7 +23,7 @@
 namespace tools {
 
 // static
-IPAddressNumber QuicSocketUtils::GetAddressFromMsghdr(struct msghdr *hdr) {
+IPAddressNumber QuicSocketUtils::GetAddressFromMsghdr(struct msghdr* hdr) {
   if (hdr->msg_controllen > 0) {
     for (cmsghdr* cmsg = CMSG_FIRSTHDR(hdr);
          cmsg != nullptr;
@@ -51,11 +51,10 @@
 }
 
 // static
-bool QuicSocketUtils::GetOverflowFromMsghdr(
-    struct msghdr *hdr,
-    QuicPacketCount *dropped_packets) {
+bool QuicSocketUtils::GetOverflowFromMsghdr(struct msghdr* hdr,
+                                            QuicPacketCount* dropped_packets) {
   if (hdr->msg_controllen > 0) {
-    struct cmsghdr *cmsg;
+    struct cmsghdr* cmsg;
     for (cmsg = CMSG_FIRSTHDR(hdr);
          cmsg != nullptr;
          cmsg = CMSG_NXTHDR(hdr, cmsg)) {
@@ -103,7 +102,7 @@
                                 QuicPacketCount* dropped_packets,
                                 IPAddressNumber* self_address,
                                 IPEndPoint* peer_address) {
-  CHECK(peer_address != nullptr);
+  DCHECK(peer_address != nullptr);
   const int kSpaceForOverflowAndIp =
       CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(in6_pktinfo));
   char cbuf[kSpaceForOverflowAndIp];
@@ -119,7 +118,7 @@
   hdr.msg_iovlen = 1;
   hdr.msg_flags = 0;
 
-  struct cmsghdr *cmsg = (struct cmsghdr *) cbuf;
+  struct cmsghdr* cmsg = (struct cmsghdr*)cbuf;
   cmsg->cmsg_len = arraysize(cbuf);
   hdr.msg_control = cmsg;
   hdr.msg_controllen = arraysize(cbuf);
@@ -209,7 +208,7 @@
   } else {
     hdr.msg_control = cbuf;
     hdr.msg_controllen = kSpaceForIp;
-    cmsghdr *cmsg = CMSG_FIRSTHDR(&hdr);
+    cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
     SetIpInfoInCmsg(self_address, cmsg);
     hdr.msg_controllen = cmsg->cmsg_len;
   }
diff --git a/net/tools/quic/quic_socket_utils.h b/net/tools/quic/quic_socket_utils.h
index 41d3b93..2c8fe43 100644
--- a/net/tools/quic/quic_socket_utils.h
+++ b/net/tools/quic/quic_socket_utils.h
@@ -24,12 +24,12 @@
   // If the msghdr contains IP_PKTINFO or IPV6_PKTINFO, this will return the
   // IPAddressNumber in that header.  Returns an uninitialized IPAddress on
   // failure.
-  static IPAddressNumber GetAddressFromMsghdr(struct msghdr *hdr);
+  static IPAddressNumber GetAddressFromMsghdr(struct msghdr* hdr);
 
   // If the msghdr contains an SO_RXQ_OVFL entry, this will set dropped_packets
   // to the correct value and return true. Otherwise it will return false.
-  static bool GetOverflowFromMsghdr(struct msghdr *hdr,
-                                    QuicPacketCount *dropped_packets);
+  static bool GetOverflowFromMsghdr(struct msghdr* hdr,
+                                    QuicPacketCount* dropped_packets);
 
   // Sets either IP_PKTINFO or IPV6_PKTINFO on the socket, based on
   // address_family.  Returns the return code from setsockopt.
diff --git a/net/tools/quic/quic_spdy_client_stream_test.cc b/net/tools/quic/quic_spdy_client_stream_test.cc
index 090e2da..94ba5aa 100644
--- a/net/tools/quic/quic_spdy_client_stream_test.cc
+++ b/net/tools/quic/quic_spdy_client_stream_test.cc
@@ -16,6 +16,7 @@
 
 using net::test::DefaultQuicConfig;
 using net::test::SupportedVersions;
+using std::string;
 using testing::StrictMock;
 using testing::TestWithParam;
 
diff --git a/net/tools/quic/quic_spdy_server_stream.h b/net/tools/quic/quic_spdy_server_stream.h
index feb809f..6fa1114 100644
--- a/net/tools/quic/quic_spdy_server_stream.h
+++ b/net/tools/quic/quic_spdy_server_stream.h
@@ -52,7 +52,7 @@
                           base::StringPiece body);
 
   BalsaHeaders headers_;
-  string body_;
+  std::string body_;
 
   // Buffer into which response header data is read.
   scoped_refptr<GrowableIOBuffer> read_buf_;
diff --git a/net/tools/quic/quic_time_wait_list_manager.cc b/net/tools/quic/quic_time_wait_list_manager.cc
index f54a465..fba4e87 100644
--- a/net/tools/quic/quic_time_wait_list_manager.cc
+++ b/net/tools/quic/quic_time_wait_list_manager.cc
@@ -28,8 +28,9 @@
 
 namespace {
 
-// Time period for which the connection_id should live in time wait state.
-const int kTimeWaitSeconds = 5;
+// Time period for which a given connection_id should live in the time-wait
+// state.
+int64 FLAGS_quic_time_wait_list_seconds = 5;
 
 }  // namespace
 
@@ -90,7 +91,8 @@
     EpollServer* epoll_server,
     const QuicVersionVector& supported_versions)
     : epoll_server_(epoll_server),
-      kTimeWaitPeriod_(QuicTime::Delta::FromSeconds(kTimeWaitSeconds)),
+      kTimeWaitPeriod_(
+          QuicTime::Delta::FromSeconds(FLAGS_quic_time_wait_list_seconds)),
       connection_id_clean_up_alarm_(new ConnectionIdCleanUpAlarm(this)),
       clock_(epoll_server_),
       writer_(writer),
@@ -282,6 +284,7 @@
       break;
     }
     // This connection_id has lived its age, retire it now.
+    DVLOG(1) << "Retiring " << it->first << " from the time-wait state.";
     delete it->second.close_packet;
     connection_id_map_.erase(it);
   }
diff --git a/net/tools/quic/test_tools/packet_dropping_test_writer.h b/net/tools/quic/test_tools/packet_dropping_test_writer.h
index 842d70e..6dcb1b9 100644
--- a/net/tools/quic/test_tools/packet_dropping_test_writer.h
+++ b/net/tools/quic/test_tools/packet_dropping_test_writer.h
@@ -6,6 +6,7 @@
 #define NET_TOOLS_QUIC_TEST_TOOLS_PACKET_DROPPING_TEST_WRITER_H_
 
 #include <list>
+#include <string>
 
 #include "base/basictypes.h"
 #include "base/logging.h"
@@ -123,7 +124,7 @@
                  QuicTime send_time);
     ~DelayedWrite();
 
-    string buffer;
+    std::string buffer;
     const IPAddressNumber self_address;
     const IPEndPoint peer_address;
     QuicTime send_time;
diff --git a/net/tools/quic/test_tools/quic_test_client.h b/net/tools/quic/test_tools/quic_test_client.h
index a1dea9e..79224ba 100644
--- a/net/tools/quic/test_tools/quic_test_client.h
+++ b/net/tools/quic/test_tools/quic_test_client.h
@@ -63,11 +63,11 @@
                        public QuicDataStream::Visitor {
  public:
   QuicTestClient(IPEndPoint server_address,
-                 const string& server_hostname,
+                 const std::string& server_hostname,
                  bool secure,
                  const QuicVersionVector& supported_versions);
   QuicTestClient(IPEndPoint server_address,
-                 const string& server_hostname,
+                 const std::string& server_hostname,
                  bool secure,
                  const QuicConfig& config,
                  const QuicVersionVector& supported_versions);
@@ -80,18 +80,18 @@
   void ExpectCertificates(bool on);
 
   // Sets the |user_agent_id| of the |client_|.
-  void SetUserAgentID(const string& user_agent_id);
+  void SetUserAgentID(const std::string& user_agent_id);
 
   // Wraps data in a quic packet and sends it.
-  ssize_t SendData(string data, bool last_data);
+  ssize_t SendData(std::string data, bool last_data);
 
   // From SimpleClient
   // Clears any outstanding state and sends a simple GET of 'uri' to the
   // server.  Returns 0 if the request failed and no bytes were written.
-  ssize_t SendRequest(const string& uri) override;
+  ssize_t SendRequest(const std::string& uri) override;
   ssize_t SendMessage(const HTTPMessage& message) override;
-  string SendCustomSynchronousRequest(const HTTPMessage& message) override;
-  string SendSynchronousRequest(const string& uri) override;
+  std::string SendCustomSynchronousRequest(const HTTPMessage& message) override;
+  std::string SendSynchronousRequest(const std::string& uri) override;
   void Connect() override;
   void ResetConnection() override;
   void Disconnect() override;
@@ -111,13 +111,13 @@
   bool buffer_body() const override;
   void set_buffer_body(bool buffer_body) override;
   bool ServerInLameDuckMode() const override;
-  const string& response_body() override;
+  const std::string& response_body() override;
   bool connected() const override;
   // These functions are all unimplemented functions from SimpleClient, and log
   // DFATAL if called by users of SimpleClient.
   ssize_t SendAndWaitForResponse(const void* buffer, size_t size) override;
   void Bind(IPEndPoint* local_address) override;
-  string SerializeMessage(const HTTPMessage& message) override;
+  std::string SerializeMessage(const HTTPMessage& message) override;
   IPAddressNumber bind_to_address() const override;
   void set_bind_to_address(IPAddressNumber address) override;
   const IPEndPoint& address() const override;
@@ -143,7 +143,7 @@
 
   // cert_common_name returns the common name value of the server's certificate,
   // or the empty string if no certificate was presented.
-  const string& cert_common_name() const;
+  const std::string& cert_common_name() const;
 
   // Get the server config map.
   QuicTagValueMap GetServerConfig() const;
@@ -178,7 +178,7 @@
   bool response_headers_complete_;
   BalsaHeaders headers_;
   QuicPriority priority_;
-  string response_;
+  std::string response_;
   uint64 bytes_read_;
   uint64 bytes_written_;
   // The number of uncompressed HTTP header bytes received.
diff --git a/net/tools/quic/test_tools/quic_test_utils.h b/net/tools/quic/test_tools/quic_test_utils.h
index d70b22d..202edf3 100644
--- a/net/tools/quic/test_tools/quic_test_utils.h
+++ b/net/tools/quic/test_tools/quic_test_utils.h
@@ -29,7 +29,7 @@
 namespace test {
 
 static const QuicConnectionId kTestConnectionId = 42;
-static const int kTestPort = 123;
+static const uint16 kTestPort = 123;
 static const uint32 kInitialStreamFlowControlWindowForTest =
     32 * 1024;  // 32 KB
 static const uint32 kInitialSessionFlowControlWindowForTest =
diff --git a/net/udp/udp_client_socket.cc b/net/udp/udp_client_socket.cc
index f6f904a..9cdaace 100644
--- a/net/udp/udp_client_socket.cc
+++ b/net/udp/udp_client_socket.cc
@@ -4,6 +4,7 @@
 
 #include "net/udp/udp_client_socket.h"
 
+#include "net/base/net_errors.h"
 #include "net/base/net_log.h"
 
 namespace net {
@@ -19,6 +20,9 @@
 }
 
 int UDPClientSocket::Connect(const IPEndPoint& address) {
+  int rv = socket_.Open(address.GetFamily());
+  if (rv != OK)
+    return rv;
   return socket_.Connect(address);
 }
 
diff --git a/net/udp/udp_server_socket.cc b/net/udp/udp_server_socket.cc
index 796c04d..4653f71 100644
--- a/net/udp/udp_server_socket.cc
+++ b/net/udp/udp_server_socket.cc
@@ -4,6 +4,7 @@
 
 #include "net/udp/udp_server_socket.h"
 
+#include "net/base/net_errors.h"
 #include "net/base/rand_callback.h"
 
 namespace net {
@@ -13,13 +14,35 @@
     : socket_(DatagramSocket::DEFAULT_BIND,
               RandIntCallback(),
               net_log,
-              source) {
+              source),
+      allow_address_reuse_(false),
+      allow_broadcast_(false) {
 }
 
 UDPServerSocket::~UDPServerSocket() {
 }
 
 int UDPServerSocket::Listen(const IPEndPoint& address) {
+  int rv = socket_.Open(address.GetFamily());
+  if (rv != OK)
+    return rv;
+
+  if (allow_address_reuse_) {
+    rv = socket_.AllowAddressReuse();
+    if (rv != OK) {
+      socket_.Close();
+      return rv;
+    }
+  }
+
+  if (allow_broadcast_) {
+    rv = socket_.SetBroadcast(true);
+    if (rv != OK) {
+      socket_.Close();
+      return rv;
+    }
+  }
+
   return socket_.Bind(address);
 }
 
@@ -62,11 +85,11 @@
 }
 
 void UDPServerSocket::AllowAddressReuse() {
-  socket_.AllowAddressReuse();
+  allow_address_reuse_ = true;
 }
 
 void UDPServerSocket::AllowBroadcast() {
-  socket_.AllowBroadcast();
+  allow_broadcast_ = true;
 }
 
 int UDPServerSocket::JoinGroup(const IPAddressNumber& group_address) const {
diff --git a/net/udp/udp_server_socket.h b/net/udp/udp_server_socket.h
index 77ca86d..0799105 100644
--- a/net/udp/udp_server_socket.h
+++ b/net/udp/udp_server_socket.h
@@ -49,6 +49,8 @@
 
  private:
   UDPSocket socket_;
+  bool allow_address_reuse_;
+  bool allow_broadcast_;
   DISALLOW_COPY_AND_ASSIGN(UDPServerSocket);
 };
 
diff --git a/net/udp/udp_socket.h b/net/udp/udp_socket.h
index 97a4bc5..2ae4b16 100644
--- a/net/udp/udp_socket.h
+++ b/net/udp/udp_socket.h
@@ -21,18 +21,20 @@
 // Client form:
 // In this case, we're connecting to a specific server, so the client will
 // usually use:
-//       Connect(address)    // Connect to a UDP server
-//       Read/Write          // Reads/Writes all go to a single destination
+//       Open(address_family)  // Open a socket.
+//       Connect(address)      // Connect to a UDP server
+//       Read/Write            // Reads/Writes all go to a single destination
 //
 // Server form:
 // In this case, we want to read/write to many clients which are connecting
 // to this server.  First the server 'binds' to an addres, then we read from
 // clients and write responses to them.
 // Example:
-//       Bind(address/port)  // Binds to port for reading from clients
-//       RecvFrom/SendTo     // Each read can come from a different client
-//                           // Writes need to be directed to a specific
-//                           // address.
+//       Open(address_family)  // Open a socket.
+//       Bind(address/port)    // Binds to port for reading from clients
+//       RecvFrom/SendTo       // Each read can come from a different client
+//                             // Writes need to be directed to a specific
+//                             // address.
 #if defined(OS_WIN)
 typedef UDPSocketWin UDPSocket;
 #elif defined(OS_POSIX)
diff --git a/net/udp/udp_socket_libevent.cc b/net/udp/udp_socket_libevent.cc
index 2dffff3..8dd102a 100644
--- a/net/udp/udp_socket_libevent.cc
+++ b/net/udp/udp_socket_libevent.cc
@@ -67,6 +67,7 @@
     const net::NetLog::Source& source)
         : socket_(kInvalidSocket),
           addr_family_(0),
+          is_connected_(false),
           socket_options_(SOCKET_OPTION_MULTICAST_LOOP),
           multicast_interface_(0),
           multicast_time_to_live_(1),
@@ -89,10 +90,26 @@
   net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE);
 }
 
+int UDPSocketLibevent::Open(AddressFamily address_family) {
+  DCHECK(CalledOnValidThread());
+  DCHECK_EQ(socket_, kInvalidSocket);
+
+  addr_family_ = ConvertAddressFamily(address_family);
+  socket_ = CreatePlatformSocket(addr_family_, SOCK_DGRAM, 0);
+  if (socket_ == kInvalidSocket)
+    return MapSystemError(errno);
+  if (SetNonBlocking(socket_)) {
+    const int err = MapSystemError(errno);
+    Close();
+    return err;
+  }
+  return OK;
+}
+
 void UDPSocketLibevent::Close() {
   DCHECK(CalledOnValidThread());
 
-  if (!is_connected())
+  if (socket_ == kInvalidSocket)
     return;
 
   // Zero out any pending read/write callback state.
@@ -115,6 +132,7 @@
 
   socket_ = kInvalidSocket;
   addr_family_ = 0;
+  is_connected_ = false;
 }
 
 int UDPSocketLibevent::GetPeerAddress(IPEndPoint* address) const {
@@ -243,12 +261,12 @@
 }
 
 int UDPSocketLibevent::Connect(const IPEndPoint& address) {
+  DCHECK_NE(socket_, kInvalidSocket);
   net_log_.BeginEvent(NetLog::TYPE_UDP_CONNECT,
                       CreateNetLogUDPConnectCallback(&address));
   int rv = InternalConnect(address);
-  if (rv != OK)
-    Close();
   net_log_.EndEventWithNetErrorCode(NetLog::TYPE_UDP_CONNECT, rv);
+  is_connected_ = (rv == OK);
   return rv;
 }
 
@@ -256,16 +274,13 @@
   DCHECK(CalledOnValidThread());
   DCHECK(!is_connected());
   DCHECK(!remote_address_.get());
-  int addr_family = address.GetSockAddrFamily();
-  int rv = CreateSocket(addr_family);
-  if (rv < 0)
-    return rv;
 
+  int rv = 0;
   if (bind_type_ == DatagramSocket::RANDOM_BIND) {
     // Construct IPAddressNumber of appropriate size (IPv4 or IPv6) of 0s,
     // representing INADDR_ANY or in6addr_any.
-    size_t addr_size =
-        addr_family == AF_INET ? kIPv4AddressSize : kIPv6AddressSize;
+    size_t addr_size = address.GetSockAddrFamily() == AF_INET ?
+        kIPv4AddressSize : kIPv6AddressSize;
     IPAddressNumber addr_any(addr_size);
     rv = RandomBind(addr_any);
   }
@@ -273,79 +288,79 @@
 
   if (rv < 0) {
     UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketRandomBindErrorCode", -rv);
-    Close();
     return rv;
   }
 
   SockaddrStorage storage;
-  if (!address.ToSockAddr(storage.addr, &storage.addr_len)) {
-    Close();
+  if (!address.ToSockAddr(storage.addr, &storage.addr_len))
     return ERR_ADDRESS_INVALID;
-  }
 
   rv = HANDLE_EINTR(connect(socket_, storage.addr, storage.addr_len));
-  if (rv < 0) {
-    // Close() may change the current errno. Map errno beforehand.
-    int result = MapSystemError(errno);
-    Close();
-    return result;
-  }
+  if (rv < 0)
+    return MapSystemError(errno);
 
   remote_address_.reset(new IPEndPoint(address));
   return rv;
 }
 
 int UDPSocketLibevent::Bind(const IPEndPoint& address) {
+  DCHECK_NE(socket_, kInvalidSocket);
   DCHECK(CalledOnValidThread());
   DCHECK(!is_connected());
-  int rv = CreateSocket(address.GetSockAddrFamily());
+
+  int rv = SetMulticastOptions();
   if (rv < 0)
     return rv;
 
-  rv = SetSocketOptions();
-  if (rv < 0) {
-    Close();
-    return rv;
-  }
   rv = DoBind(address);
-  if (rv < 0) {
-    Close();
+  if (rv < 0)
     return rv;
-  }
+
+  is_connected_ = true;
   local_address_.reset();
   return rv;
 }
 
 int UDPSocketLibevent::SetReceiveBufferSize(int32 size) {
+  DCHECK_NE(socket_, kInvalidSocket);
   DCHECK(CalledOnValidThread());
   int rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF,
                       reinterpret_cast<const char*>(&size), sizeof(size));
-  int last_error = errno;
-  DCHECK(!rv) << "Could not set socket receive buffer size: " << last_error;
-  return rv == 0 ? OK : MapSystemError(last_error);
+  return rv == 0 ? OK : MapSystemError(errno);
 }
 
 int UDPSocketLibevent::SetSendBufferSize(int32 size) {
+  DCHECK_NE(socket_, kInvalidSocket);
   DCHECK(CalledOnValidThread());
   int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF,
                       reinterpret_cast<const char*>(&size), sizeof(size));
-  int last_error = errno;
-  DCHECK(!rv) << "Could not set socket send buffer size: " << last_error;
-  return rv == 0 ? OK : MapSystemError(last_error);
+  return rv == 0 ? OK : MapSystemError(errno);
 }
 
-void UDPSocketLibevent::AllowAddressReuse() {
+int UDPSocketLibevent::AllowAddressReuse() {
+  DCHECK_NE(socket_, kInvalidSocket);
   DCHECK(CalledOnValidThread());
   DCHECK(!is_connected());
-
-  socket_options_ |= SOCKET_OPTION_REUSE_ADDRESS;
+  int true_value = 1;
+  int rv = setsockopt(
+      socket_, SOL_SOCKET, SO_REUSEADDR, &true_value, sizeof(true_value));
+  return rv == 0 ? OK : MapSystemError(errno);
 }
 
-void UDPSocketLibevent::AllowBroadcast() {
+int UDPSocketLibevent::SetBroadcast(bool broadcast) {
+  DCHECK_NE(socket_, kInvalidSocket);
   DCHECK(CalledOnValidThread());
-  DCHECK(!is_connected());
-
-  socket_options_ |= SOCKET_OPTION_BROADCAST;
+  int value = broadcast ? 1 : 0;
+  int rv;
+#if defined(OS_MACOSX)
+  // SO_REUSEPORT on OSX permits multiple processes to each receive
+  // UDP multicast or broadcast datagrams destined for the bound
+  // port.
+  rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &value, sizeof(value));
+#else
+  rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &value, sizeof(value));
+#endif  // defined(OS_MACOSX)
+  return rv == 0 ? OK : MapSystemError(errno);
 }
 
 void UDPSocketLibevent::ReadWatcher::OnFileCanReadWithoutBlocking(int) {
@@ -418,19 +433,6 @@
   NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(result);
 }
 
-int UDPSocketLibevent::CreateSocket(int addr_family) {
-  addr_family_ = addr_family;
-  socket_ = CreatePlatformSocket(addr_family_, SOCK_DGRAM, 0);
-  if (socket_ == kInvalidSocket)
-    return MapSystemError(errno);
-  if (SetNonBlocking(socket_)) {
-    const int err = MapSystemError(errno);
-    Close();
-    return err;
-  }
-  return OK;
-}
-
 void UDPSocketLibevent::DidCompleteWrite() {
   int result =
       InternalSendTo(write_buf_.get(), write_buf_len_, send_to_address_.get());
@@ -518,30 +520,7 @@
   return result;
 }
 
-int UDPSocketLibevent::SetSocketOptions() {
-  int true_value = 1;
-  if (socket_options_ & SOCKET_OPTION_REUSE_ADDRESS) {
-    int rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &true_value,
-                        sizeof(true_value));
-    if (rv < 0)
-      return MapSystemError(errno);
-  }
-  if (socket_options_ & SOCKET_OPTION_BROADCAST) {
-    int rv;
-#if defined(OS_MACOSX)
-    // SO_REUSEPORT on OSX permits multiple processes to each receive
-    // UDP multicast or broadcast datagrams destined for the bound
-    // port.
-    rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &true_value,
-                    sizeof(true_value));
-#else
-    rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &true_value,
-                    sizeof(true_value));
-#endif  // defined(OS_MACOSX)
-    if (rv < 0)
-      return MapSystemError(errno);
-  }
-
+int UDPSocketLibevent::SetMulticastOptions() {
   if (!(socket_options_ & SOCKET_OPTION_MULTICAST_LOOP)) {
     int rv;
     if (addr_family_ == AF_INET) {
diff --git a/net/udp/udp_socket_libevent.h b/net/udp/udp_socket_libevent.h
index 2ac564d..a434bb9 100644
--- a/net/udp/udp_socket_libevent.h
+++ b/net/udp/udp_socket_libevent.h
@@ -9,6 +9,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/threading/non_thread_safe.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"
@@ -28,22 +29,28 @@
                     const net::NetLog::Source& source);
   virtual ~UDPSocketLibevent();
 
-  // Connect the socket to connect with a certain |address|.
+  // Opens the socket.
+  // Returns a net error code.
+  int Open(AddressFamily address_family);
+
+  // Connects the socket to connect with a certain |address|.
+  // Should be called after Open().
   // Returns a net error code.
   int Connect(const IPEndPoint& address);
 
-  // Bind the address/port for this socket to |address|.  This is generally
-  // only used on a server.
+  // Binds the address/port for this socket to |address|.  This is generally
+  // only used on a server. Should be called after Open().
   // Returns a net error code.
   int Bind(const IPEndPoint& address);
 
-  // Close the socket.
+  // Closes the socket.
+  // TODO(rvargas, hidehiko): Disallow re-Open() after Close().
   void Close();
 
-  // Copy the remote udp address into |address| and return a network error code.
+  // Copies the remote udp address into |address| and returns a net error code.
   int GetPeerAddress(IPEndPoint* address) const;
 
-  // Copy the local udp address into |address| and return a network error code.
+  // Copies the local udp address into |address| and returns a net error code.
   // (similar to getsockname)
   int GetLocalAddress(IPEndPoint* address) const;
 
@@ -51,17 +58,17 @@
   // Multiple outstanding read requests are not supported.
   // Full duplex mode (reading and writing at the same time) is supported
 
-  // Read from the socket.
+  // Reads from the socket.
   // Only usable from the client-side of a UDP socket, after the socket
   // has been connected.
   int Read(IOBuffer* buf, int buf_len, const CompletionCallback& callback);
 
-  // Write to the socket.
+  // Writes to the socket.
   // Only usable from the client-side of a UDP socket, after the socket
   // has been connected.
   int Write(IOBuffer* buf, int buf_len, const CompletionCallback& callback);
 
-  // Read from a socket and receive sender address information.
+  // Reads from a socket and receive sender address information.
   // |buf| is the buffer to read data into.
   // |buf_len| is the maximum amount of data to read.
   // |address| is a buffer provided by the caller for receiving the sender
@@ -79,7 +86,7 @@
                IPEndPoint* address,
                const CompletionCallback& callback);
 
-  // Send to a socket with a particular destination.
+  // Sends to a socket with a particular destination.
   // |buf| is the buffer to send
   // |buf_len| is the number of bytes to send
   // |address| is the recipient address.
@@ -93,60 +100,63 @@
              const IPEndPoint& address,
              const CompletionCallback& callback);
 
-  // Set the receive buffer size (in bytes) for the socket.
+  // Sets the receive buffer size (in bytes) for the socket.
+  // Returns a net error code.
   int SetReceiveBufferSize(int32 size);
 
-  // Set the send buffer size (in bytes) for the socket.
+  // Sets the send buffer size (in bytes) for the socket.
+  // Returns a net error code.
   int SetSendBufferSize(int32 size);
 
   // Returns true if the socket is already connected or bound.
-  bool is_connected() const { return socket_ != kInvalidSocket; }
+  bool is_connected() const { return is_connected_; }
 
   const BoundNetLog& NetLog() const { return net_log_; }
 
   // Sets corresponding flags in |socket_options_| to allow the socket
   // to share the local address to which the socket will be bound with
-  // other processes. Should be called before Bind().
-  void AllowAddressReuse();
+  // other processes. Should be called between Open() and Bind().
+  // Returns a net error code.
+  int AllowAddressReuse();
 
-  // Sets corresponding flags in |socket_options_| to allow sending
-  // and receiving packets to and from broadcast addresses. Should be
-  // called before Bind().
-  void AllowBroadcast();
+  // Sets corresponding flags in |socket_options_| to allow or disallow sending
+  // and receiving packets to and from broadcast addresses.
+  // Returns a net error code.
+  int SetBroadcast(bool broadcast);
 
-  // Join the multicast group.
+  // Joins the multicast group.
   // |group_address| is the group address to join, could be either
   // an IPv4 or IPv6 address.
-  // Return a network error code.
+  // Returns a net error code.
   int JoinGroup(const IPAddressNumber& group_address) const;
 
-  // Leave the multicast group.
+  // Leaves the multicast group.
   // |group_address| is the group address to leave, could be either
   // an IPv4 or IPv6 address. If the socket hasn't joined the group,
   // it will be ignored.
   // It's optional to leave the multicast group before destroying
   // the socket. It will be done by the OS.
-  // Return a network error code.
+  // Returns a net error code.
   int LeaveGroup(const IPAddressNumber& group_address) const;
 
-  // Set interface to use for multicast. If |interface_index| set to 0, default
-  // interface is used.
+  // Sets interface to use for multicast. If |interface_index| set to 0,
+  // default interface is used.
   // Should be called before Bind().
-  // Returns a network error code.
+  // Returns a net error code.
   int SetMulticastInterface(uint32 interface_index);
 
-  // Set the time-to-live option for UDP packets sent to the multicast
+  // Sets the time-to-live option for UDP packets sent to the multicast
   // group address. The default value of this option is 1.
   // Cannot be negative or more than 255.
   // Should be called before Bind().
-  // Return a network error code.
+  // Returns a net error code.
   int SetMulticastTimeToLive(int time_to_live);
 
-  // Set the loopback flag for UDP socket. If this flag is true, the host
+  // Sets the loopback flag for UDP socket. If this flag is true, the host
   // will receive packets sent to the joined group from itself.
   // The default value of this option is true.
   // Should be called before Bind().
-  // Return a network error code.
+  // Returns a net error code.
   //
   // Note: the behavior of |SetMulticastLoopbackMode| is slightly
   // different between Windows and Unix-like systems. The inconsistency only
@@ -158,9 +168,9 @@
   // other applications on the same host. See MSDN: http://goo.gl/6vqbj
   int SetMulticastLoopbackMode(bool loopback);
 
-  // Set the differentiated services flags on outgoing packets. May not
+  // Sets the differentiated services flags on outgoing packets. May not
   // do anything on some platforms.
-  // Return a network error code.
+  // Returns a net error code.
   int SetDiffServCodePoint(DiffServCodePoint dscp);
 
   // Resets the thread to be used for thread-safety checks.
@@ -168,9 +178,7 @@
 
  private:
   enum SocketOptions {
-    SOCKET_OPTION_REUSE_ADDRESS  = 1 << 0,
-    SOCKET_OPTION_BROADCAST      = 1 << 1,
-    SOCKET_OPTION_MULTICAST_LOOP = 1 << 2
+    SOCKET_OPTION_MULTICAST_LOOP = 1 << 0
   };
 
   class ReadWatcher : public base::MessageLoopForIO::Watcher {
@@ -218,9 +226,6 @@
                const sockaddr* addr) const;
   void LogWrite(int result, const char* bytes, const IPEndPoint* address) const;
 
-  // Returns the OS error code (or 0 on success).
-  int CreateSocket(int addr_family);
-
   // Same as SendTo(), except that address is passed by pointer
   // instead of by reference. It is called from Write() with |address|
   // set to NULL.
@@ -235,13 +240,14 @@
 
   // Applies |socket_options_| to |socket_|. Should be called before
   // Bind().
-  int SetSocketOptions();
+  int SetMulticastOptions();
   int DoBind(const IPEndPoint& address);
   // Binds to a random port on |address|.
   int RandomBind(const IPAddressNumber& address);
 
   int socket_;
   int addr_family_;
+  bool is_connected_;
 
   // Bitwise-or'd combination of SocketOptions. Specifies the set of
   // options that should be applied to |socket_| before Bind().
@@ -250,7 +256,7 @@
   // Multicast interface.
   uint32 multicast_interface_;
 
-  // Multicast socket options cached for SetSocketOption.
+  // Multicast socket options cached for SetMulticastOption.
   // Cannot be used after Bind().
   int multicast_time_to_live_;
 
diff --git a/net/udp/udp_socket_unittest.cc b/net/udp/udp_socket_unittest.cc
index 8282596..c92bf2b 100644
--- a/net/udp/udp_socket_unittest.cc
+++ b/net/udp/udp_socket_unittest.cc
@@ -353,7 +353,9 @@
                     base::Bind(&PrivilegedRand),
                     NULL,
                     NetLog::Source()));
-  int rv = socket->Connect(peer_address);
+  int rv = socket->Open(peer_address.GetFamily());
+  EXPECT_EQ(OK, rv);
+  rv = socket->Connect(peer_address);
   // Connect should have failed since we couldn't bind to that port,
   EXPECT_NE(OK, rv);
   // Make sure that UDPSocket actually closed the socket.
@@ -550,6 +552,7 @@
                    RandIntCallback(),
                    NULL,
                    NetLog::Source());
+  EXPECT_EQ(OK, socket.Open(bind_address.GetFamily()));
   EXPECT_EQ(OK, socket.Bind(bind_address));
   EXPECT_EQ(OK, socket.JoinGroup(group_ip));
   // Joining group multiple times.
@@ -578,6 +581,7 @@
   EXPECT_NE(OK, socket.SetMulticastTimeToLive(-1));
   EXPECT_EQ(OK, socket.SetMulticastInterface(0));
 
+  EXPECT_EQ(OK, socket.Open(bind_address.GetFamily()));
   EXPECT_EQ(OK, socket.Bind(bind_address));
 
   EXPECT_NE(OK, socket.SetMulticastLoopbackMode(false));
@@ -598,7 +602,10 @@
                    NetLog::Source());
   // We need a real IP, but we won't actually send anything to it.
   CreateUDPAddress("8.8.8.8", 9999, &bind_address);
-  int rv = client.Connect(bind_address);
+  int rv = client.Open(bind_address.GetFamily());
+  EXPECT_EQ(OK, rv);
+
+  rv = client.Connect(bind_address);
   if (rv != OK) {
     // Let's try localhost then..
     CreateUDPAddress("127.0.0.1", 9999, &bind_address);
@@ -705,6 +712,10 @@
                    NetLog::Source());
   int rv = client.SetDiffServCodePoint(DSCP_AF41);
   EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED, rv);
+
+  rv = client.Open(bind_address.GetFamily());
+  EXPECT_EQ(OK, rv);
+
   rv = client.Connect(bind_address);
   EXPECT_EQ(OK, rv);
 
diff --git a/net/udp/udp_socket_win.cc b/net/udp/udp_socket_win.cc
index 7be97e8..2f5549f 100644
--- a/net/udp/udp_socket_win.cc
+++ b/net/udp/udp_socket_win.cc
@@ -255,6 +255,7 @@
                            const net::NetLog::Source& source)
     : socket_(INVALID_SOCKET),
       addr_family_(0),
+      is_connected_(false),
       socket_options_(SOCKET_OPTION_MULTICAST_LOOP),
       multicast_interface_(0),
       multicast_time_to_live_(1),
@@ -276,10 +277,22 @@
   net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE);
 }
 
+int UDPSocketWin::Open(AddressFamily address_family) {
+  DCHECK(CalledOnValidThread());
+  DCHECK_EQ(socket_, INVALID_SOCKET);
+
+  addr_family_ = ConvertAddressFamily(address_family);
+  socket_ = CreatePlatformSocket(addr_family_, SOCK_DGRAM, IPPROTO_UDP);
+  if (socket_ == INVALID_SOCKET)
+    return MapSystemError(WSAGetLastError());
+  core_ = new Core(this);
+  return OK;
+}
+
 void UDPSocketWin::Close() {
   DCHECK(CalledOnValidThread());
 
-  if (!is_connected())
+  if (socket_ == INVALID_SOCKET)
     return;
 
   if (qos_handle_) {
@@ -297,6 +310,7 @@
                       base::TimeTicks::Now() - start_time);
   socket_ = INVALID_SOCKET;
   addr_family_ = 0;
+  is_connected_ = false;
 
   core_->Detach();
   core_ = NULL;
@@ -407,28 +421,25 @@
 }
 
 int UDPSocketWin::Connect(const IPEndPoint& address) {
+  DCHECK_NE(socket_, INVALID_SOCKET);
   net_log_.BeginEvent(NetLog::TYPE_UDP_CONNECT,
                       CreateNetLogUDPConnectCallback(&address));
   int rv = InternalConnect(address);
-  if (rv != OK)
-    Close();
   net_log_.EndEventWithNetErrorCode(NetLog::TYPE_UDP_CONNECT, rv);
+  is_connected_ = (rv == OK);
   return rv;
 }
 
 int UDPSocketWin::InternalConnect(const IPEndPoint& address) {
   DCHECK(!is_connected());
   DCHECK(!remote_address_.get());
-  int addr_family = address.GetSockAddrFamily();
-  int rv = CreateSocket(addr_family);
-  if (rv < 0)
-    return rv;
 
+  int rv = 0;
   if (bind_type_ == DatagramSocket::RANDOM_BIND) {
     // Construct IPAddressNumber of appropriate size (IPv4 or IPv6) of 0s,
     // representing INADDR_ANY or in6addr_any.
-    size_t addr_size =
-        addr_family == AF_INET ? kIPv4AddressSize : kIPv6AddressSize;
+    size_t addr_size = (address.GetSockAddrFamily() == AF_INET) ?
+        kIPv4AddressSize : kIPv6AddressSize;
     IPAddressNumber addr_any(addr_size);
     rv = RandomBind(addr_any);
   }
@@ -436,7 +447,6 @@
 
   if (rv < 0) {
     UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketRandomBindErrorCode", -rv);
-    Close();
     return rv;
   }
 
@@ -445,46 +455,32 @@
     return ERR_ADDRESS_INVALID;
 
   rv = connect(socket_, storage.addr, storage.addr_len);
-  if (rv < 0) {
-    // Close() may change the last error. Map it beforehand.
-    int result = MapSystemError(WSAGetLastError());
-    Close();
-    return result;
-  }
+  if (rv < 0)
+    return MapSystemError(WSAGetLastError());
 
   remote_address_.reset(new IPEndPoint(address));
   return rv;
 }
 
 int UDPSocketWin::Bind(const IPEndPoint& address) {
+  DCHECK_NE(socket_, INVALID_SOCKET);
   DCHECK(!is_connected());
-  int rv = CreateSocket(address.GetSockAddrFamily());
+
+  int rv = SetMulticastOptions();
   if (rv < 0)
     return rv;
-  rv = SetSocketOptions();
-  if (rv < 0) {
-    Close();
-    return rv;
-  }
+
   rv = DoBind(address);
-  if (rv < 0) {
-    Close();
+  if (rv < 0)
     return rv;
-  }
+
   local_address_.reset();
+  is_connected_ = true;
   return rv;
 }
 
-int UDPSocketWin::CreateSocket(int addr_family) {
-  addr_family_ = addr_family;
-  socket_ = CreatePlatformSocket(addr_family_, SOCK_DGRAM, IPPROTO_UDP);
-  if (socket_ == INVALID_SOCKET)
-    return MapSystemError(WSAGetLastError());
-  core_ = new Core(this);
-  return OK;
-}
-
 int UDPSocketWin::SetReceiveBufferSize(int32 size) {
+  DCHECK_NE(socket_, INVALID_SOCKET);
   DCHECK(CalledOnValidThread());
   int rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF,
                       reinterpret_cast<const char*>(&size), sizeof(size));
@@ -507,6 +503,7 @@
 }
 
 int UDPSocketWin::SetSendBufferSize(int32 size) {
+  DCHECK_NE(socket_, INVALID_SOCKET);
   DCHECK(CalledOnValidThread());
   int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF,
                       reinterpret_cast<const char*>(&size), sizeof(size));
@@ -527,18 +524,26 @@
   return ERR_SOCKET_SEND_BUFFER_SIZE_UNCHANGEABLE;
 }
 
-void UDPSocketWin::AllowAddressReuse() {
+int UDPSocketWin::AllowAddressReuse() {
+  DCHECK_NE(socket_, INVALID_SOCKET);
   DCHECK(CalledOnValidThread());
   DCHECK(!is_connected());
 
-  socket_options_ |= SOCKET_OPTION_REUSE_ADDRESS;
+  BOOL true_value = TRUE;
+  int rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR,
+                      reinterpret_cast<const char*>(&true_value),
+                      sizeof(true_value));
+  return rv == 0 ? OK : MapSystemError(WSAGetLastError());
 }
 
-void UDPSocketWin::AllowBroadcast() {
+int UDPSocketWin::SetBroadcast(bool broadcast) {
+  DCHECK_NE(socket_, INVALID_SOCKET);
   DCHECK(CalledOnValidThread());
-  DCHECK(!is_connected());
 
-  socket_options_ |= SOCKET_OPTION_BROADCAST;
+  BOOL value = broadcast ? TRUE : FALSE;
+  int rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST,
+                      reinterpret_cast<const char*>(&value), sizeof(value));
+  return rv == 0 ? OK : MapSystemError(WSAGetLastError());
 }
 
 void UDPSocketWin::DoReadCallback(int rv) {
@@ -718,22 +723,7 @@
   return ERR_IO_PENDING;
 }
 
-int UDPSocketWin::SetSocketOptions() {
-  BOOL true_value = 1;
-  if (socket_options_ & SOCKET_OPTION_REUSE_ADDRESS) {
-    int rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR,
-                        reinterpret_cast<const char*>(&true_value),
-                        sizeof(true_value));
-    if (rv < 0)
-      return MapSystemError(WSAGetLastError());
-  }
-  if (socket_options_ & SOCKET_OPTION_BROADCAST) {
-    int rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST,
-                        reinterpret_cast<const char*>(&true_value),
-                        sizeof(true_value));
-    if (rv < 0)
-      return MapSystemError(WSAGetLastError());
-  }
+int UDPSocketWin::SetMulticastOptions() {
   if (!(socket_options_ & SOCKET_OPTION_MULTICAST_LOOP)) {
     DWORD loop = 0;
     int protocol_level =
diff --git a/net/udp/udp_socket_win.h b/net/udp/udp_socket_win.h
index bc97d56..6f0ec2c 100644
--- a/net/udp/udp_socket_win.h
+++ b/net/udp/udp_socket_win.h
@@ -12,6 +12,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/threading/non_thread_safe.h"
 #include "base/win/object_watcher.h"
+#include "net/base/address_family.h"
 #include "net/base/completion_callback.h"
 #include "net/base/net_export.h"
 #include "net/base/rand_callback.h"
@@ -30,22 +31,28 @@
                const net::NetLog::Source& source);
   virtual ~UDPSocketWin();
 
-  // Connect the socket to connect with a certain |address|.
+  // Opens the socket.
+  // Returns a net error code.
+  int Open(AddressFamily address_family);
+
+  // Connects the socket to connect with a certain |address|.
+  // Should be called after Open().
   // Returns a net error code.
   int Connect(const IPEndPoint& address);
 
-  // Bind the address/port for this socket to |address|.  This is generally
-  // only used on a server.
+  // Binds the address/port for this socket to |address|.  This is generally
+  // only used on a server. Should be called after Open().
   // Returns a net error code.
   int Bind(const IPEndPoint& address);
 
-  // Close the socket.
+  // Closes the socket.
+  // TODO(rvargas, hidehiko): Disallow re-Open() after Close().
   void Close();
 
-  // Copy the remote udp address into |address| and return a network error code.
+  // Copies the remote udp address into |address| and returns a net error code.
   int GetPeerAddress(IPEndPoint* address) const;
 
-  // Copy the local udp address into |address| and return a network error code.
+  // Copies the local udp address into |address| and returns a net error code.
   // (similar to getsockname)
   int GetLocalAddress(IPEndPoint* address) const;
 
@@ -53,17 +60,17 @@
   // Multiple outstanding read requests are not supported.
   // Full duplex mode (reading and writing at the same time) is supported
 
-  // Read from the socket.
+  // Reads from the socket.
   // Only usable from the client-side of a UDP socket, after the socket
   // has been connected.
   int Read(IOBuffer* buf, int buf_len, const CompletionCallback& callback);
 
-  // Write to the socket.
+  // Writes to the socket.
   // Only usable from the client-side of a UDP socket, after the socket
   // has been connected.
   int Write(IOBuffer* buf, int buf_len, const CompletionCallback& callback);
 
-  // Read from a socket and receive sender address information.
+  // Reads from a socket and receive sender address information.
   // |buf| is the buffer to read data into.
   // |buf_len| is the maximum amount of data to read.
   // |address| is a buffer provided by the caller for receiving the sender
@@ -81,7 +88,7 @@
                IPEndPoint* address,
                const CompletionCallback& callback);
 
-  // Send to a socket with a particular destination.
+  // Sends to a socket with a particular destination.
   // |buf| is the buffer to send
   // |buf_len| is the number of bytes to send
   // |address| is the recipient address.
@@ -95,57 +102,57 @@
              const IPEndPoint& address,
              const CompletionCallback& callback);
 
-  // Set the receive buffer size (in bytes) for the socket.
+  // Sets the receive buffer size (in bytes) for the socket.
   // Returns a net error code.
   int SetReceiveBufferSize(int32 size);
 
-  // Set the send buffer size (in bytes) for the socket.
+  // Sets the send buffer size (in bytes) for the socket.
   // Returns a net error code.
   int SetSendBufferSize(int32 size);
 
   // Returns true if the socket is already connected or bound.
-  bool is_connected() const { return socket_ != INVALID_SOCKET; }
+  bool is_connected() const { return is_connected_; }
 
   const BoundNetLog& NetLog() const { return net_log_; }
 
   // Sets corresponding flags in |socket_options_| to allow the socket
   // to share the local address to which the socket will be bound with
-  // other processes. Should be called before Bind().
-  void AllowAddressReuse();
+  // other processes. Should be called between Open() and Bind().
+  // Returns a net error code.
+  int AllowAddressReuse();
 
   // Sets corresponding flags in |socket_options_| to allow sending
-  // and receiving packets to and from broadcast addresses. Should be
-  // called before Bind().
-  void AllowBroadcast();
+  // and receiving packets to and from broadcast addresses.
+  int SetBroadcast(bool broadcast);
 
-  // Join the multicast group.
+  // Joins the multicast group.
   // |group_address| is the group address to join, could be either
   // an IPv4 or IPv6 address.
-  // Return a network error code.
+  // Returns a net error code.
   int JoinGroup(const IPAddressNumber& group_address) const;
 
-  // Leave the multicast group.
+  // Leaves the multicast group.
   // |group_address| is the group address to leave, could be either
   // an IPv4 or IPv6 address. If the socket hasn't joined the group,
   // it will be ignored.
   // It's optional to leave the multicast group before destroying
   // the socket. It will be done by the OS.
-  // Return a network error code.
+  // Return a net error code.
   int LeaveGroup(const IPAddressNumber& group_address) const;
 
-  // Set interface to use for multicast. If |interface_index| set to 0, default
-  // interface is used.
+  // Sets interface to use for multicast. If |interface_index| set to 0,
+  // default interface is used.
   // Should be called before Bind().
-  // Returns a network error code.
+  // Returns a net error code.
   int SetMulticastInterface(uint32 interface_index);
 
-  // Set the time-to-live option for UDP packets sent to the multicast
+  // Sets the time-to-live option for UDP packets sent to the multicast
   // group address. The default value of this option is 1.
   // Cannot be negative or more than 255.
   // Should be called before Bind().
   int SetMulticastTimeToLive(int time_to_live);
 
-  // Set the loopback flag for UDP socket. If this flag is true, the host
+  // Sets the loopback flag for UDP socket. If this flag is true, the host
   // will receive packets sent to the joined group from itself.
   // The default value of this option is true.
   // Should be called before Bind().
@@ -160,7 +167,7 @@
   // other applications on the same host. See MSDN: http://goo.gl/6vqbj
   int SetMulticastLoopbackMode(bool loopback);
 
-  // Set the differentiated services flags on outgoing packets. May not
+  // Sets the differentiated services flags on outgoing packets. May not
   // do anything on some platforms.
   int SetDiffServCodePoint(DiffServCodePoint dscp);
 
@@ -169,9 +176,7 @@
 
  private:
   enum SocketOptions {
-    SOCKET_OPTION_REUSE_ADDRESS  = 1 << 0,
-    SOCKET_OPTION_BROADCAST      = 1 << 1,
-    SOCKET_OPTION_MULTICAST_LOOP = 1 << 2
+    SOCKET_OPTION_MULTICAST_LOOP = 1 << 0
   };
 
   class Core;
@@ -187,9 +192,6 @@
   void LogRead(int result, const char* bytes) const;
   void LogWrite(int result, const char* bytes, const IPEndPoint* address) const;
 
-  // Returns the OS error code (or 0 on success).
-  int CreateSocket(int addr_family);
-
   // Same as SendTo(), except that address is passed by pointer
   // instead of by reference. It is called from Write() with |address|
   // set to NULL.
@@ -204,7 +206,7 @@
 
   // Applies |socket_options_| to |socket_|. Should be called before
   // Bind().
-  int SetSocketOptions();
+  int SetMulticastOptions();
   int DoBind(const IPEndPoint& address);
   // Binds to a random port on |address|.
   int RandomBind(const IPAddressNumber& address);
@@ -215,6 +217,7 @@
 
   SOCKET socket_;
   int addr_family_;
+  bool is_connected_;
 
   // Bitwise-or'd combination of SocketOptions. Specifies the set of
   // options that should be applied to |socket_| before Bind().
@@ -223,7 +226,7 @@
   // Multicast interface.
   uint32 multicast_interface_;
 
-  // Multicast socket options cached for SetSocketOption.
+  // Multicast socket options cached for SetMulticastOption.
   // Cannot be used after Bind().
   int multicast_time_to_live_;
 
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc
index c61a14b..132a67d 100644
--- a/net/url_request/url_request.cc
+++ b/net/url_request/url_request.cc
@@ -768,9 +768,18 @@
     return true;
   }
 
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
+  tracked_objects::ScopedTracker tracking_profile1(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION("423948 URLRequest::Read1"));
+
   bool rv = job_->Read(dest, dest_size, bytes_read);
   // If rv is false, the status cannot be success.
   DCHECK(rv || status_.status() != URLRequestStatus::SUCCESS);
+
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
+  tracked_objects::ScopedTracker tracking_profile2(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION("423948 URLRequest::Read2"));
+
   if (rv && *bytes_read <= 0 && status_.is_success())
     NotifyRequestCompleted();
   return rv;
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index b114ecc..099a319 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -10,7 +10,6 @@
 #endif
 
 #include <algorithm>
-#include <string>
 
 #include "base/basictypes.h"
 #include "base/bind.h"
@@ -99,6 +98,7 @@
 
 using base::ASCIIToUTF16;
 using base::Time;
+using std::string;
 
 namespace net {
 
@@ -5437,6 +5437,25 @@
   }
 }
 
+// Make sure an HTTP request using the "unsafe" port 443 fails.
+// See: https://crbug.com/436451
+TEST_F(URLRequestTestHTTP, UnsafePort) {
+  TestDelegate d;
+  {
+    scoped_ptr<URLRequest> r(default_context_.CreateRequest(
+        GURL("http://www.google.com:443/"), DEFAULT_PRIORITY, &d, NULL));
+
+    r->Start();
+    EXPECT_TRUE(r->is_pending());
+
+    base::RunLoop().Run();
+
+    EXPECT_FALSE(r->is_pending());
+    EXPECT_EQ(URLRequestStatus::FAILED, r->status().status());
+    EXPECT_EQ(ERR_UNSAFE_PORT, r->status().error());
+  }
+}
+
 // Tests that redirection to an unsafe URL is allowed when it has been marked as
 // safe.
 TEST_F(URLRequestTestHTTP, UnsafeRedirectToWhitelistedUnsafeURL) {
diff --git a/skia/BUILD.gn b/skia/BUILD.gn
index 83c4d8b..e654afb 100644
--- a/skia/BUILD.gn
+++ b/skia/BUILD.gn
@@ -282,9 +282,6 @@
     "ext/google_logging.cc",
     "ext/image_operations.cc",
     "ext/image_operations.h",
-    "ext/lazy_pixel_ref.cc",
-    "ext/lazy_pixel_ref.h",
-    "ext/SkThread_chrome.cc",
     "ext/opacity_draw_filter.cc",
     "ext/opacity_draw_filter.h",
     "ext/pixel_ref_utils.cc",
@@ -418,13 +415,6 @@
     ]
   }
 
-  # Fixup Chrome sources.
-  if (is_posix) {
-    sources -= [ "ext/SkThread_chrome.cc" ]
-  }
-  if (is_win) {
-    sources -= [ "ext/SkThread_chrome.cc" ]
-  }
   if (is_android && (!enable_basic_printing && !enable_print_preview)) {
     sources -= [ "ext/skia_utils_base.cc" ]
   }
diff --git a/skia/README.chromium b/skia/README.chromium
deleted file mode 100644
index 9deca56..0000000
--- a/skia/README.chromium
+++ /dev/null
@@ -1,20 +0,0 @@
-This is a copy of the Skia source tree. In the original repository, the include
-directories and the "corecg" directories are separated out. On top of
-  libs/graphics -> skia
-we have the following mappings from source repository to our tree:
-  include/corecg -> skia/include/corecg
-  include/graphics -> skia/include
-  libs/corecg -> skia/corecg
-
-platform/* are our own files that provide extra functionality we need our
-Skia to implement.
-
-DO NOT CHANGE THE SKIA FILES IN OUR TREE. These will be overwritten when we
-sync to newer versions of Skia. The exception is platform/
-
-THE EXCEPTION IS include/corecg/SkUserConfig.h which are the application's
-definition of its options and environment. This file must be manually merged
-with any changes in the Skia tree so that our options are preserved and we
-also pick up any important changes they make.
-
- -- brettw@google.com, 28 December 2006
diff --git a/skia/ext/analysis_canvas.cc b/skia/ext/analysis_canvas.cc
index 48a09d1..17e8390 100644
--- a/skia/ext/analysis_canvas.cc
+++ b/skia/ext/analysis_canvas.cc
@@ -95,17 +95,6 @@
     is_transparent_ = false;
 }
 
-void AnalysisCanvas::clear(SkColor color) {
-  is_transparent_ = (!is_forced_not_transparent_ && SkColorGetA(color) == 0);
-
-  if (!is_forced_not_solid_ && SkColorGetA(color) == 255) {
-    is_solid_color_ = true;
-    color_ = color;
-  } else {
-    is_solid_color_ = false;
-  }
-}
-
 void AnalysisCanvas::drawPaint(const SkPaint& paint) {
   SkRect rect;
   getClipBounds(&rect);
diff --git a/skia/ext/analysis_canvas.h b/skia/ext/analysis_canvas.h
index abedcaf..105ff2c 100644
--- a/skia/ext/analysis_canvas.h
+++ b/skia/ext/analysis_canvas.h
@@ -30,7 +30,6 @@
   bool abortDrawing() override;
 
   // SkCanvas overrides.
-  void clear(SkColor) override;
   void drawPaint(const SkPaint& paint) override;
   void drawPoints(PointMode,
                   size_t count,
diff --git a/skia/ext/lazy_pixel_ref.cc b/skia/ext/lazy_pixel_ref.cc
deleted file mode 100644
index 6941871..0000000
--- a/skia/ext/lazy_pixel_ref.cc
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "skia/ext/lazy_pixel_ref.h"
-
-namespace skia {
-
-LazyPixelRef::LazyPixelRef(const SkImageInfo& info) : SkPixelRef(info) {
-}
-
-LazyPixelRef::~LazyPixelRef() {
-}
-
-}  // namespace skia
diff --git a/skia/ext/lazy_pixel_ref.h b/skia/ext/lazy_pixel_ref.h
deleted file mode 100644
index 2335fdf..0000000
--- a/skia/ext/lazy_pixel_ref.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SKIA_EXT_LAZY_PIXEL_REF_H_
-#define SKIA_EXT_LAZY_PIXEL_REF_H_
-
-#include "third_party/skia/include/core/SkPixelRef.h"
-#include "third_party/skia/include/core/SkRect.h"
-
-namespace skia {
-
-// This class extends SkPixelRef to facilitate lazy image decoding on the impl
-// thread.
-class SK_API LazyPixelRef : public SkPixelRef {
- public:
-  explicit LazyPixelRef(const SkImageInfo& info);
-  ~LazyPixelRef() override;
-
-  struct PrepareParams {
-    // Clipping rect for this pixel ref.
-    SkIRect clip_rect;
-  };
-
-  // Request the ImageDecodingStore to prepare image decoding for the
-  // given clipping rect. Returns true is succeeded, or false otherwise.
-  virtual bool PrepareToDecode(const PrepareParams& params) = 0;
-
-  // Returns true if this pixel ref is already in the ImageDecodingStore's
-  // cache, false otherwise. Much cheaper than PrepareToDecode().
-  virtual bool MaybeDecoded() = 0;
-
-  // Start decoding the image.
-  virtual void Decode() = 0;
-};
-
-}  // namespace skia
-
-#endif  // SKIA_EXT_LAZY_PIXEL_REF_H_
diff --git a/skia/ext/pixel_ref_utils.cc b/skia/ext/pixel_ref_utils.cc
index 4e85f7a..324adbd 100644
--- a/skia/ext/pixel_ref_utils.cc
+++ b/skia/ext/pixel_ref_utils.cc
@@ -51,7 +51,6 @@
                        DiscardablePixelRefSet* pixel_ref_set)
       : SkBitmapDevice(bm), pixel_ref_set_(pixel_ref_set) {}
 
-  void clear(SkColor color) override {}
   void drawPaint(const SkDraw& draw, const SkPaint& paint) override {
     SkBitmap bitmap;
     if (GetBitmapFromPaint(paint, &bitmap)) {
diff --git a/skia/skia_chrome.gypi b/skia/skia_chrome.gypi
index cff4e3c..6a24635 100644
--- a/skia/skia_chrome.gypi
+++ b/skia/skia_chrome.gypi
@@ -52,8 +52,6 @@
     'ext/google_logging.cc',
     'ext/image_operations.cc',
     'ext/image_operations.h',
-    'ext/lazy_pixel_ref.cc',
-    'ext/lazy_pixel_ref.h',
     'ext/opacity_draw_filter.cc',
     'ext/opacity_draw_filter.h',
     'ext/pixel_ref_utils.cc',
diff --git a/sky/engine/platform/graphics/Gradient.cpp b/sky/engine/platform/graphics/Gradient.cpp
index ccd8505..e4abfe5 100644
--- a/sky/engine/platform/graphics/Gradient.cpp
+++ b/sky/engine/platform/graphics/Gradient.cpp
@@ -32,7 +32,6 @@
 #include "sky/engine/platform/graphics/GraphicsContext.h"
 #include "sky/engine/platform/graphics/skia/SkiaUtils.h"
 #include "third_party/skia/include/core/SkColor.h"
-#include "third_party/skia/include/core/SkColorShader.h"
 #include "third_party/skia/include/core/SkShader.h"
 #include "third_party/skia/include/effects/SkGradientShader.h"
 
@@ -260,7 +259,7 @@
 
     if (!m_gradient) {
         // use last color, since our "geometry" was degenerate (e.g. radius==0)
-        m_gradient = adoptRef(new SkColorShader(colors[countUsed - 1]));
+        m_gradient = adoptRef(SkShader::CreateColorShader(colors[countUsed - 1]));
     }
     return m_gradient.get();
 }
diff --git a/sky/engine/platform/graphics/InterceptingCanvas.h b/sky/engine/platform/graphics/InterceptingCanvas.h
index dbf9567..a3e9ba5 100644
--- a/sky/engine/platform/graphics/InterceptingCanvas.h
+++ b/sky/engine/platform/graphics/InterceptingCanvas.h
@@ -40,7 +40,6 @@
     InterceptingCanvas(SkBitmap bitmap) : SkCanvas(bitmap), m_depthCount(0) { };
     InterceptingCanvas(int width, int height) : SkCanvas(width, height), m_depthCount(0) { };
 
-    virtual void clear(SkColor) override = 0;
     virtual void drawPaint(const SkPaint&) override = 0;
     virtual void drawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override = 0;
     virtual void drawRect(const SkRect&, const SkPaint&) override = 0;
diff --git a/sky/engine/platform/graphics/LoggingCanvas.cpp b/sky/engine/platform/graphics/LoggingCanvas.cpp
index 892b26d..18adab9 100644
--- a/sky/engine/platform/graphics/LoggingCanvas.cpp
+++ b/sky/engine/platform/graphics/LoggingCanvas.cpp
@@ -84,13 +84,6 @@
     m_log = JSONArray::create();
 }
 
-void LoggingCanvas::clear(SkColor color)
-{
-    AutoLogger logger(this);
-    logger.logItemWithParams("clear")->setString("color", stringForSkColor(color));
-    this->SkCanvas::clear(color);
-}
-
 void LoggingCanvas::drawPaint(const SkPaint& paint)
 {
     AutoLogger logger(this);
diff --git a/sky/engine/platform/graphics/LoggingCanvas.h b/sky/engine/platform/graphics/LoggingCanvas.h
index b2a833b..3483015 100644
--- a/sky/engine/platform/graphics/LoggingCanvas.h
+++ b/sky/engine/platform/graphics/LoggingCanvas.h
@@ -41,7 +41,6 @@
     LoggingCanvas(int width, int height);
     PassRefPtr<JSONArray> log();
 
-    virtual void clear(SkColor) override;
     virtual void drawPaint(const SkPaint&) override;
     virtual void drawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override;
     virtual void drawRect(const SkRect&, const SkPaint&) override;
diff --git a/sky/engine/platform/graphics/Pattern.cpp b/sky/engine/platform/graphics/Pattern.cpp
index d29593f..3bd1112 100644
--- a/sky/engine/platform/graphics/Pattern.cpp
+++ b/sky/engine/platform/graphics/Pattern.cpp
@@ -30,7 +30,6 @@
 
 #include "sky/engine/platform/graphics/skia/SkiaUtils.h"
 #include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkColorShader.h"
 #include "v8/include/v8.h"
 
 namespace blink {
@@ -64,7 +63,7 @@
 
     // If we don't have a bitmap, return a transparent shader.
     if (!m_tileImage) {
-        m_pattern = adoptRef(new SkColorShader(SK_ColorTRANSPARENT));
+        m_pattern = adoptRef(SkShader::CreateColorShader(SK_ColorTRANSPARENT));
     } else if (m_repeatMode == RepeatModeXY) {
         m_pattern = adoptRef(SkShader::CreateBitmapShader(m_tileImage->bitmap(),
             SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix));
diff --git a/sky/engine/platform/graphics/ProfilingCanvas.cpp b/sky/engine/platform/graphics/ProfilingCanvas.cpp
index 6faaa91..2940339 100644
--- a/sky/engine/platform/graphics/ProfilingCanvas.cpp
+++ b/sky/engine/platform/graphics/ProfilingCanvas.cpp
@@ -69,12 +69,6 @@
     m_timings = timings;
 }
 
-void ProfilingCanvas::clear(SkColor color)
-{
-    AutoStamper stamper(this);
-    this->SkCanvas::clear(color);
-}
-
 void ProfilingCanvas::drawPaint(const SkPaint& paint)
 {
     AutoStamper stamper(this);
diff --git a/sky/engine/platform/graphics/ProfilingCanvas.h b/sky/engine/platform/graphics/ProfilingCanvas.h
index 007f842..b390ab4 100644
--- a/sky/engine/platform/graphics/ProfilingCanvas.h
+++ b/sky/engine/platform/graphics/ProfilingCanvas.h
@@ -41,7 +41,6 @@
     ProfilingCanvas(SkBitmap);
     void setTimings(Vector<double>*);
 
-    virtual void clear(SkColor) override;
     virtual void drawPaint(const SkPaint&) override;
     virtual void drawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override;
     virtual void drawRect(const SkRect&, const SkPaint&) override;
diff --git a/sky/engine/platform/graphics/ReplayingCanvas.cpp b/sky/engine/platform/graphics/ReplayingCanvas.cpp
index db2433a..3c13a10 100644
--- a/sky/engine/platform/graphics/ReplayingCanvas.cpp
+++ b/sky/engine/platform/graphics/ReplayingCanvas.cpp
@@ -83,12 +83,6 @@
     return m_abortDrawing;
 }
 
-void ReplayingCanvas::clear(SkColor color)
-{
-    AutoReplayer replayer(this);
-    this->SkCanvas::clear(color);
-}
-
 void ReplayingCanvas::drawPaint(const SkPaint& paint)
 {
     AutoReplayer replayer(this);
diff --git a/sky/engine/platform/graphics/ReplayingCanvas.h b/sky/engine/platform/graphics/ReplayingCanvas.h
index 99ca93a..a8e9541 100644
--- a/sky/engine/platform/graphics/ReplayingCanvas.h
+++ b/sky/engine/platform/graphics/ReplayingCanvas.h
@@ -43,7 +43,6 @@
 
     virtual bool abortDrawing() override;
 
-    virtual void clear(SkColor) override;
     virtual void drawPaint(const SkPaint&) override;
     virtual void drawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override;
     virtual void drawRect(const SkRect&, const SkPaint&) override;
diff --git a/third_party/protobuf/OWNERS b/third_party/protobuf/OWNERS
new file mode 100644
index 0000000..a0b277d
--- /dev/null
+++ b/third_party/protobuf/OWNERS
@@ -0,0 +1,2 @@
+agl@chromium.org
+scottmg@chromium.org
diff --git a/ui/gl/generate_bindings.py b/ui/gl/generate_bindings.py
index 6fff4cb..14e3052 100755
--- a/ui/gl/generate_bindings.py
+++ b/ui/gl/generate_bindings.py
@@ -326,12 +326,8 @@
   'names': ['glDisableVertexAttribArray'],
   'arguments': 'GLuint index', },
 { 'return_type': 'void',
-  'known_as': 'glDiscardFramebufferEXT',
-  'versions': [{ 'name': 'glInvalidateFramebuffer',
-                 'gl_versions': ['es3'],
-                 'extensions': [] },
-               { 'name': 'glDiscardFramebufferEXT',
-                 'gl_versions': ['es1', 'es2'] }],
+  'versions': [{ 'name': 'glDiscardFramebufferEXT',
+                 'extensions': ['GL_EXT_discard_framebuffer'] }],
   'arguments': 'GLenum target, GLsizei numAttachments, '
       'const GLenum* attachments' },
 { 'return_type': 'void',
@@ -698,6 +694,11 @@
   'names': ['glInsertEventMarkerEXT'],
   'arguments': 'GLsizei length, const char* marker', },
 { 'return_type': 'void',
+  'versions': [{ 'name': 'glInvalidateFramebuffer',
+                 'gl_versions': ['gl4', 'es3'] }],  # GL 4.3 or higher.
+  'arguments': 'GLenum target, GLsizei numAttachments, '
+      'const GLenum* attachments' },
+{ 'return_type': 'void',
   'versions': [{ 'name': 'glInvalidateSubFramebuffer',
                  'gl_versions': ['gl4', 'es3'] }],  # GL 4.3 or higher.
   'arguments':
diff --git a/ui/gl/gl_bindings.h b/ui/gl/gl_bindings.h
index 0d25bbe..86f921b 100644
--- a/ui/gl/gl_bindings.h
+++ b/ui/gl/gl_bindings.h
@@ -100,9 +100,13 @@
 #define GL_LUMINANCE_ALPHA32F_EXT                        0x8819
 #define GL_RGBA16F_EXT                                   0x881A
 #define GL_RGB16F_EXT                                    0x881B
+#define GL_RG16F_EXT 0x822F
+#define GL_R16F_EXT 0x822D
 #define GL_ALPHA16F_EXT                                  0x881C
 #define GL_LUMINANCE16F_EXT                              0x881E
 #define GL_LUMINANCE_ALPHA16F_EXT                        0x881F
+#define GL_R32F_EXT 0x822E
+#define GL_RG32F_EXT 0x8230
 #define GL_BGRA8_EXT                                     0x93A1
 
 // GL_ANGLE_instanced_arrays
diff --git a/ui/gl/gl_context_android.cc b/ui/gl/gl_context_android.cc
index 2d91a65..7f9cf2d 100644
--- a/ui/gl/gl_context_android.cc
+++ b/ui/gl/gl_context_android.cc
@@ -120,7 +120,7 @@
   // Droid Razr M(1GB)  114MB (normally 57MB)
   // Galaxy Nexus(1GB)  100MB (normally 50MB)
   // Xoom(1GB)          100MB (normally 50MB)
-  // Nexus S(low-end)   12MB (normally 8MB)
+  // Nexus S(low-end)   8MB (normally 8MB)
   // Note that the compositor now uses only some of this memory for
   // pre-painting and uses the rest only for 'emergencies'.
   static size_t limit_bytes = 0;
@@ -140,9 +140,7 @@
       // Low-end devices have 512MB or less memory by definition
       // so we hard code the limit rather than relying on the heuristics
       // above. Low-end devices use 4444 textures so we can use a lower limit.
-      // NOTE: Low-end uses 2/3 (67%) of this memory in practice, so we have
-      // increased the limit to 12 (8MB, or 12MB in emergencies).
-      limit_bytes = 12;
+      limit_bytes = 8;
     }
     limit_bytes = limit_bytes * 1024 * 1024;
   }
diff --git a/ui/gl/gl_gl_api_implementation.cc b/ui/gl/gl_gl_api_implementation.cc
index 017e123..7f6a647 100644
--- a/ui/gl/gl_gl_api_implementation.cc
+++ b/ui/gl/gl_gl_api_implementation.cc
@@ -48,6 +48,42 @@
 
   // g_version_info must be initialized when this function is bound.
   DCHECK(gfx::g_version_info);
+  if (gfx::g_version_info->is_es3) {
+    if (format == GL_RED_EXT) {
+      switch (type) {
+        case GL_UNSIGNED_BYTE:
+          gl_internal_format = GL_R8_EXT;
+          break;
+        case GL_HALF_FLOAT_OES:
+          gl_internal_format = GL_R16F_EXT;
+          break;
+        case GL_FLOAT:
+          gl_internal_format = GL_R32F_EXT;
+          break;
+        default:
+          NOTREACHED();
+          break;
+      }
+      return gl_internal_format;
+    } else if (format == GL_RG_EXT) {
+      switch (type) {
+        case GL_UNSIGNED_BYTE:
+          gl_internal_format = GL_RG8_EXT;
+          break;
+        case GL_HALF_FLOAT_OES:
+          gl_internal_format = GL_RG16F_EXT;
+          break;
+        case GL_FLOAT:
+          gl_internal_format = GL_RG32F_EXT;
+          break;
+        default:
+          NOTREACHED();
+          break;
+      }
+      return gl_internal_format;
+    }
+  }
+
   if (type == GL_FLOAT && gfx::g_version_info->is_angle &&
       gfx::g_version_info->is_es2) {
     // It's possible that the texture is using a sized internal format, and
diff --git a/ui/gl/gl_version_info.h b/ui/gl/gl_version_info.h
index 13b323f..21ca07a 100644
--- a/ui/gl/gl_version_info.h
+++ b/ui/gl/gl_version_info.h
@@ -7,10 +7,11 @@
 
 #include <string>
 #include "base/basictypes.h"
+#include "ui/gl/gl_export.h"
 
 namespace gfx {
 
-struct GLVersionInfo {
+struct GL_EXPORT GLVersionInfo {
   GLVersionInfo(const char* version_str, const char* renderer_str);
 
   // New flags, such as is_gl4_4 could be introduced as needed.
@@ -27,7 +28,7 @@
 
   bool is_angle;
 
-private:
+ private:
   DISALLOW_COPY_AND_ASSIGN(GLVersionInfo);
 };
 
diff --git a/ui/gl/gpu_switching_manager.cc b/ui/gl/gpu_switching_manager.cc
index f904629..020592f 100644
--- a/ui/gl/gpu_switching_manager.cc
+++ b/ui/gl/gpu_switching_manager.cc
@@ -9,12 +9,19 @@
 #include "ui/gl/gl_switches.h"
 
 #if defined(OS_MACOSX)
+#include <OpenGL/OpenGL.h>
 #include "base/mac/mac_util.h"
 #include "ui/gl/gl_context_cgl.h"
 #endif  // OS_MACOSX
 
 namespace ui {
 
+struct GpuSwitchingManager::PlatformSpecific {
+#if defined(OS_MACOSX)
+  CGLPixelFormatObj discrete_pixel_format;
+#endif  // OS_MACOSX
+};
+
 // static
 GpuSwitchingManager* GpuSwitchingManager::GetInstance() {
   return Singleton<GpuSwitchingManager>::get();
@@ -25,16 +32,17 @@
       gpu_switching_option_set_(false),
       supports_dual_gpus_(false),
       supports_dual_gpus_set_(false),
-      gpu_count_(0) {
+      gpu_count_(0),
+      platform_specific_(new PlatformSpecific) {
 #if defined(OS_MACOSX)
-  discrete_pixel_format_ = NULL;
+  platform_specific_->discrete_pixel_format = nullptr;
 #endif  // OS_MACOSX
 }
 
 GpuSwitchingManager::~GpuSwitchingManager() {
 #if defined(OS_MACOSX)
-  if (discrete_pixel_format_)
-    CGLReleasePixelFormat(discrete_pixel_format_);
+  if (platform_specific_->discrete_pixel_format)
+    CGLReleasePixelFormat(platform_specific_->discrete_pixel_format);
 #endif  // OS_MACOSX
 }
 
@@ -123,12 +131,13 @@
 
 #if defined(OS_MACOSX)
 void GpuSwitchingManager::SwitchToDiscreteGpuMac() {
-  if (discrete_pixel_format_)
+  if (platform_specific_->discrete_pixel_format)
     return;
   CGLPixelFormatAttribute attribs[1];
   attribs[0] = static_cast<CGLPixelFormatAttribute>(0);
   GLint num_pixel_formats = 0;
-  CGLChoosePixelFormat(attribs, &discrete_pixel_format_, &num_pixel_formats);
+  CGLChoosePixelFormat(attribs, &platform_specific_->discrete_pixel_format,
+                       &num_pixel_formats);
 }
 #endif  // OS_MACOSX
 
diff --git a/ui/gl/gpu_switching_manager.h b/ui/gl/gpu_switching_manager.h
index 7e82d62..a6a810f 100644
--- a/ui/gl/gpu_switching_manager.h
+++ b/ui/gl/gpu_switching_manager.h
@@ -13,10 +13,6 @@
 #include "ui/gl/gpu_preference.h"
 #include "ui/gl/gpu_switching_observer.h"
 
-#if defined(OS_MACOSX)
-#include <OpenGL/OpenGL.h>
-#endif  // OS_MACOSX
-
 namespace ui {
 
 class GL_EXPORT GpuSwitchingManager {
@@ -60,8 +56,6 @@
 
 #if defined(OS_MACOSX)
   void SwitchToDiscreteGpuMac();
-
-  CGLPixelFormatObj discrete_pixel_format_;
 #endif  // OS_MACOSX
 
   gfx::GpuPreference gpu_switching_option_;
@@ -72,6 +66,9 @@
 
   size_t gpu_count_;
 
+  struct PlatformSpecific;
+  scoped_ptr<PlatformSpecific> platform_specific_;
+
   ObserverList<GpuSwitchingObserver> observer_list_;
 
   DISALLOW_COPY_AND_ASSIGN(GpuSwitchingManager);
diff --git a/url/gurl.cc b/url/gurl.cc
index b580125..46ca408 100644
--- a/url/gurl.cc
+++ b/url/gurl.cc
@@ -177,6 +177,22 @@
   return EmptyStringForGURL();
 }
 
+bool GURL::operator==(const GURL& other) const {
+  return spec_ == other.spec_;
+}
+
+bool GURL::operator!=(const GURL& other) const {
+  return spec_ != other.spec_;
+}
+
+bool GURL::operator<(const GURL& other) const {
+  return spec_ < other.spec_;
+}
+
+bool GURL::operator>(const GURL& other) const {
+  return spec_ > other.spec_;
+}
+
 GURL GURL::Resolve(const std::string& relative) const {
   return ResolveWithCharsetConverter(relative, NULL);
 }
diff --git a/url/gurl.h b/url/gurl.h
index f370934..ef1e529 100644
--- a/url/gurl.h
+++ b/url/gurl.h
@@ -112,20 +112,12 @@
   }
 
   // Defiant equality operator!
-  bool operator==(const GURL& other) const {
-    return spec_ == other.spec_;
-  }
-  bool operator!=(const GURL& other) const {
-    return spec_ != other.spec_;
-  }
+  bool operator==(const GURL& other) const;
+  bool operator!=(const GURL& other) const;
 
   // Allows GURL to used as a key in STL (for example, a std::set or std::map).
-  bool operator<(const GURL& other) const {
-    return spec_ < other.spec_;
-  }
-  bool operator>(const GURL& other) const {
-    return spec_ > other.spec_;
-  }
+  bool operator<(const GURL& other) const;
+  bool operator>(const GURL& other) const;
 
   // Resolves a URL that's possibly relative to this object's URL, and returns
   // it. Absolute URLs are also handled according to the rules of URLs on web